Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vfs_lookup.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2013 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * look up directories/files by traversing path components.
25  */
26 
27 #include "precompiled.h"
29 
31 
32 #include "lib/sysdep/filesystem.h"
33 #include "lib/file/file.h"
34 #include "lib/file/vfs/vfs.h" // error codes
35 #include "lib/file/vfs/vfs_tree.h"
37 
38 #include "lib/timer.h"
39 
40 
41 static Status CreateDirectory(const OsPath& path)
42 {
43  {
44  const mode_t mode = S_IRWXU; // 0700 as prescribed by XDG basedir
45  const int ret = wmkdir(path, mode);
46  if(ret == 0) // success
47  return INFO::OK;
48  }
49 
50  // failed because the directory already exists. this can happen
51  // when the first vfs_Lookup has addMissingDirectories &&
52  // !createMissingDirectories, and the directory is subsequently
53  // created. return 'success' to attach the existing directory..
54  if(errno == EEXIST)
55  {
56  // but first ensure it's really a directory (otherwise, a
57  // file is "in the way" and needs to be deleted)
58  struct stat s;
59  const int ret = wstat(path, &s);
60  ENSURE(ret == 0); // (wmkdir said it existed)
61  ENSURE(S_ISDIR(s.st_mode));
62  return INFO::OK;
63  }
64 
65  if (errno == EACCES)
66  return ERR::FILE_ACCESS;
67 
68  // unexpected failure
69  debug_printf(L"wmkdir failed with errno=%d\n", errno);
72 }
73 
74 
75 Status vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDirectory*& directory, VfsFile** pfile, size_t flags)
76 {
77  // extract and validate flags (ensure no unknown bits are set)
78  const bool addMissingDirectories = (flags & VFS_LOOKUP_ADD) != 0;
79  const bool createMissingDirectories = (flags & VFS_LOOKUP_CREATE) != 0;
80  const bool skipPopulate = (flags & VFS_LOOKUP_SKIP_POPULATE) != 0;
81  const bool createAlways = (flags & VFS_LOOKUP_CREATE_ALWAYS) != 0;
83 
84  directory = startDirectory;
85  if(pfile)
86  *pfile = 0;
87 
88  if(!skipPopulate)
90 
91  // early-out for pathname == "" when mounting into VFS root
92  if(pathname.empty()) // (prevent iterator error in loop end condition)
93  {
94  if(pfile) // preserve a guarantee that if pfile then we either return an error or set *pfile
96  else
97  return INFO::OK;
98  }
99 
100  // for each directory component:
101  size_t pos = 0; // (needed outside of loop)
102  for(;;)
103  {
104  const size_t nextSlash = pathname.string().find_first_of('/', pos);
105  if(nextSlash == VfsPath::String::npos)
106  break;
107  const VfsPath subdirectoryName = pathname.string().substr(pos, nextSlash-pos);
108  pos = nextSlash+1;
109 
110  VfsDirectory* subdirectory = directory->GetSubdirectory(subdirectoryName);
111  if(!subdirectory)
112  {
113  if(addMissingDirectories)
114  subdirectory = directory->AddSubdirectory(subdirectoryName);
115  else
116  return ERR::VFS_DIR_NOT_FOUND; // NOWARN
117  }
118 
119  if(createMissingDirectories && (!subdirectory->AssociatedDirectory()
120  || (createAlways && (subdirectory->AssociatedDirectory()->Flags() & VFS_MOUNT_REPLACEABLE) != 0)))
121  {
122  OsPath currentPath;
123  if(directory->AssociatedDirectory()) // (is NULL when mounting into root)
124  currentPath = directory->AssociatedDirectory()->Path();
125  currentPath = currentPath / subdirectoryName;
126 
128 
129  PRealDirectory realDirectory(new RealDirectory(currentPath, 0, 0));
130  RETURN_STATUS_IF_ERR(vfs_Attach(subdirectory, realDirectory));
131  }
132 
133  if(!skipPopulate)
134  RETURN_STATUS_IF_ERR(vfs_Populate(subdirectory));
135 
136  directory = subdirectory;
137  }
138 
139  if(pfile)
140  {
141  ENSURE(!pathname.IsDirectory());
142  const VfsPath filename = pathname.string().substr(pos);
143  *pfile = directory->GetFile(filename);
144  if(!*pfile)
145  return ERR::VFS_FILE_NOT_FOUND; // NOWARN
146  }
147 
148  return INFO::OK;
149 }
const Status LOGIC
Definition: status.h:409
Status vfs_Lookup(const VfsPath &pathname, VfsDirectory *startDirectory, VfsDirectory *&directory, VfsFile **pfile, size_t flags)
Resolve a pathname.
Definition: vfs_lookup.cpp:75
const Status OK
Definition: status.h:386
const Status VFS_DIR_NOT_FOUND
Definition: vfs.h:36
bool IsDirectory() const
Definition: path.h:143
const PRealDirectory & AssociatedDirectory() const
Definition: vfs_tree.h:131
VfsFile * GetFile(const VfsPath &name)
Definition: vfs_tree.cpp:117
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:282
Definition: path.h:75
shared_ptr< RealDirectory > PRealDirectory
const String & string() const
Definition: path.h:123
Status vfs_Attach(VfsDirectory *directory, const PRealDirectory &realDirectory)
attach a real directory to a VFS directory.
#define S_IRWXU
Definition: wfilesystem.h:48
const Status VFS_FILE_NOT_FOUND
Definition: vfs.h:37
i64 Status
Error handling system.
Definition: status.h:171
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
Status StatusFromErrno()
Definition: status.cpp:105
Status vfs_Populate(VfsDirectory *directory)
populate the directory from the attached real directory.
bool empty() const
Definition: path.h:118
#define S_ISDIR(m)
Definition: wfilesystem.h:52
LIB_API int wmkdir(const OsPath &path, mode_t mode)
#define WARN_RETURN(status)
Definition: status.h:255
static Status CreateDirectory(const OsPath &path)
Definition: vfs_lookup.cpp:41
const Status FILE_ACCESS
Definition: file.h:35
VfsDirectory * GetSubdirectory(const VfsPath &name)
Definition: vfs_tree.cpp:126
LIB_API int wstat(const OsPath &pathname, struct stat *buf)
VfsDirectory * AddSubdirectory(const VfsPath &name)
Definition: vfs_tree.cpp:103
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
Definition: debug.cpp:142
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276
mark a directory replaceable, so that when writing a file to this path new real directories will be c...
Definition: vfs.h:77