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