WvStreams
unifilesystemgen.cc
1 #include "unifilesystemgen.h"
2 #include "wvfile.h"
3 #include "wvdiriter.h"
4 #include "wvfileutils.h"
5 #include "wvmoniker.h"
6 #include "wvlinkerhack.h"
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 
12 WV_LINK(UniFileSystemGen);
13 
14 
15 static IUniConfGen *creator(WvStringParm s, IObject *)
16 {
17  return new UniFileSystemGen(s, 0777);
18 }
19 
20 WvMoniker<IUniConfGen> UniFileSystemGenMoniker("fs", creator);
21 
22 
23 UniFileSystemGen::UniFileSystemGen(WvStringParm _dir, mode_t _mode)
24  : dir(_dir), mode(_mode)
25 {
26 }
27 
28 
29 static bool key_safe(const UniConfKey &key)
30 {
31  UniConfKey::Iter i(key);
32  for (i.rewind(); i.next(); )
33  {
34  if (*i == "." || *i == ".." || *i == "")
35  return false; // unsafe key segments
36  }
37 
38  // otherwise a safe filename
39  return true;
40 }
41 
42 
44 {
45  WvString null;
46 
47  if (!key_safe(key))
48  return null;
49 
50  WvString path("%s/%s", dir, key);
51 
52  // WARNING: this code depends on the ability to open() a directory
53  // as long as we don't read it, because we want to fstat() it after.
54  WvFile file(path, O_RDONLY);
55  if (!file.isok())
56  return null; // unreadable; pretend it doesn't exist
57 
58  struct stat st;
59  if (fstat(file.getrfd(), &st) < 0)
60  return null; // openable but can't stat? That's odd.
61 
62  if (S_ISREG(st.st_mode))
63  {
64  WvDynBuf buf;
65  while (file.isok())
66  file.read(buf, 4096);
67  if (file.geterr())
68  return null;
69  else
70  return buf.getstr();
71  }
72  else
73  return ""; // exists, but pretend it's an empty file
74 }
75 
76 
78 {
79  if (!key_safe(key))
80  return;
81 
82  WvString base("%s/%s", dir, key.removelast(1));
83  WvString path("%s/%s", dir, key);
84 
85  mkdirp(base, mode);
86 
87  if (value.isnull())
88  rm_rf(path);
89  else
90  {
91  WvFile file(path, O_WRONLY|O_CREAT|O_TRUNC, mode & 0666);
92  file.write(value);
93  }
94 }
95 
96 
97 void UniFileSystemGen::setv(const UniConfPairList &pairs)
98 {
99  setv_naive(pairs);
100 }
101 
102 
104 {
105 private:
106  UniFileSystemGen *gen;
107  WvDirIter i;
108  UniConfKey rel;
109 
110 public:
112  const UniConfKey &_rel)
113  : gen(_gen), i(path, false), rel(_rel)
114  { }
115 
117  { }
118 
119  void rewind()
120  { i.rewind(); }
121 
122  bool next()
123  { return i.next(); }
124 
125  UniConfKey key() const
126  { return i->relname; }
127 
128  WvString value() const
129  { return gen->get(WvString("%s/%s", rel, i->relname)); }
130 };
131 
132 
134 {
135  if (!key_safe(key))
136  return NULL;
137 
138  return new UniFileSystemGenIter(this, WvString("%s/%s", dir, key), key);
139 }