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 #include <assert.h>
     12 
     13 #include "webrtc/base/pathutils.h"
     14 #include "webrtc/base/fileutils.h"
     15 #include "webrtc/base/stringutils.h"
     16 #include "webrtc/base/stream.h"
     17 
     18 #if defined(WEBRTC_WIN)
     19 #include "webrtc/base/win32filesystem.h"
     20 #else
     21 #include "webrtc/base/unixfilesystem.h"
     22 #endif
     23 
     24 #if !defined(WEBRTC_WIN)
     25 #define MAX_PATH 260
     26 #endif
     27 
     28 namespace rtc {
     29 
     30 //////////////////////////
     31 // Directory Iterator   //
     32 //////////////////////////
     33 
     34 // A DirectoryIterator is created with a given directory. It originally points
     35 // to the first file in the directory, and can be advanecd with Next(). This
     36 // allows you to get information about each file.
     37 
     38   // Constructor
     39 DirectoryIterator::DirectoryIterator()
     40 #ifdef WEBRTC_WIN
     41     : handle_(INVALID_HANDLE_VALUE) {
     42 #else
     43     : dir_(NULL), dirent_(NULL) {
     44 #endif
     45 }
     46 
     47   // Destructor
     48 DirectoryIterator::~DirectoryIterator() {
     49 #if defined(WEBRTC_WIN)
     50   if (handle_ != INVALID_HANDLE_VALUE)
     51     ::FindClose(handle_);
     52 #else
     53   if (dir_)
     54     closedir(dir_);
     55 #endif
     56 }
     57 
     58   // Starts traversing a directory.
     59   // dir is the directory to traverse
     60   // returns true if the directory exists and is valid
     61 bool DirectoryIterator::Iterate(const Pathname &dir) {
     62   directory_ = dir.pathname();
     63 #if defined(WEBRTC_WIN)
     64   if (handle_ != INVALID_HANDLE_VALUE)
     65     ::FindClose(handle_);
     66   std::string d = dir.pathname() + '*';
     67   handle_ = ::FindFirstFile(ToUtf16(d).c_str(), &data_);
     68   if (handle_ == INVALID_HANDLE_VALUE)
     69     return false;
     70 #else
     71   if (dir_ != NULL)
     72     closedir(dir_);
     73   dir_ = ::opendir(directory_.c_str());
     74   if (dir_ == NULL)
     75     return false;
     76   dirent_ = readdir(dir_);
     77   if (dirent_ == NULL)
     78     return false;
     79 
     80   if (::stat(std::string(directory_ + Name()).c_str(), &stat_) != 0)
     81     return false;
     82 #endif
     83   return true;
     84 }
     85 
     86   // Advances to the next file
     87   // returns true if there were more files in the directory.
     88 bool DirectoryIterator::Next() {
     89 #if defined(WEBRTC_WIN)
     90   return ::FindNextFile(handle_, &data_) == TRUE;
     91 #else
     92   dirent_ = ::readdir(dir_);
     93   if (dirent_ == NULL)
     94     return false;
     95 
     96   return ::stat(std::string(directory_ + Name()).c_str(), &stat_) == 0;
     97 #endif
     98 }
     99 
    100   // returns true if the file currently pointed to is a directory
    101 bool DirectoryIterator::IsDirectory() const {
    102 #if defined(WEBRTC_WIN)
    103   return (data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE;
    104 #else
    105   return S_ISDIR(stat_.st_mode);
    106 #endif
    107 }
    108 
    109   // returns the name of the file currently pointed to
    110 std::string DirectoryIterator::Name() const {
    111 #if defined(WEBRTC_WIN)
    112   return ToUtf8(data_.cFileName);
    113 #else
    114   assert(dirent_ != NULL);
    115   return dirent_->d_name;
    116 #endif
    117 }
    118 
    119   // returns the size of the file currently pointed to
    120 size_t DirectoryIterator::FileSize() const {
    121 #if !defined(WEBRTC_WIN)
    122   return stat_.st_size;
    123 #else
    124   return data_.nFileSizeLow;
    125 #endif
    126 }
    127 
    128 bool DirectoryIterator::OlderThan(int seconds) const {
    129   time_t file_modify_time;
    130 #if defined(WEBRTC_WIN)
    131   FileTimeToUnixTime(data_.ftLastWriteTime, &file_modify_time);
    132 #else
    133   file_modify_time = stat_.st_mtime;
    134 #endif
    135   return TimeDiff(time(NULL), file_modify_time) >= seconds;
    136 }
    137 
    138 FilesystemInterface* Filesystem::default_filesystem_ = NULL;
    139 
    140 FilesystemInterface *Filesystem::EnsureDefaultFilesystem() {
    141   if (!default_filesystem_) {
    142 #if defined(WEBRTC_WIN)
    143     default_filesystem_ = new Win32Filesystem();
    144 #else
    145     default_filesystem_ = new UnixFilesystem();
    146 #endif
    147   }
    148   return default_filesystem_;
    149 }
    150 
    151 bool FilesystemInterface::CopyFolder(const Pathname &old_path,
    152                                      const Pathname &new_path) {
    153   bool success = true;
    154   VERIFY(IsFolder(old_path));
    155   Pathname new_dir;
    156   new_dir.SetFolder(new_path.pathname());
    157   Pathname old_dir;
    158   old_dir.SetFolder(old_path.pathname());
    159   if (!CreateFolder(new_dir))
    160     return false;
    161   DirectoryIterator *di = IterateDirectory();
    162   if (!di)
    163     return false;
    164   if (di->Iterate(old_dir.pathname())) {
    165     do {
    166       if (di->Name() == "." || di->Name() == "..")
    167         continue;
    168       Pathname source;
    169       Pathname dest;
    170       source.SetFolder(old_dir.pathname());
    171       dest.SetFolder(new_path.pathname());
    172       source.SetFilename(di->Name());
    173       dest.SetFilename(di->Name());
    174       if (!CopyFileOrFolder(source, dest))
    175         success = false;
    176     } while (di->Next());
    177   }
    178   delete di;
    179   return success;
    180 }
    181 
    182 bool FilesystemInterface::DeleteFolderContents(const Pathname &folder) {
    183   bool success = true;
    184   VERIFY(IsFolder(folder));
    185   DirectoryIterator *di = IterateDirectory();
    186   if (!di)
    187     return false;
    188   if (di->Iterate(folder)) {
    189     do {
    190       if (di->Name() == "." || di->Name() == "..")
    191         continue;
    192       Pathname subdir;
    193       subdir.SetFolder(folder.pathname());
    194       if (di->IsDirectory()) {
    195         subdir.AppendFolder(di->Name());
    196         if (!DeleteFolderAndContents(subdir)) {
    197           success = false;
    198         }
    199       } else {
    200         subdir.SetFilename(di->Name());
    201         if (!DeleteFile(subdir)) {
    202           success = false;
    203         }
    204       }
    205     } while (di->Next());
    206   }
    207   delete di;
    208   return success;
    209 }
    210 
    211 bool FilesystemInterface::CleanAppTempFolder() {
    212   Pathname path;
    213   if (!GetAppTempFolder(&path))
    214     return false;
    215   if (IsAbsent(path))
    216     return true;
    217   if (!IsTemporaryPath(path)) {
    218     ASSERT(false);
    219     return false;
    220   }
    221   return DeleteFolderContents(path);
    222 }
    223 
    224 Pathname Filesystem::GetCurrentDirectory() {
    225   return EnsureDefaultFilesystem()->GetCurrentDirectory();
    226 }
    227 
    228 bool CreateUniqueFile(Pathname& path, bool create_empty) {
    229   LOG(LS_INFO) << "Path " << path.pathname() << std::endl;
    230   // If no folder is supplied, use the temporary folder
    231   if (path.folder().empty()) {
    232     Pathname temporary_path;
    233     if (!Filesystem::GetTemporaryFolder(temporary_path, true, NULL)) {
    234       printf("Get temp failed\n");
    235       return false;
    236     }
    237     path.SetFolder(temporary_path.pathname());
    238   }
    239 
    240   // If no filename is supplied, use a temporary name
    241   if (path.filename().empty()) {
    242     std::string folder(path.folder());
    243     std::string filename = Filesystem::TempFilename(folder, "gt");
    244     path.SetPathname(filename);
    245     if (!create_empty) {
    246       Filesystem::DeleteFile(path.pathname());
    247     }
    248     return true;
    249   }
    250 
    251   // Otherwise, create a unique name based on the given filename
    252   // foo.txt -> foo-N.txt
    253   const std::string basename = path.basename();
    254   const size_t MAX_VERSION = 100;
    255   size_t version = 0;
    256   while (version < MAX_VERSION) {
    257     std::string pathname = path.pathname();
    258 
    259     if (!Filesystem::IsFile(pathname)) {
    260       if (create_empty) {
    261         FileStream* fs = Filesystem::OpenFile(pathname, "w");
    262         delete fs;
    263       }
    264       return true;
    265     }
    266     version += 1;
    267     char version_base[MAX_PATH];
    268     sprintfn(version_base, ARRAY_SIZE(version_base), "%s-%u",
    269              basename.c_str(), version);
    270     path.SetBasename(version_base);
    271   }
    272   return true;
    273 }
    274 
    275 }  // namespace rtc
    276