|
|
1.1 root 1: /* filewrap.c */
2:
3: /* File-related system-call wrappers */
4:
5: /* $Id: filewrap.c,v 1.33 2006/05/18 04:09:35 deuce Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /* OS-specific */
39: #if defined(__unix__)
40:
41: #include <stdarg.h> /* va_list */
42: #include <string.h> /* strlen() */
43: #include <unistd.h> /* getpid() */
44: #include <fcntl.h> /* fcntl() file/record locking */
45: #include <sys/file.h> /* L_SET for Solaris */
46: #include <errno.h>
47: #include <sys/param.h> /* BSD */
48:
49: #endif
50:
51: /* ANSI */
52: #include <sys/types.h> /* _dev_t */
53: #include <sys/stat.h> /* struct stat */
54:
55: #include "filewrap.h" /* Verify prototypes */
56:
57: /****************************************************************************/
58: /* Returns the modification time of the file in 'fd' */
59: /****************************************************************************/
60: time_t DLLCALL filetime(int fd)
61: {
62: struct stat st;
63:
64: if(fstat(fd, &st)!=0)
65: return(-1);
66:
67: return(st.st_mtime);
68: }
69:
70: #if defined(__unix__) && !defined(__BORLANDC__)
71:
72: /****************************************************************************/
73: /* Returns the length of the file in 'fd' */
74: /****************************************************************************/
75: long DLLCALL filelength(int fd)
76: {
77: struct stat st;
78:
79: if(fstat(fd, &st)!=0)
80: return(-1L);
81:
82: return(st.st_size);
83: }
84:
85: /* Sets a lock on a portion of a file */
86: int DLLCALL lock(int fd, long pos, long len)
87: {
88: #if defined(F_SANERDLCKNO) || !defined(BSD)
89: struct flock alock;
90:
91: #ifndef F_SANEWRLCKNO
92: int flags;
93: if((flags=fcntl(fd,F_GETFL))==-1)
94: return -1;
95: if(flags==O_RDONLY)
96: alock.l_type = F_RDLCK; /* set read lock to prevent writes */
97: else
98: alock.l_type = F_WRLCK; /* set write lock to prevent all access */
99: #else
100: alock.l_type = F_SANEWRLCKNO;
101: #endif
102: alock.l_whence = L_SET; /* SEEK_SET */
103: alock.l_start = pos;
104: alock.l_len = (int)len;
105:
106: if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL)
107: return(-1);
108: #endif
109:
110: #if !defined(F_SANEWRLCKNO) && !defined(__QNX__) && !defined(__solaris__)
111: /* use flock (doesn't work over NFS) */
112: if(flock(fd,LOCK_EX|LOCK_NB)!=0 && errno != EOPNOTSUPP)
113: return(-1);
114: #endif
115:
116: return(0);
117: }
118:
119: /* Removes a lock from a file record */
120: int DLLCALL unlock(int fd, long pos, long len)
121: {
122:
123: #if defined(F_SANEUNLCK) || !defined(BSD)
124: struct flock alock;
125: #ifdef F_SANEUNLCK
126: alock.l_type = F_SANEUNLCK; /* remove the lock */
127: #else
128: alock.l_type = F_UNLCK; /* remove the lock */
129: #endif
130: alock.l_whence = L_SET;
131: alock.l_start = pos;
132: alock.l_len = (int)len;
133: if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL)
134: return(-1);
135: #endif
136:
137: #if !defined(F_SANEUNLCK) && !defined(__QNX__) && !defined(__solaris__)
138: /* use flock (doesn't work over NFS) */
139: if(flock(fd,LOCK_UN|LOCK_NB)!=0 && errno != EOPNOTSUPP)
140: return(-1);
141: #endif
142:
143: return(0);
144: }
145:
146: /* Opens a file in specified sharing (file-locking) mode */
147: /*
148: * This is how it *SHOULD* work:
149: * Values of DOS 2-6.22 file sharing behavior:
150: * | Second and subsequent Opens
151: * First |Compat Deny Deny Deny Deny
152: * Open | All Write Read None
153: * |R W RW R W RW R W RW R W RW R W RW
154: * - - - - -| - - - - - - - - - - - - - - - - -
155: * Compat R |Y Y Y N N N 1 N N N N N 1 N N
156: * W |Y Y Y N N N N N N N N N N N N
157: * RW|Y Y Y N N N N N N N N N N N N
158: * - - - - -|
159: * Deny R |C C C N N N N N N N N N N N N
160: * All W |C C C N N N N N N N N N N N N
161: * RW|C C C N N N N N N N N N N N N
162: * - - - - -|
163: * Deny R |2 C C N N N Y N N N N N Y N N
164: * Write W |C C C N N N N N N Y N N Y N N
165: * RW|C C C N N N N N N N N N Y N N
166: * - - - - -|
167: * Deny R |C C C N N N N Y N N N N N Y N
168: * Read W |C C C N N N N N N N Y N N Y N
169: * RW|C C C N N N N N N N N N N Y N
170: * - - - - -|
171: * Deny R |2 C C N N N Y Y Y N N N Y Y Y
172: * None W |C C C N N N N N N Y Y Y Y Y Y
173: * RW|C C C N N N N N N N N N Y Y Y
174: *
175: * Legend:
176: * Y = open succeeds,
177: * N = open fails with error code 05h.
178: * C = open fails, INT 24 generated.
179: * 1 = open succeeds if file read-only, else fails with error code.
180: * 2 = open succeeds if file read-only, else fails with INT 24
181: */
182: #if !defined(__QNX__)
183: int DLLCALL sopen(const char *fn, int sh_access, int share, ...)
184: {
185: int fd;
186: int pmode=S_IREAD;
187: #ifndef F_SANEWRLCKNO
188: int flock_op=LOCK_NB; /* non-blocking */
189: #endif
190: #if defined(F_SANEWRLCKNO) || !defined(BSD)
191: struct flock alock;
192: #endif
193: va_list ap;
194:
195: if(sh_access&O_CREAT) {
196: va_start(ap,share);
197: pmode = va_arg(ap,unsigned int);
198: va_end(ap);
199: }
200:
201: if ((fd = open(fn, sh_access, pmode)) < 0)
202: return -1;
203:
204: if (share == SH_DENYNO || share == SH_COMPAT) /* no lock needed */
205: return fd;
206: #if defined(F_SANEWRLCKNO) || !defined(BSD)
207: /* use fcntl (doesn't work correctly with threads) */
208: alock.l_type = share;
209: alock.l_whence = L_SET;
210: alock.l_start = 0;
211: alock.l_len = 0; /* lock to EOF */
212:
213: if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL) { /* EINVAL means the file does not support locking */
214: close(fd);
215: return -1;
216: }
217: #endif
218:
219: #if !defined(F_SANEWRLCKNO) && !defined(__QNX__) && !defined(__solaris__)
220: /* use flock (doesn't work over NFS) */
221: if(share==SH_DENYRW)
222: flock_op|=LOCK_EX;
223: else /* SH_DENYWR */
224: flock_op|=LOCK_SH;
225: if(flock(fd,flock_op)!=0 && errno != EOPNOTSUPP) { /* That object doesn't do locks */
226: if(errno==EWOULDBLOCK)
227: errno=EAGAIN;
228: close(fd);
229: return(-1);
230: }
231: #endif
232:
233: return fd;
234: }
235: #endif /* !QNX */
236:
237: #elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__DMC__)
238:
239: #include <io.h> /* tell */
240: #include <stdio.h> /* SEEK_SET */
241: #include <sys/locking.h> /* _locking */
242:
243: /* Fix MinGW locking.h typo */
244: #if defined LK_UNLOCK && !defined LK_UNLCK
245: #define LK_UNLCK LK_UNLOCK
246: #endif
247:
248: int DLLCALL lock(int file, long offset, long size)
249: {
250: int i;
251: long pos;
252:
253: pos=tell(file);
254: if(offset!=pos)
255: lseek(file, offset, SEEK_SET);
256: i=_locking(file,LK_NBLCK,size);
257: if(offset!=pos)
258: lseek(file, pos, SEEK_SET);
259: return(i);
260: }
261:
262: int DLLCALL unlock(int file, long offset, long size)
263: {
264: int i;
265: long pos;
266:
267: pos=tell(file);
268: if(offset!=pos)
269: lseek(file, offset, SEEK_SET);
270: i=_locking(file,LK_UNLCK,size);
271: if(offset!=pos)
272: lseek(file, pos, SEEK_SET);
273: return(i);
274: }
275:
276: #endif /* !Unix && (MSVC || MinGW) */
277:
278: #ifdef __unix__
279: FILE *_fsopen(char *pszFilename, char *pszMode, int shmode)
280: {
281: int file;
282: int Mode=0;
283: char *p;
284:
285: for(p=pszMode;*p;p++) {
286: switch (*p) {
287: case 'r':
288: Mode |= 1;
289: break;
290: case 'w':
291: Mode |= 2;
292: break;
293: case 'a':
294: Mode |= 4;
295: break;
296: case '+':
297: Mode |= 8;
298: break;
299: case 'b':
300: case 't':
301: break;
302: default:
303: errno=EINVAL;
304: return(NULL);
305: }
306: }
307: switch(Mode) {
308: case 1:
309: Mode=O_RDONLY;
310: break;
311: case 2:
312: Mode=O_WRONLY|O_CREAT|O_TRUNC;
313: break;
314: case 4:
315: Mode=O_APPEND|O_WRONLY|O_CREAT;
316: break;
317: case 9:
318: Mode=O_RDWR|O_CREAT;
319: break;
320: case 10:
321: Mode=O_RDWR|O_CREAT|O_TRUNC;
322: break;
323: case 12:
324: Mode=O_RDWR|O_APPEND|O_CREAT;
325: break;
326: default:
327: errno=EINVAL;
328: return(NULL);
329: }
330: if(Mode&O_CREAT)
331: file=sopen(pszFilename,Mode,shmode,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
332: else
333: file=sopen(pszFilename,Mode,shmode);
334: if(file==-1)
335: return(NULL);
336: return(fdopen(file,pszMode));
337: }
338: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.