| /* |
| * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/base/fileutils.h" |
| |
| #include "webrtc/base/arraysize.h" |
| #include "webrtc/base/checks.h" |
| #include "webrtc/base/pathutils.h" |
| #include "webrtc/base/stringutils.h" |
| #include "webrtc/base/stream.h" |
| |
| #if defined(WEBRTC_WIN) |
| #include "webrtc/base/win32filesystem.h" |
| #else |
| #include "webrtc/base/unixfilesystem.h" |
| #endif |
| |
| #if !defined(WEBRTC_WIN) |
| #define MAX_PATH 260 |
| #endif |
| |
| namespace rtc { |
| |
| ////////////////////////// |
| // Directory Iterator // |
| ////////////////////////// |
| |
| // A DirectoryIterator is created with a given directory. It originally points |
| // to the first file in the directory, and can be advanecd with Next(). This |
| // allows you to get information about each file. |
| |
| // Constructor |
| DirectoryIterator::DirectoryIterator() |
| #ifdef WEBRTC_WIN |
| : handle_(INVALID_HANDLE_VALUE) { |
| #else |
| : dir_(NULL), dirent_(NULL) { |
| #endif |
| } |
| |
| // Destructor |
| DirectoryIterator::~DirectoryIterator() { |
| #if defined(WEBRTC_WIN) |
| if (handle_ != INVALID_HANDLE_VALUE) |
| ::FindClose(handle_); |
| #else |
| if (dir_) |
| closedir(dir_); |
| #endif |
| } |
| |
| // Starts traversing a directory. |
| // dir is the directory to traverse |
| // returns true if the directory exists and is valid |
| bool DirectoryIterator::Iterate(const Pathname &dir) { |
| directory_ = dir.pathname(); |
| #if defined(WEBRTC_WIN) |
| if (handle_ != INVALID_HANDLE_VALUE) |
| ::FindClose(handle_); |
| std::string d = dir.pathname() + '*'; |
| handle_ = ::FindFirstFile(ToUtf16(d).c_str(), &data_); |
| if (handle_ == INVALID_HANDLE_VALUE) |
| return false; |
| #else |
| if (dir_ != NULL) |
| closedir(dir_); |
| dir_ = ::opendir(directory_.c_str()); |
| if (dir_ == NULL) |
| return false; |
| dirent_ = readdir(dir_); |
| if (dirent_ == NULL) |
| return false; |
| |
| if (::stat(std::string(directory_ + Name()).c_str(), &stat_) != 0) |
| return false; |
| #endif |
| return true; |
| } |
| |
| // Advances to the next file |
| // returns true if there were more files in the directory. |
| bool DirectoryIterator::Next() { |
| #if defined(WEBRTC_WIN) |
| return ::FindNextFile(handle_, &data_) == TRUE; |
| #else |
| dirent_ = ::readdir(dir_); |
| if (dirent_ == NULL) |
| return false; |
| |
| return ::stat(std::string(directory_ + Name()).c_str(), &stat_) == 0; |
| #endif |
| } |
| |
| // returns true if the file currently pointed to is a directory |
| bool DirectoryIterator::IsDirectory() const { |
| #if defined(WEBRTC_WIN) |
| return (data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE; |
| #else |
| return S_ISDIR(stat_.st_mode); |
| #endif |
| } |
| |
| // returns the name of the file currently pointed to |
| std::string DirectoryIterator::Name() const { |
| #if defined(WEBRTC_WIN) |
| return ToUtf8(data_.cFileName); |
| #else |
| RTC_DCHECK(dirent_); |
| return dirent_->d_name; |
| #endif |
| } |
| |
| // returns the size of the file currently pointed to |
| size_t DirectoryIterator::FileSize() const { |
| #if !defined(WEBRTC_WIN) |
| return stat_.st_size; |
| #else |
| return data_.nFileSizeLow; |
| #endif |
| } |
| |
| bool DirectoryIterator::OlderThan(int seconds) const { |
| time_t file_modify_time; |
| #if defined(WEBRTC_WIN) |
| FileTimeToUnixTime(data_.ftLastWriteTime, &file_modify_time); |
| #else |
| file_modify_time = stat_.st_mtime; |
| #endif |
| return time(NULL) - file_modify_time >= seconds; |
| } |
| |
| FilesystemInterface* Filesystem::default_filesystem_ = NULL; |
| |
| FilesystemInterface *Filesystem::EnsureDefaultFilesystem() { |
| if (!default_filesystem_) { |
| #if defined(WEBRTC_WIN) |
| default_filesystem_ = new Win32Filesystem(); |
| #else |
| default_filesystem_ = new UnixFilesystem(); |
| #endif |
| } |
| return default_filesystem_; |
| } |
| |
| DirectoryIterator* FilesystemInterface::IterateDirectory() { |
| return new DirectoryIterator(); |
| } |
| |
| bool FilesystemInterface::CopyFolder(const Pathname &old_path, |
| const Pathname &new_path) { |
| bool success = true; |
| VERIFY(IsFolder(old_path)); |
| Pathname new_dir; |
| new_dir.SetFolder(new_path.pathname()); |
| Pathname old_dir; |
| old_dir.SetFolder(old_path.pathname()); |
| if (!CreateFolder(new_dir)) |
| return false; |
| DirectoryIterator *di = IterateDirectory(); |
| if (!di) |
| return false; |
| if (di->Iterate(old_dir.pathname())) { |
| do { |
| if (di->Name() == "." || di->Name() == "..") |
| continue; |
| Pathname source; |
| Pathname dest; |
| source.SetFolder(old_dir.pathname()); |
| dest.SetFolder(new_path.pathname()); |
| source.SetFilename(di->Name()); |
| dest.SetFilename(di->Name()); |
| if (!CopyFileOrFolder(source, dest)) |
| success = false; |
| } while (di->Next()); |
| } |
| delete di; |
| return success; |
| } |
| |
| bool FilesystemInterface::DeleteFolderContents(const Pathname &folder) { |
| bool success = true; |
| VERIFY(IsFolder(folder)); |
| DirectoryIterator *di = IterateDirectory(); |
| if (!di) |
| return false; |
| if (di->Iterate(folder)) { |
| do { |
| if (di->Name() == "." || di->Name() == "..") |
| continue; |
| Pathname subdir; |
| subdir.SetFolder(folder.pathname()); |
| if (di->IsDirectory()) { |
| subdir.AppendFolder(di->Name()); |
| if (!DeleteFolderAndContents(subdir)) { |
| success = false; |
| } |
| } else { |
| subdir.SetFilename(di->Name()); |
| if (!DeleteFile(subdir)) { |
| success = false; |
| } |
| } |
| } while (di->Next()); |
| } |
| delete di; |
| return success; |
| } |
| |
| bool FilesystemInterface::DeleteFolderAndContents(const Pathname& folder) { |
| return DeleteFolderContents(folder) && DeleteEmptyFolder(folder); |
| } |
| |
| bool FilesystemInterface::CleanAppTempFolder() { |
| Pathname path; |
| if (!GetAppTempFolder(&path)) |
| return false; |
| if (IsAbsent(path)) |
| return true; |
| if (!IsTemporaryPath(path)) { |
| ASSERT(false); |
| return false; |
| } |
| return DeleteFolderContents(path); |
| } |
| |
| Pathname Filesystem::GetCurrentDirectory() { |
| return EnsureDefaultFilesystem()->GetCurrentDirectory(); |
| } |
| |
| bool CreateUniqueFile(Pathname& path, bool create_empty) { |
| LOG(LS_INFO) << "Path " << path.pathname() << std::endl; |
| // If no folder is supplied, use the temporary folder |
| if (path.folder().empty()) { |
| Pathname temporary_path; |
| if (!Filesystem::GetTemporaryFolder(temporary_path, true, NULL)) { |
| printf("Get temp failed\n"); |
| return false; |
| } |
| path.SetFolder(temporary_path.pathname()); |
| } |
| |
| // If no filename is supplied, use a temporary name |
| if (path.filename().empty()) { |
| std::string folder(path.folder()); |
| std::string filename = Filesystem::TempFilename(folder, "gt"); |
| path.SetPathname(filename); |
| if (!create_empty) { |
| Filesystem::DeleteFile(path.pathname()); |
| } |
| return true; |
| } |
| |
| // Otherwise, create a unique name based on the given filename |
| // foo.txt -> foo-N.txt |
| const std::string basename = path.basename(); |
| const size_t MAX_VERSION = 100; |
| size_t version = 0; |
| while (version < MAX_VERSION) { |
| std::string pathname = path.pathname(); |
| |
| if (!Filesystem::IsFile(pathname)) { |
| if (create_empty) { |
| FileStream* fs = Filesystem::OpenFile(pathname, "w"); |
| delete fs; |
| } |
| return true; |
| } |
| version += 1; |
| char version_base[MAX_PATH]; |
| sprintfn(version_base, arraysize(version_base), "%s-%u", basename.c_str(), |
| version); |
| path.SetBasename(version_base); |
| } |
| return true; |
| } |
| |
| } // namespace rtc |