Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vfs_populate.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2012 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  * populate VFS directories with files
25  */
26 
27 #include "precompiled.h"
29 
31 #include "lib/file/vfs/vfs_tree.h"
33 #include "lib/file/vfs/vfs.h" // error codes
34 
35 
36 #define ENABLE_ARCHIVE_STATS 0
37 #if ENABLE_ARCHIVE_STATS
38 static std::vector<const VfsFile*> s_looseFiles;
39 static size_t s_numArchivedFiles;
40 #endif
41 
43 {
44  bool operator()(const CFileInfo& a, const CFileInfo& b)
45  {
46  return a.Name() < b.Name();
47  }
48 };
49 
50 // helper class that allows breaking up the logic into sub-functions without
51 // always having to pass directory/realDirectory as parameters.
53 {
55 public:
56  PopulateHelper(VfsDirectory* directory, const PRealDirectory& realDirectory)
57  : m_directory(directory), m_realDirectory(realDirectory)
58  {
59  }
60 
62  {
63 #if ENABLE_ARCHIVE_STATS
64  s_looseFiles.reserve(10000);
65 #endif
66 
67  CFileInfos files; files.reserve(500);
68  DirectoryNames subdirectoryNames; subdirectoryNames.reserve(50);
69  RETURN_STATUS_IF_ERR(GetDirectoryEntries(m_realDirectory->Path(), &files, &subdirectoryNames));
70 
71  // to support .DELETED files inside archives safely, we need to load
72  // archives and loose files in a deterministic order in case they add
73  // and then delete the same file (or vice versa, depending on loading
74  // order). GetDirectoryEntries has undefined order so sort its output
75  std::sort(files.begin(), files.end(), CompareFileInfoByName());
76  std::sort(subdirectoryNames.begin(), subdirectoryNames.end());
77 
79  AddSubdirectories(subdirectoryNames);
80 
81  return INFO::OK;
82  }
83 
84 private:
85  void AddFile(const CFileInfo& fileInfo) const
86  {
87  const VfsPath name = fileInfo.Name();
88  if(name.Extension() == L".DELETED")
89  {
91  if(!(m_realDirectory->Flags() & VFS_MOUNT_KEEP_DELETED))
92  return;
93  }
94 
95  const VfsFile file(name, (size_t)fileInfo.Size(), fileInfo.MTime(), m_realDirectory->Priority(), m_realDirectory);
96  const VfsFile* pfile = m_directory->AddFile(file);
97 
98 #if ENABLE_ARCHIVE_STATS
99  // notify archive builder that this file could be archived but
100  // currently isn't; if there are too many of these, archive will
101  // be rebuilt.
102  // note: check if archivable to exclude stuff like screenshots
103  // from counting towards the threshold.
105  s_looseFiles.push_back(pfile);
106 #else
107  UNUSED2(pfile);
108 #endif
109  }
110 
111  static void AddArchiveFile(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
112  {
113  PopulateHelper* this_ = (PopulateHelper*)cbData;
114 
115  // (we have to create missing subdirectoryNames because archivers
116  // don't always place directory entries before their files)
117  const size_t flags = VFS_LOOKUP_ADD|VFS_LOOKUP_SKIP_POPULATE;
118  VfsDirectory* directory;
119  WARN_IF_ERR(vfs_Lookup(pathname, this_->m_directory, directory, 0, flags));
120 
121  const VfsPath name = fileInfo.Name();
122  if(name.Extension() == L".DELETED")
123  {
124  directory->RemoveFile(name.Basename());
125  if(!(this_->m_realDirectory->Flags() & VFS_MOUNT_KEEP_DELETED))
126  return;
127  }
128 
129  const VfsFile file(name, (size_t)fileInfo.Size(), fileInfo.MTime(), this_->m_realDirectory->Priority(), archiveFile);
130  directory->AddFile(file);
131 #if ENABLE_ARCHIVE_STATS
132  s_numArchivedFiles++;
133 #endif
134  }
135 
136  Status AddFiles(const CFileInfos& files) const
137  {
138  const OsPath path(m_realDirectory->Path());
139 
140  for(size_t i = 0; i < files.size(); i++)
141  {
142  const OsPath pathname = path / files[i].Name();
143  if(pathname.Extension() == L".zip")
144  {
145  PIArchiveReader archiveReader = CreateArchiveReader_Zip(pathname);
146  // archiveReader == nullptr if file could not be opened (e.g. because
147  // archive is currently open in another program)
148  if(archiveReader)
149  RETURN_STATUS_IF_ERR(archiveReader->ReadEntries(AddArchiveFile, (uintptr_t)this));
150  }
151  else // regular (non-archive) file
152  AddFile(files[i]);
153  }
154 
155  return INFO::OK;
156  }
157 
158  void AddSubdirectories(const DirectoryNames& subdirectoryNames) const
159  {
160  for(size_t i = 0; i < subdirectoryNames.size(); i++)
161  {
162  // skip version control directories - this avoids cluttering the
163  // VFS with hundreds of irrelevant files.
164  if(subdirectoryNames[i] == L".svn")
165  continue;
166 
167  VfsDirectory* subdirectory = m_directory->AddSubdirectory(subdirectoryNames[i]);
168  PRealDirectory realDirectory = CreateRealSubdirectory(m_realDirectory, subdirectoryNames[i]);
169  vfs_Attach(subdirectory, realDirectory);
170  }
171  }
172 
175 };
176 
177 
179 {
180  if(!directory->ShouldPopulate())
181  return INFO::OK;
182 
183  const PRealDirectory& realDirectory = directory->AssociatedDirectory();
184 
185  if(realDirectory->Flags() & VFS_MOUNT_WATCH)
186  realDirectory->Watch();
187 
188  PopulateHelper helper(directory, realDirectory);
190 
191  return INFO::OK;
192 }
193 
194 
195 Status vfs_Attach(VfsDirectory* directory, const PRealDirectory& realDirectory)
196 {
198  directory->SetAssociatedDirectory(realDirectory);
199  return INFO::OK;
200 }
bool ShouldPopulate()
Definition: vfs_tree.cpp:143
PRealDirectory m_realDirectory
VfsFile * AddFile(const VfsFile &file)
Definition: vfs_tree.cpp:81
Status vfs_Lookup(const VfsPath &pathname, VfsDirectory *startDirectory, VfsDirectory *&directory, VfsFile **pfile, size_t flags)
Resolve a pathname.
Definition: vfs_lookup.cpp:75
#define WARN_IF_ERR(expression)
Definition: status.h:265
const Status OK
Definition: status.h:386
const OsPath & Name() const
Definition: file_system.h:53
static void AddArchiveFile(const VfsPath &pathname, const CFileInfo &fileInfo, PIArchiveFile archiveFile, uintptr_t cbData)
void RemoveFile(const VfsPath &name)
remove the given file from the virtual directory (no effect on the physical file).
Definition: vfs_tree.cpp:111
void AddFile(const CFileInfo &fileInfo) const
bool operator()(const CFileInfo &a, const CFileInfo &b)
PIArchiveReader CreateArchiveReader_Zip(const OsPath &archivePathname)
const PRealDirectory & AssociatedDirectory() const
Definition: vfs_tree.h:131
Status GetDirectoryEntries(const OsPath &path, CFileInfos *files, DirectoryNames *subdirectoryNames)
Definition: file_system.cpp:87
Path Basename() const
Definition: path.h:166
void SetAssociatedDirectory(const PRealDirectory &realDirectory)
side effect: the next ShouldPopulate() will return true.
Definition: vfs_tree.cpp:135
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
shared_ptr< IArchiveReader > PIArchiveReader
Definition: archive.h:62
PRealDirectory CreateRealSubdirectory(const PRealDirectory &realDirectory, const OsPath &subdirectoryName)
Definition: path.h:75
keep the files named &quot;*.DELETED&quot; visible in the VFS directories.
Definition: vfs.h:68
shared_ptr< RealDirectory > PRealDirectory
Status AddEntries() const
Status vfs_Attach(VfsDirectory *directory, const PRealDirectory &realDirectory)
attach a real directory to a VFS directory.
off_t Size() const
Definition: file_system.h:58
PopulateHelper(VfsDirectory *directory, const PRealDirectory &realDirectory)
anything mounted from here should be included when building archives.
Definition: vfs.h:54
all real directories mounted during this operation will be watched for changes.
Definition: vfs.h:49
i64 Status
Error handling system.
Definition: status.h:171
NONCOPYABLE(PopulateHelper)
Status AddFiles(const CFileInfos &files) const
shared_ptr< IArchiveFile > PIArchiveFile
Definition: archive.h:48
Status vfs_Populate(VfsDirectory *directory)
populate the directory from the attached real directory.
time_t MTime() const
Definition: file_system.h:63
Path Extension() const
Definition: path.h:176
std::vector< OsPath > DirectoryNames
Definition: file_system.h:77
VfsDirectory *const m_directory
void AddSubdirectories(const DirectoryNames &subdirectoryNames) const
std::vector< CFileInfo > CFileInfos
Definition: file_system.h:76
VfsDirectory * AddSubdirectory(const VfsPath &name)
Definition: vfs_tree.cpp:103
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276