Home | History | Annotate | Download | only in base
      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 ".."
     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:
     94   virtual ~FilesystemInterface() {}
     95 
     96   // Returns a DirectoryIterator for a given pathname.
     97   // TODO: Do fancy abstracted stuff
     98   virtual DirectoryIterator *IterateDirectory() {
     99     return new DirectoryIterator();
    100   }
    101 
    102   // Opens a file. Returns an open StreamInterface if function succeeds.
    103   // Otherwise, returns NULL.
    104   // TODO: Add an error param to indicate failure reason, similar to
    105   // FileStream::Open
    106   virtual FileStream *OpenFile(const Pathname &filename,
    107                                const std::string &mode) = 0;
    108 
    109   // Atomically creates an empty file accessible only to the current user if one
    110   // does not already exist at the given path, otherwise fails. This is the only
    111   // secure way to create a file in a shared temp directory (e.g., C:\Temp on
    112   // Windows or /tmp on Linux).
    113   // Note that if it is essential that a file be successfully created then the
    114   // app must generate random names and retry on failure, or else it will be
    115   // vulnerable to a trivial DoS.
    116   virtual bool CreatePrivateFile(const Pathname &filename) = 0;
    117 
    118   // This will attempt to delete the path located at filename.
    119   // It ASSERTS and returns false if the path points to a folder or a
    120   // non-existent file.
    121   virtual bool DeleteFile(const Pathname &filename) = 0;
    122 
    123   // This will attempt to delete the empty folder located at 'folder'
    124   // It ASSERTS and returns false if the path points to a file or a non-existent
    125   // folder. It fails normally if the folder is not empty or can otherwise
    126   // not be deleted.
    127   virtual bool DeleteEmptyFolder(const Pathname &folder) = 0;
    128 
    129   // This will call IterateDirectory, to get a directory iterator, and then
    130   // call DeleteFolderAndContents and DeleteFile on every path contained in this
    131   // folder. If the folder is empty, this returns true.
    132   virtual bool DeleteFolderContents(const Pathname &folder);
    133 
    134   // This deletes the contents of a folder, recursively, and then deletes
    135   // the folder itself.
    136   virtual bool DeleteFolderAndContents(const Pathname &folder) {
    137     return DeleteFolderContents(folder) && DeleteEmptyFolder(folder);
    138   }
    139 
    140   // This will delete whatever is located at path, be it a file or a folder.
    141   // If it is a folder, it will delete it recursively by calling
    142   // DeleteFolderAndContents
    143   bool DeleteFileOrFolder(const Pathname &path) {
    144     if (IsFolder(path))
    145       return DeleteFolderAndContents(path);
    146     else
    147       return DeleteFile(path);
    148   }
    149 
    150   // Creates a directory. This will call itself recursively to create /foo/bar
    151   // even if /foo does not exist. Returns true if the function succeeds.
    152   virtual bool CreateFolder(const Pathname &pathname) = 0;
    153 
    154   // This moves a file from old_path to new_path, where "old_path" is a
    155   // plain file. This ASSERTs and returns false if old_path points to a
    156   // directory, and returns true if the function succeeds.
    157   // If the new path is on a different volume than the old path, this function
    158   // will attempt to copy and, if that succeeds, delete the old path.
    159   virtual bool MoveFolder(const Pathname &old_path,
    160                           const Pathname &new_path) = 0;
    161 
    162   // This moves a directory from old_path to new_path, where "old_path" is a
    163   // directory. This ASSERTs and returns false if old_path points to a plain
    164   // file, and returns true if the function succeeds.
    165   // If the new path is on a different volume, this function will attempt to
    166   // copy and if that succeeds, delete the old path.
    167   virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0;
    168 
    169   // This attempts to move whatever is located at old_path to new_path,
    170   // be it a file or folder.
    171   bool MoveFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
    172     if (IsFile(old_path)) {
    173       return MoveFile(old_path, new_path);
    174     } else {
    175       return MoveFolder(old_path, new_path);
    176     }
    177   }
    178 
    179   // This copies a file from old_path to new_path. This method ASSERTs and
    180   // returns false if old_path is a folder, and returns true if the copy
    181   // succeeds.
    182   virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path) = 0;
    183 
    184   // This copies a folder from old_path to new_path.
    185   bool CopyFolder(const Pathname &old_path, const Pathname &new_path);
    186 
    187   bool CopyFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
    188     if (IsFile(old_path))
    189       return CopyFile(old_path, new_path);
    190     else
    191       return CopyFolder(old_path, new_path);
    192   }
    193 
    194   // Returns true if pathname refers to a directory
    195   virtual bool IsFolder(const Pathname& pathname) = 0;
    196 
    197   // Returns true if pathname refers to a file
    198   virtual bool IsFile(const Pathname& pathname) = 0;
    199 
    200   // Returns true if pathname refers to no filesystem object, every parent
    201   // directory either exists, or is also absent.
    202   virtual bool IsAbsent(const Pathname& pathname) = 0;
    203 
    204   // Returns true if pathname represents a temporary location on the system.
    205   virtual bool IsTemporaryPath(const Pathname& pathname) = 0;
    206 
    207   // A folder appropriate for storing temporary files (Contents are
    208   // automatically deleted when the program exits)
    209   virtual bool GetTemporaryFolder(Pathname &path, bool create,
    210                                   const std::string *append) = 0;
    211 
    212   virtual std::string TempFilename(const Pathname &dir,
    213                                    const std::string &prefix) = 0;
    214 
    215   // Determines the size of the file indicated by path.
    216   virtual bool GetFileSize(const Pathname& path, size_t* size) = 0;
    217 
    218   // Determines a timestamp associated with the file indicated by path.
    219   virtual bool GetFileTime(const Pathname& path, FileTimeType which,
    220                            time_t* time) = 0;
    221 
    222   // Returns the path to the running application.
    223   // Note: This is not guaranteed to work on all platforms.  Be aware of the
    224   // limitations before using it, and robustly handle failure.
    225   virtual bool GetAppPathname(Pathname* path) = 0;
    226 
    227   // Get a folder that is unique to the current application, which is suitable
    228   // for sharing data between executions of the app.  If the per_user arg is
    229   // true, the folder is also specific to the current user.
    230   virtual bool GetAppDataFolder(Pathname* path, bool per_user) = 0;
    231 
    232   // Get a temporary folder that is unique to the current user and application.
    233   // TODO: Re-evaluate the goals of this function.  We probably just need any
    234   // directory that won't collide with another existing directory, and which
    235   // will be cleaned up when the program exits.
    236   virtual bool GetAppTempFolder(Pathname* path) = 0;
    237 
    238   // Delete the contents of the folder returned by GetAppTempFolder
    239   bool CleanAppTempFolder();
    240 
    241   virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) = 0;
    242 
    243   // Returns the absolute path of the current directory.
    244   virtual Pathname GetCurrentDirectory() = 0;
    245 
    246   // Note: These might go into some shared config section later, but they're
    247   // used by some methods in this interface, so we're leaving them here for now.
    248   void SetOrganizationName(const std::string& organization) {
    249     organization_name_ = organization;
    250   }
    251   void GetOrganizationName(std::string* organization) {
    252     ASSERT(NULL != organization);
    253     *organization = organization_name_;
    254   }
    255   void SetApplicationName(const std::string& application) {
    256     application_name_ = application;
    257   }
    258   void GetApplicationName(std::string* application) {
    259     ASSERT(NULL != application);
    260     *application = application_name_;
    261   }
    262 
    263  protected:
    264   std::string organization_name_;
    265   std::string application_name_;
    266 };
    267 
    268 class Filesystem {
    269  public:
    270   static FilesystemInterface *default_filesystem() {
    271     ASSERT(default_filesystem_ != NULL);
    272     return default_filesystem_;
    273   }
    274 
    275   static void set_default_filesystem(FilesystemInterface *filesystem) {
    276     default_filesystem_ = filesystem;
    277   }
    278 
    279   static FilesystemInterface *swap_default_filesystem(
    280       FilesystemInterface *filesystem) {
    281     FilesystemInterface *cur = default_filesystem_;
    282     default_filesystem_ = filesystem;
    283     return cur;
    284   }
    285 
    286   static DirectoryIterator *IterateDirectory() {
    287     return EnsureDefaultFilesystem()->IterateDirectory();
    288   }
    289 
    290   static bool CreateFolder(const Pathname &pathname) {
    291     return EnsureDefaultFilesystem()->CreateFolder(pathname);
    292   }
    293 
    294   static FileStream *OpenFile(const Pathname &filename,
    295                               const std::string &mode) {
    296     return EnsureDefaultFilesystem()->OpenFile(filename, mode);
    297   }
    298 
    299   static bool CreatePrivateFile(const Pathname &filename) {
    300     return EnsureDefaultFilesystem()->CreatePrivateFile(filename);
    301   }
    302 
    303   static bool DeleteFile(const Pathname &filename) {
    304     return EnsureDefaultFilesystem()->DeleteFile(filename);
    305   }
    306 
    307   static bool DeleteEmptyFolder(const Pathname &folder) {
    308     return EnsureDefaultFilesystem()->DeleteEmptyFolder(folder);
    309   }
    310 
    311   static bool DeleteFolderContents(const Pathname &folder) {
    312     return EnsureDefaultFilesystem()->DeleteFolderContents(folder);
    313   }
    314 
    315   static bool DeleteFolderAndContents(const Pathname &folder) {
    316     return EnsureDefaultFilesystem()->DeleteFolderAndContents(folder);
    317   }
    318 
    319   static bool MoveFolder(const Pathname &old_path, const Pathname &new_path) {
    320     return EnsureDefaultFilesystem()->MoveFolder(old_path, new_path);
    321   }
    322 
    323   static bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
    324     return EnsureDefaultFilesystem()->MoveFile(old_path, new_path);
    325   }
    326 
    327   static bool CopyFolder(const Pathname &old_path, const Pathname &new_path) {
    328     return EnsureDefaultFilesystem()->CopyFolder(old_path, new_path);
    329   }
    330 
    331   static bool CopyFile(const Pathname &old_path, const Pathname &new_path) {
    332     return EnsureDefaultFilesystem()->CopyFile(old_path, new_path);
    333   }
    334 
    335   static bool IsFolder(const Pathname& pathname) {
    336     return EnsureDefaultFilesystem()->IsFolder(pathname);
    337   }
    338 
    339   static bool IsFile(const Pathname &pathname) {
    340     return EnsureDefaultFilesystem()->IsFile(pathname);
    341   }
    342 
    343   static bool IsAbsent(const Pathname &pathname) {
    344     return EnsureDefaultFilesystem()->IsAbsent(pathname);
    345   }
    346 
    347   static bool IsTemporaryPath(const Pathname& pathname) {
    348     return EnsureDefaultFilesystem()->IsTemporaryPath(pathname);
    349   }
    350 
    351   static bool GetTemporaryFolder(Pathname &path, bool create,
    352                                  const std::string *append) {
    353     return EnsureDefaultFilesystem()->GetTemporaryFolder(path, create, append);
    354   }
    355 
    356   static std::string TempFilename(const Pathname &dir,
    357                                   const std::string &prefix) {
    358     return EnsureDefaultFilesystem()->TempFilename(dir, prefix);
    359   }
    360 
    361   static bool GetFileSize(const Pathname& path, size_t* size) {
    362     return EnsureDefaultFilesystem()->GetFileSize(path, size);
    363   }
    364 
    365   static bool GetFileTime(const Pathname& path, FileTimeType which,
    366                           time_t* time) {
    367     return EnsureDefaultFilesystem()->GetFileTime(path, which, time);
    368   }
    369 
    370   static bool GetAppPathname(Pathname* path) {
    371     return EnsureDefaultFilesystem()->GetAppPathname(path);
    372   }
    373 
    374   static bool GetAppDataFolder(Pathname* path, bool per_user) {
    375     return EnsureDefaultFilesystem()->GetAppDataFolder(path, per_user);
    376   }
    377 
    378   static bool GetAppTempFolder(Pathname* path) {
    379     return EnsureDefaultFilesystem()->GetAppTempFolder(path);
    380   }
    381 
    382   static bool CleanAppTempFolder() {
    383     return EnsureDefaultFilesystem()->CleanAppTempFolder();
    384   }
    385 
    386   static bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
    387     return EnsureDefaultFilesystem()->GetDiskFreeSpace(path, freebytes);
    388   }
    389 
    390   // Definition has to be in the .cc file due to returning forward-declared
    391   // Pathname by value.
    392   static Pathname GetCurrentDirectory();
    393 
    394   static void SetOrganizationName(const std::string& organization) {
    395     EnsureDefaultFilesystem()->SetOrganizationName(organization);
    396   }
    397 
    398   static void GetOrganizationName(std::string* organization) {
    399     EnsureDefaultFilesystem()->GetOrganizationName(organization);
    400   }
    401 
    402   static void SetApplicationName(const std::string& application) {
    403     EnsureDefaultFilesystem()->SetApplicationName(application);
    404   }
    405 
    406   static void GetApplicationName(std::string* application) {
    407     EnsureDefaultFilesystem()->GetApplicationName(application);
    408   }
    409 
    410  private:
    411   static FilesystemInterface* default_filesystem_;
    412 
    413   static FilesystemInterface *EnsureDefaultFilesystem();
    414   DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
    415 };
    416 
    417 class FilesystemScope{
    418  public:
    419   explicit FilesystemScope(FilesystemInterface *new_fs) {
    420     old_fs_ = Filesystem::swap_default_filesystem(new_fs);
    421   }
    422   ~FilesystemScope() {
    423     Filesystem::set_default_filesystem(old_fs_);
    424   }
    425  private:
    426   FilesystemInterface* old_fs_;
    427   DISALLOW_IMPLICIT_CONSTRUCTORS(FilesystemScope);
    428 };
    429 
    430 // Generates a unique filename based on the input path.  If no path component
    431 // is specified, it uses the temporary directory.  If a filename is provided,
    432 // up to 100 variations of form basename-N.extension are tried.  When
    433 // create_empty is true, an empty file of this name is created (which
    434 // decreases the chance of a temporary filename collision with another
    435 // process).
    436 bool CreateUniqueFile(Pathname& path, bool create_empty);
    437 
    438 }  // namespace rtc
    439 
    440 #endif  // WEBRTC_BASE_FILEUTILS_H_
    441