fs.cc

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include <iostream>
00004 #include <fstream>
00005 
00006 #ifdef STAT_MACROS_BROKEN
00007 #error Sorry, S_ISDIR, S_ISREG et. al. appear to be broken on this system.
00008 #endif
00009 
00010 #include <cstring>
00011 #include <cerrno>
00012 
00013 #ifdef HAVE_SYS_MKDEV_H
00014 #include <sys/mkdev.h>
00015 #endif
00016 #ifdef HAVE_SYS_TYPES_H
00017 #include <sys/types.h>
00018 #endif
00019 #ifdef HAVE_SYS_STAT_H
00020 #include <sys/stat.h>
00021 #endif
00022 #ifdef HAVE_UNISTD_H
00023 #include <unistd.h>
00024 #endif
00025 
00026 #ifdef TIME_WITH_SYS_TIME
00027         #include <sys/time.h>
00028         #include <time.h>
00029 #else
00030         #ifdef HAVE_SYS_TIME_H
00031                 #include <sys/time.h>
00032         #else
00033                 #include <time.h>
00034         #endif
00035 #endif
00036 
00037 #ifdef HAVE_DIRENT_H
00038         #include <dirent.h>
00039         #define NAMELEN(dirent) strlen((dirent)->d_name)
00040 #else
00041         #define dirent direct
00042         #define NAMELEN(dirent) (dirent)->d_namlen
00043         #ifdef HAVE_SYS_NDIR_H
00044                 #include <sys/ndir.h>
00045         #endif
00046         #ifdef HAVE_SYS_DIR_H
00047                 #include <sys/dir.h>
00048         #endif
00049         #ifdef HAVE_NDIR_H
00050                 #include <ndir.h>
00051         #endif
00052 #endif
00053 
00054 #ifdef HAVE_FNMATCH_H
00055 #include <fnmatch.h>
00056 #endif
00057 
00058 #include <stdio.h>
00059 
00060 #include "asserts.h"
00061 #include "error.h"
00062 #include "estring.h"
00063 #include "fs.h"
00064 
00065 //
00066 // Define certain file attribute elements if they don't already exist
00067 //
00068 #ifndef S_IFMT
00069 #define S_IFMT  (S_IFREG|S_IFCHR|S_IFBLK|S_IFIFO)
00070 #endif
00071 
00072 #ifndef S_IAMB
00073 #define S_IAMB  (S_ISUID|S_ISGID|S_ISVTX\
00074                 |S_IRUSR|S_IWUSR|S_IXUSR\
00075                 |S_IRGRP|S_IWGRP|S_IXGRP\
00076                 |S_IROTH|S_IWOTH|S_IXOTH\
00077                 )
00078 
00079 #endif
00080 
00081 #ifdef S_IFIFO
00082 #ifndef S_ISFIFO
00083 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
00084 #endif
00085 #endif
00086 
00087 #ifdef S_IFCHR
00088 #ifndef S_ISCHR
00089 #define S_ISCHR(mode)   (((mode) & S_IFMT) == S_IFCHR)
00090 #endif
00091 #endif
00092 
00093 #ifdef S_IFDIR
00094 #ifndef S_ISDIR
00095 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
00096 #endif
00097 #endif
00098 
00099 #ifdef S_IFBLK
00100 #ifndef S_ISBLK
00101 #define S_ISBLK(mode)   (((mode) & S_IFMT) == S_IFBLK)
00102 #endif
00103 #endif
00104 
00105 #ifdef S_IFREG
00106 #ifndef S_ISREG
00107 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
00108 #endif
00109 #endif
00110 
00111 #ifdef S_IFLNK
00112 #ifndef S_ISLNK
00113 #define S_ISLNK(mode)   (((mode) & S_IFMT) == S_IFLNK)
00114 #endif
00115 #endif
00116 
00117 #ifdef S_IFSOCK
00118 #ifndef S_ISSOCK
00119 #define S_ISSOCK(mode)  (((mode) & S_IFMT) == S_IFSOCK)
00120 #endif
00121 #endif
00122 
00123 #ifdef S_IFDOOR
00124 #ifndef S_ISDOOR
00125 #define S_ISDOOR(mode)  (((mode) & S_IFMT) == S_IFDOOR)
00126 #endif
00127 #endif
00128 
00129 #ifndef S_IRWXU
00130 #define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR)
00131 #endif
00132 
00133 #ifndef S_IRWXG
00134 #define S_IRWXG (S_IRGRP|S_IWGRP|S_IXGRP)
00135 #endif
00136 
00137 #ifndef S_IRWXO
00138 #define S_IRWXO (S_IROTH|S_IWOTH|S_IXOTH)
00139 #endif
00140 
00141 #ifndef ACCESSPERMS
00142 #define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO)
00143 #endif
00144 
00145 //----------------------------------------------------------------------------
00146 
00147 /** Return the current working directory */
00148 const std::string cwd(void)
00149 {
00150         std::string s;
00151         char buf[PATH_MAX] = { 0 };
00152 
00153         if (getcwd(buf, PATH_MAX) == 0)
00154                 throw(ERROR(errno,"Could not determine current directory"));
00155 
00156         TRY_nomem(s = buf);
00157 
00158         return(s);
00159 }
00160 
00161 /** Return the PID of this process */
00162 const pid_t pid(void)
00163 {
00164         pid_t pid;
00165 
00166         pid = getpid();
00167         if (pid == -1)
00168                 throw(ERROR(errno,"Could not determine PID"));
00169 
00170         return(pid);
00171 }
00172 
00173 /** Return the PID of the parent process */
00174 const pid_t parent_pid(void)
00175 {
00176         pid_t pid;
00177 
00178         pid = getppid();
00179         if (pid == -1)
00180                 throw(ERROR(errno,"Could not determine PID"));
00181 
00182         return(pid);
00183 }
00184 
00185 /** Return true if the string looks like an absolute path */
00186 bool absolute_path(const std::string& a_path)
00187 {
00188         if ((a_path.size() > 0) && (a_path[0] == '/')) {
00189                 return(true);
00190         }
00191         return(false);
00192 }
00193 
00194 /** Return true if the string looks like a relative path */
00195 bool relative_path(const std::string& a_path)
00196 {
00197         bool value;
00198 
00199         value = !absolute_path(a_path);
00200 
00201         return(value);
00202 }
00203 
00204 /** Reformat a path to remove double slashes */
00205 std::string reform_path(const std::string& a_path)
00206 {
00207         std::string::size_type idx;
00208         std::string str;
00209 
00210         TRY_nomem(str = a_path);
00211         idx = str.find('/');
00212         while (idx != std::string::npos) {
00213                 while ((idx != str.size()-1) && (str[idx+1] == '/'))
00214                         str.erase(idx+1,1);
00215                 idx = str.find('/',idx+1);
00216         }
00217         
00218         return(str);
00219 }
00220 
00221 /** Reformat a path to remove the begining and trailing slashes, and replace
00222         all other slashes with underscores
00223  */
00224 std::string permute_path(const std::string& a_path)
00225 {
00226         std::string path;
00227         std::string::size_type idx;
00228 
00229         TRY_nomem(path = reform_path(a_path));
00230         idx = path.find('/');
00231         while (idx != std::string::npos) {
00232                 if ((idx == 0) || (idx == path.size()-1))
00233                         path.erase(idx,1);
00234                 else
00235                         path[idx] = '-';
00236                 idx = path.find('/');
00237         }
00238         if (path.size() == 0)
00239                 TRY_nomem(path = "root");
00240         if (path.substr(0,2) == ".-")
00241                 path.erase(0,2);
00242 
00243         return(path);
00244 }
00245 
00246 /** Return everything after the last slash from a path */
00247 std::string path_basename(const std::string& a_path)
00248 {
00249         std::string path;
00250         std::string::size_type idx;
00251 
00252         idx = a_path.rfind('/');
00253         if (idx == std::string::npos) {
00254                 TRY_nomem(path = a_path);
00255         }
00256         else {
00257                 TRY_nomem(path = a_path.substr(idx+1));
00258         }
00259         
00260         return(path);
00261 }
00262 
00263 /** Return everything up to the last slash from a path */
00264 std::string path_dirname(const std::string& a_path)
00265 {
00266         std::string path;
00267         std::string::size_type idx;
00268 
00269         idx = a_path.rfind('/');
00270         if (idx == std::string::npos) {
00271                 TRY_nomem(path = ".");
00272         }
00273         else {
00274                 TRY_nomem(path = a_path.substr(0,idx));
00275         }
00276         
00277         return(path);
00278 }
00279 
00280 /** Make the path a_rel_path absolute with respect to a_path, where a_rel_path
00281  * and a_path are directory names */
00282 std::string mk_absolute_path(
00283         const std::string a_path,
00284         const std::string a_rel_path
00285         )
00286 {
00287         std::string es;
00288         std::string path;
00289 
00290         if (a_rel_path.size() == 0) {
00291                 TRY_nomem(es = "Invalid relative path: \"");
00292                 TRY_nomem(es += a_rel_path);
00293                 TRY_nomem(es += "\"");
00294                 throw(ERROR(0,es));
00295         }
00296         if (relative_path(a_path)) {
00297                 TRY_nomem(es = "Invalid absolute reference path: \"");
00298                 TRY_nomem(es += a_path);
00299                 TRY_nomem(es += "\"");
00300                 throw(INTERNAL_ERROR(0,es));
00301         }
00302         if (relative_path(a_rel_path)) {
00303                 TRY_nomem(path = a_path);
00304                 TRY_nomem(path += "/");
00305         }
00306         TRY_nomem(path += a_rel_path);
00307         path = reform_path(path);
00308 
00309         return(path);
00310 }
00311 
00312 /** Make the path a_path_to relative from a_path_from, where a_path_to and
00313  * a_path_from are directory names */
00314 std::string mk_relative_path(
00315         const std::string a_path_to,
00316         const std::string a_path_from
00317         )
00318 {
00319         std::string::size_type idx_to, idx_from, idx;
00320         std::string path_to, path_from, path;
00321         std::string path_to_substr, path_from_substr;
00322 
00323         TRY_nomem(path_to = a_path_to);
00324         TRY_nomem(path_from = a_path_from);
00325         TRY_nomem(path = "");
00326 
00327         idx_to = path_to.find("/");
00328         if (idx_to != std::string::npos) {
00329                 TRY_nomem(path_to_substr = path_to.substr(0,idx_to));
00330         }
00331         else {
00332                 TRY_nomem(path_to_substr = path_to);
00333         }
00334         idx_from = path_from.find("/");
00335         if (idx_from != std::string::npos) {
00336                 TRY_nomem(path_from_substr = path_from.substr(0,idx_from));
00337         }
00338         else {
00339                 TRY_nomem(path_from_substr = path_from);
00340         }
00341 
00342         while (
00343                 (path_to.size() > 0 && path_from.size() > 0)
00344                 && (path_to_substr == path_from_substr)
00345                 )
00346         {
00347                 path_to.erase(0,path_to_substr.size());
00348                 if ((path_to.size() > 0) && (path_to[0] == '/'))
00349                         path_to.erase(0,1);
00350                 path_from.erase(0,path_from_substr.size());
00351                 if ((path_from.size() > 0) && (path_from[0] == '/'))
00352                         path_from.erase(0,1);
00353 
00354                 idx_to = path_to.find("/");
00355                 if (idx_to != std::string::npos) {
00356                         TRY_nomem(path_to_substr = path_to.substr(0,idx_to));
00357                 }
00358                 else {
00359                         TRY_nomem(path_to_substr = path_to);
00360                 }
00361                 idx_from = path_from.find("/");
00362                 if (idx_from != std::string::npos) {
00363                         TRY_nomem(path_from_substr = path_from.substr(0,idx_from));
00364                 }
00365                 else {
00366                         TRY_nomem(path_from_substr = path_from);
00367                 }
00368         }
00369 
00370         while (path_from.size() > 0) {
00371                 TRY_nomem(path += "../");
00372                 idx = path_from.find('/');
00373                 if (idx == std::string::npos)
00374                         path_from.erase();
00375                 else
00376                         path_from.erase(0,idx+1);
00377         }
00378         TRY_nomem(path += path_to);
00379         TRY_nomem(path = reform_path(path));
00380 
00381         return(path);
00382 }
00383 
00384 /** Return true if the file or directory exists */
00385 bool exists(const std::string& a_path)
00386 {
00387         if (access(a_path.c_str(), F_OK) != 0) {
00388                 errno = 0;
00389                 return(false);
00390         }
00391         return(true);
00392 }
00393 
00394 /** Return true if the file or directory exists and is readable */
00395 bool readable(const std::string& a_path)
00396 {
00397         if (access(a_path.c_str(), R_OK) != 0) {
00398                 errno = 0;
00399                 return(false);
00400         }
00401         return(true);
00402 }
00403 
00404 /** Return true if the file or directory exists and is writable */
00405 bool writable(const std::string& a_path)
00406 {
00407         if (access(a_path.c_str(), W_OK) != 0) {
00408                 errno = 0;
00409                 return(false);
00410         }
00411         return(true);
00412 }
00413 
00414 /** Return true if the file or directory exists and is executable */
00415 bool executable(const std::string& a_path)
00416 {
00417         if (access(a_path.c_str(), X_OK) != 0) {
00418                 errno = 0;
00419                 return(false);
00420         }
00421         return(true);
00422 }
00423 
00424 #ifdef S_ISFIFO
00425 /** Return true if the file is a fifo-special */
00426 bool is_fifo_special(const std::string& a_path)
00427 {
00428         filestatus fstat;
00429 
00430         try {
00431                 fstat.path(a_path);
00432                 if (fstat.is_fifo_special()) {
00433                         return(true);
00434                 }
00435         }
00436         catch(...) {
00437                 return(false);
00438         }
00439         return(false);
00440 }
00441 #endif
00442 
00443 #ifdef S_ISCHR
00444 /** Return true if the file is a char-special */
00445 bool is_char_special(const std::string& a_path)
00446 {
00447         filestatus fstat;
00448 
00449         try {
00450                 fstat.path(a_path);
00451                 if (fstat.is_character_special()) {
00452                         return(true);
00453                 }
00454         }
00455         catch(...) {
00456                 return(false);
00457         }
00458         return(false);
00459 }
00460 #endif
00461 
00462 #ifdef S_ISDIR
00463 /** Return true if the file is a directory */
00464 bool is_dir(const std::string& a_path)
00465 {
00466         filestatus fstat;
00467 
00468         try {
00469                 fstat.path(a_path);
00470                 if (fstat.is_directory()) {
00471                         return(true);
00472                 }
00473         }
00474         catch(...) {
00475                 return(false);
00476         }
00477         return(false);
00478 }
00479 #endif
00480 
00481 #ifdef S_ISREG
00482 /** Return true if the file is a regular file */
00483 bool is_file(const std::string& a_path)
00484 {
00485         filestatus fstat;
00486 
00487         try {
00488                 fstat.path(a_path);
00489                 if (fstat.is_regular_file()) {
00490                         return(true);
00491                 }
00492         }
00493         catch(...) {
00494                 return(false);
00495         }
00496         return(false);
00497 }
00498 #endif
00499 
00500 #ifdef S_ISBLK
00501 /** Return true if the file is a block-special */
00502 bool is_block_special(const std::string& a_path)
00503 {
00504         filestatus fstat;
00505 
00506         try {
00507                 fstat.path(a_path);
00508                 if (fstat.is_block_special()) {
00509                         return(true);
00510                 }
00511         }
00512         catch(...) {
00513                 return(false);
00514         }
00515         return(false);
00516 }
00517 #endif
00518 
00519 #ifdef S_ISLNK
00520 /** Return true is the file is a link */
00521 bool is_link(const std::string& a_path)
00522 {
00523         filestatus fstat;
00524 
00525         try {
00526                 fstat.path(a_path);
00527                 if (fstat.is_link()) {
00528                         return(true);
00529                 }
00530         }
00531         catch(...) {
00532                 return(false);
00533         }
00534         return(false);
00535 }
00536 #endif
00537 
00538 #ifdef S_ISSOCK
00539 /** Return true if the file is a socket */
00540 bool is_socket(const std::string& a_path)
00541 {
00542         filestatus fstat;
00543 
00544         try {
00545                 fstat.path(a_path);
00546                 if (fstat.is_socket()) {
00547                         return(true);
00548                 }
00549         }
00550         catch(...) {
00551                 return(false);
00552         }
00553         return(false);
00554 }
00555 #endif
00556 
00557 #ifdef S_ISDOOR
00558 /** Return true if the file is a door */
00559 bool is_door(const std::string& a_path)
00560 {
00561         filestatus fstat;
00562 
00563         try {
00564                 fstat.path(a_path);
00565                 if (fstat.is_door()) {
00566                         return(true);
00567                 }
00568         }
00569         catch(...) {
00570                 return(false);
00571         }
00572         return(false);
00573 }
00574 #endif
00575 
00576 /** Create a directory */
00577 void mk_dir(const std::string& a_path)
00578 {
00579         std::string es;
00580 
00581         if (mkdir(a_path.c_str(), ACCESSPERMS) != 0) {
00582                 TRY_nomem(es = "Could not create directory: \"");
00583                 TRY_nomem(es += a_path);
00584                 TRY_nomem(es += "\"");
00585                 throw(ERROR(errno,es));
00586         }
00587 }
00588 
00589 /** Remove a directory */
00590 void rm_dir(const std::string a_path)
00591 {
00592         if (rmdir(a_path.c_str()) != 0) {
00593                 std::string es;
00594 
00595                 TRY_nomem(es = "Could not remove directory: \"");
00596                 TRY_nomem(es += a_path);
00597                 TRY_nomem(es += "\"");
00598 
00599                 throw(ERROR(errno,es));
00600         }
00601 }
00602 
00603 /** Remove a file */
00604 void rm_file(const std::string a_path)
00605 {
00606         if (unlink(a_path.c_str()) != 0) {
00607                 std::string es;
00608 
00609                 TRY_nomem(es = "Could not remove file: \"");
00610                 TRY_nomem(es += a_path);
00611                 TRY_nomem(es += "\"");
00612 
00613                 throw(ERROR(errno,es));
00614         }
00615 }
00616 
00617 /** Recursively create a directory heirarchy */
00618 void mk_dirhier_recursive_(const std::string a_path)
00619 {
00620         std::string parent_dir;
00621         int ce;
00622 
00623         if (a_path.size() == 0)
00624                 return;
00625         if (exists(a_path))
00626                 return;
00627         
00628         for (ce = a_path.size()-1; ((ce > 0) && (a_path[ce] != '/')); ce--);
00629 
00630         if (ce > 0) {
00631                 TRY_nomem(parent_dir = a_path.substr(0,ce));
00632                 mk_dirhier_recursive_(parent_dir);
00633         }
00634         if (!exists(a_path))
00635                 mk_dir(a_path);
00636 }
00637 
00638 /** Recursively create a directory heirarchy */
00639 void mk_dirhier(const std::string a_path)
00640 {
00641         if (a_path.size() == 0)
00642                 return;
00643         if (exists(a_path))
00644                 return;
00645         
00646         try {
00647                 mk_dirhier_recursive_(a_path);
00648         }
00649         catch(error e) {
00650                 std::string es;
00651 
00652                 TRY_nomem(es = "Could not create directory hierarchy: \"");
00653                 TRY_nomem(es += a_path);
00654                 TRY_nomem(es += "\"");
00655 
00656                 e.push_back(ERROR_INSTANCE(es));
00657                 throw(e);
00658         }
00659         catch(...) {
00660                 throw(err_unknown);
00661         }
00662 }
00663 
00664 /** Rename a file or directory */
00665 void rename_file(const std::string a_from, const std::string a_to)
00666 {
00667         std::string es;
00668 
00669         if (a_from.size() == 0) {
00670                 TRY_nomem(es = "Illegal from filename: \"");
00671                 TRY_nomem(es += a_from);
00672                 TRY_nomem(es += "\"");
00673                 throw(INTERNAL_ERROR(0,es));
00674         }
00675         if (!exists(a_from)) {
00676                 TRY_nomem(es = "From filename does not exist: \"");
00677                 TRY_nomem(es += a_from);
00678                 TRY_nomem(es += "\"");
00679                 throw(ERROR(0,es));
00680         }
00681         if (a_to.size() == 0) {
00682                 TRY_nomem(es = "Illegal to filename: \"");
00683                 TRY_nomem(es += a_to);
00684                 TRY_nomem(es += "\"");
00685                 throw(INTERNAL_ERROR(0,es));
00686         }
00687         if (exists(a_to)) {
00688                 TRY_nomem(es = "To filename already exists: \"");
00689                 TRY_nomem(es += a_to);
00690                 TRY_nomem(es += "\"");
00691                 throw(ERROR(0,es));
00692         }
00693         if (rename(a_from.c_str(), a_to.c_str()) != 0) {
00694                 TRY_nomem(es = "Could not rename file: \"");
00695                 TRY_nomem(es += a_from);
00696                 TRY_nomem(es += "\" to \"");
00697                 TRY_nomem(es += a_to);
00698                 TRY_nomem(es += "\"");
00699                 throw(ERROR(errno,es));
00700         }
00701 }
00702 
00703 /** Create a symbolic link */
00704 void mk_symlink(const std::string a_from, const std::string a_to)
00705 {
00706         if (symlink(a_from.c_str(), a_to.c_str()) != 0) {
00707                 std::string es;
00708 
00709                 TRY_nomem(es = "Could not link: \"");
00710                 TRY_nomem(es += a_from);
00711                 TRY_nomem(es += "\" to: \"");
00712                 TRY_nomem(es += a_to);
00713                 TRY_nomem(es += "\"");
00714 
00715                 throw(ERROR(errno,es));
00716         }
00717 }
00718 
00719 /** Given a from and to path, create a relative symbolic link */
00720 void mk_relative_symlink(const std::string a_from, const std::string a_to)
00721 {
00722         std::string from_dirname, to_dirname, from_basename;
00723         std::string rel;
00724 
00725         TRY_nomem(from_dirname = path_dirname(a_from));
00726         TRY_nomem(to_dirname = path_dirname(a_to));
00727         TRY_nomem(from_basename = path_basename(a_from));
00728         TRY_nomem(rel = mk_relative_path(from_dirname, to_dirname));
00729         if (rel.size() != 0) {
00730                 TRY_nomem(rel += "/");
00731         }
00732         TRY_nomem(rel += from_basename);
00733         TRY_nomem(rel = reform_path(rel));
00734 
00735         try {
00736                 mk_symlink(rel,a_to);
00737         }
00738         catch(error e) {
00739                 std::string es;
00740 
00741                 TRY_nomem(es = "Could not link: \"");
00742                 TRY_nomem(es += a_to);
00743                 TRY_nomem(es += "\" as: \"");
00744                 TRY_nomem(es += rel);
00745                 TRY_nomem(es += "\"");
00746 
00747                 e.push_back(ERROR_INSTANCE(es));
00748                 throw(e);
00749         }
00750         catch(...) {
00751                 throw(err_unknown);
00752         }
00753 }
00754 
00755 //----------------------------------------------------------------------------
00756 
00757 /** C'tor */
00758 filestatus::filestatus()
00759 {
00760 }
00761 
00762 /** C'tor */
00763 filestatus::filestatus(const std::string a_path)
00764 {
00765         path(a_path);
00766 }
00767 
00768 /** D'tor */
00769 filestatus::~filestatus()
00770 {
00771 }
00772 
00773 /** Retrieve information about a pathname */
00774 void filestatus::path(const std::string a_path)
00775 {
00776         std::string es;
00777         struct passwd *passwd_ptr = 0;
00778         struct group *group_ptr = 0;
00779         struct stat statbuf;
00780         char path_buf[PATH_MAX] = { 0 };
00781 
00782         clear();
00783         TRY_nomem(m_path = reform_path(a_path));
00784         if (lstat(m_path.c_str(), &statbuf) < 0) {
00785                 TRY_nomem(es = "For path: \"");
00786                 TRY_nomem(es += a_path);
00787                 TRY_nomem(es += "\"");
00788                 throw(ERROR(errno,es));
00789         }
00790         if (lstat(m_path.c_str(), &m_stat) == -1) {
00791                 TRY_nomem(es = "For path: \"");
00792                 TRY_nomem(es += a_path);
00793                 TRY_nomem(es += "\"");
00794                 throw(ERROR(errno,es));
00795         }
00796 #ifdef S_ISFIFO
00797         if (S_ISFIFO(m_stat.st_mode)) {
00798                 m_major = major(m_stat.st_rdev);
00799                 m_minor = minor(m_stat.st_rdev);
00800         }
00801 #endif
00802 #ifdef S_ISCHR
00803         if (S_ISCHR(m_stat.st_mode)) {
00804                 m_major = major(m_stat.st_rdev);
00805                 m_minor = minor(m_stat.st_rdev);
00806         }
00807 #endif
00808 #ifdef S_ISBLK
00809         if (S_ISBLK(m_stat.st_mode)) {
00810                 m_major = major(m_stat.st_rdev);
00811                 m_minor = minor(m_stat.st_rdev);
00812         }
00813 #endif
00814 #ifdef S_ISLNK
00815         if (S_ISLNK(m_stat.st_mode)) {
00816                 if (readlink(a_path.c_str(), path_buf, PATH_MAX) < 0) {
00817                         TRY_nomem(es = "Could not read path's link: \"");
00818                         TRY_nomem(es += a_path);
00819                         TRY_nomem(es += "\"");
00820                         throw(ERROR(errno,es));
00821                 }
00822                 TRY_nomem(m_link = path_buf);
00823         }
00824 #endif
00825         passwd_ptr = getpwuid(m_stat.st_uid);
00826         if (passwd_ptr != 0) {
00827                 m_uidfound = true;
00828                 TRY_nomem(m_uname = passwd_ptr->pw_name);
00829         }
00830         group_ptr = getgrgid(m_stat.st_gid);
00831         if (group_ptr != 0) {
00832                 m_gidfound = true;
00833                 TRY_nomem(m_gname = group_ptr->gr_name);
00834         }
00835 }
00836 
00837 /** Return the pathname that this filestatus object has information about */
00838 const std::string filestatus::path(void) const
00839 {
00840         return(m_path);
00841 }
00842 
00843 /** Return the type of file */
00844 const filestatus::filetype filestatus::type(void) const
00845 {
00846 #ifdef S_ISFIFO
00847         if (S_ISFIFO(m_stat.st_mode)) {
00848                 return(type_fifo_special);
00849         }
00850 #endif
00851 #ifdef S_ISCHR
00852         if (S_ISCHR(m_stat.st_mode)) {
00853                 return(type_character_special);
00854         }
00855 #endif
00856 #ifdef S_ISDIR
00857         if (S_ISDIR(m_stat.st_mode)) {
00858                 return(type_directory);
00859         }
00860 #endif
00861 #ifdef S_ISBLK
00862         if (S_ISBLK(m_stat.st_mode)) {
00863                 return(type_block_special);
00864         }
00865 #endif
00866 #ifdef S_ISREG
00867         if (S_ISREG(m_stat.st_mode)) {
00868                 return(type_regular_file);
00869         }
00870 #endif
00871 #ifdef S_ISLNK
00872         if (S_ISLNK(m_stat.st_mode)) {
00873                 return(type_link);
00874         }
00875 #endif
00876 #ifdef S_ISSOCK
00877         if (S_ISSOCK(m_stat.st_mode)) {
00878                 return(type_socket);
00879         }
00880 #endif
00881 #ifdef S_ISDOOR
00882         if (S_ISDOOR(m_stat.st_mode)) {
00883                 return(type_door);
00884         }
00885 #endif
00886         return(type_unknown);
00887 }
00888 
00889 /** If the pathname is a link, return the path it is linked to */
00890 const std::string filestatus::link(void) const
00891 {
00892         return(m_link);
00893 }
00894 
00895 /** Return the file mode */
00896 const filestatus::mode_type filestatus::mode(void) const
00897 {
00898         return(m_stat.st_mode);
00899 }
00900 
00901 /** Return the file inode */
00902 const filestatus::inode_type filestatus::inode(void) const
00903 {
00904         return(m_stat.st_ino);
00905 }
00906 
00907 /** Return the file's device */
00908 const filestatus::device_type filestatus::dev(void) const
00909 {
00910         return(m_stat.st_dev);
00911 }
00912 
00913 /** Return the file's raw device */
00914 const filestatus::device_type filestatus::rdev(void) const
00915 {
00916         return(m_stat.st_rdev);
00917 }
00918 
00919 /** If the pathname is a special file, return it's major number */
00920 const filestatus::major_type filestatus::get_major(void) const
00921 {
00922         return(m_major);
00923 }
00924 
00925 /** If the pathname is a special file, return it's minor number */
00926 const filestatus::minor_type filestatus::get_minor(void) const
00927 {
00928         return(m_minor);
00929 }
00930 
00931 /** Return the number of links to this file */
00932 const filestatus::num_links_type filestatus::num_links(void) const
00933 {
00934         return(m_stat.st_nlink);
00935 }
00936 
00937 /** Return the file's owner's UID */
00938 const filestatus::uid_type filestatus::uid(void) const
00939 {
00940         return(m_stat.st_uid);
00941 }
00942 
00943 /** Return the file's owner's GID */
00944 const filestatus::gid_type filestatus::gid(void) const
00945 {
00946         return(m_stat.st_gid);
00947 }
00948 
00949 /** Return the file size in bytes */
00950 const filestatus::size_type filestatus::size(void) const
00951 {
00952         size_type value;
00953 
00954         value = static_cast<uint64>(m_stat.st_size);
00955 
00956         return(value);
00957 }
00958 
00959 /** Return the last access time of this file */
00960 const filestatus::time_type filestatus::last_access_time(void) const
00961 {
00962         return(m_stat.st_atime);
00963 }
00964 
00965 /** Return the last modification time of this file */
00966 const filestatus::time_type filestatus::last_modification_time(void) const
00967 {
00968         return(m_stat.st_mtime);
00969 }
00970 
00971 /** Return the last status change time of this file */
00972 const filestatus::time_type filestatus::last_status_change_time(void) const
00973 {
00974         return(m_stat.st_ctime);
00975 }
00976 
00977 /** Return the blocksize used to store this file */
00978 const filestatus::size_type filestatus::blocksize(void) const
00979 {
00980         size_type value;
00981 
00982         value = static_cast<uint64>(m_stat.st_blksize);
00983 
00984         return(value);
00985 }
00986 
00987 /** Return the number of blocks used to store this file */
00988 const filestatus::size_type filestatus::blocks(void) const
00989 {
00990         size_type value;
00991 
00992         value = static_cast<uint64>(m_stat.st_blocks);
00993 
00994         return(value);
00995 }
00996 
00997 /** If the file's owner's UID is found in the passwd file, return true */
00998 const bool filestatus::uid_is_found(void) const
00999 {
01000         return(m_uidfound);
01001 }
01002 
01003 /** If the file's owner's GID is found in the passwd file, return true */
01004 const bool filestatus::gid_is_found(void) const
01005 {
01006         return(m_gidfound);
01007 }
01008 
01009 /** Return the file's owner's user name (from UID) */
01010 const std::string filestatus::uid_name(void) const
01011 {
01012         return(m_uname);
01013 }
01014 
01015 /** Return the file's owner's group name (from UID) */
01016 const std::string filestatus::gid_name(void) const
01017 {
01018         return(m_gname);
01019 }
01020 
01021 #ifdef S_ISFIFO
01022 /** Return true if the file is a fifo-special */
01023 const bool filestatus::is_fifo_special(void) const
01024 {
01025         bool value;
01026 
01027         value = (type() == type_fifo_special);
01028 
01029         return(value);
01030 }
01031 #endif
01032 
01033 #ifdef S_ISCHR
01034 /** Return true if the file is a char-special */
01035 const bool filestatus::is_character_special(void) const
01036 {
01037         bool value;
01038 
01039         value = (type() == type_character_special);
01040 
01041         return(value);
01042 }
01043 #endif
01044 
01045 #ifdef S_ISBLK
01046 /** Return true if the file is a block-special */
01047 const bool filestatus::is_block_special(void) const
01048 {
01049         bool value;
01050 
01051         value = (type() == type_block_special);
01052 
01053         return(value);
01054 }
01055 #endif
01056 
01057 #ifdef S_ISLNK
01058 /** Return true if the file is a link */
01059 const bool filestatus::is_link(void) const
01060 {
01061         bool value;
01062 
01063         value = (type() == type_link);
01064 
01065         return(value);
01066 }
01067 #endif
01068 
01069 #ifdef S_ISSOCK
01070 /** Return true if the file is a socket */
01071 const bool filestatus::is_socket(void) const
01072 {
01073         bool value;
01074 
01075         value = (type() == type_socket);
01076 
01077         return(value);
01078 }
01079 #endif
01080 
01081 #ifdef S_ISDOOR
01082 /** Return true if the file is a door */
01083 const bool filestatus::is_door(void) const
01084 {
01085         bool value;
01086 
01087         value = (type() == type_door);
01088 
01089         return(value);
01090 }
01091 #endif
01092 
01093 #ifdef S_ISDIR
01094 /** Return true if the file is a directory */
01095 const bool filestatus::is_directory(void) const
01096 {
01097         bool value;
01098 
01099         value = (type() == type_directory);
01100 
01101         return(value);
01102 }
01103 #endif
01104 
01105 #ifdef S_ISREG
01106 /** Return true if the file is a regular file */
01107 const bool filestatus::is_regular_file(void) const
01108 {
01109         bool value;
01110 
01111         value = (type() == type_regular_file);
01112 
01113         return(value);
01114 }
01115 #endif
01116 
01117 #ifdef S_IRUSR
01118 /** Return true if the file is readable by it's owner */
01119 const bool filestatus::user_can_read(void) const
01120 {
01121         bool value;
01122 
01123         value = ((m_stat.st_mode & S_IRUSR) != 0);
01124 
01125         return(value);
01126 }
01127 #endif
01128 
01129 #ifdef S_IWUSR
01130 /** Return true if the file is writable by it's owner */
01131 const bool filestatus::user_can_write(void) const
01132 {
01133         bool value;
01134 
01135         value = ((m_stat.st_mode & S_IWUSR) != 0);
01136 
01137         return(value);
01138 }
01139 #endif
01140 
01141 #ifdef S_IXUSR
01142 /** Return true if the file is executable by it's owner */
01143 const bool filestatus::user_can_execute(void) const
01144 {
01145         bool value;
01146 
01147         value = ((m_stat.st_mode & S_IXUSR) != 0);
01148 
01149         return(value);
01150 }
01151 #endif
01152 
01153 #ifdef S_IRGRP
01154 /** Return true if the file is readable by users in the same group */
01155 const bool filestatus::group_can_read(void) const
01156 {
01157         bool value;
01158 
01159         value = ((m_stat.st_mode & S_IRGRP) != 0);
01160 
01161         return(value);
01162 }
01163 #endif
01164 
01165 #ifdef S_IWGRP
01166 /** Return true if the file is writable by users in the same group */
01167 const bool filestatus::group_can_write(void) const
01168 {
01169         bool value;
01170         
01171         value = ((m_stat.st_mode & S_IWGRP) != 0);
01172 
01173         return(value);
01174 }
01175 #endif
01176 
01177 #ifdef S_IXGRP
01178 /** Return true if the file is executable by users in the same group */
01179 const bool filestatus::group_can_execute(void) const
01180 {
01181         bool value;
01182 
01183         value = ((m_stat.st_mode & S_IXGRP) != 0);
01184 
01185         return(value);
01186 }
01187 #endif
01188 
01189 #ifdef S_IROTH
01190 /** Return true if the file is readable by others */
01191 const bool filestatus::other_can_read(void) const
01192 {
01193         bool value;
01194 
01195         value = ((m_stat.st_mode & S_IROTH) != 0);
01196 
01197         return(value);
01198 }
01199 #endif
01200 
01201 #ifdef S_IWOTH
01202 /** Return true if the file is writable by others */
01203 const bool filestatus::other_can_write(void) const
01204 {
01205         bool value;
01206 
01207         value = ((m_stat.st_mode & S_IWOTH) != 0);
01208 
01209         return(value);
01210 }
01211 #endif
01212 
01213 #ifdef S_IXOTH
01214 /** Return true if the file is executable by others */
01215 const bool filestatus::other_can_execute(void) const
01216 {
01217         bool value;
01218 
01219         value = ((m_stat.st_mode & S_IXOTH) != 0);
01220 
01221         return(value);
01222 }
01223 #endif
01224 
01225 #ifdef S_ISUID
01226 /** Return true if the file's mode has it's set-uid bit set */
01227 const bool filestatus::is_set_uid(void) const
01228 {
01229         bool value;
01230 
01231         value = ((m_stat.st_mode & S_ISUID) != 0);
01232 
01233         return(value);
01234 }
01235 #endif
01236 
01237 #ifdef S_ISGID
01238 /** Return true if the file's mode has it's set-gid bit set */
01239 const bool filestatus::is_set_gid(void) const
01240 {
01241         bool value;
01242 
01243         value = ((m_stat.st_mode & S_ISGID) != 0);
01244 
01245         return(value);
01246 }
01247 #endif
01248 
01249 #ifdef S_ISVTX
01250 /** Return true if the file's mode has it's sticky bit set */
01251 const bool filestatus::is_set_sticky(void) const
01252 {
01253         bool value;
01254 
01255         value = ((m_stat.st_mode & S_ISVTX) != 0);
01256 
01257         return(value);
01258 }
01259 #endif
01260 
01261 /** Clear all values */
01262 void filestatus::clear(void)
01263 {
01264         TRY_nomem(m_path = "");
01265         memset(&m_stat, 0, sizeof(m_stat));
01266         m_major = 0;
01267         m_minor = 0;
01268         m_uidfound = false;
01269         m_gidfound = false;
01270         TRY_nomem(m_uname = "");
01271         TRY_nomem(m_gname = "");
01272 }
01273 
01274 //----------------------------------------------------------------------------
01275 
01276 /** C'tor */
01277 subdirectory::subdirectory()
01278 {
01279 }
01280 
01281 /** C'tor */
01282 subdirectory::subdirectory(const subdirectory& a_class)
01283 {
01284         assign(a_class);
01285 }
01286 
01287 /** C'or */
01288 subdirectory::subdirectory(
01289         const std::string a_path, const std::string a_filter)
01290 {
01291         path(a_path, a_filter);
01292 }
01293 
01294 /** D'tor */
01295 subdirectory::~subdirectory()
01296 {
01297 }
01298 
01299 /** Assign the contents of a given subdirectory to this subdirectory */
01300 void subdirectory::assign(const subdirectory& a_class)
01301 {
01302         type::assign(a_class.begin(), a_class.end());
01303 }
01304 
01305 /** Return a vector of strings of a list of files in a subdirectory
01306 
01307         Files in the list do not contain the pathname to the file.  Only filenames
01308         that match the given wildcard filter will be listed.
01309  */
01310 const subdirectory::type& 
01311         subdirectory::path(const std::string a_path, const std::string a_filter)
01312 {
01313         std::string es;
01314         std::string name;
01315         DIR *dp = 0;
01316         struct dirent *dirp = 0;
01317         filestatus filestat;
01318 
01319         clear();
01320 
01321         TRY(filestat.path(a_path),"Could not stat directory");
01322 
01323         dp = opendir(a_path.c_str());
01324         if (dp == 0) {
01325                 TRY_nomem(es = "For path: \"");
01326                 TRY_nomem(es += a_path);
01327                 TRY_nomem(es += "\"");
01328                 throw(ERROR(errno,es));
01329         }
01330         while ( (dirp = readdir(dp)) != 0 ) {
01331                 name = dirp->d_name;
01332                 if (
01333                         ((a_filter != ".") && (a_filter != "..")) 
01334                         && 
01335                         ((name == ".") || (name == ".."))
01336                         )
01337                         continue;
01338                 if (fnmatch(a_filter.c_str(), name.c_str(), 0) == 0) {
01339                         TRY_nomem(type::push_back(name));
01340                 }
01341         }
01342         if (closedir(dp) < 0) {
01343                 TRY_nomem(es = "Error closing directory \"");
01344                 TRY_nomem(es += a_path);
01345                 TRY_nomem(es += "\"");
01346                 throw(ERROR(errno,es));
01347         }
01348 
01349         std::sort(begin(), end());
01350 
01351         return(*this);
01352 }
01353 
01354 subdirectory& subdirectory::operator=(const subdirectory& a_class)
01355 {
01356         assign(a_class);
01357 
01358         return(*this);
01359 }
01360 
01361 //----------------------------------------------------------------------------
01362 
01363 /** Recursively delete the contents of a directory */
01364 void rm_recursive(const std::string a_path)
01365 {
01366         subdirectory d;
01367         subdirectory::const_iterator di;
01368         filestatus f;
01369         std::string pathstr;
01370         std::string es;
01371 
01372         TRY_nomem(es = "Could not recursively delete: \"");
01373         TRY_nomem(es += a_path);
01374         TRY_nomem(es += "\"");
01375 
01376         if (!exists(a_path)) {
01377                 if (is_link(a_path)) {
01378                         TRY(rm_file(a_path),es);
01379                 }
01380                 return;
01381         }
01382         TRY(f.path(a_path),es);
01383         if (f.is_directory()) {
01384                 TRY(d.path(a_path),es);
01385                 if (d.size() != 0) {
01386         
01387                         for (di = d.begin(); di != d.end(); ++di) {
01388                                 TRY_nomem(
01389                                         pathstr = std::string(a_path)
01390                                                 + std::string("/")
01391                                                 + std::string(*di)
01392                                                 );
01393                                 TRY(f.path(pathstr),es);
01394                                 if (f.is_directory()) {
01395                                         TRY(rm_recursive(pathstr),es);
01396                                 }
01397                                 else {
01398                                         rm_file(pathstr);
01399                                 }
01400                         }
01401                 }
01402                 rm_dir(a_path);
01403         }
01404         else {
01405                 rm_file(a_path);
01406         }
01407 }
01408 
01409 //----------------------------------------------------------------------------
01410 
01411 /** C'tor */
01412 directory::directory()
01413 {
01414 }
01415 
01416 /** C'tor */
01417 directory::directory(const directory& a_class)
01418 {
01419         // TODO: Isn't this supposed to do something!?
01420 }
01421 
01422 /** C'tor */
01423 directory::directory(const std::string& a_str)
01424 {
01425         path(a_str);
01426 }
01427 
01428 /** D'tor */
01429 directory::~directory()
01430 {
01431 }
01432 
01433 /** Retrieve a list of paths that match the wildcard path given */
01434 const directory::type& directory::path(const std::string& a_path)
01435 {
01436         std::string es;
01437         std::string::size_type idx;
01438         std::string path;
01439         std::string subdir_path;
01440         std::string new_subdir_path;
01441         subdirectory subdir;
01442         subdirectory::const_iterator sdi;
01443         filestatus filestat;
01444         const_iterator di;
01445         type list;
01446 
01447         TRY_nomem(path = reform_path(a_path));
01448         if (path.size() == 0) {
01449                 return(*this);
01450         }
01451         
01452         idx = path.find('/');
01453         if (idx != std::string::npos) {
01454                 TRY_nomem(subdir_path = path.substr(0,idx));
01455                 path.erase(0,idx+1);
01456         }
01457         else {
01458                 TRY_nomem(subdir_path = path);
01459                 path.erase();
01460         }
01461         if (subdir_path.size() == 0)
01462                 TRY_nomem(subdir_path = "/");
01463         
01464         if (!exists(subdir_path)) {
01465                 return(*this);
01466         }
01467         TRY_nomem(push_back(subdir_path));
01468 
01469         while (path.size() != 0) {
01470                 idx = path.find('/');
01471                 if (idx != std::string::npos) {
01472                         TRY_nomem(subdir_path = path.substr(0,idx));
01473                         path.erase(0,idx+1);
01474                 }
01475                 else {
01476                         TRY_nomem(subdir_path = path);
01477                         path.erase();
01478                 }
01479                 list.clear();
01480                 for (di = begin(); di != end(); di++) {
01481                         TRY_nomem(list.push_back(*di));
01482                 }
01483                 clear();
01484                 for (di = list.begin(); di != list.end(); di++) {
01485                         filestat.path(*di);
01486                         if (!filestat.is_directory())
01487                                 continue;
01488                         subdir.path(*di, subdir_path);
01489                         for (sdi = subdir.begin(); sdi != subdir.end(); sdi++) {
01490                                 TRY_nomem(new_subdir_path = *di);
01491                                 TRY_nomem(new_subdir_path += "/");
01492                                 TRY_nomem(new_subdir_path += *sdi);
01493                                 TRY_nomem(new_subdir_path = reform_path(new_subdir_path));
01494                                 TRY_nomem(push_back(new_subdir_path));
01495                         }
01496                 }
01497         }
01498         return(*this);
01499 }
01500 
01501 //----------------------------------------------------------------------------
01502 
01503 /** C'tor */
01504 filesystem::filesystem()
01505 {
01506         clear();
01507 }
01508 
01509 /** C'tor */
01510 filesystem::filesystem(const std::string& a_path)
01511 {
01512         clear();
01513         path(a_path);
01514 }
01515 
01516 /** Clear the filesystem object */
01517 void filesystem::clear(void)
01518 {
01519         TRY_nomem(m_path = "");
01520         memset(&m_statfs, 0, sizeof(m_statfs));
01521 }
01522 
01523 /** Retrieve information about the filesystem on which the given path resides */
01524 void filesystem::path(const std::string& a_path)
01525 {
01526         std::string es;
01527 
01528         TRY_nomem(m_path = reform_path(a_path));
01529         if (STATFS(a_path.c_str(), &m_statfs) != 0) {
01530                 TRY_nomem(es = "Could not stat filesystem: \"");
01531                 TRY_nomem(es += a_path);
01532                 TRY_nomem(es += "\"");
01533                 throw(ERROR(errno,es));
01534         }
01535 }
01536 
01537 /** Return the path from which this filesystem information was obtained */
01538 const std::string filesystem::path(void) const
01539 {
01540         return(m_path);
01541 }
01542 
01543 /** Return the filesystem block size */
01544 const filesystem::size_type filesystem::blocksize(void) const
01545 {
01546         size_type value;
01547 
01548         value = static_cast<uint64>(m_statfs.f_bsize);
01549 
01550         return(value);
01551 }
01552 
01553 /** Return the filesystem's total number of blocks */
01554 const filesystem::size_type filesystem::total_blocks(void) const
01555 {
01556         size_type value;
01557 
01558         value = static_cast<uint64>(m_statfs.f_blocks);
01559 
01560         return(value);
01561 }
01562 
01563 /** Return the filesystem's number of free blocks */
01564 const filesystem::size_type filesystem::free_blocks(void) const
01565 {
01566         size_type value;
01567 
01568         value = static_cast<uint64>(m_statfs.f_bfree);
01569 
01570         return(value);
01571 }
01572 
01573 /** Return the filesystem's number of used blocks */
01574 const filesystem::size_type filesystem::used_blocks(void) const
01575 {
01576         size_type value;
01577 
01578         value = total_blocks() - free_blocks();
01579 
01580         return(value);
01581 }
01582 
01583 /** Return the filesystem's total number of inodes, if supported by the
01584         filesystem, otherwise the result is system-dependent, but usually 0.
01585  */
01586 const filesystem::size_type filesystem::total_inodes(void) const
01587 {
01588         size_type value;
01589 
01590         value = static_cast<uint64>(m_statfs.f_files);
01591 
01592         return(value);
01593 }
01594 
01595 /** Return the filesystem's total number of free inodes, if supported by the
01596         filesystem, otherwise the result is system-dependent, but usually 0.
01597  */
01598 const filesystem::size_type filesystem::free_inodes(void) const
01599 {
01600         size_type value;
01601         
01602         value = static_cast<uint64>(m_statfs.f_ffree);
01603 
01604         return(value);
01605 }
01606 
01607 /** Return the filesystem's number of used inodes */
01608 const filesystem::size_type filesystem::used_inodes(void) const
01609 {
01610         size_type value;
01611 
01612         value = total_inodes() - free_inodes();
01613 
01614         return(value);
01615 }
01616 
01617 /** Copy values from another instance */
01618 filesystem& filesystem::operator=(const filesystem& a_class)
01619 {
01620         TRY_nomem(m_path = a_class.m_path);
01621         memcpy(&m_statfs, &a_class.m_statfs, sizeof(m_statfs));
01622         
01623         return(*this);
01624 }
01625 
01626 //----------------------------------------------------------------------------
01627 

Generated on Mon Jul 12 12:02:44 2004 for rvm by doxygen 1.3.6