tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FileStreams.cpp (11134B)


      1 // FileStreams.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #ifndef _WIN32
      6 #include <fcntl.h>
      7 #include <unistd.h>
      8 #include <errno.h>
      9 #endif
     10 
     11 #ifdef SUPPORT_DEVICE_FILE
     12 #include "../../../C/Alloc.h"
     13 #include "../../Common/Defs.h"
     14 #endif
     15 
     16 #include "FileStreams.h"
     17 
     18 static inline HRESULT ConvertBoolToHRESULT(bool result)
     19 {
     20  #ifdef _WIN32
     21  if (result)
     22    return S_OK;
     23  DWORD lastError = ::GetLastError();
     24  if (lastError == 0)
     25    return E_FAIL;
     26  return HRESULT_FROM_WIN32(lastError);
     27  #else
     28  return result ? S_OK: E_FAIL;
     29  #endif
     30 }
     31 
     32 
     33 static const UInt32 kClusterSize = 1 << 18;
     34 CInFileStream::CInFileStream():
     35  #ifdef SUPPORT_DEVICE_FILE
     36  VirtPos(0),
     37  PhyPos(0),
     38  Buf(0),
     39  BufSize(0),
     40  #endif
     41  SupportHardLinks(false),
     42  Callback(NULL),
     43  CallbackRef(0)
     44 {
     45 }
     46 
     47 CInFileStream::~CInFileStream()
     48 {
     49  #ifdef SUPPORT_DEVICE_FILE
     50  MidFree(Buf);
     51  #endif
     52 
     53  if (Callback)
     54    Callback->InFileStream_On_Destroy(CallbackRef);
     55 }
     56 
     57 STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
     58 {
     59  #ifdef USE_WIN_FILE
     60  
     61  #ifdef SUPPORT_DEVICE_FILE
     62  if (processedSize)
     63    *processedSize = 0;
     64  if (size == 0)
     65    return S_OK;
     66  if (File.IsDeviceFile)
     67  {
     68    if (File.SizeDefined)
     69    {
     70      if (VirtPos >= File.Size)
     71        return VirtPos == File.Size ? S_OK : E_FAIL;
     72      UInt64 rem = File.Size - VirtPos;
     73      if (size > rem)
     74        size = (UInt32)rem;
     75    }
     76    for (;;)
     77    {
     78      const UInt32 mask = kClusterSize - 1;
     79      const UInt64 mask2 = ~(UInt64)mask;
     80      UInt64 alignedPos = VirtPos & mask2;
     81      if (BufSize > 0 && BufStartPos == alignedPos)
     82      {
     83        UInt32 pos = (UInt32)VirtPos & mask;
     84        if (pos >= BufSize)
     85          return S_OK;
     86        UInt32 rem = MyMin(BufSize - pos, size);
     87        memcpy(data, Buf + pos, rem);
     88        VirtPos += rem;
     89        if (processedSize)
     90          *processedSize += rem;
     91        return S_OK;
     92      }
     93      
     94      bool useBuf = false;
     95      if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 )
     96        useBuf = true;
     97      else
     98      {
     99        UInt64 end = VirtPos + size;
    100        if ((end & mask) != 0)
    101        {
    102          end &= mask2;
    103          if (end <= VirtPos)
    104            useBuf = true;
    105          else
    106            size = (UInt32)(end - VirtPos);
    107        }
    108      }
    109      if (!useBuf)
    110        break;
    111      if (alignedPos != PhyPos)
    112      {
    113        UInt64 realNewPosition;
    114        bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition);
    115        if (!result)
    116          return ConvertBoolToHRESULT(result);
    117        PhyPos = realNewPosition;
    118      }
    119 
    120      BufStartPos = alignedPos;
    121      UInt32 readSize = kClusterSize;
    122      if (File.SizeDefined)
    123        readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize);
    124 
    125      if (!Buf)
    126      {
    127        Buf = (Byte *)MidAlloc(kClusterSize);
    128        if (!Buf)
    129          return E_OUTOFMEMORY;
    130      }
    131      bool result = File.Read1(Buf, readSize, BufSize);
    132      if (!result)
    133        return ConvertBoolToHRESULT(result);
    134 
    135      if (BufSize == 0)
    136        return S_OK;
    137      PhyPos += BufSize;
    138    }
    139 
    140    if (VirtPos != PhyPos)
    141    {
    142      UInt64 realNewPosition;
    143      bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition);
    144      if (!result)
    145        return ConvertBoolToHRESULT(result);
    146      PhyPos = VirtPos = realNewPosition;
    147    }
    148  }
    149  #endif
    150 
    151  UInt32 realProcessedSize;
    152  bool result = File.ReadPart(data, size, realProcessedSize);
    153  if (processedSize)
    154    *processedSize = realProcessedSize;
    155 
    156  #ifdef SUPPORT_DEVICE_FILE
    157  VirtPos += realProcessedSize;
    158  PhyPos += realProcessedSize;
    159  #endif
    160 
    161  if (result)
    162    return S_OK;
    163 
    164  {
    165    DWORD error = ::GetLastError();
    166 
    167    if (Callback)
    168      return Callback->InFileStream_On_Error(CallbackRef, error);
    169    if (error == 0)
    170      return E_FAIL;
    171 
    172    return HRESULT_FROM_WIN32(error);
    173  }
    174 
    175  #else
    176  
    177  if (processedSize)
    178    *processedSize = 0;
    179  ssize_t res = File.Read(data, (size_t)size);
    180  if (res == -1)
    181  {
    182    if (Callback)
    183      return Callback->InFileStream_On_Error(CallbackRef, E_FAIL);
    184    return E_FAIL;
    185  }
    186  if (processedSize)
    187    *processedSize = (UInt32)res;
    188  return S_OK;
    189 
    190  #endif
    191 }
    192 
    193 #ifdef UNDER_CE
    194 STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
    195 {
    196  size_t s2 = fread(data, 1, size, stdin);
    197  int error = ferror(stdin);
    198  if (processedSize)
    199    *processedSize = s2;
    200  if (s2 <= size && error == 0)
    201    return S_OK;
    202  return E_FAIL;
    203 }
    204 #else
    205 STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
    206 {
    207  #ifdef _WIN32
    208  
    209  DWORD realProcessedSize;
    210  UInt32 sizeTemp = (1 << 20);
    211  if (sizeTemp > size)
    212    sizeTemp = size;
    213  BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
    214  if (processedSize)
    215    *processedSize = realProcessedSize;
    216  if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
    217    return S_OK;
    218  return ConvertBoolToHRESULT(res != FALSE);
    219  
    220  #else
    221 
    222  if (processedSize)
    223    *processedSize = 0;
    224  ssize_t res;
    225  do
    226  {
    227    res = read(0, data, (size_t)size);
    228  }
    229  while (res < 0 && (errno == EINTR));
    230  if (res == -1)
    231    return E_FAIL;
    232  if (processedSize)
    233    *processedSize = (UInt32)res;
    234  return S_OK;
    235  
    236  #endif
    237 }
    238  
    239 #endif
    240 
    241 STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    242 {
    243  if (seekOrigin >= 3)
    244    return STG_E_INVALIDFUNCTION;
    245 
    246  #ifdef USE_WIN_FILE
    247 
    248  #ifdef SUPPORT_DEVICE_FILE
    249  if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END))
    250  {
    251    switch (seekOrigin)
    252    {
    253      case STREAM_SEEK_SET: break;
    254      case STREAM_SEEK_CUR: offset += VirtPos; break;
    255      case STREAM_SEEK_END: offset += File.Size; break;
    256      default: return STG_E_INVALIDFUNCTION;
    257    }
    258    if (offset < 0)
    259      return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
    260    VirtPos = offset;
    261    if (newPosition)
    262      *newPosition = offset;
    263    return S_OK;
    264  }
    265  #endif
    266  
    267  UInt64 realNewPosition;
    268  bool result = File.Seek(offset, seekOrigin, realNewPosition);
    269  
    270  #ifdef SUPPORT_DEVICE_FILE
    271  PhyPos = VirtPos = realNewPosition;
    272  #endif
    273 
    274  if (newPosition)
    275    *newPosition = realNewPosition;
    276  return ConvertBoolToHRESULT(result);
    277  
    278  #else
    279  
    280  off_t res = File.Seek((off_t)offset, seekOrigin);
    281  if (res == -1)
    282    return E_FAIL;
    283  if (newPosition)
    284    *newPosition = (UInt64)res;
    285  return S_OK;
    286  
    287  #endif
    288 }
    289 
    290 STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
    291 {
    292  return ConvertBoolToHRESULT(File.GetLength(*size));
    293 }
    294 
    295 #ifdef USE_WIN_FILE
    296 
    297 STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
    298 {
    299  BY_HANDLE_FILE_INFORMATION info;
    300  if (File.GetFileInformation(&info))
    301  {
    302    if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
    303    if (cTime) *cTime = info.ftCreationTime;
    304    if (aTime) *aTime = info.ftLastAccessTime;
    305    if (mTime) *mTime = info.ftLastWriteTime;
    306    if (attrib) *attrib = info.dwFileAttributes;
    307    return S_OK;
    308  }
    309  return GetLastError();
    310 }
    311 
    312 STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
    313 {
    314  BY_HANDLE_FILE_INFORMATION info;
    315  if (File.GetFileInformation(&info))
    316  {
    317    props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
    318    props->VolID = info.dwVolumeSerialNumber;
    319    props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
    320    props->FileID_High = 0;
    321    props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1;
    322    props->Attrib = info.dwFileAttributes;
    323    props->CTime = info.ftCreationTime;
    324    props->ATime = info.ftLastAccessTime;
    325    props->MTime = info.ftLastWriteTime;
    326    return S_OK;
    327  }
    328  return GetLastError();
    329 }
    330 
    331 #endif
    332 
    333 //////////////////////////
    334 // COutFileStream
    335 
    336 HRESULT COutFileStream::Close()
    337 {
    338  return ConvertBoolToHRESULT(File.Close());
    339 }
    340 
    341 STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
    342 {
    343  #ifdef USE_WIN_FILE
    344 
    345  UInt32 realProcessedSize;
    346  bool result = File.Write(data, size, realProcessedSize);
    347  ProcessedSize += realProcessedSize;
    348  if (processedSize)
    349    *processedSize = realProcessedSize;
    350  return ConvertBoolToHRESULT(result);
    351  
    352  #else
    353  
    354  if (processedSize)
    355    *processedSize = 0;
    356  ssize_t res = File.Write(data, (size_t)size);
    357  if (res == -1)
    358    return E_FAIL;
    359  if (processedSize)
    360    *processedSize = (UInt32)res;
    361  ProcessedSize += res;
    362  return S_OK;
    363  
    364  #endif
    365 }
    366  
    367 STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
    368 {
    369  if (seekOrigin >= 3)
    370    return STG_E_INVALIDFUNCTION;
    371  
    372  #ifdef USE_WIN_FILE
    373 
    374  UInt64 realNewPosition;
    375  bool result = File.Seek(offset, seekOrigin, realNewPosition);
    376  if (newPosition)
    377    *newPosition = realNewPosition;
    378  return ConvertBoolToHRESULT(result);
    379  
    380  #else
    381  
    382  off_t res = File.Seek((off_t)offset, seekOrigin);
    383  if (res == -1)
    384    return E_FAIL;
    385  if (newPosition)
    386    *newPosition = (UInt64)res;
    387  return S_OK;
    388  
    389  #endif
    390 }
    391 
    392 STDMETHODIMP COutFileStream::SetSize(UInt64 newSize)
    393 {
    394  #ifdef USE_WIN_FILE
    395  
    396  UInt64 currentPos;
    397  if (!File.Seek(0, FILE_CURRENT, currentPos))
    398    return E_FAIL;
    399  bool result = File.SetLength(newSize);
    400  UInt64 currentPos2;
    401  result = result && File.Seek(currentPos, currentPos2);
    402  return result ? S_OK : E_FAIL;
    403  
    404  #else
    405  
    406  return E_FAIL;
    407  
    408  #endif
    409 }
    410 
    411 HRESULT COutFileStream::GetSize(UInt64 *size)
    412 {
    413  return ConvertBoolToHRESULT(File.GetLength(*size));
    414 }
    415 
    416 #ifdef UNDER_CE
    417 
    418 STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
    419 {
    420  size_t s2 = fwrite(data, 1, size, stdout);
    421  if (processedSize)
    422    *processedSize = s2;
    423  return (s2 == size) ? S_OK : E_FAIL;
    424 }
    425 
    426 #else
    427 
    428 STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
    429 {
    430  if (processedSize)
    431    *processedSize = 0;
    432 
    433  #ifdef _WIN32
    434 
    435  UInt32 realProcessedSize;
    436  BOOL res = TRUE;
    437  if (size > 0)
    438  {
    439    // Seems that Windows doesn't like big amounts writing to stdout.
    440    // So we limit portions by 32KB.
    441    UInt32 sizeTemp = (1 << 15);
    442    if (sizeTemp > size)
    443      sizeTemp = size;
    444    res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
    445        data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
    446    _size += realProcessedSize;
    447    size -= realProcessedSize;
    448    data = (const void *)((const Byte *)data + realProcessedSize);
    449    if (processedSize)
    450      *processedSize += realProcessedSize;
    451  }
    452  return ConvertBoolToHRESULT(res != FALSE);
    453 
    454  #else
    455  
    456  ssize_t res;
    457 
    458  do
    459  {
    460    res = write(1, data, (size_t)size);
    461  }
    462  while (res < 0 && (errno == EINTR));
    463  
    464  if (res == -1)
    465    return E_FAIL;
    466 
    467  _size += (size_t)res;
    468  if (processedSize)
    469    *processedSize = (UInt32)res;
    470  return S_OK;
    471  
    472  #endif
    473 }
    474 
    475 #endif