OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "webkit/fileapi/native_file_util.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/file_util.h" |
| 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "webkit/fileapi/file_system_operation_context.h" |
| 12 |
| 13 namespace fileapi { |
| 14 |
| 15 class NativeFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { |
| 16 public: |
| 17 NativeFileEnumerator(const FilePath& root_path, |
| 18 bool recursive, |
| 19 file_util::FileEnumerator::FileType file_type) |
| 20 : file_enum_(root_path, recursive, file_type) { |
| 21 } |
| 22 |
| 23 ~NativeFileEnumerator() {} |
| 24 |
| 25 virtual FilePath Next() OVERRIDE; |
| 26 virtual int64 Size() OVERRIDE; |
| 27 virtual bool IsDirectory() OVERRIDE; |
| 28 |
| 29 private: |
| 30 file_util::FileEnumerator file_enum_; |
| 31 file_util::FileEnumerator::FindInfo file_util_info_; |
| 32 }; |
| 33 |
| 34 FilePath NativeFileEnumerator::Next() { |
| 35 FilePath rv = file_enum_.Next(); |
| 36 if (!rv.empty()) |
| 37 file_enum_.GetFindInfo(&file_util_info_); |
| 38 return rv; |
| 39 } |
| 40 |
| 41 int64 NativeFileEnumerator::Size() { |
| 42 return file_util::FileEnumerator::GetFilesize(file_util_info_); |
| 43 } |
| 44 |
| 45 bool NativeFileEnumerator::IsDirectory() { |
| 46 return file_util::FileEnumerator::IsDirectory(file_util_info_); |
| 47 } |
| 48 |
| 49 PlatformFileError NativeFileUtil::CreateOrOpen( |
| 50 FileSystemOperationContext* unused, |
| 51 const FilePath& file_path, int file_flags, |
| 52 PlatformFile* file_handle, bool* created) { |
| 53 if (!file_util::DirectoryExists(file_path.DirName())) { |
| 54 // If its parent does not exist, should return NOT_FOUND error. |
| 55 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 56 } |
| 57 PlatformFileError error_code = base::PLATFORM_FILE_OK; |
| 58 *file_handle = base::CreatePlatformFile(file_path, file_flags, |
| 59 created, &error_code); |
| 60 return error_code; |
| 61 } |
| 62 |
| 63 PlatformFileError NativeFileUtil::Close( |
| 64 FileSystemOperationContext* unused, |
| 65 PlatformFile file_handle) { |
| 66 if (!base::ClosePlatformFile(file_handle)) |
| 67 return base::PLATFORM_FILE_ERROR_FAILED; |
| 68 return base::PLATFORM_FILE_OK; |
| 69 } |
| 70 |
| 71 PlatformFileError NativeFileUtil::EnsureFileExists( |
| 72 FileSystemOperationContext* unused, |
| 73 const FilePath& file_path, |
| 74 bool* created) { |
| 75 if (!file_util::DirectoryExists(file_path.DirName())) |
| 76 // If its parent does not exist, should return NOT_FOUND error. |
| 77 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 78 PlatformFileError error_code = base::PLATFORM_FILE_OK; |
| 79 // Tries to create the |file_path| exclusively. This should fail |
| 80 // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists. |
| 81 PlatformFile handle = base::CreatePlatformFile( |
| 82 file_path, |
| 83 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, |
| 84 created, &error_code); |
| 85 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) { |
| 86 // Make sure created_ is false. |
| 87 if (created) |
| 88 *created = false; |
| 89 error_code = base::PLATFORM_FILE_OK; |
| 90 } |
| 91 if (handle != base::kInvalidPlatformFileValue) |
| 92 base::ClosePlatformFile(handle); |
| 93 return error_code; |
| 94 } |
| 95 |
| 96 PlatformFileError NativeFileUtil::CreateDirectory( |
| 97 FileSystemOperationContext* context, |
| 98 const FilePath& file_path, |
| 99 bool exclusive, |
| 100 bool recursive) { |
| 101 // If parent dir of file doesn't exist. |
| 102 if (!recursive && !file_util::PathExists(file_path.DirName())) |
| 103 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 104 |
| 105 bool path_exists = file_util::PathExists(file_path); |
| 106 if (exclusive && path_exists) |
| 107 return base::PLATFORM_FILE_ERROR_EXISTS; |
| 108 |
| 109 // If file exists at the path. |
| 110 if (path_exists && !file_util::DirectoryExists(file_path)) |
| 111 return base::PLATFORM_FILE_ERROR_EXISTS; |
| 112 |
| 113 if (!file_util::CreateDirectory(file_path)) |
| 114 return base::PLATFORM_FILE_ERROR_FAILED; |
| 115 return base::PLATFORM_FILE_OK; |
| 116 } |
| 117 |
| 118 PlatformFileError NativeFileUtil::GetFileInfo( |
| 119 FileSystemOperationContext* unused, |
| 120 const FilePath& file_path, |
| 121 base::PlatformFileInfo* file_info, |
| 122 FilePath* platform_file_path) { |
| 123 if (!file_util::PathExists(file_path)) |
| 124 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 125 // TODO(rkc): Fix this hack once we have refactored file_util to handle |
| 126 // symlinks correctly. |
| 127 // http://code.google.com/p/chromium-os/issues/detail?id=15948 |
| 128 if (file_util::IsLink(file_path)) |
| 129 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 130 if (!file_util::GetFileInfo(file_path, file_info)) |
| 131 return base::PLATFORM_FILE_ERROR_FAILED; |
| 132 *platform_file_path = file_path; |
| 133 return base::PLATFORM_FILE_OK; |
| 134 } |
| 135 |
| 136 PlatformFileError NativeFileUtil::ReadDirectory( |
| 137 FileSystemOperationContext* unused, |
| 138 const FilePath& file_path, |
| 139 std::vector<base::FileUtilProxy::Entry>* entries) { |
| 140 // TODO(kkanetkar): Implement directory read in multiple chunks. |
| 141 if (!file_util::DirectoryExists(file_path)) |
| 142 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 143 |
| 144 file_util::FileEnumerator file_enum( |
| 145 file_path, false, static_cast<file_util::FileEnumerator::FileType>( |
| 146 file_util::FileEnumerator::FILES | |
| 147 file_util::FileEnumerator::DIRECTORIES)); |
| 148 FilePath current; |
| 149 while (!(current = file_enum.Next()).empty()) { |
| 150 base::FileUtilProxy::Entry entry; |
| 151 file_util::FileEnumerator::FindInfo info; |
| 152 file_enum.GetFindInfo(&info); |
| 153 entry.is_directory = file_enum.IsDirectory(info); |
| 154 // This will just give the entry's name instead of entire path |
| 155 // if we use current.value(). |
| 156 entry.name = file_util::FileEnumerator::GetFilename(info).value(); |
| 157 entry.size = file_util::FileEnumerator::GetFilesize(info); |
| 158 entry.last_modified_time = |
| 159 file_util::FileEnumerator::GetLastModifiedTime(info); |
| 160 // TODO(rkc): Fix this also once we've refactored file_util |
| 161 // http://code.google.com/p/chromium-os/issues/detail?id=15948 |
| 162 // This currently just prevents a file from showing up at all |
| 163 // if it's a link, hence preventing arbitary 'read' exploits. |
| 164 if (!file_util::IsLink(file_path.Append(entry.name))) |
| 165 entries->push_back(entry); |
| 166 } |
| 167 return base::PLATFORM_FILE_OK; |
| 168 } |
| 169 |
| 170 FileSystemFileUtil::AbstractFileEnumerator* |
| 171 NativeFileUtil::CreateFileEnumerator( |
| 172 FileSystemOperationContext* unused, |
| 173 const FilePath& root_path) { |
| 174 return new NativeFileEnumerator( |
| 175 root_path, true, static_cast<file_util::FileEnumerator::FileType>( |
| 176 file_util::FileEnumerator::FILES | |
| 177 file_util::FileEnumerator::DIRECTORIES)); |
| 178 } |
| 179 |
| 180 PlatformFileError NativeFileUtil::GetLocalFilePath( |
| 181 FileSystemOperationContext* unused, |
| 182 const FilePath& virtual_path, |
| 183 FilePath* local_path) { |
| 184 *local_path = virtual_path; |
| 185 return base::PLATFORM_FILE_OK; |
| 186 } |
| 187 |
| 188 PlatformFileError NativeFileUtil::Touch( |
| 189 FileSystemOperationContext* unused, |
| 190 const FilePath& file_path, |
| 191 const base::Time& last_access_time, |
| 192 const base::Time& last_modified_time) { |
| 193 if (!file_util::TouchFile( |
| 194 file_path, last_access_time, last_modified_time)) |
| 195 return base::PLATFORM_FILE_ERROR_FAILED; |
| 196 return base::PLATFORM_FILE_OK; |
| 197 } |
| 198 |
| 199 PlatformFileError NativeFileUtil::Truncate( |
| 200 FileSystemOperationContext* unused, |
| 201 const FilePath& file_path, |
| 202 int64 length) { |
| 203 PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED); |
| 204 PlatformFile file = |
| 205 base::CreatePlatformFile( |
| 206 file_path, |
| 207 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, |
| 208 NULL, |
| 209 &error_code); |
| 210 if (error_code != base::PLATFORM_FILE_OK) { |
| 211 return error_code; |
| 212 } |
| 213 DCHECK_NE(base::kInvalidPlatformFileValue, file); |
| 214 if (!base::TruncatePlatformFile(file, length)) |
| 215 error_code = base::PLATFORM_FILE_ERROR_FAILED; |
| 216 base::ClosePlatformFile(file); |
| 217 return error_code; |
| 218 } |
| 219 |
| 220 bool NativeFileUtil::PathExists( |
| 221 FileSystemOperationContext* unused, |
| 222 const FilePath& file_path) { |
| 223 return file_util::PathExists(file_path); |
| 224 } |
| 225 |
| 226 bool NativeFileUtil::DirectoryExists( |
| 227 FileSystemOperationContext* unused, |
| 228 const FilePath& file_path) { |
| 229 return file_util::DirectoryExists(file_path); |
| 230 } |
| 231 |
| 232 bool NativeFileUtil::IsDirectoryEmpty( |
| 233 FileSystemOperationContext* unused, |
| 234 const FilePath& file_path) { |
| 235 return file_util::IsDirectoryEmpty(file_path); |
| 236 } |
| 237 |
| 238 PlatformFileError NativeFileUtil::CopyOrMoveFile( |
| 239 FileSystemOperationContext* unused, |
| 240 const FilePath& src_file_path, |
| 241 const FilePath& dest_file_path, |
| 242 bool copy) { |
| 243 if (copy) { |
| 244 if (file_util::CopyFile(src_file_path, dest_file_path)) |
| 245 return base::PLATFORM_FILE_OK; |
| 246 } else { |
| 247 DCHECK(!file_util::DirectoryExists(src_file_path)); |
| 248 if (file_util::Move(src_file_path, dest_file_path)) |
| 249 return base::PLATFORM_FILE_OK; |
| 250 } |
| 251 return base::PLATFORM_FILE_ERROR_FAILED; |
| 252 } |
| 253 |
| 254 PlatformFileError NativeFileUtil::CopyInForeignFile( |
| 255 FileSystemOperationContext* context, |
| 256 const FilePath& src_file_path, |
| 257 const FilePath& dest_file_path) { |
| 258 return CopyOrMoveFile(context, src_file_path, dest_file_path, true); |
| 259 } |
| 260 |
| 261 PlatformFileError NativeFileUtil::DeleteFile( |
| 262 FileSystemOperationContext* unused, |
| 263 const FilePath& file_path) { |
| 264 if (!file_util::PathExists(file_path)) |
| 265 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 266 if (file_util::DirectoryExists(file_path)) |
| 267 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; |
| 268 if (!file_util::Delete(file_path, false)) |
| 269 return base::PLATFORM_FILE_ERROR_FAILED; |
| 270 return base::PLATFORM_FILE_OK; |
| 271 } |
| 272 |
| 273 PlatformFileError NativeFileUtil::DeleteSingleDirectory( |
| 274 FileSystemOperationContext* unused, |
| 275 const FilePath& file_path) { |
| 276 if (!file_util::PathExists(file_path)) |
| 277 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 278 if (!file_util::DirectoryExists(file_path)) { |
| 279 // TODO(dmikurube): Check if this error code is appropriate. |
| 280 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; |
| 281 } |
| 282 if (!file_util::IsDirectoryEmpty(file_path)) { |
| 283 // TODO(dmikurube): Check if this error code is appropriate. |
| 284 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; |
| 285 } |
| 286 if (!file_util::Delete(file_path, false)) |
| 287 return base::PLATFORM_FILE_ERROR_FAILED; |
| 288 return base::PLATFORM_FILE_OK; |
| 289 } |
| 290 |
| 291 } // namespace fileapi |
OLD | NEW |