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