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.

656 lines
15 KiB

  1. #include <win32.h>
  2. #include <vfw.h>
  3. #include "debug.h"
  4. #include "fileshar.h"
  5. #ifdef USE_DIRECTIO
  6. #include "directio.h"
  7. #endif
  8. #define MAXTASKS 10
  9. #ifdef _WIN32
  10. #define CurrentProcess() ((HANDLE) GetCurrentProcessId())
  11. #else
  12. #define CurrentProcess() ((HANDLE) GetCurrentPDB())
  13. #endif
  14. #ifdef _WIN32
  15. #define HSHfromPSH(psh) (HSHFILE) psh
  16. #define PSHfromHSH(hsh) (PSHFILE) hsh
  17. #else
  18. #define HSHfromPSH(psh) (HSHFILE) GlobalPtrHandle(psh)
  19. #define PSHfromHSH(hsh) (PSHFILE) GlobalLock((HGLOBAL) hsh)
  20. #endif
  21. //
  22. // allow multiple processes to use the same file handle (as will happen on
  23. // win16 and chicago when an interface pointer is simply-marshalled to another
  24. // process that shares the same global address space).
  25. //
  26. // This will not happen on NT, but we retain the code structure.
  27. //
  28. #ifdef USE_DIRECTIO
  29. // use unbuffered i/o direct to the disk, rather than going through
  30. // mmio and the disk buffer. much faster for streaming reads and writes.
  31. // open via mmio if direct io not possible (eg mmio handler installed).
  32. #endif
  33. typedef struct {
  34. #ifndef DAYTONA
  35. TCHAR szFile[256];
  36. DWORD dwOpenFlags;
  37. MMIOINFO mmioinfo;
  38. HANDLE htask;
  39. int i;
  40. LONG lOffset;
  41. HANDLE ahtask[MAXTASKS];
  42. HMMIO ahmmio[MAXTASKS];
  43. ULONG ulRef[MAXTASKS];
  44. #else
  45. ULONG ulRef;
  46. #endif
  47. HMMIO hmmio;
  48. #ifdef USE_DIRECTIO
  49. CFileStream * pdio;
  50. #ifndef DAYTONA
  51. CFileStream * adio[MAXTASKS];
  52. #endif
  53. #endif
  54. } SHFILE, FAR * PSHFILE;
  55. #ifdef DAYTONA
  56. #define GetProperTask(psh) (TRUE)
  57. #else
  58. extern "C" {
  59. extern LPTSTR FAR lstrzcpy (LPTSTR pszTgt, LPCTSTR pszSrc, size_t cch);
  60. extern LPSTR FAR lstrzcpyA (LPSTR pszTgt, LPCSTR pszSrc, size_t cch);
  61. extern LPWSTR FAR lstrzcpyW (LPWSTR pszTgt, LPCWSTR pszSrc, size_t cch);
  62. extern LPWSTR FAR lstrzcpyAtoW (LPWSTR pszTgt, LPCSTR pszSrc, size_t cch);
  63. extern LPSTR FAR lstrzcpyWtoA (LPSTR pszTgt, LPCWSTR pszSrc, size_t cch);
  64. } // extern "C"
  65. BOOL GetProperTask(PSHFILE psh)
  66. {
  67. HANDLE htask = CurrentProcess();
  68. int i;
  69. if (htask == psh->htask)
  70. return
  71. #ifdef USE_DIRECTIO
  72. (psh->pdio != NULL) ||
  73. #endif
  74. ((psh->hmmio != 0) && (psh->hmmio != (HMMIO) -1));
  75. for (i = 0; i < MAXTASKS; i++) {
  76. if (psh->ahtask[i] == htask) {
  77. Success:
  78. psh->hmmio = psh->ahmmio[i];
  79. psh->htask = htask;
  80. psh->i = i;
  81. #ifdef USE_DIRECTIO
  82. psh->pdio = psh->adio[i];
  83. if (psh->pdio != NULL) {
  84. psh->pdio->Seek(psh->lOffset);
  85. return TRUE;
  86. }
  87. #endif
  88. mmioSeek(psh->hmmio, psh->lOffset, SEEK_SET);
  89. return (psh->hmmio != 0) && (psh->hmmio != (HMMIO) -1);
  90. }
  91. }
  92. for (i = 0; i < MAXTASKS; i++) {
  93. if (psh->ahtask[i] == 0) {
  94. DPF2("Re-opening handle %lx in task %x\n", psh, htask);
  95. #ifdef USE_DIRECTIO
  96. psh->adio[i] = new CFileStream;
  97. if (!psh->adio[i]->Open(psh->szFile,
  98. (psh->dwOpenFlags & OF_READWRITE),
  99. (psh->dwOpenFlags & OF_CREATE))) {
  100. delete psh->adio[i];
  101. psh->adio[i] = NULL;
  102. #else
  103. {
  104. #endif
  105. psh->ahmmio[i] = mmioOpen(psh->szFile, NULL, psh->dwOpenFlags);
  106. psh->ahtask[i] = htask;
  107. if (psh->ahmmio[i] == 0) {
  108. DPF("mmioOpen failed in GetProperTask!\n");
  109. return FALSE;
  110. }
  111. }
  112. goto Success;
  113. }
  114. }
  115. DPF("File handle open in too many tasks!\n");
  116. return FALSE;
  117. }
  118. #endif
  119. HSHFILE WINAPI shfileOpen(LPTSTR szFileName, MMIOINFO FAR* lpmmioinfo,
  120. DWORD dwOpenFlags)
  121. {
  122. PSHFILE psh = (PSHFILE) GlobalAllocPtr(GPTR | GMEM_SHARE, sizeof(SHFILE));
  123. if (!psh)
  124. return NULL;
  125. #ifndef DAYTONA
  126. lstrzcpy(psh->szFile, szFileName, NUMELMS(psh->szFile));
  127. psh->dwOpenFlags = dwOpenFlags;
  128. #endif
  129. psh->hmmio = NULL;
  130. #ifdef USE_DIRECTIO
  131. if (
  132. // Direct I/O is broken for reading the end of files on Chicago. Don't use it.
  133. #ifndef DIRECTIOFORREADINGALSO
  134. !(dwOpenFlags & OF_CREATE) ||
  135. #endif
  136. !(psh->pdio = new CFileStream) ||
  137. !psh->pdio->Open(
  138. szFileName,
  139. (dwOpenFlags & (OF_WRITE | OF_READWRITE)),
  140. (dwOpenFlags & OF_CREATE)))
  141. {
  142. if (psh->pdio)
  143. delete psh->pdio;
  144. psh->pdio = NULL;
  145. #else
  146. {
  147. #endif
  148. psh->hmmio = mmioOpen(szFileName, lpmmioinfo, dwOpenFlags);
  149. if (psh->hmmio == 0) {
  150. DPF("mmioOpen failed!\n");
  151. GlobalFreePtr(psh);
  152. return NULL;
  153. }
  154. }
  155. //DPF("Opening handle %lx ('%s') in task %x, mode = %lx\n", psh, szFileName, CurrentProcess(), psh->dwOpenFlags);
  156. #ifndef DAYTONA
  157. psh->ahmmio[0] = psh->hmmio;
  158. psh->ahtask[0] = psh->htask = CurrentProcess();
  159. psh->ulRef[0] = 1; // !!! 0?
  160. #ifdef USE_DIRECTIO
  161. psh->adio[0] = psh->pdio;
  162. #endif
  163. #else
  164. psh->ulRef = 1; // !!! 0?
  165. #endif
  166. return HSHfromPSH(psh);
  167. }
  168. UINT WINAPI shfileClose(HSHFILE hsh, UINT uFlags)
  169. {
  170. PSHFILE psh = PSHfromHSH(hsh);
  171. #ifndef DAYTONA
  172. int i;
  173. for (i = 0; i < MAXTASKS; i++) {
  174. if (psh->ahtask[i] && psh->ahmmio[i]) {
  175. DPF("Handle %lx closed with ref count %ld in task %x\n", psh, psh->ulRef[i], psh->ahtask[i]);
  176. #ifdef USE_DIRECTIO
  177. if (psh->adio[i]) {
  178. delete psh->adio[i];
  179. psh->adio[i] = NULL;
  180. } else
  181. #endif
  182. mmioClose(psh->ahmmio[i], 0);
  183. }
  184. }
  185. #else
  186. #ifdef USE_DIRECTIO
  187. if (psh->pdio) {
  188. delete psh->pdio;
  189. psh->pdio = NULL;
  190. } else
  191. #endif
  192. if (psh->hmmio) {
  193. mmioClose(psh->hmmio, 0);
  194. }
  195. #endif
  196. GlobalFreePtr(psh);
  197. return 0;
  198. }
  199. #ifdef USE_DIRECTIO
  200. // if we are using direct io, we want to bypass the buffering
  201. // schemes that are layered on top of this module. Allow them to
  202. // determine if we are using direct io to do this.
  203. BOOL shfileIsDirect(HSHFILE hsh)
  204. {
  205. PSHFILE psh = PSHfromHSH(hsh);
  206. if (!GetProperTask(psh))
  207. return -1;
  208. return (psh->pdio != 0);
  209. }
  210. void
  211. shfileStreamStart(HSHFILE hsh)
  212. {
  213. PSHFILE psh = PSHfromHSH(hsh);
  214. if (!GetProperTask(psh))
  215. return;
  216. if (psh->pdio == 0) {
  217. return;
  218. }
  219. psh->pdio->StartStreaming();
  220. }
  221. void shfileStreamStop(HSHFILE hsh)
  222. {
  223. PSHFILE psh = PSHfromHSH(hsh);
  224. if (!GetProperTask(psh))
  225. return;
  226. if (psh->pdio == 0) {
  227. return;
  228. }
  229. psh->pdio->StopStreaming();
  230. }
  231. #endif
  232. LONG WINAPI shfileRead(HSHFILE hsh, HPSTR pch, LONG cch)
  233. {
  234. PSHFILE psh = PSHfromHSH(hsh);
  235. if (!GetProperTask(psh))
  236. return -1;
  237. #ifndef DAYTONA
  238. psh->lOffset += cch;
  239. #endif
  240. #ifdef USE_DIRECTIO
  241. if (psh->pdio) {
  242. DWORD bytes;
  243. if (!psh->pdio->Read((LPBYTE)pch, cch, &bytes)) {
  244. return 0;
  245. } else {
  246. return bytes;
  247. }
  248. } else
  249. #endif
  250. return mmioRead(psh->hmmio, pch, cch);
  251. }
  252. LONG WINAPI shfileWrite(HSHFILE hsh, const char _huge* pch, LONG cch)
  253. {
  254. PSHFILE psh = PSHfromHSH(hsh);
  255. if (!GetProperTask(psh))
  256. return -1;
  257. #ifndef DAYTONA
  258. psh->lOffset += cch;
  259. #endif
  260. #ifdef USE_DIRECTIO
  261. if (psh->pdio) {
  262. DWORD bytes;
  263. if (!psh->pdio->Write((LPBYTE)pch, cch, &bytes)) {
  264. return 0;
  265. } else {
  266. return bytes;
  267. }
  268. } else
  269. #endif
  270. return mmioWrite(psh->hmmio, pch, cch);
  271. }
  272. LONG WINAPI shfileSeek(HSHFILE hsh, LONG lOffset, int iOrigin)
  273. {
  274. PSHFILE psh = PSHfromHSH(hsh);
  275. if (!GetProperTask(psh))
  276. return -1;
  277. #ifdef USE_DIRECTIO
  278. if (psh->pdio) {
  279. Assert(iOrigin != SEEK_END);
  280. if (iOrigin == SEEK_CUR) {
  281. lOffset += psh->pdio->GetCurrentPosition();
  282. }
  283. psh->pdio->Seek(lOffset);
  284. #ifndef DAYTONA
  285. psh->lOffset = psh->pdio->GetCurrentPosition();
  286. return psh->lOffset;
  287. #else
  288. return psh->pdio->GetCurrentPosition();
  289. #endif
  290. } else
  291. #endif
  292. {
  293. #ifdef DAYTONA
  294. return mmioSeek(psh->hmmio, lOffset, iOrigin);
  295. #else
  296. psh->lOffset = mmioSeek(psh->hmmio, lOffset, iOrigin);
  297. return psh->lOffset;
  298. #endif
  299. }
  300. }
  301. LONG WINAPI shfileZero(HSHFILE hsh, LONG lBytes)
  302. {
  303. LPVOID pmem;
  304. LONG lToWrite = lBytes;
  305. #define ZERO_AT_ONCE 1024
  306. pmem = GlobalAllocPtr(GPTR, ZERO_AT_ONCE);
  307. // We write out 1024 bytes at a time, with the odd bytes being written
  308. // in the last block. This is probably more efficient than writing the
  309. // "odd" bytes first, then looping for a known number of iterations to
  310. // write 1024 bytes at a time.
  311. if (pmem) {
  312. LONG cbWrite = ZERO_AT_ONCE;
  313. while (lToWrite > 0) {
  314. if (lToWrite < cbWrite) {
  315. cbWrite = lToWrite;
  316. }
  317. if (shfileWrite(hsh, (HPSTR) pmem, cbWrite) != cbWrite) {
  318. // The file write has failed. This leaves the file in
  319. // a bad state. It might be worth trying to position
  320. // the write pointer as though nothing had been written,
  321. // but this is problematic as there may be a serious
  322. // problem with the file itself. Simply abort writing...
  323. lBytes = -1;
  324. lToWrite = 0;
  325. break;
  326. }
  327. lToWrite -= cbWrite;
  328. }
  329. GlobalFreePtr(pmem);
  330. return lBytes;
  331. } else {
  332. DPF("Unable to allocate 1K of zeroed memory!\n");
  333. shfileSeek(hsh, lBytes, SEEK_SET);
  334. return lBytes;
  335. }
  336. }
  337. LONG WINAPI shfileFlush(HSHFILE hsh, UINT uFlags)
  338. {
  339. PSHFILE psh = PSHfromHSH(hsh);
  340. if (!GetProperTask(psh))
  341. return -1;
  342. #ifdef USE_DIRECTIO
  343. if (psh->pdio) {
  344. if (!psh->pdio->CommitAndWait()) {
  345. return MMIOERR_CANNOTWRITE;
  346. }
  347. }
  348. #endif
  349. return 0;
  350. }
  351. LONG WINAPI shfileAddRef(HSHFILE hsh)
  352. {
  353. PSHFILE psh = PSHfromHSH(hsh);
  354. if (!GetProperTask(psh))
  355. return -1;
  356. #ifdef DAYTONA
  357. psh->ulRef++;
  358. #else
  359. ++psh->ulRef[psh->i];
  360. DPF2("Handle %lx in task %x: ref++ == %ld\n", psh, psh->htask, psh->ulRef[psh->i]);
  361. #endif
  362. return 0;
  363. }
  364. LONG WINAPI shfileRelease(HSHFILE hsh)
  365. {
  366. PSHFILE psh = PSHfromHSH(hsh);
  367. if (!GetProperTask(psh))
  368. return -1;
  369. #ifdef DAYTONA
  370. if (--psh->ulRef <= 0)
  371. #else
  372. if (--psh->ulRef[psh->i] <= 0)
  373. #endif
  374. {
  375. #ifndef DAYTONA
  376. DPF2("Closing handle %lx in task %x, pos = %lx\n", psh, psh->htask, psh->lOffset);
  377. #endif
  378. #ifdef USE_DIRECTIO
  379. if (psh->pdio) {
  380. delete psh->pdio;
  381. psh->pdio = 0;
  382. } else
  383. #endif
  384. {
  385. mmioClose(psh->hmmio, 0);
  386. }
  387. psh->hmmio = 0;
  388. #ifndef DAYTONA
  389. psh->ahmmio[psh->i] = 0;
  390. psh->ahtask[psh->i] = 0;
  391. psh->ulRef[psh->i] = 0;
  392. #ifdef USE_DIRECTIO
  393. psh->adio[psh->i] = 0;
  394. #endif
  395. psh->htask = 0;
  396. #endif
  397. } else {
  398. #ifndef DAYTONA
  399. DPF2("Handle %lx in task %x: ref-- == %ld\n", psh, psh->htask, psh->ulRef[psh->i]);
  400. #endif
  401. }
  402. return 0;
  403. }
  404. static BYTE bPad;
  405. MMRESULT WINAPI
  406. shfileDescend(HSHFILE hshfile, LPMMCKINFO lpck, const LPMMCKINFO lpckParent, UINT wFlags)
  407. {
  408. FOURCC ckidFind; // chunk ID to find (or NULL)
  409. FOURCC fccTypeFind; // form/list type to find (or NULL)
  410. /* figure out what chunk id and form/list type to search for */
  411. if (wFlags & MMIO_FINDCHUNK)
  412. ckidFind = lpck->ckid, fccTypeFind = 0;
  413. else
  414. if (wFlags & MMIO_FINDRIFF)
  415. ckidFind = FOURCC_RIFF, fccTypeFind = lpck->fccType;
  416. else
  417. if (wFlags & MMIO_FINDLIST)
  418. ckidFind = FOURCC_LIST, fccTypeFind = lpck->fccType;
  419. else
  420. ckidFind = fccTypeFind = 0;
  421. lpck->dwFlags = 0L;
  422. while (TRUE)
  423. {
  424. UINT w;
  425. /* read the chunk header */
  426. if (shfileRead(hshfile, (HPSTR) lpck, 2 * sizeof(DWORD)) !=
  427. 2 * sizeof(DWORD))
  428. return MMIOERR_CHUNKNOTFOUND;
  429. /* store the offset of the data part of the chunk */
  430. if ((lpck->dwDataOffset = shfileSeek(hshfile, 0L, SEEK_CUR)) == -1)
  431. return MMIOERR_CANNOTSEEK;
  432. /* check for unreasonable chunk size */
  433. /* see if the chunk is within the parent chunk (if given) */
  434. if ((lpckParent != NULL) && (( lpck->dwDataOffset - 8L) >=
  435. (lpckParent->dwDataOffset + lpckParent->cksize)))
  436. return MMIOERR_CHUNKNOTFOUND;
  437. /* if the chunk if a 'RIFF' or 'LIST' chunk, read the
  438. * form type or list type
  439. */
  440. if ((lpck->ckid == FOURCC_RIFF) || (lpck->ckid == FOURCC_LIST))
  441. {
  442. if (shfileRead(hshfile, (HPSTR) &lpck->fccType,
  443. sizeof(DWORD)) != sizeof(DWORD))
  444. return MMIOERR_CHUNKNOTFOUND;
  445. }
  446. else
  447. lpck->fccType = 0;
  448. /* if this is the chunk we're looking for, stop looking */
  449. if ( ((ckidFind == 0) || (ckidFind == lpck->ckid)) &&
  450. ((fccTypeFind == 0) || (fccTypeFind == lpck->fccType)) )
  451. break;
  452. /* ascend out of the chunk and try again */
  453. if ((w = shfileAscend(hshfile, lpck, 0)) != 0)
  454. return w;
  455. }
  456. return 0;
  457. }
  458. MMRESULT WINAPI
  459. shfileAscend(HSHFILE hshfile, LPMMCKINFO lpck, UINT wFlags)
  460. {
  461. if (lpck->dwFlags & MMIO_DIRTY)
  462. {
  463. /* <lpck> refers to a chunk created by shfileCreateChunk();
  464. * check that the chunk size that was written when
  465. * shfileCreateChunk() was called is the real chunk size;
  466. * if not, fix it
  467. */
  468. DWORD dwOffset; // current offset in file
  469. DWORD dwActualSize; // actual size of chunk data
  470. if ((dwOffset = (DWORD)shfileSeek(hshfile, 0L, SEEK_CUR)) == -1)
  471. return MMIOERR_CANNOTSEEK;
  472. if ((LONG)(dwActualSize = dwOffset - lpck->dwDataOffset) < 0)
  473. return MMIOERR_CANNOTWRITE;
  474. if (LOWORD(dwActualSize) & 1)
  475. {
  476. /* chunk size is odd -- write a null pad byte */
  477. if (shfileWrite(hshfile, (HPSTR) &bPad, sizeof(bPad))
  478. != sizeof(bPad))
  479. return MMIOERR_CANNOTWRITE;
  480. }
  481. if (lpck->cksize == (DWORD)dwActualSize)
  482. return 0;
  483. /* fix the chunk header */
  484. lpck->cksize = dwActualSize;
  485. if (shfileSeek(hshfile, lpck->dwDataOffset
  486. - sizeof(DWORD), SEEK_SET) == -1)
  487. return MMIOERR_CANNOTSEEK;
  488. if (shfileWrite(hshfile, (HPSTR) &lpck->cksize,
  489. sizeof(DWORD)) != sizeof(DWORD))
  490. return MMIOERR_CANNOTWRITE;
  491. }
  492. /* seek to the end of the chunk, past the null pad byte
  493. * (which is only there if chunk size is odd)
  494. */
  495. if (shfileSeek(hshfile, lpck->dwDataOffset + lpck->cksize
  496. + (lpck->cksize & 1L), SEEK_SET) == -1)
  497. return MMIOERR_CANNOTSEEK;
  498. return 0;
  499. }
  500. MMRESULT WINAPI
  501. shfileCreateChunk(HSHFILE hshfile, LPMMCKINFO lpck, UINT wFlags)
  502. {
  503. int iBytes; // bytes to write
  504. DWORD dwOffset; // current offset in file
  505. /* store the offset of the data part of the chunk */
  506. if ((dwOffset = (DWORD)shfileSeek(hshfile, 0L, SEEK_CUR)) == -1)
  507. return MMIOERR_CANNOTSEEK;
  508. lpck->dwDataOffset = dwOffset + 2 * sizeof(DWORD);
  509. /* figure out if a form/list type needs to be written */
  510. if (wFlags & MMIO_CREATERIFF)
  511. lpck->ckid = FOURCC_RIFF, iBytes = 3 * sizeof(DWORD);
  512. else
  513. if (wFlags & MMIO_CREATELIST)
  514. lpck->ckid = FOURCC_LIST, iBytes = 3 * sizeof(DWORD);
  515. else
  516. iBytes = 2 * sizeof(DWORD);
  517. /* write the chunk header */
  518. if (shfileWrite(hshfile, (HPSTR) lpck, (LONG) iBytes) != (LONG) iBytes)
  519. return MMIOERR_CANNOTWRITE;
  520. lpck->dwFlags = MMIO_DIRTY;
  521. return 0;
  522. }