00001 #ifndef DV_UTIL_FILE_H 00002 #define DV_UTIL_FILE_H 00003 // $Id: file.h,v 1.32 2007/12/26 19:35:27 dvermeir Exp $ 00004 00005 #include <sys/types.h> 00006 #include <sys/stat.h> 00007 #include <string> 00008 #include <vector> 00009 #include <stdexcept> 00010 #include <iostream> 00011 00012 /** @file 00013 * 00014 * A Dv::Util::File class object represents a pathname, possibly 00015 * associated with an existing file. 00016 * 00017 * Member functions are provided for retrieving or altering properties 00018 * such as existence, permissions, ownership etc. In addition, 00019 * memory-mapping the contents of a File is also supported. 00020 * A \ref Dv::Util::Directory class object represents a pathname, 00021 * possibly associated with an existing directory. It provides similar 00022 * functionality as File, augmented with the retrieval of the 00023 * directory's contents. 00024 */ 00025 namespace Dv { 00026 namespace Util { 00027 /** A runtime exception thrown by some File operations. */ 00028 class FileError: public std::runtime_error { 00029 public: 00030 /** Name of class, is prepended to each message argument of the constructor. */ 00031 static const std::string NAME; 00032 /** Constructor, prepends NAME to message to obtain runtime_error::what(). */ 00033 FileError(const std::string& message): std::runtime_error(NAME+": "+message) {} 00034 }; 00035 00036 /** 00037 * A File objects represents a pathname, possibly an existing file. 00038 * 00039 * Example usage: 00040 * 00041 * \code 00042 * const char* name; 00043 * File f(name); 00044 * if (f.exists()) { 00045 * Date d(f.last_modified()); 00046 * 00047 * cout << f.str() << endl; 00048 * cout << std::string(d) << endl; 00049 * 00050 * const char* pc = static_cast<const char*>(f.map()); 00051 * 00052 * if (pc) // note: pc is not necessarily a C string 00053 * for (unsigned int i=0;(i<f.size());++i,++pc) 00054 * cout << *pc; 00055 * } 00056 * else 00057 * f.touch(); // make it exist 00058 * \endcode 00059 */ 00060 00061 class File { 00062 public: 00063 /** Type of file, note NONEXISTENT for pathnames that do not refer to a file. */ 00064 enum Type { REGULAR, SYMLINK, DIRECTORY, SPECIALCHAR, 00065 SPECIALBLOCK, FIFO, SOCKET, OTHER, NONEXISTENT }; 00066 /** File permissions, you can use the | operator to combine them. */ 00067 enum Mode { READ_OWNER = 0400, WRITE_OWNER = 0200, EXEC_OWNER = 0100, 00068 READ_GROUP = 040, WRITE_GROUP = 020, EXEC_GROUP = 010, 00069 READ_OTHER = 04, WRITE_OTHER = 02, EXEC_OTHER = 01, 00070 SETUID = 04000, SETGID = 02000, 00071 RWX_OWNER = 0700, RWX_GROUP = 070, RWX_OTHER = 07, 00072 RW_OWNER = 0600, RW_GROUP = 060, RW_OTHER = 06 00073 }; 00074 00075 /** 00076 * Constructor, argument can be a relative or an absolute path. 00077 * @param path absolute or relative path 00078 */ 00079 File(const std::string& path) throw (FileError); 00080 /** 00081 * Copy constructor. 00082 * @param f existing File object 00083 * @warning 00084 * @code 00085 * File f(g); 00086 * @endcode 00087 * is equivalent with 00088 * @code 00089 * File f(g.str()); 00090 * @endcode 00091 */ 00092 File(const File& f) throw (FileError); 00093 /** 00094 * Assignment. 00095 * @param f existing File object 00096 * @warning 00097 * @code 00098 * f = g; 00099 * @endcode 00100 * is, if \a &f!=&g , equivalent with 00101 * @code 00102 * File f(g.str()); 00103 * @endcode 00104 */ 00105 File& operator=(const File& f) throw (FileError); 00106 /** Virtual destructor, calls unmap(). */ 00107 virtual ~File(); 00108 /** 00109 * Change File object to a non-symbolic link file by 00110 * expanding symbolic links, if any. 00111 * @return reference to \a *this. 00112 * @exception FileError e.g. if there are too many symbolic links to follow. 00113 */ 00114 File& expand() throw (FileError); 00115 00116 /** Return string representation of File::Type. */ 00117 static const std::string& typestr(Type) throw (FileError); 00118 /** Check existence of file. */ 00119 bool exists() const throw (FileError) { refresh(); return exist_; } 00120 /** Delegates to exists(). */ 00121 operator bool() const throw (FileError) { return exists(); } 00122 00123 /** Returns a full, clean, absolute path as given by ::realpath(3C). 00124 * @warning For symbolic links the path used in the constructor is returned. 00125 */ 00126 std::string str() const { return path_; } 00127 /** Returns a full, clean, absolute path as given by ::realpath(3C). 00128 * @warning For symbolic links the path used in the constructor is returned. 00129 */ 00130 static std::string absolute_path(const std::string& path) throw (FileError); 00131 00132 /** Delegates to str(). */ 00133 operator const char*() const { return path_.c_str(); } 00134 /** 00135 * Identical to str().c_str(). 00136 * @return @a str().c_str() 00137 * @warning 00138 * For symbolic links the path used in the constructor is returned. 00139 */ 00140 const char* path() const { return path_.c_str(); } 00141 /** 00142 * Retrieve full path without resolving symbolic links. 00143 * The result is absolute and does not contain '..' or '.' 00144 * components and no superfluous '/' chars. 00145 * @param path relative or absolute path 00146 * @param resolved_path (output) 00147 * @return reference to second parameter 00148 * @exception if the full path would climb up from \a '/', 00149 * e.g. '/..' would throw an exception. 00150 * An empty \a path will also throw an exception. 00151 */ 00152 static std::string& fullpath(std::string path, std::string& resolved_path) 00153 throw (FileError); 00154 00155 /** 00156 * Retrieve full path without resolving symbolic links. 00157 * The result is absolute and does not contain '..' or '.' 00158 * components and no superfluous '/' chars. 00159 * @return resolved path. 00160 * @exception if the full path would climb up from \a '/', 00161 * e.g. '/..' would throw an exception. 00162 * An empty \a path will also throw an exception. 00163 */ 00164 std::string fullpath() const throw (FileError); 00165 00166 /** Only useful for symbolic links. */ 00167 std::string realpath() const throw (FileError); 00168 /** 00169 * Return path relative to from, which must be absolute. 00170 * @param from path such that \a from/relpath(from) 00171 * refers to this file 00172 * @return relative path \a x such that \a from/x refers to 00173 * this file 00174 */ 00175 std::string relpath(const std::string& from) const throw (FileError); 00176 /** 00177 * Return path relative to Directory::pwd() 00178 * @return relpath(pwd()) 00179 */ 00180 std::string relpath() const throw (FileError); 00181 /** Return type of file (possibly File::NONEXISTENT). */ 00182 Type type() const throw (FileError); 00183 /** Return true iff type() == File::DIRECTORY. */ 00184 bool isdir() const throw (FileError) { return type() == DIRECTORY; } 00185 /** Return size in bytes of file, 0 if \a !exists(). */ 00186 size_t size() const throw (FileError); 00187 /** Return time of last modification of file, or 0 if it does not exist. */ 00188 time_t last_modified() const throw (FileError); 00189 /** Return time of last access to file, or 0 if it does not exist. */ 00190 time_t last_accessed() const throw (FileError); 00191 /** Return permissions of file, @sa File::Mode. */ 00192 mode_t mode() const throw (FileError); 00193 /** Return uid of owner of file @sa Dv::Util::User. */ 00194 uid_t owner() const throw (FileError); 00195 /** Return gid of group-owner of file @sa Dv::Util::User. */ 00196 gid_t group() const throw (FileError); 00197 /** 00198 * Change the ownership of an existing file, return true iff successful. 00199 * @param uid id of new owner. 00200 * @return true iff new owner is @a uid. 00201 */ 00202 bool chown(uid_t uid) const throw (FileError); 00203 /** 00204 * Change group-ownership of an existing file, return true iff successful. 00205 * @param groupname of new group owner. 00206 * @return true iff new group owner is @a groupname. 00207 */ 00208 bool chgrp(const char* groupname) const throw (FileError); 00209 /** 00210 * Change permissions on an existing file. 00211 * @param mode representing permissions. 00212 * @return true iff permissions where succesfully set. 00213 * @sa File::Mode 00214 */ 00215 bool chmod(int mode=0755) throw (FileError); 00216 /** 00217 * Remove a file, for directories, rmdir is used. 00218 * @return true if @a exists() 00219 * @return false afterwards or if @a !exists() 00220 */ 00221 bool rm() throw (FileError); 00222 /** Like rm -fr. Throws FileError if exists() afterwards. */ 00223 void rmfr() throw (FileError); 00224 /** 00225 * Rename file, return true iff succeeds, also renames *this. 00226 * @param newpath new name of file. 00227 * @return true iff rename succeeded. 00228 */ 00229 bool mv(const std::string& newpath) throw (FileError); 00230 /** Creates or updates modification time of file. */ 00231 bool touch(int mode=0644) throw (FileError); 00232 /** Create a directory str(), precondition is !exists(). */ 00233 bool mkdir(int mode=0755) throw (FileError); 00234 /** Create a hard link to path, precondition is !exists(). */ 00235 bool mklink(const std::string& path) throw (FileError); 00236 /** 00237 * Create a symbolic link to path. 00238 * @return false if the file already exists, true if 00239 * the link was succesfully created. 00240 * @pre exists() returns false 00241 * @warning There is no check on the path parameter. 00242 */ 00243 bool mksymlink(const std::string& path) throw (FileError); 00244 00245 /** 00246 * Compare File objects. 00247 * 00248 * File comparison is independent of the name, the operator 00249 * compares i-nodes and devices. Nonexistent File objects 00250 * are never equal. 00251 * @warning This function does not expand symbolic links. 00252 * Thus, if @a s is a symbolic link to @a f, @a s and 00253 * @a f will be different. 00254 */ 00255 friend bool operator==(const Dv::Util::File&, const Dv::Util::File&); 00256 /** 00257 * Compare File objects. 00258 * 00259 * File comparison is independent of the name, the operator 00260 * compares i-nodes and devices. Nonexistent File objects 00261 * are never equal. 00262 * @warning This function does not expand symbolic links. 00263 * Thus, if @a s is a symbolic link to @a f, @a s and 00264 * @a f will be different. 00265 */ 00266 friend bool operator!=(const File& f1,const File& f2) { return ! (f1==f2); } 00267 /** 00268 * Compare File objects. 00269 * 00270 * File comparison is independent of the name, the operator 00271 * compares i-nodes and devices. Nonexistent File objects 00272 * are never equal. 00273 * @warning This function does not expand symbolic links. 00274 * Thus, if @a s is a symbolic link to @a f, @a s and 00275 * @a f will be different. 00276 */ 00277 friend bool operator<(const File&,const File&); 00278 /** 00279 * Map the contents of an existing file into memory. Return 0 upon failure. 00280 * Map() returns a pointer to the contents of the file, mapped into 00281 * virtual memory 00282 * @warning the returned pointer is not a C string, use Dv::Util::File::size() to 00283 * obtain the size of the map. 00284 */ 00285 const void* map() throw (FileError); 00286 /** 00287 * Release a mapping, if any, obtained by File::map(). 00288 * Unmapping a file that is not mapped is a noop. 00289 * File::unmap() is automatically called by the destructor. 00290 * @exception throws a FileError iff @a munmap(2) failed. 00291 */ 00292 void unmap() throw (FileError); 00293 /** @return address of map for mapped file, or 0 otherwise. */ 00294 const void* mapped() const { return addr_; } 00295 00296 /** Append contents of file to string. 00297 * @param s string to append to 00298 * @return reference to s 00299 */ 00300 std::string& content(std::string& s) const throw (FileError); 00301 00302 /** Return contents of file to string. 00303 * @return contents of file 00304 */ 00305 std::string content() const throw (FileError); 00306 /** Return the md5 digest of the file. 00307 * @author Davy Van Nieuwenborgh <rasto@rasto.be> 00308 * @param md5sum NULL or pointer to an array of 16 unsigned char bytes which will contain the binary md5 digest sum. 00309 * @return hexadecimal string representation of the md5 digest sum. 00310 */ 00311 std::string md5(unsigned char* md5sum = NULL) throw (FileError); 00312 00313 /** Return the sha1 digest of the file. 00314 * @author Davy Van Nieuwenborgh <rasto@rasto.be> 00315 * @param sha1sum NULL or pointer to an array of 20 unsigned char bytes which will contain the binary sha1 digest sum. 00316 * @return hexadecimal string representation of the sha1 digest sum. 00317 */ 00318 std::string sha1(unsigned char* sha1sum = NULL) throw (FileError); 00319 00320 /** Updates private data members, exist_ and type_. */ 00321 virtual void refresh() const throw (Dv::Util::FileError); 00322 /** Provide access to stats object 00323 * @return const reference to stats object (man 2 stat) 00324 * @sa Dv::Util::File::stats_ 00325 */ 00326 const struct stat& stats() const { return stats_; } 00327 protected: 00328 /** True iff there is a file with pathname str(). */ 00329 bool exist_; // updated by refresh() 00330 /** Type of file. */ 00331 Type type_; 00332 private: 00333 /** Man 2 stat for more info on this */ 00334 struct stat stats_; // updated by refresh() 00335 std::string path_; 00336 void* addr_; 00337 }; 00338 // forward declaration 00339 class Directory; 00340 00341 /** Abstract class that can be subclassed to implement useful operations 00342 * on files during a Directory::walk(). 00343 * @author Davy Van Nieuwenborgh <rasto@rasto.be> 00344 */ 00345 class FileOperation { 00346 public: 00347 virtual ~FileOperation(); 00348 /** This operation is called by e.g. Directory::walk() every time a file is encountered. 00349 * This method will be in general reimplemented by the user to perform something useful. 00350 * It's default behaviour is to output path and filename to std::out. 00351 * @author Davy Van Nieuwenborgh <rasto@rasto.be> 00352 * @param parent parent directory object of the file 00353 * @param file file object of the file 00354 * @param filename the filename, i.e. filename without parent path. 00355 * @warning Remember to catch FileError exceptions if you need them, as they get catched in 00356 * Directory::walk to prevent an incomplete walk. 00357 */ 00358 virtual void operator()(const Dv::Util::Directory& parent, 00359 Dv::Util::File& file, const std::string& filename); 00360 }; 00361 00362 /** Abstract class that can be subclassed to implement useful operations 00363 * on directories during a Directory::walk(). 00364 * @author Davy Van Nieuwenborgh <rasto@rasto.be> 00365 */ 00366 class DirectoryOperation { 00367 public: 00368 virtual ~DirectoryOperation(); 00369 /** This operation is called by e.g. Directory::walk() every time a directory is encountered. 00370 * This method will be in general reimplemented by the user to perform something useful. 00371 * It's default behaviour is to output path and directoryname to std::out. 00372 * @author Davy Van Nieuwenborgh <rasto@rasto.be> 00373 * @param parent parent directory object of the directory 00374 * @param directory directory object of the directory 00375 * @param directoryname the name of the directory without the parent path 00376 * @warning Remember to catch FileError exceptions if you need them, as they get catched in 00377 * Directory::walk to prevent an incomplete walk. 00378 */ 00379 virtual void operator()(const Dv::Util::Directory& parent, 00380 Dv::Util::Directory& directory, const std::string& directoryname); 00381 }; 00382 00383 /** 00384 * A Directory represents a pathname that refers to a possibly 00385 * non-existing directory. It is privately derived from File, 00386 * relevant File members are available, 00387 * in addition tot the @a files() member that retrieves the files in an 00388 * existing directory. 00389 * 00390 * @par 00391 * The following File members are available also in Directory: 00392 * 00393 * File::exists, 00394 * File::mkdir, 00395 * File::path, 00396 * File::str, 00397 * File::realpath, 00398 * File::relpath, 00399 * File::last_modified, 00400 * File::last_accessed, 00401 * File::touch, 00402 * File::chown, 00403 * File::chgrp, 00404 * File::chmod, 00405 * File::rm, 00406 * File::mv, 00407 * File::rmfr 00408 */ 00409 class Directory: private File { 00410 public: // a directory always exists 00411 /** Constructor, note that path may not exist. */ 00412 Directory(const std::string& path) throw (FileError); 00413 /** Equivalent to Directory(file.str()); */ 00414 Directory(const File& file) throw (FileError); 00415 /** Destructor. */ 00416 ~Directory(); 00417 00418 /** 00419 * Return files (only filenames, not absolute paths) in the directory. 00420 * If the directory does not exist, the vector is empty. 00421 * The directory entries ``.'' and ``..'' are not included 00422 * in the output of Dv::Util::Directory::files(). 00423 */ 00424 const std::vector<std::string>& files() const throw (FileError) { 00425 refresh(); return files_; 00426 } 00427 /** 00428 * Return @a str()+"/"+filename, i.e. a pathname for a filename in directory. 00429 */ 00430 std::string file(const std::string& filename) const; 00431 /** 00432 * Return @a str()+"/"+temp_filename, where @a temp_filename starts 00433 * with @a prefix, i.e. a pathname for a temporary file in the directory. 00434 * @param prefix of name of file to be created in this directory. 00435 * @return the filename 00436 * @warning This function calls mkstemp() which will actually create 00437 * the corresponding file. 00438 */ 00439 std::string tempfile(const std::string& prefix) const throw (FileError); 00440 00441 /** 00442 * Return @a str()+"/"+temp_dirname, where \a temp_dirname starts 00443 * with @a prefix, i.e. a pathname for a temporary subdirectory in the directory. 00444 * @param prefix of name of file to be created in this directory. 00445 * @return the directoryname 00446 * @warning This function calls mkdtemp() which will actually create 00447 * the corresponding directory. 00448 */ 00449 std::string tempdir(const std::string& prefix) const throw (FileError); 00450 00451 /** Change working directory. */ 00452 bool cd() const throw (FileError); 00453 /** Return absolute pathname of current working directory. */ 00454 static std::string pwd() throw (FileError); 00455 00456 /** @sa File::exists */ 00457 using File::exists; 00458 /** @sa File::mkdir */ 00459 using File::mkdir; 00460 /** @sa File::path */ 00461 using File::path; 00462 /** @sa File::str */ 00463 using File::str; 00464 /** @sa File::realpath */ 00465 using File::realpath; 00466 /** @sa File::relpath */ 00467 using File::relpath; 00468 /** @sa File::last_modified */ 00469 using File::last_modified; 00470 /** @sa File::last_accessed */ 00471 using File::last_accessed; 00472 /** @sa File::touch */ 00473 using File::touch; 00474 /** @sa File::chown */ 00475 using File::chown; 00476 /** @sa File::chgrp */ 00477 using File::chgrp; 00478 /** @sa File::chmod */ 00479 using File::chmod; 00480 /** @sa File::rm */ 00481 using File::rm; 00482 /** @sa File::mv */ 00483 using File::mv; 00484 /** @sa File::rmfr */ 00485 using File::rmfr; 00486 00487 /** Performs a walk through the filesystem starting from this directory. 00488 * The operation executes for each file (special files included, except directories) 00489 * it encounters the operation fileop(), while for each directory a call to 00490 * dirop() is done. 00491 * Files and/or directories with ``permission denied'' for the user running 00492 * the program are skipped. 00493 * @param fileop NULL or pointer to an instance of a subclass of FileOperation. 00494 * @param dirop NULL or pointer to an instance of a subclass of DirectoryOperation. 00495 * @warning This method catches all thrown exceptions of type FileError, 00496 * otherwise the operation could be interupted by files that e.g. get 00497 * deleted during the walk. Thus, if you need to catch exception of 00498 * type Dv::Util::FileError, you should catch them in your subclass of 00499 * Dv::Util::FileOperation and/or Dv::Util::DirectoryOperation. 00500 */ 00501 void walk(FileOperation* fileop = NULL, DirectoryOperation* dirop = NULL); 00502 private: 00503 void refresh() const throw (FileError); 00504 void init() const throw (FileError); 00505 00506 std::vector<std::string> files_; 00507 }; 00508 } 00509 } 00510 #endif
dvutil-1.0.10 | [ 5 December, 2009] |