chromium/third_party/unrar/src/filcreat.cpp

#include "rar.hpp"

// If NewFile==NULL, we delete created file after user confirmation.
// It is useful if we need to overwrite an existing folder or file,
// but need user confirmation for that.
bool FileCreate(CommandData *Cmd,File *NewFile,std::wstring &Name,
                bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
{}


#if defined(_WIN_ALL)
// If we find a file, which short name is equal to 'Name', we try to change
// its short name, while preserving the long name. It helps when unpacking
// an archived file, which long name is equal to short name of already
// existing file. Otherwise we would overwrite the already existing file,
// even though its long name does not match the name of unpacking file.
bool UpdateExistingShortName(const std::wstring &Name)
{
  DWORD Res=GetLongPathName(Name.c_str(),NULL,0);
  if (Res==0)
    return false;
  std::vector<wchar> LongPathBuf(Res);
  Res=GetLongPathName(Name.c_str(),LongPathBuf.data(),(DWORD)LongPathBuf.size());
  if (Res==0 || Res>=LongPathBuf.size())
    return false;
  Res=GetShortPathName(Name.c_str(),NULL,0);
  if (Res==0)
    return false;
  std::vector<wchar> ShortPathBuf(Res);
  Res=GetShortPathName(Name.c_str(),ShortPathBuf.data(),(DWORD)ShortPathBuf.size());
  if (Res==0 || Res>=ShortPathBuf.size())
    return false;
  std::wstring LongPathName=LongPathBuf.data();
  std::wstring ShortPathName=ShortPathBuf.data();
  
  std::wstring LongName=PointToName(LongPathName);
  std::wstring ShortName=PointToName(ShortPathName);

  // We continue only if file has a short name, which does not match its
  // long name, and this short name is equal to name of file which we need
  // to create.
  if (ShortName.empty() || wcsicomp(LongName,ShortName)==0 ||
      wcsicomp(PointToName(Name),ShortName)!=0)
    return false;

  // Generate the temporary new name for existing file.
  std::wstring NewName;
  for (uint I=0;I<10000 && NewName.empty();I+=123)
  {
    // Here we copy the path part of file to create. We'll make the temporary
    // file in the same folder.
    NewName=Name;

    // Here we set the random name part.
    SetName(NewName,std::wstring(L"rtmp") + std::to_wstring(I));
    
    // If such file is already exist, try next random name.
    if (FileExist(NewName))
      NewName.clear();
  }

  // If we could not generate the name not used by any other file, we return.
  if (NewName.empty())
    return false;
  
  // FastFind returns the name without path, but we need the fully qualified
  // name for renaming, so we use the path from file to create and long name
  // from existing file.
  std::wstring FullName=Name;
  SetName(FullName,LongName);
  
  // Rename the existing file to randomly generated name. Normally it changes
  // the short name too.
  if (!MoveFile(FullName.c_str(),NewName.c_str()))
    return false;

  // Now we need to create the temporary empty file with same name as
  // short name of our already existing file. We do it to occupy its previous
  // short name and not allow to use it again when renaming the file back to
  // its original long name.
  File KeepShortFile;
  bool Created=false;
  if (!FileExist(Name))
    Created=KeepShortFile.Create(Name,FMF_WRITE|FMF_SHAREREAD);

  // Now we rename the existing file from temporary name to original long name.
  // Since its previous short name is occupied by another file, it should
  // get another short name.
  MoveFile(NewName.c_str(),FullName.c_str());

  if (Created)
  {
    // Delete the temporary zero length file occupying the short name,
    KeepShortFile.Close();
    KeepShortFile.Delete();
  }
  // We successfully changed the short name. We do not use the simpler
  // SetFileShortName Windows API call, because it requires SE_RESTORE_NAME
  // privilege.
  return true;
}
#endif