636a6a3d70cba403c26b4c6c1edca778ea44bc0a
[openafs.git] / src / ubik / phys.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <sys/types.h>
17 #ifdef AFS_NT40_ENV
18 #include <winsock2.h>
19 #include <io.h>
20 #include <fcntl.h>
21 #else
22 #include <sys/file.h>
23 #include <netinet/in.h>
24 #endif
25 #include <sys/stat.h>
26
27 /* #ifdef AFS_PTHREAD_ENV */
28 #if 0   /* temporary hack - klm */
29 /* nothing */
30 #else
31 #include <lwp.h>
32 #endif
33
34 #include <lock.h>
35 #include <errno.h>
36 #include <string.h>
37
38 #define UBIK_INTERNALS 1
39 #include "ubik.h"
40
41 /* these routines are called via the proc ptr in the ubik_dbase structure.  They provide access to
42  * the physical disk, by converting the file numbers being processed (>= 0 for user data space, < 0
43  * for ubik system files, such as the log) to actual pathnames to open, read, write, truncate, sync,
44  * etc.
45  */
46
47 #define MAXFDCACHE  4
48 static struct fdcache {
49     int fd;
50     int fileID;
51     int refCount;
52 } fdcache[MAXFDCACHE];
53
54 static char pbuffer[1024];
55
56 /* beware, when using this function, of the header in front of most files */
57 static int
58 uphys_open(register struct ubik_dbase *adbase, afs_int32 afid)
59 {
60     char temp[20];
61     register int fd;
62     static int initd;
63     register int i;
64     register struct fdcache *tfd;
65     struct fdcache *bestfd;
66
67     /* initialize package */
68     if (!initd) {
69         initd = 1;
70         tfd = fdcache;
71         for (i = 0; i < MAXFDCACHE; tfd++, i++) {
72             tfd->fd = -1;       /* invalid value */
73             tfd->fileID = -10000;       /* invalid value */
74             tfd->refCount = 0;
75         }
76     }
77
78     /* scan file descr cache */
79     for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
80         if (afid == tfd->fileID && tfd->refCount == 0) {        /* don't use open fd */
81             lseek(tfd->fd, 0, 0);       /* reset ptr just like open would have */
82             tfd->refCount++;
83             return tfd->fd;
84         }
85     }
86
87     /* not found, open it and try to enter in cache */
88     afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d", adbase->pathName, 
89                  (afid<0)?"SYS":"", (afid<0)?-afid:afid);
90     fd = open(pbuffer, O_CREAT | O_RDWR, 0600);
91     if (fd < 0) {
92         /* try opening read-only */
93         fd = open(pbuffer, O_RDONLY, 0);
94         if (fd < 0)
95             return fd;
96     }
97
98     /* enter it in the cache */
99     tfd = fdcache;
100     bestfd = NULL;
101     for (i = 0; i < MAXFDCACHE; i++, tfd++) {   /* look for empty slot */
102         if (tfd->fd == -1) {
103             bestfd = tfd;
104             break;
105         }
106     }
107     if (!bestfd) {              /* look for reclaimable slot */
108         tfd = fdcache;
109         for (i = 0; i < MAXFDCACHE; i++, tfd++) {
110             if (tfd->refCount == 0) {
111                 bestfd = tfd;
112                 break;
113             }
114         }
115     }
116     if (bestfd) {               /* found a usable slot */
117         tfd = bestfd;
118         if (tfd->fd >= 0) 
119             close(tfd->fd);
120         tfd->fd = fd;
121         tfd->refCount = 1;      /* us */
122         tfd->fileID = afid;
123     }
124
125     /* finally, we're done */
126     return fd;
127 }
128
129 /* close the file, maintaining ref count in cache structure */
130 int
131 uphys_close(register int afd)
132 {
133     register int i;
134     register struct fdcache *tfd;
135
136     if (afd < 0)
137         return EBADF;
138     tfd = fdcache;
139     for (i = 0; i < MAXFDCACHE; i++, tfd++) {
140         if (tfd->fd == afd) 
141             if (tfd->fileID != -10000) {
142                 tfd->refCount--;
143                 return 0;
144             } else {
145                 if (tfd->refCount > 0) {
146                     tfd->refCount--;
147                     if (tfd->refCount == 0) {
148                         close(tfd->fd);
149                         tfd->fd = -1;
150                     }
151                     return 0;
152                 }
153                 tfd->fd = -1;
154                 break;
155             }
156     }
157     return close(afd);
158 }
159
160 int
161 uphys_stat(struct ubik_dbase *adbase, afs_int32 afid, struct ubik_stat *astat)
162 {
163     register int fd;
164     struct stat tstat;
165     register afs_int32 code;
166
167     fd = uphys_open(adbase, afid);
168     if (fd < 0)
169         return fd;
170     code = fstat(fd, &tstat);
171     uphys_close(fd);
172     if (code < 0) {
173         return code;
174     }
175     astat->mtime = tstat.st_mtime;
176     code = tstat.st_size - HDRSIZE;
177     if (code < 0)
178         astat->size = 0;
179     else
180         astat->size = code;
181     return 0;
182 }
183
184 int
185 uphys_read(register struct ubik_dbase *adbase, afs_int32 afile,
186            register char *abuffer, afs_int32 apos, afs_int32 alength)
187 {
188     register int fd;
189     register afs_int32 code;
190
191     fd = uphys_open(adbase, afile);
192     if (fd < 0)
193         return -1;
194     code = lseek(fd, apos + HDRSIZE, 0);
195     if (code < 0) {
196         uphys_close(fd);
197         return -1;
198     }
199     code = read(fd, abuffer, alength);
200     uphys_close(fd);
201     return code;
202 }
203
204 int
205 uphys_write(register struct ubik_dbase *adbase, afs_int32 afile,
206             register char *abuffer, afs_int32 apos, afs_int32 alength)
207 {
208     register int fd;
209     register afs_int32 code;
210     afs_int32 length;
211
212     fd = uphys_open(adbase, afile);
213     if (fd < 0)
214         return -1;
215     code = lseek(fd, apos + HDRSIZE, 0);
216     if (code < 0) {
217         uphys_close(fd);
218         return -1;
219     }
220     length = write(fd, abuffer, alength);
221     code = uphys_close(fd);
222     if (code)
223         return -1;
224     else
225         return length;
226 }
227
228 int
229 uphys_truncate(register struct ubik_dbase *adbase, afs_int32 afile,
230                afs_int32 asize)
231 {
232     register afs_int32 code, fd;
233     fd = uphys_open(adbase, afile);
234     if (fd < 0)
235         return UNOENT;
236     code = ftruncate(fd, asize + HDRSIZE);
237     uphys_close(fd);
238     return code;
239 }
240
241 /* get number of dbase files */
242 int
243 uphys_getnfiles(register struct ubik_dbase *adbase)
244 {
245     /* really should scan dir for data */
246     return 1;
247 }
248
249 /* get database label, with aversion in host order */
250 int
251 uphys_getlabel(register struct ubik_dbase *adbase, afs_int32 afile,
252                struct ubik_version *aversion)
253 {
254     struct ubik_hdr thdr;
255     register afs_int32 code, fd;
256
257     fd = uphys_open(adbase, afile);
258     if (fd < 0)
259         return UNOENT;
260     code = read(fd, &thdr, sizeof(thdr));
261     if (code != sizeof(thdr)) {
262         uphys_close(fd);
263         return EIO;
264     }
265     aversion->epoch = ntohl(thdr.version.epoch);
266     aversion->counter = ntohl(thdr.version.counter);
267     uphys_close(fd);
268     return 0;
269 }
270
271 /* label database, with aversion in host order */
272 int
273 uphys_setlabel(register struct ubik_dbase *adbase, afs_int32 afile,
274                struct ubik_version *aversion)
275 {
276     struct ubik_hdr thdr;
277     register afs_int32 code, fd;
278
279     fd = uphys_open(adbase, afile);
280     if (fd < 0)
281         return UNOENT;
282     thdr.version.epoch = htonl(aversion->epoch);
283     thdr.version.counter = htonl(aversion->counter);
284     thdr.magic = htonl(UBIK_MAGIC);
285     thdr.size = htons(HDRSIZE);
286     code = write(fd, &thdr, sizeof(thdr));
287     fsync(fd);                  /* preserve over crash */
288     uphys_close(fd);
289     if (code != sizeof(thdr)) {
290         return EIO;
291     }
292     return 0;
293 }
294
295 int
296 uphys_sync(register struct ubik_dbase *adbase, afs_int32 afile)
297 {
298     register afs_int32 code, fd;
299     fd = uphys_open(adbase, afile);
300     code = fsync(fd);
301     uphys_close(fd);
302     return code;
303 }
304
305 void
306 uphys_invalidate(register struct ubik_dbase *adbase, afs_int32 afid)
307 {
308     register int i;
309     register struct fdcache *tfd;
310
311     /* scan file descr cache */
312     for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
313         if (afid == tfd->fileID) {
314             tfd->fileID = -10000;
315             if (tfd->fd >= 0 && tfd->refCount == 0) {
316                 close(tfd->fd);
317                 tfd->fd = -1;
318             }
319             return;
320         }
321     }
322 }