filewrap.c 7.31 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* filewrap.c */

/* File-related system-call wrappers */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
12
 *																			*
13
14
 * This library is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU Lesser General Public License		*
15
16
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
17
18
 * See the GNU Lesser General Public License for more details: lgpl.txt or	*
 * http://www.fsf.org/copyleft/lesser.html									*
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

/* OS-specific */
#if defined(__unix__)

41
#include <stdarg.h>		/* va_list */
42
43
44
#include <string.h>     /* strlen() */
#include <unistd.h>     /* getpid() */
#include <fcntl.h>      /* fcntl() file/record locking */
45
#include <sys/file.h>	/* L_SET for Solaris */
rswindell's avatar
rswindell committed
46
#include <errno.h>
47
#include <sys/param.h>	/* BSD */
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

#endif

/* ANSI */
#include <sys/types.h>	/* _dev_t */
#include <sys/stat.h>	/* struct stat */

#include "filewrap.h"	/* Verify prototypes */

/****************************************************************************/
/* Returns the modification time of the file in 'fd'						*/
/****************************************************************************/
time_t DLLCALL filetime(int fd)
{
	struct stat st;

	if(fstat(fd, &st)!=0)
		return(-1);

	return(st.st_mtime);
}

70
#if defined(__unix__) && !defined(__BORLANDC__)
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

/****************************************************************************/
/* Returns the length of the file in 'fd'									*/
/****************************************************************************/
long DLLCALL filelength(int fd)
{
	struct stat st;

	if(fstat(fd, &st)!=0)
		return(-1L);

	return(st.st_size);
}

/* Sets a lock on a portion of a file */
86
int DLLCALL lock(int fd, long pos, long len)
87
{
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	#if defined(F_SANERDLCKNO) || !defined(BSD)
 		struct flock alock;

	#ifndef F_SANEWRLCKNO
		int	flags;
		if((flags=fcntl(fd,F_GETFL))==-1)
			return -1;

		if(flags==O_RDONLY)
			alock.l_type = F_RDLCK; /* set read lock to prevent writes */
		else
			alock.l_type = F_WRLCK; /* set write lock to prevent all access */
	#else
		alock.l_type = F_SANEWRLCKNO;
	#endif
		alock.l_whence = L_SET;		/* SEEK_SET */
		alock.l_start = pos;
		alock.l_len = (int)len;

107
		if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL)
108
109
110
			return(-1);
	#endif

111
	#if !defined(F_SANEWRLCKNO) && !defined(__QNX__)
112
		/* use flock (doesn't work over NFS) */
113
		if(flock(fd,LOCK_EX|LOCK_NB)!=0 && errno != EOPNOTSUPP)
114
115
116
117
			return(-1);
	#endif

		return(0);
118
119
120
}

/* Removes a lock from a file record */
121
int DLLCALL unlock(int fd, long pos, long len)
122
123
{

124
125
126
127
128
#if defined(F_SANEUNLCK) || !defined(BSD)
	struct flock alock;
#ifdef F_SANEUNLCK
	alock.l_type = F_SANEUNLCK;   /* remove the lock */
#else
129
	alock.l_type = F_UNLCK;   /* remove the lock */
130
#endif
131
132
	alock.l_whence = L_SET;
	alock.l_start = pos;
deuce's avatar
deuce committed
133
	alock.l_len = (int)len;
134
	if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL)
135
		return(-1);
136
#endif
137

138
#if !defined(F_SANEUNLCK) && !defined(__QNX__)
139
	/* use flock (doesn't work over NFS) */
140
	if(flock(fd,LOCK_UN|LOCK_NB)!=0 && errno != EOPNOTSUPP)
141
		return(-1);
142
#endif
143

144
	return(0);
145
146
147
}

/* Opens a file in specified sharing (file-locking) mode */
148
149
#if !defined(__QNX__)
int DLLCALL sopen(const char *fn, int access, int share, ...)
150
151
{
	int fd;
152
	int pmode=S_IREAD;
153
#ifndef F_SANEWRLCKNO
154
	int	flock_op=LOCK_NB;	/* non-blocking */
155
#endif
156
#if defined(F_SANEWRLCKNO) || !defined(BSD)
157
	struct flock alock;
deuce's avatar
deuce committed
158
#endif
159
160
161
162
    va_list ap;

    if(access&O_CREAT) {
        va_start(ap,share);
rswindell's avatar
rswindell committed
163
        pmode = va_arg(ap,unsigned int);
164
165
        va_end(ap);
    }
166

167
	if ((fd = open(fn, access, pmode)) < 0)
168
169
		return -1;

170
	if (share == SH_DENYNO) /* no lock needed */
171
		return fd;
172
173
174
175
176
177
178
#if defined(F_SANEWRLCKNO) || !defined(BSD)
	/* use fcntl (doesn't work correctly with threads) */
	alock.l_type = share;
	alock.l_whence = L_SET;
	alock.l_start = 0;
	alock.l_len = 0;       /* lock to EOF */

179
	if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL) {	/* EINVAL means the file does not support locking */
180
181
182
183
184
185
		close(fd);
		return -1;
	}
#endif

#ifndef F_SANEWRLCKNO
186
	/* use flock (doesn't work over NFS) */
187
188
189
190
	if(share==SH_DENYRW)
		flock_op|=LOCK_EX;
	else   /* SH_DENYWR */
		flock_op|=LOCK_SH;
191
	if(flock(fd,flock_op)!=0 && errno != EOPNOTSUPP) { /* That object doesn't do locks */
192
193
		if(errno==EWOULDBLOCK) 
			errno=EAGAIN;
194
195
196
		close(fd);
		return(-1);
	}
197
#endif
198
199
200

	return fd;
}
201
#endif /* !QNX */
202

rswindell's avatar
rswindell committed
203
#elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__DMC__)
204
205
206
207
208
209
210
211
212
213

#include <io.h>				/* tell */
#include <stdio.h>			/* SEEK_SET */
#include <sys/locking.h>	/* _locking */

/* Fix MinGW locking.h typo */
#if defined LK_UNLOCK && !defined LK_UNLCK
	#define LK_UNLCK LK_UNLOCK
#endif

214
int DLLCALL lock(int file, long offset, long size) 
215
216
217
218
219
220
221
222
223
224
225
226
227
{
	int	i;
	long	pos;
   
	pos=tell(file);
	if(offset!=pos)
		lseek(file, offset, SEEK_SET);
	i=_locking(file,LK_NBLCK,size);
	if(offset!=pos)
		lseek(file, pos, SEEK_SET);
	return(i);
}

228
int DLLCALL unlock(int file, long offset, long size)
229
230
231
232
233
234
235
236
237
238
239
240
241
242
{
	int	i;
	long	pos;
   
	pos=tell(file);
	if(offset!=pos)
		lseek(file, offset, SEEK_SET);
	i=_locking(file,LK_UNLCK,size);
	if(offset!=pos)
		lseek(file, pos, SEEK_SET);
	return(i);
}

#endif	/* !Unix && (MSVC || MinGW) */
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

#ifdef __unix__
FILE *_fsopen(char *pszFilename, char *pszMode, int shmode)
{
	int file;
	int Mode=0;
	char *p;
	
	for(p=pszMode;*p;p++)  {
		switch (*p)  {
			case 'r':
				Mode |= 1;
				break;
			case 'w':
				Mode |= 2;
				break;
			case 'a':
				Mode |= 4;
				break;
			case '+':
				Mode |= 8;
				break;
			case 'b':
			case 't':
				break;
			default:
				errno=EINVAL;
			return(NULL);
		}
	}
	switch(Mode)  {
		case 1:
			Mode=O_RDONLY;
			break;
		case 2:
			Mode=O_WRONLY|O_CREAT;
			break;
		case 4:
			Mode=O_APPEND|O_WRONLY|O_CREAT;
			break;
		case 9:
			Mode=O_RDWR;
			break;
		case 10:
			Mode=O_RDWR|O_CREAT;
			break;
		case 12:
			Mode=O_RDWR|O_APPEND|O_CREAT;
			break;
		default:
			errno=EINVAL;
			return(NULL);
	}
	if(Mode&O_CREAT)
		file=sopen(pszFilename,Mode,shmode,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
	else
		file=sopen(pszFilename,Mode,shmode);
	if(file==-1)
		return(NULL);
	return(fdopen(file,pszMode));
}
#endif