blob: a64a7d4d7b4e74d864bd4498cc011337a486ffd2 [file] [log] [blame]
#include "rar.hpp"
// If NewFile==NULL, we delete created file after user confirmation.
// It is useful we we need to overwrite an existing folder or file,
// but need user confirmation for that.
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
if (UserReject!=NULL)
#ifdef _WIN_ALL
bool ShortNameChanged=false;
while (FileExist(Name))
#if defined(_WIN_ALL)
if (!ShortNameChanged)
// Avoid the infinite loop if UpdateExistingShortName returns
// the same name.
// Maybe our long name matches the short name of existing file.
// Let's check if we can change the short name.
if (UpdateExistingShortName(Name))
// Allow short name check again. It is necessary, because rename and
// autorename below can change the name, so we need to check it again.
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
if (Choice==UIASKREP_R_SKIP)
if (UserReject!=NULL)
return false;
// Try to truncate the existing file first instead of delete,
// so we preserve existing file permissions such as NTFS permissions.
if (NewFile!=NULL && NewFile->Create(Name,FileMode))
return true;
return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
wchar NewName[NM];
size_t NameLength=wcslen(Name);
wchar *Ext=GetExt(Name);
if (Ext==NULL)
for (uint FileVer=1;;FileVer++)
if (!FileExist(NewName))
if (FileVer>=1000000)
return false;
return true;
#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 wchar *Name)
wchar LongPathName[NM];
DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
if (Res==0 || Res>=ASIZE(LongPathName))
return false;
wchar ShortPathName[NM];
if (Res==0 || Res>=ASIZE(ShortPathName))
return false;
wchar *LongName=PointToName(LongPathName);
wchar *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==0 || wcsicomp(LongName,ShortName)==0 ||
return false;
// Generate the temporary new name for existing file.
wchar NewName[NM];
for (int I=0;I<10000 && *NewName==0;I+=123)
// Here we copy the path part of file to create. We'll make the temporary
// file in the same folder.
// Here we set the random name part.
// If such file is already exist, try next random name.
if (FileExist(NewName))
// If we could not generate the name not used by any other file, we return.
if (*NewName==0)
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.
wchar FullName[NM];
// Rename the existing file to randomly generated name. Normally it changes
// the short name too.
if (!MoveFile(FullName,NewName))
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))
// 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.
if (Created)
// Delete the temporary zero length file occupying the short name,
// We successfully changed the short name. Maybe sometimes we'll simplify
// this function by use of SetFileShortName Windows API call.
// But SetFileShortName is not available in older Windows.
return true;