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