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 28namespace 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 39DirectoryIterator::DirectoryIterator() 40#ifdef WEBRTC_WIN 41 : handle_(INVALID_HANDLE_VALUE) { 42#else 43 : dir_(NULL), dirent_(NULL) { 44#endif 45} 46 47 // Destructor 48DirectoryIterator::~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 61bool 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. 88bool 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 101bool 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 110std::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 120size_t DirectoryIterator::FileSize() const { 121#if !defined(WEBRTC_WIN) 122 return stat_.st_size; 123#else 124 return data_.nFileSizeLow; 125#endif 126} 127 128bool 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 138FilesystemInterface* Filesystem::default_filesystem_ = NULL; 139 140FilesystemInterface *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 151bool 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 182bool 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 211bool 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 224Pathname Filesystem::GetCurrentDirectory() { 225 return EnsureDefaultFilesystem()->GetCurrentDirectory(); 226} 227 228bool 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