LCOV - code coverage report
Current view: top level - source/lib/file/vfs - vfs.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 100 129 77.5 %
Date: 2023-01-19 00:18:29 Functions: 18 21 85.7 %

          Line data    Source code
       1             : /* Copyright (C) 2021 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             : #include "precompiled.h"
      24             : #include "lib/file/vfs/vfs.h"
      25             : 
      26             : #include "lib/allocators/shared_ptr.h"
      27             : #include "lib/file/file_system.h"
      28             : #include "lib/file/common/file_stats.h"
      29             : #include "lib/file/common/trace.h"
      30             : #include "lib/file/archive/archive.h"
      31             : #include "lib/file/io/io.h"
      32             : #include "lib/file/vfs/vfs_tree.h"
      33             : #include "lib/file/vfs/vfs_lookup.h"
      34             : #include "lib/file/vfs/vfs_populate.h"
      35             : 
      36             : #include <mutex>
      37             : #include <thread>
      38             : 
      39             : static const StatusDefinition vfsStatusDefinitions[] = {
      40             :     { ERR::VFS_DIR_NOT_FOUND, L"VFS directory not found" },
      41             :     { ERR::VFS_FILE_NOT_FOUND, L"VFS file not found" },
      42             :     { ERR::VFS_ALREADY_MOUNTED, L"VFS path already mounted" }
      43             : };
      44           1 : STATUS_ADD_DEFINITIONS(vfsStatusDefinitions);
      45             : 
      46             : static std::mutex vfs_mutex;
      47             : 
      48         166 : class VFS : public IVFS
      49             : {
      50             : public:
      51          83 :     VFS() : m_trace(CreateDummyTrace(8*MiB))
      52             :     {
      53          83 :     }
      54             : 
      55         175 :     virtual Status Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags /* = 0 */, size_t priority /* = 0 */)
      56             :     {
      57         175 :         ENSURE(path.IsDirectory());
      58             : 
      59         350 :         std::lock_guard<std::mutex> lock(vfs_mutex);
      60         175 :         if(!DirectoryExists(path))
      61             :         {
      62          82 :             if(flags & VFS_MOUNT_MUST_EXIST)
      63           0 :                 return ERR::VFS_DIR_NOT_FOUND;  // NOWARN
      64             :             else
      65          82 :                 RETURN_STATUS_IF_ERR(CreateDirectories(path, 0700));
      66             :         }
      67             : 
      68             :         VfsDirectory* directory;
      69         175 :         WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(mountPoint, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_SKIP_POPULATE));
      70             : 
      71         350 :         PRealDirectory realDirectory(new RealDirectory(path, priority, flags));
      72         175 :         RETURN_STATUS_IF_ERR(vfs_Attach(directory, realDirectory));
      73         175 :         return INFO::OK;
      74             :     }
      75             : 
      76        3724 :     virtual Status GetFileInfo(const VfsPath& pathname, CFileInfo* pfileInfo) const
      77             :     {
      78        7448 :         std::lock_guard<std::mutex> lock(vfs_mutex);
      79             :         VfsDirectory* directory;
      80             :         VfsFile* file;
      81             : 
      82        3724 :         Status ret = vfs_Lookup(pathname, &m_rootDirectory, directory, &file);
      83        3724 :         if(!pfileInfo)  // just indicate if the file exists without raising warnings.
      84        3334 :             return ret;
      85         390 :         WARN_RETURN_STATUS_IF_ERR(ret);
      86         390 :         *pfileInfo = CFileInfo(file->Name(), file->Size(), file->MTime());
      87         390 :         return INFO::OK;
      88             :     }
      89             : 
      90         448 :     virtual Status GetFilePriority(const VfsPath& pathname, size_t* ppriority) const
      91             :     {
      92         896 :         std::lock_guard<std::mutex> lock(vfs_mutex);
      93             :         VfsDirectory* directory; VfsFile* file;
      94         448 :         RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file));
      95           0 :         *ppriority = file->Priority();
      96           0 :         return INFO::OK;
      97             :     }
      98             : 
      99         246 :     virtual Status GetDirectoryEntries(const VfsPath& path, CFileInfos* fileInfos, DirectoryNames* subdirectoryNames) const
     100             :     {
     101         492 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     102             :         VfsDirectory* directory;
     103         246 :         RETURN_STATUS_IF_ERR(vfs_Lookup(path, &m_rootDirectory, directory, 0));
     104             : 
     105         220 :         if(fileInfos)
     106             :         {
     107         218 :             const VfsDirectory::VfsFiles& files = directory->Files();
     108         218 :             fileInfos->clear();
     109         218 :             fileInfos->reserve(files.size());
     110        2111 :             for(VfsDirectory::VfsFiles::const_iterator it = files.begin(); it != files.end(); ++it)
     111             :             {
     112        1893 :                 const VfsFile& file = it->second;
     113        1893 :                 fileInfos->push_back(CFileInfo(file.Name(), file.Size(), file.MTime()));
     114             :             }
     115             :         }
     116             : 
     117         220 :         if(subdirectoryNames)
     118             :         {
     119           6 :             const VfsDirectory::VfsSubdirectories& subdirectories = directory->Subdirectories();
     120           6 :             subdirectoryNames->clear();
     121           6 :             subdirectoryNames->reserve(subdirectories.size());
     122           6 :             for(VfsDirectory::VfsSubdirectories::const_iterator it = subdirectories.begin(); it != subdirectories.end(); ++it)
     123           0 :                 subdirectoryNames->push_back(it->first);
     124             :         }
     125             : 
     126         220 :         return INFO::OK;
     127             :     }
     128             : 
     129          96 :     virtual Status CreateFile(const VfsPath& pathname, const std::shared_ptr<u8>& fileContents, size_t size)
     130             :     {
     131         192 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     132             :         VfsDirectory* directory;
     133             :         Status st;
     134          96 :         st = vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_REAL_PATH);
     135          96 :         if (st == ERR::FILE_ACCESS)
     136           0 :             return ERR::FILE_ACCESS;
     137             : 
     138          96 :         WARN_RETURN_STATUS_IF_ERR(st);
     139             : 
     140          96 :         const PRealDirectory& realDirectory = directory->AssociatedDirectory();
     141         192 :         const OsPath name = pathname.Filename();
     142          96 :         RETURN_STATUS_IF_ERR(realDirectory->Store(name, fileContents, size));
     143             : 
     144         192 :         const VfsFile file(name, size, time(0), realDirectory->Priority(), realDirectory);
     145          96 :         directory->AddFile(file);
     146             : 
     147          96 :         m_trace->NotifyStore(pathname, size);
     148          96 :         return INFO::OK;
     149             :     }
     150             : 
     151        2842 :     virtual Status LoadFile(const VfsPath& pathname, std::shared_ptr<u8>& fileContents, size_t& size)
     152             :     {
     153        5684 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     154             : 
     155             :         VfsDirectory* directory; VfsFile* file;
     156             :         // per 2010-05-01 meeting, this shouldn't raise 'scary error
     157             :         // dialogs', which might fail to display the culprit pathname
     158             :         // instead, callers should log the error, including pathname.
     159        2842 :         RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file));
     160             : 
     161        2836 :         fileContents = DummySharedPtr((u8*)0);
     162        2836 :         size = file->Size();
     163             : 
     164        2836 :         RETURN_STATUS_IF_ERR(AllocateAligned(fileContents, size, maxSectorSize));
     165        2836 :         RETURN_STATUS_IF_ERR(file->Loader()->Load(file->Name(), fileContents, file->Size()));
     166             : 
     167             :         stats_io_user_request(size);
     168        2836 :         m_trace->NotifyLoad(pathname, size);
     169             : 
     170        2836 :         return INFO::OK;
     171             :     }
     172             : 
     173           1 :     virtual std::wstring TextRepresentation() const
     174             :     {
     175           2 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     176           1 :         std::wstring textRepresentation;
     177           1 :         textRepresentation.reserve(100*KiB);
     178           1 :         DirectoryDescriptionR(textRepresentation, m_rootDirectory, 0);
     179           2 :         return textRepresentation;
     180             :     }
     181             : 
     182         379 :     virtual Status GetOriginalPath(const VfsPath& pathname, OsPath& realPathname)
     183             :     {
     184         758 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     185             :         VfsDirectory* directory; VfsFile* file;
     186         379 :         WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file));
     187         379 :         realPathname = file->Loader()->Path() / pathname.Filename();
     188         379 :         return INFO::OK;
     189             :     }
     190             : 
     191           2 :     virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname, bool createMissingDirectories)
     192             :     {
     193           4 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     194             :         VfsDirectory* directory; VfsFile* file;
     195           2 :         size_t flags = VFS_LOOKUP_REAL_PATH | (createMissingDirectories ? VFS_LOOKUP_ADD : 0);
     196           2 :         WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file, flags));
     197           2 :         ENSURE(directory->AssociatedDirectory());
     198           2 :         realPathname = directory->AssociatedDirectory()->Path() / pathname.Filename();
     199           2 :         return INFO::OK;
     200             :     }
     201             : 
     202           9 :     virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname, bool createMissingDirectories)
     203             :     {
     204          18 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     205             :         VfsDirectory* directory;
     206           9 :         size_t flags = VFS_LOOKUP_REAL_PATH | (createMissingDirectories ? VFS_LOOKUP_ADD : 0);
     207           9 :         WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, NULL, flags));
     208           9 :         ENSURE(directory->AssociatedDirectory());
     209           9 :         realPathname = directory->AssociatedDirectory()->Path();
     210           9 :         return INFO::OK;
     211             :     }
     212             : 
     213           0 :     virtual Status GetVirtualPath(const OsPath& realPathname, VfsPath& pathname)
     214             :     {
     215           0 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     216           0 :         const OsPath realPath = realPathname.Parent()/"";
     217           0 :         VfsPath path;
     218           0 :         RETURN_STATUS_IF_ERR(FindRealPathR(realPath, m_rootDirectory, L"", path));
     219           0 :         pathname = path / realPathname.Filename();
     220           0 :         return INFO::OK;
     221             :     }
     222             : 
     223           3 :     virtual Status RemoveFile(const VfsPath& pathname)
     224             :     {
     225           6 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     226             : 
     227             :         VfsDirectory* directory; VfsFile* file;
     228           3 :         RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file));
     229           3 :         directory->RemoveFile(file->Name());
     230             : 
     231           3 :         return INFO::OK;
     232             :     }
     233             : 
     234           3 :     virtual Status RepopulateDirectory(const VfsPath& path)
     235             :     {
     236           6 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     237             : 
     238             :         VfsDirectory* directory;
     239           3 :         RETURN_STATUS_IF_ERR(vfs_Lookup(path, &m_rootDirectory, directory, 0));
     240           3 :         directory->RequestRepopulate();
     241             : 
     242           3 :         return INFO::OK;
     243             :     }
     244             : 
     245           0 :     virtual void Clear()
     246             :     {
     247           0 :         std::lock_guard<std::mutex> lock(vfs_mutex);
     248           0 :         m_rootDirectory.Clear();
     249           0 :     }
     250             : 
     251             : private:
     252           0 :     Status FindRealPathR(const OsPath& realPath, const VfsDirectory& directory, const VfsPath& curPath, VfsPath& path)
     253             :     {
     254           0 :         PRealDirectory realDirectory = directory.AssociatedDirectory();
     255           0 :         if(realDirectory && realDirectory->Path() == realPath)
     256             :         {
     257           0 :             path = curPath;
     258           0 :             return INFO::OK;
     259             :         }
     260             : 
     261           0 :         const VfsDirectory::VfsSubdirectories& subdirectories = directory.Subdirectories();
     262           0 :         for(VfsDirectory::VfsSubdirectories::const_iterator it = subdirectories.begin(); it != subdirectories.end(); ++it)
     263             :         {
     264           0 :             const OsPath& subdirectoryName = it->first;
     265           0 :             const VfsDirectory& subdirectory = it->second;
     266           0 :             Status ret = FindRealPathR(realPath, subdirectory, curPath / subdirectoryName/"", path);
     267           0 :             if(ret == INFO::OK)
     268           0 :                 return INFO::OK;
     269             :         }
     270             : 
     271           0 :         return ERR::PATH_NOT_FOUND; // NOWARN
     272             :     }
     273             : 
     274             :     PITrace m_trace;
     275             :     mutable VfsDirectory m_rootDirectory;
     276             : };
     277             : 
     278             : //-----------------------------------------------------------------------------
     279             : 
     280          83 : PIVFS CreateVfs()
     281             : {
     282          83 :     return PIVFS(new VFS());
     283           3 : }

Generated by: LCOV version 1.13