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