--- Modules/posixmodule.c.orig 2008-08-22 15:10:49.000000000 +0200
+++ Modules/posixmodule.c 2008-08-22 16:00:42.000000000 +0200
@@ -331,6 +331,40 @@
#endif
#endif
+PyObject* getInvalideFilenameType(void)
+{
+ PyObject *module;
+
+ /* FIXME: delete ref at exit */
+ static PyObject* InvalidFilenameType = NULL;
+
+ module = PyImport_ImportModule("filename");
+ if (module == NULL)
+ return NULL;
+ InvalidFilenameType = PyObject_GetAttrString(module, "InvalidFilename");
+ Py_DECREF(module);
+ return InvalidFilenameType;
+}
+
+char* posix_get_filename(PyObject *args)
+{
+ PyObject *filenameobj, *pathobj, *type;
+
+ if (!PyArg_ParseTuple(args, "O", &filenameobj))
+ return NULL;
+
+ type = getInvalideFilenameType();
+ if (!type)
+ return NULL;
+
+ if (!PyObject_IsInstance(filenameobj, type))
+ return NULL;
+ pathobj = PyObject_GetAttrString(filenameobj, "bytes");
+ if (!pathobj)
+ return NULL;
+ return PyBytes_AsString(pathobj);
+}
+
/* Return a dictionary corresponding to the POSIX environment table */
#ifdef WITH_NEXT_FRAMEWORK
/* On Darwin/MacOSX a shared library or framework has no access to
@@ -637,16 +671,23 @@
posix_1str(PyObject *args, char *format, int (*func)(const char*))
{
char *path1 = NULL;
+ int freepath = 1;
int res;
if (!PyArg_ParseTuple(args, format,
Py_FileSystemDefaultEncoding, &path1))
- return NULL;
+ {
+ path1 = posix_get_filename(args);
+ if (!path1)
+ return NULL;
+ freepath = 0;
+ }
Py_BEGIN_ALLOW_THREADS
res = (*func)(path1);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(path1);
- PyMem_Free(path1);
+ if (freepath)
+ PyMem_Free(path1);
Py_INCREF(Py_None);
return Py_None;
}
@@ -1494,8 +1535,14 @@
if (!PyArg_ParseTuple(args, format,
Py_FileSystemDefaultEncoding, &path))
- return NULL;
- pathfree = path;
+ {
+ path = posix_get_filename(args);
+ if (!path)
+ return NULL;
+ pathfree = NULL;
+ } else {
+ pathfree = path;
+ }
Py_BEGIN_ALLOW_THREADS
res = (*statfunc)(path, &st);
@@ -1511,7 +1558,8 @@
else
result = _pystat_fromstructstat(&st);
- PyMem_Free(pathfree);
+ if (pathfree)
+ PyMem_Free(pathfree);
return result;
}
@@ -2087,7 +2135,7 @@
entries '.' and '..' even if they are present in the directory.");
static PyObject *
-posix_listdir(PyObject *self, PyObject *args)
+posix_listdir(PyObject *self, PyObject *args, PyObject *kwargs)
{
/* XXX Should redo this putting the (now four) versions of opendir
in separate files instead of having them all here... */
@@ -2327,9 +2375,12 @@
DIR *dirp;
struct dirent *ep;
int arg_is_unicode = 1;
+ int accept_invalid_filename = 0;
+ static char* kwnames[] = { "path", "invalid_filename", NULL };
errno = 0;
- if (!PyArg_ParseTuple(args, "U:listdir", &v)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "U|i:listdir", kwnames,
+ &v, &accept_invalid_filename)) {
arg_is_unicode = 0;
PyErr_Clear();
}
@@ -2362,11 +2413,8 @@
(ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
continue;
v = PyBytes_FromStringAndSize(ep->d_name, NAMLEN(ep));
- if (v == NULL) {
- Py_DECREF(d);
- d = NULL;
- break;
- }
+ if (v == NULL)
+ goto error;
if (arg_is_unicode) {
PyObject *w;
@@ -2378,22 +2426,35 @@
v = w;
}
else {
- /* fall back to the original byte string, as
- discussed in patch #683592 */
- PyErr_Clear();
+ PyObject *type;
+ if (!accept_invalid_filename) {
+ Py_DECREF(v);
+ goto error;
+ }
+ type = getInvalideFilenameType();
+
+ w = PyObject_CallFunction(type, "(Os)", v, Py_FileSystemDefaultEncoding);
+ if (!w)
+ return NULL;
+ Py_DECREF(v);
+ v = w;
}
}
if (PyList_Append(d, v) != 0) {
Py_DECREF(v);
- Py_DECREF(d);
- d = NULL;
- break;
+ goto error;
}
Py_DECREF(v);
}
- closedir(dirp);
PyMem_Free(name);
+ goto exit;
+error:
+ closedir(dirp);
+ Py_DECREF(d);
+ d = NULL;
+
+exit:
return d;
#endif /* which OS */
@@ -2990,7 +3051,7 @@
return PyErr_NoMemory();
}
for (i = 0; i < argc; i++) {
- if (!PyArg_Parse((*getitem)(argv, i), format,
+ if (!PyArg_Parse((*getitem)(argv, i), "et",
Py_FileSystemDefaultEncoding,
&argvlist[i])) {
free_string_array(argvlist, i);
@@ -6816,7 +6877,7 @@
#ifdef HAVE_LINK
{"link", posix_link, METH_VARARGS, posix_link__doc__},
#endif /* HAVE_LINK */
- {"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__},
+ {"listdir", (PyCFunction)posix_listdir, METH_VARARGS|METH_KEYWORDS, posix_listdir__doc__},
{"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__},
{"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__},
#ifdef HAVE_NICE
Index: Lib/os.py
===================================================================
--- Lib/os.py (révision 65973)
+++ Lib/os.py (copie de travail)
@@ -23,6 +23,7 @@
#'
import sys, errno
+from filename import InvalidFilename
_names = sys.builtin_module_names
@@ -657,3 +658,17 @@
raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
import io
return io.open(fd, *args, **kwargs)
+
+def fixed_join(a, *p):
+ """Join two or more pathname components, inserting '/' as needed.
+ If any component is an absolute path, all previous path components
+ will be discarded."""
+ args = (a,) + p
+ for arg in args:
+ if not isinstance(arg, InvalidFilename):
+ continue
+ return InvalidFilename.join(args, arg.charset)
+ return fixed_join.default(a, *p)
+fixed_join.default = path.join
+path.join = fixed_join
+
Index: Lib/shutil.py
===================================================================
--- Lib/shutil.py (révision 65973)
+++ Lib/shutil.py (copie de travail)
@@ -176,7 +176,7 @@
if errors:
raise Error(errors)
-def rmtree(path, ignore_errors=False, onerror=None):
+def rmtree(path, ignore_errors=False, onerror=None, invalid_filename=True):
"""Recursively delete a directory tree.
If ignore_errors is set, errors are ignored; otherwise, if onerror
@@ -203,7 +203,7 @@
return
names = []
try:
- names = os.listdir(path)
+ names = os.listdir(path, invalid_filename=invalid_filename)
except os.error as err:
onerror(os.listdir, path, sys.exc_info())
for name in names:
--- /dev/null 2008-03-02 21:54:29.000000000 +0100
+++ Lib/filename.py 2008-08-22 16:16:55.000000000 +0200
@@ -0,0 +1,28 @@
+class InvalidFilename:
+ def __init__(self, filename, charset):
+ self.bytes = filename
+ self.charset = charset
+ self.str = str(filename, charset, "replace")
+
+ @staticmethod
+ def join(parts, charset):
+ path = b''
+ for part in parts:
+ if isinstance(part, InvalidFilename):
+ part = part.bytes
+ else:
+ part = part.encode(charset)
+ if part.startswith(b'/'):
+ path = part
+ elif path == b'' or path.endswith(b'/'):
+ path += part
+ else:
+ path += b'/' + part
+ return InvalidFilename(path, charset)
+
+ def __str__(self):
+ return self.str
+
+ def __repr__(self):
+ return '