summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2020-06-30 08:56:03 (GMT)
committerGitHub <noreply@github.com>2020-06-30 08:56:03 (GMT)
commitba67d7386edf20bcc0f878a518de0894cb574e9f (patch)
treebb04f9574dd940abea4025d9eacc9ed170fac1e4
parent694d31e714074176f0c324f95948b75dc768c091 (diff)
downloadcpython-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.py10
-rw-r--r--Misc/NEWS.d/next/Windows/2020-06-28-12-40-41.bpo-41142.jpZzzh.rst2
-rw-r--r--PC/_msi.c63
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.
diff --git a/PC/_msi.c b/PC/_msi.c
index 58c1cfd..60a0c3a 100644
--- a/PC/_msi.c
+++ b/PC/_msi.c
@@ -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;