File: xcreat.c

package info (click to toggle)
mush 7.2.5unoff2-25
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 1,784 kB
  • ctags: 1,342
  • sloc: ansic: 21,890; sh: 972; makefile: 90; csh: 87
file content (181 lines) | stat: -rw-r--r-- 4,389 bytes parent folder | download | duplicates (6)
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 */