Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

filemgr.cpp

00001 /******************************************************************************
00002  *  filemgr.cpp - implementation of class FileMgr used for pooling file
00003  *                                      handles
00004  *
00005  * $Id: filemgr_8cpp-source.html,v 1.3 2002/06/20 20:23:08 mgruner Exp $
00006  *
00007  * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
00008  *      CrossWire Bible Society
00009  *      P. O. Box 2528
00010  *      Tempe, AZ  85280-2528
00011  *
00012  * This program is free software; you can redistribute it and/or modify it
00013  * under the terms of the GNU General Public License as published by the
00014  * Free Software Foundation version 2.
00015  *
00016  * This program is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * General Public License for more details.
00020  *
00021  */
00022 
00023 #include <filemgr.h>
00024 #include <utilstr.h>
00025 
00026 #include <dirent.h>
00027 #include <fcntl.h>
00028 #include <sys/stat.h>
00029 #include <sys/types.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #ifndef __GNUC__
00033 #include <io.h>
00034 #else
00035 #include <unistd.h>
00036 #endif
00037 
00038 // ---------------- statics -----------------
00039 FileMgr FileMgr::systemFileMgr;
00040 
00041 // --------------- end statics --------------
00042 
00043 
00044 FileDesc::FileDesc(FileMgr *parent, char *path, int mode, int perms, bool tryDowngrade) {
00045         this->parent = parent;
00046         this->path = 0;
00047         stdstr(&this->path, path);
00048         this->mode = mode;
00049         this->perms = perms;
00050         this->tryDowngrade = tryDowngrade;
00051         offset = 0;
00052         fd = -77;
00053 }
00054 
00055 
00056 FileDesc::~FileDesc() {
00057         if (fd > 0)
00058                 close(fd);
00059                 
00060         if (path)
00061                 delete [] path;
00062 }
00063 
00064 
00065 int FileDesc::getFd() {
00066         if (fd == -77)
00067                 fd = parent->sysOpen(this);
00068         return fd;
00069 }
00070 
00071 
00072 FileMgr::FileMgr(int maxFiles) {
00073         this->maxFiles = maxFiles;              // must be at least 2
00074         files = 0;
00075 }
00076 
00077 
00078 FileMgr::~FileMgr() {
00079         FileDesc *tmp;
00080         
00081         while(files) {
00082                 tmp = files->next;
00083                 delete files;
00084                 files = tmp;
00085         }
00086 }
00087 
00088 
00089 FileDesc *FileMgr::open(char *path, int mode, bool tryDowngrade) {
00090         return open(path, mode, S_IREAD | S_IWRITE, tryDowngrade);
00091 }
00092 
00093 FileDesc *FileMgr::open(char *path, int mode, int perms, bool tryDowngrade) {
00094         FileDesc **tmp, *tmp2;
00095         
00096         for (tmp = &files; *tmp; tmp = &((*tmp)->next)) {
00097                 if ((*tmp)->fd < 0)             // insert as first non-system_open file
00098                         break;
00099         }
00100 
00101         tmp2 = new FileDesc(this, path, mode, perms, tryDowngrade);
00102         tmp2->next = *tmp;
00103         *tmp = tmp2;
00104         
00105         return tmp2;
00106 }
00107 
00108 
00109 void FileMgr::close(FileDesc *file) {
00110         FileDesc **loop;
00111         
00112         for (loop = &files; *loop; loop = &((*loop)->next)) {
00113                 if (*loop == file) {
00114                         *loop = (*loop)->next;
00115                         delete file;
00116                         break;
00117                 }
00118         }
00119 }
00120 
00121 
00122 // to truncate a file at its current position
00123 // leaving byte at current possition intact
00124 // deleting everything afterward.
00125 signed char FileMgr::trunc(FileDesc *file) {
00126 
00127         static const char *writeTest = "x";
00128         long size = lseek(file->getFd(), 1, SEEK_CUR);
00129         char nibble [ 32767 ];
00130         bool writable = write(file->getFd(), writeTest, 1);
00131         int bytes = 0;
00132 
00133         if (writable) {
00134                 // get tmpfilename
00135                 char *buf = new char [ strlen(file->path) + 10 ];
00136                 int i;
00137                 for (i = 0; i < 9999; i++) {
00138                         sprintf(buf, "%stmp%.4d", file->path, i);
00139                         if (!existsFile(buf))
00140                                 break;
00141                 }
00142                 if (i == 9999)
00143                         return -2;
00144 
00145                 int fd = ::open(buf, O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
00146                 if (fd < 0)
00147                         return -3;
00148         
00149                 lseek(file->getFd(), 0, SEEK_SET);
00150                 while (size > 0) {
00151                         bytes = read(file->getFd(), nibble, 32767);
00152                         write(fd, nibble, (bytes < size)?bytes:size);
00153                         size -= bytes;
00154                 }
00155                 // zero out the file
00156                 ::close(file->fd);
00157                 file->fd = ::open(file->path, O_TRUNC, S_IREAD|S_IWRITE);
00158                 ::close(file->fd);
00159                 file->fd = -77; // force file open by filemgr
00160                 // copy tmp file back (dumb, but must preserve file permissions)
00161                 lseek(fd, 0, SEEK_SET);
00162                 do {
00163                         bytes = read(fd, nibble, 32767);
00164                         write(file->getFd(), nibble, bytes);
00165                 } while (bytes == 32767);
00166                 
00167                 ::close(fd);
00168                 ::close(file->fd);
00169                 unlink(buf);            // remove our tmp file
00170                 file->fd = -77; // causes file to be swapped out forcing open on next call to getFd()
00171         }
00172         else { // put offset back and return failure
00173                 lseek(file->getFd(), -1, SEEK_CUR);
00174                 return -1;
00175         }
00176         return 0;
00177 }
00178 
00179 
00180 int FileMgr::sysOpen(FileDesc *file) {
00181         FileDesc **loop;
00182         int openCount = 1;              // because we are presently opening 1 file, and we need to be sure to close files to accomodate, if necessary
00183         
00184         for (loop = &files; *loop; loop = &((*loop)->next)) {
00185 
00186                 if ((*loop)->fd > 0) {
00187                         if (++openCount > maxFiles) {
00188                                 (*loop)->offset = lseek((*loop)->fd, 0, SEEK_CUR);
00189                                 ::close((*loop)->fd);
00190                                 (*loop)->fd = -77;
00191                         }
00192                 }
00193 
00194                 if (*loop == file) {
00195                         if (*loop != files) {
00196                                 *loop = (*loop)->next;
00197                                 file->next = files;
00198                                 files = file;
00199                         }
00200                         if ((!access(file->path, 04)) || ((file->mode & O_CREAT) == O_CREAT)) { // check for at least file exists / read access before we try to open
00201                                 char tries = (((file->mode & O_RDWR) == O_RDWR) && (file->tryDowngrade)) ? 2 : 1;  // try read/write if possible
00202                                 for (int i = 0; i < tries; i++) {
00203                                         if (i > 0) {
00204                                                 file->mode = (file->mode & ~O_RDWR);    // remove write access
00205                                                 file->mode = (file->mode | O_RDONLY);// add read access
00206                                         }
00207                                         file->fd = ::open(file->path, file->mode, file->perms);
00208 
00209                                         if (file->fd >= 0)
00210                                                 break;
00211                                 }
00212 
00213                                 if (file->fd >= 0)
00214                                         lseek(file->fd, file->offset, SEEK_SET);
00215                         }
00216                         else file->fd = -1;
00217                         if (!*loop)
00218                                 break;
00219                 }
00220         }
00221         return file->fd;
00222 }
00223 
00224 
00225 signed char FileMgr::existsFile(const char *ipath, const char *ifileName)
00226 {
00227         int len = strlen(ipath) + ((ifileName)?strlen(ifileName):0) + 3;
00228         char *ch;
00229         char *path = new char [ len ];
00230         strcpy(path, ipath);
00231         
00232         if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
00233                 path[strlen(path)-1] = 0;
00234         
00235         if (ifileName) {
00236                 ch = path + strlen(path);
00237                 sprintf(ch, "/%s", ifileName);
00238         }
00239         signed char retVal = !access(path, 04);
00240         delete [] path;
00241         return retVal;
00242 }
00243 
00244 
00245 signed char FileMgr::existsDir(const char *ipath, const char *idirName)
00246 {
00247         char *ch;
00248         int len = strlen(ipath) + ((idirName)?strlen(idirName):0) + 1;
00249         if (idirName)
00250                 len +=  strlen(idirName);
00251         char *path = new char [ len ];
00252         strcpy(path, ipath);
00253         
00254         if ((path[strlen(path)-1] == '\\') || (path[strlen(path)-1] == '/'))
00255                 path[strlen(path)-1] = 0;
00256         
00257         if (idirName) {
00258                 ch = path + strlen(path);
00259                 sprintf(ch, "/%s", idirName);
00260         }
00261         signed char retVal = !access(path, 04);
00262      delete [] path;
00263      return retVal;
00264 }

Generated on Thu Jun 20 22:12:59 2002 for The Sword Project by doxygen1.2.15