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.

1489 lines
43 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Qfs.c
  5. Abstract:
  6. Redirection layer for quorum access
  7. Author:
  8. GorN 19-Sep-2001
  9. Revision History:
  10. TODO:
  11. Support more than one Qfs provider
  12. --*/
  13. #define QFS_DO_NOT_UNMAP_WIN32 // get access to regular CreateFile, etc
  14. #ifndef DUMB_CLIENT
  15. #include "service.h"
  16. #endif
  17. #include "QfsTrans.h"
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include <Imagehlp.h>
  21. #ifndef min
  22. #define min(a, b) ((a) < (b) ? (a) : (b))
  23. #endif
  24. ////////////////// Debug Junk //////////////////
  25. int QfsLogLevel = 0;
  26. void
  27. debug_log(char *format, ...)
  28. {
  29. va_list marker;
  30. va_start(marker, format);
  31. #ifdef DUMB_CLIENT
  32. if (QfsLogLevel > 2) {
  33. printf("%d:%x:",GetTickCount(), GetCurrentThreadId());
  34. vprintf(format, marker);
  35. }
  36. #else
  37. {
  38. char buf[1024];
  39. vsprintf(buf, format, marker);
  40. ClRtlLogPrint(LOG_NOISE, "%1!hs!\r\n",buf);
  41. }
  42. #endif
  43. va_end(marker);
  44. }
  45. void
  46. error_log(char *format, ...)
  47. {
  48. va_list marker;
  49. va_start(marker, format);
  50. #ifdef DUMB_CLIENT
  51. if (QfsLogLevel > 0) {
  52. printf("*E %d:%x:",GetTickCount(), GetCurrentThreadId());
  53. vprintf(format, marker);
  54. }
  55. #else
  56. {
  57. char buf[1024];
  58. vsprintf(buf, format, marker);
  59. ClRtlLogPrint(LOG_ERROR, "%1!hs!\r\n",buf);
  60. }
  61. #endif
  62. va_end(marker);
  63. }
  64. #ifndef QfsError
  65. # define QfsError(x) error_log x
  66. #endif
  67. #ifndef QfsNoise
  68. # define QfsNoise(x) debug_log x
  69. #endif
  70. // When give a UNS path that looks like a Qfs path
  71. // we contact the Qfs server and query whether it
  72. // recognizes that path. If it is, we cache this recognized
  73. // path in QfsPath veriable, so that next time we
  74. // can immediately pass the request coming to this path to Qfs
  75. WCHAR QfsPath[MAX_PATH];
  76. UINT ccQfsPath = 0;
  77. CRITICAL_SECTION QfsCriticalSection;
  78. SHARED_MEM_SERVER Client;
  79. VOID QfsInitialize()
  80. {
  81. InitializeCriticalSection(&QfsCriticalSection);
  82. MemClient_Init(&Client);
  83. }
  84. VOID QfsCleanup()
  85. {
  86. MemClient_Cleanup(&Client);
  87. DeleteCriticalSection(&QfsCriticalSection);
  88. }
  89. #define AcquireExclusive() EnterCriticalSection(&QfsCriticalSection)
  90. #define ReleaseExclusive() LeaveCriticalSection(&QfsCriticalSection)
  91. #define UpgradeToExclusive() (0)
  92. #define AcquireShared() EnterCriticalSection(&QfsCriticalSection)
  93. #define ReleaseShared() LeaveCriticalSection(&QfsCriticalSection)
  94. // the whole transport interface is incapsulated in
  95. // three functions
  96. // ReserveBuffer, DeliverBuffer and RelaseBuffer
  97. // The pattern of usage is
  98. //
  99. // ReserveBuffer(Operation, Path or Handle)
  100. // [gets a pointer to a job buffer if Path or Handle belong to Qfs]
  101. // Copy in parameters to a buffer
  102. // DeliverBuffer
  103. // Copy out parameters from a buffer
  104. // ReleaseBuffer
  105. DWORD QfspReserveBuffer(
  106. DWORD OpCode,
  107. LPCWSTR FileName,
  108. QfsHANDLE* HandlePtr,
  109. PJOB_BUF *pj);
  110. BOOL QfspDeliverBuffer(
  111. PJOB_BUF j,
  112. DWORD* Status);
  113. void QfspReleaseBuffer(
  114. PJOB_BUF j);
  115. BOOL QfspDeliverBufferInternal(
  116. LPWSTR PipeName,
  117. LPVOID buf,
  118. DWORD len,
  119. DWORD timeout,
  120. DWORD* Status
  121. );
  122. DWORD QfspReserveBufferNoChecks(
  123. DWORD OpCode,
  124. LPCWSTR FileName,
  125. QfsHANDLE* HandlePtr,
  126. PJOB_BUF *pj);
  127. LPCWSTR SkipUncPrefix(
  128. IN LPCWSTR p,
  129. OUT LPBOOL bIsShareName)
  130. /*++
  131. Routine Description:
  132. If the passed string looks like \\?\unc, or \\ strip the prefix and set pIsShareName to true
  133. Outputs:
  134. bIsShareName - set to TRUE if the path looks like UNC path and to FALSE otherwise
  135. Returns:
  136. The path without \\?\unc or \\ prefix, if it is a UNC path, otherwise returns p
  137. --*/
  138. {
  139. if (p[0] == '\\' && p[1] == '\\') {
  140. *bIsShareName = TRUE;
  141. p += 2;
  142. if (p[0]=='?' && p[1]=='\\' && p[2]=='U' && p[3]=='N' && p[4]=='C' && p[5] == '\\') {
  143. p += 6;
  144. if (p[0] != 0 && p[1]==':') {
  145. p += 2;
  146. if (p[0] == '\\') {
  147. ++p;
  148. }
  149. *bIsShareName = FALSE;
  150. }
  151. }
  152. } else {
  153. *bIsShareName = FALSE;
  154. }
  155. return p;
  156. }
  157. BOOL IsQfsPath(LPCWSTR Path)
  158. /*++
  159. Routine Description:
  160. Checks whether the path looks like a QfsPath
  161. This routine has fast and slow path.
  162. If QfsPath is set and is a valid prefix of Path, the function immediately returns
  163. Otherwise, it delivers opConnect request to the QfsServer to verify that it can
  164. handle this path.
  165. If QfsServer is not running, it will get a connection failure
  166. If QfsServer is up and recognizes the path, we set QfsPath, so that we don't
  167. have to do all this when we called next time for a similar path
  168. Inputs:
  169. Path,
  170. QfsPath global
  171. Side effects:
  172. Sets QfsPath if succesfully talked to Qfs server.
  173. --*/
  174. {
  175. BOOL IsShare;
  176. PWCHAR p;
  177. WCHAR shareName[MAX_PATH];
  178. JobBuf_t *j;
  179. SIZE_T len;
  180. DWORD Status=ERROR_NO_MATCH;
  181. Path = SkipUncPrefix(Path, &IsShare);
  182. if (!IsShare) {
  183. SetLastError(Status);
  184. return FALSE;
  185. }
  186. AcquireShared();
  187. if (ccQfsPath) {
  188. if (wcsncmp(Path, QfsPath, ccQfsPath) == 0) {
  189. ReleaseShared();
  190. return TRUE;
  191. }
  192. }
  193. ReleaseShared();
  194. p = wcschr(Path, '$');
  195. if (p == NULL || p[1] !='\\' ) {
  196. SetLastError(Status);
  197. return FALSE;
  198. }
  199. len = p - Path + 2;
  200. if (len+10 >= MAX_PATH) {
  201. SetLastError(Status);
  202. return FALSE;
  203. }
  204. CopyMemory(shareName, Path, (len) * sizeof(WCHAR));
  205. shareName[len] = 0;
  206. // We are trying to connect to MNS now to verify the share path. We need to zero
  207. // out the length field (ccQfsPath). Look at QfspCopyPath().
  208. //
  209. AcquireExclusive();
  210. ccQfsPath = 0;
  211. ReleaseExclusive();
  212. Status = QfspReserveBufferNoChecks(opConnect, shareName, 0, &j);
  213. if (Status != ERROR_SUCCESS) {
  214. SetLastError(Status);
  215. return FALSE;
  216. }
  217. // Get the clussvc process ID.
  218. j->ClussvcProcessId = GetCurrentProcessId();
  219. QfspDeliverBuffer(j,&Status);
  220. QfspReleaseBuffer(j);
  221. if (Status == ERROR_SUCCESS) {
  222. AcquireExclusive();
  223. wcscpy(QfsPath, shareName);
  224. ccQfsPath = (DWORD)len;
  225. ReleaseExclusive();
  226. QfsNoise(("[Qfs] QfsPath %ws", QfsPath));
  227. // need to update
  228. } else {
  229. SetLastError(Status);
  230. return FALSE;
  231. }
  232. return TRUE;
  233. }
  234. // QfsINVALID_HANDLE_VALUE is to be used in place of INVALID_HANDLE_VALUE
  235. // to initalize hadle of QfsHANDLE type
  236. QfsHANDLE QfsINVALID_HANDLE_VALUE = {INVALID_HANDLE_VALUE, 0};
  237. #define HandlePtr(x) (&(x))
  238. BOOL IsQfsHandle(QfsHANDLE handle)
  239. {
  240. return handle.IsQfs;
  241. }
  242. HANDLE GetRealHandle(QfsHANDLE QfsHandle)
  243. {
  244. return QfsHandle.realHandle;
  245. }
  246. QfsHANDLE MakeQfsHandle(HANDLE handle)
  247. {
  248. QfsHANDLE result;
  249. result.IsQfs = 1;
  250. result.realHandle = handle;
  251. return result;
  252. }
  253. QfsHANDLE MakeWin32Handle(HANDLE handle)
  254. {
  255. QfsHANDLE result;
  256. result.IsQfs = 0;
  257. result.realHandle = handle;
  258. return result;
  259. }
  260. //////////////////////////////////////////////////////////////////
  261. #undef malloc
  262. #undef free
  263. #define malloc(dwBytes) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytes)
  264. #define free(hHeap) HeapFree(GetProcessHeap(), 0, hHeap)
  265. DWORD QfspCopyPath(
  266. OUT LPVOID Buf,
  267. IN DWORD BufSize,
  268. IN LPCWSTR FileName)
  269. /*++
  270. Routine Description:
  271. Copy path without QfsPath prefix.
  272. Ie it will take:
  273. \\.\UNC\12378\234-79879-87987$\a\b and transforms it into \a\b
  274. Sets QfsPath if succesfully talked to Qfs server.
  275. WARNING: It is a coller responsibility to make sure that the buffer
  276. is large enough to fit the filename
  277. --*/
  278. {
  279. BOOL bIsShare;
  280. DWORD cbLen;
  281. FileName = SkipUncPrefix(FileName, &bIsShare) + ccQfsPath;
  282. cbLen = sizeof(WCHAR) * (wcslen(FileName)+1);
  283. if (cbLen > BufSize) {
  284. return ERROR_BAD_PATHNAME;
  285. }
  286. CopyMemory(Buf, FileName, cbLen);
  287. return ERROR_SUCCESS;
  288. }
  289. DWORD QfspReserveBufferNoChecks(
  290. DWORD OpCode,
  291. LPCWSTR FileName,
  292. QfsHANDLE* HandlePtr,
  293. PJOB_BUF *pj)
  294. /*++
  295. Routine Description:
  296. Prepares a job buffer.
  297. Sets the OpCode, copies FileName and Handle if present
  298. Output:
  299. If the operation is successful, the pointer to a job buffer is returned in *pj
  300. --*/
  301. {
  302. PJOB_BUF j;
  303. DWORD status;
  304. status = MemClient_ReserveBuffer(&Client, &j);
  305. if (status != ERROR_SUCCESS) {
  306. return status;
  307. }
  308. j->hdr.OpCode = OpCode;
  309. if (HandlePtr) {
  310. j->Handle = GetRealHandle(*HandlePtr);
  311. }
  312. if (FileName) {
  313. status = QfspCopyPath(j->Buffer, sizeof(j->Buffer), FileName);
  314. if (status != ERROR_SUCCESS) {
  315. free(j);
  316. return status;
  317. }
  318. }
  319. *pj = j;
  320. return ERROR_SUCCESS;
  321. }
  322. DWORD QfspReserveBuffer(
  323. DWORD OpCode,
  324. LPCWSTR FileName,
  325. QfsHANDLE* HandlePtr,
  326. PJOB_BUF *pj)
  327. /*++
  328. Routine Description:
  329. Prepares a job buffer.
  330. Sets the OpCode, copies FileName and Handle if present
  331. Return codes:
  332. ERROR_NO_MATCH: the handle or path do not belong to Qfs,
  333. the caller needs to use regular Win32 i/o APIs
  334. --*/
  335. {
  336. if(HandlePtr && GetRealHandle(*HandlePtr) == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
  337. if(FileName && !IsQfsPath(FileName)) return ERROR_NO_MATCH;
  338. if(HandlePtr && !IsQfsHandle(*HandlePtr)) return ERROR_NO_MATCH;
  339. return QfspReserveBufferNoChecks(OpCode, FileName, HandlePtr, pj);
  340. }
  341. BOOL QfspDeliverBuffer(
  342. PJOB_BUF j,
  343. DWORD* Status)
  344. {
  345. *Status = MemClient_DeliverBuffer(j);
  346. if (*Status == ERROR_SUCCESS) {
  347. *Status = j->hdr.Status;
  348. }
  349. return *Status == ERROR_SUCCESS;
  350. }
  351. void QfspReleaseBuffer(
  352. PJOB_BUF j)
  353. {
  354. MemClient_Release(j);
  355. }
  356. ////////////////////////////////////////////////////////////////////
  357. // Redirection shims, most of them follow the following pattern
  358. //
  359. // ReserveBuffer(Operation, Path or Handle)
  360. // [gets a pointer to a job buffer if Path or Handle belong to Qfs]
  361. // Copy in parameters to a buffer
  362. // DeliverBuffer
  363. // Copy out parameters from a buffer
  364. // ReleaseBuffer
  365. //
  366. // If ReserveBuffer failed with error NO_MATCH, calls regular Win32 API
  367. //
  368. ////////////////////////////////////////////////////////////////////
  369. #define StatusFromBool(expr) (Status = (expr)?ERROR_SUCCESS:GetLastError())
  370. #define BoolToStatus(expr) StatusFromBool(expr)
  371. #define StatusFromHandle(expr) (Status = ((expr) != INVALID_HANDLE_VALUE)?ERROR_SUCCESS:GetLastError())
  372. BOOL QfsCloseHandle(
  373. QfsHANDLE hObject // handle to object
  374. )
  375. {
  376. PJOB_BUF j;
  377. DWORD Status = QfspReserveBuffer(opCloseFile, NULL, HandlePtr(hObject), &j);
  378. if (Status == ERROR_SUCCESS) {
  379. QfspDeliverBuffer(j, &Status);
  380. QfspReleaseBuffer(j);
  381. } else if (Status == ERROR_NO_MATCH) {
  382. Status = CloseHandle(GetRealHandle(hObject))?ERROR_SUCCESS:GetLastError();
  383. }
  384. QfsNoise(("[Qfs] QfsCloseHandle %x, status %d", GetRealHandle(hObject), Status));
  385. SetLastError(Status);
  386. return Status == ERROR_SUCCESS;
  387. }
  388. DWORD QfspRemapCreateFileStatus(DWORD Status, DWORD DispReq, DWORD DispAct)
  389. {
  390. if (Status == ERROR_ALREADY_EXISTS && DispReq == CREATE_NEW)
  391. return ERROR_FILE_EXISTS;
  392. if (Status != ERROR_SUCCESS)
  393. return Status;
  394. if (DispAct != OPEN_EXISTING)
  395. return Status;
  396. if (DispReq == CREATE_ALWAYS || DispReq == OPEN_ALWAYS)
  397. return ERROR_ALREADY_EXISTS;
  398. return Status;
  399. }
  400. QfsHANDLE QfsCreateFile(
  401. LPCWSTR lpFileName, // file name
  402. DWORD dwDesiredAccess, // access mode
  403. DWORD dwShareMode, // share mode
  404. LPSECURITY_ATTRIBUTES lpSecurityAttributes, // SD
  405. DWORD dwCreationDisposition, // how to create
  406. DWORD dwFlagsAndAttributes, // file attributes
  407. HANDLE hTemplateFile // handle to template file
  408. )
  409. {
  410. QfsHANDLE Result=QfsINVALID_HANDLE_VALUE;
  411. PJOB_BUF j;
  412. DWORD Status = QfspReserveBuffer(opCreateFile, lpFileName, NULL, &j);
  413. if (Status == ERROR_SUCCESS) {
  414. j->dwDesiredAccess = dwDesiredAccess;
  415. j->dwShareMode = dwShareMode;
  416. j->dwCreationDisposition = dwCreationDisposition;
  417. j->dwFlagsAndAttributes = dwFlagsAndAttributes;
  418. if( QfspDeliverBuffer(j, &Status) ) {
  419. Result = MakeQfsHandle(j->Handle);
  420. } else {
  421. Result = QfsINVALID_HANDLE_VALUE;
  422. }
  423. Status = QfspRemapCreateFileStatus(Status,
  424. dwCreationDisposition, j->dwCreationDisposition);
  425. dwCreationDisposition = j->dwCreationDisposition;
  426. QfspReleaseBuffer(j);
  427. } else if (Status == ERROR_NO_MATCH) {
  428. Result = MakeWin32Handle(
  429. CreateFile(
  430. lpFileName, dwDesiredAccess, dwShareMode,
  431. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile)
  432. );
  433. Status = GetLastError();
  434. }
  435. QfsNoise(("[Qfs] QfsOpenFile %ws => %x, %x status %d", lpFileName, dwCreationDisposition, Result, Status));
  436. SetLastError(Status);
  437. return Result;
  438. }
  439. // little helper structure that simplifies printing a sample of
  440. // a buffer data for debugging
  441. typedef struct _sig { char sig[5]; } SIG;
  442. SIG Prefix(LPCVOID lpBuffer) {
  443. char* p = (char*)lpBuffer;
  444. SIG Result = {"...."};
  445. if (isalpha(p[0])) Result.sig[0] = p[0];
  446. if (isalpha(p[1])) Result.sig[1] = p[1];
  447. if (isalpha(p[2])) Result.sig[2] = p[2];
  448. if (isalpha(p[3])) Result.sig[3] = p[3];
  449. return Result;
  450. }
  451. // NOWHOW MNS interprets WriteFile with Size zero as SetEndOfFile //
  452. BOOL QfsWriteFile(
  453. QfsHANDLE hFile, // handle to file
  454. LPCVOID lpBuffer, // data buffer
  455. DWORD nNumberOfBytesToWrite, // number of bytes to write
  456. LPDWORD lpNumberOfBytesWritten, // number of bytes written
  457. LPOVERLAPPED lpOverlapped // overlapped buffer
  458. )
  459. {
  460. PJOB_BUF j;
  461. ULONG PreOffset = 0, PostOffset = 0;
  462. DWORD Status = QfspReserveBuffer(opWriteFile, NULL, HandlePtr(hFile), &j);
  463. if (Status == ERROR_SUCCESS) {
  464. DWORD nRemainingBytes = nNumberOfBytesToWrite;
  465. const char* BufferWalker = lpBuffer;
  466. if (lpOverlapped) {
  467. j->Offset = lpOverlapped->Offset;
  468. } else {
  469. j->Offset = ~0; // use file pointer
  470. }
  471. PreOffset = (ULONG)j->Offset;
  472. do {
  473. j->cbSize = (USHORT)min(JOB_BUF_MAX_BUFFER, nRemainingBytes) ;
  474. CopyMemory(j->Buffer, BufferWalker, j->cbSize);
  475. if (QfspDeliverBuffer(j, &Status)) {
  476. nRemainingBytes -= j->cbSize;
  477. BufferWalker += j->cbSize;
  478. } else {
  479. break;
  480. }
  481. } while (nRemainingBytes > 0 && j->cbSize > 0);
  482. if (lpNumberOfBytesWritten) {
  483. *lpNumberOfBytesWritten = nNumberOfBytesToWrite - nRemainingBytes;
  484. }
  485. PostOffset = (ULONG)j->Offset;
  486. QfspReleaseBuffer(j);
  487. } else if (Status == ERROR_NO_MATCH) {
  488. if(WriteFile(GetRealHandle(hFile), lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped)) {
  489. Status = ERROR_SUCCESS;
  490. } else {
  491. Status = GetLastError();
  492. }
  493. }
  494. QfsNoise(("[Qfs] WriteFile %x (%s) %d, status %d (%d=>%d)", GetRealHandle(hFile), Prefix(lpBuffer).sig,
  495. nNumberOfBytesToWrite, Status, PreOffset, PostOffset));
  496. SetLastError(Status);
  497. return Status == ERROR_SUCCESS;
  498. }
  499. BOOL QfsReadFile(
  500. QfsHANDLE hFile, // handle to file
  501. LPVOID lpBuffer, // data buffer
  502. DWORD nNumberOfBytesToRead, // number of bytes to read
  503. LPDWORD lpNumberOfBytesRead, // number of bytes read
  504. LPOVERLAPPED lpOverlapped // overlapped buffer
  505. )
  506. {
  507. PJOB_BUF j; ULONG PreOffset = 0, PostOffset = 0;
  508. DWORD Status = QfspReserveBuffer(opReadFile, NULL, HandlePtr(hFile), &j);
  509. if (Status == ERROR_SUCCESS) {
  510. DWORD nRemainingBytes = nNumberOfBytesToRead;
  511. PCHAR BufferWalker = lpBuffer;
  512. if (lpOverlapped) {
  513. j->Offset = lpOverlapped->Offset;
  514. } else {
  515. j->Offset = (ULONGLONG)-1; // use file pointer
  516. }
  517. PreOffset = (ULONG)j->Offset;
  518. do {
  519. j->cbSize = (USHORT)min(JOB_BUF_MAX_BUFFER, nRemainingBytes);
  520. if (QfspDeliverBuffer(j, &Status)) {
  521. CopyMemory(BufferWalker, j->Buffer, j->cbSize);
  522. nRemainingBytes -= j->cbSize;
  523. BufferWalker += j->cbSize;
  524. } else {
  525. break;
  526. }
  527. } while (nRemainingBytes > 0 && j->cbSize > 0);
  528. if (lpNumberOfBytesRead) {
  529. *lpNumberOfBytesRead = nNumberOfBytesToRead - nRemainingBytes;
  530. }
  531. PostOffset = (ULONG)j->Offset;
  532. QfspReleaseBuffer(j);
  533. } else if (Status == ERROR_NO_MATCH) {
  534. if(ReadFile(GetRealHandle(hFile), lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped)) {
  535. Status = ERROR_SUCCESS;
  536. } else {
  537. Status = GetLastError();
  538. }
  539. }
  540. QfsNoise(("[Qfs] ReadFile %x (%s) %d %d, (%d=>%d) %x status %d",
  541. GetRealHandle(hFile), &Prefix(lpBuffer).sig,
  542. nNumberOfBytesToRead, *lpNumberOfBytesRead,
  543. PreOffset, PostOffset, lpOverlapped, Status));
  544. SetLastError(Status);
  545. return Status == ERROR_SUCCESS;
  546. }
  547. BOOL QfsFlushFileBuffers(
  548. QfsHANDLE hFile // handle to file
  549. )
  550. {
  551. PJOB_BUF j;
  552. DWORD Status = QfspReserveBuffer(opFlushFile, NULL, HandlePtr(hFile), &j);
  553. if (Status == ERROR_SUCCESS) {
  554. QfspDeliverBuffer(j, &Status);
  555. QfspReleaseBuffer(j);
  556. } else if (Status == ERROR_NO_MATCH) {
  557. Status = FlushFileBuffers(GetRealHandle(hFile))?ERROR_SUCCESS:GetLastError();
  558. }
  559. QfsNoise(("[Qfs] QfsFlushBuffers %x, status %d", GetRealHandle(hFile), Status));
  560. SetLastError(Status);
  561. return Status == ERROR_SUCCESS;
  562. }
  563. BOOL QfsDeleteFile(
  564. LPCTSTR lpFileName
  565. )
  566. {
  567. PJOB_BUF j;
  568. DWORD Status = QfspReserveBuffer(opDeleteFile, lpFileName, NULL, &j);
  569. if (Status == ERROR_SUCCESS) {
  570. QfspDeliverBuffer(j, &Status);
  571. QfspReleaseBuffer(j);
  572. } else if (Status == ERROR_NO_MATCH) {
  573. Status = DeleteFile(lpFileName)?ERROR_SUCCESS:GetLastError();
  574. }
  575. QfsNoise(("[Qfs] QfsDeleteFile %ws, status %d", lpFileName, Status));
  576. SetLastError(Status);
  577. return Status == ERROR_SUCCESS;
  578. }
  579. BOOL QfsRemoveDirectory(
  580. LPCTSTR lpFileName
  581. )
  582. {
  583. PJOB_BUF j;
  584. DWORD Status = QfspReserveBuffer(opDeleteFile, lpFileName, NULL, &j);
  585. if (Status == ERROR_SUCCESS) {
  586. QfspDeliverBuffer(j, &Status);
  587. QfspReleaseBuffer(j);
  588. } else if (Status == ERROR_NO_MATCH) {
  589. Status = RemoveDirectory(lpFileName)?ERROR_SUCCESS:GetLastError();
  590. }
  591. QfsNoise(("[Qfs] QfsRemoveDirectory %ws, status %d", lpFileName, Status));
  592. SetLastError(Status);
  593. return Status == ERROR_SUCCESS;
  594. }
  595. QfsHANDLE QfsFindFirstFile(
  596. LPCWSTR lpFileName, // file name
  597. LPWIN32_FIND_DATA lpFindFileData // data buffer
  598. )
  599. {
  600. QfsHANDLE Result=QfsINVALID_HANDLE_VALUE;
  601. PJOB_BUF j;
  602. DWORD Status = QfspReserveBuffer(opFindFirstFile, lpFileName, NULL, &j);
  603. if (Status == ERROR_SUCCESS) {
  604. if(QfspDeliverBuffer(j, &Status)) {
  605. Result = MakeQfsHandle(j->Handle);
  606. *lpFindFileData = j->FindFileData;
  607. } else {
  608. Result = QfsINVALID_HANDLE_VALUE;
  609. }
  610. QfspReleaseBuffer(j);
  611. } else if (Status == ERROR_NO_MATCH) {
  612. Result = MakeWin32Handle(
  613. FindFirstFile(lpFileName, lpFindFileData)
  614. );
  615. Status = QfsIsHandleValid(Result)?ERROR_SUCCESS:GetLastError();
  616. }
  617. QfsNoise(("[Qfs] QfsFindFirstFile %ws => %x, error %d", lpFileName, GetRealHandle(Result), Status));
  618. SetLastError(Status);
  619. return Result;
  620. }
  621. BOOL QfsFindNextFile(
  622. QfsHANDLE hFindFile, // search handle
  623. LPWIN32_FIND_DATA lpFindFileData // data buffer
  624. )
  625. {
  626. PJOB_BUF j;
  627. DWORD Status = QfspReserveBuffer(opFindNextFile, NULL, HandlePtr(hFindFile), &j);
  628. if (Status == ERROR_SUCCESS) {
  629. if(QfspDeliverBuffer(j, &Status)) {
  630. *lpFindFileData = j->FindFileData;
  631. }
  632. QfspReleaseBuffer(j);
  633. } else if (Status == ERROR_NO_MATCH) {
  634. StatusFromBool( FindNextFile(GetRealHandle(hFindFile), lpFindFileData) );
  635. }
  636. QfsNoise(("[Qfs] QfsFindNextFile %x", GetRealHandle(hFindFile)));
  637. SetLastError(Status);
  638. return Status == ERROR_SUCCESS;
  639. }
  640. BOOL QfsFindClose(
  641. QfsHANDLE hFindFile // file search handle
  642. )
  643. {
  644. PJOB_BUF j;
  645. DWORD Status = QfspReserveBuffer(opFindClose, NULL, HandlePtr(hFindFile), &j);
  646. if (Status == ERROR_SUCCESS) {
  647. QfspDeliverBuffer(j, &Status);
  648. QfspReleaseBuffer(j);
  649. } else if (Status == ERROR_NO_MATCH) {
  650. StatusFromBool( FindClose(GetRealHandle(hFindFile)) );
  651. }
  652. QfsNoise(("[Qfs] QfsFindClose %x", GetRealHandle(hFindFile)));
  653. SetLastError(Status);
  654. return Status == ERROR_SUCCESS;
  655. }
  656. BOOL QfsCreateDirectory(
  657. LPCWSTR lpPathName, // directory name
  658. LPSECURITY_ATTRIBUTES lpSecurityAttributes // SD
  659. )
  660. {
  661. PJOB_BUF j;
  662. DWORD Status = QfspReserveBuffer(opCreateDir, lpPathName, NULL, &j);
  663. if (Status == ERROR_SUCCESS) {
  664. QfspDeliverBuffer(j, &Status);
  665. QfspReleaseBuffer(j);
  666. } else if (Status == ERROR_NO_MATCH) {
  667. StatusFromBool( CreateDirectory(lpPathName, lpSecurityAttributes) );
  668. }
  669. QfsNoise(("[Qfs] QfsCreateDirectory %ws, status %d", lpPathName, Status));
  670. SetLastError(Status);
  671. return Status == ERROR_SUCCESS;
  672. }
  673. BOOL QfsGetDiskFreeSpaceEx(
  674. LPCTSTR lpDirectoryName, // directory name
  675. PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
  676. PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
  677. PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  678. )
  679. {
  680. PJOB_BUF j;
  681. DWORD Status = QfspReserveBuffer(opGetDiskFreeSpace, lpDirectoryName, NULL, &j);
  682. if (Status == ERROR_SUCCESS) {
  683. if(QfspDeliverBuffer(j, &Status)) {
  684. lpFreeBytesAvailable->QuadPart = j->FreeBytesAvailable;
  685. lpTotalNumberOfBytes->QuadPart = j->TotalNumberOfBytes;
  686. if (lpTotalNumberOfFreeBytes) {
  687. lpTotalNumberOfFreeBytes->QuadPart = j->TotalNumberOfFreeBytes;
  688. }
  689. }
  690. QfspReleaseBuffer(j);
  691. } else if (Status == ERROR_NO_MATCH) {
  692. StatusFromBool( GetDiskFreeSpaceEx(lpDirectoryName, lpFreeBytesAvailable,
  693. lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes) );
  694. }
  695. QfsNoise(("[Qfs] GetDiskFreeSpaceEx %ws, status %d", lpDirectoryName, Status));
  696. SetLastError(Status);
  697. return Status == ERROR_SUCCESS;
  698. }
  699. BOOL QfsGetFileSizeEx(
  700. QfsHANDLE hFile, // handle to file
  701. PLARGE_INTEGER lpFileSize) // file size
  702. {
  703. PJOB_BUF j;
  704. DWORD Status = QfspReserveBuffer(opGetAttr, NULL, HandlePtr(hFile), &j);
  705. if (Status == ERROR_SUCCESS) {
  706. if(QfspDeliverBuffer(j, &Status)) {
  707. lpFileSize->QuadPart = j->EndOfFile;
  708. }
  709. QfspReleaseBuffer(j);
  710. } else if (Status == ERROR_NO_MATCH) {
  711. StatusFromBool( GetFileSizeEx(GetRealHandle(hFile), lpFileSize) );
  712. }
  713. QfsNoise(("[Qfs] QfsGetFileSize %x %I64d", GetRealHandle(hFile), lpFileSize->QuadPart));
  714. SetLastError(Status);
  715. return Status == ERROR_SUCCESS;
  716. }
  717. DWORD QfsGetFileSize(
  718. QfsHANDLE hFile, // handle to file
  719. LPDWORD lpFileSizeHigh) // high-order word of file size
  720. {
  721. LARGE_INTEGER Li;
  722. if ( QfsGetFileSizeEx(hFile,&Li) ) {
  723. if ( lpFileSizeHigh ) {
  724. *lpFileSizeHigh = (DWORD)Li.HighPart;
  725. }
  726. if (Li.LowPart == -1 ) {
  727. SetLastError(0);
  728. }
  729. } else {
  730. Li.LowPart = -1;
  731. }
  732. return Li.LowPart;
  733. }
  734. // NOWHOW MNS interprets WriteFile with Size zero as SetEndOfFile //
  735. DWORD QfsSetEndOfFile(
  736. QfsHANDLE hFile,
  737. LONGLONG Offset
  738. )
  739. {
  740. PJOB_BUF j;
  741. DWORD Status = QfspReserveBuffer(opWriteFile, NULL, HandlePtr(hFile), &j);
  742. if (Status == ERROR_SUCCESS) {
  743. j->Offset = Offset;
  744. j->cbSize = 0;
  745. QfspDeliverBuffer(j, &Status);
  746. QfspReleaseBuffer(j);
  747. } else if (Status == ERROR_NO_MATCH) {
  748. Status = SetFilePointerEx(GetRealHandle(hFile), *(PLARGE_INTEGER)&Offset, NULL, FILE_BEGIN);
  749. if (Status != 0xFFFFFFFF && SetEndOfFile(GetRealHandle(hFile))) {
  750. Status = ERROR_SUCCESS;
  751. } else {
  752. Status = GetLastError();
  753. }
  754. }
  755. QfsNoise(("[Qfs] QfsSetEndOfFile %x %d, Status %d", GetRealHandle(hFile), Offset, Status));
  756. return Status;
  757. }
  758. DWORD QfsIsOnline(
  759. IN LPCWSTR Path,
  760. OUT BOOL *pfOnline
  761. )
  762. {
  763. PJOB_BUF j;
  764. DWORD Status=ERROR_NO_MATCH;
  765. if (IsQfsPath(Path)) {
  766. // This is a MNS path.
  767. // Try to perform null operation on the server.
  768. //
  769. Status = QfspReserveBufferNoChecks(opNone, NULL, NULL, &j);
  770. if (Status == ERROR_SUCCESS) {
  771. *pfOnline = QfspDeliverBuffer(j, &Status);
  772. QfspReleaseBuffer(j);
  773. }
  774. else {
  775. *pfOnline = FALSE;
  776. }
  777. }
  778. else {
  779. // Cases:
  780. // 1. If this is not MNS path, should return ERROR_NO_MATCH.
  781. // 2. If this is MNS path, but MNS not online, should return some other error value.
  782. //
  783. // Soln: IsQfsPath() now returns the error value through SetLastError().
  784. //
  785. Status = GetLastError();
  786. *pfOnline = FALSE;
  787. }
  788. QfsNoise(("[Qfs] QfsIsOnline => %d, Status %d", *pfOnline, Status));
  789. return Status;
  790. }
  791. HANDLE QfsCreateFileMapping(
  792. QfsHANDLE hFile, // handle to file
  793. LPSECURITY_ATTRIBUTES lpAttributes, // security
  794. DWORD flProtect, // protection
  795. DWORD dwMaximumSizeHigh, // high-order DWORD of size
  796. DWORD dwMaximumSizeLow, // low-order DWORD of size
  797. LPCTSTR lpName // object name
  798. )
  799. {
  800. if (IsQfsHandle(hFile)) {
  801. QfsError(("[Qfs] !!!!! CreateFileMapping for qfs handle !!!!! %x", hFile));
  802. return INVALID_HANDLE_VALUE;
  803. } else {
  804. return CreateFileMapping(GetRealHandle(hFile), lpAttributes, flProtect,
  805. dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
  806. }
  807. }
  808. BOOL QfsGetOverlappedResult(
  809. QfsHANDLE hFile, // handle to file, pipe, or device
  810. LPOVERLAPPED lpOverlapped, // overlapped structure
  811. LPDWORD lpNumberOfBytesTransferred, // bytes transferred
  812. BOOL bWait // wait option
  813. )
  814. {
  815. if (IsQfsHandle(hFile)) {
  816. QfsError(("[Qfs] GetOverlappedResults for qfs handle !!!%x", hFile));
  817. return FALSE;
  818. } else {
  819. return GetOverlappedResult(GetRealHandle(hFile), lpOverlapped,
  820. lpNumberOfBytesTransferred, bWait);
  821. }
  822. }
  823. BOOL QfsSetFileAttributes(
  824. LPCWSTR lpFileName, // file name
  825. DWORD dwFileAttributes // attributes
  826. )
  827. {
  828. PJOB_BUF j;
  829. DWORD Status = QfspReserveBuffer(opSetAttr2, lpFileName, NULL, &j);
  830. if (Status == ERROR_SUCCESS) {
  831. j->EndOfFile = 0;
  832. j->AllocationSize = 0;
  833. j->CreationTime = 0;
  834. j->LastAccessTime = 0;
  835. j->LastWriteTime = 0;
  836. j->FileAttributes = dwFileAttributes;
  837. QfspDeliverBuffer(j, &Status);
  838. QfspReleaseBuffer(j);
  839. } else if (Status == ERROR_NO_MATCH) {
  840. StatusFromBool( SetFileAttributes(lpFileName, dwFileAttributes) );
  841. }
  842. QfsNoise(("[Qfs] QfsSetFileAttributes %ws %x, status %d", lpFileName, dwFileAttributes, Status));
  843. SetLastError(Status);
  844. return Status == ERROR_SUCCESS;
  845. }
  846. BOOL QfsCopyFile(
  847. LPCWSTR lpExistingFileName,
  848. LPCWSTR lpNewFileName,
  849. BOOL bFailIfExists
  850. )
  851. {
  852. return QfsCopyFileEx(
  853. lpExistingFileName,
  854. lpNewFileName,
  855. (LPPROGRESS_ROUTINE)NULL,
  856. (LPVOID)NULL,
  857. (LPBOOL)NULL,
  858. bFailIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0
  859. );
  860. }
  861. // We have to implement our own version of CopyFile,
  862. // using Qfs apis, if either a source or destination contain QfsPath
  863. #define BUF_SIZE (32 * 1024)
  864. #define COPY_FILE_FLUSH_BUFFERS 1
  865. DWORD QfspCopyFileInternal(
  866. LPCWSTR lpSrc,
  867. LPCWSTR lpDst,
  868. LPBOOL pbCancel,
  869. DWORD dwCopyFlags,
  870. DWORD ExtraFlags)
  871. {
  872. QfsHANDLE src = QfsINVALID_HANDLE_VALUE;
  873. QfsHANDLE dst = QfsINVALID_HANDLE_VALUE;
  874. DWORD dstDisp;
  875. char* buf = malloc(65536);
  876. DWORD Status=ERROR_SUCCESS;
  877. if (buf == NULL) {
  878. Status = GetLastError();
  879. goto exit;
  880. }
  881. if (dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) {
  882. dstDisp = CREATE_NEW;
  883. } else {
  884. dstDisp = CREATE_ALWAYS;
  885. }
  886. src = QfsCreateFile(lpSrc,
  887. GENERIC_READ,
  888. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  889. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  890. if (!QfsIsHandleValid(src)) {
  891. Status = GetLastError();
  892. goto exit;
  893. }
  894. dst = QfsCreateFile(lpDst,
  895. GENERIC_WRITE,
  896. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
  897. dstDisp, FILE_ATTRIBUTE_NORMAL, NULL);
  898. if (!QfsIsHandleValid(dst)) {
  899. Status = GetLastError();
  900. goto exit;
  901. }
  902. for(;;) {
  903. DWORD dwSize;
  904. if (pbCancel && *pbCancel) {
  905. Status = ERROR_OPERATION_ABORTED;
  906. goto exit;
  907. }
  908. if ( !QfsReadFile(src, buf, BUF_SIZE, &dwSize, NULL) ) {
  909. Status = GetLastError();
  910. goto exit;
  911. }
  912. if (dwSize == 0) {
  913. break;
  914. }
  915. if (pbCancel && *pbCancel) {
  916. Status = ERROR_OPERATION_ABORTED;
  917. goto exit;
  918. }
  919. if (!QfsWriteFile(dst, buf, dwSize, &dwSize, NULL) ) {
  920. Status = GetLastError();
  921. goto exit;
  922. }
  923. }
  924. if (ExtraFlags & COPY_FILE_FLUSH_BUFFERS) {
  925. QfsFlushFileBuffers(dst);
  926. }
  927. exit:
  928. QfsCloseHandleIfValid(src);
  929. QfsCloseHandleIfValid(dst);
  930. if (buf) { free(buf); }
  931. return Status;
  932. }
  933. BOOL QfsCopyFileEx(
  934. LPCWSTR lpExistingFileName, // name of existing file
  935. LPCWSTR lpNewFileName, // name of new file
  936. LPPROGRESS_ROUTINE lpProgressRoutine, // callback function
  937. LPVOID lpData, // callback parameter
  938. LPBOOL pbCancel, // cancel status
  939. DWORD dwCopyFlags // copy options
  940. )
  941. {
  942. DWORD Status;
  943. if (!IsQfsPath(lpExistingFileName) && !IsQfsPath(lpNewFileName)) {
  944. BoolToStatus( CopyFileEx(lpExistingFileName, lpNewFileName, lpProgressRoutine,
  945. lpData, pbCancel, dwCopyFlags) );
  946. } else if (lpProgressRoutine || (dwCopyFlags & COPY_FILE_RESTARTABLE)) {
  947. Status = ERROR_INVALID_PARAMETER;
  948. } else {
  949. Status = QfspCopyFileInternal(
  950. lpExistingFileName, lpNewFileName, pbCancel, dwCopyFlags, 0);
  951. }
  952. QfsNoise(("[Qfs] QfsCopyFileEx %ws=>%ws, status %d", lpExistingFileName, lpNewFileName, Status));
  953. return Status == ERROR_SUCCESS;
  954. }
  955. BOOL QfsMoveFileEx(
  956. LPCWSTR lpExistingFileName, // file name
  957. LPCWSTR lpNewFileName, // new file name
  958. DWORD dwFlags // move options
  959. )
  960. {
  961. BOOL bSrcQfs = IsQfsPath(lpExistingFileName);
  962. BOOL bDstQfs = IsQfsPath(lpNewFileName);
  963. DWORD Status;
  964. if (!bSrcQfs && !bDstQfs) {
  965. BoolToStatus( MoveFileEx(lpExistingFileName, lpNewFileName, dwFlags) );
  966. } else if (bSrcQfs && bDstQfs) {
  967. PJOB_BUF j;
  968. Status = QfspReserveBuffer(opRename, lpExistingFileName, NULL, &j);
  969. if (Status == ERROR_SUCCESS) {
  970. Status = QfspCopyPath(j->FileNameDest, sizeof(j->FileNameDest), lpNewFileName);
  971. if (Status == ERROR_SUCCESS) {
  972. QfspDeliverBuffer(j, &Status);
  973. }
  974. QfspReleaseBuffer(j);
  975. }
  976. } else {
  977. BoolToStatus(
  978. QfsClRtlCopyFileAndFlushBuffers(lpExistingFileName, lpNewFileName) );
  979. if (Status == ERROR_SUCCESS) {
  980. BoolToStatus(QfsDeleteFile(lpExistingFileName));
  981. }
  982. }
  983. QfsNoise(("[Qfs] QfsMoveFileEx %ws=>%ws", lpExistingFileName, lpNewFileName));
  984. SetLastError(Status);
  985. return Status == ERROR_SUCCESS;
  986. }
  987. // GetTempFileName had to be shimmed so that it can work over Qfs path
  988. UINT QfsGetTempFileName(
  989. LPCWSTR lpPathName, // directory name
  990. LPCWSTR lpPrefixString, // file name prefix
  991. UINT uUnique, // integer
  992. LPWSTR lpTempFileName // file name buffer
  993. )
  994. {
  995. DWORD Status = ERROR_SUCCESS;
  996. if ( IsQfsPath(lpPathName) ) {
  997. int len;
  998. wcscpy(lpTempFileName, lpPathName);
  999. wcscat(lpTempFileName, lpPrefixString);
  1000. len = wcslen(lpTempFileName);
  1001. uUnique = uUnique & 0x0000ffff;
  1002. if (uUnique) {
  1003. wsprintf(lpTempFileName+len, L"%04x.tmp", uUnique);
  1004. } else {
  1005. DWORD uStartPoint = GetTickCount() & 0x0000ffff | 1;
  1006. uUnique = uStartPoint;
  1007. for(;;) {
  1008. QfsHANDLE hdl;
  1009. wsprintf(lpTempFileName+len, L"%04x.tmp", uUnique);
  1010. hdl = QfsCreateFile(lpTempFileName, GENERIC_WRITE,
  1011. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_NEW, 0, 0);
  1012. if (QfsIsHandleValid(hdl)) {
  1013. QfsCloseHandle(hdl);
  1014. break;
  1015. }
  1016. Status = GetLastError();
  1017. if (Status == ERROR_ALREADY_EXISTS
  1018. ||Status == ERROR_FILE_EXISTS
  1019. ||Status == ERROR_SHARING_VIOLATION
  1020. ||Status == ERROR_ACCESS_DENIED)
  1021. {
  1022. uUnique = (uUnique + 1) & 0xFFFF;
  1023. if (uUnique == 0) { ++uUnique; }
  1024. if (uUnique == uStartPoint) {
  1025. SetLastError(Status = ERROR_NO_MORE_FILES);
  1026. break;
  1027. }
  1028. } else {
  1029. break;
  1030. }
  1031. }
  1032. }
  1033. } else { // not QfsPath
  1034. uUnique = GetTempFileName(
  1035. lpPathName, lpPrefixString, uUnique, lpTempFileName);
  1036. if (uUnique == 0) {
  1037. Status = GetLastError();
  1038. lpTempFileName[0] = 0;
  1039. }
  1040. }
  1041. QfsNoise(("[Qfs] QfsGetTempFileName %ws, %ws, %d => %ws, status %d",
  1042. lpPathName, lpPrefixString, uUnique, lpTempFileName, Status));
  1043. return uUnique;
  1044. }
  1045. // Helper routine for QfsRegSaveKey and QfsMapFileAndCheckSum
  1046. // creates thread specific TempFile name
  1047. DWORD QfspThreadTempFileName(
  1048. OUT LPWSTR Path // assumes MAX_PATH size
  1049. )
  1050. {
  1051. DWORD Status = GetModuleFileName(NULL, Path, MAX_PATH);
  1052. PWCHAR p;
  1053. if (Status == 0) {
  1054. return GetLastError();
  1055. }
  1056. if (Status == MAX_PATH) {
  1057. return ERROR_BUFFER_OVERFLOW;
  1058. }
  1059. p = wcsrchr(Path, '\\');
  1060. if (p == NULL) {
  1061. return ERROR_PATH_NOT_FOUND;
  1062. }
  1063. wsprintf(p+1, L"Qfs%x.tmp", GetCurrentThreadId());
  1064. QfsNoise(("[Qfs] TempName generated %ws", p));
  1065. return ERROR_SUCCESS;
  1066. }
  1067. // Saves registry key in a temporary file on the system disk
  1068. // then copies it onto the quorum
  1069. LONG QfsRegSaveKey(
  1070. HKEY hKey, // handle to key
  1071. LPCWSTR lpFile, // data file
  1072. LPSECURITY_ATTRIBUTES lpSecurityAttributes // SD
  1073. )
  1074. {
  1075. DWORD Status;
  1076. if (IsQfsPath(lpFile)) {
  1077. WCHAR TempName[MAX_PATH];
  1078. Status = QfspThreadTempFileName(TempName);
  1079. if (Status == ERROR_SUCCESS) {
  1080. DeleteFile(TempName);
  1081. Status = RegSaveKey(hKey, TempName, lpSecurityAttributes);
  1082. if (Status == ERROR_SUCCESS) {
  1083. BoolToStatus( QfsMoveFile(TempName, lpFile) );
  1084. }
  1085. }
  1086. } else {
  1087. Status = RegSaveKey(hKey, lpFile, lpSecurityAttributes);
  1088. }
  1089. QfsNoise(("[Qfs] QfsRegSaveKey %ws, status %d",
  1090. lpFile, Status));
  1091. return Status;
  1092. }
  1093. #ifndef DUMB_CLIENT
  1094. // Computes a checksome for the file on the quorum disk,
  1095. // by copying it to the temp file on the system disk and invoking regular MapFileAndChecksum API
  1096. DWORD QfsMapFileAndCheckSum(
  1097. LPCWSTR Filename,
  1098. PDWORD HeaderSum,
  1099. PDWORD CheckSum
  1100. )
  1101. {
  1102. DWORD RetCode = 1, Status;
  1103. if (IsQfsPath(Filename)) {
  1104. WCHAR TempName[MAX_PATH];
  1105. Status = QfspThreadTempFileName(TempName);
  1106. if (Status == ERROR_SUCCESS) {
  1107. DeleteFile(TempName);
  1108. if (QfsCopyFile(Filename, TempName, 0)) {
  1109. RetCode = MapFileAndCheckSum((LPWSTR)TempName, HeaderSum, CheckSum);
  1110. DeleteFile(TempName);
  1111. }
  1112. }
  1113. } else {
  1114. RetCode = MapFileAndCheckSum((LPWSTR)Filename, HeaderSum, CheckSum);
  1115. }
  1116. Status = RetCode ? GetLastError() : ERROR_SUCCESS;
  1117. QfsNoise(("[Qfs] QfsMapFileAndCheckSum %ws, ret %d status %d",
  1118. Filename, RetCode, Status));
  1119. return RetCode;
  1120. }
  1121. // Some of the ClRtl function has to be redone here.
  1122. // The reason is that ClRtl is not Qfs aware and cannot call Qfs shims directly
  1123. DWORD
  1124. QfsSetFileSecurityInfo(
  1125. IN LPCWSTR lpszFile,
  1126. IN DWORD dwAdminMask,
  1127. IN DWORD dwOwnerMask,
  1128. IN DWORD dwEveryoneMask
  1129. )
  1130. {
  1131. HANDLE hFile;
  1132. DWORD dwError;
  1133. if (IsQfsPath(lpszFile)) {
  1134. // don't do this for QFS shares
  1135. return ERROR_SUCCESS;
  1136. }
  1137. hFile = CreateFile(lpszFile,
  1138. GENERIC_READ|WRITE_DAC|READ_CONTROL,
  1139. 0,
  1140. NULL,
  1141. OPEN_ALWAYS,
  1142. FILE_FLAG_BACKUP_SEMANTICS,
  1143. NULL);
  1144. if (hFile == INVALID_HANDLE_VALUE)
  1145. {
  1146. dwError = GetLastError();
  1147. ClRtlLogPrint(LOG_UNUSUAL,
  1148. "[Qfs] QfsSetFileSecurityInfo - Failed to open file %1!ws!, Status=%2!u!\n",
  1149. lpszFile,
  1150. dwError);
  1151. return dwError;
  1152. }
  1153. dwError = ClRtlSetObjSecurityInfo(hFile,
  1154. SE_FILE_OBJECT,
  1155. dwAdminMask,
  1156. dwOwnerMask,
  1157. dwEveryoneMask);
  1158. CloseHandle(hFile);
  1159. return dwError;
  1160. }
  1161. #endif
  1162. BOOL
  1163. QfsClRtlCopyFileAndFlushBuffers(
  1164. IN LPCWSTR lpszSourceFile,
  1165. IN LPCWSTR lpszDestinationFile
  1166. )
  1167. {
  1168. DWORD Status = QfspCopyFileInternal(
  1169. lpszSourceFile, lpszDestinationFile,
  1170. NULL, 0, COPY_FILE_FLUSH_BUFFERS);
  1171. return Status == ERROR_SUCCESS;
  1172. }
  1173. BOOL QfsClRtlCreateDirectory(
  1174. IN LPCWSTR lpszPath
  1175. )
  1176. {
  1177. WCHAR cSlash = L'\\';
  1178. DWORD dwLen;
  1179. LPCWSTR pszNext;
  1180. WCHAR lpszDir[MAX_PATH];
  1181. LPWSTR pszDirPath=NULL;
  1182. DWORD dwError = ERROR_SUCCESS;
  1183. if (!lpszPath || ((dwLen=lstrlenW(lpszPath)) < 1))
  1184. {
  1185. dwError = ERROR_INVALID_PARAMETER;
  1186. goto FnExit;
  1187. }
  1188. pszDirPath = (LPWSTR)LocalAlloc(LMEM_FIXED, ((dwLen + 2) * sizeof(WCHAR)));
  1189. if (pszDirPath == NULL)
  1190. {
  1191. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1192. goto FnExit;
  1193. }
  1194. lstrcpyW(pszDirPath, lpszPath);
  1195. //if it doesnt terminate with \, terminate it
  1196. if (pszDirPath[dwLen-1] != cSlash)
  1197. {
  1198. pszDirPath[dwLen] = cSlash;
  1199. pszDirPath[dwLen+1] = L'\0';
  1200. }
  1201. dwLen = lstrlenW(pszDirPath);
  1202. //handle SMB Path names e.g \\xyz\abc\lmn
  1203. if ((dwLen > 2) && (pszDirPath[0]== L'\\') && (pszDirPath[1] == L'\\'))
  1204. {
  1205. //check if the name if of format \\?\UNC\XYZ\ABC\LMN
  1206. // or if the format \\?\C:\xyz\abz
  1207. if ((dwLen >3) && (pszDirPath[2] == L'?'))
  1208. {
  1209. //search for the \ after ?
  1210. pszNext = wcschr(pszDirPath + 2, cSlash);
  1211. //check if it is followed by UNC
  1212. if (pszNext)
  1213. {
  1214. if (!wcsncmp(pszNext+1, L"UNC", lstrlenW(L"UNC")))
  1215. {
  1216. //it is a UNC Path name
  1217. //move past the third slash from here
  1218. pszNext = wcschr(pszNext+1, cSlash);
  1219. if (pszNext)
  1220. pszNext = wcschr(pszNext+1, cSlash);
  1221. if (pszNext)
  1222. pszNext = wcschr(pszNext+1, cSlash);
  1223. }
  1224. else
  1225. {
  1226. //it is a volume name, move to the next slash
  1227. pszNext = wcschr(pszNext+1, cSlash);
  1228. }
  1229. }
  1230. }
  1231. else
  1232. {
  1233. //it is of type \\xyz\abc\lmn
  1234. pszNext = wcschr(pszDirPath + 2, cSlash);
  1235. if (pszNext)
  1236. pszNext = wcschr(pszNext+1, cSlash);
  1237. }
  1238. }
  1239. else
  1240. {
  1241. pszNext = pszDirPath;
  1242. pszNext = wcschr(pszNext, cSlash);
  1243. // if the character before the first \ is :, skip the creation
  1244. // of the c:\ level directory
  1245. if (pszNext && pszNext > pszDirPath)
  1246. {
  1247. pszNext--;
  1248. if (*pszNext == L':')
  1249. {
  1250. pszNext++;
  1251. pszNext = wcschr(pszNext+1, cSlash);
  1252. }
  1253. else
  1254. pszNext++;
  1255. }
  1256. }
  1257. while ( pszNext)
  1258. {
  1259. DWORD_PTR dwptrLen;
  1260. dwptrLen = pszNext - pszDirPath + 1;
  1261. dwLen=(DWORD)dwptrLen;
  1262. lstrcpynW(lpszDir, pszDirPath, dwLen+1);
  1263. if (!QfsCreateDirectory(lpszDir, NULL))
  1264. {
  1265. dwError = GetLastError();
  1266. if (dwError == ERROR_ALREADY_EXISTS)
  1267. {
  1268. //this is not a problem,continue
  1269. dwError = ERROR_SUCCESS;
  1270. }
  1271. else
  1272. {
  1273. QfsError(("[ClRtl] CreateDirectory Failed on %ws. Error %u",
  1274. lpszDir, dwError));
  1275. goto FnExit;
  1276. }
  1277. }
  1278. pszNext = wcschr(pszNext+1, cSlash);
  1279. }
  1280. FnExit:
  1281. if (pszDirPath) LocalFree(pszDirPath);
  1282. return(dwError);
  1283. }