bpo-41142: Add support of non-ASCII paths for CAB files. (GH-21195)

* The path to the CAB file can be non-ASCII.
* Paths of added files can be non-ASCII.
This commit is contained in:
Serhiy Storchaka 2020-06-30 11:56:03 +03:00 committed by GitHub
parent 694d31e714
commit ba67d7386e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 12 deletions

View File

@ -112,6 +112,16 @@ class MsiDatabaseTestCase(unittest.TestCase):
with self.assertRaises(msilib.MSIError): with self.assertRaises(msilib.MSIError):
si.GetProperty(-1) si.GetProperty(-1)
def test_FCICreate(self):
filepath = TESTFN + '.txt'
cabpath = TESTFN + '.cab'
self.addCleanup(unlink, filepath)
with open(filepath, 'wb'):
pass
self.addCleanup(unlink, cabpath)
msilib.FCICreate(cabpath, [(filepath, 'test.txt')])
self.assertTrue(os.path.isfile(cabpath))
class Test_make_id(unittest.TestCase): class Test_make_id(unittest.TestCase):
#http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx #http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx

View File

@ -0,0 +1,2 @@
:mod:`msilib` now supports creating CAB files with non-ASCII file path and
adding files with non-ASCII file path to them.

View File

@ -41,21 +41,50 @@ uuidcreate(PyObject* obj, PyObject*args)
} }
/* Helper for converting file names from UTF-8 to wchat_t*. */
static wchar_t *
utf8_to_wchar(const char *s, int *err)
{
PyObject *obj = PyUnicode_FromString(s);
if (obj == NULL) {
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
*err = ENOMEM;
}
else {
*err = EINVAL;
}
PyErr_Clear();
return NULL;
}
wchar_t *ws = PyUnicode_AsWideCharString(obj, NULL);
if (ws == NULL) {
*err = ENOMEM;
PyErr_Clear();
}
Py_DECREF(obj);
return ws;
}
/* FCI callback functions */ /* FCI callback functions */
static FNFCIALLOC(cb_alloc) static FNFCIALLOC(cb_alloc)
{ {
return malloc(cb); return PyMem_RawMalloc(cb);
} }
static FNFCIFREE(cb_free) static FNFCIFREE(cb_free)
{ {
free(memory); PyMem_RawFree(memory);
} }
static FNFCIOPEN(cb_open) static FNFCIOPEN(cb_open)
{ {
int result = _open(pszFile, oflag | O_NOINHERIT, pmode); wchar_t *ws = utf8_to_wchar(pszFile, err);
if (ws == NULL) {
return -1;
}
int result = _wopen(ws, oflag | O_NOINHERIT, pmode);
PyMem_Free(ws);
if (result == -1) if (result == -1)
*err = errno; *err = errno;
return result; return result;
@ -95,7 +124,12 @@ static FNFCISEEK(cb_seek)
static FNFCIDELETE(cb_delete) static FNFCIDELETE(cb_delete)
{ {
int result = remove(pszFile); wchar_t *ws = utf8_to_wchar(pszFile, err);
if (ws == NULL) {
return -1;
}
int result = _wremove(ws);
PyMem_Free(ws);
if (result != 0) if (result != 0)
*err = errno; *err = errno;
return result; return result;
@ -159,15 +193,22 @@ static FNFCIGETOPENINFO(cb_getopeninfo)
FILETIME filetime; FILETIME filetime;
HANDLE handle; HANDLE handle;
/* Need Win32 handle to get time stamps */ wchar_t *ws = utf8_to_wchar(pszName, err);
handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL, if (ws == NULL) {
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
return -1; return -1;
}
if (GetFileInformationByHandle(handle, &bhfi) == FALSE) /* Need Win32 handle to get time stamps */
{ handle = CreateFileW(ws, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
PyMem_Free(ws);
return -1;
}
if (GetFileInformationByHandle(handle, &bhfi) == FALSE) {
CloseHandle(handle); CloseHandle(handle);
PyMem_Free(ws);
return -1; return -1;
} }
@ -179,7 +220,9 @@ static FNFCIGETOPENINFO(cb_getopeninfo)
CloseHandle(handle); CloseHandle(handle);
return _open(pszName, _O_RDONLY | _O_BINARY | O_NOINHERIT); int result = _wopen(ws, _O_RDONLY | _O_BINARY | O_NOINHERIT);
PyMem_Free(ws);
return result;
} }
static PyObject* fcicreate(PyObject* obj, PyObject* args) static PyObject* fcicreate(PyObject* obj, PyObject* args)
@ -212,7 +255,7 @@ static PyObject* fcicreate(PyObject* obj, PyObject* args)
ccab.setID = 0; ccab.setID = 0;
ccab.szDisk[0] = '\0'; ccab.szDisk[0] = '\0';
for (i = 0, p = cabname; *p; p = CharNext(p)) for (i = 0, p = cabname; *p; p++)
if (*p == '\\' || *p == '/') if (*p == '\\' || *p == '/')
i = p - cabname + 1; i = p - cabname + 1;