Home | History | Annotate | Download | only in disk_cache
      1 // Copyright (c) 2006-2008 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 "net/disk_cache/file.h"
      6 
      7 #include "base/file_path.h"
      8 #include "base/message_loop.h"
      9 #include "base/singleton.h"
     10 #include "net/disk_cache/disk_cache.h"
     11 
     12 namespace {
     13 
     14 // Structure used for asynchronous operations.
     15 struct MyOverlapped {
     16   MyOverlapped(disk_cache::File* file, size_t offset,
     17                disk_cache::FileIOCallback* callback);
     18   ~MyOverlapped();
     19   OVERLAPPED* overlapped() {
     20     return &context_.overlapped;
     21   }
     22 
     23   MessageLoopForIO::IOContext context_;
     24   scoped_refptr<disk_cache::File> file_;
     25   disk_cache::FileIOCallback* callback_;
     26   const void* buffer_;
     27   bool delete_buffer_;  // Delete the user buffer at completion.
     28 };
     29 
     30 COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
     31 
     32 // Helper class to handle the IO completion notifications from the message loop.
     33 class CompletionHandler : public MessageLoopForIO::IOHandler {
     34   virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
     35                              DWORD actual_bytes, DWORD error);
     36 };
     37 
     38 void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
     39                                       DWORD actual_bytes, DWORD error) {
     40   MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
     41 
     42   if (error) {
     43     DCHECK(!actual_bytes);
     44     actual_bytes = static_cast<DWORD>(-1);
     45     NOTREACHED();
     46   }
     47 
     48   if (data->callback_)
     49     data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes));
     50 
     51   delete data;
     52 }
     53 
     54 MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset,
     55                            disk_cache::FileIOCallback* callback) {
     56   memset(this, 0, sizeof(*this));
     57   context_.handler = Singleton<CompletionHandler>::get();
     58   context_.overlapped.Offset = static_cast<DWORD>(offset);
     59   file_ = file;
     60   callback_ = callback;
     61 }
     62 
     63 MyOverlapped::~MyOverlapped() {
     64   if (delete_buffer_) {
     65     DCHECK(!callback_);
     66     // This whole thing could be updated to use IOBuffer, but PostWrite is not
     67     // used at the moment. TODO(rvargas): remove or update this code.
     68     delete[] reinterpret_cast<const char*>(buffer_);
     69   }
     70 }
     71 
     72 }  // namespace
     73 
     74 namespace disk_cache {
     75 
     76 File::File(base::PlatformFile file)
     77     : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE),
     78       sync_platform_file_(file) {
     79 }
     80 
     81 bool File::Init(const FilePath& name) {
     82   DCHECK(!init_);
     83   if (init_)
     84     return false;
     85 
     86   platform_file_ = CreateFile(name.value().c_str(),
     87                               GENERIC_READ | GENERIC_WRITE,
     88                               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
     89                               OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
     90 
     91   if (INVALID_HANDLE_VALUE == platform_file_)
     92     return false;
     93 
     94   MessageLoopForIO::current()->RegisterIOHandler(
     95       platform_file_, Singleton<CompletionHandler>::get());
     96 
     97   init_ = true;
     98   sync_platform_file_  = CreateFile(name.value().c_str(),
     99                                     GENERIC_READ | GENERIC_WRITE,
    100                                     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    101                                     OPEN_EXISTING, 0, NULL);
    102 
    103   if (INVALID_HANDLE_VALUE == sync_platform_file_)
    104     return false;
    105 
    106   return true;
    107 }
    108 
    109 File::~File() {
    110   if (!init_)
    111     return;
    112 
    113   if (INVALID_HANDLE_VALUE != platform_file_)
    114     CloseHandle(platform_file_);
    115   if (INVALID_HANDLE_VALUE != sync_platform_file_)
    116     CloseHandle(sync_platform_file_);
    117 }
    118 
    119 base::PlatformFile File::platform_file() const {
    120   DCHECK(init_);
    121   return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
    122                                                     platform_file_;
    123 }
    124 
    125 bool File::IsValid() const {
    126   if (!init_)
    127     return false;
    128   return (INVALID_HANDLE_VALUE != platform_file_ ||
    129           INVALID_HANDLE_VALUE != sync_platform_file_);
    130 }
    131 
    132 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
    133   DCHECK(init_);
    134   if (buffer_len > ULONG_MAX || offset > LONG_MAX)
    135     return false;
    136 
    137   DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
    138                              NULL, FILE_BEGIN);
    139   if (INVALID_SET_FILE_POINTER == ret)
    140     return false;
    141 
    142   DWORD actual;
    143   DWORD size = static_cast<DWORD>(buffer_len);
    144   if (!ReadFile(sync_platform_file_, buffer, size, &actual, NULL))
    145     return false;
    146   return actual == size;
    147 }
    148 
    149 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
    150   DCHECK(init_);
    151   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
    152     return false;
    153 
    154   DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
    155                              NULL, FILE_BEGIN);
    156   if (INVALID_SET_FILE_POINTER == ret)
    157     return false;
    158 
    159   DWORD actual;
    160   DWORD size = static_cast<DWORD>(buffer_len);
    161   if (!WriteFile(sync_platform_file_, buffer, size, &actual, NULL))
    162     return false;
    163   return actual == size;
    164 }
    165 
    166 // We have to increase the ref counter of the file before performing the IO to
    167 // prevent the completion to happen with an invalid handle (if the file is
    168 // closed while the IO is in flight).
    169 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
    170                 FileIOCallback* callback, bool* completed) {
    171   DCHECK(init_);
    172   if (!callback) {
    173     if (completed)
    174       *completed = true;
    175     return Read(buffer, buffer_len, offset);
    176   }
    177 
    178   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
    179     return false;
    180 
    181   MyOverlapped* data = new MyOverlapped(this, offset, callback);
    182   DWORD size = static_cast<DWORD>(buffer_len);
    183 
    184   DWORD actual;
    185   if (!ReadFile(platform_file_, buffer, size, &actual, data->overlapped())) {
    186     *completed = false;
    187     if (GetLastError() == ERROR_IO_PENDING)
    188       return true;
    189     delete data;
    190     return false;
    191   }
    192 
    193   // The operation completed already. We'll be called back anyway.
    194   *completed = (actual == size);
    195   DCHECK(actual == size);
    196   data->callback_ = NULL;
    197   data->file_ = NULL;  // There is no reason to hold on to this anymore.
    198   return *completed;
    199 }
    200 
    201 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
    202                  FileIOCallback* callback, bool* completed) {
    203   DCHECK(init_);
    204   if (!callback) {
    205     if (completed)
    206       *completed = true;
    207     return Write(buffer, buffer_len, offset);
    208   }
    209 
    210   return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
    211 }
    212 
    213 bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) {
    214   DCHECK(init_);
    215   return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL);
    216 }
    217 
    218 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
    219                       bool notify, FileIOCallback* callback, bool* completed) {
    220   DCHECK(init_);
    221   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
    222     return false;
    223 
    224   MyOverlapped* data = new MyOverlapped(this, offset, callback);
    225   bool dummy_completed;
    226   if (!callback) {
    227     DCHECK(!notify);
    228     data->delete_buffer_ = true;
    229     data->buffer_ = buffer;
    230     completed = &dummy_completed;
    231   }
    232 
    233   DWORD size = static_cast<DWORD>(buffer_len);
    234 
    235   DWORD actual;
    236   if (!WriteFile(platform_file_, buffer, size, &actual, data->overlapped())) {
    237     *completed = false;
    238     if (GetLastError() == ERROR_IO_PENDING)
    239       return true;
    240     delete data;
    241     return false;
    242   }
    243 
    244   // The operation completed already. We'll be called back anyway.
    245   *completed = (actual == size);
    246   DCHECK(actual == size);
    247   data->callback_ = NULL;
    248   data->file_ = NULL;  // There is no reason to hold on to this anymore.
    249   return *completed;
    250 }
    251 
    252 bool File::SetLength(size_t length) {
    253   DCHECK(init_);
    254   if (length > ULONG_MAX)
    255     return false;
    256 
    257   DWORD size = static_cast<DWORD>(length);
    258   HANDLE file = platform_file();
    259   if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN))
    260     return false;
    261 
    262   return TRUE == SetEndOfFile(file);
    263 }
    264 
    265 size_t File::GetLength() {
    266   DCHECK(init_);
    267   LARGE_INTEGER size;
    268   HANDLE file = platform_file();
    269   if (!GetFileSizeEx(file, &size))
    270     return 0;
    271   if (size.HighPart)
    272     return ULONG_MAX;
    273 
    274   return static_cast<size_t>(size.LowPart);
    275 }
    276 
    277 // Static.
    278 void File::WaitForPendingIO(int* num_pending_io) {
    279   while (*num_pending_io) {
    280     // Asynchronous IO operations may be in flight and the completion may end
    281     // up calling us back so let's wait for them.
    282     MessageLoopForIO::IOHandler* handler = Singleton<CompletionHandler>::get();
    283     MessageLoopForIO::current()->WaitForIOCompletion(100, handler);
    284   }
    285 }
    286 
    287 }  // namespace disk_cache
    288