BOOL My_ReadFileScatter() { HANDLE hFile=NULL; FILE_SEGMENT_ELEMENT aSegmentArray[50]; DWORD nNumberOfBytesToRead=NULL; LPDWORD lpReserved=NULL; LPOVERLAPPED lpOverlapped=NULL; BOOL returnVal_Real = NULL; BOOL returnVal_Intercepted = NULL; DWORD error_Real = 0; DWORD error_Intercepted = 0; disableInterception(); returnVal_Real = ReadFileScatter (hFile,aSegmentArray,nNumberOfBytesToRead,lpReserved,lpOverlapped); error_Real = GetLastError(); enableInterception(); returnVal_Intercepted = ReadFileScatter (hFile,aSegmentArray,nNumberOfBytesToRead,lpReserved,lpOverlapped); error_Intercepted = GetLastError(); return ((returnVal_Real == returnVal_Intercepted) && (error_Real == error_Intercepted)); }
size_type file::readv(size_type file_offset, iovec_t const* bufs, int num_bufs, error_code& ec) { TORRENT_ASSERT((m_open_mode & rw_mask) == read_only || (m_open_mode & rw_mask) == read_write); TORRENT_ASSERT(bufs); TORRENT_ASSERT(num_bufs > 0); TORRENT_ASSERT(is_open()); #if defined TORRENT_WINDOWS || defined TORRENT_LINUX || defined TORRENT_DEBUG // make sure m_page_size is initialized init_file(); #endif #ifdef TORRENT_DEBUG if (m_open_mode & no_buffer) { bool eof = false; int size = 0; // when opened in no_buffer mode, the file_offset must // be aligned to pos_alignment() TORRENT_ASSERT((file_offset & (pos_alignment()-1)) == 0); for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i) { TORRENT_ASSERT((uintptr_t(i->iov_base) & (buf_alignment()-1)) == 0); // every buffer must be a multiple of the page size // except for the last one TORRENT_ASSERT((i->iov_len & (size_alignment()-1)) == 0 || i == end-1); if ((i->iov_len & (size_alignment()-1)) != 0) eof = true; size += i->iov_len; } error_code code; if (eof) TORRENT_ASSERT(file_offset + size >= get_size(code)); } #endif #ifdef TORRENT_WINDOWS DWORD ret = 0; // since the ReadFileScatter requires the file to be opened // with no buffering, and no buffering requires page aligned // buffers, open the file in non-buffered mode in case the // buffer is not aligned. Most of the times the buffer should // be aligned though if ((m_open_mode & no_buffer) == 0) { // this means the buffer base or the buffer size is not aligned // to the page size. Use a regular file for this operation. LARGE_INTEGER offs; offs.QuadPart = file_offset; if (SetFilePointerEx(m_file_handle, offs, &offs, FILE_BEGIN) == FALSE) { ec = error_code(GetLastError(), get_system_category()); return -1; } for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i) { DWORD intermediate = 0; if (ReadFile(m_file_handle, (char*)i->iov_base , (DWORD)i->iov_len, &intermediate, 0) == FALSE) { ec = error_code(GetLastError(), get_system_category()); return -1; } ret += intermediate; } return ret; } int size = bufs_size(bufs, num_bufs); // number of pages for the read. round up int num_pages = (size + m_page_size - 1) / m_page_size; // allocate array of FILE_SEGMENT_ELEMENT for ReadFileScatter FILE_SEGMENT_ELEMENT* segment_array = TORRENT_ALLOCA(FILE_SEGMENT_ELEMENT, num_pages + 1); FILE_SEGMENT_ELEMENT* cur_seg = segment_array; for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i) { for (int k = 0; k < i->iov_len; k += m_page_size) { cur_seg->Buffer = PtrToPtr64((((char*)i->iov_base) + k)); ++cur_seg; } } // terminate the array cur_seg->Buffer = 0; OVERLAPPED ol; ol.Internal = 0; ol.InternalHigh = 0; ol.OffsetHigh = file_offset >> 32; ol.Offset = file_offset & 0xffffffff; ol.hEvent = CreateEvent(0, true, false, 0); ret += size; size = num_pages * m_page_size; if (ReadFileScatter(m_file_handle, segment_array, size, 0, &ol) == 0) { DWORD last_error = GetLastError(); if (last_error != ERROR_IO_PENDING) { TORRENT_ASSERT(GetLastError() != ERROR_BAD_ARGUMENTS); ec = error_code(GetLastError(), get_system_category()); CloseHandle(ol.hEvent); return -1; } if (GetOverlappedResult(m_file_handle, &ol, &ret, true) == 0) { ec = error_code(GetLastError(), get_system_category()); CloseHandle(ol.hEvent); return -1; } } CloseHandle(ol.hEvent); return ret; #else // TORRENT_WINDOWS size_type ret = lseek(m_fd, file_offset, SEEK_SET); if (ret < 0) { ec = error_code(errno, get_posix_category()); return -1; } #if TORRENT_USE_READV #ifdef TORRENT_LINUX bool aligned = false; int size = 0; // if we're not opened in no-buffer mode, we don't need alignment if ((m_open_mode & no_buffer) == 0) aligned = true; if (!aligned) { size = bufs_size(bufs, num_bufs); if ((size & (size_alignment()-1)) == 0) aligned = true; } if (aligned) #endif // TORRENT_LINUX { ret = ::readv(m_fd, bufs, num_bufs); if (ret < 0) { ec = error_code(errno, get_posix_category()); return -1; } return ret; } #ifdef TORRENT_LINUX file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs); memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * num_bufs); iovec_t& last = temp_bufs[num_bufs-1]; last.iov_len = (last.iov_len & ~(size_alignment()-1)) + m_page_size; ret = ::readv(m_fd, temp_bufs, num_bufs); if (ret < 0) { ec = error_code(errno, get_posix_category()); return -1; } return (std::min)(ret, size_type(size)); #endif // TORRENT_LINUX #else // TORRENT_USE_READV ret = 0; for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i) { int tmp = read(m_fd, i->iov_base, i->iov_len); if (tmp < 0) { ec = error_code(errno, get_posix_category()); return -1; } ret += tmp; if (tmp < i->iov_len) break; } return ret; #endif // TORRENT_USE_READV #endif // TORRENT_WINDOWS }