File: xcreat.c

package info (click to toggle)
cucipop 1.31-5
  • links: PTS
  • area: non-free
  • in suites: slink
  • size: 236 kB
  • ctags: 379
  • sloc: ansic: 2,260; sh: 148; makefile: 92
file content (130 lines) | stat: -rw-r--r-- 4,280 bytes parent folder | download | duplicates (3)
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
/************************************************************************
 *	secure exclusive creat/lock	v1.6 1995/05/05			*
 *	(works even across NFS, which O_EXCL does *not*)		*
 *									*
 *	Created 1990-1997, S.R. van den Berg, The Netherlands		*
 *			srb@cuci.nl					*
 *									*
 *	This file is donated to the public domain.			*
 *	Customised for cucipop.						*
 *									*
 *	Usage: int xcreat(const char*filename,mode_t mode)		*
 *									*
 *	returns	 0:success  -1:lock busy				*
 *		-2:parameter error or out of memory			*
 *									*
 *		sets errno on failure					*
 *									*
 *	To remove a `lockfile', simply unlink it.			*
 *									*
 ************************************************************************/
#define HOSTNAMElen	9	      /* significant characters for hostname */
/*#define NOuname		      /* uncomment if uname is not available */
/*#define NOstrpbrk		    /* uncomment if strpbrk is not available */
/*#define strchr(s,c) index(s,c)     /* uncomment if strchr is not available */
#define const			      /* can be undefined for ANSI compilers */

#include <unistd.h>			/* open() close() link() unlink()
					   getpid() */
#include <fcntl.h>			/* O_WRONLY O_CREAT O_EXCL */
#include <stdlib.h>			/* malloc() free() */
#include <string.h>			/* strncpy() strcat() strpbrk() */
#include <sys/stat.h>			/* stat() struct stat */
#ifndef NOuname
#include <sys/utsname.h>		/* uname() struct utsname */
#endif
#include <errno.h>

/************************************************************************
 * Only edit below this line if you *think* you know what you are doing *
 ************************************************************************/

#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 log(string)			      /* should log string to stderr */
#define UNIQ_PREFIX	'_'
#define charsSERIAL	4
#define UNIQnamelen	(1+charsSERIAL+HOSTNAMElen+1)
#define bitsSERIAL	(6*charsSERIAL)
#define maskSERIAL	((1L<<bitsSERIAL)-1)
#define rotbSERIAL	2
#define irotbSERIAL	(1L<<bitsSERIAL-rotbSERIAL)
#define mrotbSERIAL	((maskSERIAL&irotbSERIAL-1)+irotbSERIAL)

extern errno;

#ifdef NOstrpbrk
char*strpbrk(st,del)const char*const st,*del;
{ const char*f=0,*t;
  for(f=0;*del;)
     if((t=strchr(st,*del++))&&(!f||t<f))
	f=t;
  return(char*)f;
}
#endif

static const char*hostname()
{ static char name[HOSTNAMElen+1];
#ifdef	NOuname
  gethostname(name,HOSTNAMElen+1);
#else
  struct utsname names;
  uname(&names);strncpy(name,names.nodename,HOSTNAMElen);
#endif
  name[HOSTNAMElen]='\0';return name;
}
						      /* convert to a number */
static void ultoan(val,dest)unsigned long val;char*dest;
{ register i;				     /* within the set [0-9A-Za-z-_] */
  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';
}

static int unique(full,p,mode)const char*const full;char*const p;
 const mode_t mode;
{ unsigned long retry=mrotbSERIAL;int i;	  /* create unique file name */
  do
   { ultoan(maskSERIAL&(retry-=irotbSERIAL)+(long)getpid(),p+1);*p=UNIQ_PREFIX;
     strcat(p,hostname());
   }
  while(0>(i=copen(full,O_WRONLY|O_CREAT|O_EXCL|O_SYNC,mode))&&errno==EEXIST&&
   retry);	    /* casually check if it already exists (highly unlikely) */
  write(i,"0",1);					/* put in a fake pid */
  if(i<0)
   { log("Error while writing to \"");log(full);log("\"\n");
     return 0;
   }
  close(i);return 1;
}
				     /* rename MUST fail if already existent */
static int myrename(old,newn)const char*const old,*const newn;
{ int i,serrno;struct stat stbuf;
  if(!link(old,newn))
   { unlink(old);
     return 0;
   }
  serrno=errno;i=stat(old,&stbuf);unlink(old);errno=serrno;
  return stbuf.st_nlink==2?i:-1;
}
					/* an NFS secure exclusive file open */
int xcreat(name,mode)char*name;const mode_t mode;
{ char*p,*q;int j= -2,i;
  for(q=name;p=strchr(q,'/');q=p+1);			 /* find last DIRSEP */
  if(!(p=malloc((i=q-name)+UNIQnamelen)))		    /* out of memory */
     return j;
  strncpy(p,name,i);
  if(unique(p,p+i,mode))
     j=myrename(p,name);	 /* try and rename it, fails if nonexclusive */
  free(p);return j;
}