WvStreams
|
00001 #include "unifilesystemgen.h" 00002 #include "wvfile.h" 00003 #include "wvdiriter.h" 00004 #include "wvfileutils.h" 00005 #include "wvmoniker.h" 00006 #include "wvlinkerhack.h" 00007 #include <sys/types.h> 00008 #include <sys/stat.h> 00009 #include <unistd.h> 00010 #include <fcntl.h> 00011 00012 WV_LINK(UniFileSystemGen); 00013 00014 00015 static IUniConfGen *creator(WvStringParm s, IObject *) 00016 { 00017 return new UniFileSystemGen(s, 0777); 00018 } 00019 00020 WvMoniker<IUniConfGen> UniFileSystemGenMoniker("fs", creator); 00021 00022 00023 UniFileSystemGen::UniFileSystemGen(WvStringParm _dir, mode_t _mode) 00024 : dir(_dir), mode(_mode) 00025 { 00026 } 00027 00028 00029 static bool key_safe(const UniConfKey &key) 00030 { 00031 UniConfKey::Iter i(key); 00032 for (i.rewind(); i.next(); ) 00033 { 00034 if (*i == "." || *i == ".." || *i == "") 00035 return false; // unsafe key segments 00036 } 00037 00038 // otherwise a safe filename 00039 return true; 00040 } 00041 00042 00043 WvString UniFileSystemGen::get(const UniConfKey &key) 00044 { 00045 WvString null; 00046 00047 if (!key_safe(key)) 00048 return null; 00049 00050 WvString path("%s/%s", dir, key); 00051 00052 // WARNING: this code depends on the ability to open() a directory 00053 // as long as we don't read it, because we want to fstat() it after. 00054 WvFile file(path, O_RDONLY); 00055 if (!file.isok()) 00056 return null; // unreadable; pretend it doesn't exist 00057 00058 struct stat st; 00059 if (fstat(file.getrfd(), &st) < 0) 00060 return null; // openable but can't stat? That's odd. 00061 00062 if (S_ISREG(st.st_mode)) 00063 { 00064 WvDynBuf buf; 00065 while (file.isok()) 00066 file.read(buf, 4096); 00067 if (file.geterr()) 00068 return null; 00069 else 00070 return buf.getstr(); 00071 } 00072 else 00073 return ""; // exists, but pretend it's an empty file 00074 } 00075 00076 00077 void UniFileSystemGen::set(const UniConfKey &key, WvStringParm value) 00078 { 00079 if (!key_safe(key)) 00080 return; 00081 00082 WvString base("%s/%s", dir, key.removelast(1)); 00083 WvString path("%s/%s", dir, key); 00084 00085 mkdirp(base, mode); 00086 00087 if (value.isnull()) 00088 rm_rf(path); 00089 else 00090 { 00091 WvFile file(path, O_WRONLY|O_CREAT|O_TRUNC, mode & 0666); 00092 file.write(value); 00093 } 00094 } 00095 00096 00097 void UniFileSystemGen::setv(const UniConfPairList &pairs) 00098 { 00099 setv_naive(pairs); 00100 } 00101 00102 00103 class UniFileSystemGenIter : public UniConfGen::Iter 00104 { 00105 private: 00106 UniFileSystemGen *gen; 00107 WvDirIter i; 00108 UniConfKey rel; 00109 00110 public: 00111 UniFileSystemGenIter(UniFileSystemGen *_gen, WvStringParm path, 00112 const UniConfKey &_rel) 00113 : gen(_gen), i(path, false), rel(_rel) 00114 { } 00115 00116 ~UniFileSystemGenIter() 00117 { } 00118 00119 void rewind() 00120 { i.rewind(); } 00121 00122 bool next() 00123 { return i.next(); } 00124 00125 UniConfKey key() const 00126 { return i->relname; } 00127 00128 WvString value() const 00129 { return gen->get(WvString("%s/%s", rel, i->relname)); } 00130 }; 00131 00132 00133 UniConfGen::Iter *UniFileSystemGen::iterator(const UniConfKey &key) 00134 { 00135 if (!key_safe(key)) 00136 return NULL; 00137 00138 return new UniFileSystemGenIter(this, WvString("%s/%s", dir, key), key); 00139 }