void PlotsFile::preallocate(const std::string& p_path, unsigned long long p_size) throw (std::exception) { bool granted = setPrivilege(); HANDLE out = CreateFileA(p_path.c_str(), GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, 0); if(out == INVALID_HANDLE_VALUE) { std::ostringstream msg; msg << "Unable to open the output file: " << GetLastError(); throw std::runtime_error(msg.str().c_str()); } LARGE_INTEGER targetPointer; targetPointer.QuadPart = p_size; SetFilePointerEx(out, targetPointer, 0, FILE_BEGIN); if(SetEndOfFile(out) == 0) { CloseHandle(out); std::ostringstream msg; msg << "Unable to extend output file: " << GetLastError(); throw std::runtime_error(msg.str().c_str()); } if(granted) { if(SetFileValidData(out, p_size) == 0) { CloseHandle(out); std::ostringstream msg; msg << "Unable to prevent zero filling: " << GetLastError(); throw std::runtime_error(msg.str().c_str()); } } CloseHandle(out); }
static BOOL resize_file(HANDLE file, size_t new_size) { DWORD end_size, start_size = GetFileSize(file, NULL); DWORD dwp = SetFilePointer(file, (LONG) new_size, NULL, FILE_BEGIN); DWORD err = GetLastError(); if (dwp != INVALID_SET_FILE_POINTER) { err = SetEndOfFile(file); if (err == 0) { err = GetLastError(); } err = SetFileValidData(file, new_size); } end_size = GetFileSize(file, NULL); return (start_size != INVALID_FILE_SIZE && end_size != INVALID_FILE_SIZE); }
bool file::set_size(size_type s, error_code& ec) { TORRENT_ASSERT(is_open()); TORRENT_ASSERT(s >= 0); #ifdef TORRENT_WINDOWS LARGE_INTEGER offs; LARGE_INTEGER cur_size; if (GetFileSizeEx(m_file_handle, &cur_size) == FALSE) { ec = error_code(GetLastError(), get_system_category()); return false; } offs.QuadPart = s; // only set the file size if it's not already at // the right size. We don't want to update the // modification time if we don't have to if (cur_size.QuadPart != s) { if (SetFilePointerEx(m_file_handle, offs, &offs, FILE_BEGIN) == FALSE) { ec.assign(GetLastError(), get_system_category()); return false; } if (::SetEndOfFile(m_file_handle) == FALSE) { ec.assign(GetLastError(), get_system_category()); return false; } } #if _WIN32_WINNT >= 0x501 if ((m_open_mode & sparse) == 0) { // only allocate the space if the file // is not fully allocated DWORD high_dword = 0; offs.LowPart = GetCompressedFileSize(m_path.c_str(), &high_dword); offs.HighPart = high_dword; ec.assign(GetLastError(), get_system_category()); if (ec) return false; if (offs.QuadPart != s) { // if the user has permissions, avoid filling // the file with zeroes, but just fill it with // garbage instead SetFileValidData(m_file_handle, offs.QuadPart); } } #endif // _WIN32_WINNT >= 0x501 #else // NON-WINDOWS struct stat st; if (fstat(m_fd, &st) != 0) { ec.assign(errno, get_posix_category()); return false; } // only truncate the file if it doesn't already // have the right size. We don't want to update if (st.st_size != s && ftruncate(m_fd, s) < 0) { ec.assign(errno, get_posix_category()); return false; } // if we're not in sparse mode, allocate the storage // but only if the number of allocated blocks for the file // is less than the file size. Otherwise we would just // update the modification time of the file for no good // reason. if ((m_open_mode & sparse) == 0 && st.st_blocks < (s + st.st_blksize - 1) / st.st_blksize) { // How do we know that the file is already allocated? // if we always try to allocate the space, we'll update // the modification time without actually changing the file // but if we don't do anything if the file size is #ifdef F_PREALLOCATE fstore_t f = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, s, 0}; if (fcntl(m_fd, F_PREALLOCATE, &f) < 0) { ec = error_code(errno, get_posix_category()); return false; } #endif // F_PREALLOCATE #if defined TORRENT_LINUX || TORRENT_HAS_FALLOCATE int ret; #endif #if defined TORRENT_LINUX ret = my_fallocate(m_fd, 0, 0, s); // if we return 0, everything went fine // the fallocate call succeeded if (ret == 0) return true; // otherwise, something went wrong. If the error // is ENOSYS, just keep going and do it the old-fashioned // way. If fallocate failed with some other error, it // probably means the user should know about it, error out // and report it. if (errno != ENOSYS && errno != EOPNOTSUPP) { ec.assign(errno, get_posix_category()); return false; } #endif // TORRENT_LINUX #if TORRENT_HAS_FALLOCATE // if fallocate failed, we have to use posix_fallocate // which can be painfully slow // if you get a compile error here, you might want to // define TORRENT_HAS_FALLOCATE to 0. ret = posix_fallocate(m_fd, 0, s); // posix_allocate fails with EINVAL in case the underlying // filesystem does bot support this operation if (ret != 0 && ret != EINVAL) { ec = error_code(ret, get_posix_category()); return false; } #endif // TORRENT_HAS_FALLOCATE } #endif // TORRENT_WINDOWS return true; }