示例#1
0
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);
}
示例#2
0
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;
}