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