• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef WEBRTC_BASE_FILEUTILS_H_
12 #define WEBRTC_BASE_FILEUTILS_H_
13 
14 #include <string>
15 
16 #if !defined(WEBRTC_WIN)
17 #include <dirent.h>
18 #include <stdio.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #endif
23 
24 #include "webrtc/base/basictypes.h"
25 #include "webrtc/base/common.h"
26 #include "webrtc/base/platform_file.h"
27 #include "webrtc/base/scoped_ptr.h"
28 
29 namespace rtc {
30 
31 class FileStream;
32 class Pathname;
33 
34 //////////////////////////
35 // Directory Iterator   //
36 //////////////////////////
37 
38 // A DirectoryIterator is created with a given directory. It originally points
39 // to the first file in the directory, and can be advanecd with Next(). This
40 // allows you to get information about each file.
41 
42 class DirectoryIterator {
43   friend class Filesystem;
44  public:
45   // Constructor
46   DirectoryIterator();
47   // Destructor
48   virtual ~DirectoryIterator();
49 
50   // Starts traversing a directory
51   // dir is the directory to traverse
52   // returns true if the directory exists and is valid
53   // The iterator will point to the first entry in the directory
54   virtual bool Iterate(const Pathname &path);
55 
56   // Advances to the next file
57   // returns true if there were more files in the directory.
58   virtual bool Next();
59 
60   // returns true if the file currently pointed to is a directory
61   virtual bool IsDirectory() const;
62 
63   // returns the name of the file currently pointed to
64   virtual std::string Name() const;
65 
66   // returns the size of the file currently pointed to
67   virtual size_t FileSize() const;
68 
69   // returns true if the file is older than seconds
70   virtual bool OlderThan(int seconds) const;
71 
72   // checks whether current file is a special directory file "." or ".."
IsDots()73   bool IsDots() const {
74     std::string filename(Name());
75     return (filename.compare(".") == 0) || (filename.compare("..") == 0);
76   }
77 
78  private:
79   std::string directory_;
80 #if defined(WEBRTC_WIN)
81   WIN32_FIND_DATA data_;
82   HANDLE handle_;
83 #else
84   DIR *dir_;
85   struct dirent *dirent_;
86   struct stat stat_;
87 #endif
88 };
89 
90 enum FileTimeType { FTT_CREATED, FTT_MODIFIED, FTT_ACCESSED };
91 
92 class FilesystemInterface {
93  public:
~FilesystemInterface()94   virtual ~FilesystemInterface() {}
95 
96   // Returns a DirectoryIterator for a given pathname.
97   // TODO: Do fancy abstracted stuff
98   virtual DirectoryIterator* IterateDirectory();
99 
100   // Opens a file. Returns an open StreamInterface if function succeeds.
101   // Otherwise, returns NULL.
102   // TODO: Add an error param to indicate failure reason, similar to
103   // FileStream::Open
104   virtual FileStream *OpenFile(const Pathname &filename,
105                                const std::string &mode) = 0;
106 
107   // Atomically creates an empty file accessible only to the current user if one
108   // does not already exist at the given path, otherwise fails. This is the only
109   // secure way to create a file in a shared temp directory (e.g., C:\Temp on
110   // Windows or /tmp on Linux).
111   // Note that if it is essential that a file be successfully created then the
112   // app must generate random names and retry on failure, or else it will be
113   // vulnerable to a trivial DoS.
114   virtual bool CreatePrivateFile(const Pathname &filename) = 0;
115 
116   // This will attempt to delete the path located at filename.
117   // It ASSERTS and returns false if the path points to a folder or a
118   // non-existent file.
119   virtual bool DeleteFile(const Pathname &filename) = 0;
120 
121   // This will attempt to delete the empty folder located at 'folder'
122   // It ASSERTS and returns false if the path points to a file or a non-existent
123   // folder. It fails normally if the folder is not empty or can otherwise
124   // not be deleted.
125   virtual bool DeleteEmptyFolder(const Pathname &folder) = 0;
126 
127   // This will call IterateDirectory, to get a directory iterator, and then
128   // call DeleteFolderAndContents and DeleteFile on every path contained in this
129   // folder. If the folder is empty, this returns true.
130   virtual bool DeleteFolderContents(const Pathname &folder);
131 
132   // This deletes the contents of a folder, recursively, and then deletes
133   // the folder itself.
134   virtual bool DeleteFolderAndContents(const Pathname& folder);
135 
136   // This will delete whatever is located at path, be it a file or a folder.
137   // If it is a folder, it will delete it recursively by calling
138   // DeleteFolderAndContents
DeleteFileOrFolder(const Pathname & path)139   bool DeleteFileOrFolder(const Pathname &path) {
140     if (IsFolder(path))
141       return DeleteFolderAndContents(path);
142     else
143       return DeleteFile(path);
144   }
145 
146   // Creates a directory. This will call itself recursively to create /foo/bar
147   // even if /foo does not exist. Returns true if the function succeeds.
148   virtual bool CreateFolder(const Pathname &pathname) = 0;
149 
150   // This moves a file from old_path to new_path, where "old_path" is a
151   // plain file. This ASSERTs and returns false if old_path points to a
152   // directory, and returns true if the function succeeds.
153   // If the new path is on a different volume than the old path, this function
154   // will attempt to copy and, if that succeeds, delete the old path.
155   virtual bool MoveFolder(const Pathname &old_path,
156                           const Pathname &new_path) = 0;
157 
158   // This moves a directory from old_path to new_path, where "old_path" is a
159   // directory. This ASSERTs and returns false if old_path points to a plain
160   // file, and returns true if the function succeeds.
161   // If the new path is on a different volume, this function will attempt to
162   // copy and if that succeeds, delete the old path.
163   virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0;
164 
165   // This attempts to move whatever is located at old_path to new_path,
166   // be it a file or folder.
MoveFileOrFolder(const Pathname & old_path,const Pathname & new_path)167   bool MoveFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
168     if (IsFile(old_path)) {
169       return MoveFile(old_path, new_path);
170     } else {
171       return MoveFolder(old_path, new_path);
172     }
173   }
174 
175   // This copies a file from old_path to new_path. This method ASSERTs and
176   // returns false if old_path is a folder, and returns true if the copy
177   // succeeds.
178   virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path) = 0;
179 
180   // This copies a folder from old_path to new_path.
181   bool CopyFolder(const Pathname &old_path, const Pathname &new_path);
182 
CopyFileOrFolder(const Pathname & old_path,const Pathname & new_path)183   bool CopyFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
184     if (IsFile(old_path))
185       return CopyFile(old_path, new_path);
186     else
187       return CopyFolder(old_path, new_path);
188   }
189 
190   // Returns true if pathname refers to a directory
191   virtual bool IsFolder(const Pathname& pathname) = 0;
192 
193   // Returns true if pathname refers to a file
194   virtual bool IsFile(const Pathname& pathname) = 0;
195 
196   // Returns true if pathname refers to no filesystem object, every parent
197   // directory either exists, or is also absent.
198   virtual bool IsAbsent(const Pathname& pathname) = 0;
199 
200   // Returns true if pathname represents a temporary location on the system.
201   virtual bool IsTemporaryPath(const Pathname& pathname) = 0;
202 
203   // A folder appropriate for storing temporary files (Contents are
204   // automatically deleted when the program exits)
205   virtual bool GetTemporaryFolder(Pathname &path, bool create,
206                                   const std::string *append) = 0;
207 
208   virtual std::string TempFilename(const Pathname &dir,
209                                    const std::string &prefix) = 0;
210 
211   // Determines the size of the file indicated by path.
212   virtual bool GetFileSize(const Pathname& path, size_t* size) = 0;
213 
214   // Determines a timestamp associated with the file indicated by path.
215   virtual bool GetFileTime(const Pathname& path, FileTimeType which,
216                            time_t* time) = 0;
217 
218   // Returns the path to the running application.
219   // Note: This is not guaranteed to work on all platforms.  Be aware of the
220   // limitations before using it, and robustly handle failure.
221   virtual bool GetAppPathname(Pathname* path) = 0;
222 
223   // Get a folder that is unique to the current application, which is suitable
224   // for sharing data between executions of the app.  If the per_user arg is
225   // true, the folder is also specific to the current user.
226   virtual bool GetAppDataFolder(Pathname* path, bool per_user) = 0;
227 
228   // Get a temporary folder that is unique to the current user and application.
229   // TODO: Re-evaluate the goals of this function.  We probably just need any
230   // directory that won't collide with another existing directory, and which
231   // will be cleaned up when the program exits.
232   virtual bool GetAppTempFolder(Pathname* path) = 0;
233 
234   // Delete the contents of the folder returned by GetAppTempFolder
235   bool CleanAppTempFolder();
236 
237   virtual bool GetDiskFreeSpace(const Pathname& path, int64_t* freebytes) = 0;
238 
239   // Returns the absolute path of the current directory.
240   virtual Pathname GetCurrentDirectory() = 0;
241 
242   // Note: These might go into some shared config section later, but they're
243   // used by some methods in this interface, so we're leaving them here for now.
SetOrganizationName(const std::string & organization)244   void SetOrganizationName(const std::string& organization) {
245     organization_name_ = organization;
246   }
GetOrganizationName(std::string * organization)247   void GetOrganizationName(std::string* organization) {
248     ASSERT(NULL != organization);
249     *organization = organization_name_;
250   }
SetApplicationName(const std::string & application)251   void SetApplicationName(const std::string& application) {
252     application_name_ = application;
253   }
GetApplicationName(std::string * application)254   void GetApplicationName(std::string* application) {
255     ASSERT(NULL != application);
256     *application = application_name_;
257   }
258 
259  protected:
260   std::string organization_name_;
261   std::string application_name_;
262 };
263 
264 class Filesystem {
265  public:
default_filesystem()266   static FilesystemInterface *default_filesystem() {
267     ASSERT(default_filesystem_ != NULL);
268     return default_filesystem_;
269   }
270 
set_default_filesystem(FilesystemInterface * filesystem)271   static void set_default_filesystem(FilesystemInterface *filesystem) {
272     default_filesystem_ = filesystem;
273   }
274 
swap_default_filesystem(FilesystemInterface * filesystem)275   static FilesystemInterface *swap_default_filesystem(
276       FilesystemInterface *filesystem) {
277     FilesystemInterface *cur = default_filesystem_;
278     default_filesystem_ = filesystem;
279     return cur;
280   }
281 
IterateDirectory()282   static DirectoryIterator *IterateDirectory() {
283     return EnsureDefaultFilesystem()->IterateDirectory();
284   }
285 
CreateFolder(const Pathname & pathname)286   static bool CreateFolder(const Pathname &pathname) {
287     return EnsureDefaultFilesystem()->CreateFolder(pathname);
288   }
289 
OpenFile(const Pathname & filename,const std::string & mode)290   static FileStream *OpenFile(const Pathname &filename,
291                               const std::string &mode) {
292     return EnsureDefaultFilesystem()->OpenFile(filename, mode);
293   }
294 
CreatePrivateFile(const Pathname & filename)295   static bool CreatePrivateFile(const Pathname &filename) {
296     return EnsureDefaultFilesystem()->CreatePrivateFile(filename);
297   }
298 
DeleteFile(const Pathname & filename)299   static bool DeleteFile(const Pathname &filename) {
300     return EnsureDefaultFilesystem()->DeleteFile(filename);
301   }
302 
DeleteEmptyFolder(const Pathname & folder)303   static bool DeleteEmptyFolder(const Pathname &folder) {
304     return EnsureDefaultFilesystem()->DeleteEmptyFolder(folder);
305   }
306 
DeleteFolderContents(const Pathname & folder)307   static bool DeleteFolderContents(const Pathname &folder) {
308     return EnsureDefaultFilesystem()->DeleteFolderContents(folder);
309   }
310 
DeleteFolderAndContents(const Pathname & folder)311   static bool DeleteFolderAndContents(const Pathname &folder) {
312     return EnsureDefaultFilesystem()->DeleteFolderAndContents(folder);
313   }
314 
MoveFolder(const Pathname & old_path,const Pathname & new_path)315   static bool MoveFolder(const Pathname &old_path, const Pathname &new_path) {
316     return EnsureDefaultFilesystem()->MoveFolder(old_path, new_path);
317   }
318 
MoveFile(const Pathname & old_path,const Pathname & new_path)319   static bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
320     return EnsureDefaultFilesystem()->MoveFile(old_path, new_path);
321   }
322 
CopyFolder(const Pathname & old_path,const Pathname & new_path)323   static bool CopyFolder(const Pathname &old_path, const Pathname &new_path) {
324     return EnsureDefaultFilesystem()->CopyFolder(old_path, new_path);
325   }
326 
CopyFile(const Pathname & old_path,const Pathname & new_path)327   static bool CopyFile(const Pathname &old_path, const Pathname &new_path) {
328     return EnsureDefaultFilesystem()->CopyFile(old_path, new_path);
329   }
330 
IsFolder(const Pathname & pathname)331   static bool IsFolder(const Pathname& pathname) {
332     return EnsureDefaultFilesystem()->IsFolder(pathname);
333   }
334 
IsFile(const Pathname & pathname)335   static bool IsFile(const Pathname &pathname) {
336     return EnsureDefaultFilesystem()->IsFile(pathname);
337   }
338 
IsAbsent(const Pathname & pathname)339   static bool IsAbsent(const Pathname &pathname) {
340     return EnsureDefaultFilesystem()->IsAbsent(pathname);
341   }
342 
IsTemporaryPath(const Pathname & pathname)343   static bool IsTemporaryPath(const Pathname& pathname) {
344     return EnsureDefaultFilesystem()->IsTemporaryPath(pathname);
345   }
346 
GetTemporaryFolder(Pathname & path,bool create,const std::string * append)347   static bool GetTemporaryFolder(Pathname &path, bool create,
348                                  const std::string *append) {
349     return EnsureDefaultFilesystem()->GetTemporaryFolder(path, create, append);
350   }
351 
TempFilename(const Pathname & dir,const std::string & prefix)352   static std::string TempFilename(const Pathname &dir,
353                                   const std::string &prefix) {
354     return EnsureDefaultFilesystem()->TempFilename(dir, prefix);
355   }
356 
GetFileSize(const Pathname & path,size_t * size)357   static bool GetFileSize(const Pathname& path, size_t* size) {
358     return EnsureDefaultFilesystem()->GetFileSize(path, size);
359   }
360 
GetFileTime(const Pathname & path,FileTimeType which,time_t * time)361   static bool GetFileTime(const Pathname& path, FileTimeType which,
362                           time_t* time) {
363     return EnsureDefaultFilesystem()->GetFileTime(path, which, time);
364   }
365 
GetAppPathname(Pathname * path)366   static bool GetAppPathname(Pathname* path) {
367     return EnsureDefaultFilesystem()->GetAppPathname(path);
368   }
369 
GetAppDataFolder(Pathname * path,bool per_user)370   static bool GetAppDataFolder(Pathname* path, bool per_user) {
371     return EnsureDefaultFilesystem()->GetAppDataFolder(path, per_user);
372   }
373 
GetAppTempFolder(Pathname * path)374   static bool GetAppTempFolder(Pathname* path) {
375     return EnsureDefaultFilesystem()->GetAppTempFolder(path);
376   }
377 
CleanAppTempFolder()378   static bool CleanAppTempFolder() {
379     return EnsureDefaultFilesystem()->CleanAppTempFolder();
380   }
381 
GetDiskFreeSpace(const Pathname & path,int64_t * freebytes)382   static bool GetDiskFreeSpace(const Pathname& path, int64_t* freebytes) {
383     return EnsureDefaultFilesystem()->GetDiskFreeSpace(path, freebytes);
384   }
385 
386   // Definition has to be in the .cc file due to returning forward-declared
387   // Pathname by value.
388   static Pathname GetCurrentDirectory();
389 
SetOrganizationName(const std::string & organization)390   static void SetOrganizationName(const std::string& organization) {
391     EnsureDefaultFilesystem()->SetOrganizationName(organization);
392   }
393 
GetOrganizationName(std::string * organization)394   static void GetOrganizationName(std::string* organization) {
395     EnsureDefaultFilesystem()->GetOrganizationName(organization);
396   }
397 
SetApplicationName(const std::string & application)398   static void SetApplicationName(const std::string& application) {
399     EnsureDefaultFilesystem()->SetApplicationName(application);
400   }
401 
GetApplicationName(std::string * application)402   static void GetApplicationName(std::string* application) {
403     EnsureDefaultFilesystem()->GetApplicationName(application);
404   }
405 
406  private:
407   static FilesystemInterface* default_filesystem_;
408 
409   static FilesystemInterface *EnsureDefaultFilesystem();
410   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
411 };
412 
413 class FilesystemScope{
414  public:
FilesystemScope(FilesystemInterface * new_fs)415   explicit FilesystemScope(FilesystemInterface *new_fs) {
416     old_fs_ = Filesystem::swap_default_filesystem(new_fs);
417   }
~FilesystemScope()418   ~FilesystemScope() {
419     Filesystem::set_default_filesystem(old_fs_);
420   }
421  private:
422   FilesystemInterface* old_fs_;
423   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(FilesystemScope);
424 };
425 
426 // Generates a unique filename based on the input path.  If no path component
427 // is specified, it uses the temporary directory.  If a filename is provided,
428 // up to 100 variations of form basename-N.extension are tried.  When
429 // create_empty is true, an empty file of this name is created (which
430 // decreases the chance of a temporary filename collision with another
431 // process).
432 bool CreateUniqueFile(Pathname& path, bool create_empty);
433 
434 }  // namespace rtc
435 
436 #endif  // WEBRTC_BASE_FILEUTILS_H_
437