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