|
|
1.1 root 1: /* filewrap.c */
2:
3: /* File-related system-call wrappers */
4:
1.1.1.2 ! root 5: /* $Id: filewrap.c,v 1.37 2010/03/09 03:23:34 rswindell Exp $ */
1.1 root 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: * *
1.1.1.2 ! root 11: * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 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' */
1.1.1.2 ! root 59: /* or -1 if file doesn't exist. */
1.1 root 60: /****************************************************************************/
61: time_t DLLCALL filetime(int fd)
62: {
63: struct stat st;
64:
65: if(fstat(fd, &st)!=0)
66: return(-1);
67:
68: return(st.st_mtime);
69: }
70:
71: #if defined(__unix__) && !defined(__BORLANDC__)
72:
73: /****************************************************************************/
74: /* Returns the length of the file in 'fd' */
1.1.1.2 ! root 75: /* or -1 if file doesn't exist. */
1.1 root 76: /****************************************************************************/
1.1.1.2 ! root 77: off_t DLLCALL filelength(int fd)
1.1 root 78: {
79: struct stat st;
80:
81: if(fstat(fd, &st)!=0)
82: return(-1L);
83:
84: return(st.st_size);
85: }
86:
87: /* Sets a lock on a portion of a file */
1.1.1.2 ! root 88: int DLLCALL lock(int fd, off_t pos, off_t len)
1.1 root 89: {
90: #if defined(F_SANERDLCKNO) || !defined(BSD)
91: struct flock alock;
92:
93: #ifndef F_SANEWRLCKNO
94: int flags;
95: if((flags=fcntl(fd,F_GETFL))==-1)
96: return -1;
1.1.1.2 ! root 97: if((flags & (O_RDONLY|O_RDWR|O_WRONLY))==O_RDONLY)
1.1 root 98: alock.l_type = F_RDLCK; /* set read lock to prevent writes */
99: else
100: alock.l_type = F_WRLCK; /* set write lock to prevent all access */
101: #else
102: alock.l_type = F_SANEWRLCKNO;
103: #endif
104: alock.l_whence = L_SET; /* SEEK_SET */
105: alock.l_start = pos;
106: alock.l_len = (int)len;
107:
108: if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL)
109: return(-1);
110: #endif
111:
112: #if !defined(F_SANEWRLCKNO) && !defined(__QNX__) && !defined(__solaris__)
113: /* use flock (doesn't work over NFS) */
114: if(flock(fd,LOCK_EX|LOCK_NB)!=0 && errno != EOPNOTSUPP)
115: return(-1);
116: #endif
117:
118: return(0);
119: }
120:
121: /* Removes a lock from a file record */
1.1.1.2 ! root 122: int DLLCALL unlock(int fd, off_t pos, off_t len)
1.1 root 123: {
124:
125: #if defined(F_SANEUNLCK) || !defined(BSD)
126: struct flock alock;
127: #ifdef F_SANEUNLCK
128: alock.l_type = F_SANEUNLCK; /* remove the lock */
129: #else
130: alock.l_type = F_UNLCK; /* remove the lock */
131: #endif
132: alock.l_whence = L_SET;
133: alock.l_start = pos;
134: alock.l_len = (int)len;
135: if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL)
136: return(-1);
137: #endif
138:
139: #if !defined(F_SANEUNLCK) && !defined(__QNX__) && !defined(__solaris__)
140: /* use flock (doesn't work over NFS) */
141: if(flock(fd,LOCK_UN|LOCK_NB)!=0 && errno != EOPNOTSUPP)
142: return(-1);
143: #endif
144:
145: return(0);
146: }
147:
148: /* Opens a file in specified sharing (file-locking) mode */
149: /*
150: * This is how it *SHOULD* work:
151: * Values of DOS 2-6.22 file sharing behavior:
152: * | Second and subsequent Opens
153: * First |Compat Deny Deny Deny Deny
154: * Open | All Write Read None
155: * |R W RW R W RW R W RW R W RW R W RW
156: * - - - - -| - - - - - - - - - - - - - - - - -
157: * Compat R |Y Y Y N N N 1 N N N N N 1 N N
158: * W |Y Y Y N N N N N N N N N N N N
159: * RW|Y Y Y N N N N N N N N N N N N
160: * - - - - -|
161: * Deny R |C C C N N N N N N N N N N N N
162: * All W |C C C N N N N N N N N N N N N
163: * RW|C C C N N N N N N N N N N N N
164: * - - - - -|
165: * Deny R |2 C C N N N Y N N N N N Y N N
166: * Write W |C C C N N N N N N Y N N Y N N
167: * RW|C C C N N N N N N N N N Y N N
168: * - - - - -|
169: * Deny R |C C C N N N N Y N N N N N Y N
170: * Read W |C C C N N N N N N N Y N N Y N
171: * RW|C C C N N N N N N N N N N Y N
172: * - - - - -|
173: * Deny R |2 C C N N N Y Y Y N N N Y Y Y
174: * None W |C C C N N N N N N Y Y Y Y Y Y
175: * RW|C C C N N N N N N N N N Y Y Y
176: *
177: * Legend:
178: * Y = open succeeds,
179: * N = open fails with error code 05h.
180: * C = open fails, INT 24 generated.
181: * 1 = open succeeds if file read-only, else fails with error code.
182: * 2 = open succeeds if file read-only, else fails with INT 24
183: */
184: #if !defined(__QNX__)
185: int DLLCALL sopen(const char *fn, int sh_access, int share, ...)
186: {
187: int fd;
188: int pmode=S_IREAD;
189: #ifndef F_SANEWRLCKNO
190: int flock_op=LOCK_NB; /* non-blocking */
191: #endif
192: #if defined(F_SANEWRLCKNO) || !defined(BSD)
193: struct flock alock;
194: #endif
195: va_list ap;
196:
197: if(sh_access&O_CREAT) {
198: va_start(ap,share);
199: pmode = va_arg(ap,unsigned int);
200: va_end(ap);
201: }
202:
203: if ((fd = open(fn, sh_access, pmode)) < 0)
204: return -1;
205:
206: if (share == SH_DENYNO || share == SH_COMPAT) /* no lock needed */
207: return fd;
208: #if defined(F_SANEWRLCKNO) || !defined(BSD)
209: /* use fcntl (doesn't work correctly with threads) */
210: alock.l_type = share;
211: alock.l_whence = L_SET;
212: alock.l_start = 0;
213: alock.l_len = 0; /* lock to EOF */
214:
215: if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL) { /* EINVAL means the file does not support locking */
216: close(fd);
217: return -1;
218: }
219: #endif
220:
221: #if !defined(F_SANEWRLCKNO) && !defined(__QNX__) && !defined(__solaris__)
222: /* use flock (doesn't work over NFS) */
223: if(share==SH_DENYRW)
224: flock_op|=LOCK_EX;
225: else /* SH_DENYWR */
226: flock_op|=LOCK_SH;
227: if(flock(fd,flock_op)!=0 && errno != EOPNOTSUPP) { /* That object doesn't do locks */
228: if(errno==EWOULDBLOCK)
229: errno=EAGAIN;
230: close(fd);
231: return(-1);
232: }
233: #endif
234:
235: return fd;
236: }
237: #endif /* !QNX */
238:
239: #elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__DMC__)
240:
241: #include <io.h> /* tell */
242: #include <stdio.h> /* SEEK_SET */
243: #include <sys/locking.h> /* _locking */
244:
245: /* Fix MinGW locking.h typo */
246: #if defined LK_UNLOCK && !defined LK_UNLCK
247: #define LK_UNLCK LK_UNLOCK
248: #endif
249:
1.1.1.2 ! root 250: int DLLCALL lock(int file, off_t offset, off_t size)
1.1 root 251: {
252: int i;
1.1.1.2 ! root 253: off_t pos;
1.1 root 254:
255: pos=tell(file);
256: if(offset!=pos)
257: lseek(file, offset, SEEK_SET);
1.1.1.2 ! root 258: i=_locking(file,LK_NBLCK,(long)size);
1.1 root 259: if(offset!=pos)
260: lseek(file, pos, SEEK_SET);
261: return(i);
262: }
263:
1.1.1.2 ! root 264: int DLLCALL unlock(int file, off_t offset, off_t size)
1.1 root 265: {
266: int i;
1.1.1.2 ! root 267: off_t pos;
1.1 root 268:
269: pos=tell(file);
270: if(offset!=pos)
271: lseek(file, offset, SEEK_SET);
1.1.1.2 ! root 272: i=_locking(file,LK_UNLCK,(long)size);
1.1 root 273: if(offset!=pos)
274: lseek(file, pos, SEEK_SET);
275: return(i);
276: }
277:
278: #endif /* !Unix && (MSVC || MinGW) */
279:
280: #ifdef __unix__
281: FILE *_fsopen(char *pszFilename, char *pszMode, int shmode)
282: {
283: int file;
284: int Mode=0;
285: char *p;
286:
287: for(p=pszMode;*p;p++) {
288: switch (*p) {
289: case 'r':
290: Mode |= 1;
291: break;
292: case 'w':
293: Mode |= 2;
294: break;
295: case 'a':
296: Mode |= 4;
297: break;
298: case '+':
299: Mode |= 8;
300: break;
301: case 'b':
302: case 't':
303: break;
304: default:
305: errno=EINVAL;
306: return(NULL);
307: }
308: }
309: switch(Mode) {
310: case 1:
1.1.1.2 ! root 311: Mode =O_RDONLY;
1.1 root 312: break;
313: case 2:
314: Mode=O_WRONLY|O_CREAT|O_TRUNC;
315: break;
316: case 4:
317: Mode=O_APPEND|O_WRONLY|O_CREAT;
318: break;
319: case 9:
320: Mode=O_RDWR|O_CREAT;
321: break;
322: case 10:
323: Mode=O_RDWR|O_CREAT|O_TRUNC;
324: break;
325: case 12:
326: Mode=O_RDWR|O_APPEND|O_CREAT;
327: break;
328: default:
329: errno=EINVAL;
330: return(NULL);
331: }
332: if(Mode&O_CREAT)
333: file=sopen(pszFilename,Mode,shmode,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
334: else
335: file=sopen(pszFilename,Mode,shmode);
336: if(file==-1)
337: return(NULL);
338: return(fdopen(file,pszMode));
339: }
340: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.