filcreat.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #include "rar.hpp"
  2. // If NewFile==NULL, we delete created file after user confirmation.
  3. // It is useful if we need to overwrite an existing folder or file,
  4. // but need user confirmation for that.
  5. bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
  6. bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
  7. {
  8. return true; // OPENMPT ADDITION
  9. if (UserReject!=NULL)
  10. *UserReject=false;
  11. #ifdef _WIN_ALL
  12. bool ShortNameChanged=false;
  13. #endif
  14. while (FileExist(Name))
  15. {
  16. #if defined(_WIN_ALL)
  17. if (!ShortNameChanged)
  18. {
  19. // Avoid the infinite loop if UpdateExistingShortName returns
  20. // the same name.
  21. ShortNameChanged=true;
  22. // Maybe our long name matches the short name of existing file.
  23. // Let's check if we can change the short name.
  24. if (UpdateExistingShortName(Name))
  25. continue;
  26. }
  27. // Allow short name check again. It is necessary, because rename and
  28. // autorename below can change the name, so we need to check it again.
  29. ShortNameChanged=false;
  30. #endif
  31. UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
  32. if (Choice==UIASKREP_R_REPLACE)
  33. break;
  34. if (Choice==UIASKREP_R_SKIP)
  35. {
  36. if (UserReject!=NULL)
  37. *UserReject=true;
  38. return false;
  39. }
  40. if (Choice==UIASKREP_R_CANCEL)
  41. ErrHandler.Exit(RARX_USERBREAK);
  42. }
  43. // Try to truncate the existing file first instead of delete,
  44. // so we preserve existing file permissions, such as NTFS permissions,
  45. // also as "Compressed" attribute and hard links. In GUI version we avoid
  46. // deleting an existing file for non-.rar archive formats as well.
  47. uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD;
  48. if (NewFile!=NULL && NewFile->Create(Name,FileMode))
  49. return true;
  50. CreatePath(Name,true,Cmd->DisableNames);
  51. return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
  52. }
  53. bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
  54. {
  55. return true; // OPENMPT ADDITION
  56. wchar NewName[NM];
  57. size_t NameLength=wcslen(Name);
  58. wchar *Ext=GetExt(Name);
  59. if (Ext==NULL)
  60. Ext=Name+NameLength;
  61. for (uint FileVer=1;;FileVer++)
  62. {
  63. swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
  64. if (!FileExist(NewName))
  65. {
  66. wcsncpyz(Name,NewName,MaxNameSize);
  67. break;
  68. }
  69. if (FileVer>=1000000)
  70. return false;
  71. }
  72. return true;
  73. }
  74. #if defined(_WIN_ALL)
  75. // If we find a file, which short name is equal to 'Name', we try to change
  76. // its short name, while preserving the long name. It helps when unpacking
  77. // an archived file, which long name is equal to short name of already
  78. // existing file. Otherwise we would overwrite the already existing file,
  79. // even though its long name does not match the name of unpacking file.
  80. bool UpdateExistingShortName(const wchar *Name)
  81. {
  82. wchar LongPathName[NM];
  83. DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
  84. if (Res==0 || Res>=ASIZE(LongPathName))
  85. return false;
  86. wchar ShortPathName[NM];
  87. Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName));
  88. if (Res==0 || Res>=ASIZE(ShortPathName))
  89. return false;
  90. wchar *LongName=PointToName(LongPathName);
  91. wchar *ShortName=PointToName(ShortPathName);
  92. // We continue only if file has a short name, which does not match its
  93. // long name, and this short name is equal to name of file which we need
  94. // to create.
  95. if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 ||
  96. wcsicomp(PointToName(Name),ShortName)!=0)
  97. return false;
  98. // Generate the temporary new name for existing file.
  99. wchar NewName[NM];
  100. *NewName=0;
  101. for (int I=0;I<10000 && *NewName==0;I+=123)
  102. {
  103. // Here we copy the path part of file to create. We'll make the temporary
  104. // file in the same folder.
  105. wcsncpyz(NewName,Name,ASIZE(NewName));
  106. // Here we set the random name part.
  107. swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
  108. // If such file is already exist, try next random name.
  109. if (FileExist(NewName))
  110. *NewName=0;
  111. }
  112. // If we could not generate the name not used by any other file, we return.
  113. if (*NewName==0)
  114. return false;
  115. // FastFind returns the name without path, but we need the fully qualified
  116. // name for renaming, so we use the path from file to create and long name
  117. // from existing file.
  118. wchar FullName[NM];
  119. wcsncpyz(FullName,Name,ASIZE(FullName));
  120. SetName(FullName,LongName,ASIZE(FullName));
  121. // Rename the existing file to randomly generated name. Normally it changes
  122. // the short name too.
  123. if (!MoveFile(FullName,NewName))
  124. return false;
  125. // Now we need to create the temporary empty file with same name as
  126. // short name of our already existing file. We do it to occupy its previous
  127. // short name and not allow to use it again when renaming the file back to
  128. // its original long name.
  129. File KeepShortFile;
  130. bool Created=false;
  131. if (!FileExist(Name))
  132. Created=KeepShortFile.Create(Name,FMF_WRITE|FMF_SHAREREAD);
  133. // Now we rename the existing file from temporary name to original long name.
  134. // Since its previous short name is occupied by another file, it should
  135. // get another short name.
  136. MoveFile(NewName,FullName);
  137. if (Created)
  138. {
  139. // Delete the temporary zero length file occupying the short name,
  140. KeepShortFile.Close();
  141. KeepShortFile.Delete();
  142. }
  143. // We successfully changed the short name. Maybe sometimes we'll simplify
  144. // this function by use of SetFileShortName Windows API call.
  145. // But SetFileShortName is not available in older Windows.
  146. return true;
  147. }
  148. #endif