/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
#include <afsconfig.h>
#include <afs/param.h>
-RCSID("$Header$");
-
-#include <sys/types.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#include <io.h>
-#include <fcntl.h>
-#else
-#include <sys/file.h>
-#include <netinet/in.h>
-#endif
-#include <sys/stat.h>
+#include <roken.h>
+
#include <lwp.h>
+
#include <lock.h>
-#include <errno.h>
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
+#include <afs/afsutil.h>
#define UBIK_INTERNALS 1
#include "ubik.h"
-/* these routines are called via the proc ptr in the ubik_dbase structure. They provide access to
- * the physical disk, by converting the file numbers being processed (>= 0 for user data space, < 0
+/*! \file
+ * These routines are called via the proc ptr in the ubik_dbase structure. They provide access to
+ * the physical disk, by converting the file numbers being processed ( >= 0 for user data space, < 0
* for ubik system files, such as the log) to actual pathnames to open, read, write, truncate, sync,
* etc.
*/
int refCount;
} fdcache[MAXFDCACHE];
+/* Cache a stdio handle for a given database file, for uphys_buf_append
+ * operations. We only use buf_append for one file at a time, so only try to
+ * cache a single file handle, since that's all we should need. */
+static struct buf_fdcache {
+ int fileID;
+ FILE *stream;
+} buf_fdcache;
+
static char pbuffer[1024];
-/* beware, when using this function, of the header in front of most files */
-static int uphys_open(register struct ubik_dbase *adbase, afs_int32 afid)
+static int uphys_buf_flush(struct ubik_dbase *adbase, afs_int32 afid);
+
+#ifdef HAVE_PIO
+# define uphys_pread pread
+# define uphys_pwrite pwrite
+#else /* HAVE_PIO */
+static_inline ssize_t
+uphys_pread(int fd, void *buf, size_t nbyte, off_t offset)
+{
+ if (lseek(fd, offset, 0) < 0) {
+ return -1;
+ }
+ return read(fd, buf, nbyte);
+}
+
+static_inline ssize_t
+uphys_pwrite(int fd, void *buf, size_t nbyte, off_t offset)
{
- char temp[20];
- register int fd;
+ if (lseek(fd, offset, 0) < 0) {
+ return -1;
+ }
+ return write(fd, buf, nbyte);
+}
+#endif /* !HAVE_PIO */
+
+/*!
+ * \warning Beware, when using this function, of the header in front of most files.
+ */
+static int
+uphys_open(struct ubik_dbase *adbase, afs_int32 afid)
+{
+ int fd;
static int initd;
- register int i;
- register struct fdcache *tfd;
+ int i;
+ struct fdcache *tfd;
struct fdcache *bestfd;
/* initialize package */
if (!initd) {
- initd=1;
- tfd=fdcache;
- for(i=0;i<MAXFDCACHE;tfd++,i++) {
- tfd->fd = -1; /* invalid value */
- tfd->fileID = -10000; /* invalid value */
+ initd = 1;
+ tfd = fdcache;
+ for (i = 0; i < MAXFDCACHE; tfd++, i++) {
+ tfd->fd = -1; /* invalid value */
+ tfd->fileID = -10000; /* invalid value */
tfd->refCount = 0;
}
}
/* scan file descr cache */
- for(tfd=fdcache,i=0; i<MAXFDCACHE; i++,tfd++) {
- if (afid == tfd->fileID && tfd->refCount == 0) { /* don't use open fd */
- lseek(tfd->fd, 0, 0); /* reset ptr just like open would have */
+ for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
+ if (afid == tfd->fileID && tfd->refCount == 0) { /* don't use open fd */
tfd->refCount++;
return tfd->fd;
}
}
/* not found, open it and try to enter in cache */
- strcpy(pbuffer, adbase->pathName);
- strcat(pbuffer, ".DB");
- if (afid < 0) {
- i = -afid;
- strcat(pbuffer, "SYS");
- }
- else i = afid;
- sprintf(temp, "%d", i);
- strcat(pbuffer, temp);
+ snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d", adbase->pathName,
+ (afid<0)?"SYS":"", (afid<0)?-afid:afid);
fd = open(pbuffer, O_CREAT | O_RDWR, 0600);
if (fd < 0) {
/* try opening read-only */
fd = open(pbuffer, O_RDONLY, 0);
- if (fd < 0) return fd;
+ if (fd < 0)
+ return fd;
}
-
+
/* enter it in the cache */
tfd = fdcache;
bestfd = NULL;
- for(i=0;i<MAXFDCACHE;i++,tfd++) { /* look for empty slot */
+ for (i = 0; i < MAXFDCACHE; i++, tfd++) { /* look for empty slot */
if (tfd->fd == -1) {
bestfd = tfd;
break;
}
}
- if (!bestfd) { /* look for reclaimable slot */
+ if (!bestfd) { /* look for reclaimable slot */
tfd = fdcache;
- for(i=0;i<MAXFDCACHE;i++,tfd++) {
+ for (i = 0; i < MAXFDCACHE; i++, tfd++) {
if (tfd->refCount == 0) {
bestfd = tfd;
break;
}
}
}
- if (bestfd) { /* found a usable slot */
+ if (bestfd) { /* found a usable slot */
tfd = bestfd;
- if (tfd->fd >= 0) close(tfd->fd);
+ if (tfd->fd >= 0)
+ close(tfd->fd);
tfd->fd = fd;
tfd->refCount = 1; /* us */
tfd->fileID = afid;
return fd;
}
-/* close the file, maintaining ref count in cache structure */
-int uphys_close (register int afd)
+/*!
+ * \brief Close the file, maintaining ref count in cache structure.
+ */
+static int
+uphys_close(int afd)
{
- register int i;
- register struct fdcache *tfd;
+ int i;
+ struct fdcache *tfd;
- if (afd < 0) return EBADF;
+ if (afd < 0)
+ return EBADF;
tfd = fdcache;
- for(i=0;i<MAXFDCACHE;i++,tfd++) {
+ for (i = 0; i < MAXFDCACHE; i++, tfd++) {
if (tfd->fd == afd) {
- tfd->refCount--;
- return 0;
+ if (tfd->fileID != -10000) {
+ tfd->refCount--;
+ return 0;
+ } else {
+ if (tfd->refCount > 0) {
+ tfd->refCount--;
+ if (tfd->refCount == 0) {
+ close(tfd->fd);
+ tfd->fd = -1;
+ }
+ return 0;
+ }
+ tfd->fd = -1;
+ break;
+ }
}
}
return close(afd);
}
-int uphys_stat(struct ubik_dbase *adbase, afs_int32 afid, struct ubik_stat *astat)
+int
+uphys_stat(struct ubik_dbase *adbase, afs_int32 afid, struct ubik_stat *astat)
{
- register int fd;
+ int fd;
struct stat tstat;
- register afs_int32 code;
-
+ afs_int32 code;
+
fd = uphys_open(adbase, afid);
- if (fd < 0) return fd;
+ if (fd < 0)
+ return fd;
code = fstat(fd, &tstat);
uphys_close(fd);
if (code < 0) {
return code;
}
- astat->mtime = tstat.st_mtime;
- code = tstat.st_size-HDRSIZE;
- if (code < 0) astat->size = 0;
- else astat->size = code;
+ code = tstat.st_size - HDRSIZE;
+ if (code < 0)
+ astat->size = 0;
+ else
+ astat->size = code;
return 0;
}
-int uphys_read(register struct ubik_dbase *adbase, afs_int32 afile, register char *abuffer,
- afs_int32 apos, afs_int32 alength)
+int
+uphys_read(struct ubik_dbase *adbase, afs_int32 afile,
+ void *abuffer, afs_int32 apos, afs_int32 alength)
{
- register int fd;
- register afs_int32 code;
+ int fd;
+ afs_int32 code;
fd = uphys_open(adbase, afile);
- if (fd < 0) return -1;
- code = lseek(fd, apos+HDRSIZE, 0);
- if (code < 0) {
- uphys_close(fd);
+ if (fd < 0)
return -1;
- }
- code = read(fd, abuffer, alength);
+ code = uphys_pread(fd, abuffer, alength, apos + HDRSIZE);
uphys_close(fd);
return code;
}
-int uphys_write(register struct ubik_dbase *adbase, afs_int32 afile, register char *abuffer,
- afs_int32 apos, afs_int32 alength)
+int
+uphys_write(struct ubik_dbase *adbase, afs_int32 afile,
+ void *abuffer, afs_int32 apos, afs_int32 alength)
{
- register int fd;
- register afs_int32 code;
+ int fd;
+ afs_int32 code;
afs_int32 length;
fd = uphys_open(adbase, afile);
- if (fd < 0) return -1;
- code = lseek(fd, apos+HDRSIZE, 0);
- if (code < 0) {
- uphys_close(fd);
+ if (fd < 0)
return -1;
- }
- length = write(fd, abuffer, alength);
+ length = uphys_pwrite(fd, abuffer, alength, apos + HDRSIZE);
code = uphys_close(fd);
- if (code) return -1;
- else return length;
+ if (code)
+ return -1;
+ else
+ return length;
}
-int uphys_truncate(register struct ubik_dbase *adbase, afs_int32 afile, afs_int32 asize)
+int
+uphys_truncate(struct ubik_dbase *adbase, afs_int32 afile,
+ afs_int32 asize)
{
- register afs_int32 code, fd;
+ afs_int32 code, fd;
+
+ /* Just in case there's memory-buffered data for this file, flush it before
+ * truncating. */
+ if (uphys_buf_flush(adbase, afile) < 0) {
+ return UIOERROR;
+ }
+
fd = uphys_open(adbase, afile);
- if (fd < 0) return UNOENT;
- code = ftruncate(fd, asize+HDRSIZE);
+ if (fd < 0)
+ return UNOENT;
+ code = ftruncate(fd, asize + HDRSIZE);
uphys_close(fd);
return code;
}
-/* get number of dbase files */
-int uphys_getnfiles(register struct ubik_dbase *adbase)
+/*!
+ * \brief Get number of dbase files.
+ *
+ * \todo Really should scan dir for data.
+ */
+int
+uphys_getnfiles(struct ubik_dbase *adbase)
{
/* really should scan dir for data */
return 1;
}
-/* get database label, with aversion in host order */
-int uphys_getlabel(register struct ubik_dbase *adbase, afs_int32 afile, struct ubik_version *aversion)
+/*!
+ * \brief Get database label, with \p aversion in host order.
+ */
+int
+uphys_getlabel(struct ubik_dbase *adbase, afs_int32 afile,
+ struct ubik_version *aversion)
{
struct ubik_hdr thdr;
- register afs_int32 code, fd;
+ afs_int32 code, fd;
fd = uphys_open(adbase, afile);
- if (fd < 0) return UNOENT;
- code = read(fd, &thdr, sizeof(thdr));
+ if (fd < 0)
+ return UNOENT;
+ code = uphys_pread(fd, &thdr, sizeof(thdr), 0);
if (code != sizeof(thdr)) {
uphys_close(fd);
return EIO;
}
aversion->epoch = ntohl(thdr.version.epoch);
- aversion->counter=ntohl(thdr.version.counter);
+ aversion->counter = ntohl(thdr.version.counter);
uphys_close(fd);
return 0;
}
-/* label database, with aversion in host order */
-int uphys_setlabel(register struct ubik_dbase *adbase, afs_int32 afile, struct ubik_version *aversion)
+/*!
+ * \brief Label database, with \p aversion in host order.
+ */
+int
+uphys_setlabel(struct ubik_dbase *adbase, afs_int32 afile,
+ struct ubik_version *aversion)
{
struct ubik_hdr thdr;
- register afs_int32 code, fd;
+ afs_int32 code, fd;
fd = uphys_open(adbase, afile);
- if (fd < 0) return UNOENT;
+ if (fd < 0)
+ return UNOENT;
+
+ memset(&thdr, 0, sizeof(thdr));
+
thdr.version.epoch = htonl(aversion->epoch);
thdr.version.counter = htonl(aversion->counter);
thdr.magic = htonl(UBIK_MAGIC);
- thdr.size = htonl(HDRSIZE);
- code = write(fd, &thdr, sizeof(thdr));
- fsync(fd); /* preserve over crash */
+ thdr.size = htons(HDRSIZE);
+ code = uphys_pwrite(fd, &thdr, sizeof(thdr), 0);
+ fsync(fd); /* preserve over crash */
uphys_close(fd);
if (code != sizeof(thdr)) {
return EIO;
return 0;
}
-int uphys_sync(register struct ubik_dbase *adbase, afs_int32 afile)
+int
+uphys_sync(struct ubik_dbase *adbase, afs_int32 afile)
{
- register afs_int32 code, fd;
+ afs_int32 code, fd;
+
+ /* Flush any in-memory data, so we can sync it. */
+ if (uphys_buf_flush(adbase, afile) < 0) {
+ return -1;
+ }
+
fd = uphys_open(adbase, afile);
code = fsync(fd);
uphys_close(fd);
return code;
}
+
+void
+uphys_invalidate(struct ubik_dbase *adbase, afs_int32 afid)
+{
+ int i;
+ struct fdcache *tfd;
+
+ /* scan file descr cache */
+ for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) {
+ if (afid == tfd->fileID) {
+ tfd->fileID = -10000;
+ if (tfd->fd >= 0 && tfd->refCount == 0) {
+ close(tfd->fd);
+ tfd->fd = -1;
+ }
+ return;
+ }
+ }
+}
+
+static FILE *
+uphys_buf_append_open(struct ubik_dbase *adbase, afs_int32 afid)
+{
+ /* If we have a cached handle open for this file, just return it. */
+ if (buf_fdcache.stream && buf_fdcache.fileID == afid) {
+ return buf_fdcache.stream;
+ }
+
+ /* Otherwise, close the existing handle, and open a new handle for the
+ * given file. */
+
+ if (buf_fdcache.stream) {
+ fclose(buf_fdcache.stream);
+ }
+
+ snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d", adbase->pathName,
+ (afid<0)?"SYS":"", (afid<0)?-afid:afid);
+ buf_fdcache.stream = fopen(pbuffer, "a");
+ buf_fdcache.fileID = afid;
+ return buf_fdcache.stream;
+}
+
+static int
+uphys_buf_flush(struct ubik_dbase *adbase, afs_int32 afid)
+{
+ if (buf_fdcache.stream && buf_fdcache.fileID == afid) {
+ int code = fflush(buf_fdcache.stream);
+ if (code) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Append the given data to the given database file, allowing the data to be
+ * buffered in memory. */
+int
+uphys_buf_append(struct ubik_dbase *adbase, afs_int32 afid, void *adata,
+ afs_int32 alength)
+{
+ FILE *stream;
+ size_t code;
+
+ stream = uphys_buf_append_open(adbase, afid);
+ if (!stream) {
+ return -1;
+ }
+
+ code = fwrite(adata, alength, 1, stream);
+ if (code != 1) {
+ return -1;
+ }
+ return alength;
+}