00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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());
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
00148 needdelete.push_back((*ci)->position);
00149 ci++;
00150 } else if((*fi).first[0] == '.') {
00151
00152 fi++;
00153 } else if(ci == children.end()) {
00154
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
00163 needdelete.push_back((*ci)->position);
00164 ci++;
00165 } else {
00166
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);
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
00185 LOG("directory", 2, "VOS and directory don't match after delete sync???");
00186 ci++;
00187 } else if((*fi).first[0] == '.') {
00188
00189 fi++;
00190 } else if(ci == children.end()) {
00191
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
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
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 }