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.

2494 lines
62 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. fileio.c
  5. Abstract:
  6. This module contains the routines for performing file system functions.
  7. No other part of the server should be calling filesystem NtXXX routines
  8. directly
  9. Author:
  10. Jameel Hyder (microsoft!jameelh)
  11. Revision History:
  12. 18 Jun 1992 Initial Version
  13. Notes: Tab stop: 4
  14. --*/
  15. #define FILEIO_LOCALS
  16. #define FILENUM FILE_FILEIO
  17. #include <afp.h>
  18. #include <client.h>
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( PAGE, AfpFileIoInit)
  21. #pragma alloc_text( PAGE, AfpIoOpen)
  22. #pragma alloc_text( PAGE, AfpIoCreate)
  23. #pragma alloc_text( PAGE, AfpIoRead)
  24. #pragma alloc_text( PAGE, AfpIoWrite)
  25. #pragma alloc_text( PAGE, AfpIoQuerySize)
  26. #pragma alloc_text( PAGE, AfpIoSetSize)
  27. #pragma alloc_text( PAGE, AfpIoChangeNTModTime)
  28. #pragma alloc_text( PAGE, AfpIoQueryTimesnAttr)
  29. #pragma alloc_text( PAGE, AfpIoSetTimesnAttr)
  30. #pragma alloc_text( PAGE, AfpIoQueryLongName)
  31. #pragma alloc_text( PAGE, AfpIoQueryShortName)
  32. #pragma alloc_text( PAGE, AfpIoQueryStreams)
  33. #pragma alloc_text( PAGE, AfpIoMarkFileForDelete)
  34. #pragma alloc_text( PAGE, AfpIoQueryDirectoryFile)
  35. #pragma alloc_text( PAGE, AfpIoQueryBasicInfo)
  36. #pragma alloc_text( PAGE, AfpIoClose)
  37. #pragma alloc_text( PAGE, AfpIoQueryVolumeSize)
  38. #pragma alloc_text( PAGE, AfpIoMoveAndOrRename)
  39. #pragma alloc_text( PAGE, AfpIoCopyFile1)
  40. #pragma alloc_text( PAGE, AfpIoCopyFile2)
  41. #pragma alloc_text( PAGE, AfpIoWait)
  42. #pragma alloc_text( PAGE, AfpIoConvertNTStatusToAfpStatus)
  43. #pragma alloc_text( PAGE, AfpQueryPath)
  44. #pragma alloc_text( PAGE, AfpIoIsSupportedDevice)
  45. #endif
  46. /*** AfpFileIoInit
  47. *
  48. * Initialize various strings that we use for stream names etc.
  49. */
  50. NTSTATUS
  51. AfpFileIoInit(
  52. VOID
  53. )
  54. {
  55. // NTFS Stream names
  56. RtlInitUnicodeString(&AfpIdDbStream, AFP_IDDB_STREAM);
  57. RtlInitUnicodeString(&AfpDesktopStream, AFP_DT_STREAM);
  58. RtlInitUnicodeString(&AfpResourceStream, AFP_RESC_STREAM);
  59. RtlInitUnicodeString(&AfpInfoStream, AFP_INFO_STREAM);
  60. RtlInitUnicodeString(&AfpCommentStream, AFP_COMM_STREAM);
  61. RtlInitUnicodeString(&AfpDataStream, L"");
  62. // Directory enumeration names to ignore
  63. RtlInitUnicodeString(&Dot,L".");
  64. RtlInitUnicodeString(&DotDot,L"..");
  65. // Supported file systems
  66. RtlInitUnicodeString(&afpNTFSName, AFP_NTFS);
  67. RtlInitUnicodeString(&afpCDFSName, AFP_CDFS);
  68. RtlInitUnicodeString(&afpAHFSName, AFP_AHFS);
  69. // Prepended to full path names originating at drive letter
  70. RtlInitUnicodeString(&DosDevices, AFP_DOSDEVICES);
  71. // CopyFile stream not to create
  72. RtlInitUnicodeString(&DataStreamName, FULL_DATA_STREAM_NAME);
  73. RtlInitUnicodeString(&FullCommentStreamName, FULL_COMMENT_STREAM_NAME);
  74. RtlInitUnicodeString(&FullResourceStreamName, FULL_RESOURCE_STREAM_NAME);
  75. RtlInitUnicodeString(&FullInfoStreamName, FULL_INFO_STREAM_NAME);
  76. // ExchangeFiles temporary filename
  77. RtlInitUnicodeString(&AfpExchangeName, AFP_TEMP_EXCHANGE_NAME);
  78. return STATUS_SUCCESS;
  79. }
  80. /*** AfpIoOpen
  81. *
  82. * Perform a file/stream open. The stream is specified by a manifest rather
  83. * than a name. The entity can only be opened by name (Not by ID).
  84. * If a stream other than the DATA stream is to be opened, then
  85. * the phRelative handle MUST be that of the unnamed (that is, DATA) stream
  86. * of the file/dir itself.
  87. */
  88. NTSTATUS
  89. AfpIoOpen(
  90. IN PFILESYSHANDLE phRelative OPTIONAL,
  91. IN DWORD StreamId,
  92. IN DWORD OpenOptions,
  93. IN PUNICODE_STRING pObject,
  94. IN DWORD AfpAccess, // FILEIO_ACCESS_XXX desired access
  95. IN DWORD AfpDenyMode, // FILIEO_DENY_XXX
  96. IN BOOLEAN CheckAccess,
  97. OUT PFILESYSHANDLE pNewHandle
  98. )
  99. {
  100. OBJECT_ATTRIBUTES ObjAttr;
  101. IO_STATUS_BLOCK IoStsBlk;
  102. NTSTATUS Status;
  103. NTSTATUS Status2;
  104. UNICODE_STRING UName;
  105. HANDLE hRelative = NULL;
  106. BOOLEAN FreeBuf = False;
  107. #ifdef PROFILING
  108. TIME TimeS, TimeE, TimeD;
  109. AfpGetPerfCounter(&TimeS);
  110. #endif
  111. PAGED_CODE( );
  112. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  113. ("AfpIoOpen entered\n"));
  114. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  115. #if DBG
  116. pNewHandle->Signature = FSH_SIGNATURE;
  117. #endif
  118. // Assume Failure
  119. pNewHandle->fsh_FileHandle = NULL;
  120. if (phRelative != NULL)
  121. {
  122. ASSERT(VALID_FSH(phRelative));
  123. hRelative = phRelative->fsh_FileHandle;
  124. }
  125. ASSERT (StreamId < AFP_STREAM_MAX);
  126. ASSERT ((pObject->Length > 0) || (phRelative != NULL));
  127. if (StreamId != AFP_STREAM_DATA)
  128. {
  129. if (pObject->Length > 0)
  130. {
  131. UName.Length =
  132. UName.MaximumLength = pObject->Length + AFP_MAX_STREAMNAME*sizeof(WCHAR);
  133. UName.Buffer = (LPWSTR)AfpAllocNonPagedMemory(UName.Length);
  134. if (UName.Buffer == NULL)
  135. {
  136. return STATUS_NO_MEMORY;
  137. }
  138. AfpCopyUnicodeString(&UName, pObject);
  139. RtlAppendUnicodeStringToString(&UName, &AfpStreams[StreamId]);
  140. pObject = &UName;
  141. FreeBuf = True;
  142. }
  143. else
  144. {
  145. pObject = &AfpStreams[StreamId];
  146. }
  147. }
  148. InitializeObjectAttributes(&ObjAttr,
  149. pObject,
  150. OBJ_CASE_INSENSITIVE,
  151. hRelative,
  152. NULL); // no security descriptor
  153. ObjAttr.SecurityQualityOfService = &AfpSecurityQOS;
  154. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  155. ("AfpIoOpen: about to call NtOpenFile\n"));
  156. // If we are opening for RWCTRL, then specify to use privilege.
  157. if (AfpAccess & (WRITE_DAC | WRITE_OWNER))
  158. {
  159. OpenOptions |= FILE_OPEN_FOR_BACKUP_INTENT;
  160. }
  161. Status = IoCreateFile(&pNewHandle->fsh_FileHandle,
  162. AfpAccess,
  163. &ObjAttr,
  164. &IoStsBlk,
  165. NULL,
  166. 0,
  167. AfpDenyMode,
  168. FILE_OPEN,
  169. OpenOptions,
  170. (PVOID)NULL,
  171. 0L,
  172. CreateFileTypeNone,
  173. (PVOID)NULL,
  174. CheckAccess ? IO_FORCE_ACCESS_CHECK : 0);
  175. if (Status != 0)
  176. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  177. ("AfpIoOpen: IoCreateFile returned 0x%lx, %Z\n",Status,
  178. ObjAttr.ObjectName));
  179. if (FreeBuf)
  180. AfpFreeMemory(UName.Buffer);
  181. if (NT_SUCCESS(Status))
  182. {
  183. Status = ObReferenceObjectByHandle(pNewHandle->fsh_FileHandle,
  184. AfpAccess,
  185. NULL,
  186. KernelMode,
  187. (PVOID *)(&pNewHandle->fsh_FileObject),
  188. NULL);
  189. if (!NT_SUCCESS(Status)) {
  190. ASSERT(VALID_FSH((PFILESYSHANDLE)&pNewHandle->fsh_FileHandle)) ;
  191. Status2 = NtClose(pNewHandle->fsh_FileHandle);
  192. pNewHandle->fsh_FileHandle = NULL;
  193. ASSERT(NT_SUCCESS(Status2));
  194. }
  195. else
  196. {
  197. pNewHandle->fsh_DeviceObject = IoGetRelatedDeviceObject(pNewHandle->fsh_FileObject);
  198. (ULONG_PTR)(pNewHandle->fsh_FileObject) |= 1;
  199. ASSERT(NT_SUCCESS(Status));
  200. afpUpdateOpenFiles(True, True);
  201. #ifdef PROFILING
  202. AfpGetPerfCounter(&TimeE);
  203. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  204. if (OpenOptions == FILEIO_OPEN_DIR)
  205. {
  206. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_OpenCountDR);
  207. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_OpenTimeDR,
  208. TimeD,
  209. &AfpStatisticsLock);
  210. }
  211. else
  212. {
  213. if ((AfpAccess & FILEIO_ACCESS_DELETE) == FILEIO_ACCESS_DELETE)
  214. {
  215. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_OpenCountDL);
  216. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_OpenTimeDL,
  217. TimeD,
  218. &AfpStatisticsLock);
  219. }
  220. else if (((AfpAccess & FILEIO_ACCESS_READWRITE) == FILEIO_ACCESS_READ) ||
  221. ((AfpAccess & FILEIO_ACCESS_READWRITE) == FILEIO_ACCESS_WRITE) ||
  222. ((AfpAccess & FILEIO_ACCESS_READWRITE) == FILEIO_ACCESS_READWRITE))
  223. {
  224. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_OpenCountRW);
  225. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_OpenTimeRW,
  226. TimeD,
  227. &AfpStatisticsLock);
  228. }
  229. else if (AfpAccess & (WRITE_DAC | WRITE_OWNER))
  230. {
  231. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_OpenCountWC);
  232. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_OpenTimeWC,
  233. TimeD,
  234. &AfpStatisticsLock);
  235. }
  236. else if (AfpAccess & READ_CONTROL)
  237. {
  238. INTERLOCKED_INCREMENT_LONG( &AfpServerProfile->perf_OpenCountRC);
  239. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_OpenTimeRC,
  240. TimeD,
  241. &AfpStatisticsLock);
  242. }
  243. else // Ought to be read-attributes or write-attributes
  244. {
  245. ASSERT ((AfpAccess == FILEIO_ACCESS_NONE) ||
  246. (AfpAccess == (FILEIO_ACCESS_NONE | FILE_WRITE_ATTRIBUTES)));
  247. INTERLOCKED_INCREMENT_LONG( &AfpServerProfile->perf_OpenCountRA);
  248. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_OpenTimeRA,
  249. TimeD,
  250. &AfpStatisticsLock);
  251. }
  252. }
  253. #endif
  254. }
  255. }
  256. return Status;
  257. }
  258. /*** AfpIoCreate
  259. *
  260. * Perform a file/stream create. The stream is specified by a manifest rather
  261. * than a name. If a stream other than the DATA stream is to be created, then
  262. * the phRelative handle MUST be that of either the Parent directory, or the
  263. * unnamed (that is, DATA) stream of the file/dir itself because we only use
  264. * a buffer large enough for a AFP filename plus the maximum stream name
  265. * length.
  266. */
  267. NTSTATUS
  268. AfpIoCreate(
  269. IN PFILESYSHANDLE phRelative, // create relative to this
  270. IN DWORD StreamId, // Id of stream to create
  271. IN PUNICODE_STRING pObject, // Name of file
  272. IN DWORD AfpAccess, // FILEIO_ACCESS_XXX desired access
  273. IN DWORD AfpDenyMode, // FILEIO_DENY_XXX
  274. IN DWORD CreateOptions, // File/Directory etc.
  275. IN DWORD Disposition, // Soft or hard create
  276. IN DWORD Attributes, // hidden, archive, normal, etc.
  277. IN BOOLEAN CheckAccess, // If TRUE, enforce security
  278. IN PSECURITY_DESCRIPTOR pSecDesc OPTIONAL, // Security descriptor to slap on
  279. OUT PFILESYSHANDLE pNewHandle, // Place holder for the handle
  280. OUT PDWORD pInformation OPTIONAL, // file opened, created, etc.
  281. IN PVOLDESC pVolDesc OPTIONAL, // only if NotifyPath
  282. IN PUNICODE_STRING pNotifyPath OPTIONAL,
  283. IN PUNICODE_STRING pNotifyParentPath OPTIONAL
  284. )
  285. {
  286. NTSTATUS Status;
  287. NTSTATUS Status2;
  288. OBJECT_ATTRIBUTES ObjAttr;
  289. UNICODE_STRING RealName;
  290. IO_STATUS_BLOCK IoStsBlk;
  291. HANDLE hRelative;
  292. WCHAR NameBuffer[AFP_FILENAME_LEN + 1 + AFP_MAX_STREAMNAME];
  293. BOOLEAN Queue = False;
  294. #ifdef PROFILING
  295. TIME TimeS, TimeE, TimeD;
  296. AfpGetPerfCounter(&TimeS);
  297. #endif
  298. PAGED_CODE( );
  299. ASSERT(pObject != NULL && phRelative != NULL && StreamId < AFP_STREAM_MAX);
  300. ASSERT(VALID_FSH(phRelative) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  301. #if DBG
  302. pNewHandle->Signature = FSH_SIGNATURE;
  303. #endif
  304. hRelative = phRelative->fsh_FileHandle;
  305. // Assume Failure
  306. pNewHandle->fsh_FileHandle = NULL;
  307. if (StreamId != AFP_STREAM_DATA)
  308. {
  309. ASSERT(pObject->Length <= (AFP_FILENAME_LEN*sizeof(WCHAR)));
  310. // Construct the name to pass to NtCreateFile
  311. AfpSetEmptyUnicodeString(&RealName, sizeof(NameBuffer), NameBuffer);
  312. AfpCopyUnicodeString(&RealName, pObject);
  313. RtlAppendUnicodeStringToString(&RealName, &AfpStreams[StreamId]);
  314. pObject = &RealName;
  315. }
  316. InitializeObjectAttributes(&ObjAttr,
  317. pObject,
  318. OBJ_CASE_INSENSITIVE,
  319. hRelative,
  320. pSecDesc);
  321. ObjAttr.SecurityQualityOfService = &AfpSecurityQOS;
  322. // Do not queue our changes for exclusive volumes since no notifies are posted
  323. if (ARGUMENT_PRESENT(pNotifyPath) &&
  324. !EXCLUSIVE_VOLUME(pVolDesc) &&
  325. (StreamId == AFP_STREAM_DATA))
  326. {
  327. ASSERT(VALID_VOLDESC(pVolDesc));
  328. ASSERT((Disposition == FILEIO_CREATE_HARD) ||
  329. (Disposition == FILEIO_CREATE_SOFT));
  330. Queue = True;
  331. // Queue a change for both cases.
  332. AfpQueueOurChange(pVolDesc,
  333. FILE_ACTION_ADDED,
  334. pNotifyPath,
  335. pNotifyParentPath);
  336. AfpQueueOurChange(pVolDesc,
  337. FILE_ACTION_MODIFIED,
  338. pNotifyPath,
  339. NULL);
  340. }
  341. Status = IoCreateFile(&pNewHandle->fsh_FileHandle,
  342. AfpAccess,
  343. &ObjAttr,
  344. &IoStsBlk,
  345. NULL,
  346. Attributes,
  347. AfpDenyMode,
  348. Disposition,
  349. CreateOptions,
  350. NULL,
  351. 0,
  352. CreateFileTypeNone,
  353. (PVOID)NULL,
  354. CheckAccess ? IO_FORCE_ACCESS_CHECK : 0);
  355. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  356. ("AfpIoCreate: IoCreateFile returned 0x%lx\n", Status) );
  357. if (Queue)
  358. {
  359. if (NT_SUCCESS(Status))
  360. {
  361. ASSERT((IoStsBlk.Information == FILE_CREATED) ||
  362. (IoStsBlk.Information == FILE_SUPERSEDED));
  363. // Dequeue the extra change that was queued
  364. AfpDequeueOurChange(pVolDesc,
  365. (IoStsBlk.Information == FILE_CREATED) ?
  366. FILE_ACTION_MODIFIED : FILE_ACTION_ADDED,
  367. pNotifyPath,
  368. NULL);
  369. }
  370. else
  371. {
  372. AfpDequeueOurChange(pVolDesc,
  373. FILE_ACTION_ADDED,
  374. pNotifyPath,
  375. pNotifyParentPath);
  376. AfpDequeueOurChange(pVolDesc,
  377. FILE_ACTION_MODIFIED,
  378. pNotifyPath,
  379. NULL);
  380. }
  381. }
  382. if (NT_SUCCESS(Status))
  383. {
  384. if (ARGUMENT_PRESENT(pInformation))
  385. {
  386. *pInformation = (ULONG)(IoStsBlk.Information);
  387. }
  388. Status = ObReferenceObjectByHandle(pNewHandle->fsh_FileHandle,
  389. AfpAccess,
  390. NULL,
  391. KernelMode,
  392. (PVOID *)(&pNewHandle->fsh_FileObject),
  393. NULL);
  394. if (!NT_SUCCESS(Status))
  395. {
  396. ASSERT(VALID_FSH((PFILESYSHANDLE)&pNewHandle->fsh_FileHandle)) ;
  397. Status2 = NtClose(pNewHandle->fsh_FileHandle);
  398. pNewHandle->fsh_FileHandle = NULL;
  399. ASSERT(NT_SUCCESS(Status2));
  400. }
  401. else
  402. {
  403. ASSERT(NT_SUCCESS(Status));
  404. pNewHandle->fsh_DeviceObject = IoGetRelatedDeviceObject(pNewHandle->fsh_FileObject);
  405. (ULONG_PTR)(pNewHandle->fsh_FileObject) |= 1;
  406. afpUpdateOpenFiles(True, True);
  407. #ifdef PROFILING
  408. AfpGetPerfCounter(&TimeE);
  409. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  410. if (StreamId == AFP_STREAM_DATA)
  411. {
  412. if (CreateOptions == FILEIO_OPEN_FILE)
  413. {
  414. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_CreateCountFIL);
  415. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_CreateTimeFIL,
  416. TimeD,
  417. &AfpStatisticsLock);
  418. }
  419. else
  420. {
  421. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_CreateCountDIR);
  422. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_CreateTimeDIR,
  423. TimeD,
  424. &AfpStatisticsLock);
  425. }
  426. }
  427. else
  428. {
  429. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_CreateCountSTR);
  430. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_CreateTimeSTR,
  431. TimeD,
  432. &AfpStatisticsLock);
  433. }
  434. #endif
  435. }
  436. }
  437. return Status;
  438. }
  439. /*** AfpIoRead
  440. *
  441. * Perform file read. Just a wrapper over NtReadFile.
  442. */
  443. AFPSTATUS
  444. AfpIoRead(
  445. IN PFILESYSHANDLE pFileHandle,
  446. IN PFORKOFFST pForkOffset,
  447. IN LONG SizeReq,
  448. OUT PLONG pSizeRead,
  449. OUT PBYTE pBuffer
  450. )
  451. {
  452. NTSTATUS Status;
  453. DWORD Key = 0;
  454. IO_STATUS_BLOCK IoStsBlk;
  455. PAGED_CODE( );
  456. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  457. ("AfpIoRead Entered, Size %lx, Key %lx\n",
  458. SizeReq, Key));
  459. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() == LOW_LEVEL));
  460. ASSERT (INTERNAL_HANDLE(pFileHandle));
  461. *pSizeRead = 0;
  462. Status = NtReadFile(pFileHandle->fsh_FileHandle,
  463. NULL,
  464. NULL,
  465. NULL,
  466. &IoStsBlk,
  467. pBuffer,
  468. (DWORD)SizeReq,
  469. pForkOffset,
  470. &Key);
  471. if (NT_SUCCESS(Status))
  472. {
  473. *pSizeRead = (LONG)IoStsBlk.Information;
  474. INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataReadInternal,
  475. (ULONG)(IoStsBlk.Information),
  476. &AfpStatisticsLock);
  477. }
  478. else
  479. {
  480. if (Status == STATUS_FILE_LOCK_CONFLICT)
  481. Status = AFP_ERR_LOCK;
  482. else if (Status == STATUS_END_OF_FILE)
  483. Status = AFP_ERR_EOF;
  484. else
  485. {
  486. AFPLOG_HERROR(AFPSRVMSG_CANT_READ,
  487. Status,
  488. NULL,
  489. 0,
  490. pFileHandle->fsh_FileHandle);
  491. Status = AFP_ERR_MISC;
  492. }
  493. }
  494. return Status;
  495. }
  496. /*** AfpIoWrite
  497. *
  498. * Perform file write. Just a wrapper over NtWriteFile.
  499. */
  500. AFPSTATUS
  501. AfpIoWrite(
  502. IN PFILESYSHANDLE pFileHandle,
  503. IN PFORKOFFST pForkOffset,
  504. IN LONG SizeWrite,
  505. OUT PBYTE pBuffer
  506. )
  507. {
  508. NTSTATUS Status;
  509. DWORD Key = 0;
  510. IO_STATUS_BLOCK IoStsBlk;
  511. PAGED_CODE( );
  512. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  513. ("AfpIoWrite Entered, Size %lx, Key %lx\n",
  514. SizeWrite, Key));
  515. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() == LOW_LEVEL));
  516. ASSERT (INTERNAL_HANDLE(pFileHandle));
  517. Status = NtWriteFile(pFileHandle->fsh_FileHandle,
  518. NULL,
  519. NULL,
  520. NULL,
  521. &IoStsBlk,
  522. pBuffer,
  523. (DWORD)SizeWrite,
  524. pForkOffset,
  525. &Key);
  526. if (NT_SUCCESS(Status))
  527. {
  528. INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataWrittenInternal,
  529. SizeWrite,
  530. &AfpStatisticsLock);
  531. }
  532. else
  533. {
  534. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  535. ("AfpIoWrite: NtWriteFile returned 0x%lx\n",Status));
  536. if (Status == STATUS_FILE_LOCK_CONFLICT)
  537. Status = AFP_ERR_LOCK;
  538. else
  539. {
  540. AFPLOG_HERROR(AFPSRVMSG_CANT_WRITE,
  541. Status,
  542. NULL,
  543. 0,
  544. pFileHandle->fsh_FileHandle);
  545. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  546. }
  547. }
  548. return Status;
  549. }
  550. /*** AfpIoQuerySize
  551. *
  552. * Get the current size of the fork.
  553. */
  554. AFPSTATUS FASTCALL
  555. AfpIoQuerySize(
  556. IN PFILESYSHANDLE pFileHandle,
  557. OUT PFORKSIZE pForkLength
  558. )
  559. {
  560. FILE_STANDARD_INFORMATION FStdInfo;
  561. NTSTATUS Status;
  562. IO_STATUS_BLOCK IoStsBlk;
  563. PFAST_IO_DISPATCH fastIoDispatch;
  564. PAGED_CODE( );
  565. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  566. fastIoDispatch = pFileHandle->fsh_DeviceObject->DriverObject->FastIoDispatch;
  567. if (fastIoDispatch &&
  568. fastIoDispatch->FastIoQueryStandardInfo &&
  569. fastIoDispatch->FastIoQueryStandardInfo(AfpGetRealFileObject(pFileHandle->fsh_FileObject),
  570. True,
  571. &FStdInfo,
  572. &IoStsBlk,
  573. pFileHandle->fsh_DeviceObject))
  574. {
  575. Status = IoStsBlk.Status;
  576. #ifdef PROFILING
  577. // The fast I/O path worked. Update statistics
  578. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
  579. #endif
  580. }
  581. else
  582. {
  583. #ifdef PROFILING
  584. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
  585. #endif
  586. Status = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  587. &IoStsBlk,
  588. &FStdInfo,
  589. sizeof(FStdInfo),
  590. FileStandardInformation);
  591. }
  592. if (!NT_SUCCESS((NTSTATUS)Status))
  593. {
  594. AFPLOG_HERROR(AFPSRVMSG_CANT_GET_FILESIZE,
  595. Status,
  596. NULL,
  597. 0,
  598. pFileHandle->fsh_FileHandle);
  599. return AFP_ERR_MISC; // What else can we do
  600. }
  601. *pForkLength = FStdInfo.EndOfFile;
  602. return AFP_ERR_NONE;
  603. }
  604. /*** AfpIoSetSize
  605. *
  606. * Set the size of the open fork to the value specified.
  607. *
  608. * ISSUE:
  609. * We can check the locks and resolve any lock conflicts before we go
  610. * to the filesystem. The issue that needs to be resolved here is:
  611. * Is it OK to truncate the file such that our own locks cause
  612. * conflict ?
  613. */
  614. AFPSTATUS FASTCALL
  615. AfpIoSetSize(
  616. IN PFILESYSHANDLE pFileHandle,
  617. IN LONG ForkLength
  618. )
  619. {
  620. NTSTATUS Status;
  621. FILE_END_OF_FILE_INFORMATION FEofInfo;
  622. IO_STATUS_BLOCK IoStsBlk;
  623. PAGED_CODE( );
  624. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  625. FEofInfo.EndOfFile.QuadPart = ForkLength;
  626. Status = NtSetInformationFile(pFileHandle->fsh_FileHandle,
  627. &IoStsBlk,
  628. &FEofInfo,
  629. sizeof(FEofInfo),
  630. FileEndOfFileInformation);
  631. if (!NT_SUCCESS(Status))
  632. {
  633. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  634. ("AfpIoSetSize: NtSetInformationFile returned 0x%lx\n",Status));
  635. if (Status != STATUS_FILE_LOCK_CONFLICT)
  636. AFPLOG_HERROR(AFPSRVMSG_CANT_SET_FILESIZE,
  637. Status,
  638. &ForkLength,
  639. sizeof(ForkLength),
  640. pFileHandle->fsh_FileHandle);
  641. if (Status == STATUS_DISK_FULL)
  642. {
  643. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,("AfpIoSetSize: DISK_FULL error\n"));
  644. ASSERT(0);
  645. Status = AFP_ERR_DISK_FULL;
  646. }
  647. else if (Status == STATUS_FILE_LOCK_CONFLICT)
  648. Status = AFP_ERR_LOCK;
  649. // Default error code. What else can it be ?
  650. else Status = AFP_ERR_MISC;
  651. }
  652. return Status;
  653. }
  654. /*** AfpIoChangeNTModTime
  655. *
  656. * Get the NTFS ChangeTime of a file/dir. If it is larger than the
  657. * NTFS LastWriteTime, set NTFS LastWriteTime to this time.
  658. * Return the resultant LastWriteTime in pModTime (whether changed or not).
  659. * This is used to update the modified time when the resource fork is changed
  660. * or when some other attribute changes that should cause the timestamp on
  661. * the file to change as viewed by mac.
  662. *
  663. */
  664. AFPSTATUS
  665. AfpIoChangeNTModTime(
  666. IN PFILESYSHANDLE pFileHandle,
  667. OUT PTIME pModTime
  668. )
  669. {
  670. FILE_BASIC_INFORMATION FBasicInfo;
  671. NTSTATUS Status;
  672. IO_STATUS_BLOCK IoStsBlk;
  673. PFAST_IO_DISPATCH fastIoDispatch;
  674. PAGED_CODE( );
  675. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() == LOW_LEVEL));
  676. // Set all times/attr to Zero (this will cause NTFS to update LastModTime
  677. // if there are any writes pending)
  678. RtlZeroMemory(&FBasicInfo, sizeof(FBasicInfo));
  679. Status = NtSetInformationFile(pFileHandle->fsh_FileHandle,
  680. &IoStsBlk,
  681. (PVOID)&FBasicInfo,
  682. sizeof(FBasicInfo),
  683. FileBasicInformation);
  684. if (!NT_SUCCESS(Status))
  685. {
  686. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  687. ("AfpIoChangeNTModTime: NtSetInformationFile failed with 0x%lx\n",Status));
  688. AFPLOG_HERROR(AFPSRVMSG_CANT_SET_TIMESNATTR,
  689. Status,
  690. NULL,
  691. 0,
  692. pFileHandle->fsh_FileHandle);
  693. return AFP_ERR_MISC;
  694. }
  695. // now, go and query for the updated times
  696. Status = AfpIoQueryTimesnAttr( pFileHandle,
  697. NULL,
  698. pModTime,
  699. NULL );
  700. if (!NT_SUCCESS(Status))
  701. {
  702. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  703. ("AfpIoChangeNTModTime: AfpIoQueryTimesnAttr returned 0x%lx\n",Status));
  704. }
  705. return Status;
  706. }
  707. /*** AfpIoQueryTimesnAttr
  708. *
  709. * Get the times associated with the file.
  710. */
  711. AFPSTATUS
  712. AfpIoQueryTimesnAttr(
  713. IN PFILESYSHANDLE pFileHandle,
  714. OUT PDWORD pCreatTime OPTIONAL,
  715. OUT PTIME pModTime OPTIONAL,
  716. OUT PDWORD pAttr OPTIONAL
  717. )
  718. {
  719. FILE_BASIC_INFORMATION FBasicInfo;
  720. NTSTATUS Status;
  721. IO_STATUS_BLOCK IoStsBlk;
  722. PFAST_IO_DISPATCH fastIoDispatch;
  723. #ifdef PROFILING
  724. TIME TimeS, TimeE, TimeD;
  725. AfpGetPerfCounter(&TimeS);
  726. #endif
  727. PAGED_CODE( );
  728. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  729. // Atleast something should be queried.
  730. ASSERT((pCreatTime != NULL) || (pModTime != NULL) || (pAttr != NULL));
  731. fastIoDispatch = pFileHandle->fsh_DeviceObject->DriverObject->FastIoDispatch;
  732. if (fastIoDispatch &&
  733. fastIoDispatch->FastIoQueryBasicInfo &&
  734. fastIoDispatch->FastIoQueryBasicInfo(AfpGetRealFileObject(pFileHandle->fsh_FileObject),
  735. True,
  736. &FBasicInfo,
  737. &IoStsBlk,
  738. pFileHandle->fsh_DeviceObject))
  739. {
  740. Status = IoStsBlk.Status;
  741. #ifdef PROFILING
  742. // The fast I/O path worked. Update statistics
  743. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
  744. #endif
  745. }
  746. else
  747. {
  748. #ifdef PROFILING
  749. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
  750. #endif
  751. Status = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  752. &IoStsBlk, &FBasicInfo, sizeof(FBasicInfo),
  753. FileBasicInformation);
  754. }
  755. if (NT_SUCCESS((NTSTATUS)Status))
  756. {
  757. if (pModTime != NULL)
  758. *pModTime = FBasicInfo.LastWriteTime;
  759. if (pCreatTime != NULL)
  760. *pCreatTime = AfpConvertTimeToMacFormat(&FBasicInfo.CreationTime);
  761. if (pAttr != NULL)
  762. *pAttr = FBasicInfo.FileAttributes;
  763. #ifdef PROFILING
  764. AfpGetPerfCounter(&TimeE);
  765. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  766. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_GetInfoCount);
  767. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_GetInfoTime,
  768. TimeD,
  769. &AfpStatisticsLock);
  770. #endif
  771. }
  772. else
  773. {
  774. AFPLOG_HERROR(AFPSRVMSG_CANT_GET_TIMESNATTR,
  775. Status,
  776. NULL,
  777. 0,
  778. pFileHandle->fsh_FileHandle);
  779. Status = AFP_ERR_MISC; // What else can we do
  780. }
  781. return Status;
  782. }
  783. /*** AfpIoSetTimesnAttr
  784. *
  785. * Set the times and attributes associated with the file.
  786. */
  787. AFPSTATUS
  788. AfpIoSetTimesnAttr(
  789. IN PFILESYSHANDLE pFileHandle,
  790. IN AFPTIME * pCreateTime OPTIONAL,
  791. IN AFPTIME * pModTime OPTIONAL,
  792. IN DWORD AttrSet,
  793. IN DWORD AttrClear,
  794. IN PVOLDESC pVolDesc OPTIONAL, // only if NotifyPath
  795. IN PUNICODE_STRING pNotifyPath OPTIONAL
  796. )
  797. {
  798. NTSTATUS Status;
  799. FILE_BASIC_INFORMATION FBasicInfo;
  800. IO_STATUS_BLOCK IoStsBlk;
  801. PFAST_IO_DISPATCH fastIoDispatch;
  802. BOOLEAN Queue = False;
  803. #ifdef PROFILING
  804. TIME TimeS, TimeE, TimeD;
  805. #endif
  806. PAGED_CODE( );
  807. #ifdef PROFILING
  808. AfpGetPerfCounter(&TimeS);
  809. #endif
  810. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  811. ("AfpIoSetTimesnAttr entered\n"));
  812. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  813. // At least something should be set
  814. ASSERT((pCreateTime != NULL) || (pModTime != NULL) || (AttrSet != 0) || (AttrClear != 0));
  815. // First query the information
  816. fastIoDispatch = pFileHandle->fsh_DeviceObject->DriverObject->FastIoDispatch;
  817. if (fastIoDispatch &&
  818. fastIoDispatch->FastIoQueryBasicInfo &&
  819. fastIoDispatch->FastIoQueryBasicInfo(AfpGetRealFileObject(pFileHandle->fsh_FileObject),
  820. True,
  821. &FBasicInfo,
  822. &IoStsBlk,
  823. pFileHandle->fsh_DeviceObject))
  824. {
  825. Status = IoStsBlk.Status;
  826. #ifdef PROFILING
  827. // The fast I/O path worked. Update statistics
  828. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
  829. #endif
  830. }
  831. else
  832. {
  833. #ifdef PROFILING
  834. INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
  835. #endif
  836. Status = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  837. &IoStsBlk,
  838. &FBasicInfo,
  839. sizeof(FBasicInfo),
  840. FileBasicInformation);
  841. }
  842. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  843. ("AfpIoSetTimesnAttr: NtQueryInformationFile returned 0x%lx\n",Status));
  844. if (!NT_SUCCESS((NTSTATUS)Status))
  845. {
  846. AFPLOG_HERROR(AFPSRVMSG_CANT_GET_TIMESNATTR,
  847. Status,
  848. NULL,
  849. 0,
  850. pFileHandle->fsh_FileHandle);
  851. return AFP_ERR_MISC; // What else can we do
  852. }
  853. // Set all times to Zero. This will not change it. Then set the times that are to
  854. // change
  855. FBasicInfo.CreationTime = LIZero;
  856. FBasicInfo.ChangeTime = LIZero;
  857. FBasicInfo.LastWriteTime = LIZero;
  858. FBasicInfo.LastAccessTime = LIZero;
  859. if (pCreateTime != NULL)
  860. AfpConvertTimeFromMacFormat(*pCreateTime, &FBasicInfo.CreationTime);
  861. if (pModTime != NULL)
  862. {
  863. AfpConvertTimeFromMacFormat(*pModTime, &FBasicInfo.LastWriteTime);
  864. FBasicInfo.ChangeTime = FBasicInfo.LastWriteTime;
  865. }
  866. // NTFS is not returning FILE_ATTRIBUTE_NORMAL if it is a file,
  867. // therefore we may end up trying to set attributes of 0 when we
  868. // want to clear all attributes. 0 is taken to mean you do not want
  869. // to set any attributes, so it is ignored all together by NTFS. In
  870. // this case, just tack on the normal bit so that our request is not
  871. // ignored.
  872. if (!(FBasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  873. {
  874. FBasicInfo.FileAttributes |= FILE_ATTRIBUTE_NORMAL;
  875. }
  876. FBasicInfo.FileAttributes |= AttrSet;
  877. FBasicInfo.FileAttributes &= ~AttrClear;
  878. // Do not queue our changes for exclusive volumes since no notifies are posted
  879. if (ARGUMENT_PRESENT(pNotifyPath) &&
  880. !EXCLUSIVE_VOLUME(pVolDesc))
  881. {
  882. ASSERT(VALID_VOLDESC(pVolDesc));
  883. Queue = True;
  884. AfpQueueOurChange(pVolDesc,
  885. FILE_ACTION_MODIFIED,
  886. pNotifyPath,
  887. NULL);
  888. }
  889. Status = NtSetInformationFile(pFileHandle->fsh_FileHandle,
  890. &IoStsBlk,
  891. (PVOID)&FBasicInfo,
  892. sizeof(FBasicInfo),
  893. FileBasicInformation);
  894. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  895. ("AfpIoSetTimesnAttr: NtSetInformationFile returned 0x%lx\n",Status));
  896. if (!NT_SUCCESS(Status))
  897. {
  898. if (Queue)
  899. {
  900. AfpDequeueOurChange(pVolDesc,
  901. FILE_ACTION_MODIFIED,
  902. pNotifyPath,
  903. NULL);
  904. }
  905. AFPLOG_HERROR(AFPSRVMSG_CANT_SET_TIMESNATTR,
  906. Status,
  907. NULL,
  908. 0,
  909. pFileHandle->fsh_FileHandle);
  910. return AFP_ERR_MISC;
  911. }
  912. else
  913. {
  914. #ifdef PROFILING
  915. AfpGetPerfCounter(&TimeE);
  916. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  917. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SetInfoCount);
  918. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_SetInfoTime,
  919. TimeD,
  920. &AfpStatisticsLock);
  921. #endif
  922. }
  923. return AFP_ERR_NONE;
  924. }
  925. /*** AfpIoRestoreTimeStamp
  926. *
  927. * When we don't want to change the modification timestamp, we call this function
  928. * in 2 steps: first time, it queries the original Mod time; second time, it sets it
  929. */
  930. AFPSTATUS
  931. AfpIoRestoreTimeStamp(
  932. IN PFILESYSHANDLE pFileHandle,
  933. IN OUT PTIME pOriginalModTime,
  934. IN DWORD dwFlag
  935. )
  936. {
  937. NTSTATUS Status;
  938. DWORD NTAttr = 0;
  939. FILE_BASIC_INFORMATION FBasicInfo;
  940. IO_STATUS_BLOCK IoStsBlk;
  941. PFAST_IO_DISPATCH fastIoDispatch;
  942. // if we are asked to retrieve the original timestamp, do that and return
  943. if (dwFlag == AFP_RETRIEVE_MODTIME)
  944. {
  945. Status = AfpIoQueryTimesnAttr(pFileHandle, NULL, pOriginalModTime, &NTAttr);
  946. return(Status);
  947. }
  948. //
  949. // we've been asked to restore the timestamp: let's do that!
  950. //
  951. ASSERT(dwFlag == AFP_RESTORE_MODTIME);
  952. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  953. // this will cause file system to flush any timestamps
  954. RtlZeroMemory(&FBasicInfo, sizeof(FBasicInfo));
  955. Status = NtSetInformationFile(pFileHandle->fsh_FileHandle,
  956. &IoStsBlk,
  957. (PVOID)&FBasicInfo,
  958. sizeof(FBasicInfo),
  959. FileBasicInformation);
  960. if (!NT_SUCCESS(Status))
  961. {
  962. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  963. ("AfpIoRestoreTimeStamp: NtSetInformationFile failed with 0x%lx\n",Status));
  964. }
  965. // First query the information
  966. fastIoDispatch = pFileHandle->fsh_DeviceObject->DriverObject->FastIoDispatch;
  967. if (fastIoDispatch &&
  968. fastIoDispatch->FastIoQueryBasicInfo &&
  969. fastIoDispatch->FastIoQueryBasicInfo(AfpGetRealFileObject(pFileHandle->fsh_FileObject),
  970. True,
  971. &FBasicInfo,
  972. &IoStsBlk,
  973. pFileHandle->fsh_DeviceObject))
  974. {
  975. Status = IoStsBlk.Status;
  976. }
  977. else
  978. {
  979. Status = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  980. &IoStsBlk,
  981. &FBasicInfo,
  982. sizeof(FBasicInfo),
  983. FileBasicInformation);
  984. }
  985. if (!NT_SUCCESS((NTSTATUS)Status))
  986. {
  987. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  988. ("AfpIoRestoreTimeStamp: NtQueryInformationFile returned 0x%lx\n",Status));
  989. return AFP_ERR_MISC; // What else can we do
  990. }
  991. //
  992. // Set times to Zero for the ones we don't want to restore, so that those don't change
  993. //
  994. FBasicInfo.CreationTime = LIZero;
  995. FBasicInfo.LastAccessTime = LIZero;
  996. FBasicInfo.LastWriteTime = *pOriginalModTime;
  997. FBasicInfo.ChangeTime = *pOriginalModTime;
  998. // see AfpIoSetTimesnAttr()
  999. if (!(FBasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  1000. {
  1001. FBasicInfo.FileAttributes |= FILE_ATTRIBUTE_NORMAL;
  1002. }
  1003. Status = NtSetInformationFile(pFileHandle->fsh_FileHandle,
  1004. &IoStsBlk,
  1005. (PVOID)&FBasicInfo,
  1006. sizeof(FBasicInfo),
  1007. FileBasicInformation);
  1008. if (!NT_SUCCESS(Status))
  1009. {
  1010. return AFP_ERR_MISC;
  1011. }
  1012. return AFP_ERR_NONE;
  1013. }
  1014. /*** AfpIoQueryLongName
  1015. *
  1016. * Get the long name associated with a file. Caller makes sure that
  1017. * the buffer is big enough to handle the long name. The only caller of this
  1018. * should be the AfpFindEntryByName routine when looking up a name by
  1019. * SHORTNAME. If it dosn't find it in the database by shortname (i.e.
  1020. * shortname == longname), then it queries for the longname so it can look
  1021. * in the database by longname (since all database entries are stored with
  1022. * longname only).
  1023. * The Admin Get/SetDirectoryInfo calls may also call this if they find a
  1024. * ~ in a path component, then it will assume that it got a shortname.
  1025. */
  1026. NTSTATUS
  1027. AfpIoQueryLongName(
  1028. IN PFILESYSHANDLE pFileHandle,
  1029. IN PUNICODE_STRING pShortname,
  1030. OUT PUNICODE_STRING pLongName
  1031. )
  1032. {
  1033. LONGLONG Infobuf[(sizeof(FILE_BOTH_DIR_INFORMATION) + MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR))/sizeof(LONGLONG) + 1];
  1034. NTSTATUS Status;
  1035. IO_STATUS_BLOCK IoStsBlk;
  1036. UNICODE_STRING uName;
  1037. PFILE_BOTH_DIR_INFORMATION pFBDInfo = (PFILE_BOTH_DIR_INFORMATION)Infobuf;
  1038. PAGED_CODE( );
  1039. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1040. Status = NtQueryDirectoryFile(pFileHandle->fsh_FileHandle,
  1041. NULL,NULL,NULL,
  1042. &IoStsBlk,
  1043. Infobuf,
  1044. sizeof(Infobuf),
  1045. FileBothDirectoryInformation,
  1046. True,
  1047. pShortname,
  1048. False);
  1049. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1050. ("NtQueryDirectoryFile returned 0x%lx\n",Status) );
  1051. // Do not errorlog if an error occurs (usually STATUS_NO_SUCH_FILE) because
  1052. // this normally happens when someone is creating a file/dir by SHORTNAME
  1053. // and it does not yet exist. This would not be an error.
  1054. if (NT_SUCCESS(Status))
  1055. {
  1056. uName.Length =
  1057. uName.MaximumLength = (USHORT)pFBDInfo->FileNameLength;
  1058. uName.Buffer = pFBDInfo->FileName;
  1059. //if (pFBDInfo->FileNameLength/sizeof(WCHAR) > AFP_FILENAME_LEN)
  1060. if ((RtlUnicodeStringToAnsiSize(&uName)-1) > AFP_FILENAME_LEN)
  1061. {
  1062. // NTFS name is longer than 31 chars, use the shortname
  1063. uName.Length =
  1064. uName.MaximumLength = (USHORT)pFBDInfo->ShortNameLength;
  1065. uName.Buffer = pFBDInfo->ShortName;
  1066. }
  1067. else
  1068. {
  1069. uName.Length =
  1070. uName.MaximumLength = (USHORT)pFBDInfo->FileNameLength;
  1071. uName.Buffer = pFBDInfo->FileName;
  1072. }
  1073. AfpCopyUnicodeString(pLongName, &uName);
  1074. ASSERT(pLongName->Length == uName.Length);
  1075. }
  1076. return Status;
  1077. }
  1078. /*** AfpIoQueryShortName
  1079. *
  1080. * Get the short name associated with a file. Caller makes sure that
  1081. * the buffer is big enough to handle the short name.
  1082. */
  1083. AFPSTATUS FASTCALL
  1084. AfpIoQueryShortName(
  1085. IN PFILESYSHANDLE pFileHandle,
  1086. OUT PANSI_STRING pName
  1087. )
  1088. {
  1089. LONGLONG ShortNameBuf[(sizeof(FILE_NAME_INFORMATION) + AFP_SHORTNAME_LEN * sizeof(WCHAR))/sizeof(LONGLONG) + 1];
  1090. NTSTATUS Status;
  1091. IO_STATUS_BLOCK IoStsBlk;
  1092. UNICODE_STRING uName;
  1093. PAGED_CODE( );
  1094. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1095. // Query for the alternate name
  1096. Status = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  1097. &IoStsBlk, ShortNameBuf, sizeof(ShortNameBuf),
  1098. FileAlternateNameInformation);
  1099. if (!NT_SUCCESS(Status))
  1100. {
  1101. AFPLOG_ERROR(AFPSRVMSG_CANT_GET_FILENAME,
  1102. Status,
  1103. NULL,
  1104. 0,
  1105. NULL);
  1106. Status = AFP_ERR_MISC; // What else can we do
  1107. }
  1108. else
  1109. {
  1110. uName.Length =
  1111. uName.MaximumLength = (USHORT)(((PFILE_NAME_INFORMATION)ShortNameBuf)->FileNameLength);
  1112. uName.Buffer = ((PFILE_NAME_INFORMATION)ShortNameBuf)->FileName;
  1113. if (!NT_SUCCESS(AfpConvertMungedUnicodeToAnsi(&uName, pName)))
  1114. Status = AFP_ERR_MISC; // What else can we do
  1115. }
  1116. return Status;
  1117. }
  1118. /*** AfpIoQueryStreams
  1119. *
  1120. * Get the names of all the streams that a file has. Memory is allocated out
  1121. * of non-paged pool to hold the stream names. These have to be freed by the
  1122. * caller.
  1123. */
  1124. PSTREAM_INFO FASTCALL
  1125. AfpIoQueryStreams(
  1126. IN PFILESYSHANDLE pFileHandle
  1127. )
  1128. {
  1129. PFILE_STREAM_INFORMATION pStreamBuf;
  1130. PBYTE pBuffer;
  1131. NTSTATUS Status = STATUS_SUCCESS;
  1132. IO_STATUS_BLOCK IoStsBlk;
  1133. DWORD BufferSize;
  1134. LONGLONG Buffer[512/sizeof(LONGLONG) + 1];
  1135. PSTREAM_INFO pStreams = NULL;
  1136. PAGED_CODE( );
  1137. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1138. pBuffer = (PBYTE)Buffer;
  1139. BufferSize = sizeof(Buffer);
  1140. do
  1141. {
  1142. if (Status != STATUS_SUCCESS)
  1143. {
  1144. if (pBuffer != (PBYTE)Buffer)
  1145. AfpFreeMemory(pBuffer);
  1146. BufferSize *= 2;
  1147. if ((pBuffer = AfpAllocNonPagedMemory(BufferSize)) == NULL)
  1148. {
  1149. Status = STATUS_NO_MEMORY;
  1150. break;
  1151. }
  1152. }
  1153. // Query for the stream information
  1154. Status = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  1155. &IoStsBlk,
  1156. pBuffer,
  1157. BufferSize,
  1158. FileStreamInformation);
  1159. } while ((Status != STATUS_SUCCESS) &&
  1160. ((Status == STATUS_BUFFER_OVERFLOW) ||
  1161. (Status == STATUS_MORE_ENTRIES)));
  1162. if (NT_SUCCESS(Status)) do
  1163. {
  1164. USHORT i, NumStreams = 1;
  1165. USHORT TotalBufferSize = 0;
  1166. PBYTE NamePtr;
  1167. // Make a pass thru the buffer and figure out the # of streams and then
  1168. // allocate memory to hold the information
  1169. pStreamBuf = (PFILE_STREAM_INFORMATION)pBuffer;
  1170. if (IoStsBlk.Information != 0)
  1171. {
  1172. pStreamBuf = (PFILE_STREAM_INFORMATION)pBuffer;
  1173. for (NumStreams = 1,
  1174. TotalBufferSize = (USHORT)(pStreamBuf->StreamNameLength + sizeof(WCHAR));
  1175. NOTHING; NumStreams++)
  1176. {
  1177. if (pStreamBuf->NextEntryOffset == 0)
  1178. break;
  1179. pStreamBuf = (PFILE_STREAM_INFORMATION)((PBYTE)pStreamBuf +
  1180. pStreamBuf->NextEntryOffset);
  1181. TotalBufferSize += (USHORT)(pStreamBuf->StreamNameLength + sizeof(WCHAR));
  1182. }
  1183. NumStreams ++;
  1184. }
  1185. // Now allocate space for the streams
  1186. if ((pStreams = (PSTREAM_INFO)AfpAllocNonPagedMemory(TotalBufferSize +
  1187. (NumStreams * sizeof(STREAM_INFO)))) == NULL)
  1188. {
  1189. Status = AFP_ERR_MISC;
  1190. break;
  1191. }
  1192. // The end is marked by an empty string
  1193. pStreams[NumStreams-1].si_StreamName.Buffer = NULL;
  1194. pStreams[NumStreams-1].si_StreamName.Length =
  1195. pStreams[NumStreams-1].si_StreamName.MaximumLength = 0;
  1196. pStreams[NumStreams-1].si_StreamSize.QuadPart = 0;
  1197. // Now initialize the array
  1198. NamePtr = (PBYTE)pStreams + (NumStreams * sizeof(STREAM_INFO));
  1199. pStreamBuf = (PFILE_STREAM_INFORMATION)pBuffer;
  1200. for (i = 0; NumStreams-1 != 0; i++)
  1201. {
  1202. PUNICODE_STRING pStream;
  1203. pStream = &pStreams[i].si_StreamName;
  1204. pStream->Buffer = (LPWSTR)NamePtr;
  1205. pStream->Length = (USHORT)(pStreamBuf->StreamNameLength);
  1206. pStream->MaximumLength = pStream->Length + sizeof(WCHAR);
  1207. pStreams[i].si_StreamSize = pStreamBuf->StreamSize;
  1208. RtlCopyMemory(NamePtr,
  1209. pStreamBuf->StreamName,
  1210. pStreamBuf->StreamNameLength);
  1211. NamePtr += pStream->MaximumLength;
  1212. if (pStreamBuf->NextEntryOffset == 0)
  1213. break;
  1214. pStreamBuf = (PFILE_STREAM_INFORMATION)((PBYTE)pStreamBuf +
  1215. pStreamBuf->NextEntryOffset);
  1216. }
  1217. } while (False);
  1218. if (!NT_SUCCESS(Status))
  1219. {
  1220. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  1221. ("AfpIoQueryStreams: Failed %lx\n", Status));
  1222. // Free up any memory that has been allocated
  1223. if (pStreams != NULL)
  1224. AfpFreeMemory(pStreams);
  1225. // We get the following error for non-NTFS volumes, if this case simply assume it to be
  1226. // CDFS and return the data stream.
  1227. if (Status == STATUS_INVALID_PARAMETER)
  1228. {
  1229. if ((pStreams = (PSTREAM_INFO)AfpAllocNonPagedMemory((2*sizeof(STREAM_INFO)) +
  1230. DataStreamName.MaximumLength)) != NULL)
  1231. {
  1232. pStreams[0].si_StreamName.Buffer = (PWCHAR)((PBYTE)pStreams + 2*sizeof(STREAM_INFO));
  1233. pStreams[0].si_StreamName.Length = DataStreamName.Length;
  1234. pStreams[0].si_StreamName.MaximumLength = DataStreamName.MaximumLength;
  1235. RtlCopyMemory(pStreams[0].si_StreamName.Buffer,
  1236. DataStreamName.Buffer,
  1237. DataStreamName.MaximumLength);
  1238. AfpIoQuerySize(pFileHandle, &pStreams[0].si_StreamSize);
  1239. pStreams[1].si_StreamName.Length =
  1240. pStreams[1].si_StreamName.MaximumLength = 0;
  1241. pStreams[1].si_StreamName.Buffer = NULL;
  1242. }
  1243. }
  1244. else
  1245. {
  1246. AFPLOG_HERROR(AFPSRVMSG_CANT_GET_STREAMS,
  1247. Status,
  1248. NULL,
  1249. 0,
  1250. pFileHandle->fsh_FileHandle);
  1251. }
  1252. }
  1253. if ((pBuffer != NULL) && (pBuffer != (PBYTE)Buffer))
  1254. AfpFreeMemory(pBuffer);
  1255. return pStreams;
  1256. }
  1257. /*** AfpIoMarkFileForDelete
  1258. *
  1259. * Mark an open file as deleted. Returns NTSTATUS, not AFPSTATUS.
  1260. */
  1261. NTSTATUS
  1262. AfpIoMarkFileForDelete(
  1263. IN PFILESYSHANDLE pFileHandle,
  1264. IN PVOLDESC pVolDesc OPTIONAL, // only if pNotifyPath
  1265. IN PUNICODE_STRING pNotifyPath OPTIONAL,
  1266. IN PUNICODE_STRING pNotifyParentPath OPTIONAL
  1267. )
  1268. {
  1269. NTSTATUS rc;
  1270. IO_STATUS_BLOCK IoStsBlk;
  1271. FILE_DISPOSITION_INFORMATION fdispinfo;
  1272. #ifdef PROFILING
  1273. TIME TimeS, TimeE, TimeD;
  1274. AfpGetPerfCounter(&TimeS);
  1275. #endif
  1276. PAGED_CODE( );
  1277. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1278. fdispinfo.DeleteFile = True;
  1279. rc = NtSetInformationFile(pFileHandle->fsh_FileHandle,
  1280. &IoStsBlk,
  1281. &fdispinfo,
  1282. sizeof(fdispinfo),
  1283. FileDispositionInformation);
  1284. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1285. ("AfpIoMarkFileForDelete: NtSetInfoFile returned 0x%lx\n",rc) );
  1286. if (ARGUMENT_PRESENT(pNotifyPath) &&
  1287. !EXCLUSIVE_VOLUME(pVolDesc))
  1288. {
  1289. ASSERT(VALID_VOLDESC(pVolDesc));
  1290. // Do not queue for exclusive volumes
  1291. if (NT_SUCCESS(rc))
  1292. {
  1293. AfpQueueOurChange(pVolDesc,
  1294. FILE_ACTION_REMOVED,
  1295. pNotifyPath,
  1296. pNotifyParentPath);
  1297. }
  1298. }
  1299. #ifdef PROFILING
  1300. AfpGetPerfCounter(&TimeE);
  1301. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  1302. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_DeleteCount);
  1303. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_DeleteTime,
  1304. TimeD,
  1305. &AfpStatisticsLock);
  1306. #endif
  1307. return rc;
  1308. }
  1309. /*** AfpIoQueryDirectoryFile
  1310. *
  1311. * Enumerate a directory.
  1312. * Note this must return NTSTATUS in order for the caller to know when to
  1313. * stop enumerating.
  1314. */
  1315. NTSTATUS
  1316. AfpIoQueryDirectoryFile(
  1317. IN PFILESYSHANDLE pFileHandle,
  1318. OUT PVOID Enumbuf, // type depends on FileInfoClass
  1319. IN ULONG Enumbuflen,
  1320. IN ULONG FileInfoClass,
  1321. IN BOOLEAN ReturnSingleEntry,
  1322. IN BOOLEAN RestartScan,
  1323. IN PUNICODE_STRING pString OPTIONAL
  1324. )
  1325. {
  1326. NTSTATUS rc;
  1327. IO_STATUS_BLOCK IoStsBlk;
  1328. PAGED_CODE( );
  1329. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1330. ("AfpIoQueryDirectoryFile entered\n"));
  1331. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1332. rc = NtQueryDirectoryFile(pFileHandle->fsh_FileHandle,
  1333. NULL,
  1334. NULL,
  1335. NULL,
  1336. &IoStsBlk,
  1337. Enumbuf,
  1338. Enumbuflen,
  1339. FileInfoClass,
  1340. ReturnSingleEntry,
  1341. pString,
  1342. RestartScan);
  1343. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1344. ("NtQueryDirectoryFile returned 0x%lx\n",rc) );
  1345. return rc;
  1346. }
  1347. /*** AfpIoQueryBasicInfo
  1348. *
  1349. * Query FILE_BASIC_INFO for a handle.
  1350. */
  1351. NTSTATUS
  1352. AfpIoQueryBasicInfo(
  1353. IN PFILESYSHANDLE pFileHandle,
  1354. OUT PVOID BasicInfobuf
  1355. )
  1356. {
  1357. NTSTATUS rc;
  1358. IO_STATUS_BLOCK IoStsBlk;
  1359. PAGED_CODE( );
  1360. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1361. ("AfpIoQueryBasicInfo entered\n"));
  1362. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1363. rc = NtQueryInformationFile(pFileHandle->fsh_FileHandle,
  1364. &IoStsBlk,
  1365. BasicInfobuf,
  1366. sizeof(FILE_BASIC_INFORMATION),
  1367. FileBasicInformation);
  1368. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1369. ("AfpIoQuerybasicInfo: NtQueryInformationFile returned 0x%lx\n",rc) );
  1370. return rc;
  1371. }
  1372. /*** AfpIoClose
  1373. *
  1374. * Close the File/Fork/Directory.
  1375. */
  1376. AFPSTATUS FASTCALL
  1377. AfpIoClose(
  1378. IN PFILESYSHANDLE pFileHandle
  1379. )
  1380. {
  1381. NTSTATUS Status;
  1382. BOOLEAN Internal;
  1383. #ifdef PROFILING
  1384. TIME TimeS, TimeE, TimeD;
  1385. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_CloseCount);
  1386. AfpGetPerfCounter(&TimeS);
  1387. #endif
  1388. PAGED_CODE ();
  1389. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1390. ("AfpIoClose entered\n"));
  1391. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1392. Internal = INTERNAL_HANDLE(pFileHandle);
  1393. afpUpdateOpenFiles(Internal, False);
  1394. ObDereferenceObject(AfpGetRealFileObject(pFileHandle->fsh_FileObject));
  1395. Status = NtClose(pFileHandle->fsh_FileHandle);
  1396. pFileHandle->fsh_FileHandle = NULL;
  1397. ASSERT(NT_SUCCESS(Status));
  1398. #ifdef PROFILING
  1399. AfpGetPerfCounter(&TimeE);
  1400. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  1401. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_CloseTime,
  1402. TimeD,
  1403. &AfpStatisticsLock);
  1404. #endif
  1405. return AFP_ERR_NONE;
  1406. }
  1407. /*** AfpIoQueryVolumeSize
  1408. *
  1409. * Get the volume size and free space.
  1410. *
  1411. * Called by Admin thread and Scavenger thread
  1412. */
  1413. AFPSTATUS
  1414. AfpIoQueryVolumeSize(
  1415. IN PVOLDESC pVolDesc,
  1416. OUT LARGE_INTEGER *pFreeBytes,
  1417. OUT LARGE_INTEGER *pVolumeSize OPTIONAL
  1418. )
  1419. {
  1420. FILE_FS_SIZE_INFORMATION fssizeinfo;
  1421. IO_STATUS_BLOCK IoStsBlk;
  1422. NTSTATUS rc;
  1423. LONG BytesPerAllocationUnit;
  1424. LARGE_INTEGER FreeBytes, VolumeSize;
  1425. PAGED_CODE( );
  1426. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1427. ("AfpIoQueryVolumeSize entered\n"));
  1428. ASSERT(VALID_VOLDESC(pVolDesc) && VALID_FSH(&pVolDesc->vds_hRootDir) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1429. rc = NtQueryVolumeInformationFile(pVolDesc->vds_hRootDir.fsh_FileHandle,
  1430. &IoStsBlk,
  1431. (PVOID)&fssizeinfo,
  1432. sizeof(fssizeinfo),
  1433. FileFsSizeInformation);
  1434. if (!NT_SUCCESS(rc))
  1435. {
  1436. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  1437. ("AfpIoQueryVolumeSize: NtQueryVolInfoFile returned 0x%lx\n",rc));
  1438. return rc;
  1439. }
  1440. BytesPerAllocationUnit =
  1441. (LONG)(fssizeinfo.BytesPerSector * fssizeinfo.SectorsPerAllocationUnit);
  1442. if (ARGUMENT_PRESENT(pVolumeSize))
  1443. {
  1444. VolumeSize = RtlExtendedIntegerMultiply(fssizeinfo.TotalAllocationUnits,
  1445. BytesPerAllocationUnit);
  1446. *pVolumeSize = VolumeSize;
  1447. }
  1448. FreeBytes = RtlExtendedIntegerMultiply(fssizeinfo.AvailableAllocationUnits,
  1449. BytesPerAllocationUnit);
  1450. *pFreeBytes = FreeBytes;
  1451. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1452. ("AfpIoQueryVolumeSize: volume size=%lu, freebytes=%lu\n",
  1453. VolumeSize.LowPart, FreeBytes.LowPart));
  1454. pVolDesc->vds_AllocationBlockSize = BytesPerAllocationUnit;
  1455. return STATUS_SUCCESS;
  1456. }
  1457. /*** AfpIoMoveAndOrRename
  1458. *
  1459. * Calls NtSetInformationFile with name information in order to rename, move,
  1460. * or move AND rename a file or directory. pNewName must be a node name.
  1461. * The pfshNewDir parameter is required for a Move operation, and is
  1462. * an open handle to the target parent directory of the item to be moved.
  1463. *
  1464. * Retain the last change/modified time in this case.
  1465. */
  1466. AFPSTATUS
  1467. AfpIoMoveAndOrRename(
  1468. IN PFILESYSHANDLE pfshFile,
  1469. IN PFILESYSHANDLE pfshNewParent OPTIONAL, // Supply for Move operation
  1470. IN PUNICODE_STRING pNewName,
  1471. IN PVOLDESC pVolDesc OPTIONAL, // only if NotifyPath
  1472. IN PUNICODE_STRING pNotifyPath1 OPTIONAL, // REMOVE or RENAME action
  1473. IN PUNICODE_STRING pNotifyParentPath1 OPTIONAL,
  1474. IN PUNICODE_STRING pNotifyPath2 OPTIONAL, // ADDED action
  1475. IN PUNICODE_STRING pNotifyParentPath2 OPTIONAL
  1476. )
  1477. {
  1478. NTSTATUS Status;
  1479. IO_STATUS_BLOCK iosb;
  1480. BOOLEAN Queue = False;
  1481. PFILE_RENAME_INFORMATION pFRenameInfo;
  1482. // this has to be at least as big as AfpExchangeName
  1483. BYTE buffer[sizeof(FILE_RENAME_INFORMATION) + 42 * sizeof(WCHAR)];
  1484. PAGED_CODE( );
  1485. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1486. ("AfpIoMoveAndOrRename entered\n"));
  1487. ASSERT(VALID_FSH(pfshFile) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  1488. pFRenameInfo = (PFILE_RENAME_INFORMATION)buffer;
  1489. pFRenameInfo->RootDirectory = NULL;
  1490. if (ARGUMENT_PRESENT(pfshNewParent))
  1491. {
  1492. // its a move operation
  1493. ASSERT(VALID_FSH(pfshNewParent));
  1494. pFRenameInfo->RootDirectory = pfshNewParent->fsh_FileHandle;
  1495. }
  1496. pFRenameInfo->FileNameLength = pNewName->Length;
  1497. RtlCopyMemory(pFRenameInfo->FileName, pNewName->Buffer, pNewName->Length);
  1498. pFRenameInfo->ReplaceIfExists = False;
  1499. // Do not queue for exclusive volumes
  1500. if (ARGUMENT_PRESENT(pNotifyPath1) &&
  1501. !EXCLUSIVE_VOLUME(pVolDesc))
  1502. {
  1503. ASSERT(VALID_VOLDESC(pVolDesc));
  1504. Queue = True;
  1505. if (ARGUMENT_PRESENT(pNotifyPath2))
  1506. {
  1507. // move operation
  1508. ASSERT(ARGUMENT_PRESENT(pfshNewParent));
  1509. AfpQueueOurChange(pVolDesc,
  1510. FILE_ACTION_REMOVED,
  1511. pNotifyPath1,
  1512. pNotifyParentPath1);
  1513. AfpQueueOurChange(pVolDesc,
  1514. FILE_ACTION_ADDED,
  1515. pNotifyPath2,
  1516. pNotifyParentPath2);
  1517. }
  1518. else
  1519. {
  1520. // rename operation
  1521. ASSERT(!ARGUMENT_PRESENT(pfshNewParent));
  1522. AfpQueueOurChange(pVolDesc,
  1523. FILE_ACTION_RENAMED_OLD_NAME,
  1524. pNotifyPath1,
  1525. pNotifyParentPath1);
  1526. }
  1527. }
  1528. Status = NtSetInformationFile(pfshFile->fsh_FileHandle,
  1529. &iosb,
  1530. pFRenameInfo,
  1531. sizeof(*pFRenameInfo) + pFRenameInfo->FileNameLength,
  1532. FileRenameInformation);
  1533. if (!NT_SUCCESS(Status))
  1534. {
  1535. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  1536. ("AfpIoMoveAndOrRename: NtSetInfoFile returned 0x%lx\n",Status));
  1537. }
  1538. if (Queue)
  1539. {
  1540. // Undo on failure
  1541. if (!NT_SUCCESS(Status))
  1542. {
  1543. if (ARGUMENT_PRESENT(pNotifyPath2))
  1544. {
  1545. // move operation
  1546. ASSERT(ARGUMENT_PRESENT(pfshNewParent));
  1547. AfpDequeueOurChange(pVolDesc,
  1548. FILE_ACTION_REMOVED,
  1549. pNotifyPath1,
  1550. pNotifyParentPath1);
  1551. AfpDequeueOurChange(pVolDesc,
  1552. FILE_ACTION_ADDED,
  1553. pNotifyPath2,
  1554. pNotifyParentPath2);
  1555. }
  1556. else
  1557. {
  1558. // rename operation
  1559. ASSERT(!ARGUMENT_PRESENT(pfshNewParent));
  1560. AfpDequeueOurChange(pVolDesc,
  1561. FILE_ACTION_RENAMED_OLD_NAME,
  1562. pNotifyPath1,
  1563. pNotifyParentPath1);
  1564. }
  1565. }
  1566. }
  1567. if (!NT_SUCCESS(Status))
  1568. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  1569. return Status;
  1570. }
  1571. /*** AfpIoCopyFile1
  1572. *
  1573. * Copy phSrcFile to phDstDir directory with the name of pNewName. Returns
  1574. * the handles to the streams on the newly created file (open with DELETE access.
  1575. * Caller must close all the handles after copying the data.
  1576. */
  1577. AFPSTATUS
  1578. AfpIoCopyFile1(
  1579. IN PFILESYSHANDLE phSrcFile,
  1580. IN PFILESYSHANDLE phDstDir,
  1581. IN PUNICODE_STRING pNewName,
  1582. IN PVOLDESC pVolDesc OPTIONAL, // only if pNotifyPath
  1583. IN PUNICODE_STRING pNotifyPath OPTIONAL,
  1584. IN PUNICODE_STRING pNotifyParentPath OPTIONAL,
  1585. OUT PCOPY_FILE_INFO pCopyFileInfo
  1586. )
  1587. {
  1588. NTSTATUS Status = STATUS_SUCCESS;
  1589. PUNICODE_STRING pStreamName;
  1590. PSTREAM_INFO pStreams = NULL, pCurStream;
  1591. DWORD CreateTime = 0, ModTime = 0;
  1592. FILESYSHANDLE hDstFile;
  1593. LONG NumStreams, i;
  1594. IO_STATUS_BLOCK IoStsBlk;
  1595. PAGED_CODE( );
  1596. ASSERT(VALID_FSH(phDstDir) && VALID_FSH(phSrcFile));
  1597. do
  1598. {
  1599. hDstFile.fsh_FileHandle = NULL;
  1600. // Create (soft) the destination file
  1601. Status = AfpIoCreate(phDstDir,
  1602. AFP_STREAM_DATA,
  1603. pNewName,
  1604. FILEIO_ACCESS_WRITE | FILEIO_ACCESS_DELETE,
  1605. FILEIO_DENY_NONE,
  1606. FILEIO_OPEN_FILE,
  1607. FILEIO_CREATE_SOFT,
  1608. FILE_ATTRIBUTE_ARCHIVE,
  1609. True,
  1610. NULL,
  1611. &hDstFile,
  1612. NULL,
  1613. pVolDesc,
  1614. pNotifyPath,
  1615. pNotifyParentPath);
  1616. if (!NT_SUCCESS(Status))
  1617. {
  1618. break;
  1619. }
  1620. // Get a list of all stream names of the source file
  1621. if ((pStreams = AfpIoQueryStreams(phSrcFile)) != NULL)
  1622. {
  1623. for (pCurStream = pStreams, NumStreams = 0;
  1624. pCurStream->si_StreamName.Buffer != NULL;
  1625. pCurStream++, NumStreams ++)
  1626. NOTHING;
  1627. // Allocate an array of handles for storing stream handles as we create them
  1628. if (((pCopyFileInfo->cfi_SrcStreamHandle = (PFILESYSHANDLE)
  1629. AfpAllocNonPagedMemory(sizeof(FILESYSHANDLE)*NumStreams)) == NULL) ||
  1630. ((pCopyFileInfo->cfi_DstStreamHandle = (PFILESYSHANDLE)
  1631. AfpAllocNonPagedMemory(sizeof(FILESYSHANDLE)*NumStreams)) == NULL))
  1632. {
  1633. if (pCopyFileInfo->cfi_SrcStreamHandle != NULL)
  1634. {
  1635. AfpFreeMemory(pCopyFileInfo->cfi_SrcStreamHandle);
  1636. pCopyFileInfo->cfi_SrcStreamHandle = NULL;
  1637. }
  1638. Status = STATUS_INSUFFICIENT_RESOURCES;
  1639. break;
  1640. }
  1641. else
  1642. {
  1643. RtlZeroMemory(pCopyFileInfo->cfi_SrcStreamHandle, sizeof(FILESYSHANDLE)*NumStreams);
  1644. RtlZeroMemory(pCopyFileInfo->cfi_DstStreamHandle, sizeof(FILESYSHANDLE)*NumStreams);
  1645. pCopyFileInfo->cfi_SrcStreamHandle[0] = *phSrcFile;
  1646. pCopyFileInfo->cfi_DstStreamHandle[0] = hDstFile;
  1647. pCopyFileInfo->cfi_NumStreams = 1;
  1648. }
  1649. }
  1650. else
  1651. {
  1652. Status = STATUS_INSUFFICIENT_RESOURCES;
  1653. break;
  1654. }
  1655. for (pCurStream = pStreams, i = 1; // Start index
  1656. NT_SUCCESS(Status) &&
  1657. ((pStreamName = &pCurStream->si_StreamName)->Buffer != NULL);
  1658. pCurStream++)
  1659. {
  1660. PFILESYSHANDLE phdst;
  1661. // For each stream, create it on the destination, open it on src,
  1662. // set the size and lock the range. We already have the data forks
  1663. // open, ignore Afp_AfpInfo streams since we are going to re-create
  1664. // it again soon. Also ignore streams of 0 size.
  1665. if (IS_INFO_STREAM(pStreamName) ||
  1666. (pCurStream->si_StreamSize.QuadPart == 0))
  1667. {
  1668. continue;
  1669. }
  1670. if (!IS_DATA_STREAM(pStreamName))
  1671. {
  1672. Status = AfpIoOpen( phSrcFile,
  1673. AFP_STREAM_DATA,
  1674. FILEIO_OPEN_FILE,
  1675. pStreamName,
  1676. FILEIO_ACCESS_READ,
  1677. FILEIO_DENY_READ | FILEIO_DENY_WRITE,
  1678. True,
  1679. &pCopyFileInfo->cfi_SrcStreamHandle[i]);
  1680. if (!NT_SUCCESS(Status))
  1681. {
  1682. break;
  1683. }
  1684. Status = AfpIoCreate(&hDstFile,
  1685. AFP_STREAM_DATA,
  1686. pStreamName,
  1687. FILEIO_ACCESS_WRITE,
  1688. FILEIO_DENY_READ | FILEIO_DENY_WRITE,
  1689. FILEIO_OPEN_FILE,
  1690. FILEIO_CREATE_SOFT,
  1691. 0,
  1692. True,
  1693. NULL,
  1694. &pCopyFileInfo->cfi_DstStreamHandle[i],
  1695. NULL,
  1696. NULL,
  1697. NULL,
  1698. NULL);
  1699. if (!NT_SUCCESS(Status))
  1700. {
  1701. break;
  1702. }
  1703. phdst = &pCopyFileInfo->cfi_DstStreamHandle[i];
  1704. pCopyFileInfo->cfi_NumStreams ++;
  1705. i ++; // Onto the next stream
  1706. }
  1707. else // IS_DATA_STREAM(pStreamName)
  1708. {
  1709. phdst = &hDstFile;
  1710. }
  1711. // Set the size of the new stream and lock it down
  1712. Status = AfpIoSetSize(phdst, pCurStream->si_StreamSize.LowPart);
  1713. if (!NT_SUCCESS(Status))
  1714. {
  1715. break;
  1716. }
  1717. NtLockFile(phdst,
  1718. NULL,
  1719. NULL,
  1720. NULL,
  1721. &IoStsBlk,
  1722. &LIZero,
  1723. &pCurStream->si_StreamSize,
  1724. 0,
  1725. True,
  1726. True);
  1727. }
  1728. // We failed to create/open a stream
  1729. if (!NT_SUCCESS(Status))
  1730. {
  1731. // Delete the new file we just created. The handle is closed below.
  1732. AfpIoMarkFileForDelete(&hDstFile,
  1733. pVolDesc,
  1734. pNotifyPath,
  1735. pNotifyParentPath);
  1736. // Close all the handles, Free the handle space.
  1737. // DO NOT FREE THE SRC FILE HANDLE IN THE ERROR CASE.
  1738. // The Destination has already been deleted above.
  1739. for (i = 1; i < NumStreams; i++)
  1740. {
  1741. if (pCopyFileInfo->cfi_SrcStreamHandle[i].fsh_FileHandle != NULL)
  1742. {
  1743. AfpIoClose(&pCopyFileInfo->cfi_SrcStreamHandle[i]);
  1744. }
  1745. if (pCopyFileInfo->cfi_DstStreamHandle[i].fsh_FileHandle != NULL)
  1746. {
  1747. AfpIoClose(&pCopyFileInfo->cfi_DstStreamHandle[i]);
  1748. }
  1749. }
  1750. if (pCopyFileInfo->cfi_SrcStreamHandle != NULL)
  1751. AfpFreeMemory(pCopyFileInfo->cfi_SrcStreamHandle);
  1752. if (pCopyFileInfo->cfi_DstStreamHandle)
  1753. AfpFreeMemory(pCopyFileInfo->cfi_DstStreamHandle);
  1754. RtlZeroMemory(pCopyFileInfo, sizeof(COPY_FILE_INFO));
  1755. }
  1756. } while (False);
  1757. if (pStreams != NULL)
  1758. AfpFreeMemory(pStreams);
  1759. if (!NT_SUCCESS(Status) && (hDstFile.fsh_FileHandle != NULL))
  1760. {
  1761. AfpIoClose(&hDstFile);
  1762. }
  1763. if (!NT_SUCCESS(Status))
  1764. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  1765. return Status;
  1766. }
  1767. /*** AfpIoCopyFile2
  1768. *
  1769. * Phase 2 of the copy file. See AfpIoCopyFile1( above.
  1770. * The physical data is copied here.
  1771. * The relevant streams have been already created and locked.
  1772. * Destination file acquires the CreateTime and ModTime of the source file.
  1773. */
  1774. AFPSTATUS
  1775. AfpIoCopyFile2(
  1776. IN PCOPY_FILE_INFO pCopyFileInfo,
  1777. IN PVOLDESC pVolDesc OPTIONAL, // only if pNotifyPath
  1778. IN PUNICODE_STRING pNotifyPath OPTIONAL,
  1779. IN PUNICODE_STRING pNotifyParentPath OPTIONAL
  1780. )
  1781. {
  1782. NTSTATUS Status = STATUS_SUCCESS;
  1783. PBYTE RWbuf;
  1784. DWORD CreateTime = 0;
  1785. TIME ModTime;
  1786. LONG i;
  1787. #define RWBUFSIZE 1500 // So we can use secondary buffer from IO Pool.
  1788. PAGED_CODE( );
  1789. do
  1790. {
  1791. if ((RWbuf = AfpIOAllocBuffer(RWBUFSIZE)) == NULL)
  1792. {
  1793. Status = STATUS_NO_MEMORY;
  1794. break;
  1795. }
  1796. for (i = 0; i < pCopyFileInfo->cfi_NumStreams; i++)
  1797. {
  1798. while (NT_SUCCESS(Status))
  1799. {
  1800. LONG bytesRead;
  1801. bytesRead = 0;
  1802. // Read from src, write to dst
  1803. Status = AfpIoRead(&pCopyFileInfo->cfi_SrcStreamHandle[i],
  1804. NULL,
  1805. RWBUFSIZE,
  1806. &bytesRead,
  1807. RWbuf);
  1808. if (Status == AFP_ERR_EOF)
  1809. {
  1810. Status = STATUS_SUCCESS;
  1811. break;
  1812. }
  1813. else if (NT_SUCCESS(Status))
  1814. {
  1815. Status = AfpIoWrite(&pCopyFileInfo->cfi_DstStreamHandle[i],
  1816. NULL,
  1817. bytesRead,
  1818. RWbuf);
  1819. }
  1820. }
  1821. }
  1822. if (!NT_SUCCESS(Status))
  1823. {
  1824. // We failed to read/write a stream
  1825. // Delete the new file we just created
  1826. AfpIoMarkFileForDelete(&pCopyFileInfo->cfi_DstStreamHandle[0],
  1827. pVolDesc,
  1828. pNotifyPath,
  1829. pNotifyParentPath);
  1830. }
  1831. } while (False);
  1832. if (RWbuf != NULL)
  1833. AfpIOFreeBuffer(RWbuf);
  1834. if (!NT_SUCCESS(Status))
  1835. Status = AfpIoConvertNTStatusToAfpStatus(Status);
  1836. return Status;
  1837. }
  1838. /*** AfpIoWait
  1839. *
  1840. * Wait on a single object. This is a wrapper over KeWaitForSingleObject.
  1841. */
  1842. NTSTATUS FASTCALL
  1843. AfpIoWait(
  1844. IN PVOID pObject,
  1845. IN PLARGE_INTEGER pTimeOut OPTIONAL
  1846. )
  1847. {
  1848. NTSTATUS Status;
  1849. PAGED_CODE( );
  1850. Status = KeWaitForSingleObject( pObject,
  1851. UserRequest,
  1852. KernelMode,
  1853. False,
  1854. pTimeOut);
  1855. if (!NT_SUCCESS(Status))
  1856. {
  1857. AFPLOG_DDERROR(AFPSRVMSG_WAIT4SINGLE,
  1858. Status,
  1859. NULL,
  1860. 0,
  1861. NULL);
  1862. }
  1863. return Status;
  1864. }
  1865. /*** AfpUpgradeHandle
  1866. *
  1867. * Change a handles type from internal to client.
  1868. */
  1869. VOID FASTCALL
  1870. AfpUpgradeHandle(
  1871. IN PFILESYSHANDLE pFileHandle
  1872. )
  1873. {
  1874. KIRQL OldIrql;
  1875. UPGRADE_HANDLE(pFileHandle);
  1876. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  1877. AfpServerStatistics.stat_CurrentFilesOpen ++;
  1878. AfpServerStatistics.stat_TotalFilesOpened ++;
  1879. if (AfpServerStatistics.stat_CurrentFilesOpen >
  1880. AfpServerStatistics.stat_MaxFilesOpened)
  1881. AfpServerStatistics.stat_MaxFilesOpened =
  1882. AfpServerStatistics.stat_CurrentFilesOpen;
  1883. AfpServerStatistics.stat_CurrentInternalOpens --;
  1884. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  1885. }
  1886. /*** afpUpdateOpenFiles
  1887. *
  1888. * Update statistics to indicate number of open files.
  1889. */
  1890. LOCAL VOID FASTCALL
  1891. afpUpdateOpenFiles(
  1892. IN BOOLEAN Internal, // True for internal handles
  1893. IN BOOLEAN Open // True for open, False for close
  1894. )
  1895. {
  1896. KIRQL OldIrql;
  1897. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  1898. if (Open)
  1899. {
  1900. if (!Internal)
  1901. {
  1902. AfpServerStatistics.stat_CurrentFilesOpen ++;
  1903. AfpServerStatistics.stat_TotalFilesOpened ++;
  1904. if (AfpServerStatistics.stat_CurrentFilesOpen >
  1905. AfpServerStatistics.stat_MaxFilesOpened)
  1906. AfpServerStatistics.stat_MaxFilesOpened =
  1907. AfpServerStatistics.stat_CurrentFilesOpen;
  1908. }
  1909. else
  1910. {
  1911. AfpServerStatistics.stat_CurrentInternalOpens ++;
  1912. AfpServerStatistics.stat_TotalInternalOpens ++;
  1913. if (AfpServerStatistics.stat_CurrentInternalOpens >
  1914. AfpServerStatistics.stat_MaxInternalOpens)
  1915. AfpServerStatistics.stat_MaxInternalOpens =
  1916. AfpServerStatistics.stat_CurrentInternalOpens;
  1917. }
  1918. }
  1919. else
  1920. {
  1921. if (!Internal)
  1922. AfpServerStatistics.stat_CurrentFilesOpen --;
  1923. else AfpServerStatistics.stat_CurrentInternalOpens --;
  1924. }
  1925. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  1926. }
  1927. /*** AfpIoConvertNTStatusToAfpStatus
  1928. *
  1929. * Map NT Status code to the closest AFP equivalents. Currently it only handles
  1930. * error codes from NtOpenFile and NtCreateFile.
  1931. */
  1932. AFPSTATUS FASTCALL
  1933. AfpIoConvertNTStatusToAfpStatus(
  1934. IN NTSTATUS Status
  1935. )
  1936. {
  1937. AFPSTATUS RetCode;
  1938. PAGED_CODE( );
  1939. ASSERT (!NT_SUCCESS(Status));
  1940. if ((Status >= AFP_ERR_PWD_NEEDS_CHANGE) &&
  1941. (Status <= AFP_ERR_ACCESS_DENIED))
  1942. {
  1943. // Status is already in mac format
  1944. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  1945. ("AfpIoConvertNTStatusToAfpStatus: Status (%d) already in mac format!!\n", Status));
  1946. return Status;
  1947. }
  1948. switch (Status)
  1949. {
  1950. case STATUS_OBJECT_PATH_INVALID:
  1951. case STATUS_OBJECT_NAME_INVALID:
  1952. RetCode = AFP_ERR_PARAM;
  1953. break;
  1954. case STATUS_OBJECT_PATH_NOT_FOUND:
  1955. case STATUS_OBJECT_NAME_NOT_FOUND:
  1956. RetCode = AFP_ERR_OBJECT_NOT_FOUND;
  1957. break;
  1958. case STATUS_OBJECT_NAME_COLLISION:
  1959. case STATUS_OBJECT_NAME_EXISTS:
  1960. RetCode = AFP_ERR_OBJECT_EXISTS;
  1961. break;
  1962. case STATUS_ACCESS_DENIED:
  1963. RetCode = AFP_ERR_ACCESS_DENIED;
  1964. break;
  1965. case STATUS_QUOTA_EXCEEDED:
  1966. case STATUS_DISK_FULL:
  1967. RetCode = AFP_ERR_DISK_FULL;
  1968. break;
  1969. case STATUS_DIRECTORY_NOT_EMPTY:
  1970. RetCode = AFP_ERR_DIR_NOT_EMPTY;
  1971. break;
  1972. case STATUS_SHARING_VIOLATION:
  1973. RetCode = AFP_ERR_DENY_CONFLICT;
  1974. break;
  1975. default:
  1976. RetCode = AFP_ERR_MISC;
  1977. break;
  1978. }
  1979. return RetCode;
  1980. }
  1981. /*** AfpQueryPath
  1982. *
  1983. * Given a file handle, get the full pathname of the file/dir. If the
  1984. * name is longer than MaximumBuf, then forget it and return an error.
  1985. * Caller must free the pPath.Buffer.
  1986. */
  1987. NTSTATUS
  1988. AfpQueryPath(
  1989. IN HANDLE FileHandle,
  1990. IN PUNICODE_STRING pPath,
  1991. IN ULONG MaximumBuf
  1992. )
  1993. {
  1994. PFILE_NAME_INFORMATION pNameinfo;
  1995. IO_STATUS_BLOCK iosb;
  1996. NTSTATUS Status;
  1997. PAGED_CODE( );
  1998. do
  1999. {
  2000. if ((pNameinfo = (PFILE_NAME_INFORMATION)AfpAllocNonPagedMemory(MaximumBuf)) == NULL)
  2001. {
  2002. Status = STATUS_NO_MEMORY;
  2003. break;
  2004. }
  2005. Status = NtQueryInformationFile(FileHandle,
  2006. &iosb,
  2007. pNameinfo,
  2008. MaximumBuf,
  2009. FileNameInformation);
  2010. if (!NT_SUCCESS(Status))
  2011. {
  2012. AfpFreeMemory(pNameinfo);
  2013. break;
  2014. }
  2015. pPath->Length = pPath->MaximumLength = (USHORT) pNameinfo->FileNameLength;
  2016. // Shift the name to the front of the buffer
  2017. RtlMoveMemory(pNameinfo, &pNameinfo->FileName[0], pNameinfo->FileNameLength);
  2018. pPath->Buffer = (PWCHAR)pNameinfo;
  2019. } while (False);
  2020. return Status;
  2021. }
  2022. /*** AfpIoIsSupportedDevice
  2023. *
  2024. * AFP volumes can only be created on local disk or cdrom devices.
  2025. * (i.e. not network, virtual, etc. devices
  2026. */
  2027. BOOLEAN FASTCALL
  2028. AfpIoIsSupportedDevice(
  2029. IN PFILESYSHANDLE pFileHandle,
  2030. OUT PDWORD pFlags
  2031. )
  2032. {
  2033. IO_STATUS_BLOCK IoStsBlk;
  2034. FILE_FS_DEVICE_INFORMATION DevInfo;
  2035. PFILE_FS_ATTRIBUTE_INFORMATION pFSAttrInfo;
  2036. LONGLONG Buffer[(sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + AFP_FSNAME_BUFLEN)/sizeof(LONGLONG) + 1];
  2037. UNICODE_STRING uFsName;
  2038. NTSTATUS Status;
  2039. BOOLEAN RetCode = False;
  2040. PAGED_CODE( );
  2041. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  2042. ("AfpIoIsSupportedDevice entered\n"));
  2043. ASSERT(VALID_FSH(pFileHandle) && (KeGetCurrentIrql() < DISPATCH_LEVEL));
  2044. do
  2045. {
  2046. Status = NtQueryVolumeInformationFile(pFileHandle->fsh_FileHandle,
  2047. &IoStsBlk,
  2048. (PVOID)&DevInfo,
  2049. sizeof(DevInfo),
  2050. FileFsDeviceInformation);
  2051. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  2052. ("AfpIoIsSupportedDevice: NtQueryVolInfFile returned 0x%lx\n", Status));
  2053. if (!NT_SUCCESS(Status) ||
  2054. ((DevInfo.DeviceType != FILE_DEVICE_DISK) &&
  2055. (DevInfo.DeviceType != FILE_DEVICE_CD_ROM)))
  2056. {
  2057. break;
  2058. }
  2059. // need to check if this is NTFS, CDFS or unsupported FS
  2060. pFSAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
  2061. Status = NtQueryVolumeInformationFile(pFileHandle->fsh_FileHandle,
  2062. &IoStsBlk,
  2063. (PVOID)pFSAttrInfo,
  2064. sizeof(Buffer),
  2065. FileFsAttributeInformation);
  2066. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_INFO,
  2067. ("AfpIoIsSupportedDevice: NtQueryVolInfFile returned 0x%lx\n", Status));
  2068. if (!NT_SUCCESS(Status))
  2069. {
  2070. break;
  2071. }
  2072. if (pFSAttrInfo->FileSystemAttributes & FILE_VOLUME_QUOTAS)
  2073. {
  2074. *pFlags |= VOLUME_DISKQUOTA_ENABLED;
  2075. }
  2076. // convert returned non-null terminated file system name to counted unicode
  2077. AfpInitUnicodeStringWithNonNullTerm(&uFsName,
  2078. (USHORT)pFSAttrInfo->FileSystemNameLength,
  2079. pFSAttrInfo->FileSystemName);
  2080. if (EQUAL_UNICODE_STRING(&afpNTFSName, &uFsName, True))
  2081. {
  2082. // its an NTFS volume
  2083. *pFlags |= VOLUME_NTFS;
  2084. RetCode = True;
  2085. }
  2086. else if (EQUAL_UNICODE_STRING(&afpCDFSName, &uFsName, True))
  2087. {
  2088. // its a CDFS volume
  2089. *pFlags |= AFP_VOLUME_READONLY;
  2090. RetCode = True;
  2091. }
  2092. else if (EQUAL_UNICODE_STRING(&afpAHFSName, &uFsName, True))
  2093. {
  2094. // its a volume on CD with HFS support
  2095. *pFlags |= (AFP_VOLUME_READONLY | VOLUME_CD_HFS);
  2096. RetCode = True;
  2097. }
  2098. else
  2099. {
  2100. // an unsupported file system
  2101. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  2102. ("AfpIoIsSupportedDevice: unsupported file system: name=%Z, CDString=%Z\n", &uFsName, &afpCDFSName));
  2103. break;
  2104. }
  2105. } while (False);
  2106. if (!NT_SUCCESS(Status))
  2107. {
  2108. AFPLOG_HERROR(AFPSRVMSG_CANT_GET_FSNAME,
  2109. Status,
  2110. NULL,
  2111. 0,
  2112. pFileHandle->fsh_FileHandle);
  2113. }
  2114. return RetCode;
  2115. }
  2116.