Index: Modules/posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.251 diff -u -r2.251 posixmodule.c --- Modules/posixmodule.c 2 Aug 2002 02:27:13 -0000 2.251 +++ Modules/posixmodule.c 12 Aug 2002 11:29:57 -0000 @@ -481,11 +481,44 @@ return Py_None; } +static int +unicode_file_names(void) +{ +#if defined(MS_WINDOWS) && !defined(Py_UNICODE_WIDE) + static int canusewide = -1; + if (canusewide == -1) { + canusewide = (GetVersion() < 0x80000000) ? 1 : 0; + } + return canusewide; +#else + return 0; +#endif +} + static PyObject * -posix_1str(PyObject *args, char *format, int (*func)(const char*)) +posix_1str(PyObject *args, char *format, int (*func)(const char*), + char *wformat, int (*wfunc)(const Py_UNICODE*)) { char *path1 = NULL; int res; + if (unicode_file_names() && wfunc) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, wformat, &po)) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread + lock as it is a simple dereference. */ + res = (*wfunc)(PyUnicode_AS_UNICODE(po)); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; + } + /* Drop the argument parsing error as narrow + strings are also valid. */ + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, format, Py_FileSystemDefaultEncoding, &path1)) return NULL; @@ -500,11 +533,40 @@ } static PyObject * -posix_2str(PyObject *args, char *format, - int (*func)(const char *, const char *)) +posix_2str(PyObject *args, + char *format, + int (*func)(const char *, const char *), + char *wformat, + int (*wfunc)(const Py_UNICODE *, const Py_UNICODE *)) { char *path1 = NULL, *path2 = NULL; int res; + if (unicode_file_names() && wfunc) { + PyObject *po1; + PyObject *po2; + if (PyArg_ParseTuple(args, wformat, &po1, &po2)) { + if (PyUnicode_Check(po1) || PyUnicode_Check(po2)) { + PyObject *wpath1; + PyObject *wpath2; + wpath1 = PyUnicode_FromObject(po1); + wpath2 = PyUnicode_FromObject(po2); + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread + lock as it is a simple dereference. */ + res = (*wfunc)(PyUnicode_AS_UNICODE(wpath1), + PyUnicode_AS_UNICODE(wpath2)); + Py_END_ALLOW_THREADS + Py_XDECREF(wpath1); + Py_XDECREF(wpath2); + if (res != 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; + } + /* Else flow through as neither is Unicode. */ + } + } + if (!PyArg_ParseTuple(args, format, Py_FileSystemDefaultEncoding, &path1, Py_FileSystemDefaultEncoding, &path2)) @@ -678,8 +740,11 @@ } static PyObject * -posix_do_stat(PyObject *self, PyObject *args, char *format, - int (*statfunc)(const char *, STRUCT_STAT *)) +posix_do_stat(PyObject *self, PyObject *args, + char *format, + int (*statfunc)(const char *, STRUCT_STAT *), + char *wformat, + int (*wstatfunc)(const Py_UNICODE *, STRUCT_STAT *)) { STRUCT_STAT st; char *path = NULL; /* pass this to stat; do not free() it */ @@ -691,6 +756,51 @@ char pathcopy[MAX_PATH]; #endif /* MS_WINDOWS */ + /* If on wide-character-capable OS see if argument + is Unicode and if so use wide API. */ + if (unicode_file_names() && wstatfunc) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, wformat, &po)) { +#ifdef MS_WINDOWS + Py_UNICODE wpath[MAX_PATH+1]; + pathlen = wcslen(PyUnicode_AS_UNICODE(po)); + /* the library call can blow up if the file name is too long! */ + if (pathlen > MAX_PATH) { + errno = ENAMETOOLONG; + return posix_error(); + } + wcscpy(wpath, PyUnicode_AS_UNICODE(po)); + /* Remove trailing slash or backslash, unless it's the current + drive root (/ or \) or a specific drive's root (like c:\ or c:/). + */ + if (pathlen > 0 && + (wpath[pathlen-1]== L'\\' || wpath[pathlen-1] == L'/')) { + /* It does end with a slash -- exempt the root drive cases. */ + /* XXX UNC root drives should also be exempted? */ + if (pathlen == 1 || (pathlen == 3 && wpath[1] == L':')) + /* leave it alone */; + else { + /* nuke the trailing backslash */ + wpath[pathlen-1] = L'\0'; + } + } +#else + Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po); +#endif /* MS_WINDOWS */ + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE result OK without + thread lock as it is a simple dereference. */ + res = wstatfunc(wpath, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); + return _pystat_fromstructstat(st); + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, format, Py_FileSystemDefaultEncoding, &path)) return NULL; @@ -825,10 +935,12 @@ static PyObject * posix_chdir(PyObject *self, PyObject *args) { -#if defined(PYOS_OS2) && defined(PYCC_GCC) - return posix_1str(args, "et:chdir", _chdir2); +#ifdef MS_WINDOWS + return posix_1str(args, "et:chdir", chdir, "U:chdir", _wchdir); +#elif defined(PYOS_OS2) && defined(PYCC_GCC) + return posix_1str(args, "et:chdir", _chdir2, NULL, NULL); #else - return posix_1str(args, "et:chdir", chdir); + return posix_1str(args, "et:chdir", chdir, NULL, NULL); #endif } @@ -878,7 +990,7 @@ static PyObject * posix_chroot(PyObject *self, PyObject *args) { - return posix_1str(args, "et:chroot", chroot); + return posix_1str(args, "et:chroot", chroot, NULL, NULL); } #endif @@ -1001,7 +1113,7 @@ static PyObject * posix_link(PyObject *self, PyObject *args) { - return posix_2str(args, "etet:link", link); + return posix_2str(args, "etet:link", link, NULL, NULL); } #endif /* HAVE_LINK */ @@ -1030,6 +1142,72 @@ char *bufptr = namebuf; int len = sizeof(namebuf)/sizeof(namebuf[0]); + /* If on wide-character-capable OS see if argument + is Unicode and if so use wide API. */ + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "U:listdir", &po)) { + WIN32_FIND_DATAW wFileData; + Py_UNICODE wnamebuf[MAX_PATH*2+5]; + Py_UNICODE wch; + int i; + wcsncpy(wnamebuf, PyUnicode_AS_UNICODE(po), MAX_PATH); + wnamebuf[MAX_PATH] = L'\0'; + /* Ensure something indicative if not always + accurate available for error reporting. */ + for (i=0; wnamebuf[i]; i++) { + if (wnamebuf[i] == L'\0') + namebuf[i] = '\0'; + else if (isascii(wnamebuf[i])) + namebuf[i] = (char)(wnamebuf[i]); + else + namebuf[i] = '?'; + } + len = wcslen(wnamebuf); + wch = (len > 0) ? wnamebuf[len-1] : L'\0'; + if (wch != L'/' && wch != L'\\' && wch != L':') + wnamebuf[len++] = L'/'; + wcscpy(wnamebuf + len, L"*.*"); + if ((d = PyList_New(0)) == NULL) + return NULL; + hFindFile = FindFirstFileW(wnamebuf, &wFileData); + if (hFindFile == INVALID_HANDLE_VALUE) { + errno = GetLastError(); + if (errno == ERROR_FILE_NOT_FOUND) { + return PyList_New(0); + } + return win32_error("FindFirstFileW", namebuf); + } + do { + if (wFileData.cFileName[0] == L'.' && + (wFileData.cFileName[1] == L'\0' || + wFileData.cFileName[1] == L'.' && + wFileData.cFileName[2] == L'\0')) + continue; + v = PyUnicode_FromUnicode(wFileData.cFileName, wcslen(wFileData.cFileName)); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (FindNextFileW(hFindFile, &wFileData) == TRUE); + + if (FindClose(hFindFile) == FALSE) + return win32_error("FindClose", namebuf); + return d; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, "et#:listdir", Py_FileSystemDefaultEncoding, &bufptr, &len)) return NULL; @@ -1199,6 +1377,21 @@ int insize = sizeof(inbuf)/sizeof(inbuf[0]); char outbuf[MAX_PATH*2]; char *temp; + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po)) { + Py_UNICODE woutbuf[MAX_PATH*2]; + Py_UNICODE *wtemp; + if (!GetFullPathNameW(PyUnicode_AS_UNICODE(po), + sizeof(woutbuf)/sizeof(woutbuf[0]), + woutbuf, &wtemp)) + return win32_error("GetFullPathName", ""); + return PyUnicode_FromUnicode(woutbuf, wcslen(woutbuf)); + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } if (!PyArg_ParseTuple (args, "et#:_getfullpathname", Py_FileSystemDefaultEncoding, &inbufp, &insize)) @@ -1220,6 +1413,27 @@ int res; char *path = NULL; int mode = 0777; + +#ifdef MS_WINDOWS + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "U|i:mkdir", &po)) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread lock as + it is a simple dereference. */ + res = _wmkdir(PyUnicode_AS_UNICODE(po)); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } +#endif + if (!PyArg_ParseTuple(args, "et|i:mkdir", Py_FileSystemDefaultEncoding, &path, &mode)) return NULL; @@ -1288,7 +1502,11 @@ static PyObject * posix_rename(PyObject *self, PyObject *args) { - return posix_2str(args, "etet:rename", rename); +#ifdef MS_WINDOWS + return posix_2str(args, "etet:rename", rename, "OO:rename", _wrename); +#else + return posix_2str(args, "etet:rename", rename, NULL, NULL); +#endif } @@ -1299,7 +1517,11 @@ static PyObject * posix_rmdir(PyObject *self, PyObject *args) { - return posix_1str(args, "et:rmdir", rmdir); +#ifdef MS_WINDOWS + return posix_1str(args, "et:rmdir", rmdir, "U:rmdir", _wrmdir); +#else + return posix_1str(args, "et:rmdir", rmdir, NULL, NULL); +#endif } @@ -1310,7 +1532,11 @@ static PyObject * posix_stat(PyObject *self, PyObject *args) { - return posix_do_stat(self, args, "et:stat", STAT); +#ifdef MS_WINDOWS + return posix_do_stat(self, args, "et:stat", STAT, "U:stat", _wstati64); +#else + return posix_do_stat(self, args, "et:stat", STAT, NULL, NULL); +#endif } @@ -1362,7 +1588,11 @@ static PyObject * posix_unlink(PyObject *self, PyObject *args) { - return posix_1str(args, "et:remove", unlink); +#ifdef MS_WINDOWS + return posix_1str(args, "et:remove", unlink, "U:remove", _wunlink); +#else + return posix_1str(args, "et:remove", unlink, NULL, NULL); +#endif } @@ -4092,9 +4322,13 @@ posix_lstat(PyObject *self, PyObject *args) { #ifdef HAVE_LSTAT - return posix_do_stat(self, args, "et:lstat", lstat); + return posix_do_stat(self, args, "et:lstat", lstat, NULL, NULL); #else /* !HAVE_LSTAT */ - return posix_do_stat(self, args, "et:lstat", STAT); +#ifdef MS_WINDOWS + return posix_do_stat(self, args, "et:lstat", STAT, "u:lstat", _wstati64); +#else + return posix_do_stat(self, args, "et:lstat", STAT, NULL, NULL); +#endif #endif /* !HAVE_LSTAT */ } @@ -4130,7 +4364,7 @@ static PyObject * posix_symlink(PyObject *self, PyObject *args) { - return posix_2str(args, "etet:symlink", symlink); + return posix_2str(args, "etet:symlink", symlink, NULL, NULL); } #endif /* HAVE_SYMLINK */ @@ -4311,6 +4545,26 @@ int flag; int mode = 0777; int fd; + +#ifdef MS_WINDOWS + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "Ui|i:mkdir", &po, &flag, &mode)) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread + lock as it is a simple dereference. */ + fd = _wopen(PyUnicode_AS_UNICODE(po), flag, mode); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error(); + return PyInt_FromLong((long)fd); + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } +#endif + if (!PyArg_ParseTuple(args, "eti|i", Py_FileSystemDefaultEncoding, &file, &flag, &mode)) Index: Objects/fileobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/fileobject.c,v retrieving revision 2.167 diff -u -r2.167 fileobject.c --- Objects/fileobject.c 6 Aug 2002 21:50:54 -0000 2.167 +++ Objects/fileobject.c 12 Aug 2002 11:29:58 -0000 @@ -15,6 +15,12 @@ #include #endif +#ifdef _MSC_VER +/* Need GetVersion to see if on NT so safe to use _wfopen */ +#define WINDOWS_LEAN_AND_MEAN +#include +#endif /* _MSC_VER */ + #ifdef macintosh #ifdef USE_GUSI #define HAVE_FTRUNCATE @@ -101,7 +107,7 @@ static PyObject * fill_file_fields(PyFileObject *f, FILE *fp, char *name, char *mode, - int (*close)(FILE *)) + int (*close)(FILE *), PyObject *wname) { assert(f != NULL); assert(PyFile_Check(f)); @@ -109,7 +115,10 @@ Py_DECREF(f->f_name); Py_DECREF(f->f_mode); - f->f_name = PyString_FromString(name); + if (wname) + f->f_name = PyUnicode_FromObject(wname); + else + f->f_name = PyString_FromString(name); f->f_mode = PyString_FromString(mode); f->f_close = close; @@ -155,7 +164,6 @@ else #endif { - Py_BEGIN_ALLOW_THREADS #ifdef WITH_UNIVERSAL_NEWLINES if (strcmp(mode, "U") == 0 || strcmp(mode, "rU") == 0) mode = "rb"; @@ -167,8 +175,26 @@ if (strcmp(mode, "U") == 0 || strcmp(mode, "rU") == 0) mode = "r"; #endif - f->f_fp = fopen(name, mode); - Py_END_ALLOW_THREADS +#ifdef MS_WINDOWS + if (PyUnicode_Check(f->f_name)) { + PyObject *wmode; + wmode = PyUnicode_DecodeASCII(mode, strlen(mode), NULL); + if (f->f_name && wmode) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread + lock as it is a simple dereference. */ + f->f_fp = _wfopen(PyUnicode_AS_UNICODE(f->f_name), + PyUnicode_AS_UNICODE(wmode)); + Py_END_ALLOW_THREADS + } + Py_XDECREF(wmode); + } +#endif + if (NULL == f->f_fp) { + Py_BEGIN_ALLOW_THREADS + f->f_fp = fopen(name, mode); + Py_END_ALLOW_THREADS + } } if (f->f_fp == NULL) { #ifdef NO_FOPEN_ERRNO @@ -214,7 +240,7 @@ PyFileObject *f = (PyFileObject *)PyFile_Type.tp_new(&PyFile_Type, NULL, NULL); if (f != NULL) { - if (fill_file_fields(f, fp, name, mode, close) == NULL) { + if (fill_file_fields(f, fp, name, mode, close, NULL) == NULL) { Py_DECREF(f); f = NULL; } @@ -292,11 +318,24 @@ static PyObject * file_repr(PyFileObject *f) { - return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", + if (PyUnicode_Check(f->f_name)) { + PyObject *ret = NULL; + PyObject *name; + name = PyUnicode_AsUnicodeEscapeString(f->f_name); + ret = PyString_FromFormat("<%s file u'%s', mode '%s' at %p>", + f->f_fp == NULL ? "closed" : "open", + PyString_AsString(name), + PyString_AsString(f->f_mode), + f); + Py_XDECREF(name); + return ret; + } else { + return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", f->f_fp == NULL ? "closed" : "open", PyString_AsString(f->f_name), PyString_AsString(f->f_mode), f); + } } static PyObject * @@ -1760,6 +1799,7 @@ char *name = NULL; char *mode = "r"; int bufsize = -1; + int wideargument = 0; assert(PyFile_Check(self)); if (foself->f_fp != NULL) { @@ -1770,12 +1810,33 @@ Py_DECREF(closeresult); } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:file", kwlist, - Py_FileSystemDefaultEncoding, &name, - &mode, &bufsize)) - return -1; - if (fill_file_fields(foself, NULL, name, mode, fclose) == NULL) - goto Error; +#if defined(MS_WINDOWS) && !defined(Py_UNICODE_WIDE) + if (GetVersion() < 0x80000000) { /* On NT, so wide API available */ + PyObject *po; + if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:file", + kwlist, &po, &mode, &bufsize)) { + wideargument = 1; + if (fill_file_fields(foself, NULL, name, mode, + fclose, po) == NULL) + goto Error; + } else { + /* Drop the argument parsing error as narrow + strings are also valid. */ + PyErr_Clear(); + } + } +#endif + + if (!wideargument) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:file", kwlist, + Py_FileSystemDefaultEncoding, + &name, + &mode, &bufsize)) + return -1; + if (fill_file_fields(foself, NULL, name, mode, + fclose, NULL) == NULL) + goto Error; + } if (open_the_file(foself, name, mode) == NULL) goto Error; PyFile_SetBufSize(self, bufsize);