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 ftouch(WvStringParm file, time_t mtime)
00110 {
00111     if (!WvFile(file, O_WRONLY|O_CREAT).isok())
00112         return false;
00113 
00114     struct utimbuf *buf = NULL;
00115     if (mtime != 0)
00116     {
00117         buf = (struct utimbuf *)malloc(sizeof(struct utimbuf));
00118         buf->actime = time(NULL);
00119         buf->modtime = mtime;
00120     }
00121 
00122     if (utime(file, buf) == 0)
00123     {
00124         free(buf);
00125         return true;
00126     }
00127 
00128     free(buf);
00129     return false;
00130 }
00131 
00132 
00133 bool samedate(WvStringParm file1, WvStringParm file2)
00134 {
00135     struct stat buf;
00136     struct stat buf2;
00137 
00138     if (stat(file1, &buf) || stat(file2, &buf2))
00139         return false;
00140 
00141     if (buf.st_mtime == buf2.st_mtime || buf.st_ctime == buf2.st_ctime)
00142         return true;
00143 
00144     return false;
00145 }
00146 
00147 
00148 bool samedate(WvStringParm dir1, WvStringParm dir2, WvStringParm relname)
00149 {
00150     return samedate(WvString("%s/%s", dir1, relname),
00151         WvString("%s/%s", dir2, relname));
00152 }
00153 
00154 
00155 #ifndef _WIN32
00156 // runs fnmatch against everything in patterns.  We also interpret 
00157 // CVS-style '!' patterns, which makes us very fancy.
00158 bool wvfnmatch(WvStringList& patterns, WvStringParm name, int flags)
00159 {
00160     WvStringList::Iter i(patterns);
00161     bool match = false;
00162 
00163     for (i.rewind(); i.next(); )
00164     {
00165         // if we hit JUST a '!', reset any matches found so far.
00166         if (*i == "!") {
00167             match = false;
00168             continue;
00169         }
00170 
00171         // if we hit something that starts with '!', we unmatch anything
00172         // found so far.
00173         if (i->cstr()[0] == '!')
00174         {
00175             if (!match)
00176                 continue;   // nothing to unmatch, so why try?
00177             if (fnmatch(*i+1, name, flags) == 0)    // matches
00178                 match = false;                      // unmatch it.
00179         }
00180         else
00181         {
00182             // just a straightforward matching case.
00183             if (fnmatch(*i, name, flags) == 0)  // matches
00184                 match = true;
00185         }
00186     }
00187 
00188     return match;
00189 }
00190 
00191 // Only chmod a given file or dir, do not follow symlinks
00192 int wvchmod(const char *path, mode_t mode)
00193 {
00194     struct stat st;
00195     if (lstat(path, &st) == -1) {
00196         return -1;
00197     }
00198 
00199     int filedes = open(path, O_RDONLY);
00200     if (filedes == -1) {
00201         // if we're not running as root, this file/dir may have 0
00202         // perms and open() fails, so let's try again
00203         //
00204         // NOTE: This is not as secure as the proper way, since
00205         // it's conceivable that someone swaps out the dir/file
00206         // for a symlink between our check and the chmod() call
00207         //
00208         struct stat sst;
00209         if (getuid() != 0)
00210             if (stat(path, &sst) != -1)
00211                 if (st.st_ino == sst.st_ino)
00212                     return chmod(path, mode);
00213         
00214         return -1;
00215     }
00216 
00217     struct stat fst;
00218     if (fstat(filedes, &fst) == -1) {
00219         close(filedes);
00220         return -1;
00221     }
00222 
00223     if (st.st_ino != fst.st_ino) {
00224         close(filedes);
00225         return -1;
00226     }
00227 
00228     int retval = fchmod(filedes, mode);
00229     close(filedes);
00230 
00231     return retval;
00232 }
00233 #endif
00234 
00235 
00236 FILE *wvtmpfile()
00237 {
00238 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
00239     return tmpfile();
00240 #else
00241     // in win32, tmpfile() creates files in c:\...
00242     // and that directory isn't always writable!  Idiots.
00243     char *name = _tempnam("c:\\temp", "wvtmp");
00244     FILE *f = fopen(name, "wb+");
00245     free(name);
00246     return f;
00247 #endif
00248 }
00249 
00250 
00251 WvString wvtmpfilename(WvStringParm prefix)
00252 {
00253 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
00254     WvString tmpname("/tmp/%sXXXXXX", prefix);
00255     int fd;
00256     if ((fd = mkstemp(tmpname.edit())) == (-1))
00257         return WvString();    
00258     close(fd);
00259 #else
00260     WvString tmpname(_tempnam("c:\\temp", prefix.cstr()));
00261 #endif
00262 
00263     return tmpname;
00264 }
00265 
00266 
00267 mode_t get_umask()
00268 {
00269     mode_t rv = umask(0);
00270     umask(rv);
00271 
00272     return rv;
00273 }
00274 

Generated on Fri Oct 5 18:20:25 2007 for WvStreams by  doxygen 1.5.3