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 >
Wrap
C/C++ Source or Header
|
1992-10-30
|
4KB
|
183 lines
/************************************************************************
* 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;
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 */
free(p);
return j;
}
#ifdef XCTEST
main(argc, argv)
int argc;
char **argv;
{
if (argc > 1)
exit(xcreat(argv[1], 0444) < 0);
}
#endif /* XCTEXT */