#include <roken.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.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>
-
-/* #ifdef AFS_PTHREAD_ENV */
-#if 0 /* temporary hack - klm */
-/* nothing */
-#else
#include <lwp.h>
-#endif
#include <lock.h>
#include <afs/afsutil.h>
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];
+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.
*/
/* 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;
}
if (code < 0) {
return code;
}
- astat->mtime = tstat.st_mtime;
code = tstat.st_size - HDRSIZE;
if (code < 0)
astat->size = 0;
afs_int32 asize)
{
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;
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);
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 = 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);
uphys_sync(struct ubik_dbase *adbase, afs_int32 afile)
{
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);
}
}
}
+
+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;
+}