lsm_win32.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. /*
  2. ** 2011-12-03
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. **
  7. ** May you do good and not evil.
  8. ** May you find forgiveness for yourself and forgive others.
  9. ** May you share freely, never taking more than you give.
  10. **
  11. *************************************************************************
  12. **
  13. ** Win32-specific run-time environment implementation for LSM.
  14. */
  15. #ifdef _WIN32
  16. #include <assert.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include "windows.h"
  23. #include "lsmInt.h"
  24. /*
  25. ** An open file is an instance of the following object
  26. */
  27. typedef struct Win32File Win32File;
  28. struct Win32File {
  29. lsm_env *pEnv; /* The run-time environment */
  30. const char *zName; /* Full path to file */
  31. HANDLE hFile; /* Open file handle */
  32. HANDLE hShmFile; /* File handle for *-shm file */
  33. SYSTEM_INFO sysInfo; /* Operating system information */
  34. HANDLE hMap; /* File handle for mapping */
  35. LPVOID pMap; /* Pointer to mapping of file fd */
  36. size_t nMap; /* Size of mapping at pMap in bytes */
  37. int nShm; /* Number of entries in ahShm[]/apShm[] */
  38. LPHANDLE ahShm; /* Array of handles for shared mappings */
  39. LPVOID *apShm; /* Array of 32K shared memory segments */
  40. };
  41. static char *win32ShmFile(Win32File *pWin32File){
  42. char *zShm;
  43. int nName = strlen(pWin32File->zName);
  44. zShm = (char *)lsmMallocZero(pWin32File->pEnv, nName+4+1);
  45. if( zShm ){
  46. memcpy(zShm, pWin32File->zName, nName);
  47. memcpy(&zShm[nName], "-shm", 5);
  48. }
  49. return zShm;
  50. }
  51. static int win32Sleep(int us){
  52. Sleep((us + 999) / 1000);
  53. return LSM_OK;
  54. }
  55. /*
  56. ** The number of times that an I/O operation will be retried following a
  57. ** locking error - probably caused by antivirus software. Also the initial
  58. ** delay before the first retry. The delay increases linearly with each
  59. ** retry.
  60. */
  61. #ifndef LSM_WIN32_IOERR_RETRY
  62. # define LSM_WIN32_IOERR_RETRY 10
  63. #endif
  64. #ifndef LSM_WIN32_IOERR_RETRY_DELAY
  65. # define LSM_WIN32_IOERR_RETRY_DELAY 25000
  66. #endif
  67. static int win32IoerrRetry = LSM_WIN32_IOERR_RETRY;
  68. static int win32IoerrRetryDelay = LSM_WIN32_IOERR_RETRY_DELAY;
  69. /*
  70. ** The "win32IoerrCanRetry1" macro is used to determine if a particular
  71. ** I/O error code obtained via GetLastError() is eligible to be retried.
  72. ** It must accept the error code DWORD as its only argument and should
  73. ** return non-zero if the error code is transient in nature and the
  74. ** operation responsible for generating the original error might succeed
  75. ** upon being retried. The argument to this macro should be a variable.
  76. **
  77. ** Additionally, a macro named "win32IoerrCanRetry2" may be defined. If
  78. ** it is defined, it will be consulted only when the macro
  79. ** "win32IoerrCanRetry1" returns zero. The "win32IoerrCanRetry2" macro
  80. ** is completely optional and may be used to include additional error
  81. ** codes in the set that should result in the failing I/O operation being
  82. ** retried by the caller. If defined, the "win32IoerrCanRetry2" macro
  83. ** must exhibit external semantics identical to those of the
  84. ** "win32IoerrCanRetry1" macro.
  85. */
  86. #if !defined(win32IoerrCanRetry1)
  87. #define win32IoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
  88. ((a)==ERROR_SHARING_VIOLATION) || \
  89. ((a)==ERROR_LOCK_VIOLATION) || \
  90. ((a)==ERROR_DEV_NOT_EXIST) || \
  91. ((a)==ERROR_NETNAME_DELETED) || \
  92. ((a)==ERROR_SEM_TIMEOUT) || \
  93. ((a)==ERROR_NETWORK_UNREACHABLE))
  94. #endif
  95. /*
  96. ** If an I/O error occurs, invoke this routine to see if it should be
  97. ** retried. Return TRUE to retry. Return FALSE to give up with an
  98. ** error.
  99. */
  100. static int win32RetryIoerr(
  101. lsm_env *pEnv,
  102. int *pnRetry
  103. ){
  104. DWORD lastErrno;
  105. if( *pnRetry>=win32IoerrRetry ){
  106. return 0;
  107. }
  108. lastErrno = GetLastError();
  109. if( win32IoerrCanRetry1(lastErrno) ){
  110. win32Sleep(win32IoerrRetryDelay*(1+*pnRetry));
  111. ++*pnRetry;
  112. return 1;
  113. }
  114. #if defined(win32IoerrCanRetry2)
  115. else if( win32IoerrCanRetry2(lastErrno) ){
  116. win32Sleep(win32IoerrRetryDelay*(1+*pnRetry));
  117. ++*pnRetry;
  118. return 1;
  119. }
  120. #endif
  121. return 0;
  122. }
  123. /*
  124. ** Convert a UTF-8 string to Microsoft Unicode.
  125. **
  126. ** Space to hold the returned string is obtained from lsmMalloc().
  127. */
  128. static LPWSTR win32Utf8ToUnicode(lsm_env *pEnv, const char *zText){
  129. int nChar;
  130. LPWSTR zWideText;
  131. nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
  132. if( nChar==0 ){
  133. return 0;
  134. }
  135. zWideText = lsmMallocZero(pEnv, nChar * sizeof(WCHAR));
  136. if( zWideText==0 ){
  137. return 0;
  138. }
  139. nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, nChar);
  140. if( nChar==0 ){
  141. lsmFree(pEnv, zWideText);
  142. zWideText = 0;
  143. }
  144. return zWideText;
  145. }
  146. /*
  147. ** Convert a Microsoft Unicode string to UTF-8.
  148. **
  149. ** Space to hold the returned string is obtained from lsmMalloc().
  150. */
  151. static char *win32UnicodeToUtf8(lsm_env *pEnv, LPCWSTR zWideText){
  152. int nByte;
  153. char *zText;
  154. nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
  155. if( nByte == 0 ){
  156. return 0;
  157. }
  158. zText = lsmMallocZero(pEnv, nByte);
  159. if( zText==0 ){
  160. return 0;
  161. }
  162. nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, 0, 0);
  163. if( nByte == 0 ){
  164. lsmFree(pEnv, zText);
  165. zText = 0;
  166. }
  167. return zText;
  168. }
  169. #if !defined(win32IsNotFound)
  170. #define win32IsNotFound(a) (((a)==ERROR_FILE_NOT_FOUND) || \
  171. ((a)==ERROR_PATH_NOT_FOUND))
  172. #endif
  173. static int win32Open(
  174. lsm_env *pEnv,
  175. const char *zFile,
  176. int flags,
  177. LPHANDLE phFile
  178. ){
  179. int rc;
  180. LPWSTR zConverted;
  181. zConverted = win32Utf8ToUnicode(pEnv, zFile);
  182. if( zConverted==0 ){
  183. rc = LSM_NOMEM_BKPT;
  184. }else{
  185. int bReadonly = (flags & LSM_OPEN_READONLY);
  186. DWORD dwDesiredAccess;
  187. DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  188. DWORD dwCreationDisposition;
  189. DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
  190. HANDLE hFile;
  191. int nRetry = 0;
  192. if( bReadonly ){
  193. dwDesiredAccess = GENERIC_READ;
  194. dwCreationDisposition = OPEN_EXISTING;
  195. }else{
  196. dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
  197. dwCreationDisposition = OPEN_ALWAYS;
  198. }
  199. while( (hFile = CreateFileW((LPCWSTR)zConverted,
  200. dwDesiredAccess,
  201. dwShareMode, NULL,
  202. dwCreationDisposition,
  203. dwFlagsAndAttributes,
  204. NULL))==INVALID_HANDLE_VALUE &&
  205. win32RetryIoerr(pEnv, &nRetry) ){
  206. /* Noop */
  207. }
  208. lsmFree(pEnv, zConverted);
  209. if( hFile!=INVALID_HANDLE_VALUE ){
  210. *phFile = hFile;
  211. rc = LSM_OK;
  212. }else{
  213. if( win32IsNotFound(GetLastError()) ){
  214. rc = lsmErrorBkpt(LSM_IOERR_NOENT);
  215. }else{
  216. rc = LSM_IOERR_BKPT;
  217. }
  218. }
  219. }
  220. return rc;
  221. }
  222. static int lsmWin32OsOpen(
  223. lsm_env *pEnv,
  224. const char *zFile,
  225. int flags,
  226. lsm_file **ppFile
  227. ){
  228. int rc = LSM_OK;
  229. Win32File *pWin32File;
  230. pWin32File = lsmMallocZero(pEnv, sizeof(Win32File));
  231. if( pWin32File==0 ){
  232. rc = LSM_NOMEM_BKPT;
  233. }else{
  234. HANDLE hFile = NULL;
  235. rc = win32Open(pEnv, zFile, flags, &hFile);
  236. if( rc==LSM_OK ){
  237. memset(&pWin32File->sysInfo, 0, sizeof(SYSTEM_INFO));
  238. GetSystemInfo(&pWin32File->sysInfo);
  239. pWin32File->pEnv = pEnv;
  240. pWin32File->zName = zFile;
  241. pWin32File->hFile = hFile;
  242. }else{
  243. lsmFree(pEnv, pWin32File);
  244. pWin32File = 0;
  245. }
  246. }
  247. *ppFile = (lsm_file *)pWin32File;
  248. return rc;
  249. }
  250. static int lsmWin32OsWrite(
  251. lsm_file *pFile, /* File to write to */
  252. lsm_i64 iOff, /* Offset to write to */
  253. void *pData, /* Write data from this buffer */
  254. int nData /* Bytes of data to write */
  255. ){
  256. Win32File *pWin32File = (Win32File *)pFile;
  257. OVERLAPPED overlapped; /* The offset for WriteFile. */
  258. u8 *aRem = (u8 *)pData; /* Data yet to be written */
  259. int nRem = nData; /* Number of bytes yet to be written */
  260. int nRetry = 0; /* Number of retrys */
  261. memset(&overlapped, 0, sizeof(OVERLAPPED));
  262. overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF);
  263. overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF);
  264. while( nRem>0 ){
  265. DWORD nWrite = 0; /* Bytes written using WriteFile */
  266. if( !WriteFile(pWin32File->hFile, aRem, nRem, &nWrite, &overlapped) ){
  267. if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue;
  268. break;
  269. }
  270. assert( nWrite==0 || nWrite<=(DWORD)nRem );
  271. if( nWrite==0 || nWrite>(DWORD)nRem ){
  272. break;
  273. }
  274. iOff += nWrite;
  275. overlapped.Offset = (LONG)(iOff & 0xFFFFFFFF);
  276. overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF);
  277. aRem += nWrite;
  278. nRem -= nWrite;
  279. }
  280. if( nRem!=0 ) return LSM_IOERR_BKPT;
  281. return LSM_OK;
  282. }
  283. static int win32Truncate(
  284. HANDLE hFile,
  285. lsm_i64 nSize
  286. ){
  287. LARGE_INTEGER offset;
  288. offset.QuadPart = nSize;
  289. if( !SetFilePointerEx(hFile, offset, 0, FILE_BEGIN) ){
  290. return LSM_IOERR_BKPT;
  291. }
  292. if (!SetEndOfFile(hFile) ){
  293. return LSM_IOERR_BKPT;
  294. }
  295. return LSM_OK;
  296. }
  297. static int lsmWin32OsTruncate(
  298. lsm_file *pFile, /* File to write to */
  299. lsm_i64 nSize /* Size to truncate file to */
  300. ){
  301. Win32File *pWin32File = (Win32File *)pFile;
  302. return win32Truncate(pWin32File->hFile, nSize);
  303. }
  304. static int lsmWin32OsRead(
  305. lsm_file *pFile, /* File to read from */
  306. lsm_i64 iOff, /* Offset to read from */
  307. void *pData, /* Read data into this buffer */
  308. int nData /* Bytes of data to read */
  309. ){
  310. Win32File *pWin32File = (Win32File *)pFile;
  311. OVERLAPPED overlapped; /* The offset for ReadFile */
  312. DWORD nRead = 0; /* Bytes read using ReadFile */
  313. int nRetry = 0; /* Number of retrys */
  314. memset(&overlapped, 0, sizeof(OVERLAPPED));
  315. overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF);
  316. overlapped.OffsetHigh = (LONG)((iOff>>32) & 0X7FFFFFFF);
  317. while( !ReadFile(pWin32File->hFile, pData, nData, &nRead, &overlapped) &&
  318. GetLastError()!=ERROR_HANDLE_EOF ){
  319. if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue;
  320. return LSM_IOERR_BKPT;
  321. }
  322. if( nRead<(DWORD)nData ){
  323. /* Unread parts of the buffer must be zero-filled */
  324. memset(&((char*)pData)[nRead], 0, nData - nRead);
  325. }
  326. return LSM_OK;
  327. }
  328. static int lsmWin32OsSync(lsm_file *pFile){
  329. int rc = LSM_OK;
  330. #ifndef LSM_NO_SYNC
  331. Win32File *pWin32File = (Win32File *)pFile;
  332. if( pWin32File->pMap!=NULL ){
  333. if( !FlushViewOfFile(pWin32File->pMap, 0) ){
  334. rc = LSM_IOERR_BKPT;
  335. }
  336. }
  337. if( rc==LSM_OK && !FlushFileBuffers(pWin32File->hFile) ){
  338. rc = LSM_IOERR_BKPT;
  339. }
  340. #else
  341. unused_parameter(pFile);
  342. #endif
  343. return rc;
  344. }
  345. static int lsmWin32OsSectorSize(lsm_file *pFile){
  346. return 512;
  347. }
  348. static void win32Unmap(Win32File *pWin32File){
  349. if( pWin32File->pMap!=NULL ){
  350. UnmapViewOfFile(pWin32File->pMap);
  351. pWin32File->pMap = NULL;
  352. pWin32File->nMap = 0;
  353. }
  354. if( pWin32File->hMap!=NULL ){
  355. CloseHandle(pWin32File->hMap);
  356. pWin32File->hMap = NULL;
  357. }
  358. }
  359. static int lsmWin32OsRemap(
  360. lsm_file *pFile,
  361. lsm_i64 iMin,
  362. void **ppOut,
  363. lsm_i64 *pnOut
  364. ){
  365. Win32File *pWin32File = (Win32File *)pFile;
  366. /* If the file is between 0 and 2MB in size, extend it in chunks of 256K.
  367. ** Thereafter, in chunks of 1MB at a time. */
  368. const int aIncrSz[] = {256*1024, 1024*1024};
  369. int nIncrSz = aIncrSz[iMin>(2*1024*1024)];
  370. *ppOut = NULL;
  371. *pnOut = 0;
  372. win32Unmap(pWin32File);
  373. if( iMin>=0 ){
  374. LARGE_INTEGER fileSize;
  375. DWORD dwSizeHigh;
  376. DWORD dwSizeLow;
  377. HANDLE hMap;
  378. LPVOID pMap;
  379. memset(&fileSize, 0, sizeof(LARGE_INTEGER));
  380. if( !GetFileSizeEx(pWin32File->hFile, &fileSize) ){
  381. return LSM_IOERR_BKPT;
  382. }
  383. assert( fileSize.QuadPart>=0 );
  384. if( fileSize.QuadPart<iMin ){
  385. int rc;
  386. fileSize.QuadPart = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz;
  387. rc = lsmWin32OsTruncate(pFile, fileSize.QuadPart);
  388. if( rc!=LSM_OK ){
  389. return rc;
  390. }
  391. }
  392. dwSizeLow = (DWORD)(fileSize.QuadPart & 0xFFFFFFFF);
  393. dwSizeHigh = (DWORD)((fileSize.QuadPart & 0x7FFFFFFFFFFFFFFF) >> 32);
  394. hMap = CreateFileMappingW(pWin32File->hFile, NULL, PAGE_READWRITE,
  395. dwSizeHigh, dwSizeLow, NULL);
  396. if( hMap==NULL ){
  397. return LSM_IOERR_BKPT;
  398. }
  399. pWin32File->hMap = hMap;
  400. assert( fileSize.QuadPart<=0xFFFFFFFF );
  401. pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
  402. (SIZE_T)fileSize.QuadPart);
  403. if( pMap==NULL ){
  404. return LSM_IOERR_BKPT;
  405. }
  406. pWin32File->pMap = pMap;
  407. pWin32File->nMap = (SIZE_T)fileSize.QuadPart;
  408. }
  409. *ppOut = pWin32File->pMap;
  410. *pnOut = pWin32File->nMap;
  411. return LSM_OK;
  412. }
  413. static BOOL win32IsDriveLetterAndColon(
  414. const char *zPathname
  415. ){
  416. return ( isalpha(zPathname[0]) && zPathname[1]==':' );
  417. }
  418. static int lsmWin32OsFullpath(
  419. lsm_env *pEnv,
  420. const char *zName,
  421. char *zOut,
  422. int *pnOut
  423. ){
  424. DWORD nByte;
  425. void *zConverted;
  426. LPWSTR zTempWide;
  427. char *zTempUtf8;
  428. if( zName[0]=='/' && win32IsDriveLetterAndColon(zName+1) ){
  429. zName++;
  430. }
  431. zConverted = win32Utf8ToUnicode(pEnv, zName);
  432. if( zConverted==0 ){
  433. return LSM_NOMEM_BKPT;
  434. }
  435. nByte = GetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
  436. if( nByte==0 ){
  437. lsmFree(pEnv, zConverted);
  438. return LSM_IOERR_BKPT;
  439. }
  440. nByte += 3;
  441. zTempWide = lsmMallocZero(pEnv, nByte * sizeof(zTempWide[0]));
  442. if( zTempWide==0 ){
  443. lsmFree(pEnv, zConverted);
  444. return LSM_NOMEM_BKPT;
  445. }
  446. nByte = GetFullPathNameW((LPCWSTR)zConverted, nByte, zTempWide, 0);
  447. if( nByte==0 ){
  448. lsmFree(pEnv, zConverted);
  449. lsmFree(pEnv, zTempWide);
  450. return LSM_IOERR_BKPT;
  451. }
  452. lsmFree(pEnv, zConverted);
  453. zTempUtf8 = win32UnicodeToUtf8(pEnv, zTempWide);
  454. lsmFree(pEnv, zTempWide);
  455. if( zTempUtf8 ){
  456. int nOut = *pnOut;
  457. int nLen = strlen(zTempUtf8) + 1;
  458. if( nLen<=nOut ){
  459. snprintf(zOut, nOut, "%s", zTempUtf8);
  460. }
  461. lsmFree(pEnv, zTempUtf8);
  462. *pnOut = nLen;
  463. return LSM_OK;
  464. }else{
  465. return LSM_NOMEM_BKPT;
  466. }
  467. }
  468. static int lsmWin32OsFileid(
  469. lsm_file *pFile,
  470. void *pBuf,
  471. int *pnBuf
  472. ){
  473. int nBuf;
  474. int nReq;
  475. u8 *pBuf2 = (u8 *)pBuf;
  476. Win32File *pWin32File = (Win32File *)pFile;
  477. BY_HANDLE_FILE_INFORMATION fileInfo;
  478. nBuf = *pnBuf;
  479. nReq = (sizeof(fileInfo.dwVolumeSerialNumber) +
  480. sizeof(fileInfo.nFileIndexHigh) +
  481. sizeof(fileInfo.nFileIndexLow));
  482. *pnBuf = nReq;
  483. if( nReq>nBuf ) return LSM_OK;
  484. memset(&fileInfo, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
  485. if( !GetFileInformationByHandle(pWin32File->hFile, &fileInfo) ){
  486. return LSM_IOERR_BKPT;
  487. }
  488. nReq = sizeof(fileInfo.dwVolumeSerialNumber);
  489. memcpy(pBuf2, &fileInfo.dwVolumeSerialNumber, nReq);
  490. pBuf2 += nReq;
  491. nReq = sizeof(fileInfo.nFileIndexHigh);
  492. memcpy(pBuf, &fileInfo.nFileIndexHigh, nReq);
  493. pBuf2 += nReq;
  494. nReq = sizeof(fileInfo.nFileIndexLow);
  495. memcpy(pBuf2, &fileInfo.nFileIndexLow, nReq);
  496. return LSM_OK;
  497. }
  498. static int win32Delete(
  499. lsm_env *pEnv,
  500. const char *zFile
  501. ){
  502. int rc;
  503. LPWSTR zConverted;
  504. zConverted = win32Utf8ToUnicode(pEnv, zFile);
  505. if( zConverted==0 ){
  506. rc = LSM_NOMEM_BKPT;
  507. }else{
  508. int nRetry = 0;
  509. DWORD attr;
  510. do {
  511. attr = GetFileAttributesW(zConverted);
  512. if ( attr==INVALID_FILE_ATTRIBUTES ){
  513. rc = LSM_IOERR_BKPT;
  514. break;
  515. }
  516. if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
  517. rc = LSM_IOERR_BKPT; /* Files only. */
  518. break;
  519. }
  520. if ( DeleteFileW(zConverted) ){
  521. rc = LSM_OK; /* Deleted OK. */
  522. break;
  523. }
  524. if ( !win32RetryIoerr(pEnv, &nRetry) ){
  525. rc = LSM_IOERR_BKPT; /* No more retries. */
  526. break;
  527. }
  528. }while( 1 );
  529. }
  530. lsmFree(pEnv, zConverted);
  531. return rc;
  532. }
  533. static int lsmWin32OsUnlink(lsm_env *pEnv, const char *zFile){
  534. return win32Delete(pEnv, zFile);
  535. }
  536. #if !defined(win32IsLockBusy)
  537. #define win32IsLockBusy(a) (((a)==ERROR_LOCK_VIOLATION) || \
  538. ((a)==ERROR_IO_PENDING))
  539. #endif
  540. static int win32LockFile(
  541. Win32File *pWin32File,
  542. int iLock,
  543. int nLock,
  544. int eType
  545. ){
  546. OVERLAPPED ovlp;
  547. assert( LSM_LOCK_UNLOCK==0 );
  548. assert( LSM_LOCK_SHARED==1 );
  549. assert( LSM_LOCK_EXCL==2 );
  550. assert( eType>=LSM_LOCK_UNLOCK && eType<=LSM_LOCK_EXCL );
  551. assert( nLock>=0 );
  552. assert( iLock>0 && iLock<=32 );
  553. memset(&ovlp, 0, sizeof(OVERLAPPED));
  554. ovlp.Offset = (4096-iLock-nLock+1);
  555. if( eType>LSM_LOCK_UNLOCK ){
  556. DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
  557. if( eType>=LSM_LOCK_EXCL ) flags |= LOCKFILE_EXCLUSIVE_LOCK;
  558. if( !LockFileEx(pWin32File->hFile, flags, 0, (DWORD)nLock, 0, &ovlp) ){
  559. if( win32IsLockBusy(GetLastError()) ){
  560. return LSM_BUSY;
  561. }else{
  562. return LSM_IOERR_BKPT;
  563. }
  564. }
  565. }else{
  566. if( !UnlockFileEx(pWin32File->hFile, 0, (DWORD)nLock, 0, &ovlp) ){
  567. return LSM_IOERR_BKPT;
  568. }
  569. }
  570. return LSM_OK;
  571. }
  572. static int lsmWin32OsLock(lsm_file *pFile, int iLock, int eType){
  573. Win32File *pWin32File = (Win32File *)pFile;
  574. return win32LockFile(pWin32File, iLock, 1, eType);
  575. }
  576. static int lsmWin32OsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){
  577. int rc;
  578. Win32File *pWin32File = (Win32File *)pFile;
  579. rc = win32LockFile(pWin32File, iLock, nLock, eType);
  580. if( rc!=LSM_OK ) return rc;
  581. win32LockFile(pWin32File, iLock, nLock, LSM_LOCK_UNLOCK);
  582. return LSM_OK;
  583. }
  584. static int lsmWin32OsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
  585. int rc;
  586. Win32File *pWin32File = (Win32File *)pFile;
  587. int iOffset = iChunk * sz;
  588. int iOffsetShift = iOffset % pWin32File->sysInfo.dwAllocationGranularity;
  589. int nNew = iChunk + 1;
  590. lsm_i64 nReq = nNew * sz;
  591. *ppShm = NULL;
  592. assert( sz>=0 );
  593. assert( sz==LSM_SHM_CHUNK_SIZE );
  594. if( iChunk>=pWin32File->nShm ){
  595. LPHANDLE ahNew;
  596. LPVOID *apNew;
  597. LARGE_INTEGER fileSize;
  598. /* If the shared-memory file has not been opened, open it now. */
  599. if( pWin32File->hShmFile==NULL ){
  600. char *zShm = win32ShmFile(pWin32File);
  601. if( !zShm ) return LSM_NOMEM_BKPT;
  602. rc = win32Open(pWin32File->pEnv, zShm, 0, &pWin32File->hShmFile);
  603. lsmFree(pWin32File->pEnv, zShm);
  604. if( rc!=LSM_OK ){
  605. return rc;
  606. }
  607. }
  608. /* If the shared-memory file is not large enough to contain the
  609. ** requested chunk, cause it to grow. */
  610. memset(&fileSize, 0, sizeof(LARGE_INTEGER));
  611. if( !GetFileSizeEx(pWin32File->hShmFile, &fileSize) ){
  612. return LSM_IOERR_BKPT;
  613. }
  614. assert( fileSize.QuadPart>=0 );
  615. if( fileSize.QuadPart<nReq ){
  616. rc = win32Truncate(pWin32File->hShmFile, nReq);
  617. if( rc!=LSM_OK ){
  618. return rc;
  619. }
  620. }
  621. ahNew = (LPHANDLE)lsmMallocZero(pWin32File->pEnv, sizeof(HANDLE) * nNew);
  622. if( !ahNew ) return LSM_NOMEM_BKPT;
  623. apNew = (LPVOID *)lsmMallocZero(pWin32File->pEnv, sizeof(LPVOID) * nNew);
  624. if( !apNew ){
  625. lsmFree(pWin32File->pEnv, ahNew);
  626. return LSM_NOMEM_BKPT;
  627. }
  628. memcpy(ahNew, pWin32File->ahShm, sizeof(HANDLE) * pWin32File->nShm);
  629. memcpy(apNew, pWin32File->apShm, sizeof(LPVOID) * pWin32File->nShm);
  630. lsmFree(pWin32File->pEnv, pWin32File->ahShm);
  631. pWin32File->ahShm = ahNew;
  632. lsmFree(pWin32File->pEnv, pWin32File->apShm);
  633. pWin32File->apShm = apNew;
  634. pWin32File->nShm = nNew;
  635. }
  636. if( pWin32File->ahShm[iChunk]==NULL ){
  637. HANDLE hMap;
  638. assert( nReq<=0xFFFFFFFF );
  639. hMap = CreateFileMappingW(pWin32File->hShmFile, NULL, PAGE_READWRITE, 0,
  640. (DWORD)nReq, NULL);
  641. if( hMap==NULL ){
  642. return LSM_IOERR_BKPT;
  643. }
  644. pWin32File->ahShm[iChunk] = hMap;
  645. }
  646. if( pWin32File->apShm[iChunk]==NULL ){
  647. LPVOID pMap;
  648. pMap = MapViewOfFile(pWin32File->ahShm[iChunk],
  649. FILE_MAP_WRITE | FILE_MAP_READ, 0,
  650. iOffset - iOffsetShift, sz + iOffsetShift);
  651. if( pMap==NULL ){
  652. return LSM_IOERR_BKPT;
  653. }
  654. pWin32File->apShm[iChunk] = pMap;
  655. }
  656. if( iOffsetShift!=0 ){
  657. char *p = (char *)pWin32File->apShm[iChunk];
  658. *ppShm = (void *)&p[iOffsetShift];
  659. }else{
  660. *ppShm = pWin32File->apShm[iChunk];
  661. }
  662. return LSM_OK;
  663. }
  664. static void lsmWin32OsShmBarrier(void){
  665. MemoryBarrier();
  666. }
  667. static int lsmWin32OsShmUnmap(lsm_file *pFile, int bDelete){
  668. Win32File *pWin32File = (Win32File *)pFile;
  669. if( pWin32File->hShmFile!=NULL ){
  670. int i;
  671. for(i=0; i<pWin32File->nShm; i++){
  672. if( pWin32File->apShm[i]!=NULL ){
  673. UnmapViewOfFile(pWin32File->apShm[i]);
  674. pWin32File->apShm[i] = NULL;
  675. }
  676. if( pWin32File->ahShm[i]!=NULL ){
  677. CloseHandle(pWin32File->ahShm[i]);
  678. pWin32File->ahShm[i] = NULL;
  679. }
  680. }
  681. CloseHandle(pWin32File->hShmFile);
  682. pWin32File->hShmFile = NULL;
  683. if( bDelete ){
  684. char *zShm = win32ShmFile(pWin32File);
  685. if( zShm ){ win32Delete(pWin32File->pEnv, zShm); }
  686. lsmFree(pWin32File->pEnv, zShm);
  687. }
  688. }
  689. return LSM_OK;
  690. }
  691. #define MX_CLOSE_ATTEMPT 3
  692. static int lsmWin32OsClose(lsm_file *pFile){
  693. int rc;
  694. int nRetry = 0;
  695. Win32File *pWin32File = (Win32File *)pFile;
  696. lsmWin32OsShmUnmap(pFile, 0);
  697. win32Unmap(pWin32File);
  698. do{
  699. if( pWin32File->hFile==NULL ){
  700. rc = LSM_IOERR_BKPT;
  701. break;
  702. }
  703. rc = CloseHandle(pWin32File->hFile);
  704. if( rc ){
  705. pWin32File->hFile = NULL;
  706. rc = LSM_OK;
  707. break;
  708. }
  709. if( ++nRetry>=MX_CLOSE_ATTEMPT ){
  710. rc = LSM_IOERR_BKPT;
  711. break;
  712. }
  713. }while( 1 );
  714. lsmFree(pWin32File->pEnv, pWin32File->ahShm);
  715. lsmFree(pWin32File->pEnv, pWin32File->apShm);
  716. lsmFree(pWin32File->pEnv, pWin32File);
  717. return rc;
  718. }
  719. static int lsmWin32OsSleep(lsm_env *pEnv, int us){
  720. unused_parameter(pEnv);
  721. return win32Sleep(us);
  722. }
  723. /****************************************************************************
  724. ** Memory allocation routines.
  725. */
  726. static void *lsmWin32OsMalloc(lsm_env *pEnv, size_t N){
  727. assert( HeapValidate(GetProcessHeap(), 0, NULL) );
  728. return HeapAlloc(GetProcessHeap(), 0, (SIZE_T)N);
  729. }
  730. static void lsmWin32OsFree(lsm_env *pEnv, void *p){
  731. assert( HeapValidate(GetProcessHeap(), 0, NULL) );
  732. if( p ){
  733. HeapFree(GetProcessHeap(), 0, p);
  734. }
  735. }
  736. static void *lsmWin32OsRealloc(lsm_env *pEnv, void *p, size_t N){
  737. unsigned char *m = (unsigned char *)p;
  738. assert( HeapValidate(GetProcessHeap(), 0, NULL) );
  739. if( 1>N ){
  740. lsmWin32OsFree(pEnv, p);
  741. return NULL;
  742. }else if( NULL==p ){
  743. return lsmWin32OsMalloc(pEnv, N);
  744. }else{
  745. #if 0 /* arguable: don't shrink */
  746. SIZE_T sz = HeapSize(GetProcessHeap(), 0, m);
  747. if( sz>=(SIZE_T)N ){
  748. return p;
  749. }
  750. #endif
  751. return HeapReAlloc(GetProcessHeap(), 0, m, N);
  752. }
  753. }
  754. static size_t lsmWin32OsMSize(lsm_env *pEnv, void *p){
  755. assert( HeapValidate(GetProcessHeap(), 0, NULL) );
  756. return (size_t)HeapSize(GetProcessHeap(), 0, p);
  757. }
  758. #ifdef LSM_MUTEX_WIN32
  759. /*************************************************************************
  760. ** Mutex methods for Win32 based systems. If LSM_MUTEX_WIN32 is
  761. ** missing then a no-op implementation of mutexes found below will be
  762. ** used instead.
  763. */
  764. #include "windows.h"
  765. typedef struct Win32Mutex Win32Mutex;
  766. struct Win32Mutex {
  767. lsm_env *pEnv;
  768. CRITICAL_SECTION mutex;
  769. #ifdef LSM_DEBUG
  770. DWORD owner;
  771. #endif
  772. };
  773. #ifndef WIN32_MUTEX_INITIALIZER
  774. # define WIN32_MUTEX_INITIALIZER { 0 }
  775. #endif
  776. #ifdef LSM_DEBUG
  777. # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER, 0 }
  778. #else
  779. # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER }
  780. #endif
  781. static int lsmWin32OsMutexStatic(
  782. lsm_env *pEnv,
  783. int iMutex,
  784. lsm_mutex **ppStatic
  785. ){
  786. static volatile LONG initialized = 0;
  787. static Win32Mutex sMutex[2] = {
  788. LSM_WIN32_STATIC_MUTEX,
  789. LSM_WIN32_STATIC_MUTEX
  790. };
  791. assert( iMutex==LSM_MUTEX_GLOBAL || iMutex==LSM_MUTEX_HEAP );
  792. assert( LSM_MUTEX_GLOBAL==1 && LSM_MUTEX_HEAP==2 );
  793. if( InterlockedCompareExchange(&initialized, 1, 0)==0 ){
  794. int i;
  795. for(i=0; i<array_size(sMutex); i++){
  796. InitializeCriticalSection(&sMutex[i].mutex);
  797. }
  798. }
  799. *ppStatic = (lsm_mutex *)&sMutex[iMutex-1];
  800. return LSM_OK;
  801. }
  802. static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
  803. Win32Mutex *pMutex; /* Pointer to new mutex */
  804. pMutex = (Win32Mutex *)lsmMallocZero(pEnv, sizeof(Win32Mutex));
  805. if( !pMutex ) return LSM_NOMEM_BKPT;
  806. pMutex->pEnv = pEnv;
  807. InitializeCriticalSection(&pMutex->mutex);
  808. *ppNew = (lsm_mutex *)pMutex;
  809. return LSM_OK;
  810. }
  811. static void lsmWin32OsMutexDel(lsm_mutex *p){
  812. Win32Mutex *pMutex = (Win32Mutex *)p;
  813. DeleteCriticalSection(&pMutex->mutex);
  814. lsmFree(pMutex->pEnv, pMutex);
  815. }
  816. static void lsmWin32OsMutexEnter(lsm_mutex *p){
  817. Win32Mutex *pMutex = (Win32Mutex *)p;
  818. EnterCriticalSection(&pMutex->mutex);
  819. #ifdef LSM_DEBUG
  820. assert( pMutex->owner!=GetCurrentThreadId() );
  821. pMutex->owner = GetCurrentThreadId();
  822. assert( pMutex->owner==GetCurrentThreadId() );
  823. #endif
  824. }
  825. static int lsmWin32OsMutexTry(lsm_mutex *p){
  826. BOOL bRet;
  827. Win32Mutex *pMutex = (Win32Mutex *)p;
  828. bRet = TryEnterCriticalSection(&pMutex->mutex);
  829. #ifdef LSM_DEBUG
  830. if( bRet ){
  831. assert( pMutex->owner!=GetCurrentThreadId() );
  832. pMutex->owner = GetCurrentThreadId();
  833. assert( pMutex->owner==GetCurrentThreadId() );
  834. }
  835. #endif
  836. return !bRet;
  837. }
  838. static void lsmWin32OsMutexLeave(lsm_mutex *p){
  839. Win32Mutex *pMutex = (Win32Mutex *)p;
  840. #ifdef LSM_DEBUG
  841. assert( pMutex->owner==GetCurrentThreadId() );
  842. pMutex->owner = 0;
  843. assert( pMutex->owner!=GetCurrentThreadId() );
  844. #endif
  845. LeaveCriticalSection(&pMutex->mutex);
  846. }
  847. #ifdef LSM_DEBUG
  848. static int lsmWin32OsMutexHeld(lsm_mutex *p){
  849. Win32Mutex *pMutex = (Win32Mutex *)p;
  850. return pMutex ? pMutex->owner==GetCurrentThreadId() : 1;
  851. }
  852. static int lsmWin32OsMutexNotHeld(lsm_mutex *p){
  853. Win32Mutex *pMutex = (Win32Mutex *)p;
  854. return pMutex ? pMutex->owner!=GetCurrentThreadId() : 1;
  855. }
  856. #endif
  857. /*
  858. ** End of Win32 mutex implementation.
  859. *************************************************************************/
  860. #else
  861. /*************************************************************************
  862. ** Noop mutex implementation
  863. */
  864. typedef struct NoopMutex NoopMutex;
  865. struct NoopMutex {
  866. lsm_env *pEnv; /* Environment handle (for xFree()) */
  867. int bHeld; /* True if mutex is held */
  868. int bStatic; /* True for a static mutex */
  869. };
  870. static NoopMutex aStaticNoopMutex[2] = {
  871. {0, 0, 1},
  872. {0, 0, 1},
  873. };
  874. static int lsmWin32OsMutexStatic(
  875. lsm_env *pEnv,
  876. int iMutex,
  877. lsm_mutex **ppStatic
  878. ){
  879. assert( iMutex>=1 && iMutex<=(int)array_size(aStaticNoopMutex) );
  880. *ppStatic = (lsm_mutex *)&aStaticNoopMutex[iMutex-1];
  881. return LSM_OK;
  882. }
  883. static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
  884. NoopMutex *p;
  885. p = (NoopMutex *)lsmMallocZero(pEnv, sizeof(NoopMutex));
  886. if( p ) p->pEnv = pEnv;
  887. *ppNew = (lsm_mutex *)p;
  888. return (p ? LSM_OK : LSM_NOMEM_BKPT);
  889. }
  890. static void lsmWin32OsMutexDel(lsm_mutex *pMutex) {
  891. NoopMutex *p = (NoopMutex *)pMutex;
  892. assert( p->bStatic==0 && p->pEnv );
  893. lsmFree(p->pEnv, p);
  894. }
  895. static void lsmWin32OsMutexEnter(lsm_mutex *pMutex){
  896. NoopMutex *p = (NoopMutex *)pMutex;
  897. assert( p->bHeld==0 );
  898. p->bHeld = 1;
  899. }
  900. static int lsmWin32OsMutexTry(lsm_mutex *pMutex){
  901. NoopMutex *p = (NoopMutex *)pMutex;
  902. assert( p->bHeld==0 );
  903. p->bHeld = 1;
  904. return 0;
  905. }
  906. static void lsmWin32OsMutexLeave(lsm_mutex *pMutex){
  907. NoopMutex *p = (NoopMutex *)pMutex;
  908. assert( p->bHeld==1 );
  909. p->bHeld = 0;
  910. }
  911. #ifdef LSM_DEBUG
  912. static int lsmWin32OsMutexHeld(lsm_mutex *pMutex){
  913. NoopMutex *p = (NoopMutex *)pMutex;
  914. return p ? p->bHeld : 1;
  915. }
  916. static int lsmWin32OsMutexNotHeld(lsm_mutex *pMutex){
  917. NoopMutex *p = (NoopMutex *)pMutex;
  918. return p ? !p->bHeld : 1;
  919. }
  920. #endif
  921. /***************************************************************************/
  922. #endif /* else LSM_MUTEX_NONE */
  923. /* Without LSM_DEBUG, the MutexHeld tests are never called */
  924. #ifndef LSM_DEBUG
  925. # define lsmWin32OsMutexHeld 0
  926. # define lsmWin32OsMutexNotHeld 0
  927. #endif
  928. lsm_env *lsm_default_env(void){
  929. static lsm_env win32_env = {
  930. sizeof(lsm_env), /* nByte */
  931. 1, /* iVersion */
  932. /***** file i/o ******************/
  933. 0, /* pVfsCtx */
  934. lsmWin32OsFullpath, /* xFullpath */
  935. lsmWin32OsOpen, /* xOpen */
  936. lsmWin32OsRead, /* xRead */
  937. lsmWin32OsWrite, /* xWrite */
  938. lsmWin32OsTruncate, /* xTruncate */
  939. lsmWin32OsSync, /* xSync */
  940. lsmWin32OsSectorSize, /* xSectorSize */
  941. lsmWin32OsRemap, /* xRemap */
  942. lsmWin32OsFileid, /* xFileid */
  943. lsmWin32OsClose, /* xClose */
  944. lsmWin32OsUnlink, /* xUnlink */
  945. lsmWin32OsLock, /* xLock */
  946. lsmWin32OsTestLock, /* xTestLock */
  947. lsmWin32OsShmMap, /* xShmMap */
  948. lsmWin32OsShmBarrier, /* xShmBarrier */
  949. lsmWin32OsShmUnmap, /* xShmUnmap */
  950. /***** memory allocation *********/
  951. 0, /* pMemCtx */
  952. lsmWin32OsMalloc, /* xMalloc */
  953. lsmWin32OsRealloc, /* xRealloc */
  954. lsmWin32OsFree, /* xFree */
  955. lsmWin32OsMSize, /* xSize */
  956. /***** mutexes *********************/
  957. 0, /* pMutexCtx */
  958. lsmWin32OsMutexStatic, /* xMutexStatic */
  959. lsmWin32OsMutexNew, /* xMutexNew */
  960. lsmWin32OsMutexDel, /* xMutexDel */
  961. lsmWin32OsMutexEnter, /* xMutexEnter */
  962. lsmWin32OsMutexTry, /* xMutexTry */
  963. lsmWin32OsMutexLeave, /* xMutexLeave */
  964. lsmWin32OsMutexHeld, /* xMutexHeld */
  965. lsmWin32OsMutexNotHeld, /* xMutexNotHeld */
  966. /***** other *********************/
  967. lsmWin32OsSleep, /* xSleep */
  968. };
  969. return &win32_env;
  970. }
  971. #endif