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 <unistd.h>
00013 #include <sys/stat.h>
00014 #include <utime.h>
00015 #ifndef _WIN32
00016 #include <fnmatch.h>
00017 #endif
00018 
00019 bool mkdirp(WvStringParm _dir, int create_mode)
00020 {
00021     if (!access(_dir, X_OK))
00022         return true;
00023 
00024     // You're trying to make a nothing directory eh?
00025     assert(!!_dir);
00026 
00027     WvString dir(_dir);
00028     char *p = dir.edit();
00029 
00030     while ((p = strchr(++p, '/')))
00031     {
00032         *p = '\0';
00033 #ifndef _WIN32
00034         if (access(dir.cstr(), X_OK) && mkdir(dir.cstr(), create_mode))
00035 #else
00036         if (access(dir.cstr(), X_OK) && mkdir(dir.cstr()))
00037 #endif
00038             return false;
00039         *p = '/';
00040     }
00041 
00042     // You're probably creating the directory to write to it? Maybe this should
00043     // look for R_OK&X_OK instead of X_OK&W_OK...
00044 #ifndef _WIN32
00045     return  !(access(dir.cstr(), X_OK&W_OK) && mkdir(dir.cstr(), create_mode));
00046 #else
00047     return  !(access(dir.cstr(), X_OK&W_OK) && mkdir(dir.cstr()));
00048 #endif
00049 }
00050 
00051 
00052 void rm_rf(WvStringParm dir)
00053 {
00054     WvDirIter i(dir, false, false); // non-recursive, don't skip_mounts
00055     for (i.rewind(); i.next(); )
00056     {
00057         if (i.isdir())
00058             rm_rf(i->fullname);
00059         else
00060             ::unlink(i->fullname);
00061     }
00062     ::rmdir(dir);
00063     ::unlink(dir);
00064 }
00065 
00066 
00067 bool fcopy(WvStringParm src, WvStringParm dst)
00068 {
00069     struct stat buf;
00070     if (stat(src, &buf))
00071         return false;
00072 
00073     WvFile in(src, O_RDONLY);
00074     unlink(dst);
00075 
00076     int oldmode = umask(0);
00077     WvFile out(dst, O_CREAT|O_WRONLY, buf.st_mode & 007777);
00078     umask(oldmode);
00079 
00080     in.autoforward(out);
00081     while (in.isok() && out.isok())
00082     {
00083         /* This used to be a select(0), but really, if select() returns
00084          * false, it'll keep doing it until the end of time. If you're
00085          * going into an infinite loop, better save the CPU a bit, since
00086          * you can still find out about it with strace... */
00087         if (in.select(-1, true, false))
00088             in.callback();
00089     }
00090     if (!out.isok())
00091         return false;
00092 
00093     struct utimbuf utim;
00094     utim.actime = utim.modtime = buf.st_mtime;
00095     if (utime(dst, &utim))
00096         return false;
00097 
00098     return true;
00099 }
00100 
00101 
00102 bool fcopy(WvStringParm srcdir, WvStringParm dstdir, WvStringParm relname)
00103 {
00104     return fcopy(WvString("%s/%s", srcdir, relname),
00105         WvString("%s/%s", dstdir, relname));
00106 }
00107 
00108 
00109 bool samedate(WvStringParm file1, WvStringParm file2)
00110 {
00111     struct stat buf;
00112     struct stat buf2;
00113 
00114     if (stat(file1, &buf) || stat(file2, &buf2))
00115         return false;
00116 
00117     if (buf.st_mtime == buf2.st_mtime || buf.st_ctime == buf2.st_ctime)
00118         return true;
00119 
00120     return false;
00121 }
00122 
00123 
00124 bool samedate(WvStringParm dir1, WvStringParm dir2, WvStringParm relname)
00125 {
00126     return samedate(WvString("%s/%s", dir1, relname),
00127         WvString("%s/%s", dir2, relname));
00128 }
00129 
00130 
00131 #ifndef _WIN32
00132 // runs fnmatch against everything in patterns.  We also interpret 
00133 // CVS-style '!' patterns, which makes us very fancy.
00134 bool wvfnmatch(WvStringList& patterns, WvStringParm name, int flags)
00135 {
00136     WvStringList::Iter i(patterns);
00137     bool match = false;
00138 
00139     for (i.rewind(); i.next(); )
00140     {
00141         // if we hit JUST a '!', reset any matches found so far.
00142         if (*i == "!") {
00143             match = false;
00144             continue;
00145         }
00146 
00147         // if we hit something that starts with '!', we unmatch anything
00148         // found so far.
00149         if (i->cstr()[0] == '!')
00150         {
00151             if (!match)
00152                 continue;   // nothing to unmatch, so why try?
00153             if (fnmatch(*i+1, name, flags) == 0)    // matches
00154                 match = false;                      // unmatch it.
00155         }
00156         else
00157         {
00158             // just a straightforward matching case.
00159             if (fnmatch(*i, name, flags) == 0)  // matches
00160                 match = true;
00161         }
00162     }
00163 
00164     return match;
00165 }
00166 
00167 // Only chmod a given file or dir, do not follow symlinks
00168 int wvchmod(const char *path, mode_t mode)
00169 {
00170     struct stat st;
00171     if (lstat(path, &st) == -1) {
00172         return -1;
00173     }
00174 
00175     int filedes = open(path, O_RDONLY);
00176     if (filedes == -1) {
00177         // if we're not running as root, this file/dir may have 0
00178         // perms and open() fails, so let's try again
00179         //
00180         // NOTE: This is not as secure as the proper way, since
00181         // it's conceivable that someone swaps out the dir/file
00182         // for a symlink between our check and the chmod() call
00183         //
00184         struct stat sst;
00185         if (getuid() != 0)
00186             if (stat(path, &sst) != -1)
00187                 if (st.st_ino == sst.st_ino)
00188                     return chmod(path, mode);
00189         
00190         return -1;
00191     }
00192 
00193     struct stat fst;
00194     if (fstat(filedes, &fst) == -1) {
00195         close(filedes);
00196         return -1;
00197     }
00198 
00199     if (st.st_ino != fst.st_ino) {
00200         close(filedes);
00201         return -1;
00202     }
00203 
00204     int retval = fchmod(filedes, mode);
00205     close(filedes);
00206 
00207     return retval;
00208 }
00209 #endif
00210 
00211 
00212 FILE *wvtmpfile()
00213 {
00214 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
00215     return tmpfile();
00216 #else
00217     // in win32, tmpfile() creates files in c:\...
00218     // and that directory isn't always writable!  Idiots.
00219     char *name = _tempnam("c:\\temp", "wvtmp");
00220     FILE *f = fopen(name, "wb+");
00221     free(name);
00222     return f;
00223 #endif
00224 }
00225 
00226 
00227 WvString wvtmpfilename(WvStringParm prefix)
00228 {
00229 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
00230     WvString tmpname("/tmp/%sXXXXXX", prefix);
00231     int fd;
00232     if ((fd = mkstemp(tmpname.edit())) == (-1))
00233         return WvString();    
00234     close(fd);
00235 #else
00236     WvString tmpname(_tempnam("c:\\temp", prefix.cstr()));
00237 #endif
00238 
00239     return tmpname;
00240 }
00241 
00242 
00243 mode_t get_umask()
00244 {
00245     mode_t rv = umask(0);
00246     umask(rv);
00247 
00248     return rv;
00249 }
00250 

Generated on Thu May 25 21:51:01 2006 for WvStreams by  doxygen 1.4.6