Make WvStreams compile with gcc 4.4.
[wvstreams.git] / streams / fileutils.cc
blob2ce7b120eb99e4a998c5fafaffd840a97f8d8520
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Various useful file utilities.
7 */
8 #include "fileutils.h"
9 #include "wvfile.h"
10 #include "wvdiriter.h"
11 #include <string.h>
12 #include <sys/stat.h>
13 #ifndef _WIN32
14 #include <fnmatch.h>
15 #endif
16 #ifndef _MSC_VER
17 #include <unistd.h>
18 #include <utime.h>
19 #endif
21 int wvmkdir(WvStringParm _dir, int create_mode)
23 #ifdef _WIN32
24 return mkdir(_dir);
25 #else
26 return mkdir(_dir, create_mode);
27 #endif
30 int mkdirp(WvStringParm _dir, int create_mode)
32 if (!access(_dir, X_OK))
33 return 0;
35 // You're trying to make a nothing directory eh?
36 assert(!!_dir);
38 WvString dir(_dir);
39 char *p = dir.edit();
41 while ((p = strchr(++p, '/')))
43 *p = '\0';
44 if (access(dir, X_OK) && wvmkdir(dir, create_mode))
45 return -1;
46 *p = '/';
49 // You're probably creating the directory to write to it? Maybe this should
50 // look for R_OK&X_OK instead of X_OK&W_OK...
51 return (access(dir, X_OK&W_OK) && wvmkdir(dir, create_mode)) ? -1 : 0;
55 void rm_rf(WvStringParm dir)
57 WvDirIter i(dir, false, false); // non-recursive, don't skip_mounts
58 for (i.rewind(); i.next(); )
60 if (i.isdir())
61 rm_rf(i->fullname);
62 else
63 ::unlink(i->fullname);
65 ::rmdir(dir);
66 ::unlink(dir);
70 bool fcopy(WvStringParm src, WvStringParm dst)
72 struct stat buf;
73 if (stat(src, &buf))
74 return false;
76 WvFile in(src, O_RDONLY);
77 unlink(dst);
79 int oldmode = umask(0);
80 WvFile out(dst, O_CREAT|O_WRONLY, buf.st_mode & 007777);
81 umask(oldmode);
83 in.autoforward(out);
84 while (in.isok() && out.isok())
86 /* This used to be a select(0), but really, if select() returns
87 * false, it'll keep doing it until the end of time. If you're
88 * going into an infinite loop, better save the CPU a bit, since
89 * you can still find out about it with strace... */
90 if (in.select(-1, true, false))
91 in.callback();
93 if (!out.isok())
94 return false;
96 struct utimbuf utim;
97 utim.actime = utim.modtime = buf.st_mtime;
98 if (utime(dst, &utim))
99 return false;
101 return true;
105 bool fcopy(WvStringParm srcdir, WvStringParm dstdir, WvStringParm relname)
107 return fcopy(WvString("%s/%s", srcdir, relname),
108 WvString("%s/%s", dstdir, relname));
112 bool ftouch(WvStringParm file, time_t mtime)
114 if (!WvFile(file, O_WRONLY|O_CREAT).isok())
115 return false;
117 struct utimbuf *buf = NULL;
118 if (mtime != 0)
120 buf = (struct utimbuf *)malloc(sizeof(struct utimbuf));
121 buf->actime = time(NULL);
122 buf->modtime = mtime;
125 if (utime(file, buf) == 0)
127 free(buf);
128 return true;
131 free(buf);
132 return false;
136 // Reads the contents of a symlink. Returns WvString::null on error.
137 WvString wvreadlink(WvStringParm path)
139 #ifdef _WIN32
140 return WvString::null; // no such thing as a symlink on Windows
141 #else
142 WvString result;
143 int size = 64;
144 for (;;)
146 result.setsize(size);
147 int readlink_result = readlink(path, result.edit(), size);
148 if (readlink_result == -1)
149 return WvString::null;
150 if (readlink_result < size)
152 result.edit()[readlink_result] = '\0';
153 break;
155 size = 2*size; // increase buffer size
157 return result;
158 #endif
162 bool samedate(WvStringParm file1, WvStringParm file2)
164 struct stat buf;
165 struct stat buf2;
167 if (stat(file1, &buf) || stat(file2, &buf2))
168 return false;
170 if (buf.st_mtime == buf2.st_mtime || buf.st_ctime == buf2.st_ctime)
171 return true;
173 return false;
177 bool samedate(WvStringParm dir1, WvStringParm dir2, WvStringParm relname)
179 return samedate(WvString("%s/%s", dir1, relname),
180 WvString("%s/%s", dir2, relname));
184 #ifndef _WIN32
185 // runs fnmatch against everything in patterns. We also interpret
186 // CVS-style '!' patterns, which makes us very fancy.
187 bool wvfnmatch(WvStringList& patterns, WvStringParm name, int flags)
189 WvStringList::Iter i(patterns);
190 bool match = false;
192 for (i.rewind(); i.next(); )
194 // if we hit JUST a '!', reset any matches found so far.
195 if (*i == "!") {
196 match = false;
197 continue;
200 // if we hit something that starts with '!', we unmatch anything
201 // found so far.
202 if (i->cstr()[0] == '!')
204 if (!match)
205 continue; // nothing to unmatch, so why try?
206 if (fnmatch(*i+1, name, flags) == 0) // matches
207 match = false; // unmatch it.
209 else
211 // just a straightforward matching case.
212 if (fnmatch(*i, name, flags) == 0) // matches
213 match = true;
217 return match;
219 #endif
221 #ifndef _WIN32 // file permissions are too screwy in win32
222 int wvchmod(const char *path, mode_t mode)
224 struct stat st;
225 if (lstat(path, &st) == -1) {
226 return -1;
229 int filedes = open(path, O_RDONLY);
230 if (filedes == -1) {
231 // if we're not running as root, this file/dir may have 0
232 // perms and open() fails, so let's try again
234 // NOTE: This is not as secure as the proper way, since
235 // it's conceivable that someone swaps out the dir/file
236 // for a symlink between our check and the chmod() call
238 struct stat sst;
239 if (getuid() != 0)
240 if (stat(path, &sst) != -1)
241 if (st.st_ino == sst.st_ino)
242 return chmod(path, mode);
244 return -1;
247 struct stat fst;
248 if (fstat(filedes, &fst) == -1) {
249 close(filedes);
250 return -1;
253 if (st.st_ino != fst.st_ino) {
254 close(filedes);
255 return -1;
258 #ifndef _WIN32
259 // we're definitely chmod'ing the open file here, which is good,
260 // because the filename itself might have been moved around between
261 // our stat'ing and chmod'ing it.
262 int retval = fchmod(filedes, mode);
263 #else
264 // this is guaranteed to be the same file as filedes, because in
265 // Windows, open files can't be changed on the filesystem (unlike in
266 // Unix).
267 int retval = chmod(path, mode);
268 #endif
269 close(filedes);
271 return retval;
273 #endif // !_WIN32
276 FILE *wvtmpfile()
278 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
279 return tmpfile();
280 #else
281 // in win32, tmpfile() creates files in c:\...
282 // and that directory isn't always writable! Idiots.
283 char *name = _tempnam("c:\\temp", "wvtmp");
284 FILE *f = fopen(name, "wb+");
285 free(name);
286 return f;
287 #endif
291 WvString wvtmpfilename(WvStringParm prefix)
293 #ifndef _WIN32 // tmpfile() is really the best choice, when it works
294 WvString tmpname("/tmp/%sXXXXXX", prefix);
295 int fd;
296 if ((fd = mkstemp(tmpname.edit())) == (-1))
297 return WvString();
298 close(fd);
299 #else
300 WvString tmpname(_tempnam("c:\\temp", prefix.cstr()));
301 int fd;
302 fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, 0777);
303 if (fd < 0)
304 return WvString::null; // weird
305 _close(fd);
306 #endif
308 return tmpname;
312 mode_t get_umask()
314 mode_t rv = umask(0);
315 umask(rv);
317 return rv;