The Pedigree Project  0.1
VFS.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "VFS.h"
21 #include "File.h"
22 #include "pedigree/kernel/Log.h"
23 #include "pedigree/kernel/syscallError.h"
24 #include "pedigree/kernel/utilities/Iterator.h"
25 #include "pedigree/kernel/utilities/StaticString.h"
26 #include "pedigree/kernel/utilities/StringView.h"
27 #include "pedigree/kernel/utilities/Vector.h"
28 #include "pedigree/kernel/utilities/utility.h"
29 
30 #ifndef VFS_STANDALONE
31 #include "modules/Module.h"
32 #include "pedigree/kernel/process/Process.h"
33 #include "pedigree/kernel/process/Thread.h"
34 #include "pedigree/kernel/processor/Processor.h"
35 #include "pedigree/kernel/processor/ProcessorInformation.h"
36 #endif
37 
38 class Disk;
39 
44 
46 
47 static void splitPathOnColon(
48  size_t colonPosition, const StringView &path, StringView &left,
49  StringView &right)
50 {
51  size_t afterColon = path.nextCharacter(colonPosition);
52  right = path.substring(afterColon, path.length());
53  left = path.substring(0, colonPosition);
54 }
55 
57 {
58  return m_Instance;
59 }
60 
61 VFS::VFS() : m_Aliases(), m_ProbeCallbacks(), m_MountCallbacks()
62 {
63 }
64 
66 {
67  // Wipe out probe callbacks we know about.
68  for (auto it = m_ProbeCallbacks.begin(); it != m_ProbeCallbacks.end(); ++it)
69  {
70  delete *it;
71  }
72 
73  // Unmount aliases.
74  for (auto it = m_Mounts.begin(); it != m_Mounts.end(); ++it)
75  {
76  auto fs = it.key();
77  auto aliases = it.value();
78  for (auto it2 = aliases->begin(); it2 != aliases->end(); ++it2)
79  {
80  delete *it2;
81  }
82 
83  delete aliases;
84  delete fs;
85  }
86 }
87 
88 bool VFS::mount(Disk *pDisk, String &alias)
89 {
91  m_ProbeCallbacks.begin();
92  it != m_ProbeCallbacks.end(); it++)
93  {
94  Filesystem::ProbeCallback cb = **it;
95  Filesystem *pFs = cb(pDisk);
96  if (pFs)
97  {
98  if (alias.length() == 0)
99  {
100  alias = pFs->getVolumeLabel();
101  }
102  alias = getUniqueAlias(alias);
103  addAlias(pFs, alias);
104 
105  if (m_Mounts.lookup(pFs) == 0)
106  m_Mounts.insert(pFs, new List<String *>);
107 
108  m_Mounts.lookup(pFs)->pushBack(new String(alias));
109 
110  for (List<MountCallback *>::Iterator it2 = m_MountCallbacks.begin();
111  it2 != m_MountCallbacks.end(); it2++)
112  {
113  MountCallback mc = *(*it2);
114  mc();
115  }
116 
117  return true;
118  }
119  }
120  return false;
121 }
122 
123 void VFS::addAlias(Filesystem *pFs, const String &alias)
124 {
125  if (!pFs)
126  return;
127 
128  pFs->m_nAliases++;
129  m_Aliases.insert(alias, pFs);
130 
131  if (m_Mounts.lookup(pFs) == 0)
132  m_Mounts.insert(pFs, new List<String *>);
133 
134  m_Mounts.lookup(pFs)->pushBack(new String(alias));
135 }
136 
137 void VFS::addAlias(const String &oldAlias, const String &newAlias)
138 {
139  AliasTable::LookupResult result = m_Aliases.lookup(oldAlias);
140  if (result.hasValue())
141  {
142  Filesystem *pFs = result.value();
143 
144  m_Aliases.insert(newAlias, pFs);
145 
146  if (m_Mounts.lookup(pFs) == 0)
147  m_Mounts.insert(pFs, new List<String *>);
148 
149  m_Mounts.lookup(pFs)->pushBack(new String(newAlias));
150  }
151 }
152 
154 {
155  if (!aliasExists(alias))
156  return alias;
157 
158  // <alias>-n is how we keep them unique
159  // negative numbers already have a dash
160  int32_t index = -1;
161  while (true)
162  {
163  NormalStaticString tmpAlias;
164  tmpAlias += static_cast<const char *>(alias);
165  tmpAlias.append(index);
166 
167  String s(static_cast<const char *>(tmpAlias));
168  if (!aliasExists(s))
169  return s;
170  index--;
171  }
172 }
173 
174 bool VFS::aliasExists(const String &alias)
175 {
176  return m_Aliases.contains(alias);
177 }
178 
179 void VFS::removeAlias(const String &alias)
180 {
182  m_Aliases.remove(alias);
183 }
184 
185 void VFS::removeAllAliases(Filesystem *pFs, bool canDelete)
186 {
187  if (!pFs)
188  return;
189 
190  for (AliasTable::Iterator it = m_Aliases.begin(); it != m_Aliases.end();)
191  {
192  if (pFs == (*it))
193  {
194  it = m_Aliases.erase(it);
195  }
196  else
197  ++it;
198  }
199 
201  if (m_Mounts.lookup(pFs) != 0)
202  {
203  List<String *> *pList = m_Mounts.lookup(pFs);
204  for (List<String *>::Iterator it = pList->begin(); it != pList->end();
205  it++)
206  {
207  delete *it;
208  }
209 
210  delete pList;
211 
212  m_Mounts.remove(pFs);
213  }
214 
215  if (canDelete)
216  {
217  delete pFs;
218  }
219 }
220 
222 {
223  Filesystem *fs;
224 #if VFS_WITH_LRU_CACHES
225  if (!m_AliasCache.get(alias, fs))
226  {
227 #endif
228  fs = lookupFilesystem(alias.view());
229 #if VFS_WITH_LRU_CACHES
230  }
231 
232  m_AliasCache.store(alias, fs);
233 #endif
234  return fs;
235 }
236 
238 {
239  AliasTable::LookupResult result = m_Aliases.lookup(alias);
240  return result.hasValue() ? result.value() : nullptr;
241 }
242 
243 File *VFS::find(const String &path, File *pStartNode)
244 {
245  // NOTICE("find: " << path);
246 
247  File *pResult = 0;
248 
249  StringView pathView = path.view();
250 
251  // Search for a colon.
252  ssize_t colon = findColon(path);
253  if (colon < 0)
254  {
255  // Pass directly through to the filesystem, if one specified.
256  if (pStartNode)
257  {
258  pResult = pStartNode->getFilesystem()->find(pathView, pStartNode);
259  }
260  }
261  else
262  {
263  // Can only cache lookups with the colon as they are not ambiguous
264 #if VFS_WITH_LRU_CACHES
265  if (m_FindCache.get(path, pResult))
266  {
267  m_FindCache.store(path, pResult);
268  }
269  else
270  {
271 #endif
272 
273  StringView left, right;
274  splitPathOnColon(colon, pathView, left, right);
275 
276  // Attempt to find a filesystem alias.
277  Filesystem *pFs = lookupFilesystem(left);
278  if (pFs)
279  {
280  pResult = pFs->find(right);
281 #if VFS_WITH_LRU_CACHES
282  if (pResult)
283  {
284  m_FindCache.store(path, pResult);
285  }
286 #endif
287  }
288 
289 #if VFS_WITH_LRU_CACHES
290  }
291 #endif
292  }
293 
294  // NOTICE("find: " << path << " -> " << pResult);
295  return pResult;
296 }
297 
299 {
301  *p = callback;
302  m_ProbeCallbacks.pushBack(p);
303 }
304 
306 {
307  MountCallback *p = new MountCallback;
308  *p = callback;
309  m_MountCallbacks.pushBack(p);
310 }
311 
312 bool VFS::createFile(const String &path, uint32_t mask, File *pStartNode)
313 {
314  // Search for a colon.
315  ssize_t colon = findColon(path);
316  if (colon < 0)
317  {
318  // Pass directly through to the filesystem, if one specified.
319  if (!pStartNode)
320  return false;
321  else
322  return pStartNode->getFilesystem()->createFile(
323  path, mask, pStartNode);
324  }
325  else
326  {
327  StringView left, right;
328  splitPathOnColon(colon, path, left, right);
329 
330  // Attempt to find a filesystem alias.
331  Filesystem *pFs = lookupFilesystem(left);
332  if (!pFs)
333  return false;
334  return pFs->createFile(right, mask, 0);
335  }
336 }
337 
338 bool VFS::createDirectory(const String &path, uint32_t mask, File *pStartNode)
339 {
340  // Search for a colon.
341  ssize_t colon = findColon(path);
342  if (colon < 0)
343  {
344  // Pass directly through to the filesystem, if one specified.
345  if (!pStartNode)
346  {
347  return false;
348  }
349  else
350  {
351  return pStartNode->getFilesystem()->createDirectory(
352  path, mask, pStartNode);
353  }
354  }
355  else
356  {
357  StringView left, right;
358  splitPathOnColon(colon, path, left, right);
359 
360  // Attempt to find a filesystem alias.
361  Filesystem *pFs = lookupFilesystem(left);
362  if (!pFs)
363  {
364  return false;
365  }
366  return pFs->createDirectory(right, mask, 0);
367  }
368 }
369 
371  const String &path, const String &value, File *pStartNode)
372 {
373  // Search for a colon.
374  ssize_t colon = findColon(path);
375  if (colon < 0)
376  {
377  // Pass directly through to the filesystem, if one specified.
378  if (!pStartNode)
379  return false;
380  else
381  return pStartNode->getFilesystem()->createSymlink(
382  path, value, pStartNode);
383  }
384  else
385  {
386  StringView left, right;
387  splitPathOnColon(colon, path, left, right);
388 
389  // Attempt to find a filesystem alias.
390  Filesystem *pFs = lookupFilesystem(left);
391  if (!pFs)
392  return false;
393  return pFs->createSymlink(right, value, 0);
394  }
395 }
396 
397 bool VFS::createLink(const String &path, File *target, File *pStartNode)
398 {
399  // Search for a colon.
400  ssize_t colon = findColon(path);
401  if (colon < 0)
402  {
403  // Pass directly through to the filesystem, if one specified.
404  if (!pStartNode)
405  return false;
406  else
407  return pStartNode->getFilesystem()->createLink(
408  path, target, pStartNode);
409  }
410  else
411  {
412  StringView left, right;
413  splitPathOnColon(colon, path, left, right);
414 
415  // Attempt to find a filesystem alias.
416  Filesystem *pFs = lookupFilesystem(left);
417  if (!pFs)
418  return false;
419  return pFs->createLink(right, target, 0);
420  }
421 }
422 
423 bool VFS::remove(const String &path, File *pStartNode)
424 {
425  // Search for a colon.
426  ssize_t colon = findColon(path);
427  if (colon < 0)
428  {
429  // Pass directly through to the filesystem, if one specified.
430  if (!pStartNode)
431  return false;
432  else
433  return pStartNode->getFilesystem()->remove(path, pStartNode);
434  }
435  else
436  {
437  StringView left, right;
438  splitPathOnColon(colon, path, left, right);
439 
440  // Attempt to find a filesystem alias.
441  Filesystem *pFs = lookupFilesystem(left);
442  if (!pFs)
443  return false;
444  return pFs->remove(right, 0);
445  }
446 }
447 
448 bool VFS::checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
449 {
450  return true;
451 
452 #ifdef VFS_STANDALONE
453  // We don't check permissions on standalone builds of the VFS.
454  return true;
455 #else
456  if (!pFile)
457  {
458  // The error for a null file is not EPERM or EACCESS.
459  return true;
460  }
461 
462  Process *pProcess =
463  Processor::information().getCurrentThread()->getParent();
464 
465  int64_t fuid = pFile->getUid();
466  int64_t fgid = pFile->getGid();
467 
468  int64_t processUid = pProcess->getEffectiveUserId();
469  if (processUid < 0)
470  {
471  processUid = pProcess->getUserId();
472  }
473 
474  int64_t processGid = pProcess->getEffectiveGroupId();
475  if (processGid < 0)
476  {
477  processGid = pProcess->getGroupId();
478  }
479 
480  uint32_t check = 0;
481  uint32_t permissions = pFile->getPermissions();
482 
483  if (fuid == processUid)
484  {
485  check = (permissions >> FILE_UBITS) & 0x7;
486  }
487  else if (fgid == processGid)
488  {
489  check = (permissions >> FILE_GBITS) & 0x7;
490  }
491  else
492  {
493  Vector<int64_t> supplementalGroups;
494  pProcess->getSupplementalGroupIds(supplementalGroups);
495 
496  for (auto it : supplementalGroups)
497  {
498  if (it == fgid)
499  {
500  check = (permissions >> FILE_GBITS) & 0x7;
501  break;
502  }
503  }
504 
505  if (!check)
506  {
507  check = (permissions >> FILE_OBITS) & 0x7;
508  }
509  }
510 
511  if (!check)
512  {
513  NOTICE(
514  "no permissions? perms=" << Oct << permissions
515  << ", check=" << check);
516  return false;
517  }
518 
519  // Needed permissions.
520  uint32_t needed = (bRead ? FILE_UR : 0) | (bWrite ? FILE_UW : 0) |
521  (bExecute ? FILE_UX : 0);
522  if ((check & needed) != needed)
523  {
524  NOTICE(
525  "VFS::checkAccess: needed " << Oct << needed << ", check was "
526  << check);
527  SYSCALL_ERROR(PermissionDenied);
528  return false;
529  }
530 
531  return true;
532 #endif
533 }
534 
535 ssize_t VFS::findColon(const String &path)
536 {
537  // Search for a colon.
538  bool bColon = false;
539  size_t i;
540  ssize_t result = 0;
541  size_t len = path.length();
542  for (i = 0; i < len; i++, result++)
543  {
544  char c = path[i];
545 
546  // Look for the UTF-8 'ยป'; 0xC2 0xBB.
547  if (c == '\xc2')
548  {
549  if (path[i + 1] == '\xbb')
550  {
551  bColon = true;
552  break;
553  }
554  }
555  else if (c == '/')
556  {
557  // The separator must come before any slashes in the path.
558  break;
559  }
560  }
561 
562  return bColon ? result : -1;
563 }
564 
565 #ifndef VFS_STANDALONE
566 static bool initVFS()
567 {
568  return true;
569 }
570 
571 static void destroyVFS()
572 {
573 }
574 
575 MODULE_INFO("vfs", &initVFS, &destroyVFS, "users");
576 #endif
void store(const K &key, const T &object)
Definition: LruCache.h:78
void removeAlias(const String &alias)
Definition: VFS.cc:179
File * find(const String &path, File *pStartNode=0)
Definition: VFS.cc:243
Iterator end()
Definition: Tree.h:348
void pushBack(const T &value)
Definition: List.h:232
void(* MountCallback)()
Definition: VFS.h:61
StringView substring(size_t start, size_t end, bool hashed=HASH_STRINGVIEWS_BY_DEFAULT) const
Definition: StringView.cc:131
bool contains(const K &k) const
Definition: HashTable.h:165
bool createLink(const String &path, File *target, File *pStartNode=0)
Definition: VFS.cc:397
bool createLink(const StringView &path, File *target, File *pStartNode=0)
Definition: Filesystem.cc:188
void addAlias(Filesystem *pFs, const String &alias)
Definition: VFS.cc:123
size_t m_nAliases
Definition: Filesystem.h:155
~VFS()
Definition: VFS.cc:65
virtual int64_t getUserId() const
Definition: Process.cc:320
bool createFile(const StringView &path, uint32_t mask, File *pStartNode=0)
Definition: Filesystem.cc:75
void removeAllAliases(Filesystem *pFs, bool canDelete=true)
Definition: VFS.cc:185
void addMountCallback(MountCallback callback)
Definition: VFS.cc:305
Definition: String.h:49
Definition: Result.h:36
Filesystem * lookupFilesystem(const String &alias)
Definition: VFS.cc:221
void addProbeCallback(Filesystem::ProbeCallback callback)
Definition: VFS.cc:298
static ProcessorInformation & information()
Definition: Processor.cc:45
static VFS & instance()
Definition: VFS.cc:56
Definition: Disk.h:32
bool remove(const StringView &path, File *pStartNode=0)
Definition: Filesystem.cc:234
Iterator erase(Iterator &at)
Definition: HashTable.h:443
Filesystem *(* ProbeCallback)(Disk *)
Definition: Filesystem.h:58
Definition: VFS.h:57
bool aliasExists(const String &alias)
Definition: VFS.cc:174
bool createSymlink(const String &path, const String &value, File *pStartNode=0)
Definition: VFS.cc:370
StringView view() const
Definition: String.cc:880
Definition: List.h:64
virtual File * find(const StringView &path)
Definition: Filesystem.cc:53
void insert(const K &key, const E &value)
Definition: Tree.h:173
Iterator begin()
Definition: Tree.h:326
#define NOTICE(text)
Definition: Log.h:74
::Iterator< T, node_t > Iterator
Definition: List.h:71
bool insert(const K &k, const V &v)
Definition: HashTable.h:264
bool createDirectory(const String &path, uint32_t mask, File *pStartNode=0)
Definition: VFS.cc:338
Iterator begin()
Definition: List.h:123
bool createDirectory(const StringView &path, uint32_t mask, File *pStartNode=0)
Definition: Filesystem.cc:112
bool createFile(const String &path, uint32_t mask, File *pStartNode=0)
Definition: VFS.cc:312
bool remove(const String &path, File *pStartNode=0)
Definition: VFS.cc:423
Definition: Log.h:140
LookupResult lookup(const K &k) const
Definition: HashTable.h:200
void remove(const K &k)
Definition: HashTable.h:323
VFS()
Definition: VFS.cc:61
String getUniqueAlias(const String &alias)
Definition: VFS.cc:153
virtual String getVolumeLabel() const =0
bool mount(Disk *pDisk, String &alias)
Definition: VFS.cc:88
void remove(const K &key)
Definition: Tree.h:242
static VFS m_Instance
Definition: VFS.h:161
Definition: File.h:66
Iterator end()
Definition: List.h:135
bool get(const K &key, T &object)
Definition: LruCache.h:55
bool createSymlink(const StringView &path, const String &value, File *pStartNode=0)
Definition: Filesystem.cc:149
E lookup(const K &key) const
Definition: Tree.h:192
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
Definition: VFS.cc:448