-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create sparse files on Windows and read yEnc begin and end (#89)
* Add reading of yenc start and end * Update output based on feedback * Add method for creating sparse files * Use same platform test as elsewhere * Add test that file is sparse * Only close file on Windows * Init msvcrt module once and simplify calls * Use CallMethod when no arguments are needed * Add some error checking * On Windows still set the file length even if it couldn't be made sparse * Remove length check since it depends on filesystem * Truncate already sets error * Simplify is_sparse check by using os.stat to check if allocated space is less than file size * Only set file length if making sparse succeeds * Seek back to the original position after setting file length * Test file position is unchanged * Set version to 7.0.0 --------- Co-authored-by: Safihre <[email protected]>
- Loading branch information
1 parent
5d1a12c
commit c0f3b40
Showing
11 changed files
with
242 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Copyright 2007-2023 The SABnzbd-Team <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
|
||
#include "sparse.h" | ||
|
||
PyObject *Py_msvcrt_module = NULL; | ||
PyObject *get_osfhandle_string = NULL; | ||
|
||
void sparse_init() | ||
{ | ||
#if defined(_WIN32) || defined(__CYGWIN__) | ||
Py_msvcrt_module = PyImport_ImportModule("msvcrt"); | ||
get_osfhandle_string = PyUnicode_FromString("get_osfhandle"); | ||
#endif | ||
} | ||
|
||
PyObject *sparse(PyObject *self, PyObject *args) | ||
{ | ||
PyObject *Py_file; | ||
long long length; | ||
|
||
PyObject *Py_file_fileno = NULL; | ||
PyObject *Py_file_handle = NULL; | ||
PyObject *Py_file_truncate = NULL; | ||
|
||
if (!PyArg_ParseTuple(args, "OL:sparse", &Py_file, &length)) | ||
{ | ||
return NULL; | ||
} | ||
|
||
#if defined(_WIN32) || defined(__CYGWIN__) | ||
// Get the windows file handle and set file attributes to sparse | ||
|
||
if (Py_msvcrt_module == NULL) | ||
{ | ||
PyErr_SetString(PyExc_SystemError, "msvcrt module not loaded."); | ||
goto error; | ||
} | ||
|
||
if (!(Py_file_fileno = PyObject_CallMethod(Py_file, "fileno", NULL))) | ||
{ | ||
PyErr_SetString(PyExc_SystemError, "Error calling fileno function."); | ||
goto error; | ||
} | ||
|
||
if (!(Py_file_handle = PyObject_CallMethodObjArgs(Py_msvcrt_module, get_osfhandle_string, Py_file_fileno, NULL))) | ||
{ | ||
PyErr_SetString(PyExc_SystemError, "Failed calling get_osfhandle function."); | ||
goto error; | ||
} | ||
|
||
HANDLE handle = reinterpret_cast<HANDLE>(PyLong_AsLongLong(Py_file_handle)); | ||
|
||
// Creating a sparse file may fail but that's OK | ||
DWORD bytesReturned; | ||
if (DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &bytesReturned, nullptr)) | ||
{ | ||
// Increase the file length without writing any data and seek back to the original position | ||
LARGE_INTEGER li_size; | ||
li_size.QuadPart = length; | ||
LARGE_INTEGER li_start = {0}; | ||
if (!SetFilePointerEx(handle, {0}, &li_start, FILE_CURRENT) || !SetFilePointerEx(handle, li_size, nullptr, FILE_END) || !SetEndOfFile(handle) || !SetFilePointerEx(handle, li_start, nullptr, FILE_BEGIN)) | ||
{ | ||
PyErr_SetFromWindowsErr(0); | ||
goto error; | ||
} | ||
} | ||
#else | ||
// Call file.truncate(length) | ||
|
||
if (!(Py_file_truncate = PyObject_CallMethod(Py_file, "truncate", "(L)", length))) | ||
{ | ||
goto error; | ||
} | ||
#endif | ||
|
||
done: | ||
Py_XDECREF(Py_file_fileno); | ||
Py_XDECREF(Py_file_handle); | ||
Py_XDECREF(Py_file_truncate); | ||
Py_RETURN_NONE; | ||
|
||
error: | ||
Py_XDECREF(Py_file_fileno); | ||
Py_XDECREF(Py_file_handle); | ||
Py_XDECREF(Py_file_truncate); | ||
return NULL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright 2007-2023 The SABnzbd-Team <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
|
||
#ifndef SABCTOOLS_SPARSE_H | ||
#define SABCTOOLS_SPARSE_H | ||
|
||
#include <Python.h> | ||
|
||
#if defined(_WIN32) || defined(__CYGWIN__) | ||
#include <Windows.h> | ||
#endif | ||
|
||
void sparse_init(); | ||
PyObject *sparse(PyObject *, PyObject *); | ||
|
||
#endif //SABCTOOLS_SPARSE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import os | ||
import subprocess | ||
import sys | ||
import tempfile | ||
import pytest | ||
from typing import IO | ||
|
||
from tests.testsupport import * | ||
|
||
|
||
def test_sparse(): | ||
file = tempfile.NamedTemporaryFile(delete=False) | ||
try: | ||
sabctools.sparse(file, 100) | ||
assert os.path.getsize(file.name) == 100 | ||
assert is_sparse(file) is True | ||
finally: | ||
file.close() | ||
os.unlink(file.name) | ||
|
||
@pytest.mark.parametrize( | ||
"length,position", | ||
[ | ||
(1024, 0), | ||
(1024, 512), | ||
(1024, 4096), | ||
], | ||
) | ||
def test_sparse_position_expected(length, position): | ||
with tempfile.TemporaryFile() as file: | ||
file.seek(position) | ||
sabctools.sparse(file, length) | ||
assert file.tell() == position | ||
|
||
def is_sparse(file: IO) -> bool: | ||
"""Is the file sparse? | ||
On Windows this closes the file""" | ||
if sys.platform == "win32": | ||
file.close() | ||
return b"This file is set as sparse" in subprocess.run( | ||
["fsutil", "sparse", "queryflag", file.name], | ||
capture_output=True | ||
).stdout | ||
|
||
return os.stat(file.name).st_blocks * 512 < os.path.getsize(file.name) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.