/*
* 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_buf_flush(struct ubik_dbase *adbase, afs_int32 afid);
+
+/*!
+ * \warning 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)
+uphys_open(struct ubik_dbase *adbase, afs_int32 afid)
{
- char temp[20];
- register int fd;
+ int fd;
static int initd;
- register int i;
- register struct fdcache *tfd;
+ int i;
+ struct fdcache *tfd;
struct fdcache *bestfd;
/* initialize package */
/* 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 */
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 */
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;
tfd = fdcache;
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)
{
- register int fd;
+ int fd;
struct stat tstat;
- register afs_int32 code;
+ afs_int32 code;
fd = uphys_open(adbase, afid);
if (fd < 0)
if (code < 0) {
return code;
}
- astat->mtime = tstat.st_mtime;
code = tstat.st_size - HDRSIZE;
if (code < 0)
astat->size = 0;
}
int
-uphys_read(register struct ubik_dbase *adbase, afs_int32 afile,
- register char *abuffer, afs_int32 apos, afs_int32 alength)
+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)
}
int
-uphys_write(register struct ubik_dbase *adbase, afs_int32 afile,
- register char *abuffer, afs_int32 apos, afs_int32 alength)
+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);
}
int
-uphys_truncate(register struct ubik_dbase *adbase, afs_int32 afile,
+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;
return code;
}
-/* get number of dbase files */
+/*!
+ * \brief Get number of dbase files.
+ *
+ * \todo Really should scan dir for data.
+ */
int
-uphys_getnfiles(register struct ubik_dbase *adbase)
+uphys_getnfiles(struct ubik_dbase *adbase)
{
/* really should scan dir for data */
return 1;
}
-/* get database label, with aversion in host order */
+/*!
+ * \brief Get database label, with \p aversion in host order.
+ */
int
-uphys_getlabel(register struct ubik_dbase *adbase, afs_int32 afile,
+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;
+ if (lseek(fd, 0, 0) < 0) {
+ uphys_close(fd);
+ return EIO;
+ }
code = read(fd, &thdr, sizeof(thdr));
if (code != sizeof(thdr)) {
uphys_close(fd);
return 0;
}
-/* label database, with aversion in host order */
+/*!
+ * \brief Label database, with \p aversion in host order.
+ */
int
-uphys_setlabel(register struct ubik_dbase *adbase, afs_int32 afile,
+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;
+
+ 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);
+ thdr.size = htons(HDRSIZE);
+ if (lseek(fd, 0, 0) < 0) {
+ uphys_close(fd);
+ return EIO;
+ }
code = write(fd, &thdr, sizeof(thdr));
fsync(fd); /* preserve over crash */
uphys_close(fd);
}
int
-uphys_sync(register struct ubik_dbase *adbase, afs_int32 afile)
+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;
+}