home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / xcreat.c < prev    next >
C/C++ Source or Header  |  1992-10-30  |  4KB  |  183 lines

  1. /************************************************************************
  2.  *    secure exclusive creat/lock    v1.4 1992/04/27            *
  3.  *    (works even across NFS, which O_EXCL does *not*)        *
  4.  *                                    *
  5.  *    Created 1990-1992, S.R. van den Berg, The Netherlands        *
  6.  *            berg@pool.informatik.rwth-aachen.de        *
  7.  *            berg@physik.tu-muenchen.de            *
  8.  *                                    *
  9.  *    This file is donated to the public domain.            *
  10.  *                                    *
  11.  *    Cleaned up 1992, Bart Schaefer, Z-Code Software Corp.        *
  12.  *            schaefer@z-code.com                *
  13.  *            schaefer@cse.ogi.edu                *
  14.  *        Cleanup includes reformatting for readability,        *
  15.  *        more comments, and using some file-name macros        *
  16.  *        that Mush defines (removed calls to strpbrk()        *
  17.  *        and avoided malloc()ing when max. size known).        *
  18.  *        Also added XCTEST standalone test program mode.        *
  19.  *                                    *
  20.  *    Usage: int xcreat(char *filename, int mode)            *
  21.  *                                    *
  22.  *    returns  0:success  -1:lock busy                *
  23.  *                                    *
  24.  *        sets errno on failure                    *
  25.  *                                    *
  26.  *    To remove a `lockfile', simply unlink it.            *
  27.  *                                    *
  28.  ************************************************************************/
  29.  
  30. #include "mush.h"    /* For OS-specific include files and macros */
  31.  
  32. #ifdef XCTEST_LOUDLY
  33. #ifndef XCTEST
  34. #define XCTEST
  35. #endif /* XCTEST */
  36. #endif /* XCTEST_LOUDLY */
  37.  
  38. #ifdef XCTEST
  39. #define hostname()    "xctest"
  40. #else
  41. extern char **ourname;
  42. #define hostname()    ourname[0]
  43. #endif /* XCTEST */
  44.  
  45. #ifdef DECLARE_ERRNO
  46. extern int errno;
  47. #endif /* DECLARE_ERRNO */
  48.  
  49. #ifndef O_SYNC
  50. #define O_SYNC        0
  51. #endif
  52. #ifndef    O_CREAT
  53. #define    copen(path,type,mode)    creat(path,mode)
  54. #else
  55. #define copen(path,type,mode)    open(path,type,mode)
  56. #endif
  57.  
  58. #define UNIQ_PREFIX    '_'        /* Any unlikely character works */
  59. #define charsULTOAN    4        /* # of chars output by ultoan() */
  60.  
  61. #ifndef MAXNAMLEN
  62. #if defined(BSD) || defined(IRIX4) || defined(HPUX)
  63. #define MAXNAMLEN    (MAXPATHLEN/2)    /* Any fairly large number works */
  64. #else /* !SYSV */
  65. #define MAXNAMLEN    14        /* 14 is SysVr3 standard */
  66. #endif /* BSD */
  67. #endif /* MAXNAMLEN */
  68.  
  69. #define HOSTNAMElen    (MAXNAMLEN-charsULTOAN-1)
  70.  
  71. /* Define a bit rotation to generate pseudo-unique numbers in "sequence" */
  72. #define bitsSERIAL    (6*charsULTOAN)
  73. #define maskSERIAL    ((1L<<bitsSERIAL)-1)
  74. #define rotbSERIAL    2
  75. #define mrotbSERIAL    ((1L<<rotbSERIAL)-1)
  76.  
  77. #define XCserialize(n,r) \
  78.     ((u_long) maskSERIAL&((u_long)(r)<<bitsSERIAL-mrotbSERIAL)+(u_long)(n))
  79.  
  80. /* Generate an almost-unique 4-character string from an unsigned long */
  81. static 
  82. ultoan(val, dest)
  83. unsigned long val;
  84. char *dest;    /* convert to a number */
  85. {
  86.     register i;    /* within the set [0-9A-Za-z-_] */
  87.  
  88. #ifdef XCTEST_LOUDLY
  89.     printf("Converting %lu to ascii.\n", val);
  90. #endif /* XCTEST_LOUDLY */
  91.  
  92.     do {
  93.     i = val & 0x3f;
  94.     *dest++ = i+(i < 10? '0' :
  95.             i < 10+26? 'A'-10 :
  96.             i < 10+26+26? 'a'-10-26 :
  97.             i == 10+26+26 ? '-'-10-26-26 :
  98.             '_'-10-26-27);
  99.     }
  100.     while (val >>= 6);
  101.     *dest = '\0';
  102. }
  103.  
  104. /* create unique file name */
  105. static
  106. unique(full, p, mode)
  107. char *full;
  108. char *p;
  109. int mode;
  110. {
  111.     unsigned long retry = 3;
  112.     int i;
  113.  
  114.     do {
  115. #ifdef XCTEST_LOUDLY
  116.     printf("Using PID = %d:  ", getpid());
  117. #endif /* XCTEST_LOUDLY */
  118.     ultoan(XCserialize(getpid(),retry), p + 1);
  119.     *p = UNIQ_PREFIX;
  120.     strncat(p, hostname(), HOSTNAMElen);
  121.     } /* casually check if it already exists (highly unlikely) */
  122.     while (0 > (i = copen(full, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, mode)) &&
  123.         errno == EEXIST && retry--);
  124.     if (i < 0)
  125.     return 0;
  126.     close(i);
  127.     return 1;
  128. }
  129.  
  130. /* rename MUST fail if already existent */
  131. static 
  132. myrename(old, newn)
  133. char *old, *newn;
  134. {
  135.     int i, serrno;
  136.     struct stat stbuf;
  137.  
  138. #ifdef XCTEST_LOUDLY
  139.     printf("Renaming %s to %s\n", old, newn);
  140. #endif /* XCTEST_LOUDLY */
  141.  
  142.     link(old, newn);
  143.     serrno = errno;
  144.     i = stat(old, &stbuf);
  145.     unlink(old);
  146.     errno = serrno;
  147.     return stbuf.st_nlink == 2 ? i : -1;
  148. }
  149.  
  150. /* an NFS secure exclusive file open */
  151. xcreat(name, mode)
  152. char *name;
  153. int mode;
  154. {
  155.     char buf[MAXPATHLEN];
  156.     char *p, *q;
  157.     int j = -2, i;
  158.  
  159.     q = rindex(name, '/');
  160.     if (q)
  161.     i = q - name;
  162.     else {
  163.     i = 0;    /* Creating in the current directory */
  164.     }
  165.     p = strncpy(buf, name, i);
  166.     if (unique(p, p + i, mode))
  167.     j = myrename(p, name);    /* try and rename it, fails if nonexclusive */
  168.     free(p);
  169.     return j;
  170. }
  171.  
  172. #ifdef XCTEST
  173.  
  174. main(argc, argv)
  175. int argc;
  176. char **argv;
  177. {
  178.     if (argc > 1)
  179.     exit(xcreat(argv[1], 0444) < 0);
  180. }
  181.  
  182. #endif /* XCTEXT */
  183.