[project @ 2004-08-16 11:07:31 by simonmar]
[haskell-directory.git] / cbits / lockFile.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-2004
3  *
4  * $Id: lockFile.c,v 1.3 2004/06/02 12:35:11 simonmar Exp $
5  *
6  * stdin/stout/stderr Runtime Support
7  */
8
9 #include "HsBase.h"
10 #include "Rts.h"
11 #include "../../ghc/rts/RtsUtils.h" // for barf()
12
13 #ifdef mingw32_TARGET_OS
14    // The Win32 C runtime has a max of 2048 file descriptors (see
15    // _NHANDLE_ in the crt sources), but mingw defines FD_SETSIZE to
16    // 64.
17 #  define NUM_FDS 2048
18 #else
19 #  ifndef FD_SETSIZE
20 #    error No FD_SETSIZE defined!
21 #  else
22 #    define NUM_FDS FD_SETSIZE
23 #  endif
24 #endif
25
26 typedef struct {
27     dev_t device;
28     ino_t inode;
29     int fd;
30 } Lock;
31
32 static Lock readLock[NUM_FDS];
33 static Lock writeLock[NUM_FDS];
34
35 static int readLocks = 0;
36 static int writeLocks = 0;
37
38 int
39 lockFile(int fd, int for_writing, int exclusive)
40 {
41     struct stat sb;
42     int i;
43
44     if (fd > NUM_FDS) {
45         barf("lockFile: fd out of range");
46     }
47
48     while (fstat(fd, &sb) < 0) {
49         if (errno != EINTR) {
50 #ifndef _WIN32
51             return -1;
52 #else
53             /* fstat()ing socket fd's seems to fail with CRT's fstat(),
54                so let's just silently return and hope for the best..
55             */
56             return 0;
57 #endif
58         }
59     }
60
61     if (for_writing) {
62       /* opening a file for writing, check to see whether
63          we don't have any read locks on it already.. */
64       for (i = 0; i < readLocks; i++) {
65          if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
66 #ifndef __MINGW32__
67             return -1;
68 #else
69             break;    
70 #endif
71          }          
72       }
73       /* If we're determined that there is only a single
74          writer to the file, check to see whether the file
75          hasn't already been opened for writing..
76       */
77       if (exclusive) {
78         for (i = 0; i < writeLocks; i++) {
79           if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
80 #ifndef __MINGW32__
81              return -1;
82 #else
83              break;
84 #endif
85           }
86         }
87       }
88       /* OK, everything is cool lock-wise, record it and leave. */
89       i = writeLocks++;
90       writeLock[i].device = sb.st_dev;
91       writeLock[i].inode = sb.st_ino;
92       writeLock[i].fd = fd;
93       return 0;
94     } else { 
95       /* For reading, it's simpler - just check to see
96          that there's no-one writing to the underlying file. */
97       for (i = 0; i < writeLocks; i++) {
98         if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
99 #ifndef __MINGW32__
100              return -1;
101 #else
102              break;
103 #endif
104         }
105       }
106       /* Fit in new entry, reusing an existing table entry, if possible. */
107       for (i = 0; i < readLocks; i++) {
108          if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
109            return 0;
110          }
111       }
112       i = readLocks++;
113       readLock[i].device = sb.st_dev;
114       readLock[i].inode = sb.st_ino;
115       readLock[i].fd = fd;
116       return 0;
117     }
118
119 }
120
121 int
122 unlockFile(int fd)
123 {
124     int i;
125
126     for (i = 0; i < readLocks; i++)
127         if (readLock[i].fd == fd) {
128             while (++i < readLocks)
129                 readLock[i - 1] = readLock[i];
130             readLocks--;
131             return 0;
132         }
133
134     for (i = 0; i < writeLocks; i++)
135         if (writeLock[i].fd == fd) {
136             while (++i < writeLocks)
137                 writeLock[i - 1] = writeLock[i];
138             writeLocks--;
139             return 0;
140         }
141      /* Signal that we did not find an entry */
142     return 1;
143 }