2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #include <afs/afsutil.h>
20 #define UBIK_INTERNALS 1
24 * These routines are called via the proc ptr in the ubik_dbase structure. They provide access to
25 * the physical disk, by converting the file numbers being processed ( >= 0 for user data space, < 0
26 * for ubik system files, such as the log) to actual pathnames to open, read, write, truncate, sync,
31 static struct fdcache {
35 } fdcache[MAXFDCACHE];
37 /* Cache a stdio handle for a given database file, for uphys_buf_append
38 * operations. We only use buf_append for one file at a time, so only try to
39 * cache a single file handle, since that's all we should need. */
40 static struct buf_fdcache {
45 static char pbuffer[1024];
47 static int uphys_buf_flush(struct ubik_dbase *adbase, afs_int32 afid);
50 # define uphys_pread pread
51 # define uphys_pwrite pwrite
54 uphys_pread(int fd, void *buf, size_t nbyte, off_t offset)
56 if (lseek(fd, offset, 0) < 0) {
59 return read(fd, buf, nbyte);
63 uphys_pwrite(int fd, void *buf, size_t nbyte, off_t offset)
65 if (lseek(fd, offset, 0) < 0) {
68 return write(fd, buf, nbyte);
70 #endif /* !HAVE_PIO */
73 * \warning Beware, when using this function, of the header in front of most files.
76 uphys_open(struct ubik_dbase *adbase, afs_int32 afid)
82 struct fdcache *bestfd;
84 /* initialize package */
88 for (i = 0; i < MAXFDCACHE; tfd++, i++) {
89 tfd->fd = -1; /* invalid value */
90 tfd->fileID = -10000; /* invalid value */
95 /* scan file descr cache */
96 for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
97 if (afid == tfd->fileID && tfd->refCount == 0) { /* don't use open fd */
103 /* not found, open it and try to enter in cache */
104 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d", adbase->pathName,
105 (afid<0)?"SYS":"", (afid<0)?-afid:afid);
106 fd = open(pbuffer, O_CREAT | O_RDWR, 0600);
108 /* try opening read-only */
109 fd = open(pbuffer, O_RDONLY, 0);
114 /* enter it in the cache */
117 for (i = 0; i < MAXFDCACHE; i++, tfd++) { /* look for empty slot */
123 if (!bestfd) { /* look for reclaimable slot */
125 for (i = 0; i < MAXFDCACHE; i++, tfd++) {
126 if (tfd->refCount == 0) {
132 if (bestfd) { /* found a usable slot */
137 tfd->refCount = 1; /* us */
141 /* finally, we're done */
146 * \brief Close the file, maintaining ref count in cache structure.
157 for (i = 0; i < MAXFDCACHE; i++, tfd++) {
158 if (tfd->fd == afd) {
159 if (tfd->fileID != -10000) {
163 if (tfd->refCount > 0) {
165 if (tfd->refCount == 0) {
180 uphys_stat(struct ubik_dbase *adbase, afs_int32 afid, struct ubik_stat *astat)
186 fd = uphys_open(adbase, afid);
189 code = fstat(fd, &tstat);
194 code = tstat.st_size - HDRSIZE;
203 uphys_read(struct ubik_dbase *adbase, afs_int32 afile,
204 void *abuffer, afs_int32 apos, afs_int32 alength)
209 fd = uphys_open(adbase, afile);
212 code = uphys_pread(fd, abuffer, alength, apos + HDRSIZE);
218 uphys_write(struct ubik_dbase *adbase, afs_int32 afile,
219 void *abuffer, afs_int32 apos, afs_int32 alength)
225 fd = uphys_open(adbase, afile);
228 length = uphys_pwrite(fd, abuffer, alength, apos + HDRSIZE);
229 code = uphys_close(fd);
237 uphys_truncate(struct ubik_dbase *adbase, afs_int32 afile,
242 /* Just in case there's memory-buffered data for this file, flush it before
244 if (uphys_buf_flush(adbase, afile) < 0) {
248 fd = uphys_open(adbase, afile);
251 code = ftruncate(fd, asize + HDRSIZE);
257 * \brief Get number of dbase files.
259 * \todo Really should scan dir for data.
262 uphys_getnfiles(struct ubik_dbase *adbase)
264 /* really should scan dir for data */
269 * \brief Get database label, with \p aversion in host order.
272 uphys_getlabel(struct ubik_dbase *adbase, afs_int32 afile,
273 struct ubik_version *aversion)
275 struct ubik_hdr thdr;
278 fd = uphys_open(adbase, afile);
281 code = uphys_pread(fd, &thdr, sizeof(thdr), 0);
282 if (code != sizeof(thdr)) {
286 aversion->epoch = ntohl(thdr.version.epoch);
287 aversion->counter = ntohl(thdr.version.counter);
293 * \brief Label database, with \p aversion in host order.
296 uphys_setlabel(struct ubik_dbase *adbase, afs_int32 afile,
297 struct ubik_version *aversion)
299 struct ubik_hdr thdr;
302 fd = uphys_open(adbase, afile);
306 memset(&thdr, 0, sizeof(thdr));
308 thdr.version.epoch = htonl(aversion->epoch);
309 thdr.version.counter = htonl(aversion->counter);
310 thdr.magic = htonl(UBIK_MAGIC);
311 thdr.size = htons(HDRSIZE);
312 code = uphys_pwrite(fd, &thdr, sizeof(thdr), 0);
313 fsync(fd); /* preserve over crash */
315 if (code != sizeof(thdr)) {
322 uphys_sync(struct ubik_dbase *adbase, afs_int32 afile)
326 /* Flush any in-memory data, so we can sync it. */
327 if (uphys_buf_flush(adbase, afile) < 0) {
331 fd = uphys_open(adbase, afile);
338 uphys_invalidate(struct ubik_dbase *adbase, afs_int32 afid)
343 /* scan file descr cache */
344 for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
345 if (afid == tfd->fileID) {
346 tfd->fileID = -10000;
347 if (tfd->fd >= 0 && tfd->refCount == 0) {
357 uphys_buf_append_open(struct ubik_dbase *adbase, afs_int32 afid)
359 /* If we have a cached handle open for this file, just return it. */
360 if (buf_fdcache.stream && buf_fdcache.fileID == afid) {
361 return buf_fdcache.stream;
364 /* Otherwise, close the existing handle, and open a new handle for the
367 if (buf_fdcache.stream) {
368 fclose(buf_fdcache.stream);
371 snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d", adbase->pathName,
372 (afid<0)?"SYS":"", (afid<0)?-afid:afid);
373 buf_fdcache.stream = fopen(pbuffer, "a");
374 buf_fdcache.fileID = afid;
375 return buf_fdcache.stream;
379 uphys_buf_flush(struct ubik_dbase *adbase, afs_int32 afid)
381 if (buf_fdcache.stream && buf_fdcache.fileID == afid) {
382 int code = fflush(buf_fdcache.stream);
390 /* Append the given data to the given database file, allowing the data to be
391 * buffered in memory. */
393 uphys_buf_append(struct ubik_dbase *adbase, afs_int32 afid, void *adata,
399 stream = uphys_buf_append_open(adbase, afid);
404 code = fwrite(adata, alength, 1, stream);