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