filcreat.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #include "rar.hpp"
  2. bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
  3. OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize,
  4. uint FileTime)
  5. {
  6. if (UserReject!=NULL)
  7. *UserReject=false;
  8. #if defined(_WIN_ALL) && !defined(_WIN_CE)
  9. bool ShortNameChanged=false;
  10. #endif
  11. while (FileExist(Name,NameW))
  12. {
  13. #if defined(_WIN_ALL) && !defined(_WIN_CE)
  14. if (!ShortNameChanged)
  15. {
  16. // Avoid the infinite loop if UpdateExistingShortName returns
  17. // the same name.
  18. ShortNameChanged=true;
  19. // Maybe our long name matches the short name of existing file.
  20. // Let's check if we can change the short name.
  21. wchar WideName[NM];
  22. GetWideName(Name,NameW,WideName,ASIZE(WideName));
  23. if (UpdateExistingShortName(WideName))
  24. {
  25. if (Name!=NULL && *Name!=0)
  26. WideToChar(WideName,Name);
  27. if (NameW!=NULL && *NameW!=0)
  28. wcscpy(NameW,WideName);
  29. continue;
  30. }
  31. }
  32. // Allow short name check again. It is necessary, because rename and
  33. // autorename below can change the name, so we need to check it again.
  34. ShortNameChanged=false;
  35. #endif
  36. if (Mode==OVERWRITE_NONE)
  37. {
  38. if (UserReject!=NULL)
  39. *UserReject=true;
  40. return(false);
  41. }
  42. // Must be before Cmd->AllYes check or -y switch would override -or.
  43. if (Mode==OVERWRITE_AUTORENAME)
  44. {
  45. if (!GetAutoRenamedName(Name,NameW))
  46. Mode=OVERWRITE_DEFAULT;
  47. continue;
  48. }
  49. #ifdef SILENT
  50. Mode=OVERWRITE_ALL;
  51. #endif
  52. // This check must be after OVERWRITE_AUTORENAME processing or -y switch
  53. // would override -or.
  54. if (Cmd->AllYes || Mode==OVERWRITE_ALL)
  55. break;
  56. if (Mode==OVERWRITE_DEFAULT || Mode==OVERWRITE_FORCE_ASK)
  57. {
  58. char NewName[NM];
  59. wchar NewNameW[NM];
  60. *NewNameW=0;
  61. eprintf(St(MFileExists),Name);
  62. int Choice=Ask(St(MYesNoAllRenQ));
  63. if (Choice==1)
  64. break;
  65. if (Choice==2)
  66. {
  67. if (UserReject!=NULL)
  68. *UserReject=true;
  69. return(false);
  70. }
  71. if (Choice==3)
  72. {
  73. Cmd->Overwrite=OVERWRITE_ALL;
  74. break;
  75. }
  76. if (Choice==4)
  77. {
  78. if (UserReject!=NULL)
  79. *UserReject=true;
  80. Cmd->Overwrite=OVERWRITE_NONE;
  81. return(false);
  82. }
  83. if (Choice==5)
  84. {
  85. #ifndef GUI
  86. mprintf(St(MAskNewName));
  87. #ifdef _WIN_ALL
  88. File SrcFile;
  89. SrcFile.SetHandleType(FILE_HANDLESTD);
  90. int Size=SrcFile.Read(NewName,sizeof(NewName)-1);
  91. NewName[Size]=0;
  92. OemToCharA(NewName,NewName);
  93. #else
  94. if (fgets(NewName,sizeof(NewName),stdin)==NULL)
  95. {
  96. // Process fgets failure as if user answered 'No'.
  97. if (UserReject!=NULL)
  98. *UserReject=true;
  99. return(false);
  100. }
  101. #endif
  102. RemoveLF(NewName);
  103. #endif
  104. if (PointToName(NewName)==NewName)
  105. strcpy(PointToName(Name),NewName);
  106. else
  107. strcpy(Name,NewName);
  108. if (NameW!=NULL)
  109. if (PointToName(NewNameW)==NewNameW)
  110. wcscpy(PointToName(NameW),NewNameW);
  111. else
  112. wcscpy(NameW,NewNameW);
  113. continue;
  114. }
  115. if (Choice==6)
  116. ErrHandler.Exit(USER_BREAK);
  117. }
  118. }
  119. if (NewFile!=NULL && NewFile->Create(Name,NameW))
  120. return(true);
  121. PrepareToDelete(Name,NameW);
  122. CreatePath(Name,NameW,true);
  123. return(NewFile!=NULL ? NewFile->Create(Name,NameW):DelFile(Name,NameW));
  124. }
  125. bool GetAutoRenamedName(char *Name,wchar *NameW)
  126. {
  127. char NewName[NM];
  128. wchar NewNameW[NM];
  129. if (Name!=NULL && strlen(Name)>ASIZE(NewName)-10 ||
  130. NameW!=NULL && wcslen(NameW)>ASIZE(NewNameW)-10)
  131. return(false);
  132. char *Ext=NULL;
  133. if (Name!=NULL && *Name!=0)
  134. {
  135. Ext=GetExt(Name);
  136. if (Ext==NULL)
  137. Ext=Name+strlen(Name);
  138. }
  139. wchar *ExtW=NULL;
  140. if (NameW!=NULL && *NameW!=0)
  141. {
  142. ExtW=GetExt(NameW);
  143. if (ExtW==NULL)
  144. ExtW=NameW+wcslen(NameW);
  145. }
  146. *NewName=0;
  147. *NewNameW=0;
  148. for (int FileVer=1;;FileVer++)
  149. {
  150. if (Name!=NULL && *Name!=0)
  151. sprintf(NewName,"%.*s(%d)%s",int(Ext-Name),Name,FileVer,Ext);
  152. if (NameW!=NULL && *NameW!=0)
  153. sprintfw(NewNameW,ASIZE(NewNameW),L"%.*s(%d)%s",int(ExtW-NameW),NameW,FileVer,ExtW);
  154. if (!FileExist(NewName,NewNameW))
  155. {
  156. if (Name!=NULL && *Name!=0)
  157. strcpy(Name,NewName);
  158. if (NameW!=NULL && *NameW!=0)
  159. wcscpy(NameW,NewNameW);
  160. break;
  161. }
  162. if (FileVer>=1000000)
  163. return(false);
  164. }
  165. return(true);
  166. }
  167. #if defined(_WIN_ALL) && !defined(_WIN_CE)
  168. // If we find a file, which short name is equal to 'Name', we try to change
  169. // its short name, while preserving the long name. It helps when unpacking
  170. // an archived file, which long name is equal to short name of already
  171. // existing file. Otherwise we would overwrite the already existing file,
  172. // even though its long name does not match the name of unpacking file.
  173. bool UpdateExistingShortName(wchar *Name)
  174. {
  175. // 'Name' is the name of file which we want to create. Let's check
  176. // if file with such name is exist. If it does not, we return.
  177. FindData fd;
  178. if (!FindFile::FastFind(NULL,Name,&fd))
  179. return(false);
  180. // We continue only if file has a short name, which does not match its
  181. // long name, and this short name is equal to name of file which we need
  182. // to create.
  183. if (*fd.ShortName==0 || wcsicomp(PointToName(fd.NameW),fd.ShortName)==0 ||
  184. wcsicomp(PointToName(Name),fd.ShortName)!=0)
  185. return(false);
  186. // Generate the temporary new name for existing file.
  187. wchar NewName[NM];
  188. *NewName=0;
  189. for (int I=0;I<10000 && *NewName==0;I+=123)
  190. {
  191. // Here we copy the path part of file to create. We'll make the temporary
  192. // file in the same folder.
  193. wcsncpyz(NewName,Name,ASIZE(NewName));
  194. // Here we set the random name part.
  195. sprintfw(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
  196. // If such file is already exist, try next random name.
  197. if (FileExist(NULL,NewName))
  198. *NewName=0;
  199. }
  200. // If we could not generate the name not used by any other file, we return.
  201. if (*NewName==0)
  202. return(false);
  203. // FastFind returns the name without path, but we need the fully qualified
  204. // name for renaming, so we use the path from file to create and long name
  205. // from existing file.
  206. wchar FullName[NM];
  207. wcsncpyz(FullName,Name,ASIZE(FullName));
  208. wcscpy(PointToName(FullName),PointToName(fd.NameW));
  209. // Rename the existing file to randomly generated name. Normally it changes
  210. // the short name too.
  211. if (!MoveFileW(FullName,NewName))
  212. return(false);
  213. // Now we need to create the temporary empty file with same name as
  214. // short name of our already existing file. We do it to occupy its previous
  215. // short name and not allow to use it again when renaming the file back to
  216. // its original long name.
  217. File KeepShortFile;
  218. bool Created=false;
  219. if (!FileExist(NULL,Name))
  220. Created=KeepShortFile.Create(NULL,Name);
  221. // Now we rename the existing file from temporary name to original long name.
  222. // Since its previous short name is occupied by another file, it should
  223. // get another short name.
  224. MoveFileW(NewName,FullName);
  225. if (Created)
  226. {
  227. // Delete the temporary zero length file occupying the short name,
  228. KeepShortFile.Close();
  229. KeepShortFile.Delete();
  230. }
  231. // We successfully changed the short name. Maybe sometimes we'll simplify
  232. // this function by use of SetFileShortName Windows API call.
  233. // But SetFileShortName is not available in older Windows.
  234. return(true);
  235. }
  236. #endif