fileutils.cc

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 bool samedate(WvStringParm file1, WvStringParm file2)
00137 {
00138     struct stat buf;
00139     struct stat buf2;
00140 
00141     if (stat(file1, &buf) || stat(file2, &buf2))
00142         return false;
00143 
00144     if (buf.st_mtime == buf2.st_mtime || buf.st_ctime == buf2.st_ctime)
00145         return true;
00146 
00147     return false;
00148 }
00149 
00150 
00151 bool samedate(WvStringParm dir1, WvStringParm dir2, WvStringParm relname)
00152 {
00153     return samedate(WvString("%s/%s", dir1, relname),
00154         WvString("%s/%s", dir2, relname));
00155 }
00156 
00157 
00158 #ifndef _WIN32
00159 // runs fnmatch against everything in patterns.  We also interpret 
00160 // CVS-style '!' patterns, which makes us very fancy.
00161 bool wvfnmatch(WvStringList& patterns, WvStringParm name, int flags)
00162 {
00163     WvStringList::Iter i(patterns);
00164     bool match = false;
00165 
00166     for (i.rewind(); i.next(); )
00167     {
00168         // if we hit JUST a '!', reset any matches found so far.
00169         if (*i == "!") {
00170             match = false;
00171             continue;
00172         }
00173 
00174         // if we hit something that starts with '!', we unmatch anything
00175         // found so far.
00176         if (i->cstr()[0] == '!')
00177         {
00178             if (!match)
00179                 continue;   // nothing to unmatch, so why try?
00180             if (fnmatch(*i+1, name, flags) == 0)    // matches
00181                 match = false;                      // unmatch it.
00182         }
00183         else
00184         {
00185             // just a straightforward matching case.
00186             if (fnmatch(*i, name, flags) == 0)  // matches
00187                 match = true;
00188         }
00189     }
00190 
00191     return match;
00192 }
00193 #endif
00194 
00195 #ifndef _WIN32 // file permissions are too screwy in win32
00196 int wvchmod(const char *path, mode_t mode)
00197 {
00198     struct stat st;
00199     if (lstat(path, &st) == -1) {
00200         return -1;
00201     }
00202 
00203     int filedes = open(path, O_RDONLY);
00204     if (filedes == -1) {
00205         // if we're not running as root, this file/dir may have 0
00206         // perms and open() fails, so let's try again
00207         //
00208         // NOTE: This is not as secure as the proper way, since
00209         // it's conceivable that someone swaps out the dir/file
00210         // for a symlink between our check and the chmod() call
00211         //
00212         struct stat sst;
00213         if (getuid() != 0)
00214             if (stat(path, &sst) != -1)
00215                 if (st.st_ino == sst.st_ino)
00216                     return chmod(path, mode);
00217         
00218         return -1;
00219     }
00220 
00221     struct stat fst;
00222     if (fstat(filedes, &fst) == -1) {
00223         close(filedes);
00224         return -1;
00225     }
00226 
00227     if (st.st_ino != fst.st_ino) {
00228         close(filedes);
00229         return -1;
00230     }
00231 
00232 #ifndef _WIN32
00233     // we're definitely chmod'ing the open file here, which is good,
00234     // because the filename itself might have been moved around between
00235     // our stat'ing and chmod'ing it.
00236     int retval = fchmod(filedes, mode);
00237 #else
00238     // this is guaranteed to be the same file as filedes, because in
00239     // Windows, open files can't be changed on the filesystem (unlike in
00240     // Unix).
00241     int retval = chmod(path, mode);
00242 #endif
00243     close(filedes);
00244 
00245     return retval;
00246 }
00247 #endif // !_WIN32
00248 
00249 
00250 FILE *wvtmpfile()
00251 {
00252 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
00253     return tmpfile();
00254 #else
00255     // in win32, tmpfile() creates files in c:\...
00256     // and that directory isn't always writable!  Idiots.
00257     char *name = _tempnam("c:\\temp", "wvtmp");
00258     FILE *f = fopen(name, "wb+");
00259     free(name);
00260     return f;
00261 #endif
00262 }
00263 
00264 
00265 WvString wvtmpfilename(WvStringParm prefix)
00266 {
00267 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
00268     WvString tmpname("/tmp/%sXXXXXX", prefix);
00269     int fd;
00270     if ((fd = mkstemp(tmpname.edit())) == (-1))
00271         return WvString();    
00272     close(fd);
00273 #else
00274     WvString tmpname(_tempnam("c:\\temp", prefix.cstr()));
00275     int fd;
00276     fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, 0777);
00277     if (fd < 0)
00278         return WvString::null; // weird
00279     _close(fd);
00280 #endif
00281 
00282     return tmpname;
00283 }
00284 
00285 
00286 mode_t get_umask()
00287 {
00288     mode_t rv = umask(0);
00289     umask(rv);
00290 
00291     return rv;
00292 }
00293 
00294 
00295 void wvdelay(int msec_delay)
00296 {
00297 #ifdef _WIN32
00298     Sleep(msec_delay);
00299 #else
00300     usleep(msec_delay * 1000);
00301 #endif
00302 }

Generated on Thu Jan 24 16:50:54 2008 for WvStreams by  doxygen 1.5.4