Changeset View
Changeset View
Standalone View
Standalone View
source/lib/file/vfs/vfs_lookup.cpp
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | static Status CreateDirectory(const OsPath& path) | ||||
WARN_RETURN(StatusFromErrno()); | WARN_RETURN(StatusFromErrno()); | ||||
} | } | ||||
Status vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDirectory*& directory, VfsFile** pfile, size_t flags) | Status vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDirectory*& directory, VfsFile** pfile, size_t flags) | ||||
{ | { | ||||
// extract and validate flags (ensure no unknown bits are set) | // extract and validate flags (ensure no unknown bits are set) | ||||
const bool addMissingDirectories = (flags & VFS_LOOKUP_ADD) != 0; | const bool addMissingDirectories = (flags & VFS_LOOKUP_ADD) != 0; | ||||
const bool createMissingDirectories = (flags & VFS_LOOKUP_CREATE) != 0; | |||||
const bool skipPopulate = (flags & VFS_LOOKUP_SKIP_POPULATE) != 0; | const bool skipPopulate = (flags & VFS_LOOKUP_SKIP_POPULATE) != 0; | ||||
const bool createAlways = (flags & VFS_LOOKUP_CREATE_ALWAYS) != 0; | const bool realPath = (flags & VFS_LOOKUP_REAL_PATH) != 0; | ||||
ENSURE((flags & ~(VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE|VFS_LOOKUP_SKIP_POPULATE|VFS_LOOKUP_CREATE_ALWAYS)) == 0); | ENSURE((flags & ~(VFS_LOOKUP_ADD|VFS_LOOKUP_SKIP_POPULATE|VFS_LOOKUP_REAL_PATH)) == 0); | ||||
directory = startDirectory; | directory = startDirectory; | ||||
if(pfile) | if (pfile) | ||||
*pfile = 0; | *pfile = 0; | ||||
if(!skipPopulate) | if (!skipPopulate) | ||||
RETURN_STATUS_IF_ERR(vfs_Populate(directory)); | RETURN_STATUS_IF_ERR(vfs_Populate(directory)); | ||||
// early-out for pathname == "" when mounting into VFS root | // early-out for pathname == "" when mounting into VFS root | ||||
if(pathname.empty()) // (prevent iterator error in loop end condition) | if (pathname.empty()) // (prevent iterator error in loop end condition) | ||||
{ | { | ||||
if(pfile) // preserve a guarantee that if pfile then we either return an error or set *pfile | if (pfile) // preserve a guarantee that if pfile then we either return an error or set *pfile | ||||
return ERR::VFS_FILE_NOT_FOUND; | return ERR::VFS_FILE_NOT_FOUND; | ||||
else | else | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
// for each directory component: | // for each directory component: | ||||
size_t pos = 0; // (needed outside of loop) | size_t pos = 0; // (needed outside of loop) | ||||
for(;;) | for(;;) | ||||
{ | { | ||||
const size_t nextSlash = pathname.string().find_first_of('/', pos); | const size_t nextSlash = pathname.string().find_first_of('/', pos); | ||||
if(nextSlash == VfsPath::String::npos) | if (nextSlash == VfsPath::String::npos) | ||||
break; | break; | ||||
const VfsPath subdirectoryName = pathname.string().substr(pos, nextSlash-pos); | const VfsPath subdirectoryName = pathname.string().substr(pos, nextSlash-pos); | ||||
pos = nextSlash+1; | pos = nextSlash+1; | ||||
VfsDirectory* subdirectory = directory->GetSubdirectory(subdirectoryName); | VfsDirectory* subdirectory = directory->GetSubdirectory(subdirectoryName); | ||||
if(!subdirectory) | if (!subdirectory) | ||||
{ | { | ||||
if(addMissingDirectories) | if (addMissingDirectories) | ||||
subdirectory = directory->AddSubdirectory(subdirectoryName); | subdirectory = directory->AddSubdirectory(subdirectoryName); | ||||
else | else | ||||
return ERR::VFS_DIR_NOT_FOUND; // NOWARN | return ERR::VFS_DIR_NOT_FOUND; // NOWARN | ||||
} | } | ||||
PRealDirectory realDir = directory->AssociatedDirectory(); | |||||
if(createMissingDirectories && (!subdirectory->AssociatedDirectory() | // When looking for a real path, create a matching real directory if there are none, | ||||
|| (createAlways && (subdirectory->AssociatedDirectory()->Flags() & VFS_MOUNT_REPLACEABLE) != 0))) | // or overwrite the existing if the parent has higher priority than the child. | ||||
if (realPath && | |||||
(!subdirectory->AssociatedDirectory() || | |||||
(realDir && realDir->Priority() > subdirectory->AssociatedDirectory()->Priority()))) | |||||
{ | { | ||||
OsPath currentPath; | OsPath currentPath; | ||||
if(directory->AssociatedDirectory()) // (is NULL when mounting into root) | if (directory->AssociatedDirectory()) // (is NULL when mounting into root) | ||||
currentPath = directory->AssociatedDirectory()->Path(); | currentPath = directory->AssociatedDirectory()->Path(); | ||||
currentPath = currentPath / subdirectoryName; | currentPath = currentPath / subdirectoryName; | ||||
// Only actually create the directory if we're in LOOKUP_ADD mode. | |||||
//if (addMissingDirectories) | |||||
RETURN_STATUS_IF_ERR(CreateDirectory(currentPath)); | RETURN_STATUS_IF_ERR(CreateDirectory(currentPath)); | ||||
PRealDirectory realDirectory(new RealDirectory(currentPath, 0, 0)); | // Propagate priority and flags to the newly created subdirectory. | ||||
PRealDirectory realDirectory(new RealDirectory(currentPath, | |||||
realDir ? realDir->Priority() : 0, | |||||
realDir ? realDir->Flags() : 0) | |||||
); | |||||
RETURN_STATUS_IF_ERR(vfs_Attach(subdirectory, realDirectory)); | RETURN_STATUS_IF_ERR(vfs_Attach(subdirectory, realDirectory)); | ||||
} | } | ||||
if(!skipPopulate) | if (!skipPopulate) | ||||
RETURN_STATUS_IF_ERR(vfs_Populate(subdirectory)); | RETURN_STATUS_IF_ERR(vfs_Populate(subdirectory)); | ||||
directory = subdirectory; | directory = subdirectory; | ||||
} | } | ||||
if (realPath && !directory->AssociatedDirectory()) | |||||
return ERR::VFS_DIR_NOT_FOUND; | |||||
if(pfile) | if (pfile) | ||||
{ | { | ||||
ENSURE(!pathname.IsDirectory()); | ENSURE(!pathname.IsDirectory()); | ||||
const VfsPath filename = pathname.string().substr(pos); | const VfsPath filename = pathname.string().substr(pos); | ||||
*pfile = directory->GetFile(filename); | *pfile = directory->GetFile(filename); | ||||
if(!*pfile) | if (!*pfile) | ||||
return ERR::VFS_FILE_NOT_FOUND; // NOWARN | return ERR::VFS_FILE_NOT_FOUND; // NOWARN | ||||
} | } | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } |
Wildfire Games · Phabricator