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