diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2020-06-30 08:56:03 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-30 08:56:03 (GMT) |
commit | ba67d7386edf20bcc0f878a518de0894cb574e9f (patch) | |
tree | bb04f9574dd940abea4025d9eacc9ed170fac1e4 | |
parent | 694d31e714074176f0c324f95948b75dc768c091 (diff) | |
download | cpython-ba67d7386edf20bcc0f878a518de0894cb574e9f.zip cpython-ba67d7386edf20bcc0f878a518de0894cb574e9f.tar.gz cpython-ba67d7386edf20bcc0f878a518de0894cb574e9f.tar.bz2 |
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.
-rw-r--r-- | Lib/test/test_msilib.py | 10 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Windows/2020-06-28-12-40-41.bpo-41142.jpZzzh.rst | 2 | ||||
-rw-r--r-- | PC/_msi.c | 63 |
3 files changed, 65 insertions, 10 deletions
diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index 4a233c3..743bea7 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -112,6 +112,16 @@ class MsiDatabaseTestCase(unittest.TestCase): with self.assertRaises(msilib.MSIError): 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): #http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx diff --git a/Misc/NEWS.d/next/Windows/2020-06-28-12-40-41.bpo-41142.jpZzzh.rst b/Misc/NEWS.d/next/Windows/2020-06-28-12-40-41.bpo-41142.jpZzzh.rst new file mode 100644 index 0000000..91406da --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2020-06-28-12-40-41.bpo-41142.jpZzzh.rst @@ -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. @@ -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 */ static FNFCIALLOC(cb_alloc) { - return malloc(cb); + return PyMem_RawMalloc(cb); } static FNFCIFREE(cb_free) { - free(memory); + PyMem_RawFree(memory); } 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) *err = errno; return result; @@ -95,7 +124,12 @@ static FNFCISEEK(cb_seek) 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) *err = errno; return result; @@ -159,15 +193,22 @@ static FNFCIGETOPENINFO(cb_getopeninfo) FILETIME filetime; HANDLE handle; + wchar_t *ws = utf8_to_wchar(pszName, err); + if (ws == NULL) { + return -1; + } + /* Need Win32 handle to get time stamps */ - handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL, + handle = CreateFileW(ws, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (handle == INVALID_HANDLE_VALUE) + if (handle == INVALID_HANDLE_VALUE) { + PyMem_Free(ws); return -1; + } - if (GetFileInformationByHandle(handle, &bhfi) == FALSE) - { + if (GetFileInformationByHandle(handle, &bhfi) == FALSE) { CloseHandle(handle); + PyMem_Free(ws); return -1; } @@ -179,7 +220,9 @@ static FNFCIGETOPENINFO(cb_getopeninfo) 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) @@ -212,7 +255,7 @@ static PyObject* fcicreate(PyObject* obj, PyObject* args) ccab.setID = 0; ccab.szDisk[0] = '\0'; - for (i = 0, p = cabname; *p; p = CharNext(p)) + for (i = 0, p = cabname; *p; p++) if (*p == '\\' || *p == '/') i = p - cabname + 1; |