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