win32lnk.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #define SYMLINK_FLAG_RELATIVE 1
  2. typedef struct _REPARSE_DATA_BUFFER {
  3. ULONG ReparseTag;
  4. USHORT ReparseDataLength;
  5. USHORT Reserved;
  6. union {
  7. struct {
  8. USHORT SubstituteNameOffset;
  9. USHORT SubstituteNameLength;
  10. USHORT PrintNameOffset;
  11. USHORT PrintNameLength;
  12. ULONG Flags;
  13. WCHAR PathBuffer[1];
  14. } SymbolicLinkReparseBuffer;
  15. struct {
  16. USHORT SubstituteNameOffset;
  17. USHORT SubstituteNameLength;
  18. USHORT PrintNameOffset;
  19. USHORT PrintNameLength;
  20. WCHAR PathBuffer[1];
  21. } MountPointReparseBuffer;
  22. struct {
  23. UCHAR DataBuffer[1];
  24. } GenericReparseBuffer;
  25. };
  26. } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
  27. bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd)
  28. {
  29. return false; /* // OPENMPT ADDITION
  30. static bool PrivSet=false;
  31. if (!PrivSet)
  32. {
  33. SetPrivilege(SE_RESTORE_NAME);
  34. // Not sure if we really need it, but let's request anyway.
  35. SetPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME);
  36. PrivSet=true;
  37. }
  38. const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024;
  39. Array<byte> Buf(BufSize);
  40. REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0];
  41. wchar SubstName[NM];
  42. wcsncpyz(SubstName,hd->RedirName,ASIZE(SubstName));
  43. size_t SubstLength=wcslen(SubstName);
  44. wchar PrintName[NM],*PrintNameSrc=SubstName,*PrintNameDst=PrintName;
  45. bool WinPrefix=wcsncmp(PrintNameSrc,L"\\??\\",4)==0;
  46. if (WinPrefix)
  47. PrintNameSrc+=4;
  48. if (WinPrefix && wcsncmp(PrintNameSrc,L"UNC\\",4)==0)
  49. {
  50. *(PrintNameDst++)='\\'; // Insert second \ in beginning of share name.
  51. PrintNameSrc+=3;
  52. }
  53. wcscpy(PrintNameDst,PrintNameSrc);
  54. size_t PrintLength=wcslen(PrintName);
  55. bool AbsPath=WinPrefix;
  56. // IsFullPath is not really needed here, AbsPath check is enough.
  57. // We added it just for extra safety, in case some Windows version would
  58. // allow to create absolute targets with SYMLINK_FLAG_RELATIVE.
  59. // Use hd->FileName instead of Name, since Name can include the destination
  60. // path as a prefix, which can confuse IsRelativeSymlinkSafe algorithm.
  61. if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) ||
  62. !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
  63. return false;
  64. CreatePath(Name,true,Cmd->DisableNames);
  65. // Overwrite prompt was already issued and confirmed earlier, so we can
  66. // remove existing symlink or regular file here. PrepareToDelete was also
  67. // called earlier inside of uiAskReplaceEx.
  68. if (FileExist(Name))
  69. if (IsDir(GetFileAttr(Name)))
  70. DelDir(Name);
  71. else
  72. DelFile(Name);
  73. // 'DirTarget' check is important for Unix symlinks to directories.
  74. // Unix symlinks do not have their own 'directory' attribute.
  75. if (hd->Dir || hd->DirTarget)
  76. {
  77. if (!CreateDirectory(Name,NULL))
  78. {
  79. uiMsg(UIERROR_DIRCREATE,UINULL,Name);
  80. ErrHandler.SetErrorCode(RARX_CREATE);
  81. return false;
  82. }
  83. }
  84. else
  85. {
  86. HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
  87. if (hFile == INVALID_HANDLE_VALUE)
  88. {
  89. ErrHandler.CreateErrorMsg(Name);
  90. return false;
  91. }
  92. CloseHandle(hFile);
  93. }
  94. if (hd->RedirType==FSREDIR_JUNCTION)
  95. {
  96. rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT;
  97. rdb->ReparseDataLength=USHORT(
  98. sizeof(rdb->MountPointReparseBuffer.SubstituteNameOffset)+
  99. sizeof(rdb->MountPointReparseBuffer.SubstituteNameLength)+
  100. sizeof(rdb->MountPointReparseBuffer.PrintNameOffset)+
  101. sizeof(rdb->MountPointReparseBuffer.PrintNameLength)+
  102. (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
  103. rdb->Reserved=0;
  104. rdb->MountPointReparseBuffer.SubstituteNameOffset=0;
  105. rdb->MountPointReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
  106. wcscpy(rdb->MountPointReparseBuffer.PathBuffer,SubstName);
  107. rdb->MountPointReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
  108. rdb->MountPointReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
  109. wcscpy(rdb->MountPointReparseBuffer.PathBuffer+SubstLength+1,PrintName);
  110. }
  111. else
  112. if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_UNIXSYMLINK)
  113. {
  114. rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK;
  115. rdb->ReparseDataLength=USHORT(
  116. sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset)+
  117. sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameLength)+
  118. sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameOffset)+
  119. sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameLength)+
  120. sizeof(rdb->SymbolicLinkReparseBuffer.Flags)+
  121. (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
  122. rdb->Reserved=0;
  123. rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset=0;
  124. rdb->SymbolicLinkReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
  125. wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer,SubstName);
  126. rdb->SymbolicLinkReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
  127. rdb->SymbolicLinkReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
  128. wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstLength+1,PrintName);
  129. rdb->SymbolicLinkReparseBuffer.Flags=AbsPath ? 0:SYMLINK_FLAG_RELATIVE;
  130. }
  131. else
  132. return false;
  133. HANDLE hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,0,NULL,
  134. OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT|
  135. FILE_FLAG_BACKUP_SEMANTICS,NULL);
  136. if (hFile==INVALID_HANDLE_VALUE)
  137. {
  138. ErrHandler.CreateErrorMsg(Name);
  139. ErrHandler.SetErrorCode(RARX_CREATE);
  140. return false;
  141. }
  142. DWORD Returned;
  143. if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb,
  144. FIELD_OFFSET(REPARSE_DATA_BUFFER,GenericReparseBuffer)+
  145. rdb->ReparseDataLength,NULL,0,&Returned,NULL))
  146. {
  147. CloseHandle(hFile);
  148. uiMsg(UIERROR_SLINKCREATE,UINULL,Name);
  149. DWORD LastError=GetLastError();
  150. if ((LastError==ERROR_ACCESS_DENIED || LastError==ERROR_PRIVILEGE_NOT_HELD) &&
  151. !IsUserAdmin())
  152. uiMsg(UIERROR_NEEDADMIN);
  153. ErrHandler.SysErrMsg();
  154. ErrHandler.SetErrorCode(RARX_CREATE);
  155. if (hd->Dir)
  156. RemoveDirectory(Name);
  157. else
  158. DeleteFile(Name);
  159. return false;
  160. }
  161. File LinkFile;
  162. LinkFile.SetHandle(hFile);
  163. LinkFile.SetOpenFileTime(
  164. Cmd->xmtime==EXTTIME_NONE ? NULL:&hd->mtime,
  165. Cmd->xctime==EXTTIME_NONE ? NULL:&hd->ctime,
  166. Cmd->xatime==EXTTIME_NONE ? NULL:&hd->atime);
  167. LinkFile.Close();
  168. if (!Cmd->IgnoreGeneralAttr)
  169. SetFileAttr(Name,hd->FileAttr);
  170. return true;
  171. */ // OPENMPT ADDITION
  172. }