Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
12 KiB

  1. #define UNICODE
  2. #define _UNICODE
  3. #include <nt.h>
  4. #include <ntrtl.h>
  5. #include <nturtl.h>
  6. #include <tchar.h>
  7. #include "compdir.h"
  8. #define SHARE_ALL (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
  9. #define lstrchr wcschr
  10. typedef VOID (*RtlFreeUnicodeStringFunction)();
  11. typedef ULONG (*RtlNtStatusToDosErrorFunction)();
  12. typedef NTSTATUS (*NtCloseFunction)();
  13. typedef NTSTATUS (*NtSetInformationFileFunction)();
  14. typedef VOID (*RtlInitUnicodeStringFunction)();
  15. typedef NTSTATUS (*NtOpenFileFunction)();
  16. typedef BOOLEAN (*RtlCreateUnicodeStringFromAsciizFunction)();
  17. typedef NTSTATUS (*NtQueryInformationFileFunction)();
  18. typedef NTSTATUS (*NtFsControlFileFunction)();
  19. typedef NTSTATUS (*RtlDosPathNameToNtPathName_UFunction)();
  20. RtlFreeUnicodeStringFunction CDRtlFreeUnicodeString;
  21. RtlNtStatusToDosErrorFunction CDRtlNtStatusToDosError;
  22. NtCloseFunction CDNtClose;
  23. NtSetInformationFileFunction CDNtSetInformationFile;
  24. RtlInitUnicodeStringFunction CDRtlInitUnicodeString;
  25. NtOpenFileFunction CDNtOpenFile;
  26. RtlCreateUnicodeStringFromAsciizFunction CDRtlCreateUnicodeStringFromAsciiz;
  27. NtQueryInformationFileFunction CDNtQueryInformationFile;
  28. NtFsControlFileFunction CDNtFsControlFile;
  29. RtlDosPathNameToNtPathName_UFunction CDRtlDosPathNameToNtPathName_U;
  30. BOOL InitializeNtDllFunctions()
  31. {
  32. CDRtlFreeUnicodeString = (RtlFreeUnicodeStringFunction) GetProcAddress( NtDll, "RtlFreeUnicodeString");
  33. if (CDRtlFreeUnicodeString == NULL) return FALSE;
  34. CDRtlNtStatusToDosError = (RtlNtStatusToDosErrorFunction) GetProcAddress( NtDll, "RtlNtStatusToDosError");
  35. if (CDRtlNtStatusToDosError == NULL) return FALSE;
  36. CDNtClose = (NtCloseFunction) GetProcAddress( NtDll, "NtClose");
  37. if (CDNtClose == NULL) return FALSE;
  38. CDNtSetInformationFile = (NtSetInformationFileFunction) GetProcAddress( NtDll, "NtSetInformationFile");
  39. if (CDNtSetInformationFile == NULL) return FALSE;
  40. CDRtlInitUnicodeString = (RtlInitUnicodeStringFunction) GetProcAddress( NtDll, "RtlInitUnicodeString");
  41. if (CDRtlInitUnicodeString == NULL) return FALSE;
  42. CDNtOpenFile = (NtOpenFileFunction) GetProcAddress( NtDll, "NtOpenFile");
  43. if (CDNtOpenFile == NULL) return FALSE;
  44. CDRtlCreateUnicodeStringFromAsciiz = (RtlCreateUnicodeStringFromAsciizFunction) GetProcAddress( NtDll, "RtlCreateUnicodeStringFromAsciiz");
  45. if (CDRtlCreateUnicodeStringFromAsciiz == NULL) return FALSE;
  46. CDNtQueryInformationFile = (NtQueryInformationFileFunction) GetProcAddress( NtDll, "NtQueryInformationFile");
  47. if (CDNtQueryInformationFile == NULL) return FALSE;
  48. CDNtFsControlFile = (NtFsControlFileFunction)GetProcAddress( NtDll, "NtFsControlFile");
  49. if (CDNtFsControlFile == NULL) return FALSE;
  50. CDRtlDosPathNameToNtPathName_U = (RtlDosPathNameToNtPathName_UFunction)GetProcAddress( NtDll, "RtlDosPathNameToNtPathName_U");
  51. if (CDRtlDosPathNameToNtPathName_U == NULL) return FALSE;
  52. return TRUE;
  53. }
  54. BOOL MakeLink( char *src, char *dst, BOOL Output)
  55. {
  56. WCHAR OldNameBuf[MAX_PATH + 50];
  57. WCHAR NewNameBuf[MAX_PATH + 50];
  58. HANDLE FileHandle,
  59. NewFileHandle,
  60. RootDirHandle;
  61. NTSTATUS Status;
  62. IO_STATUS_BLOCK Iosb;
  63. OBJECT_ATTRIBUTES Obj;
  64. PFILE_LINK_INFORMATION pLinkInfo;
  65. UNICODE_STRING u,
  66. uRel;
  67. WCHAR *pch, ch;
  68. UNICODE_STRING uOldName;
  69. UNICODE_STRING uNewName;
  70. UNICODE_STRING uSrc, uDst;
  71. (CDRtlCreateUnicodeStringFromAsciiz)( &uSrc, src);
  72. (CDRtlCreateUnicodeStringFromAsciiz)( &uDst, dst);
  73. lstrcpy( OldNameBuf, L"\\??\\");
  74. lstrcat( OldNameBuf, uSrc.Buffer);
  75. (CDRtlInitUnicodeString)( &uOldName, OldNameBuf);
  76. lstrcpy( NewNameBuf, L"\\??\\");
  77. lstrcat( NewNameBuf, uDst.Buffer);
  78. (CDRtlInitUnicodeString)( &uNewName, NewNameBuf);
  79. //
  80. // Open the existing pathname.
  81. //
  82. InitializeObjectAttributes( &Obj, &uOldName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  83. Status = (CDNtOpenFile)( &FileHandle, SYNCHRONIZE, &Obj, &Iosb,
  84. SHARE_ALL, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  85. if ( !NT_SUCCESS( Status))
  86. {
  87. SetLastError( ( CDRtlNtStatusToDosError)( Status));
  88. if ( Output)
  89. {
  90. fprintf( stderr, "Could not open %s", src);
  91. }
  92. return FALSE;
  93. }
  94. //
  95. // Now we need to get a handle on the root directory of the 'new'
  96. // pathname; we'll pass that in the link information, and the
  97. // rest of the path will be given relative to the root. We
  98. // depend on paths looking like "\DosDevices\X:\path".
  99. //
  100. pch = lstrchr( uNewName.Buffer + 1, '\\');
  101. ASSERT( NULL != pch);
  102. pch = lstrchr( pch + 1, '\\');
  103. if (!pch) {
  104. SetLastError(ERROR_INVALID_PARAMETER);
  105. if ( Output)
  106. {
  107. fprintf( stderr, "Invalid path %S", uNewName.Buffer);
  108. }
  109. return FALSE;
  110. }
  111. ch = pch[1];
  112. pch[1] = '\0';
  113. uNewName.Length = (USHORT)(lstrlen( uNewName.Buffer) * sizeof( WCHAR));
  114. InitializeObjectAttributes( &Obj, &uNewName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  115. Status = (CDNtOpenFile)( &RootDirHandle, SYNCHRONIZE, &Obj, &Iosb,
  116. SHARE_ALL, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
  117. pch[1] = ch;
  118. if ( !NT_SUCCESS( Status))
  119. {
  120. SetLastError( (CDRtlNtStatusToDosError)( Status));
  121. if ( Output)
  122. {
  123. fprintf( stderr, "Could not get directory handle for %s", dst);
  124. }
  125. return FALSE;
  126. }
  127. //
  128. // Now get the path relative to the root.
  129. //
  130. (CDRtlInitUnicodeString)( &uRel, &pch[1]);
  131. pLinkInfo = _alloca( sizeof( *pLinkInfo) + uRel.Length);
  132. if ( NULL == pLinkInfo)
  133. {
  134. (CDNtClose)( RootDirHandle);
  135. (CDNtClose)( FileHandle);
  136. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  137. return FALSE;
  138. }
  139. RtlMoveMemory( pLinkInfo->FileName, uRel.Buffer, uRel.Length);
  140. pLinkInfo->FileNameLength = uRel.Length;
  141. pLinkInfo->ReplaceIfExists = TRUE;
  142. pLinkInfo->RootDirectory = RootDirHandle;
  143. Status = (CDNtSetInformationFile)( FileHandle, &Iosb, pLinkInfo,
  144. sizeof( *pLinkInfo) + uRel.Length, FileLinkInformation);
  145. // If file is already linked to an open file try to delete it
  146. if ( Status == STATUS_ACCESS_DENIED)
  147. {
  148. _unlink( dst);
  149. Status = (CDNtSetInformationFile)( FileHandle, &Iosb, pLinkInfo,
  150. sizeof( *pLinkInfo) + uRel.Length, FileLinkInformation);
  151. }
  152. (CDNtClose)( RootDirHandle);
  153. (CDNtClose)( FileHandle);
  154. if ( !NT_SUCCESS( Status))
  155. {
  156. SetLastError( (CDRtlNtStatusToDosError)( Status));
  157. if ( Output)
  158. {
  159. fprintf( stderr, "Could not create link for %s", dst);
  160. }
  161. return FALSE;
  162. }
  163. (CDRtlFreeUnicodeString)( &uSrc);
  164. (CDRtlFreeUnicodeString)( &uDst);
  165. return TRUE;
  166. }
  167. int NumberOfLinks( char *FileName)
  168. {
  169. FILE_STANDARD_INFORMATION FileInfo;
  170. WCHAR FileNameBuf[MAX_PATH + 50];
  171. HANDLE FileHandle;
  172. NTSTATUS Status;
  173. IO_STATUS_BLOCK Iosb;
  174. OBJECT_ATTRIBUTES Obj;
  175. UNICODE_STRING uPrelimFileName,
  176. uFileName;
  177. (CDRtlCreateUnicodeStringFromAsciiz)( &uPrelimFileName, FileName);
  178. lstrcpy( FileNameBuf, L"\\??\\");
  179. lstrcat( FileNameBuf, uPrelimFileName.Buffer);
  180. (CDRtlInitUnicodeString)( &uFileName, FileNameBuf);
  181. InitializeObjectAttributes( &Obj, &uFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  182. Status = (CDNtOpenFile)( &FileHandle, SYNCHRONIZE, &Obj, &Iosb,
  183. SHARE_ALL, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  184. if ( !NT_SUCCESS( Status))
  185. {
  186. SetLastError( (CDRtlNtStatusToDosError)( Status));
  187. return 0;
  188. }
  189. Status = (CDNtQueryInformationFile)( FileHandle, &Iosb, &FileInfo,
  190. sizeof( FileInfo), FileStandardInformation);
  191. (CDNtClose)( FileHandle);
  192. if ( !NT_SUCCESS( Status))
  193. {
  194. SetLastError( (CDRtlNtStatusToDosError)( Status));
  195. return 0;
  196. }
  197. return FileInfo.NumberOfLinks;
  198. }
  199. BOOL
  200. SisCopyFile(
  201. LPCSTR lpExistingFileName,
  202. LPCSTR lpNewFileName,
  203. BOOL bFailIfExists,
  204. LPBOOL fTrySis
  205. )
  206. {
  207. BOOL ok;
  208. DWORD err;
  209. NTSTATUS Status;
  210. HANDLE volHandle;
  211. UNICODE_STRING srcFileName, dstFileName;
  212. UNICODE_STRING srcDosFileName, dstDosFileName;
  213. PSI_COPYFILE copyFile;
  214. UCHAR Buffer[(sizeof(SI_COPYFILE) + MAX_PATH * 2) * sizeof(WCHAR)];
  215. OBJECT_ATTRIBUTES objectAttributes;
  216. IO_STATUS_BLOCK ioStatusBlock;
  217. int i;
  218. copyFile = (PSI_COPYFILE)Buffer;
  219. srcFileName.Buffer = NULL;
  220. dstFileName.Buffer = NULL;
  221. srcDosFileName.Buffer = NULL;
  222. srcDosFileName.Buffer = NULL;
  223. //
  224. // Convert the ansii names to unicode and place in the copyFile buffer.
  225. //
  226. ok = CDRtlCreateUnicodeStringFromAsciiz( &srcDosFileName, lpExistingFileName );
  227. if (!ok) {
  228. return FALSE;
  229. }
  230. ok = CDRtlDosPathNameToNtPathName_U( srcDosFileName.Buffer, &srcFileName, NULL, NULL );
  231. if (!ok) {
  232. goto error;
  233. }
  234. CDRtlFreeUnicodeString( &srcDosFileName );
  235. ok = CDRtlCreateUnicodeStringFromAsciiz( &dstDosFileName, lpNewFileName );
  236. if (!ok) {
  237. goto error;
  238. }
  239. ok = CDRtlDosPathNameToNtPathName_U( dstDosFileName.Buffer, &dstFileName, NULL, NULL );
  240. if (!ok) {
  241. goto error;
  242. }
  243. CDRtlFreeUnicodeString( &dstDosFileName );
  244. copyFile->SourceFileNameLength = srcFileName.Length + sizeof(WCHAR);
  245. copyFile->DestinationFileNameLength = dstFileName.Length + sizeof(WCHAR);
  246. copyFile->Flags = bFailIfExists ? 0 : COPYFILE_SIS_REPLACE;
  247. RtlCopyMemory(
  248. &copyFile->FileNameBuffer[0],
  249. srcFileName.Buffer,
  250. copyFile->SourceFileNameLength);
  251. RtlCopyMemory(
  252. &copyFile->FileNameBuffer[copyFile->SourceFileNameLength / sizeof(WCHAR)],
  253. dstFileName.Buffer,
  254. copyFile->DestinationFileNameLength);
  255. CDRtlFreeUnicodeString( &dstFileName );
  256. #define copyFileSize (FIELD_OFFSET(SI_COPYFILE, FileNameBuffer) + \
  257. copyFile->SourceFileNameLength + \
  258. copyFile->DestinationFileNameLength)
  259. //
  260. // Get a handle to the source file's containing directory to pass into
  261. // FSCTL_SIS_COPYFILE,
  262. //
  263. for (i = srcFileName.Length / sizeof(WCHAR) - 1;
  264. i >= 0 && srcFileName.Buffer[i] != '\\';
  265. --i)
  266. continue;
  267. srcFileName.Length = (USHORT)(i * sizeof(WCHAR));
  268. InitializeObjectAttributes(
  269. &objectAttributes,
  270. &srcFileName,
  271. OBJ_CASE_INSENSITIVE,
  272. NULL,
  273. NULL);
  274. //
  275. // Need to use NtOpenFile because Win32 doesn't let you open a directory.
  276. //
  277. Status = CDNtOpenFile(
  278. &volHandle,
  279. GENERIC_READ | SYNCHRONIZE,
  280. &objectAttributes,
  281. &ioStatusBlock,
  282. SHARE_ALL,
  283. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  284. CDRtlFreeUnicodeString( &srcFileName );
  285. if (!NT_SUCCESS(Status)) {
  286. SetLastError(CDRtlNtStatusToDosError(Status));
  287. return FALSE;
  288. }
  289. //
  290. // Invoke the SIS CopyFile FsCtrl.
  291. //
  292. Status = CDNtFsControlFile(
  293. volHandle,
  294. NULL,
  295. NULL,
  296. NULL,
  297. &ioStatusBlock,
  298. FSCTL_SIS_COPYFILE,
  299. copyFile, // Input buffer
  300. copyFileSize, // Input buffer length
  301. NULL, // Output buffer
  302. 0 ); // Output buffer length
  303. CloseHandle( volHandle );
  304. if (NT_SUCCESS( Status )) {
  305. return TRUE;
  306. }
  307. if ((Status == STATUS_INVALID_DEVICE_REQUEST) || (Status == STATUS_INVALID_PARAMETER)) {
  308. *fTrySis = FALSE;
  309. }
  310. SetLastError(CDRtlNtStatusToDosError(Status));
  311. return FALSE;
  312. error:
  313. err = GetLastError();
  314. CDRtlFreeUnicodeString( &srcDosFileName );
  315. CDRtlFreeUnicodeString( &dstDosFileName );
  316. CDRtlFreeUnicodeString( &srcFileName );
  317. CDRtlFreeUnicodeString( &dstDosFileName );
  318. SetLastError(err);
  319. return FALSE;
  320. }