/// // Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING /// #include "filesys.h" #include "stringutil.h" #include "os.h" #include #include #include #include #include "defines.h" #include #ifndef HAVE_MKDTEMP #include #endif using std::string; ClibException::ClibException(const string& msg) : runtime_error(msg + ": " + strerror(errno)) {} bool exists(const string& filename) { return access(filename.c_str(), F_OK) == 0; } bool access(const string& filename, int mode) { int c_mode = 0; if(mode & std::ios::in) c_mode |= R_OK; if(mode & std::ios::out) c_mode |= W_OK; int result = access(filename.c_str(), c_mode); return result == 0; } bool executable(const std::string& filename) { return access(filename.c_str(), X_OK) == 0; } time_t modified(const std::string& filename) { struct stat buf; if(stat(filename.c_str(), &buf) == 0) // returns 0 on success, -1 otherwise return buf.st_mtime; else throw ClibException("Failed to stat(2) \"" + filename + '"'); } string suffix(const string& filename) { const string::size_type pos = filename.find_last_of('.'); if(pos == string::npos) return string(); return filename.substr(pos+1); } string no_suffix(const string& filename) { const string::size_type pos = filename.find_last_of('.'); if(pos == string::npos) return string(); return filename.substr(0, pos); } string basename(const string& filename) { const string::size_type pos = filename.find_last_of('/'); if(pos == string::npos) return filename; return filename.substr(pos+1); } string path(const string& filename) { const string::size_type pos = filename.find_last_of('/'); if(pos == string::npos) return "./"; return filename.substr(0, pos+1); } string expand_path(const string& filename) { unsigned int path_max; // from man 3 realpath: #ifdef PATH_MAX path_max = PATH_MAX; #else // pathconf doesn't seem to like empty strings path_max = pathconf (filename.empty()?".":filename.c_str(), _PC_PATH_MAX); if (path_max <= 0) path_max = 4096; #endif std::auto_ptr resolved_path(new char[path_max]); if(realpath(filename.empty()?".":filename.c_str(), resolved_path.get())) return resolved_path.get(); else throw ClibException("Failed to resolve \"" + filename + '"'); } string relative_path(const string& start_path, const string& filename) { if(start_path.empty() || !starts_with(filename, start_path)) return filename; int i = start_path.length(); if(filename[i]=='/') i++; return filename.substr(i); } void unlink(const std::string& filename) { if(::unlink(filename.c_str()) != 0) throw ClibException("Failed to unlink \"" + filename + '"'); } void rmdir(const std::string& dirname) { if(::rmdir(dirname.c_str()) != 0) throw ClibException("Failed to rmdir \"" + dirname + '"'); } std::string mkdtemp(const std::string& tmpl_name) { if(tmpl_name.empty()) throw std::invalid_argument("Template for mkdtemp must be non-empty"); string name; if(tmpl_name[0] == '/') name = tmpl_name; else { // A non-relative name, put in $TMPDIR std::string tmpdir = os::get_env("TMPDIR"); if(tmpdir.empty()) name = "/tmp/" + tmpl_name; else if(*tmpdir.end() == '/') name = tmpdir + tmpl_name; else name = tmpdir + '/' + tmpl_name; } #ifdef HAVE_MKDTEMP char* actual = ::mkdtemp(strcpy(new char[name.length()+1], name.c_str())); const string result = actual; delete[] actual; #else #warning Using workaround for lack of mkdtemp. Probably buggy. // This is seriously bad: Not only is there a possible race condition, the // man page for mktemp on solaris states that "Only 26 unique file names per // thread can be created for each unique template". char *actual = ::mktemp(strcpy(new char[name.length()+1], name.c_str())); const string result = actual; if(::mkdir(actual, 0700) != 0) throw ClibException("Failed to mkdir \"" + result + "\""); delete[] actual; #endif return result; }