16d528ed9Sopenharmony_ci// Copyright (c) 2012 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#include "base/files/file.h" 66d528ed9Sopenharmony_ci 76d528ed9Sopenharmony_ci#include <io.h> 86d528ed9Sopenharmony_ci#include <stdint.h> 96d528ed9Sopenharmony_ci 106d528ed9Sopenharmony_ci#include "base/logging.h" 116d528ed9Sopenharmony_ci#include "base/win/win_util.h" 126d528ed9Sopenharmony_ci 136d528ed9Sopenharmony_ci#include <windows.h> 146d528ed9Sopenharmony_ci 156d528ed9Sopenharmony_cinamespace base { 166d528ed9Sopenharmony_ci 176d528ed9Sopenharmony_ci// Make sure our Whence mappings match the system headers. 186d528ed9Sopenharmony_cistatic_assert(File::FROM_BEGIN == FILE_BEGIN && 196d528ed9Sopenharmony_ci File::FROM_CURRENT == FILE_CURRENT && 206d528ed9Sopenharmony_ci File::FROM_END == FILE_END, 216d528ed9Sopenharmony_ci "whence mapping must match the system headers"); 226d528ed9Sopenharmony_ci 236d528ed9Sopenharmony_cibool File::IsValid() const { 246d528ed9Sopenharmony_ci return file_.IsValid(); 256d528ed9Sopenharmony_ci} 266d528ed9Sopenharmony_ci 276d528ed9Sopenharmony_ciPlatformFile File::GetPlatformFile() const { 286d528ed9Sopenharmony_ci return file_.Get(); 296d528ed9Sopenharmony_ci} 306d528ed9Sopenharmony_ci 316d528ed9Sopenharmony_ciPlatformFile File::TakePlatformFile() { 326d528ed9Sopenharmony_ci return file_.Take(); 336d528ed9Sopenharmony_ci} 346d528ed9Sopenharmony_ci 356d528ed9Sopenharmony_civoid File::Close() { 366d528ed9Sopenharmony_ci if (!file_.IsValid()) 376d528ed9Sopenharmony_ci return; 386d528ed9Sopenharmony_ci 396d528ed9Sopenharmony_ci file_.Close(); 406d528ed9Sopenharmony_ci} 416d528ed9Sopenharmony_ci 426d528ed9Sopenharmony_ciint64_t File::Seek(Whence whence, int64_t offset) { 436d528ed9Sopenharmony_ci DCHECK(IsValid()); 446d528ed9Sopenharmony_ci 456d528ed9Sopenharmony_ci LARGE_INTEGER distance, res; 466d528ed9Sopenharmony_ci distance.QuadPart = offset; 476d528ed9Sopenharmony_ci DWORD move_method = static_cast<DWORD>(whence); 486d528ed9Sopenharmony_ci if (!SetFilePointerEx(file_.Get(), distance, &res, move_method)) 496d528ed9Sopenharmony_ci return -1; 506d528ed9Sopenharmony_ci return res.QuadPart; 516d528ed9Sopenharmony_ci} 526d528ed9Sopenharmony_ci 536d528ed9Sopenharmony_ciint File::Read(int64_t offset, char* data, int size) { 546d528ed9Sopenharmony_ci DCHECK(IsValid()); 556d528ed9Sopenharmony_ci if (size < 0) 566d528ed9Sopenharmony_ci return -1; 576d528ed9Sopenharmony_ci 586d528ed9Sopenharmony_ci LARGE_INTEGER offset_li; 596d528ed9Sopenharmony_ci offset_li.QuadPart = offset; 606d528ed9Sopenharmony_ci 616d528ed9Sopenharmony_ci OVERLAPPED overlapped = {}; 626d528ed9Sopenharmony_ci overlapped.Offset = offset_li.LowPart; 636d528ed9Sopenharmony_ci overlapped.OffsetHigh = offset_li.HighPart; 646d528ed9Sopenharmony_ci 656d528ed9Sopenharmony_ci DWORD bytes_read; 666d528ed9Sopenharmony_ci if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped)) 676d528ed9Sopenharmony_ci return bytes_read; 686d528ed9Sopenharmony_ci if (ERROR_HANDLE_EOF == GetLastError()) 696d528ed9Sopenharmony_ci return 0; 706d528ed9Sopenharmony_ci 716d528ed9Sopenharmony_ci return -1; 726d528ed9Sopenharmony_ci} 736d528ed9Sopenharmony_ci 746d528ed9Sopenharmony_ciint File::ReadAtCurrentPos(char* data, int size) { 756d528ed9Sopenharmony_ci DCHECK(IsValid()); 766d528ed9Sopenharmony_ci if (size < 0) 776d528ed9Sopenharmony_ci return -1; 786d528ed9Sopenharmony_ci 796d528ed9Sopenharmony_ci DWORD bytes_read; 806d528ed9Sopenharmony_ci if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL)) 816d528ed9Sopenharmony_ci return bytes_read; 826d528ed9Sopenharmony_ci if (ERROR_HANDLE_EOF == GetLastError()) 836d528ed9Sopenharmony_ci return 0; 846d528ed9Sopenharmony_ci 856d528ed9Sopenharmony_ci return -1; 866d528ed9Sopenharmony_ci} 876d528ed9Sopenharmony_ci 886d528ed9Sopenharmony_ciint File::ReadNoBestEffort(int64_t offset, char* data, int size) { 896d528ed9Sopenharmony_ci // TODO(dbeam): trace this separately? 906d528ed9Sopenharmony_ci return Read(offset, data, size); 916d528ed9Sopenharmony_ci} 926d528ed9Sopenharmony_ci 936d528ed9Sopenharmony_ciint File::ReadAtCurrentPosNoBestEffort(char* data, int size) { 946d528ed9Sopenharmony_ci // TODO(dbeam): trace this separately? 956d528ed9Sopenharmony_ci return ReadAtCurrentPos(data, size); 966d528ed9Sopenharmony_ci} 976d528ed9Sopenharmony_ci 986d528ed9Sopenharmony_ciint File::Write(int64_t offset, const char* data, int size) { 996d528ed9Sopenharmony_ci DCHECK(IsValid()); 1006d528ed9Sopenharmony_ci 1016d528ed9Sopenharmony_ci LARGE_INTEGER offset_li; 1026d528ed9Sopenharmony_ci offset_li.QuadPart = offset; 1036d528ed9Sopenharmony_ci 1046d528ed9Sopenharmony_ci OVERLAPPED overlapped = {}; 1056d528ed9Sopenharmony_ci overlapped.Offset = offset_li.LowPart; 1066d528ed9Sopenharmony_ci overlapped.OffsetHigh = offset_li.HighPart; 1076d528ed9Sopenharmony_ci 1086d528ed9Sopenharmony_ci DWORD bytes_written; 1096d528ed9Sopenharmony_ci if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped)) 1106d528ed9Sopenharmony_ci return bytes_written; 1116d528ed9Sopenharmony_ci 1126d528ed9Sopenharmony_ci return -1; 1136d528ed9Sopenharmony_ci} 1146d528ed9Sopenharmony_ci 1156d528ed9Sopenharmony_ciint File::WriteAtCurrentPos(const char* data, int size) { 1166d528ed9Sopenharmony_ci DCHECK(IsValid()); 1176d528ed9Sopenharmony_ci if (size < 0) 1186d528ed9Sopenharmony_ci return -1; 1196d528ed9Sopenharmony_ci 1206d528ed9Sopenharmony_ci DWORD bytes_written; 1216d528ed9Sopenharmony_ci if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL)) 1226d528ed9Sopenharmony_ci return bytes_written; 1236d528ed9Sopenharmony_ci 1246d528ed9Sopenharmony_ci return -1; 1256d528ed9Sopenharmony_ci} 1266d528ed9Sopenharmony_ci 1276d528ed9Sopenharmony_ciint File::WriteAtCurrentPosNoBestEffort(const char* data, int size) { 1286d528ed9Sopenharmony_ci return WriteAtCurrentPos(data, size); 1296d528ed9Sopenharmony_ci} 1306d528ed9Sopenharmony_ci 1316d528ed9Sopenharmony_ciint64_t File::GetLength() { 1326d528ed9Sopenharmony_ci DCHECK(IsValid()); 1336d528ed9Sopenharmony_ci 1346d528ed9Sopenharmony_ci LARGE_INTEGER size; 1356d528ed9Sopenharmony_ci if (!::GetFileSizeEx(file_.Get(), &size)) 1366d528ed9Sopenharmony_ci return -1; 1376d528ed9Sopenharmony_ci 1386d528ed9Sopenharmony_ci return static_cast<int64_t>(size.QuadPart); 1396d528ed9Sopenharmony_ci} 1406d528ed9Sopenharmony_ci 1416d528ed9Sopenharmony_cibool File::SetLength(int64_t length) { 1426d528ed9Sopenharmony_ci DCHECK(IsValid()); 1436d528ed9Sopenharmony_ci 1446d528ed9Sopenharmony_ci // Get the current file pointer. 1456d528ed9Sopenharmony_ci LARGE_INTEGER file_pointer; 1466d528ed9Sopenharmony_ci LARGE_INTEGER zero; 1476d528ed9Sopenharmony_ci zero.QuadPart = 0; 1486d528ed9Sopenharmony_ci if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT)) 1496d528ed9Sopenharmony_ci return false; 1506d528ed9Sopenharmony_ci 1516d528ed9Sopenharmony_ci LARGE_INTEGER length_li; 1526d528ed9Sopenharmony_ci length_li.QuadPart = length; 1536d528ed9Sopenharmony_ci // If length > file size, SetFilePointerEx() should extend the file 1546d528ed9Sopenharmony_ci // with zeroes on all Windows standard file systems (NTFS, FATxx). 1556d528ed9Sopenharmony_ci if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN)) 1566d528ed9Sopenharmony_ci return false; 1576d528ed9Sopenharmony_ci 1586d528ed9Sopenharmony_ci // Set the new file length and move the file pointer to its old position. 1596d528ed9Sopenharmony_ci // This is consistent with ftruncate()'s behavior, even when the file 1606d528ed9Sopenharmony_ci // pointer points to a location beyond the end of the file. 1616d528ed9Sopenharmony_ci // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not 1626d528ed9Sopenharmony_ci // promised by the interface (nor was promised by PlatformFile). See if this 1636d528ed9Sopenharmony_ci // implementation detail can be removed. 1646d528ed9Sopenharmony_ci return ((::SetEndOfFile(file_.Get()) != FALSE) && 1656d528ed9Sopenharmony_ci (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) != 1666d528ed9Sopenharmony_ci FALSE)); 1676d528ed9Sopenharmony_ci} 1686d528ed9Sopenharmony_ci 1696d528ed9Sopenharmony_cibool File::GetInfo(Info* info) { 1706d528ed9Sopenharmony_ci DCHECK(IsValid()); 1716d528ed9Sopenharmony_ci 1726d528ed9Sopenharmony_ci BY_HANDLE_FILE_INFORMATION file_info; 1736d528ed9Sopenharmony_ci if (!GetFileInformationByHandle(file_.Get(), &file_info)) 1746d528ed9Sopenharmony_ci return false; 1756d528ed9Sopenharmony_ci 1766d528ed9Sopenharmony_ci LARGE_INTEGER size; 1776d528ed9Sopenharmony_ci size.HighPart = file_info.nFileSizeHigh; 1786d528ed9Sopenharmony_ci size.LowPart = file_info.nFileSizeLow; 1796d528ed9Sopenharmony_ci info->size = size.QuadPart; 1806d528ed9Sopenharmony_ci info->is_directory = 1816d528ed9Sopenharmony_ci (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; 1826d528ed9Sopenharmony_ci info->is_symbolic_link = false; // Windows doesn't have symbolic links. 1836d528ed9Sopenharmony_ci info->last_modified = 1846d528ed9Sopenharmony_ci *reinterpret_cast<uint64_t*>(&file_info.ftLastWriteTime); 1856d528ed9Sopenharmony_ci info->last_accessed = 1866d528ed9Sopenharmony_ci *reinterpret_cast<uint64_t*>(&file_info.ftLastAccessTime); 1876d528ed9Sopenharmony_ci info->creation_time = *reinterpret_cast<uint64_t*>(&file_info.ftCreationTime); 1886d528ed9Sopenharmony_ci return true; 1896d528ed9Sopenharmony_ci} 1906d528ed9Sopenharmony_ci 1916d528ed9Sopenharmony_ciFile::Error File::Lock() { 1926d528ed9Sopenharmony_ci DCHECK(IsValid()); 1936d528ed9Sopenharmony_ci 1946d528ed9Sopenharmony_ci BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD); 1956d528ed9Sopenharmony_ci if (!result) 1966d528ed9Sopenharmony_ci return GetLastFileError(); 1976d528ed9Sopenharmony_ci return FILE_OK; 1986d528ed9Sopenharmony_ci} 1996d528ed9Sopenharmony_ci 2006d528ed9Sopenharmony_ciFile::Error File::Unlock() { 2016d528ed9Sopenharmony_ci DCHECK(IsValid()); 2026d528ed9Sopenharmony_ci 2036d528ed9Sopenharmony_ci BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD); 2046d528ed9Sopenharmony_ci if (!result) 2056d528ed9Sopenharmony_ci return GetLastFileError(); 2066d528ed9Sopenharmony_ci return FILE_OK; 2076d528ed9Sopenharmony_ci} 2086d528ed9Sopenharmony_ci 2096d528ed9Sopenharmony_ciFile File::Duplicate() const { 2106d528ed9Sopenharmony_ci if (!IsValid()) 2116d528ed9Sopenharmony_ci return File(); 2126d528ed9Sopenharmony_ci 2136d528ed9Sopenharmony_ci HANDLE other_handle = nullptr; 2146d528ed9Sopenharmony_ci 2156d528ed9Sopenharmony_ci if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle 2166d528ed9Sopenharmony_ci GetPlatformFile(), 2176d528ed9Sopenharmony_ci GetCurrentProcess(), // hTargetProcessHandle 2186d528ed9Sopenharmony_ci &other_handle, 2196d528ed9Sopenharmony_ci 0, // dwDesiredAccess ignored due to SAME_ACCESS 2206d528ed9Sopenharmony_ci FALSE, // !bInheritHandle 2216d528ed9Sopenharmony_ci DUPLICATE_SAME_ACCESS)) { 2226d528ed9Sopenharmony_ci return File(GetLastFileError()); 2236d528ed9Sopenharmony_ci } 2246d528ed9Sopenharmony_ci 2256d528ed9Sopenharmony_ci File other(other_handle); 2266d528ed9Sopenharmony_ci return other; 2276d528ed9Sopenharmony_ci} 2286d528ed9Sopenharmony_ci 2296d528ed9Sopenharmony_ci// Static. 2306d528ed9Sopenharmony_ciFile::Error File::OSErrorToFileError(DWORD last_error) { 2316d528ed9Sopenharmony_ci switch (last_error) { 2326d528ed9Sopenharmony_ci case ERROR_SHARING_VIOLATION: 2336d528ed9Sopenharmony_ci return FILE_ERROR_IN_USE; 2346d528ed9Sopenharmony_ci case ERROR_ALREADY_EXISTS: 2356d528ed9Sopenharmony_ci case ERROR_FILE_EXISTS: 2366d528ed9Sopenharmony_ci return FILE_ERROR_EXISTS; 2376d528ed9Sopenharmony_ci case ERROR_FILE_NOT_FOUND: 2386d528ed9Sopenharmony_ci case ERROR_PATH_NOT_FOUND: 2396d528ed9Sopenharmony_ci return FILE_ERROR_NOT_FOUND; 2406d528ed9Sopenharmony_ci case ERROR_ACCESS_DENIED: 2416d528ed9Sopenharmony_ci return FILE_ERROR_ACCESS_DENIED; 2426d528ed9Sopenharmony_ci case ERROR_TOO_MANY_OPEN_FILES: 2436d528ed9Sopenharmony_ci return FILE_ERROR_TOO_MANY_OPENED; 2446d528ed9Sopenharmony_ci case ERROR_OUTOFMEMORY: 2456d528ed9Sopenharmony_ci case ERROR_NOT_ENOUGH_MEMORY: 2466d528ed9Sopenharmony_ci return FILE_ERROR_NO_MEMORY; 2476d528ed9Sopenharmony_ci case ERROR_HANDLE_DISK_FULL: 2486d528ed9Sopenharmony_ci case ERROR_DISK_FULL: 2496d528ed9Sopenharmony_ci#ifndef __MINGW32__ 2506d528ed9Sopenharmony_ci case ERROR_DISK_RESOURCES_EXHAUSTED: 2516d528ed9Sopenharmony_ci#endif 2526d528ed9Sopenharmony_ci return FILE_ERROR_NO_SPACE; 2536d528ed9Sopenharmony_ci case ERROR_USER_MAPPED_FILE: 2546d528ed9Sopenharmony_ci return FILE_ERROR_INVALID_OPERATION; 2556d528ed9Sopenharmony_ci case ERROR_NOT_READY: 2566d528ed9Sopenharmony_ci case ERROR_SECTOR_NOT_FOUND: 2576d528ed9Sopenharmony_ci case ERROR_DEV_NOT_EXIST: 2586d528ed9Sopenharmony_ci case ERROR_IO_DEVICE: 2596d528ed9Sopenharmony_ci case ERROR_FILE_CORRUPT: 2606d528ed9Sopenharmony_ci case ERROR_DISK_CORRUPT: 2616d528ed9Sopenharmony_ci return FILE_ERROR_IO; 2626d528ed9Sopenharmony_ci default: 2636d528ed9Sopenharmony_ci // This function should only be called for errors. 2646d528ed9Sopenharmony_ci DCHECK_NE(static_cast<DWORD>(ERROR_SUCCESS), last_error); 2656d528ed9Sopenharmony_ci return FILE_ERROR_FAILED; 2666d528ed9Sopenharmony_ci } 2676d528ed9Sopenharmony_ci} 2686d528ed9Sopenharmony_ci 2696d528ed9Sopenharmony_civoid File::DoInitialize(const FilePath& path, uint32_t flags) { 2706d528ed9Sopenharmony_ci DCHECK(!IsValid()); 2716d528ed9Sopenharmony_ci 2726d528ed9Sopenharmony_ci DWORD disposition = 0; 2736d528ed9Sopenharmony_ci 2746d528ed9Sopenharmony_ci if (flags & FLAG_OPEN) 2756d528ed9Sopenharmony_ci disposition = OPEN_EXISTING; 2766d528ed9Sopenharmony_ci 2776d528ed9Sopenharmony_ci if (flags & FLAG_CREATE) { 2786d528ed9Sopenharmony_ci DCHECK(!disposition); 2796d528ed9Sopenharmony_ci disposition = CREATE_NEW; 2806d528ed9Sopenharmony_ci } 2816d528ed9Sopenharmony_ci 2826d528ed9Sopenharmony_ci if (flags & FLAG_CREATE_ALWAYS) { 2836d528ed9Sopenharmony_ci DCHECK(!disposition); 2846d528ed9Sopenharmony_ci DCHECK(flags & FLAG_WRITE); 2856d528ed9Sopenharmony_ci disposition = CREATE_ALWAYS; 2866d528ed9Sopenharmony_ci } 2876d528ed9Sopenharmony_ci 2886d528ed9Sopenharmony_ci if (!disposition) { 2896d528ed9Sopenharmony_ci ::SetLastError(ERROR_INVALID_PARAMETER); 2906d528ed9Sopenharmony_ci error_details_ = FILE_ERROR_FAILED; 2916d528ed9Sopenharmony_ci NOTREACHED(); 2926d528ed9Sopenharmony_ci return; 2936d528ed9Sopenharmony_ci } 2946d528ed9Sopenharmony_ci 2956d528ed9Sopenharmony_ci DWORD access = 0; 2966d528ed9Sopenharmony_ci if (flags & FLAG_WRITE) 2976d528ed9Sopenharmony_ci access = GENERIC_WRITE; 2986d528ed9Sopenharmony_ci if (flags & FLAG_READ) 2996d528ed9Sopenharmony_ci access |= GENERIC_READ; 3006d528ed9Sopenharmony_ci 3016d528ed9Sopenharmony_ci DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 3026d528ed9Sopenharmony_ci DWORD create_flags = 0; 3036d528ed9Sopenharmony_ci file_.Set(CreateFile(ToWCharT(&path.value()), access, sharing, NULL, 3046d528ed9Sopenharmony_ci disposition, create_flags, NULL)); 3056d528ed9Sopenharmony_ci 3066d528ed9Sopenharmony_ci if (file_.IsValid()) { 3076d528ed9Sopenharmony_ci error_details_ = FILE_OK; 3086d528ed9Sopenharmony_ci } else { 3096d528ed9Sopenharmony_ci error_details_ = GetLastFileError(); 3106d528ed9Sopenharmony_ci } 3116d528ed9Sopenharmony_ci} 3126d528ed9Sopenharmony_ci 3136d528ed9Sopenharmony_cibool File::Flush() { 3146d528ed9Sopenharmony_ci DCHECK(IsValid()); 3156d528ed9Sopenharmony_ci return ::FlushFileBuffers(file_.Get()) != FALSE; 3166d528ed9Sopenharmony_ci} 3176d528ed9Sopenharmony_ci 3186d528ed9Sopenharmony_civoid File::SetPlatformFile(PlatformFile file) { 3196d528ed9Sopenharmony_ci file_.Set(file); 3206d528ed9Sopenharmony_ci} 3216d528ed9Sopenharmony_ci 3226d528ed9Sopenharmony_ci// static 3236d528ed9Sopenharmony_ciFile::Error File::GetLastFileError() { 3246d528ed9Sopenharmony_ci return File::OSErrorToFileError(GetLastError()); 3256d528ed9Sopenharmony_ci} 3266d528ed9Sopenharmony_ci 3276d528ed9Sopenharmony_ci} // namespace base 328