aboutsummaryrefslogtreecommitdiffstats
path: root/src/mgr/filemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr/filemgr.cpp')
-rw-r--r--src/mgr/filemgr.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/mgr/filemgr.cpp b/src/mgr/filemgr.cpp
new file mode 100644
index 0000000..0b31576
--- /dev/null
+++ b/src/mgr/filemgr.cpp
@@ -0,0 +1,266 @@
+/******************************************************************************
+ * filemgr.cpp - implementation of class FileMgr used for pooling file
+ * handles
+ *
+ * $Id: filemgr.cpp,v 1.22 2002/07/31 20:26:38 scribe Exp $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <filemgr.h>
+#include <utilstr.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef __GNUC__
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+// ---------------- statics -----------------
+FileMgr FileMgr::systemFileMgr;
+
+// --------------- end statics --------------
+
+
+FileDesc::FileDesc(FileMgr *parent, char *path, int mode, int perms, bool tryDowngrade) {
+ this->parent = parent;
+ this->path = 0;
+ stdstr(&this->path, path);
+ this->mode = mode;
+ this->perms = perms;
+ this->tryDowngrade = tryDowngrade;
+ offset = 0;
+ fd = -77;
+}
+
+
+FileDesc::~FileDesc() {
+ if (fd > 0)
+ close(fd);
+
+ if (path)
+ delete [] path;
+}
+
+
+int FileDesc::getFd() {
+ if (fd == -77)
+ fd = parent->sysOpen(this);
+ return fd;
+}
+
+
+FileMgr::FileMgr(int maxFiles) {
+ this->maxFiles = maxFiles; // must be at least 2
+ files = 0;
+}
+
+
+FileMgr::~FileMgr() {
+ FileDesc *tmp;
+
+ while(files) {
+ tmp = files->next;
+ delete files;
+ files = tmp;
+ }
+}
+
+
+FileDesc *FileMgr::open(char *path, int mode, bool tryDowngrade) {
+ return open(path, mode, S_IREAD | S_IWRITE, tryDowngrade);
+}
+
+FileDesc *FileMgr::open(char *path, int mode, int perms, bool tryDowngrade) {
+ FileDesc **tmp, *tmp2;
+
+ for (tmp = &files; *tmp; tmp = &((*tmp)->next)) {
+ if ((*tmp)->fd < 0) // insert as first non-system_open file
+ break;
+ }
+
+ tmp2 = new FileDesc(this, path, mode, perms, tryDowngrade);
+ tmp2->next = *tmp;
+ *tmp = tmp2;
+
+ return tmp2;
+}
+
+
+void FileMgr::close(FileDesc *file) {
+ FileDesc **loop;
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+ if (*loop == file) {
+ *loop = (*loop)->next;
+ delete file;
+ break;
+ }
+ }
+}
+
+
+// to truncate a file at its current position
+// leaving byte at current possition intact
+// deleting everything afterward.
+signed char FileMgr::trunc(FileDesc *file) {
+
+ static const char *writeTest = "x";
+ long size = lseek(file->getFd(), 1, SEEK_CUR);
+ if (size == 1) // was empty
+ size = 0;
+ char nibble [ 32767 ];
+ bool writable = write(file->getFd(), writeTest, 1);
+ int bytes = 0;
+
+ if (writable) {
+ // get tmpfilename
+ char *buf = new char [ strlen(file->path) + 10 ];
+ int i;
+ for (i = 0; i < 9999; i++) {
+ sprintf(buf, "%stmp%.4d", file->path, i);
+ if (!existsFile(buf))
+ break;
+ }
+ if (i == 9999)
+ return -2;
+
+ int fd = ::open(buf, O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
+ if (fd < 0)
+ return -3;
+
+ lseek(file->getFd(), 0, SEEK_SET);
+ while (size > 0) {
+ bytes = read(file->getFd(), nibble, 32767);
+ write(fd, nibble, (bytes < size)?bytes:size);
+ size -= bytes;
+ }
+ // zero out the file
+ ::close(file->fd);
+ file->fd = ::open(file->path, O_TRUNC, S_IREAD|S_IWRITE);
+ ::close(file->fd);
+ file->fd = -77; // force file open by filemgr
+ // copy tmp file back (dumb, but must preserve file permissions)
+ lseek(fd, 0, SEEK_SET);
+ do {
+ bytes = read(fd, nibble, 32767);
+ write(file->getFd(), nibble, bytes);
+ } while (bytes == 32767);
+
+ ::close(fd);
+ ::close(file->fd);
+ unlink(buf); // remove our tmp file
+ file->fd = -77; // causes file to be swapped out forcing open on next call to getFd()
+ }
+ else { // put offset back and return failure
+ lseek(file->getFd(), -1, SEEK_CUR);
+ return -1;
+ }
+ return 0;
+}
+
+
+int FileMgr::sysOpen(FileDesc *file) {
+ FileDesc **loop;
+ int openCount = 1; // because we are presently opening 1 file, and we need to be sure to close files to accomodate, if necessary
+
+ for (loop = &files; *loop; loop = &((*loop)->next)) {
+
+ if ((*loop)->fd > 0) {
+ if (++openCount > maxFiles) {
+ (*loop)->offset = lseek((*loop)->fd, 0, SEEK_CUR);
+ ::close((*loop)->fd);
+ (*loop)->fd = -77;
+ }
+ }
+
+ if (*loop == file) {
+ if (*loop != files) {
+ *loop = (*loop)->next;
+ file->next = files;
+ files = file;
+ }
+ if ((!access(file->path, 04)) || ((file->mode & O_CREAT) == O_CREAT)) { // check for at least file exists / read access before we try to open
+ char tries = (((file->mode & O_RDWR) == O_RDWR) && (file->tryDowngrade)) ? 2 : 1; // try read/write if possible
+ for (int i = 0; i < tries; i++) {
+ if (i > 0) {
+ file->mode = (file->mode & ~O_RDWR); // remove write access
+ file->mode = (file->mode | O_RDONLY);// add read access
+ }
+ file->fd = ::open(file->path, file->mode, file->perms);
+
+ if (file->fd >= 0)
+ break;
+ }
+
+ if (file->fd >= 0)
+ lseek(file->fd, file->offset, SEEK_SET);
+ }
+ else file->fd = -1;
+ if (!*loop)
+ break;
+ }
+ }
+ return file->fd;
+}
+
+
+signed char FileMgr::existsFile(const char *ipath, const char *ifileName)
+{
+ int len = strlen(ipath) + ((ifileName)?strlen(ifileName):0) + 3;
+ char *ch;
+ char *path = new char [ len ];
+ strcpy(path, ipath);
+
+ if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
+ path[strlen(path)-1] = 0;
+
+ if (ifileName) {
+ ch = path + strlen(path);
+ sprintf(ch, "/%s", ifileName);
+ }
+ signed char retVal = !access(path, 04);
+ delete [] path;
+ return retVal;
+}
+
+
+signed char FileMgr::existsDir(const char *ipath, const char *idirName)
+{
+ char *ch;
+ int len = strlen(ipath) + ((idirName)?strlen(idirName):0) + 1;
+ if (idirName)
+ len += strlen(idirName);
+ char *path = new char [ len ];
+ strcpy(path, ipath);
+
+ if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
+ path[strlen(path)-1] = 0;
+
+ if (idirName) {
+ ch = path + strlen(path);
+ sprintf(ch, "/%s", idirName);
+ }
+ signed char retVal = !access(path, 04);
+ delete [] path;
+ return retVal;
+}