99b2edff308023a3a109c59cfd37d2d9fc5874f2
[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 /*! \file
42  * These routines are called via the proc ptr in the ubik_dbase structure.  They provide access to
43  * the physical disk, by converting the file numbers being processed ( >= 0 for user data space, < 0
44  * for ubik system files, such as the log) to actual pathnames to open, read, write, truncate, sync,
45  * etc.
46  */
47
48 #define MAXFDCACHE  4
49 static struct fdcache {
50     int fd;
51     int fileID;
52     int refCount;
53 } fdcache[MAXFDCACHE];
54
55 static char pbuffer[1024];
56
57 /*!
58  * \warning Beware, when using this function, of the header in front of most files.
59  */
60 static int
61 uphys_open(register struct ubik_dbase *adbase, afs_int32 afid)
62 {
63     char temp[20];
64     register int fd;
65     static int initd;
66     register int i;
67     register 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(register int afd)
137 {
138     register int i;
139     register 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     return close(afd);
163 }
164
165 int
166 uphys_stat(struct ubik_dbase *adbase, afs_int32 afid, struct ubik_stat *astat)
167 {
168     register int fd;
169     struct stat tstat;
170     register afs_int32 code;
171
172     fd = uphys_open(adbase, afid);
173     if (fd < 0)
174         return fd;
175     code = fstat(fd, &tstat);
176     uphys_close(fd);
177     if (code < 0) {
178         return code;
179     }
180     astat->mtime = tstat.st_mtime;
181     code = tstat.st_size - HDRSIZE;
182     if (code < 0)
183         astat->size = 0;
184     else
185         astat->size = code;
186     return 0;
187 }
188
189 int
190 uphys_read(register struct ubik_dbase *adbase, afs_int32 afile,
191            register char *abuffer, afs_int32 apos, afs_int32 alength)
192 {
193     register int fd;
194     register afs_int32 code;
195
196     fd = uphys_open(adbase, afile);
197     if (fd < 0)
198         return -1;
199     code = lseek(fd, apos + HDRSIZE, 0);
200     if (code < 0) {
201         uphys_close(fd);
202         return -1;
203     }
204     code = read(fd, abuffer, alength);
205     uphys_close(fd);
206     return code;
207 }
208
209 int
210 uphys_write(register struct ubik_dbase *adbase, afs_int32 afile,
211             register char *abuffer, afs_int32 apos, afs_int32 alength)
212 {
213     register int fd;
214     register afs_int32 code;
215     afs_int32 length;
216
217     fd = uphys_open(adbase, afile);
218     if (fd < 0)
219         return -1;
220     code = lseek(fd, apos + HDRSIZE, 0);
221     if (code < 0) {
222         uphys_close(fd);
223         return -1;
224     }
225     length = write(fd, abuffer, alength);
226     code = uphys_close(fd);
227     if (code)
228         return -1;
229     else
230         return length;
231 }
232
233 int
234 uphys_truncate(register struct ubik_dbase *adbase, afs_int32 afile,
235                afs_int32 asize)
236 {
237     register afs_int32 code, fd;
238     fd = uphys_open(adbase, afile);
239     if (fd < 0)
240         return UNOENT;
241     code = ftruncate(fd, asize + HDRSIZE);
242     uphys_close(fd);
243     return code;
244 }
245
246 /*!
247  * \brief Get number of dbase files.
248  *
249  * \todo Really should scan dir for data.
250  */
251 int
252 uphys_getnfiles(register struct ubik_dbase *adbase)
253 {
254     /* really should scan dir for data */
255     return 1;
256 }
257
258 /*!
259  * \brief Get database label, with \p aversion in host order.
260  */
261 int
262 uphys_getlabel(register struct ubik_dbase *adbase, afs_int32 afile,
263                struct ubik_version *aversion)
264 {
265     struct ubik_hdr thdr;
266     register afs_int32 code, fd;
267
268     fd = uphys_open(adbase, afile);
269     if (fd < 0)
270         return UNOENT;
271     code = read(fd, &thdr, sizeof(thdr));
272     if (code != sizeof(thdr)) {
273         uphys_close(fd);
274         return EIO;
275     }
276     aversion->epoch = ntohl(thdr.version.epoch);
277     aversion->counter = ntohl(thdr.version.counter);
278     uphys_close(fd);
279     return 0;
280 }
281
282 /*!
283  * \brief Label database, with \p aversion in host order.
284  */
285 int
286 uphys_setlabel(register struct ubik_dbase *adbase, afs_int32 afile,
287                struct ubik_version *aversion)
288 {
289     struct ubik_hdr thdr;
290     register afs_int32 code, fd;
291
292     fd = uphys_open(adbase, afile);
293     if (fd < 0)
294         return UNOENT;
295     thdr.version.epoch = htonl(aversion->epoch);
296     thdr.version.counter = htonl(aversion->counter);
297     thdr.magic = htonl(UBIK_MAGIC);
298     thdr.size = htons(HDRSIZE);
299     code = write(fd, &thdr, sizeof(thdr));
300     fsync(fd);                  /* preserve over crash */
301     uphys_close(fd);
302     if (code != sizeof(thdr)) {
303         return EIO;
304     }
305     return 0;
306 }
307
308 int
309 uphys_sync(register struct ubik_dbase *adbase, afs_int32 afile)
310 {
311     register afs_int32 code, fd;
312     fd = uphys_open(adbase, afile);
313     code = fsync(fd);
314     uphys_close(fd);
315     return code;
316 }
317
318 void
319 uphys_invalidate(register struct ubik_dbase *adbase, afs_int32 afid)
320 {
321     register int i;
322     register struct fdcache *tfd;
323
324     /* scan file descr cache */
325     for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
326         if (afid == tfd->fileID) {
327             tfd->fileID = -10000;
328             if (tfd->fd >= 0 && tfd->refCount == 0) {
329                 close(tfd->fd);
330                 tfd->fd = -1;
331             }
332             return;
333         }
334     }
335 }