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