00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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)) {
00101
00102 PathName entryPathName(pathname); entryPathName+=PathName(name);
00103 if ( stat( entryPathName.str().c_str(), &statbuf) == 0) {
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
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
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
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
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
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
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 }