Leaked source code of windows server 2003
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.

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