Home | History | Annotate | Download | only in files
      1 // Copyright (c) 2012 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 "base/files/file.h"
      6 
      7 #include <io.h>
      8 
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "base/metrics/sparse_histogram.h"
     12 #include "base/threading/thread_restrictions.h"
     13 
     14 namespace base {
     15 
     16 void File::CreateBaseFileUnsafe(const FilePath& name, uint32 flags) {
     17   base::ThreadRestrictions::AssertIOAllowed();
     18   DCHECK(!IsValid());
     19 
     20   DWORD disposition = 0;
     21 
     22   if (flags & FLAG_OPEN)
     23     disposition = OPEN_EXISTING;
     24 
     25   if (flags & FLAG_CREATE) {
     26     DCHECK(!disposition);
     27     disposition = CREATE_NEW;
     28   }
     29 
     30   if (flags & FLAG_OPEN_ALWAYS) {
     31     DCHECK(!disposition);
     32     disposition = OPEN_ALWAYS;
     33   }
     34 
     35   if (flags & FLAG_CREATE_ALWAYS) {
     36     DCHECK(!disposition);
     37     disposition = CREATE_ALWAYS;
     38   }
     39 
     40   if (flags & FLAG_OPEN_TRUNCATED) {
     41     DCHECK(!disposition);
     42     DCHECK(flags & FLAG_WRITE);
     43     disposition = TRUNCATE_EXISTING;
     44   }
     45 
     46   if (!disposition) {
     47     NOTREACHED();
     48     return;
     49   }
     50 
     51   DWORD access = 0;
     52   if (flags & FLAG_WRITE)
     53     access = GENERIC_WRITE;
     54   if (flags & FLAG_APPEND) {
     55     DCHECK(!access);
     56     access = FILE_APPEND_DATA;
     57   }
     58   if (flags & FLAG_READ)
     59     access |= GENERIC_READ;
     60   if (flags & FLAG_WRITE_ATTRIBUTES)
     61     access |= FILE_WRITE_ATTRIBUTES;
     62   if (flags & FLAG_EXECUTE)
     63     access |= GENERIC_EXECUTE;
     64 
     65   DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
     66   if (!(flags & FLAG_EXCLUSIVE_WRITE))
     67     sharing |= FILE_SHARE_WRITE;
     68   if (flags & FLAG_SHARE_DELETE)
     69     sharing |= FILE_SHARE_DELETE;
     70 
     71   DWORD create_flags = 0;
     72   if (flags & FLAG_ASYNC)
     73     create_flags |= FILE_FLAG_OVERLAPPED;
     74   if (flags & FLAG_TEMPORARY)
     75     create_flags |= FILE_ATTRIBUTE_TEMPORARY;
     76   if (flags & FLAG_HIDDEN)
     77     create_flags |= FILE_ATTRIBUTE_HIDDEN;
     78   if (flags & FLAG_DELETE_ON_CLOSE)
     79     create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
     80   if (flags & FLAG_BACKUP_SEMANTICS)
     81     create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
     82 
     83   file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
     84                        disposition, create_flags, NULL));
     85 
     86   if (file_.IsValid()) {
     87     error_ = FILE_OK;
     88     async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
     89 
     90     if (flags & (FLAG_OPEN_ALWAYS))
     91       created_ = (ERROR_ALREADY_EXISTS != GetLastError());
     92     else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
     93       created_ = true;
     94   } else {
     95     error_ = OSErrorToFileError(GetLastError());
     96   }
     97 }
     98 
     99 bool File::IsValid() const {
    100   return file_.IsValid();
    101 }
    102 PlatformFile File::TakePlatformFile() {
    103   return file_.Take();
    104 }
    105 
    106 void File::Close() {
    107   base::ThreadRestrictions::AssertIOAllowed();
    108   file_.Close();
    109 }
    110 
    111 int64 File::Seek(Whence whence, int64 offset) {
    112   base::ThreadRestrictions::AssertIOAllowed();
    113   DCHECK(IsValid());
    114   if (offset < 0)
    115     return -1;
    116 
    117   LARGE_INTEGER distance, res;
    118   distance.QuadPart = offset;
    119   DWORD move_method = static_cast<DWORD>(whence);
    120   if (!SetFilePointerEx(file_, distance, &res, move_method))
    121     return -1;
    122   return res.QuadPart;
    123 }
    124 
    125 int File::Read(int64 offset, char* data, int size) {
    126   base::ThreadRestrictions::AssertIOAllowed();
    127   DCHECK(IsValid());
    128   DCHECK(!async_);
    129   if (size < 0)
    130     return -1;
    131 
    132   LARGE_INTEGER offset_li;
    133   offset_li.QuadPart = offset;
    134 
    135   OVERLAPPED overlapped = {0};
    136   overlapped.Offset = offset_li.LowPart;
    137   overlapped.OffsetHigh = offset_li.HighPart;
    138 
    139   DWORD bytes_read;
    140   if (::ReadFile(file_, data, size, &bytes_read, &overlapped) != 0)
    141     return bytes_read;
    142   if (ERROR_HANDLE_EOF == GetLastError())
    143     return 0;
    144 
    145   return -1;
    146 }
    147 
    148 int File::ReadAtCurrentPos(char* data, int size) {
    149   base::ThreadRestrictions::AssertIOAllowed();
    150   DCHECK(IsValid());
    151   DCHECK(!async_);
    152   if (size < 0)
    153     return -1;
    154 
    155   DWORD bytes_read;
    156   if (::ReadFile(file_, data, size, &bytes_read, NULL) != 0)
    157     return bytes_read;
    158   if (ERROR_HANDLE_EOF == GetLastError())
    159     return 0;
    160 
    161   return -1;
    162 }
    163 
    164 int File::ReadNoBestEffort(int64 offset, char* data, int size) {
    165   return Read(offset, data, size);
    166 }
    167 
    168 int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
    169   return ReadAtCurrentPos(data, size);
    170 }
    171 
    172 int File::Write(int64 offset, const char* data, int size) {
    173   base::ThreadRestrictions::AssertIOAllowed();
    174   DCHECK(IsValid());
    175   DCHECK(!async_);
    176 
    177   LARGE_INTEGER offset_li;
    178   offset_li.QuadPart = offset;
    179 
    180   OVERLAPPED overlapped = {0};
    181   overlapped.Offset = offset_li.LowPart;
    182   overlapped.OffsetHigh = offset_li.HighPart;
    183 
    184   DWORD bytes_written;
    185   if (::WriteFile(file_, data, size, &bytes_written, &overlapped) != 0)
    186     return bytes_written;
    187 
    188   return -1;
    189 }
    190 
    191 int File::WriteAtCurrentPos(const char* data, int size) {
    192   NOTREACHED();
    193   return -1;
    194 }
    195 
    196 int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
    197   return WriteAtCurrentPos(data, size);
    198 }
    199 
    200 bool File::Truncate(int64 length) {
    201   base::ThreadRestrictions::AssertIOAllowed();
    202   DCHECK(IsValid());
    203 
    204   // Get the current file pointer.
    205   LARGE_INTEGER file_pointer;
    206   LARGE_INTEGER zero;
    207   zero.QuadPart = 0;
    208   if (::SetFilePointerEx(file_, zero, &file_pointer, FILE_CURRENT) == 0)
    209     return false;
    210 
    211   LARGE_INTEGER length_li;
    212   length_li.QuadPart = length;
    213   // If length > file size, SetFilePointerEx() should extend the file
    214   // with zeroes on all Windows standard file systems (NTFS, FATxx).
    215   if (!::SetFilePointerEx(file_, length_li, NULL, FILE_BEGIN))
    216     return false;
    217 
    218   // Set the new file length and move the file pointer to its old position.
    219   // This is consistent with ftruncate()'s behavior, even when the file
    220   // pointer points to a location beyond the end of the file.
    221   return ((::SetEndOfFile(file_) != 0) &&
    222           (::SetFilePointerEx(file_, file_pointer, NULL, FILE_BEGIN) != 0));
    223 }
    224 
    225 bool File::Flush() {
    226   base::ThreadRestrictions::AssertIOAllowed();
    227   DCHECK(IsValid());
    228   return ::FlushFileBuffers(file_) != FALSE;
    229 }
    230 
    231 bool File::SetTimes(Time last_access_time, Time last_modified_time) {
    232   base::ThreadRestrictions::AssertIOAllowed();
    233   DCHECK(IsValid());
    234 
    235   FILETIME last_access_filetime = last_access_time.ToFileTime();
    236   FILETIME last_modified_filetime = last_modified_time.ToFileTime();
    237   return (::SetFileTime(file_, NULL, &last_access_filetime,
    238                         &last_modified_filetime) != 0);
    239 }
    240 
    241 bool File::GetInfo(Info* info) {
    242   base::ThreadRestrictions::AssertIOAllowed();
    243   DCHECK(IsValid());
    244 
    245   BY_HANDLE_FILE_INFORMATION file_info;
    246   if (GetFileInformationByHandle(file_, &file_info) == 0)
    247     return false;
    248 
    249   LARGE_INTEGER size;
    250   size.HighPart = file_info.nFileSizeHigh;
    251   size.LowPart = file_info.nFileSizeLow;
    252   info->size = size.QuadPart;
    253   info->is_directory =
    254       (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
    255   info->is_symbolic_link = false;  // Windows doesn't have symbolic links.
    256   info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
    257   info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
    258   info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
    259   return true;
    260 }
    261 
    262 File::Error base::File::Lock() {
    263   DCHECK(IsValid());
    264   BOOL result = LockFile(file_, 0, 0, MAXDWORD, MAXDWORD);
    265   if (!result)
    266     return OSErrorToFileError(GetLastError());
    267   return FILE_OK;
    268 }
    269 
    270 File::Error File::Unlock() {
    271   DCHECK(IsValid());
    272   BOOL result = UnlockFile(file_, 0, 0, MAXDWORD, MAXDWORD);
    273   if (!result)
    274     return OSErrorToFileError(GetLastError());
    275   return FILE_OK;
    276 }
    277 
    278 // Static.
    279 File::Error File::OSErrorToFileError(DWORD last_error) {
    280   switch (last_error) {
    281     case ERROR_SHARING_VIOLATION:
    282       return FILE_ERROR_IN_USE;
    283     case ERROR_FILE_EXISTS:
    284       return FILE_ERROR_EXISTS;
    285     case ERROR_FILE_NOT_FOUND:
    286     case ERROR_PATH_NOT_FOUND:
    287       return FILE_ERROR_NOT_FOUND;
    288     case ERROR_ACCESS_DENIED:
    289       return FILE_ERROR_ACCESS_DENIED;
    290     case ERROR_TOO_MANY_OPEN_FILES:
    291       return FILE_ERROR_TOO_MANY_OPENED;
    292     case ERROR_OUTOFMEMORY:
    293     case ERROR_NOT_ENOUGH_MEMORY:
    294       return FILE_ERROR_NO_MEMORY;
    295     case ERROR_HANDLE_DISK_FULL:
    296     case ERROR_DISK_FULL:
    297     case ERROR_DISK_RESOURCES_EXHAUSTED:
    298       return FILE_ERROR_NO_SPACE;
    299     case ERROR_USER_MAPPED_FILE:
    300       return FILE_ERROR_INVALID_OPERATION;
    301     case ERROR_NOT_READY:
    302     case ERROR_SECTOR_NOT_FOUND:
    303     case ERROR_DEV_NOT_EXIST:
    304     case ERROR_IO_DEVICE:
    305     case ERROR_FILE_CORRUPT:
    306     case ERROR_DISK_CORRUPT:
    307       return FILE_ERROR_IO;
    308     default:
    309       UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
    310                                   last_error);
    311       return FILE_ERROR_FAILED;
    312   }
    313 }
    314 
    315 void File::SetPlatformFile(PlatformFile file) {
    316   file_.Set(file);
    317 }
    318 
    319 }  // namespace base
    320