home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2610 / lock-file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-25  |  11.4 KB  |  597 lines

  1. /* @(#)lock-file.c    1.2 91/01/24 */
  2. /* copyright 1991, Mike Howard & Miller/Howard Investments, Inc.
  3.    all rights reserved */
  4.  
  5. /*
  6.   these are convenience routines which implement file locking in standard
  7.   ways regardless of the method selected within the particular operating
  8.   system.
  9.  
  10.   Note: for record locks, the current file position is changed to the
  11.   beginning of the locked region.  for whole file locks, the current file
  12.   position is not changed.
  13.  
  14.   Note: these routines do not work on buffered files.
  15.  
  16.   In all cases, the three parameters are:
  17.   fd - int - file descriptor
  18.   offset - off_t - offset from the beginning of file to begin locking
  19.                    region.
  20.   len - off_t - length of locked region.
  21.  
  22.   offset == 0, len == 0 locks entire file.
  23.  
  24.   The functions do what they appear to do:
  25.     int lock_record_shared_wait(fd, offset, len)
  26.     int lock_record_exclusive_wait(fd, offset, len)
  27.     int lock_record_shared_nowait(fd, offset, len)
  28.     int lock_record_exclusive_nowait(fd, offset, len)
  29.     int unlock_record(fd, offset, len)
  30.     int lock_file_shared_wait(fd)
  31.     int lock_file_exclusive_wait(fd)
  32.     int lock_file_shared_nowait(fd)
  33.     int lock_file_exclusive_nowait(fd)
  34.     int unlock_file(fd)
  35.  
  36.   All functions return 0 if successful, -1 if the requested lock would
  37.   block, and-2 on failure.  They set  the extern int lock_errno as follows:
  38.   return  lock_errno   explanation
  39.      0    LCK_OK       requested lock implemented
  40.  
  41.     -1    LCK_BLOCK    the requested lock was blocked
  42.  
  43.     -2    LCK_BADFD    fd is not a valid file descriptor
  44.     -2    LCK_DEADLOCK a deadlock was detected
  45.     -2    LCK_INTR     an interrupt occurred which aborted the system call
  46.     -2    LCK_OTHER    some other error - errno may give more information
  47.                        if you know how to interpret it
  48.  
  49.   The extent of support depends on the system call used to implement
  50.   the actual locks.  The int lock_support contains the appropriate bitwise
  51.   OR of the following defines:
  52.     LCK_RECORD      1
  53.     LCK_SHARED      2
  54.     LCK_EXCLUSIVE   4
  55.     LCK_NO_BLOCK    8
  56.  
  57.   The character pointer locking_style contains a user readable message
  58.   specifying the underlying locking mechanism.
  59.  
  60.   Not all functions are available under all UNIX file locking schemes.
  61.   For example, flock style locking only locks entire files.  lockf style
  62.   locking does not support shared locks.  If a requested feature is not
  63.   supported, the least restrictive feature which does gives at least the
  64.   requested protection is used.
  65.  
  66. */
  67. /*
  68. a convenient template
  69. int lock_record_shared_wait(fd, offset, len)
  70. int fd;
  71. off_t offset;
  72. off_t len;
  73. {
  74. }
  75.  
  76. int lock_record_exclusive_wait(fd, offset, len)
  77. int fd;
  78. off_t offset;
  79. off_t len;
  80. {
  81. }
  82.  
  83. int lock_record_shared_nowait(fd, offset, len)
  84. int fd;
  85. off_t offset;
  86. off_t len;
  87. {
  88. }
  89.  
  90. int lock_record_exclusive_nowait(fd, offset, len)
  91. int fd;
  92. off_t offset;
  93. off_t len;
  94. {
  95. }
  96.  
  97. int unlock_record(fd, offset, len)
  98. int fd;
  99. off_t offset;
  100. off_t len;
  101. {
  102. }
  103.  
  104. int lock_file_shared_wait(fd)
  105. int fd;
  106. {
  107. }
  108.  
  109. int lock_file_exclusive_wait(fd)
  110. int fd;
  111. {
  112. }
  113.  
  114. int lock_file_shared_nowait(fd)
  115. int fd;
  116. {
  117. }
  118.  
  119. int lock_file_exclusive_nowait(fd)
  120. int fd;
  121. {
  122. }
  123.  
  124. int unlock_file(fd)
  125. int fd;
  126. {
  127. }
  128. */
  129.  
  130.  
  131. #include <sys/types.h>
  132. #include <errno.h>
  133. extern int errno;
  134. int lock_errno;
  135. #include "lock-file.h"
  136. #include "patchlevel.h"
  137.  
  138. static patchlevel = PATCHLEVEL;
  139.  
  140. /* #define FCNTL_STYLE /* */
  141. /* #define FLOCK_STYLE /* */
  142. /* #define LOCKF_STYLE /* */
  143.  
  144. /* default style is FCNTL_STYLE */
  145. #ifndef FCNTL_STYLE
  146. #ifndef FLOCK_STYLE
  147. #ifndef LOCKF_STYLE
  148. # define FCNTL_STYLE
  149. #endif
  150. #endif
  151. #endif
  152.  
  153. #ifdef FCNTL_STYLE
  154. #include <fcntl.h>
  155.  
  156. int lock_support = LCK_RECORD | LCK_SHARED | LCK_EXCLUSIVE | LCK_NO_BLOCK;
  157. static struct flock flock;
  158. static int do_fcntl_lock();
  159.  
  160. char *locking_style = "fcntl style file locking";
  161.  
  162. int lock_record_shared_wait(fd, offset, len)
  163. int fd;
  164. off_t offset;
  165. off_t len;
  166. {
  167.   if (len < 0) {
  168.     offset += len;
  169.     len = -len;
  170.   }
  171.   if (lseek(fd, offset, 0) < 0) {
  172.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  173.     return -2;
  174.   }
  175.   return do_fcntl_lock(fd, offset, len, F_RDLCK, F_SETLKW);
  176. }
  177.  
  178. int lock_record_exclusive_wait(fd, offset, len)
  179. int fd;
  180. off_t offset;
  181. off_t len;
  182. {
  183.   if (len < 0) {
  184.     offset += len;
  185.     len = -len;
  186.   }
  187.   if (lseek(fd, offset, 0) < 0) {
  188.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  189.     return -2;
  190.   }
  191.   return do_fcntl_lock(fd, offset, len, F_WRLCK, F_SETLKW);
  192. }
  193.  
  194. int lock_record_shared_nowait(fd, offset, len)
  195. int fd;
  196. off_t offset;
  197. off_t len;
  198. {
  199.   if (len < 0) {
  200.     offset += len;
  201.     len = -len;
  202.   }
  203.   if (lseek(fd, offset, 0) < 0) {
  204.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  205.     return -2;
  206.   }
  207.   return do_fcntl_lock(fd, offset, len, F_RDLCK, F_SETLK);
  208. }
  209.  
  210. int lock_record_exclusive_nowait(fd, offset, len)
  211. int fd;
  212. off_t offset;
  213. off_t len;
  214. {
  215.   if (len < 0) {
  216.     offset += len;
  217.     len = -len;
  218.   }
  219.   if (lseek(fd, offset, 0) < 0) {
  220.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  221.     return -2;
  222.   }
  223.   return do_fcntl_lock(fd, offset, len, F_WRLCK, F_SETLK);
  224. }
  225.  
  226. int unlock_record(fd, offset, len)
  227. int fd;
  228. off_t offset;
  229. off_t len;
  230. {
  231.   if (len < 0) {
  232.     offset += len;
  233.     len = -len;
  234.   }
  235.   if (lseek(fd, offset, 0) < 0) {
  236.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  237.     return -2;
  238.   }
  239.   return do_fcntl_lock(fd, offset, len, F_UNLCK, F_SETLK);
  240. }
  241.  
  242. int lock_file_shared_wait(fd)
  243. int fd;
  244. {
  245.   return do_fcntl_lock(fd, 0L, 0L, F_RDLCK, F_SETLKW);
  246. }
  247.  
  248. int lock_file_exclusive_wait(fd)
  249. int fd;
  250. {
  251.   return do_fcntl_lock(fd, 0L, 0L, F_WRLCK, F_SETLKW);
  252. }
  253.  
  254. int lock_file_shared_nowait(fd)
  255. int fd;
  256. {
  257.   return do_fcntl_lock(fd, 0L, 0L, F_RDLCK, F_SETLK);
  258. }
  259.  
  260. int lock_file_exclusive_nowait(fd)
  261. int fd;
  262. {
  263.   return do_fcntl_lock(fd, 0L, 0L, F_WRLCK, F_SETLK);
  264. }
  265.  
  266. int unlock_file(fd)
  267. int fd;
  268. {
  269.   return do_fcntl_lock(fd, 0L, 0L, F_UNLCK, F_SETLK);
  270. }
  271.  
  272. static int do_fcntl_lock(fd, offset, len, lock_cmd, set_cmd)
  273. int fd;
  274. off_t offset;
  275. off_t len;
  276. int lock_cmd;
  277. int set_cmd;
  278. {
  279.   flock.l_type = lock_cmd;
  280.   flock.l_whence = 0;
  281.   flock.l_start = offset;
  282.   flock.l_len = len;
  283.   if (fcntl(fd, set_cmd, &flock)) {
  284.     switch (errno) {
  285.     case EACCES:
  286.     case EAGAIN:
  287.       lock_errno = LCK_BLOCK;
  288.       return -1;
  289.     case EBADF:
  290.       lock_errno = LCK_BADFD;
  291.       return -2;
  292.     case EDEADLK:
  293.       lock_errno = LCK_DEADLOCK;
  294.       return -2;
  295.     case EINTR:
  296.       lock_errno = LCK_INTR;
  297.       return -2;
  298.     default:
  299.       lock_errno = LCK_OTHER;
  300.       return -2;
  301.     }
  302.   }
  303.  
  304.   lock_errno = LCK_OK;
  305.   return 0;
  306. }
  307. #endif
  308.  
  309. #ifdef FLOCK_STYLE
  310. /* WARNING: this does not correctly handle the case where more than
  311.    one lock is applied to a file (or segments of a file) by a single
  312.    process and then released `a little at a time'.  The fix is straight
  313.    forward: build a list of lock count records indexed by fd's and
  314.    decrement when an unlock is requested.  But this doesn't work either
  315.    in the case that a file is dup'ed or reopenned.  So I have not bothered
  316.    to 'do it right', inasmuch as 'right' isn't.
  317. */
  318.  
  319. #include <sys/file.h>
  320.  
  321. char *locking_style = "flock style file locking";
  322. int lock_support = LCK_SHARED | LCK_EXCLUSIVE | LCK_NO_BLOCK;
  323. static int do_flock();
  324.  
  325. int lock_record_shared_wait(fd, offset, len)
  326. int fd;
  327. off_t offset;
  328. off_t len;
  329. {
  330.   if (len < 0) {
  331.     offset += len;
  332.     len = -len;
  333.   }
  334.  
  335.   if (lseek(fd, offset, 0) < 0) {
  336.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  337.     return -2;
  338.   }
  339.   return do_flock(fd, LOCK_SH);
  340. }
  341.  
  342. int lock_record_exclusive_wait(fd, offset, len)
  343. int fd;
  344. off_t offset;
  345. off_t len;
  346. {
  347.   if (len < 0) {
  348.     offset += len;
  349.     len = -len;
  350.   }
  351.  
  352.   if (lseek(fd, offset, 0) < 0) {
  353.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  354.     return -2;
  355.   }
  356.   return do_flock(fd, LOCK_EX);
  357. }
  358.  
  359. int lock_record_shared_nowait(fd, offset, len)
  360. int fd;
  361. off_t offset;
  362. off_t len;
  363. {
  364.   if (len < 0) {
  365.     offset += len;
  366.     len = -len;
  367.   }
  368.  
  369.   if (lseek(fd, offset, 0) < 0) {
  370.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  371.     return -2;
  372.   }
  373.   return do_flock(fd, LOCK_SH | LOCK_NB);
  374. }
  375.  
  376. int lock_record_exclusive_nowait(fd, offset, len)
  377. int fd;
  378. off_t offset;
  379. off_t len;
  380. {
  381.   if (len < 0) {
  382.     offset += len;
  383.     len = -len;
  384.   }
  385.  
  386.   if (lseek(fd, offset, 0) < 0) {
  387.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  388.     return -2;
  389.   }
  390.   return do_flock(fd, LOCK_EX | LOCK_NB);
  391. }
  392.  
  393. int unlock_record(fd, offset, len)
  394. int fd;
  395. off_t offset;
  396. off_t len;
  397. {
  398.   return do_flock(fd, LOCK_UN);
  399. }
  400.  
  401. int lock_file_shared_wait(fd)
  402. int fd;
  403. {
  404.   return do_flock(fd, LOCK_SH);
  405. }
  406.  
  407. int lock_file_exclusive_wait(fd)
  408. int fd;
  409. {
  410.   return do_flock(fd, LOCK_EX);
  411. }
  412.  
  413. int lock_file_shared_nowait(fd)
  414. int fd;
  415. {
  416.   return do_flock(fd, LOCK_SH | LOCK_NB);
  417. }
  418.  
  419. int lock_file_exclusive_nowait(fd)
  420. int fd;
  421. {
  422.   return do_flock(fd, LOCK_EX | LOCK_NB);
  423. }
  424.  
  425. int unlock_file(fd)
  426. int fd;
  427. {
  428.   return do_flock(fd, LOCK_UN);
  429. }
  430.  
  431. static int do_flock(fd, operation)
  432. int fd;
  433. int operation;
  434. {
  435.   if (flock(fd, operation)) {
  436.     switch (errno) {
  437.     case EWOULDBLOCK:
  438.       lock_errno = LCK_BLOCK;
  439.       return -1;
  440.     case EBADF:
  441.       lock_errno = LCK_BADFD;
  442.       return -2;
  443.     case EDEADLK:
  444.       lock_errno = LCK_DEADLOCK;
  445.       return -2;
  446.     case EINTR:
  447.       lock_errno = LCK_INTR;
  448.       return -2;
  449.     default:
  450.       lock_errno = LCK_OTHER;
  451.       return -2;
  452.     }
  453.   }
  454.  
  455.   lock_errno = LCK_OK;
  456.   return 0;
  457. }
  458. #endif
  459.  
  460. #ifdef LOCKF_STYLE
  461. #include <unistd.h>
  462. #ifndef lseek
  463. long lseek();
  464. #endif
  465.  
  466. char *locking_style = "lockf style file locking";
  467. int lock_support = LCK_RECORD | LCK_EXCLUSIVE | LCK_NO_BLOCK;
  468. static int do_lockf();
  469.  
  470. int lock_record_shared_wait(fd, offset, len)
  471. int fd;
  472. off_t offset;
  473. off_t len;
  474. {
  475.   return do_lockf(fd, F_LOCK, offset, len, 0);
  476. }
  477.  
  478. int lock_record_exclusive_wait(fd, offset, len)
  479. int fd;
  480. off_t offset;
  481. off_t len;
  482. {
  483.   return do_lockf(fd, F_LOCK, offset, len, 0);
  484. }
  485.  
  486. int lock_record_shared_nowait(fd, offset, len)
  487. int fd;
  488. off_t offset;
  489. off_t len;
  490. {
  491.   return do_lockf(fd, F_TLOCK, offset, len, 0);
  492. }
  493.  
  494. int lock_record_exclusive_nowait(fd, offset, len)
  495. int fd;
  496. off_t offset;
  497. off_t len;
  498. {
  499.   return do_lockf(fd, F_TLOCK, offset, len, 0);
  500. }
  501.  
  502. int unlock_record(fd, offset, len)
  503. int fd;
  504. off_t offset;
  505. off_t len;
  506. {
  507.   return do_lockf(fd, F_ULOCK, offset, len, 0);
  508. }
  509.  
  510. int lock_file_shared_wait(fd)
  511. int fd;
  512. {
  513.   return do_lockf(fd, F_LOCK, 0L, 0L, 1);
  514. }
  515.  
  516. int lock_file_exclusive_wait(fd)
  517. int fd;
  518. {
  519.   return do_lockf(fd, F_LOCK, 0L, 0L, 1);
  520. }
  521.  
  522. int lock_file_shared_nowait(fd)
  523. int fd;
  524. {
  525.   return do_lockf(fd, F_TLOCK, 0L, 0L, 1);
  526. }
  527.  
  528. int lock_file_exclusive_nowait(fd)
  529. int fd;
  530. {
  531.   return do_lockf(fd, F_TLOCK, 0L, 0L, 1);
  532. }
  533.  
  534. int unlock_file(fd)
  535. int fd;
  536. {
  537.   return do_lockf(fd, F_ULOCK, 0L, 0L, 1);
  538. }
  539.  
  540. static int do_lockf(fd, command, offset, len, original_offset_flag)
  541. int fd;
  542. int command;
  543. off_t offset;
  544. off_t len;
  545. int original_offset_flag;
  546. {
  547.   int ret;
  548.   off_t original_offset;
  549.   long lseek();
  550.  
  551.   if (original_offset_flag) {
  552.     if ((original_offset = (off_t)lseek(fd, 0L, 1)) < 0)
  553.       original_offset_flag = 0;
  554.   }
  555.   if (len < 0) {
  556.     offset += len;
  557.     len = -len;
  558.   }
  559.   if (lseek(fd, offset, 0) < 0) {
  560.     lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
  561.     return -2;
  562.   }
  563.   if (lockf(fd, command, len)) {
  564.     switch (errno) {
  565.     case EACCES:
  566.       lock_errno = LCK_BLOCK;
  567.       ret = -1;
  568.       break;
  569.     case EBADF:
  570.       lock_errno = LCK_BADFD;
  571.       ret = -2;
  572.       break;
  573.     case EDEADLK:
  574.       lock_errno = LCK_DEADLOCK;
  575.       ret = -2;
  576.       break;
  577.     case EINTR:
  578.       lock_errno = LCK_INTR;
  579.       ret = -2;
  580.       break;
  581.     default:
  582.       lock_errno = LCK_OTHER;
  583.       ret = -2;
  584.       break;
  585.     }
  586.   }
  587.   else {
  588.     lock_errno = LCK_OK;
  589.     ret = 0;
  590.   }
  591.   if (original_offset_flag)
  592.     lseek(fd, original_offset, 0);
  593.  
  594.   return ret;
  595. }
  596. #endif
  597.