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

vos/metaobjects/property/directory.cc

Go to the documentation of this file.
00001 /*
00002     This file is part of the Virtual Object System of
00003     the Interreality project (http://interreality.org).
00004 
00005     Copyright (C) 2001, 2002 Peter Amstutz
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 
00021     Peter Amstutz <tetron@interreality.org>
00022 */
00023 
00024 #include <sys/types.h>
00025 #include <dirent.h>
00026 #include <errno.h>
00027 #include <sys/stat.h>
00028 
00029 #ifndef S_ISDIR
00030 #define S_ISDIR(x) (x & _S_IFDIR)
00031 #endif
00032 
00033 #ifndef S_ISREG
00034 #define S_ISREG(x) (x & _S_IFREG)
00035 #endif
00036 
00037 #include <vos/corelibs/vos/vos.hh>
00038 #include "property.hh"
00039 #include "fileproperty.hh"
00040 #include "directory.hh"
00041 
00042 struct InsertEntry
00043 {
00044     bool isDir;
00045     int pos;
00046     string filename;
00047 };
00048 
00049 
00050 Directory::Directory(string name, LocalSite* localsite, VobjectAccessControl* ac, const string& path)
00051     : VobjectImplementation(name = localsite->uniqueName(name.c_str()), localsite, true), LocalVobject(name, localsite, ac),
00052       MetaObject(0), LocalMetaObject(name, localsite, ac)
00053 {
00054     dirpath = path;
00055     localsite->LocalVobject::insertChild(-1, name, this);
00056     status.st_mtime = 0;
00057     insync = false;
00058 }
00059 
00060 Directory::~Directory()
00061 {
00062 }
00063 
00064 const Vobject::ChildList& Directory::getChildren() throw (AccessControlError, RemoteError)
00065 {
00066     if(! insync) sync();
00067     return LocalMetaObject::getChildren();
00068 }
00069 
00070 Vobject& Directory::findObject(const string& path)
00071     throw (Vobject::NoSuchSiteError, Vobject::NoSuchObjectError, URL::BadURLError,
00072            Vobject::AccessControlError, Vobject::RemoteError)
00073 {
00074     if(! insync) sync();
00075     return LocalMetaObject::findObject(path);
00076 }
00077 
00078 Vobject::ParentChildRelation& Directory::findChild(const string& path)
00079     throw (Vobject::NoSuchObjectError, Vobject::AccessControlError, Vobject::RemoteError)
00080 {
00081     if(! insync) sync();
00082     return LocalMetaObject::findChild(path);
00083 }
00084 
00085 void Directory::syncTypes(string filename, Vobject* obj)
00086 {
00087     struct stat typestat;
00088     if(stat(filename.c_str(), &typestat) == 0) {
00089         if(typestat.st_mtime > status.st_mtime) {
00090             if(FILE* f = fopen(filename.c_str(), "r")) {
00091                 char t[256];
00092                 while(fscanf(f, " %255s ", t) != EOF) obj->addType(t);
00093                 fclose(f);
00094             }
00095         }
00096     }
00097 
00098 }
00099 
00100 void Directory::sync()
00101 {
00102     struct stat curstat;
00103     stat(dirpath.c_str(), &curstat);
00104 
00105     // check if directory has changed since we last looked at it
00106     if(curstat.st_mtime > status.st_mtime) {
00107         insync = true;
00108 
00109         string typepath = dirpath;
00110         typepath += "/.vostypes";
00111         syncTypes(typepath, this);
00112 
00113         DIR* dir = opendir(dirpath.c_str()); // scandir(3) might make my life easier, but it's not POSIX...
00114         if(! dir) {
00115             LOG("directory", 2, "Cannot read directory \"" << dirpath << "\": " << strerror(errno));
00116             return;
00117         }
00118 
00119         map<string, bool> filelist;
00120 
00121         struct dirent* entry;
00122         while((entry = readdir(dir))) {
00123             if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
00124                 string filepath = dirpath;
00125                 filepath += "/";
00126                 filepath += entry->d_name;
00127 
00128                 struct stat fileinfo;
00129                 stat(filepath.c_str(), &fileinfo);
00130                 if(S_ISREG(fileinfo.st_mode)) {
00131                     filelist[filepath.substr(dirpath.length()+1)] = false;
00132                 } else if(S_ISDIR(fileinfo.st_mode)) {
00133                     filelist[filepath.substr(dirpath.length()+1)] = true;
00134                 }
00135             }
00136         }
00137 
00138         map<string, bool>::iterator fi = filelist.begin();
00139 
00140         fi = filelist.begin();
00141         const ChildList& children = getChildren();
00142         ChildList::const_iterator ci = children.begin();
00143         list<int> needdelete;
00144 
00145         while(fi != filelist.end() || ci != children.end()) {
00146             if(fi == filelist.end()) {
00147                 // some item exists in VOS but not in the directory, so want to delete it
00148                 needdelete.push_back((*ci)->position);
00149                 ci++;
00150             } else if((*fi).first[0] == '.') {
00151                 // skip dotfiles entirely
00152                 fi++;
00153             } else if(ci == children.end()) {
00154                 // some item exists in directory but not in VOS (want to add it, will do this in next pass)
00155                 fi++;
00156             } else {
00157                 FileProperty* fp = meta_cast<FileProperty*>((*ci)->child);
00158                 string filebackend = (fp ? fp->getFileBackend() : "");
00159                 unsigned int pos = (fp ? filebackend.find_last_of('/') + 1 : 0);
00160                 cout << "del " << filebackend.substr(pos) << "\n";
00161                 if(!fp || filebackend.substr(pos) != (*fi).first) {
00162                     // directory and VOS don't match, start deleting stuff from VOS until we get back on track
00163                     needdelete.push_back((*ci)->position);
00164                     ci++;
00165                 } else {
00166                     // else VOS/directory match completely -- keep going
00167                     ci++;
00168                     fi++;
00169                 }
00170             }
00171         }
00172 
00173         for(list<int>::reverse_iterator i = needdelete.rbegin(); i != needdelete.rend(); i++) {
00174             LOG("directory", 3, "removing child " << *i);
00175             removeChild(*i); // XXX should excise maybe
00176         }
00177 
00178         fi = filelist.begin();
00179         ci = children.begin();
00180         list<InsertEntry> needinsert;
00181         InsertEntry e;
00182         while(fi != filelist.end() || ci != children.end()) {
00183             if(fi == filelist.end()) {
00184                 // some item exists in VOS but not in the directory -- this shouldn't happen!
00185                 LOG("directory", 2, "VOS and directory don't match after delete sync???");
00186                 ci++;
00187             } else if((*fi).first[0] == '.') {
00188                 // skip dotfiles entirely
00189                 fi++;
00190             } else if(ci == children.end()) {
00191                 // some item exists in directory but not in VOS, want to add it
00192                 e.pos = children.size();
00193                 e.filename = (*fi).first;
00194                 e.isDir = (*fi).second;
00195                 needinsert.push_back(e);
00196                 fi++;
00197             } else {
00198                 FileProperty* fp = meta_cast<FileProperty*>((*ci)->child);
00199                 string filebackend = (fp ? fp->getFileBackend() : "");
00200                 unsigned int pos = (fp ? filebackend.find_last_of('/') + 1 : 0);
00201                 cout << "ins " << filebackend.substr(pos) << "\n";
00202                 if(!fp || filebackend.substr(pos) != (*fi).first) {
00203                     // directory and VOS don't match -- add vobjects until it we're back on track
00204                     e.pos = children.size();
00205                     e.filename = (*fi).first;
00206                     e.isDir = (*fi).second;
00207                     needinsert.push_back(e);
00208                     fi++;
00209                 } else {
00210                     // else VOS/directory match completely -- keep going
00211                     ci++;
00212                     fi++;
00213                 }
00214             }
00215         }
00216 
00217         vRef<LocalSite> localsite = dynamic_cast<LocalSite&>(getSite());
00218         for(list<InsertEntry>::reverse_iterator i = needinsert.rbegin(); i != needinsert.rend(); i++) {
00219             LOG("directory", 3, "adding child " << (*i).filename);
00220             if((*i).isDir) {
00221                 vRef<Directory> d2 = new Directory(localsite->generateUniqueName(),
00222                                                    &localsite, getAccessControls()[0], dirpath+"/"+(*i).filename);
00223                 d2->sync();
00224                 insertChild((*i).pos, (*i).filename, &d2);
00225             } else {
00226                 vRef<FileProperty> fp = MetaObject::meta_cast<FileProperty*>
00227                     (localsite->createMetaObject((char*)0, typeid(FileProperty).name(), 0));
00228                 fp->insertPropertyAccessControl(-1, &ReadOnlyPropertyAccessControl::static_);
00229                 fp->setFileBackend(dirpath+"/"+(*i).filename);
00230                 string childname = (*i).filename;
00231                 unsigned int hashpos;
00232                 if((hashpos = childname.find_first_of('#')) != string::npos) childname = childname.substr(0, hashpos);
00233                 insertChild((*i).pos, childname, &fp);
00234             }
00235         }
00236 
00237         for(ci = children.begin(); ci != children.end(); ci++) {
00238             syncTypes(dirpath+"/."+(*ci)->contextual_name+".vostypes", (*ci)->child);
00239         }
00240 
00241         stat(dirpath.c_str(), &status);
00242         insync = false;
00243     }
00244 }

Generated on Tue Aug 12 03:55:45 2003 for Interreality Project - VOS by doxygen 1.3.2