Changeset View
Changeset View
Standalone View
Standalone View
source/lib/file/vfs/vfs.cpp
Show All 18 Lines | |||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "lib/file/vfs/vfs.h" | #include "lib/file/vfs/vfs.h" | ||||
#include "lib/allocators/shared_ptr.h" | #include "lib/allocators/shared_ptr.h" | ||||
#include "lib/posix/posix_pthread.h" | |||||
#include "lib/file/file_system.h" | #include "lib/file/file_system.h" | ||||
#include "lib/file/common/file_stats.h" | #include "lib/file/common/file_stats.h" | ||||
#include "lib/file/common/trace.h" | #include "lib/file/common/trace.h" | ||||
#include "lib/file/archive/archive.h" | #include "lib/file/archive/archive.h" | ||||
#include "lib/file/io/io.h" | #include "lib/file/io/io.h" | ||||
#include "lib/file/vfs/vfs_tree.h" | #include "lib/file/vfs/vfs_tree.h" | ||||
#include "lib/file/vfs/vfs_lookup.h" | #include "lib/file/vfs/vfs_lookup.h" | ||||
#include "lib/file/vfs/vfs_populate.h" | #include "lib/file/vfs/vfs_populate.h" | ||||
#include <thread> | |||||
static const StatusDefinition vfsStatusDefinitions[] = { | static const StatusDefinition vfsStatusDefinitions[] = { | ||||
{ ERR::VFS_DIR_NOT_FOUND, L"VFS directory not found" }, | { ERR::VFS_DIR_NOT_FOUND, L"VFS directory not found" }, | ||||
{ ERR::VFS_FILE_NOT_FOUND, L"VFS file not found" }, | { ERR::VFS_FILE_NOT_FOUND, L"VFS file not found" }, | ||||
{ ERR::VFS_ALREADY_MOUNTED, L"VFS path already mounted" } | { ERR::VFS_ALREADY_MOUNTED, L"VFS path already mounted" } | ||||
}; | }; | ||||
STATUS_ADD_DEFINITIONS(vfsStatusDefinitions); | STATUS_ADD_DEFINITIONS(vfsStatusDefinitions); | ||||
static pthread_mutex_t vfs_mutex = PTHREAD_MUTEX_INITIALIZER; | static std::mutex vfs_mutex; | ||||
Stan: Missing an include ? | |||||
namespace { | |||||
struct ScopedLock | |||||
{ | |||||
ScopedLock() { pthread_mutex_lock(&vfs_mutex); } | |||||
~ScopedLock() { pthread_mutex_unlock(&vfs_mutex); } | |||||
}; | |||||
} // namespace | |||||
class VFS : public IVFS | class VFS : public IVFS | ||||
{ | { | ||||
public: | public: | ||||
VFS() : m_trace(CreateDummyTrace(8*MiB)) | VFS() : m_trace(CreateDummyTrace(8*MiB)) | ||||
{ | { | ||||
} | } | ||||
virtual Status Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags /* = 0 */, size_t priority /* = 0 */) | virtual Status Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags /* = 0 */, size_t priority /* = 0 */) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
if(!DirectoryExists(path)) | if(!DirectoryExists(path)) | ||||
{ | { | ||||
if(flags & VFS_MOUNT_MUST_EXIST) | if(flags & VFS_MOUNT_MUST_EXIST) | ||||
return ERR::VFS_DIR_NOT_FOUND; // NOWARN | return ERR::VFS_DIR_NOT_FOUND; // NOWARN | ||||
else | else | ||||
RETURN_STATUS_IF_ERR(CreateDirectories(path, 0700)); | RETURN_STATUS_IF_ERR(CreateDirectories(path, 0700)); | ||||
} | } | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(mountPoint, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_SKIP_POPULATE)); | WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(mountPoint, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_SKIP_POPULATE)); | ||||
PRealDirectory realDirectory(new RealDirectory(path, priority, flags)); | PRealDirectory realDirectory(new RealDirectory(path, priority, flags)); | ||||
RETURN_STATUS_IF_ERR(vfs_Attach(directory, realDirectory)); | RETURN_STATUS_IF_ERR(vfs_Attach(directory, realDirectory)); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status GetFileInfo(const VfsPath& pathname, CFileInfo* pfileInfo) const | virtual Status GetFileInfo(const VfsPath& pathname, CFileInfo* pfileInfo) const | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
VfsFile* file; | VfsFile* file; | ||||
Status ret = vfs_Lookup(pathname, &m_rootDirectory, directory, &file); | Status ret = vfs_Lookup(pathname, &m_rootDirectory, directory, &file); | ||||
if(!pfileInfo) // just indicate if the file exists without raising warnings. | if(!pfileInfo) // just indicate if the file exists without raising warnings. | ||||
return ret; | return ret; | ||||
WARN_RETURN_STATUS_IF_ERR(ret); | WARN_RETURN_STATUS_IF_ERR(ret); | ||||
*pfileInfo = CFileInfo(file->Name(), file->Size(), file->MTime()); | *pfileInfo = CFileInfo(file->Name(), file->Size(), file->MTime()); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status GetFilePriority(const VfsPath& pathname, size_t* ppriority) const | virtual Status GetFilePriority(const VfsPath& pathname, size_t* ppriority) const | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; VfsFile* file; | VfsDirectory* directory; VfsFile* file; | ||||
RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | ||||
*ppriority = file->Priority(); | *ppriority = file->Priority(); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status GetDirectoryEntries(const VfsPath& path, CFileInfos* fileInfos, DirectoryNames* subdirectoryNames) const | virtual Status GetDirectoryEntries(const VfsPath& path, CFileInfos* fileInfos, DirectoryNames* subdirectoryNames) const | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
RETURN_STATUS_IF_ERR(vfs_Lookup(path, &m_rootDirectory, directory, 0)); | RETURN_STATUS_IF_ERR(vfs_Lookup(path, &m_rootDirectory, directory, 0)); | ||||
if(fileInfos) | if(fileInfos) | ||||
{ | { | ||||
const VfsDirectory::VfsFiles& files = directory->Files(); | const VfsDirectory::VfsFiles& files = directory->Files(); | ||||
fileInfos->clear(); | fileInfos->clear(); | ||||
fileInfos->reserve(files.size()); | fileInfos->reserve(files.size()); | ||||
Show All 13 Lines | if(subdirectoryNames) | ||||
subdirectoryNames->push_back(it->first); | subdirectoryNames->push_back(it->first); | ||||
} | } | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status CreateFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) | virtual Status CreateFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
Status st; | Status st; | ||||
st = vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE|VFS_LOOKUP_CREATE_ALWAYS); | st = vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE|VFS_LOOKUP_CREATE_ALWAYS); | ||||
if (st == ERR::FILE_ACCESS) | if (st == ERR::FILE_ACCESS) | ||||
return ERR::FILE_ACCESS; | return ERR::FILE_ACCESS; | ||||
WARN_RETURN_STATUS_IF_ERR(st); | WARN_RETURN_STATUS_IF_ERR(st); | ||||
const PRealDirectory& realDirectory = directory->AssociatedDirectory(); | const PRealDirectory& realDirectory = directory->AssociatedDirectory(); | ||||
const OsPath name = pathname.Filename(); | const OsPath name = pathname.Filename(); | ||||
RETURN_STATUS_IF_ERR(realDirectory->Store(name, fileContents, size)); | RETURN_STATUS_IF_ERR(realDirectory->Store(name, fileContents, size)); | ||||
const VfsFile file(name, size, time(0), realDirectory->Priority(), realDirectory); | const VfsFile file(name, size, time(0), realDirectory->Priority(), realDirectory); | ||||
directory->AddFile(file); | directory->AddFile(file); | ||||
m_trace->NotifyStore(pathname, size); | m_trace->NotifyStore(pathname, size); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status ReplaceFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) | virtual Status ReplaceFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) | ||||
{ | { | ||||
ScopedLock s; | std::unique_lock<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
VfsFile* file; | VfsFile* file; | ||||
Status st; | Status st; | ||||
st = vfs_Lookup(pathname, &m_rootDirectory, directory, &file, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE); | st = vfs_Lookup(pathname, &m_rootDirectory, directory, &file, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE); | ||||
// There is no such file, create it. | // There is no such file, create it. | ||||
if (st == ERR::VFS_FILE_NOT_FOUND) | if (st == ERR::VFS_FILE_NOT_FOUND) | ||||
{ | { | ||||
s.~ScopedLock(); | lock.unlock(); | ||||
return CreateFile(pathname, fileContents, size); | return CreateFile(pathname, fileContents, size); | ||||
} | } | ||||
WARN_RETURN_STATUS_IF_ERR(st); | WARN_RETURN_STATUS_IF_ERR(st); | ||||
RealDirectory realDirectory(file->Loader()->Path(), file->Priority(), directory->AssociatedDirectory()->Flags()); | RealDirectory realDirectory(file->Loader()->Path(), file->Priority(), directory->AssociatedDirectory()->Flags()); | ||||
RETURN_STATUS_IF_ERR(realDirectory.Store(pathname.Filename(), fileContents, size)); | RETURN_STATUS_IF_ERR(realDirectory.Store(pathname.Filename(), fileContents, size)); | ||||
directory->AddFile(*file); | directory->AddFile(*file); | ||||
m_trace->NotifyStore(pathname, size); | m_trace->NotifyStore(pathname, size); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status LoadFile(const VfsPath& pathname, shared_ptr<u8>& fileContents, size_t& size) | virtual Status LoadFile(const VfsPath& pathname, shared_ptr<u8>& fileContents, size_t& size) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; VfsFile* file; | VfsDirectory* directory; VfsFile* file; | ||||
// per 2010-05-01 meeting, this shouldn't raise 'scary error | // per 2010-05-01 meeting, this shouldn't raise 'scary error | ||||
// dialogs', which might fail to display the culprit pathname | // dialogs', which might fail to display the culprit pathname | ||||
// instead, callers should log the error, including pathname. | // instead, callers should log the error, including pathname. | ||||
RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | ||||
fileContents = DummySharedPtr((u8*)0); | fileContents = DummySharedPtr((u8*)0); | ||||
size = file->Size(); | size = file->Size(); | ||||
RETURN_STATUS_IF_ERR(AllocateAligned(fileContents, size, maxSectorSize)); | RETURN_STATUS_IF_ERR(AllocateAligned(fileContents, size, maxSectorSize)); | ||||
RETURN_STATUS_IF_ERR(file->Loader()->Load(file->Name(), fileContents, file->Size())); | RETURN_STATUS_IF_ERR(file->Loader()->Load(file->Name(), fileContents, file->Size())); | ||||
stats_io_user_request(size); | stats_io_user_request(size); | ||||
m_trace->NotifyLoad(pathname, size); | m_trace->NotifyLoad(pathname, size); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual std::wstring TextRepresentation() const | virtual std::wstring TextRepresentation() const | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
std::wstring textRepresentation; | std::wstring textRepresentation; | ||||
textRepresentation.reserve(100*KiB); | textRepresentation.reserve(100*KiB); | ||||
DirectoryDescriptionR(textRepresentation, m_rootDirectory, 0); | DirectoryDescriptionR(textRepresentation, m_rootDirectory, 0); | ||||
return textRepresentation; | return textRepresentation; | ||||
} | } | ||||
virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname) | virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; VfsFile* file; | VfsDirectory* directory; VfsFile* file; | ||||
WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | ||||
realPathname = file->Loader()->Path() / pathname.Filename(); | realPathname = file->Loader()->Path() / pathname.Filename(); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname) | virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, NULL)); | WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, NULL)); | ||||
realPathname = directory->AssociatedDirectory()->Path(); | realPathname = directory->AssociatedDirectory()->Path(); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status GetVirtualPath(const OsPath& realPathname, VfsPath& pathname) | virtual Status GetVirtualPath(const OsPath& realPathname, VfsPath& pathname) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
const OsPath realPath = realPathname.Parent()/""; | const OsPath realPath = realPathname.Parent()/""; | ||||
VfsPath path; | VfsPath path; | ||||
RETURN_STATUS_IF_ERR(FindRealPathR(realPath, m_rootDirectory, L"", path)); | RETURN_STATUS_IF_ERR(FindRealPathR(realPath, m_rootDirectory, L"", path)); | ||||
pathname = path / realPathname.Filename(); | pathname = path / realPathname.Filename(); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status RemoveFile(const VfsPath& pathname) | virtual Status RemoveFile(const VfsPath& pathname) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; VfsFile* file; | VfsDirectory* directory; VfsFile* file; | ||||
RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file)); | ||||
directory->RemoveFile(file->Name()); | directory->RemoveFile(file->Name()); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual Status RepopulateDirectory(const VfsPath& path) | virtual Status RepopulateDirectory(const VfsPath& path) | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
VfsDirectory* directory; | VfsDirectory* directory; | ||||
RETURN_STATUS_IF_ERR(vfs_Lookup(path, &m_rootDirectory, directory, 0)); | RETURN_STATUS_IF_ERR(vfs_Lookup(path, &m_rootDirectory, directory, 0)); | ||||
directory->RequestRepopulate(); | directory->RequestRepopulate(); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
virtual void Clear() | virtual void Clear() | ||||
{ | { | ||||
ScopedLock s; | std::lock_guard<std::mutex> lock(vfs_mutex); | ||||
m_rootDirectory.Clear(); | m_rootDirectory.Clear(); | ||||
} | } | ||||
private: | private: | ||||
Status FindRealPathR(const OsPath& realPath, const VfsDirectory& directory, const VfsPath& curPath, VfsPath& path) | Status FindRealPathR(const OsPath& realPath, const VfsDirectory& directory, const VfsPath& curPath, VfsPath& path) | ||||
{ | { | ||||
PRealDirectory realDirectory = directory.AssociatedDirectory(); | PRealDirectory realDirectory = directory.AssociatedDirectory(); | ||||
if(realDirectory && realDirectory->Path() == realPath) | if(realDirectory && realDirectory->Path() == realPath) | ||||
Show All 28 Lines |
Wildfire Games · Phabricator
Missing an include ?