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.

798 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. fsutil.c
  5. Abstract:
  6. Implements interface to underlying filesystem
  7. Author:
  8. Ahmed Mohamed (ahmedm) 1-Feb-2000
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntdef.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <ntddvol.h>
  18. #include <string.h>
  19. #include <assert.h>
  20. #include <malloc.h>
  21. #include "fs.h"
  22. #include "fsp.h"
  23. #include "fsutil.h"
  24. #define XFS_ENUM_FIRST 0x1
  25. #define XFS_ENUM_LAST 0x2
  26. #define XFS_ENUM_DIR 0x4
  27. typedef NTSTATUS (*PXFS_ENUM_CALLBACK)(PVOID,HANDLE,PFILE_DIRECTORY_INFORMATION);
  28. NTSTATUS
  29. xFsCreate(HANDLE *fd, HANDLE root, LPWSTR buf, int n, UINT32 flag,
  30. UINT32 attrib, UINT32 share, UINT32 *disp, UINT32 access,
  31. PVOID eabuf, int easz)
  32. {
  33. OBJECT_ATTRIBUTES objattrs;
  34. UNICODE_STRING cwspath;
  35. NTSTATUS status;
  36. IO_STATUS_BLOCK iostatus;
  37. n = n * sizeof(WCHAR);
  38. cwspath.Buffer = buf;
  39. cwspath.Length = (USHORT) n;
  40. cwspath.MaximumLength = (USHORT) n;
  41. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  42. root, NULL);
  43. // if write access is enabled, we turn on write-through bit
  44. if (access & FILE_WRITE_DATA) {
  45. flag |= FILE_WRITE_THROUGH;
  46. }
  47. *fd = INVALID_HANDLE_VALUE;
  48. status = NtCreateFile(fd,
  49. SYNCHRONIZE |
  50. access,
  51. &objattrs, &iostatus,
  52. 0,
  53. attrib,
  54. share,
  55. *disp,
  56. FILE_SYNCHRONOUS_IO_ALERT |
  57. flag,
  58. eabuf,
  59. easz);
  60. *disp = (UINT32) iostatus.Information;
  61. return status;
  62. }
  63. NTSTATUS
  64. xFsOpen(HANDLE *fd, HANDLE root, LPWSTR buf, int n, UINT32 access,
  65. UINT32 share, UINT32 flags)
  66. {
  67. OBJECT_ATTRIBUTES objattrs;
  68. UNICODE_STRING cwspath;
  69. IO_STATUS_BLOCK iostatus;
  70. n = n * sizeof(WCHAR);
  71. cwspath.Buffer = buf;
  72. cwspath.Length = (USHORT) n;
  73. cwspath.MaximumLength = (USHORT) n;
  74. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  75. root, NULL);
  76. *fd = INVALID_HANDLE_VALUE;
  77. return NtOpenFile(fd,
  78. SYNCHRONIZE |
  79. access,
  80. &objattrs,
  81. &iostatus,
  82. share,
  83. flags | FILE_SYNCHRONOUS_IO_ALERT);
  84. }
  85. NTSTATUS
  86. xFsDelete(HANDLE root, LPWSTR buf, int n)
  87. {
  88. OBJECT_ATTRIBUTES objattrs;
  89. UNICODE_STRING cwspath;
  90. n = n * sizeof(WCHAR);
  91. cwspath.Buffer = buf;
  92. cwspath.Length = (USHORT) n;
  93. cwspath.MaximumLength = (USHORT) n;
  94. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  95. root, NULL);
  96. return NtDeleteFile(&objattrs);
  97. }
  98. NTSTATUS
  99. xFsQueryObjectId(HANDLE fd, PVOID id)
  100. {
  101. NTSTATUS status;
  102. IO_STATUS_BLOCK iostatus;
  103. fs_ea_t x;
  104. fs_ea_name_t name;
  105. FsInitEa(&x);
  106. FsInitEaName(&name);
  107. status = NtQueryEaFile(fd, &iostatus,
  108. (PVOID) &x, sizeof(x),
  109. TRUE, (PVOID) &name, sizeof(name),
  110. NULL, TRUE);
  111. if (status == STATUS_SUCCESS) {
  112. fs_id_t *fid;
  113. if (iostatus.Information > sizeof(x.hdr)) {
  114. FsInitEaFid(&x, fid);
  115. memcpy(id, fid, sizeof(fs_id_t));
  116. } else {
  117. memset(id, 0, sizeof(fs_id_t));
  118. }
  119. } else {
  120. FsLog(("QueryEa failed %x\n", status));
  121. }
  122. return status;
  123. }
  124. NTSTATUS
  125. xFsRename(HANDLE fh, HANDLE root, WCHAR *dname, int n)
  126. {
  127. NTSTATUS status;
  128. IO_STATUS_BLOCK iostatus;
  129. struct {
  130. FILE_RENAME_INFORMATION x;
  131. WCHAR buf[MAXPATH];
  132. }info;
  133. info.x.ReplaceIfExists = TRUE;
  134. info.x.RootDirectory = root;
  135. ASSERT(n == (int)wcslen(dname));
  136. // convert to unicode
  137. wcscpy(info.x.FileName, dname);
  138. info.x.FileNameLength = n * 2;
  139. status = NtSetInformationFile(fh, &iostatus, (PVOID) &info, sizeof(info),
  140. FileRenameInformation);
  141. return status;
  142. }
  143. NTSTATUS
  144. xFsSetAttr(HANDLE fd, FILE_BASIC_INFORMATION *attr)
  145. {
  146. IO_STATUS_BLOCK iostatus;
  147. return NtSetInformationFile(fd, &iostatus,
  148. (PVOID) attr, sizeof(*attr),
  149. FileBasicInformation);
  150. }
  151. NTSTATUS
  152. xFsQueryAttr(HANDLE fd, FILE_NETWORK_OPEN_INFORMATION *attr)
  153. {
  154. IO_STATUS_BLOCK iostatus;
  155. return NtQueryInformationFile(fd, &iostatus,
  156. (PVOID)attr, sizeof(*attr),
  157. FileNetworkOpenInformation);
  158. }
  159. NTSTATUS
  160. xFsQueryAttrName(HANDLE root, LPWSTR buf, int n, FILE_NETWORK_OPEN_INFORMATION *attr)
  161. {
  162. NTSTATUS err;
  163. OBJECT_ATTRIBUTES objattrs;
  164. UNICODE_STRING cwspath;
  165. n = n * sizeof(WCHAR);
  166. cwspath.Buffer = buf;
  167. cwspath.Length = (USHORT) n;
  168. cwspath.MaximumLength = (USHORT) n;
  169. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  170. root, NULL);
  171. err = NtQueryFullAttributesFile(&objattrs, attr);
  172. return err;
  173. }
  174. NTSTATUS
  175. xFsReadDir(HANDLE fd, PVOID buf, int *rlen, BOOLEAN flag)
  176. {
  177. NTSTATUS err;
  178. IO_STATUS_BLOCK iostatus;
  179. err = NtQueryDirectoryFile(fd, NULL, NULL, NULL, &iostatus,
  180. (LPVOID) buf, *rlen >> 1,
  181. FileDirectoryInformation, FALSE, NULL,
  182. flag);
  183. *rlen = (int) iostatus.Information;
  184. return err;
  185. }
  186. LPWSTR
  187. xFsBuildRelativePath(VolInfo_t *vol, int nid, LPWSTR path)
  188. {
  189. LPWSTR share, s;
  190. share = wcschr(vol->DiskList[nid], L'\\');
  191. if (share != NULL) {
  192. s = wcsstr(path, share);
  193. if (s == path) {
  194. path += (wcslen(share)+1);
  195. s = wcsstr(path, vol->Root);
  196. if (s == path) {
  197. path += (wcslen(vol->Root) + 1);
  198. }
  199. }
  200. }
  201. return path;
  202. }
  203. NTSTATUS
  204. _FsGetHandleById(HANDLE root, fs_id_t *id, UINT32 access, HANDLE *fhdl)
  205. {
  206. ULONGLONG buf[MAXPATH/sizeof(ULONGLONG)];
  207. NTSTATUS err, status;
  208. int sz;
  209. BOOLEAN flag = TRUE;
  210. IO_STATUS_BLOCK ios;
  211. status = STATUS_OBJECT_PATH_NOT_FOUND;
  212. while (TRUE) {
  213. PFILE_DIRECTORY_INFORMATION p;
  214. err = NtQueryDirectoryFile(root, NULL, NULL, NULL, &ios,
  215. (LPVOID) buf, sizeof(buf),
  216. FileDirectoryInformation, FALSE, NULL,
  217. flag);
  218. sz = (int) ios.Information;
  219. if (err != STATUS_SUCCESS) {
  220. // FsLogError(("ReadDir failed %x flags %d\n", err, flag));
  221. break;
  222. }
  223. flag = FALSE;
  224. p = (PFILE_DIRECTORY_INFORMATION) buf;
  225. while (TRUE) {
  226. // open each entry and get its object id
  227. HANDLE fd;
  228. OBJECT_ATTRIBUTES objattrs;
  229. UNICODE_STRING cwspath;
  230. cwspath.Buffer = p->FileName;
  231. cwspath.Length = (USHORT) p->FileNameLength;
  232. cwspath.MaximumLength = (USHORT) p->FileNameLength;
  233. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  234. root, NULL);
  235. // todo: what if the file is nonsharable @ this time?
  236. err = NtOpenFile(&fd,
  237. SYNCHRONIZE | FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
  238. &objattrs,
  239. &ios,
  240. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  241. FILE_SYNCHRONOUS_IO_ALERT);
  242. if (err == STATUS_SUCCESS) {
  243. fs_id_t fid;
  244. err = xFsQueryObjectId(fd, (PVOID) &fid);
  245. if (err == STATUS_SUCCESS) {
  246. #ifdef DEBUG
  247. wprintf(L"Compare file %wZ, %I64x:%I64x with %I64x:%I64x\n",
  248. &cwspath, fid[0], fid[1], (*id)[0], (*id)[1]);
  249. #endif
  250. if (fid[0] == (*id)[0] && fid[1] == (*id)[1]) {
  251. #ifdef DEBUG
  252. wprintf(L"Found file %wZ, %I64x:%I64x\n",
  253. &cwspath, fid[0], fid[1]);
  254. #endif
  255. status = STATUS_SUCCESS;
  256. if (access != FILE_GENERIC_READ) {
  257. HANDLE nfd;
  258. err = NtOpenFile(&nfd,
  259. SYNCHRONIZE | access,
  260. &objattrs,
  261. &ios,
  262. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  263. FILE_SYNCHRONOUS_IO_ALERT);
  264. if (err == STATUS_SUCCESS) {
  265. xFsClose(fd);
  266. fd = nfd;
  267. }
  268. }
  269. *fhdl = fd;
  270. } else if (p->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  271. status = _FsGetHandleById(fd, id, access, fhdl);
  272. }
  273. }
  274. if (status == STATUS_SUCCESS)
  275. return status;
  276. xFsClose(fd);
  277. }
  278. if (p->NextEntryOffset == 0)
  279. break;
  280. p = (PFILE_DIRECTORY_INFORMATION) (((PBYTE)p) + p->NextEntryOffset);
  281. }
  282. }
  283. return status;
  284. }
  285. NTSTATUS
  286. xFsGetHandleById(HANDLE root, fs_id_t *id, UINT32 access, HANDLE *fhdl)
  287. {
  288. // open each entry and get its object id
  289. HANDLE fd;
  290. OBJECT_ATTRIBUTES objattrs;
  291. UNICODE_STRING cwspath;
  292. IO_STATUS_BLOCK ios;
  293. NTSTATUS err;
  294. cwspath.Buffer = L"";
  295. cwspath.Length = 0;
  296. cwspath.MaximumLength = 0;
  297. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  298. root, NULL);
  299. // todo: what if the file is nonsharable @ this time?
  300. err = NtOpenFile(&fd,
  301. SYNCHRONIZE | FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
  302. &objattrs,
  303. &ios,
  304. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  305. FILE_SYNCHRONOUS_IO_ALERT);
  306. if (err != STATUS_SUCCESS) {
  307. FsLogError(("Unable to duplicate handle for search %x\n", err));
  308. return err;
  309. }
  310. err = _FsGetHandleById(fd, id, access, fhdl);
  311. xFsClose(fd);
  312. return err;
  313. }
  314. DWORD
  315. xFsGetHandlePath(HANDLE fd, WCHAR *path, int *pathlen)
  316. {
  317. NTSTATUS status;
  318. IO_STATUS_BLOCK iostatus;
  319. struct {
  320. FILE_NAME_INFORMATION x;
  321. WCHAR buf[MAXPATH];
  322. }info;
  323. *path = L'\0';
  324. *pathlen = 0;
  325. status = NtQueryInformationFile(fd, &iostatus,
  326. (LPVOID) &info, sizeof(info),
  327. FileNameInformation);
  328. if (status == STATUS_SUCCESS) {
  329. int k = info.x.FileNameLength / sizeof(WCHAR);
  330. info.x.FileName[k] = L'\0';
  331. wcscpy(path, info.x.FileName);
  332. *pathlen = k;
  333. }
  334. return status;
  335. }
  336. NTSTATUS
  337. xFsGetPathById(HANDLE vfd, fs_id_t *id, WCHAR *name, int *name_len)
  338. {
  339. NTSTATUS err;
  340. HANDLE fd;
  341. err = xFsGetHandleById(vfd, id, FILE_GENERIC_READ, &fd);
  342. if (err == STATUS_SUCCESS) {
  343. err = xFsGetHandlePath(fd, name, name_len);
  344. xFsClose(fd);
  345. }
  346. return err;
  347. }
  348. NTSTATUS
  349. _xFsEnumTree(HANDLE hdl, int mode, PXFS_ENUM_CALLBACK callback, PVOID callback_arg)
  350. {
  351. NTSTATUS err = STATUS_SUCCESS;
  352. IO_STATUS_BLOCK ios;
  353. BOOLEAN flag;
  354. ULONGLONG buf[PAGESIZE/sizeof(ULONGLONG)];
  355. flag = TRUE;
  356. while (err == STATUS_SUCCESS) {
  357. PFILE_DIRECTORY_INFORMATION p;
  358. p = (PFILE_DIRECTORY_INFORMATION) buf;
  359. err = NtQueryDirectoryFile(hdl, NULL, NULL, NULL, &ios,
  360. (LPVOID) buf, sizeof(buf),
  361. FileDirectoryInformation, FALSE, NULL, flag);
  362. if (err != STATUS_SUCCESS) {
  363. break;
  364. }
  365. flag = FALSE;
  366. while (err == STATUS_SUCCESS) {
  367. BOOLEAN skip = FALSE;
  368. if (p->FileNameLength == 2 && p->FileName[0] == L'.' ||
  369. (p->FileNameLength == 4 && p->FileName[0] == L'.' && p->FileName[1] == L'.'))
  370. skip = TRUE;
  371. // skip . and ..
  372. if (skip == FALSE) {
  373. // traverse before
  374. if (mode & XFS_ENUM_FIRST) {
  375. err = callback(callback_arg, hdl, p);
  376. }
  377. if ((mode & XFS_ENUM_DIR) && (p->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  378. HANDLE fd;
  379. OBJECT_ATTRIBUTES objattrs;
  380. UNICODE_STRING cwspath;
  381. cwspath.Buffer = p->FileName;
  382. cwspath.Length = (USHORT) p->FileNameLength;
  383. cwspath.MaximumLength = (USHORT) p->FileNameLength;
  384. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  385. hdl, NULL);
  386. // todo: what if the dir is nonsharable @ this time?
  387. err = NtOpenFile(&fd,
  388. SYNCHRONIZE | FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
  389. &objattrs,
  390. &ios,
  391. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  392. FILE_SYNCHRONOUS_IO_ALERT);
  393. if (err == STATUS_SUCCESS) {
  394. err = _xFsEnumTree(fd, mode, callback, callback_arg);
  395. NtClose(fd);
  396. } else {
  397. FsLog(("Open failed on traverse dir %S %x\n", p->FileName, err));
  398. }
  399. }
  400. // traverse after
  401. if (mode & XFS_ENUM_LAST) {
  402. err = callback(callback_arg, hdl, p);
  403. }
  404. }
  405. if (p->NextEntryOffset == 0)
  406. break;
  407. p = (PFILE_DIRECTORY_INFORMATION) (((PBYTE)p) + p->NextEntryOffset);
  408. }
  409. }
  410. if (err == STATUS_NO_MORE_FILES)
  411. err = STATUS_SUCCESS;
  412. return err;
  413. }
  414. NTSTATUS
  415. xFsRemove(PVOID arg, HANDLE root, PFILE_DIRECTORY_INFORMATION item)
  416. {
  417. NTSTATUS err;
  418. OBJECT_ATTRIBUTES objattrs;
  419. UNICODE_STRING cwspath;
  420. cwspath.Buffer = item->FileName;
  421. cwspath.Length = (USHORT) item->FileNameLength;
  422. cwspath.MaximumLength = (USHORT) item->FileNameLength;
  423. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  424. root, NULL);
  425. // if the file is marked read-only, we have to clear it first before we delete
  426. if (item->FileAttributes & FILE_ATTRIBUTE_READONLY) {
  427. // clear this bit in order to delete
  428. HANDLE fd;
  429. IO_STATUS_BLOCK iostatus;
  430. err = NtOpenFile(&fd,
  431. SYNCHRONIZE | (STANDARD_RIGHTS_WRITE | FILE_WRITE_ATTRIBUTES),
  432. &objattrs,
  433. &iostatus,
  434. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  435. FILE_SYNCHRONOUS_IO_ALERT);
  436. if (err == STATUS_SUCCESS) {
  437. FILE_BASIC_INFORMATION attr;
  438. memset((PVOID) &attr, 0, sizeof(attr));
  439. attr.FileAttributes = item->FileAttributes & ~FILE_ATTRIBUTE_READONLY;
  440. err = NtSetInformationFile(fd, &iostatus,
  441. (PVOID) &attr, sizeof(attr),
  442. FileBasicInformation);
  443. xFsClose(fd);
  444. }
  445. }
  446. err = NtDeleteFile(&objattrs);
  447. FsLog(("xFsRemove: '%wZ' err 0x%x\n", &cwspath, err));
  448. return err;
  449. }
  450. NTSTATUS
  451. xFsCopy(PVOID arg, HANDLE root, PFILE_DIRECTORY_INFORMATION item)
  452. {
  453. WCHAR *name = item->FileName;
  454. int name_len = item->FileNameLength / sizeof(WCHAR);
  455. NTSTATUS err;
  456. err = xFsDupFile(root, (HANDLE) arg, name, name_len, TRUE);
  457. return err;
  458. }
  459. // copy all files from mvfd to vfd.
  460. NTSTATUS
  461. xFsCopyTree(HANDLE mvfd, HANDLE vfd)
  462. {
  463. NTSTATUS err;
  464. // first, remove all files in vfd
  465. FsLog(("CopyTree: remove first\n"));
  466. err = _xFsEnumTree(vfd, XFS_ENUM_LAST|XFS_ENUM_DIR, xFsRemove, NULL);
  467. // copy files
  468. if (err == STATUS_SUCCESS) {
  469. FsLog(("CopyTree: copy second\n"));
  470. err = _xFsEnumTree(mvfd, XFS_ENUM_FIRST, xFsCopy, (PVOID) vfd);
  471. }
  472. FsLog(("CopyTree: exit %x\n", err));
  473. return err;
  474. }
  475. // delete all files
  476. NTSTATUS
  477. xFsDeleteTree(HANDLE vfd)
  478. {
  479. // remove all files in vfd
  480. return _xFsEnumTree(vfd, XFS_ENUM_LAST|XFS_ENUM_DIR, xFsRemove, NULL);
  481. }
  482. NTSTATUS
  483. xFsTouch(PVOID arg, HANDLE root, PFILE_DIRECTORY_INFORMATION item)
  484. {
  485. NTSTATUS err;
  486. OBJECT_ATTRIBUTES objattrs;
  487. UNICODE_STRING cwspath;
  488. cwspath.Buffer = item->FileName;
  489. cwspath.Length = (USHORT) item->FileNameLength;
  490. cwspath.MaximumLength = (USHORT) item->FileNameLength;
  491. InitializeObjectAttributes(&objattrs, &cwspath, OBJ_CASE_INSENSITIVE,
  492. root, NULL);
  493. // if the file is marked read-only or directory then skip it
  494. if (!(item->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY))) {
  495. HANDLE fd;
  496. IO_STATUS_BLOCK iostatus;
  497. err = NtOpenFile(&fd,
  498. SYNCHRONIZE | FILE_GENERIC_READ,
  499. &objattrs,
  500. &iostatus,
  501. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  502. FILE_SYNCHRONOUS_IO_ALERT);
  503. if (err == STATUS_SUCCESS) {
  504. char buf[1];
  505. LARGE_INTEGER off;
  506. off.QuadPart = 0;
  507. err = NtReadFile(fd, NULL, NULL, NULL, &iostatus, buf, sizeof(buf), &off, NULL);
  508. xFsClose(fd);
  509. if (err != STATUS_SUCCESS)
  510. FsLogError(("xFsTouch: read '%wZ' failed 0x%x\n", &cwspath, err));
  511. } else {
  512. FsLogError(("xFsTouch: open '%wZ' failed 0x%x\n", &cwspath, err));
  513. }
  514. }
  515. return STATUS_SUCCESS;
  516. }
  517. // touch each file
  518. NTSTATUS
  519. xFsTouchTree(HANDLE mvfd)
  520. {
  521. return _xFsEnumTree(mvfd, XFS_ENUM_LAST | XFS_ENUM_DIR, xFsTouch, NULL);
  522. }
  523. NTSTATUS
  524. xFsDupFile(HANDLE mvfd, HANDLE vfd, WCHAR *name, int name_len, BOOLEAN flag)
  525. {
  526. NTSTATUS err;
  527. HANDLE mfd, fd;
  528. IO_STATUS_BLOCK ios;
  529. fs_id_t *fs_id;
  530. fs_ea_t xattr;
  531. FILE_NETWORK_OPEN_INFORMATION attr;
  532. FILE_BASIC_INFORMATION new_attr;
  533. char buf[PAGESIZE];
  534. // Create file on vfd with same name and attrib and extended attributes (object id)
  535. // If we created a directory, we are done.
  536. // Otherwise, copy all data from source file to new file
  537. // Open master file
  538. err = xFsOpenRD(&mfd, mvfd, name, name_len);
  539. if (err != STATUS_SUCCESS) {
  540. // We couldn't open source file. If file is locked we have to use the handle we
  541. // already have. todo:
  542. FsLog(("FsDupFile: unable to open source '%S' err %x\n", name, err));
  543. return err;
  544. }
  545. // Query name on mvfd and obtain all attributes.
  546. err = xFsQueryAttr(mfd, &attr);
  547. if (err != STATUS_SUCCESS) {
  548. FsLog(("FsDupFile: unable to query source '%S' err %x\n", name, err));
  549. xFsClose(mfd);
  550. return err;
  551. }
  552. // get objectid and set the ea stuff
  553. FsInitEa(&xattr);
  554. FsInitEaFid(&xattr, fs_id);
  555. err = xFsQueryObjectId(mfd, (PVOID) fs_id);
  556. if (err == STATUS_SUCCESS) {
  557. UINT32 disp = FILE_CREATE;
  558. err = xFsCreate(&fd, vfd, name, name_len,
  559. (attr.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ?
  560. FILE_DIRECTORY_FILE : 0),
  561. attr.FileAttributes,
  562. FILE_SHARE_READ | FILE_SHARE_WRITE,
  563. &disp,
  564. FILE_GENERIC_EXECUTE | FILE_GENERIC_WRITE,
  565. (PVOID) &xattr,
  566. sizeof(xattr));
  567. if (err == STATUS_SUCCESS) {
  568. assert(disp == FILE_CREATED);
  569. // if file we need to copy data and set access flags
  570. if (!(attr.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  571. int buflen = sizeof(buf);
  572. LARGE_INTEGER off;
  573. off.LowPart = 0;
  574. off.HighPart = 0;
  575. while (1) {
  576. err = NtReadFile(mfd, NULL, NULL, NULL, &ios, buf, buflen, &off, NULL);
  577. if (err == STATUS_PENDING) {
  578. EventWait(mfd);
  579. err = ios.Status;
  580. }
  581. if (err != STATUS_SUCCESS) {
  582. break;
  583. }
  584. err = NtWriteFile(fd, NULL, NULL, NULL, &ios, buf, (ULONG)ios.Information,
  585. &off, NULL);
  586. if (err == STATUS_PENDING) {
  587. EventWait(fd);
  588. err = ios.Status;
  589. }
  590. if (err != STATUS_SUCCESS) {
  591. break;
  592. }
  593. off.LowPart += (ULONG) ios.Information;
  594. }
  595. // adjust return code
  596. if (err == STATUS_END_OF_FILE) {
  597. err = STATUS_SUCCESS;
  598. }
  599. FsLog(("FsDupFile: '%S' err %x\n", name, err));
  600. } else if (flag == TRUE) {
  601. // call enum again
  602. err = _xFsEnumTree(mfd, XFS_ENUM_FIRST, xFsCopy, (PVOID) fd);
  603. }
  604. // set new file attributes
  605. new_attr.CreationTime = attr.CreationTime;
  606. new_attr.LastAccessTime = attr.LastAccessTime;
  607. new_attr.LastWriteTime = attr.LastWriteTime;
  608. new_attr.ChangeTime = attr.ChangeTime;
  609. new_attr.FileAttributes = attr.FileAttributes;
  610. err = xFsSetAttr(fd, &new_attr);
  611. // close new file
  612. xFsClose(fd);
  613. }
  614. if (err != STATUS_SUCCESS)
  615. FsLog(("FsDupFile: unable to open/reset attr '%S' err %x\n", name, err));
  616. } else {
  617. FsLog(("FsDupFile: unable to query sid '%S' err %x, skip!\n", name, err));
  618. err = STATUS_SUCCESS;
  619. }
  620. // close master file
  621. xFsClose(mfd);
  622. return err;
  623. }