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