mbase.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*
  2. JAMLIB - A JAM subroutine library
  3. Copyright (C) 1999 Bj�rn Stenberg
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. Changes made by Johan Billing 2000-04-16:
  16. - Added support for Win32 and Linux
  17. - Changed JAM_OpenMB to open files in binary mode
  18. - Changed source to use feof() instead of errno == EPASTEOF
  19. - Changed source to use structrw to read and write structures
  20. - Fixed broken JAM_FindUser()
  21. - #includes string.h and stdlib.h instead of memory.h
  22. Backported changes from JAMLIB 1.4.7 made by Johan Billing 2003-10-26
  23. - Now uses calloc instead of malloc/memset
  24. - (*NewArea_PPS) will be set to zero even if calloc() failed in
  25. JAM_OpenMB() and JAM_CreateMB()
  26. - JAM_CreateMB() no longer attempts to forever to lock the newly created
  27. messagebase. If the first attempt fails, it will return an error.
  28. - jam_Lock() now sets Base_PS->Errno under Linux
  29. Other changes made by Johan Billing 2003-10-26
  30. - Fixed comparison between signed and unsigned variable in JAM_GetMBSize()
  31. - JAM_CreateMB() would not unlock and close the newly created messagebase
  32. upon failure.
  33. Changes made by Johan Billing 2004-07-10
  34. - Updated the Win32-specific parts of the code to make it compatible with
  35. newer versions of MinGW (tested with 3.1.0-1):
  36. * Now uses Sleep() instead of sleep()
  37. * Changed _LK_UNLOCK to _LK_UNLCK in jam_Lock()
  38. */
  39. /***********************************************************************
  40. **
  41. ** MBASE.C -- Message base handling
  42. **
  43. ** Author: Bj�rn Stenberg ([email protected])
  44. **
  45. ***********************************************************************/
  46. #include <stdio.h>
  47. #include <errno.h>
  48. #include <time.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include "jam.h"
  52. #include "structrw.h"
  53. #if defined( __OS2__ )
  54. #include <os2.h> /* ANSI C does not include file locking :-( */
  55. #endif
  56. #if defined( __WIN32__ )
  57. #include <sys/locking.h>
  58. #include <io.h>
  59. #include <windows.h>
  60. #if !defined( _LK_UNLCK ) && defined ( _LK_UNLOCK )
  61. #define _LK_UNLCK _LK_UNLOCK /* For backwards compatibility */
  62. #endif
  63. #endif
  64. #if defined( __LINUX__ )
  65. #include <sys/file.h>
  66. #include <unistd.h>
  67. #if defined(__sun) || defined(__MUSL__) || defined(__HAIKU__)
  68. #include <fcntl.h>
  69. #endif
  70. #endif
  71. #define OS_ERROR_OFFSET 10000
  72. #if defined( __OS2__ )
  73. #define JAM_Sleep( _x_ ) DosSleep( _x_*1000 )
  74. #endif
  75. #if defined( __WIN32__ )
  76. #define JAM_Sleep(x) Sleep(x*1000)
  77. #endif
  78. #if defined( __LINUX__ )
  79. #define JAM_Sleep(x) sleep(x)
  80. #endif
  81. /*************************************<**********************************
  82. **
  83. ** File-global functions
  84. **
  85. ***********************************************************************/
  86. int jam_Open( s_JamBase* Base_PS, char* Filename_PC, char* Mode_PC );
  87. int jam_Lock( s_JamBase* Base_PS, int DoLock_I );
  88. /***********************************************************************
  89. **
  90. ** JAM_OpenMB - Open message base
  91. **
  92. ***********************************************************************/
  93. int JAM_OpenMB( char* Basename_PC, s_JamBase** NewArea_PPS )
  94. {
  95. s_JamBase* Base_PS;
  96. int Status_I;
  97. if ( !NewArea_PPS )
  98. return JAM_BAD_PARAM;
  99. *NewArea_PPS = NULL;
  100. Base_PS = (s_JamBase*) calloc( 1, sizeof( s_JamBase ) );
  101. if (!Base_PS)
  102. return JAM_NO_MEMORY;
  103. *NewArea_PPS = Base_PS;
  104. Status_I = jam_Open( Base_PS, Basename_PC, "r+b" );
  105. if ( Status_I ) {
  106. return Status_I;
  107. }
  108. return 0;
  109. }
  110. /***********************************************************************
  111. **
  112. ** JAM_CreateMB - Create a new message base
  113. **
  114. ***********************************************************************/
  115. int JAM_CreateMB( char* Basename_PC,
  116. uint32_t BaseMsg_I,
  117. s_JamBase** NewArea_PPS )
  118. {
  119. s_JamBaseHeader Base_S;
  120. int Status_I;
  121. s_JamBase* Base_PS;
  122. if ( !NewArea_PPS || !BaseMsg_I )
  123. return JAM_BAD_PARAM;
  124. *NewArea_PPS = NULL;
  125. Base_PS = (s_JamBase*) calloc( 1, sizeof( s_JamBase ) );
  126. if (!Base_PS)
  127. return JAM_NO_MEMORY;
  128. *NewArea_PPS = Base_PS;
  129. Status_I = jam_Open( Base_PS, Basename_PC, "w+b" );
  130. if ( Status_I )
  131. return Status_I;
  132. Base_S.DateCreated = time(NULL);
  133. Base_S.ModCounter = 0;
  134. Base_S.ActiveMsgs = 0;
  135. Base_S.PasswordCRC = 0xffffffff;
  136. Base_S.BaseMsgNum = BaseMsg_I;
  137. memset( &Base_S.RSRVD, 0, sizeof( Base_S.RSRVD ) );
  138. Status_I = JAM_LockMB( Base_PS, 0 ); /* If the new base cannot be locked directly, something is seriously wrong */
  139. if ( Status_I ) {
  140. JAM_CloseMB(Base_PS);
  141. return Status_I;
  142. }
  143. Status_I = JAM_WriteMBHeader( Base_PS, &Base_S );
  144. if ( Status_I ) {
  145. JAM_UnlockMB( Base_PS );
  146. JAM_CloseMB(Base_PS);
  147. return Status_I;
  148. }
  149. JAM_UnlockMB( Base_PS );
  150. return 0;
  151. }
  152. /***********************************************************************
  153. **
  154. ** JAM_CloseMB - Close message base
  155. **
  156. ***********************************************************************/
  157. int JAM_CloseMB( s_JamBase* Base_PS )
  158. {
  159. if ( Base_PS->Locked_I ) {
  160. int Status_I = JAM_UnlockMB( Base_PS );
  161. if ( Status_I )
  162. return Status_I;
  163. }
  164. if ( Base_PS->HdrFile_PS ) {
  165. fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
  166. fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
  167. fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL;
  168. fclose( Base_PS->LrdFile_PS ); Base_PS->LrdFile_PS = NULL;
  169. }
  170. Base_PS->Locked_I = 0;
  171. return 0;
  172. }
  173. /***********************************************************************
  174. **
  175. ** JAM_RemoveMB - Remove a message base
  176. **
  177. ***********************************************************************/
  178. int JAM_RemoveMB( s_JamBase* Base_PS, char* Basename_PC )
  179. {
  180. char Filename_AC[250];
  181. int Status_AI[4];
  182. /* .JHR file */
  183. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_HDRFILE );
  184. Status_AI[0] = remove( Filename_AC );
  185. if ( Status_AI[0] )
  186. Base_PS->Errno_I = errno;
  187. /* .JDT file */
  188. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_TXTFILE );
  189. Status_AI[1] = remove( Filename_AC );
  190. if ( Status_AI[1] )
  191. Base_PS->Errno_I = errno;
  192. /* .JDX file */
  193. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_IDXFILE );
  194. Status_AI[2] = remove( Filename_AC );
  195. if ( Status_AI[2] )
  196. Base_PS->Errno_I = errno;
  197. /* .JLR file */
  198. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_LRDFILE );
  199. Status_AI[3] = remove( Filename_AC );
  200. if ( Status_AI[3] )
  201. Base_PS->Errno_I = errno;
  202. if (Status_AI[0] || Status_AI[1] || Status_AI[2] || Status_AI[3])
  203. return JAM_IO_ERROR;
  204. return 0;
  205. }
  206. /***********************************************************************
  207. **
  208. ** JAM_GetMBSize - Get the number of messages in message base
  209. **
  210. ***********************************************************************/
  211. int JAM_GetMBSize( s_JamBase* Base_PS, uint32_t* Messages_PI )
  212. {
  213. long Offset_I;
  214. /* go to end of index file */
  215. if ( fseek( Base_PS->IdxFile_PS, 0, SEEK_END ) ) {
  216. Base_PS->Errno_I = errno;
  217. return JAM_IO_ERROR;
  218. }
  219. Offset_I = ftell( Base_PS->IdxFile_PS );
  220. if ( Offset_I == -1 ) {
  221. Base_PS->Errno_I = errno;
  222. return JAM_IO_ERROR;
  223. }
  224. *Messages_PI = Offset_I / sizeof( s_JamIndex );
  225. return 0;
  226. }
  227. /***********************************************************************
  228. **
  229. ** JAM_LockMB - Lock message base
  230. **
  231. ***********************************************************************/
  232. int JAM_LockMB( s_JamBase* Base_PS, int Timeout_I )
  233. {
  234. if ( Base_PS->Locked_I )
  235. return 0;
  236. switch ( Timeout_I )
  237. {
  238. /* unlimited timeout */
  239. case -1:
  240. while ( jam_Lock( Base_PS, 1 ) == JAM_LOCK_FAILED )
  241. JAM_Sleep( 1 );
  242. return 0;
  243. /* no timeout */
  244. case 0:
  245. return jam_Lock( Base_PS, 1 );
  246. /* X seconds timeout */
  247. default:
  248. {
  249. time_t Time_I = time(NULL) + Timeout_I;
  250. while ( time(NULL) < Time_I )
  251. {
  252. int Result_I;
  253. Result_I = jam_Lock( Base_PS, 1 );
  254. if ( Result_I == JAM_LOCK_FAILED )
  255. JAM_Sleep( 1 );
  256. else
  257. return Result_I;
  258. }
  259. return JAM_LOCK_FAILED;
  260. }
  261. }
  262. }
  263. /***********************************************************************
  264. **
  265. ** JAM_UnlockMB - Flush all writes and unlock message base
  266. **
  267. ***********************************************************************/
  268. int JAM_UnlockMB( s_JamBase* Base_PS )
  269. {
  270. fflush( Base_PS->HdrFile_PS );
  271. fflush( Base_PS->TxtFile_PS );
  272. fflush( Base_PS->IdxFile_PS );
  273. fflush( Base_PS->LrdFile_PS );
  274. return jam_Lock( Base_PS, 0 );
  275. }
  276. /***********************************************************************
  277. **
  278. ** JAM_ReadMBHeader - Read message base header
  279. **
  280. ***********************************************************************/
  281. int JAM_ReadMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS )
  282. {
  283. if ( !Header_PS || !Base_PS )
  284. return JAM_BAD_PARAM;
  285. if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_SET ) ) {
  286. Base_PS->Errno_I = errno;
  287. return JAM_IO_ERROR;
  288. }
  289. if ( 1 > freadjambaseheader(Base_PS->HdrFile_PS,Header_PS) ) {
  290. Base_PS->Errno_I = errno;
  291. return JAM_IO_ERROR;
  292. }
  293. return 0;
  294. }
  295. /***********************************************************************
  296. **
  297. ** JAM_WriteMBHeader - Write message base header
  298. **
  299. ***********************************************************************/
  300. int JAM_WriteMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS )
  301. {
  302. if ( !Header_PS || !Base_PS )
  303. return JAM_BAD_PARAM;
  304. if ( !Base_PS->Locked_I )
  305. return JAM_NOT_LOCKED;
  306. if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_SET ) ) {
  307. Base_PS->Errno_I = errno;
  308. return JAM_IO_ERROR;
  309. }
  310. /* ensure header looks right */
  311. memcpy( Header_PS->Signature, HEADERSIGNATURE, 4 );
  312. Header_PS->ModCounter++;
  313. if ( 1 > fwritejambaseheader(Base_PS->HdrFile_PS,Header_PS) ) {
  314. Base_PS->Errno_I = errno;
  315. return JAM_IO_ERROR;
  316. }
  317. fflush( Base_PS->HdrFile_PS );
  318. return 0;
  319. }
  320. /***********************************************************************
  321. **
  322. ** JAM_FindUser - Scan scan file for messages to a user
  323. **
  324. ***********************************************************************/
  325. int JAM_FindUser( s_JamBase* Base_PS,
  326. uint32_t UserCrc_I,
  327. uint32_t StartMsg_I,
  328. uint32_t* MsgNo_PI )
  329. {
  330. uint32_t MsgNo_I;
  331. /* go to start message */
  332. if ( fseek( Base_PS->IdxFile_PS, StartMsg_I * sizeof( s_JamIndex ),
  333. SEEK_SET ) ) {
  334. Base_PS->Errno_I = errno;
  335. return JAM_IO_ERROR;
  336. }
  337. /* scan file */
  338. for ( MsgNo_I = StartMsg_I; ; MsgNo_I++ ) {
  339. s_JamIndex Index_S;
  340. if ( 1 > freadjamindex(Base_PS->IdxFile_PS,&Index_S) ) {
  341. if ( feof(Base_PS->IdxFile_PS) )
  342. return JAM_NO_USER;
  343. Base_PS->Errno_I = errno;
  344. return JAM_IO_ERROR;
  345. }
  346. if ( Index_S.UserCRC == UserCrc_I )
  347. break;
  348. }
  349. *MsgNo_PI = MsgNo_I;
  350. return 0;
  351. }
  352. /***********************************************************************
  353. **
  354. ** jam_Lock - Lock/unlock a message base
  355. **
  356. ***********************************************************************/
  357. int jam_Lock( s_JamBase* Base_PS, int DoLock_I )
  358. {
  359. #if defined(__OS2__)
  360. FILELOCK Area_S;
  361. APIRET Status_I;
  362. ULONG Timeout_I = 0;
  363. int Handle_I;
  364. Handle_I = fileno( Base_PS->HdrFile_PS );
  365. if ( Handle_I == -1 ) {
  366. Base_PS->Errno_I = errno;
  367. return JAM_IO_ERROR;
  368. }
  369. Area_S.lOffset = 0;
  370. Area_S.lRange = 1;
  371. if ( DoLock_I )
  372. Status_I = DosSetFileLocks( Handle_I, NULL, &Area_S, Timeout_I, 0 );
  373. else
  374. Status_I = DosSetFileLocks( Handle_I, &Area_S, NULL, Timeout_I, 0 );
  375. if ( Status_I ) {
  376. if ( 232 == Status_I )
  377. return JAM_LOCK_FAILED;
  378. Base_PS->Errno_I = Status_I + OS_ERROR_OFFSET;
  379. return JAM_IO_ERROR;
  380. }
  381. if ( DoLock_I )
  382. Base_PS->Locked_I = 1;
  383. else
  384. Base_PS->Locked_I = 0;
  385. return 0;
  386. #elif defined(__WIN32__)
  387. int Handle_I,Status_I;
  388. fseek(Base_PS->HdrFile_PS,0,SEEK_SET); /* Lock from start of file */
  389. Handle_I = fileno( Base_PS->HdrFile_PS );
  390. if ( Handle_I == -1 ) {
  391. Base_PS->Errno_I = errno;
  392. return JAM_IO_ERROR;
  393. }
  394. if ( DoLock_I )
  395. Status_I = _locking(Handle_I,_LK_NBLCK,1);
  396. else
  397. Status_I = _locking(Handle_I,_LK_UNLCK,1);
  398. if ( Status_I )
  399. return JAM_LOCK_FAILED;
  400. if ( DoLock_I )
  401. Base_PS->Locked_I = 1;
  402. else
  403. Base_PS->Locked_I = 0;
  404. return 0;
  405. #elif defined(__LINUX__)
  406. int Handle_I,Status_I;
  407. struct flock fl;
  408. fseek(Base_PS->HdrFile_PS,0,SEEK_SET); /* Lock from start of file */
  409. Handle_I = fileno( Base_PS->HdrFile_PS );
  410. if ( Handle_I == -1 ) {
  411. Base_PS->Errno_I = errno;
  412. return JAM_IO_ERROR;
  413. }
  414. if(DoLock_I) fl.l_type=F_WRLCK;
  415. else fl.l_type=F_UNLCK;
  416. fl.l_whence=SEEK_SET;
  417. fl.l_start=0;
  418. fl.l_len=1;
  419. fl.l_pid=getpid();
  420. Status_I=fcntl(Handle_I,F_SETLK,&fl);
  421. if ( Status_I ) {
  422. Base_PS->Errno_I = errno;
  423. return JAM_LOCK_FAILED;
  424. }
  425. if ( DoLock_I )
  426. Base_PS->Locked_I = 1;
  427. else
  428. Base_PS->Locked_I = 0;
  429. return 0;
  430. #else
  431. #error Unsupported platform
  432. #endif
  433. }
  434. /***********************************************************************
  435. **
  436. ** jam_Open - Open/create message base files
  437. **
  438. ***********************************************************************/
  439. int jam_Open( s_JamBase* Base_PS, char* Basename_PC, char* Mode_PC )
  440. {
  441. char Filename_AC[250];
  442. /* .JHR file */
  443. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_HDRFILE );
  444. Base_PS->HdrFile_PS = fopen( Filename_AC, Mode_PC );
  445. if (!Base_PS->HdrFile_PS) {
  446. Base_PS->Errno_I = errno;
  447. return JAM_IO_ERROR;
  448. }
  449. /* .JDT file */
  450. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_TXTFILE );
  451. Base_PS->TxtFile_PS = fopen( Filename_AC, Mode_PC );
  452. if (!Base_PS->TxtFile_PS) {
  453. Base_PS->Errno_I = errno;
  454. fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
  455. return JAM_IO_ERROR;
  456. }
  457. /* .JDX file */
  458. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_IDXFILE );
  459. Base_PS->IdxFile_PS = fopen( Filename_AC, Mode_PC );
  460. if (!Base_PS->IdxFile_PS) {
  461. Base_PS->Errno_I = errno;
  462. fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
  463. fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
  464. return JAM_IO_ERROR;
  465. }
  466. /* .JLR file */
  467. sprintf( Filename_AC, "%s%s", Basename_PC, EXT_LRDFILE );
  468. Base_PS->LrdFile_PS = fopen( Filename_AC, Mode_PC );
  469. if (!Base_PS->LrdFile_PS) {
  470. if (strcmp(Mode_PC, "r+b") == 0) {
  471. Base_PS->LrdFile_PS = fopen(Filename_AC, "w+b");
  472. if (!Base_PS->LrdFile_PS) {
  473. Base_PS->Errno_I = errno;
  474. fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
  475. fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
  476. fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL;
  477. return JAM_IO_ERROR;
  478. }
  479. } else {
  480. Base_PS->Errno_I = errno;
  481. fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL;
  482. fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL;
  483. fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL;
  484. return JAM_IO_ERROR;
  485. }
  486. }
  487. return 0;
  488. }