WvStreams
|
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Various useful file utilities. 00006 * 00007 */ 00008 #include "fileutils.h" 00009 #include "wvfile.h" 00010 #include "wvdiriter.h" 00011 #include <string.h> 00012 #include <sys/stat.h> 00013 #ifndef _WIN32 00014 #include <fnmatch.h> 00015 #endif 00016 #ifndef _MSC_VER 00017 #include <unistd.h> 00018 #include <utime.h> 00019 #endif 00020 00021 int wvmkdir(WvStringParm _dir, int create_mode) 00022 { 00023 #ifdef _WIN32 00024 return mkdir(_dir); 00025 #else 00026 return mkdir(_dir, create_mode); 00027 #endif 00028 } 00029 00030 int mkdirp(WvStringParm _dir, int create_mode) 00031 { 00032 if (!access(_dir, X_OK)) 00033 return 0; 00034 00035 // You're trying to make a nothing directory eh? 00036 assert(!!_dir); 00037 00038 WvString dir(_dir); 00039 char *p = dir.edit(); 00040 00041 while ((p = strchr(++p, '/'))) 00042 { 00043 *p = '\0'; 00044 if (access(dir, X_OK) && wvmkdir(dir, create_mode)) 00045 return -1; 00046 *p = '/'; 00047 } 00048 00049 // You're probably creating the directory to write to it? Maybe this should 00050 // look for R_OK&X_OK instead of X_OK&W_OK... 00051 return (access(dir, X_OK&W_OK) && wvmkdir(dir, create_mode)) ? -1 : 0; 00052 } 00053 00054 00055 void rm_rf(WvStringParm dir) 00056 { 00057 WvDirIter i(dir, false, false); // non-recursive, don't skip_mounts 00058 for (i.rewind(); i.next(); ) 00059 { 00060 if (i.isdir()) 00061 rm_rf(i->fullname); 00062 else 00063 ::unlink(i->fullname); 00064 } 00065 ::rmdir(dir); 00066 ::unlink(dir); 00067 } 00068 00069 00070 bool fcopy(WvStringParm src, WvStringParm dst) 00071 { 00072 struct stat buf; 00073 if (stat(src, &buf)) 00074 return false; 00075 00076 WvFile in(src, O_RDONLY); 00077 unlink(dst); 00078 00079 int oldmode = umask(0); 00080 WvFile out(dst, O_CREAT|O_WRONLY, buf.st_mode & 007777); 00081 umask(oldmode); 00082 00083 in.autoforward(out); 00084 while (in.isok() && out.isok()) 00085 { 00086 /* This used to be a select(0), but really, if select() returns 00087 * false, it'll keep doing it until the end of time. If you're 00088 * going into an infinite loop, better save the CPU a bit, since 00089 * you can still find out about it with strace... */ 00090 if (in.select(-1, true, false)) 00091 in.callback(); 00092 } 00093 if (!out.isok()) 00094 return false; 00095 00096 struct utimbuf utim; 00097 utim.actime = utim.modtime = buf.st_mtime; 00098 if (utime(dst, &utim)) 00099 return false; 00100 00101 return true; 00102 } 00103 00104 00105 bool fcopy(WvStringParm srcdir, WvStringParm dstdir, WvStringParm relname) 00106 { 00107 return fcopy(WvString("%s/%s", srcdir, relname), 00108 WvString("%s/%s", dstdir, relname)); 00109 } 00110 00111 00112 bool ftouch(WvStringParm file, time_t mtime) 00113 { 00114 if (!WvFile(file, O_WRONLY|O_CREAT).isok()) 00115 return false; 00116 00117 struct utimbuf *buf = NULL; 00118 if (mtime != 0) 00119 { 00120 buf = (struct utimbuf *)malloc(sizeof(struct utimbuf)); 00121 buf->actime = time(NULL); 00122 buf->modtime = mtime; 00123 } 00124 00125 if (utime(file, buf) == 0) 00126 { 00127 free(buf); 00128 return true; 00129 } 00130 00131 free(buf); 00132 return false; 00133 } 00134 00135 00136 // Reads the contents of a symlink. Returns WvString::null on error. 00137 WvString wvreadlink(WvStringParm path) 00138 { 00139 #ifdef _WIN32 00140 return WvString::null; // no such thing as a symlink on Windows 00141 #else 00142 WvString result; 00143 int size = 64; 00144 for (;;) 00145 { 00146 result.setsize(size); 00147 int readlink_result = readlink(path, result.edit(), size); 00148 if (readlink_result == -1) 00149 return WvString::null; 00150 if (readlink_result < size) 00151 { 00152 result.edit()[readlink_result] = '\0'; 00153 break; 00154 } 00155 size = 2*size; // increase buffer size 00156 } 00157 return result; 00158 #endif 00159 } 00160 00161 00162 bool samedate(WvStringParm file1, WvStringParm file2) 00163 { 00164 struct stat buf; 00165 struct stat buf2; 00166 00167 if (stat(file1, &buf) || stat(file2, &buf2)) 00168 return false; 00169 00170 if (buf.st_mtime == buf2.st_mtime || buf.st_ctime == buf2.st_ctime) 00171 return true; 00172 00173 return false; 00174 } 00175 00176 00177 bool samedate(WvStringParm dir1, WvStringParm dir2, WvStringParm relname) 00178 { 00179 return samedate(WvString("%s/%s", dir1, relname), 00180 WvString("%s/%s", dir2, relname)); 00181 } 00182 00183 00184 #ifndef _WIN32 00185 // runs fnmatch against everything in patterns. We also interpret 00186 // CVS-style '!' patterns, which makes us very fancy. 00187 bool wvfnmatch(WvStringList& patterns, WvStringParm name, int flags) 00188 { 00189 WvStringList::Iter i(patterns); 00190 bool match = false; 00191 00192 for (i.rewind(); i.next(); ) 00193 { 00194 // if we hit JUST a '!', reset any matches found so far. 00195 if (*i == "!") { 00196 match = false; 00197 continue; 00198 } 00199 00200 // if we hit something that starts with '!', we unmatch anything 00201 // found so far. 00202 if (i->cstr()[0] == '!') 00203 { 00204 if (!match) 00205 continue; // nothing to unmatch, so why try? 00206 if (fnmatch(*i+1, name, flags) == 0) // matches 00207 match = false; // unmatch it. 00208 } 00209 else 00210 { 00211 // just a straightforward matching case. 00212 if (fnmatch(*i, name, flags) == 0) // matches 00213 match = true; 00214 } 00215 } 00216 00217 return match; 00218 } 00219 #endif 00220 00221 #ifndef _WIN32 // file permissions are too screwy in win32 00222 int wvchmod(const char *path, mode_t mode) 00223 { 00224 struct stat st; 00225 if (lstat(path, &st) == -1) { 00226 return -1; 00227 } 00228 00229 int filedes = open(path, O_RDONLY); 00230 if (filedes == -1) { 00231 // if we're not running as root, this file/dir may have 0 00232 // perms and open() fails, so let's try again 00233 // 00234 // NOTE: This is not as secure as the proper way, since 00235 // it's conceivable that someone swaps out the dir/file 00236 // for a symlink between our check and the chmod() call 00237 // 00238 struct stat sst; 00239 if (getuid() != 0) 00240 if (stat(path, &sst) != -1) 00241 if (st.st_ino == sst.st_ino) 00242 return chmod(path, mode); 00243 00244 return -1; 00245 } 00246 00247 struct stat fst; 00248 if (fstat(filedes, &fst) == -1) { 00249 close(filedes); 00250 return -1; 00251 } 00252 00253 if (st.st_ino != fst.st_ino) { 00254 close(filedes); 00255 return -1; 00256 } 00257 00258 #ifndef _WIN32 00259 // we're definitely chmod'ing the open file here, which is good, 00260 // because the filename itself might have been moved around between 00261 // our stat'ing and chmod'ing it. 00262 int retval = fchmod(filedes, mode); 00263 #else 00264 // this is guaranteed to be the same file as filedes, because in 00265 // Windows, open files can't be changed on the filesystem (unlike in 00266 // Unix). 00267 int retval = chmod(path, mode); 00268 #endif 00269 close(filedes); 00270 00271 return retval; 00272 } 00273 #endif // !_WIN32 00274 00275 00276 FILE *wvtmpfile() 00277 { 00278 #ifndef _WIN32 // tmpfile() is really the best choice, when it works 00279 return tmpfile(); 00280 #else 00281 // in win32, tmpfile() creates files in c:\... 00282 // and that directory isn't always writable! Idiots. 00283 char *name = _tempnam("c:\\temp", "wvtmp"); 00284 FILE *f = fopen(name, "wb+"); 00285 free(name); 00286 return f; 00287 #endif 00288 } 00289 00290 00291 WvString wvtmpfilename(WvStringParm prefix) 00292 { 00293 #ifndef _WIN32 // tmpfile() is really the best choice, when it works 00294 WvString tmpname("/tmp/%sXXXXXX", prefix); 00295 int fd; 00296 if ((fd = mkstemp(tmpname.edit())) == (-1)) 00297 return WvString(); 00298 close(fd); 00299 #else 00300 WvString tmpname(_tempnam("c:\\temp", prefix.cstr())); 00301 int fd; 00302 fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, 0777); 00303 if (fd < 0) 00304 return WvString::null; // weird 00305 _close(fd); 00306 #endif 00307 00308 return tmpname; 00309 } 00310 00311 00312 mode_t get_umask() 00313 { 00314 mode_t rv = umask(0); 00315 umask(rv); 00316 00317 return rv; 00318 } 00319