Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Directory.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Directory.cpp 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.4 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <base/Directory>
00026 
00027 #include <base/File>
00028 
00029 extern "C" {
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <unistd.h>
00033 #include <fcntl.h>
00034 #include <dirent.h>
00035 #include <errno.h>
00036 }
00037 
00038 using base::Directory;
00039 using base::File;
00040 using base::VEntry;
00041 using base::VDirectory;
00042 using base::VFile;
00043 using base::PathName;
00044 using base::path_not_found;
00045 
00046 
00047 
00048 Directory::Directory(ref<const Directory> parent)
00049   : loaded(false), parent(parent)
00050 {
00051 }
00052 
00053 
00054 Directory::Directory(const PathName& pathname, ref<const Directory> parent)
00055   : VDirectory(pathname), loaded(false), parent(parent)
00056 {
00057 }
00058 
00059 Directory::Directory(const Directory& d)
00060   : VDirectory(d), loaded(false), parent(d.parent)
00061 {
00062 }
00063 
00064 Directory::~Directory()
00065 {
00066 }
00067 
00068 void Directory::operator=(const Directory& d)
00069 {
00070   pathname=d.pathname;
00071   parent=d.parent;
00072   if (loaded) 
00073     entries.clear();
00074   loaded=false;
00075 }
00076 
00077 
00078 void Directory::load() const
00079 {
00080   if (!loaded) {
00081     entries.clear();
00082     DIR* d = opendir(pathname.str().c_str());
00083 
00084     if (d==0) {
00085       if ((errno == ENOENT) || (errno == ENOTDIR))
00086         throw path_not_found(Exception(String("directory not found: ")+pathname.str()));
00087       else
00088         throw io_error(Exception(String("can't open directory: ")+pathname.str()));
00089     }
00090 
00091     ref<const Directory> self(this);
00092     struct dirent* dentry;
00093     struct stat statbuf;
00094     do {
00095 
00096       dentry = readdir(d);
00097       if (dentry!=0) {
00098         String name(dentry->d_name);
00099 
00100         if ((name != PathName::currentDirectory) && (name != PathName::parentDirectory)) { // ignore "." and ".." 
00101           
00102           PathName entryPathName(pathname); entryPathName+=PathName(name);
00103           if ( stat( entryPathName.str().c_str(), &statbuf) == 0) { // if we can't stat it, skip it
00104             try {
00105               ref<VEntry> newEntry;
00106 
00107               if ( S_ISREG(statbuf.st_mode) ) newEntry = ref<File>( NewObj File(entryPathName) );
00108               if ( S_ISDIR(statbuf.st_mode) ) newEntry = ref<Directory>( NewObj Directory(entryPathName,self) );
00109               
00110               if (newEntry!=0) entries.push_back(newEntry);
00111             } catch (path_not_found&) {}
00112           }
00113         }
00114 
00115       }
00116 
00117     } while (dentry!=0);
00118 
00119     closedir(d);
00120     loaded=true;
00121   }
00122 }
00123 
00124 
00125 ref<VEntry> Directory::find(const String& name) const
00126 {
00127   load();
00128   bool found=false;
00129   VEntries::iterator it = entries.begin();
00130   while ((it != entries.end()) && !found) {
00131     if ( (*it)->name() == name )
00132       return (*it);
00133     ++it;
00134   }
00135   return ref<VEntry>(0);
00136 }
00137 
00138 
00139 
00140 
00141 bool Directory::contains(ref<const VEntry> entry) const
00142 {
00143   if (entry->path() != pathName()) return false;
00144   return ( find(entry->name().str()) != 0);
00145 }
00146 
00147 
00148 bool Directory::contains(const PathName& name) const
00149 {
00150   if (name.str() == PathName::currentDirectory) return true;
00151   if ((name.str() == PathName::parentDirectory) && (parent !=0)) return true;
00152   return ( find(name.str()) != 0 );
00153 }
00154 
00155 
00156 base::ref<VFile> Directory::file(const PathName& name) const throw(path_not_found)
00157 {
00158   ref<VEntry> e = find(name.str());
00159   if (e==0) throw path_not_found(Exception(String("file '")+name.str()+"' doesn't exist in directory: '"+pathname.str()+"'"));
00160   if (e->isDirectory()) throw path_not_found(Exception(String("'")+name.str()+"' is a directory"));
00161   return narrow_ref<VFile>(e);
00162 }
00163 
00164 base::ref<VDirectory> Directory::directory(const PathName& name) const throw(path_not_found)
00165 {
00166   if (name.str() == PathName::currentDirectory) 
00167     return ref<VDirectory>( NewObj Directory(*this) );
00168   if ((name.str() == PathName::parentDirectory) && (parent!=0)) 
00169     return ref<VDirectory>( NewObj Directory(*parent) );
00170 
00171   if (!name.isSimple()) 
00172     throw path_not_found(Exception(String("name '")+name.str()+"' must be simple; not a full path"));
00173 
00174   ref<VEntry> e = find(name.str());
00175   if (e==0) throw path_not_found(Exception(String("directory '")+name.str()+"' doesn't exist in directory: '"+pathName().str()+"'"));
00176   if (!e->isDirectory()) throw path_not_found(Exception(String("'")+name.str()+"' is a file"));
00177   return narrow_ref<VDirectory>(e);
00178 }
00179 
00180 
00181 ref<VFile> Directory::createFile(const PathName& name) const throw(io_error)
00182 {
00183   PathName pn(name);
00184   if (!pn.isRelative() || pn.path() != PathName::currentDirectory)
00185     throw io_error(Exception(String("'")+name.str()+"' must be a simple file name, not a path"));
00186   pn = pathname+pn;
00187 
00188   // create it
00189   int fd = creat(pn.str().c_str(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00190 
00191   if (fd == -1)
00192     throw io_error(Exception(String("error creating file '")+name.str()+"' in '"+pathName().str()+"': "+strerror(errno)));
00193   close(fd);
00194 
00195 
00196   // re-load directory (probably a better way)
00197   loaded=false;
00198   load();
00199 
00200   return file(name);
00201 }
00202 
00203 void Directory::deleteFile(const PathName& name) const throw(path_not_found, io_error)
00204 {
00205   ref<VEntry> e = find(name.str());
00206   if (e==0) throw path_not_found(Exception(String("file '")+name.str()+"' doesn't exist in this directory"));
00207   if (e->isDirectory()) throw path_not_found(Exception(String("'")+name.str()+"' is a directory"));
00208 
00209   int ret = unlink(e->pathName().str().c_str());
00210   if (ret == -1)
00211     throw io_error(Exception(String("error deleting file '")+name.str()+"' in '"+pathName().str()+"': "+strerror(errno)));
00212 
00213   // re-load directory (probably a better way)
00214   loaded=false;
00215   load();
00216 }
00217 
00218 ref<VDirectory> Directory::createDirectory(const PathName& name) const throw(io_error)
00219 {
00220   PathName pn(name);
00221   if (pn.isRelative() || pn.path() != PathName::currentDirectory)
00222     throw io_error(Exception(String("'")+name.str()+"' must be a simple directory name, not a path"));
00223   pn = pathname+pn;
00224 
00225   // create it
00226   int ret = mkdir(pn.str().c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
00227 
00228   if (ret == -1) 
00229     throw io_error(Exception(String("error creating directory '")+name.str()+"' in '"+pathName().str()+"': "+strerror(errno)));
00230 
00231   // re-load directory (probably a better way)
00232   loaded=false;
00233   load();
00234 
00235   return directory(name);
00236 }
00237 
00238 void Directory::deleteDirectory(const PathName& name) const throw(path_not_found, io_error)
00239 {
00240   if (name.str() == PathName::currentDirectory) 
00241     throw io_error(Exception("can't delete 'this' directory (delete it from parent)"));
00242   if (name.str() == PathName::parentDirectory)
00243     throw io_error(Exception("can't delete parent directory (delete it from parent's parent)"));
00244 
00245   if (!name.isSimple()) 
00246     throw path_not_found(Exception("name must be simple; not a full path"));
00247 
00248   ref<VEntry> e = find(name.str());
00249   if (e==0) throw path_not_found(Exception(String("directory '")+name.str()+"' doesn't exist in this directory"));
00250   if (!e->isDirectory()) throw path_not_found(Exception(String("'")+name.str()+"' is a file"));
00251 
00252   int ret = unlink(e->pathName().str().c_str());
00253   if (ret == -1)
00254     throw io_error(Exception(String("error deleting directory '")+name.str()+"' in '"+pathName().str()+"': "+strerror(errno)));
00255 
00256   // re-load directory (probably a better way)
00257   loaded=false;
00258   load();
00259 }
00260 
00261 
00262 
00263 
00264 
00265 base::ref<VEntry> Directory::entry(Int i) const
00266 {
00267   if (!loaded) load();
00268   return entries[i];
00269 }
00270 
00271 Int Directory::size() const 
00272 {
00273   if (!loaded) load();
00274   return entries.size();
00275 }

Generated on Thu Jul 29 15:56:05 2004 for OpenSim by doxygen 1.3.6