LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Python - fileutils.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 71 184 38.6 %
Date: 2012-12-17 Functions: 7 10 70.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "Python.h"
       2             : #ifdef MS_WINDOWS
       3             : #  include <windows.h>
       4             : #endif
       5             : 
       6             : #ifdef HAVE_LANGINFO_H
       7             : #include <langinfo.h>
       8             : #endif
       9             : 
      10             : PyObject *
      11           4 : _Py_device_encoding(int fd)
      12             : {
      13             : #if defined(MS_WINDOWS) || defined(MS_WIN64)
      14             :     UINT cp;
      15             : #endif
      16           4 :     if (!_PyVerify_fd(fd) || !isatty(fd)) {
      17           4 :         Py_RETURN_NONE;
      18             :     }
      19             : #if defined(MS_WINDOWS) || defined(MS_WIN64)
      20             :     if (fd == 0)
      21             :         cp = GetConsoleCP();
      22             :     else if (fd == 1 || fd == 2)
      23             :         cp = GetConsoleOutputCP();
      24             :     else
      25             :         cp = 0;
      26             :     /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application
      27             :        has no console */
      28             :     if (cp != 0)
      29             :         return PyUnicode_FromFormat("cp%u", (unsigned int)cp);
      30             : #elif defined(CODESET)
      31             :     {
      32           0 :         char *codeset = nl_langinfo(CODESET);
      33           0 :         if (codeset != NULL && codeset[0] != 0)
      34           0 :             return PyUnicode_FromString(codeset);
      35             :     }
      36             : #endif
      37           0 :     Py_RETURN_NONE;
      38             : }
      39             : 
      40             : #ifdef HAVE_STAT
      41             : 
      42             : /* Decode a byte string from the locale encoding with the
      43             :    surrogateescape error handler (undecodable bytes are decoded as characters
      44             :    in range U+DC80..U+DCFF). If a byte sequence can be decoded as a surrogate
      45             :    character, escape the bytes using the surrogateescape error handler instead
      46             :    of decoding them.
      47             : 
      48             :    Use _Py_wchar2char() to encode the character string back to a byte string.
      49             : 
      50             :    Return a pointer to a newly allocated wide character string (use
      51             :    PyMem_Free() to free the memory) and write the number of written wide
      52             :    characters excluding the null character into *size if size is not NULL, or
      53             :    NULL on error (decoding or memory allocation error). If size is not NULL,
      54             :    *size is set to (size_t)-1 on memory error and (size_t)-2 on decoding
      55             :    error.
      56             : 
      57             :    Conversion errors should never happen, unless there is a bug in the C
      58             :    library. */
      59             : wchar_t*
      60         343 : _Py_char2wchar(const char* arg, size_t *size)
      61             : {
      62             :     wchar_t *res;
      63             : #ifdef HAVE_BROKEN_MBSTOWCS
      64             :     /* Some platforms have a broken implementation of
      65             :      * mbstowcs which does not count the characters that
      66             :      * would result from conversion.  Use an upper bound.
      67             :      */
      68             :     size_t argsize = strlen(arg);
      69             : #else
      70         343 :     size_t argsize = mbstowcs(NULL, arg, 0);
      71             : #endif
      72             :     size_t count;
      73             :     unsigned char *in;
      74             :     wchar_t *out;
      75             : #ifdef HAVE_MBRTOWC
      76             :     mbstate_t mbs;
      77             : #endif
      78         343 :     if (argsize != (size_t)-1) {
      79         343 :         res = (wchar_t *)PyMem_Malloc((argsize+1)*sizeof(wchar_t));
      80         343 :         if (!res)
      81           0 :             goto oom;
      82         343 :         count = mbstowcs(res, arg, argsize+1);
      83         343 :         if (count != (size_t)-1) {
      84             :             wchar_t *tmp;
      85             :             /* Only use the result if it contains no
      86             :                surrogate characters. */
      87       10826 :             for (tmp = res; *tmp != 0 &&
      88       10140 :                          (*tmp < 0xd800 || *tmp > 0xdfff); tmp++)
      89             :                 ;
      90         343 :             if (*tmp == 0) {
      91         343 :                 if (size != NULL)
      92         339 :                     *size = count;
      93         343 :                 return res;
      94             :             }
      95             :         }
      96           0 :         PyMem_Free(res);
      97             :     }
      98             :     /* Conversion failed. Fall back to escaping with surrogateescape. */
      99             : #ifdef HAVE_MBRTOWC
     100             :     /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
     101             : 
     102             :     /* Overallocate; as multi-byte characters are in the argument, the
     103             :        actual output could use less memory. */
     104           0 :     argsize = strlen(arg) + 1;
     105           0 :     res = (wchar_t*)PyMem_Malloc(argsize*sizeof(wchar_t));
     106           0 :     if (!res)
     107           0 :         goto oom;
     108           0 :     in = (unsigned char*)arg;
     109           0 :     out = res;
     110           0 :     memset(&mbs, 0, sizeof mbs);
     111           0 :     while (argsize) {
     112           0 :         size_t converted = mbrtowc(out, (char*)in, argsize, &mbs);
     113           0 :         if (converted == 0)
     114             :             /* Reached end of string; null char stored. */
     115           0 :             break;
     116           0 :         if (converted == (size_t)-2) {
     117             :             /* Incomplete character. This should never happen,
     118             :                since we provide everything that we have -
     119             :                unless there is a bug in the C library, or I
     120             :                misunderstood how mbrtowc works. */
     121           0 :             PyMem_Free(res);
     122           0 :             if (size != NULL)
     123           0 :                 *size = (size_t)-2;
     124           0 :             return NULL;
     125             :         }
     126           0 :         if (converted == (size_t)-1) {
     127             :             /* Conversion error. Escape as UTF-8b, and start over
     128             :                in the initial shift state. */
     129           0 :             *out++ = 0xdc00 + *in++;
     130           0 :             argsize--;
     131           0 :             memset(&mbs, 0, sizeof mbs);
     132           0 :             continue;
     133             :         }
     134           0 :         if (*out >= 0xd800 && *out <= 0xdfff) {
     135             :             /* Surrogate character.  Escape the original
     136             :                byte sequence with surrogateescape. */
     137           0 :             argsize -= converted;
     138           0 :             while (converted--)
     139           0 :                 *out++ = 0xdc00 + *in++;
     140           0 :             continue;
     141             :         }
     142             :         /* successfully converted some bytes */
     143           0 :         in += converted;
     144           0 :         argsize -= converted;
     145           0 :         out++;
     146             :     }
     147             : #else
     148             :     /* Cannot use C locale for escaping; manually escape as if charset
     149             :        is ASCII (i.e. escape all bytes > 128. This will still roundtrip
     150             :        correctly in the locale's charset, which must be an ASCII superset. */
     151             :     res = PyMem_Malloc((strlen(arg)+1)*sizeof(wchar_t));
     152             :     if (!res)
     153             :         goto oom;
     154             :     in = (unsigned char*)arg;
     155             :     out = res;
     156             :     while(*in)
     157             :         if(*in < 128)
     158             :             *out++ = *in++;
     159             :         else
     160             :             *out++ = 0xdc00 + *in++;
     161             :     *out = 0;
     162             : #endif
     163           0 :     if (size != NULL)
     164           0 :         *size = out - res;
     165           0 :     return res;
     166             : oom:
     167           0 :     if (size != NULL)
     168           0 :         *size = (size_t)-1;
     169           0 :     return NULL;
     170             : }
     171             : 
     172             : /* Encode a (wide) character string to the locale encoding with the
     173             :    surrogateescape error handler (characters in range U+DC80..U+DCFF are
     174             :    converted to bytes 0x80..0xFF).
     175             : 
     176             :    This function is the reverse of _Py_char2wchar().
     177             : 
     178             :    Return a pointer to a newly allocated byte string (use PyMem_Free() to free
     179             :    the memory), or NULL on encoding or memory allocation error.
     180             : 
     181             :    If error_pos is not NULL: *error_pos is the index of the invalid character
     182             :    on encoding error, or (size_t)-1 otherwise. */
     183             : char*
     184          40 : _Py_wchar2char(const wchar_t *text, size_t *error_pos)
     185             : {
     186          40 :     const size_t len = wcslen(text);
     187          40 :     char *result = NULL, *bytes = NULL;
     188             :     size_t i, size, converted;
     189             :     wchar_t c, buf[2];
     190             : 
     191          40 :     if (error_pos != NULL)
     192          26 :         *error_pos = (size_t)-1;
     193             : 
     194             :     /* The function works in two steps:
     195             :        1. compute the length of the output buffer in bytes (size)
     196             :        2. outputs the bytes */
     197          40 :     size = 0;
     198          40 :     buf[1] = 0;
     199             :     while (1) {
     200        7280 :         for (i=0; i < len; i++) {
     201        7200 :             c = text[i];
     202        7200 :             if (c >= 0xdc80 && c <= 0xdcff) {
     203             :                 /* UTF-8b surrogate */
     204           0 :                 if (bytes != NULL) {
     205           0 :                     *bytes++ = c - 0xdc00;
     206           0 :                     size--;
     207             :                 }
     208             :                 else
     209           0 :                     size++;
     210           0 :                 continue;
     211             :             }
     212             :             else {
     213        7200 :                 buf[0] = c;
     214        7200 :                 if (bytes != NULL)
     215        3600 :                     converted = wcstombs(bytes, buf, size);
     216             :                 else
     217        3600 :                     converted = wcstombs(NULL, buf, 0);
     218        7200 :                 if (converted == (size_t)-1) {
     219           0 :                     if (result != NULL)
     220           0 :                         PyMem_Free(result);
     221           0 :                     if (error_pos != NULL)
     222           0 :                         *error_pos = i;
     223           0 :                     return NULL;
     224             :                 }
     225        7200 :                 if (bytes != NULL) {
     226        3600 :                     bytes += converted;
     227        3600 :                     size -= converted;
     228             :                 }
     229             :                 else
     230        3600 :                     size += converted;
     231             :             }
     232             :         }
     233          80 :         if (result != NULL) {
     234          40 :             *bytes = 0;
     235          40 :             break;
     236             :         }
     237             : 
     238          40 :         size += 1; /* nul byte at the end */
     239          40 :         result = PyMem_Malloc(size);
     240          40 :         if (result == NULL)
     241           0 :             return NULL;
     242          40 :         bytes = result;
     243          40 :     }
     244          40 :     return result;
     245             : }
     246             : 
     247             : /* In principle, this should use HAVE__WSTAT, and _wstat
     248             :    should be detected by autoconf. However, no current
     249             :    POSIX system provides that function, so testing for
     250             :    it is pointless.
     251             :    Not sure whether the MS_WINDOWS guards are necessary:
     252             :    perhaps for cygwin/mingw builds?
     253             : */
     254             : #if defined(HAVE_STAT) && !defined(MS_WINDOWS)
     255             : 
     256             : /* Get file status. Encode the path to the locale encoding. */
     257             : 
     258             : int
     259          11 : _Py_wstat(const wchar_t* path, struct stat *buf)
     260             : {
     261             :     int err;
     262             :     char *fname;
     263          11 :     fname = _Py_wchar2char(path, NULL);
     264          11 :     if (fname == NULL) {
     265           0 :         errno = EINVAL;
     266           0 :         return -1;
     267             :     }
     268          11 :     err = stat(fname, buf);
     269          11 :     PyMem_Free(fname);
     270          11 :     return err;
     271             : }
     272             : #endif
     273             : 
     274             : /* Call _wstat() on Windows, or encode the path to the filesystem encoding and
     275             :    call stat() otherwise. Only fill st_mode attribute on Windows.
     276             : 
     277             :    Return 0 on success, -1 on _wstat() / stat() error, -2 if an exception was
     278             :    raised. */
     279             : 
     280             : int
     281          23 : _Py_stat(PyObject *path, struct stat *statbuf)
     282             : {
     283             : #ifdef MS_WINDOWS
     284             :     int err;
     285             :     struct _stat wstatbuf;
     286             :     wchar_t *wpath;
     287             : 
     288             :     wpath = PyUnicode_AsUnicode(path);
     289             :     if (wpath == NULL)
     290             :         return -2;
     291             :     err = _wstat(wpath, &wstatbuf);
     292             :     if (!err)
     293             :         statbuf->st_mode = wstatbuf.st_mode;
     294             :     return err;
     295             : #else
     296             :     int ret;
     297          23 :     PyObject *bytes = PyUnicode_EncodeFSDefault(path);
     298          23 :     if (bytes == NULL)
     299           0 :         return -2;
     300          23 :     ret = stat(PyBytes_AS_STRING(bytes), statbuf);
     301          23 :     Py_DECREF(bytes);
     302          23 :     return ret;
     303             : #endif
     304             : }
     305             : 
     306             : /* Open a file. Use _wfopen() on Windows, encode the path to the locale
     307             :    encoding and use fopen() otherwise. */
     308             : 
     309             : FILE *
     310           2 : _Py_wfopen(const wchar_t *path, const wchar_t *mode)
     311             : {
     312             : #ifndef MS_WINDOWS
     313             :     FILE *f;
     314             :     char *cpath;
     315             :     char cmode[10];
     316             :     size_t r;
     317           2 :     r = wcstombs(cmode, mode, 10);
     318           2 :     if (r == (size_t)-1 || r >= 10) {
     319           0 :         errno = EINVAL;
     320           0 :         return NULL;
     321             :     }
     322           2 :     cpath = _Py_wchar2char(path, NULL);
     323           2 :     if (cpath == NULL)
     324           0 :         return NULL;
     325           2 :     f = fopen(cpath, cmode);
     326           2 :     PyMem_Free(cpath);
     327           2 :     return f;
     328             : #else
     329             :     return _wfopen(path, mode);
     330             : #endif
     331             : }
     332             : 
     333             : /* Call _wfopen() on Windows, or encode the path to the filesystem encoding and
     334             :    call fopen() otherwise.
     335             : 
     336             :    Return the new file object on success, or NULL if the file cannot be open or
     337             :    (if PyErr_Occurred()) on unicode error */
     338             : 
     339             : FILE*
     340           0 : _Py_fopen(PyObject *path, const char *mode)
     341             : {
     342             : #ifdef MS_WINDOWS
     343             :     wchar_t *wpath;
     344             :     wchar_t wmode[10];
     345             :     int usize;
     346             : 
     347             :     if (!PyUnicode_Check(path)) {
     348             :         PyErr_Format(PyExc_TypeError,
     349             :                      "str file path expected under Windows, got %R",
     350             :                      Py_TYPE(path));
     351             :         return NULL;
     352             :     }
     353             :     wpath = PyUnicode_AsUnicode(path);
     354             :     if (wpath == NULL)
     355             :         return NULL;
     356             : 
     357             :     usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, wmode, sizeof(wmode));
     358             :     if (usize == 0)
     359             :         return NULL;
     360             : 
     361             :     return _wfopen(wpath, wmode);
     362             : #else
     363             :     FILE *f;
     364             :     PyObject *bytes;
     365           0 :     if (!PyUnicode_FSConverter(path, &bytes))
     366           0 :         return NULL;
     367           0 :     f = fopen(PyBytes_AS_STRING(bytes), mode);
     368           0 :     Py_DECREF(bytes);
     369           0 :     return f;
     370             : #endif
     371             : }
     372             : 
     373             : #ifdef HAVE_READLINK
     374             : 
     375             : /* Read value of symbolic link. Encode the path to the locale encoding, decode
     376             :    the result from the locale encoding. Return -1 on error. */
     377             : 
     378             : int
     379           1 : _Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz)
     380             : {
     381             :     char *cpath;
     382             :     char cbuf[PATH_MAX];
     383             :     wchar_t *wbuf;
     384             :     int res;
     385             :     size_t r1;
     386             : 
     387           1 :     cpath = _Py_wchar2char(path, NULL);
     388           1 :     if (cpath == NULL) {
     389           0 :         errno = EINVAL;
     390           0 :         return -1;
     391             :     }
     392           1 :     res = (int)readlink(cpath, cbuf, PATH_MAX);
     393           1 :     PyMem_Free(cpath);
     394           1 :     if (res == -1)
     395           1 :         return -1;
     396           0 :     if (res == PATH_MAX) {
     397           0 :         errno = EINVAL;
     398           0 :         return -1;
     399             :     }
     400           0 :     cbuf[res] = '\0'; /* buf will be null terminated */
     401           0 :     wbuf = _Py_char2wchar(cbuf, &r1);
     402           0 :     if (wbuf == NULL) {
     403           0 :         errno = EINVAL;
     404           0 :         return -1;
     405             :     }
     406           0 :     if (bufsiz <= r1) {
     407           0 :         PyMem_Free(wbuf);
     408           0 :         errno = EINVAL;
     409           0 :         return -1;
     410             :     }
     411           0 :     wcsncpy(buf, wbuf, bufsiz);
     412           0 :     PyMem_Free(wbuf);
     413           0 :     return (int)r1;
     414             : }
     415             : #endif
     416             : 
     417             : #ifdef HAVE_REALPATH
     418             : 
     419             : /* Return the canonicalized absolute pathname. Encode path to the locale
     420             :    encoding, decode the result from the locale encoding.
     421             :    Return NULL on error. */
     422             : 
     423             : wchar_t*
     424           0 : _Py_wrealpath(const wchar_t *path,
     425             :               wchar_t *resolved_path, size_t resolved_path_size)
     426             : {
     427             :     char *cpath;
     428             :     char cresolved_path[PATH_MAX];
     429             :     wchar_t *wresolved_path;
     430             :     char *res;
     431             :     size_t r;
     432           0 :     cpath = _Py_wchar2char(path, NULL);
     433           0 :     if (cpath == NULL) {
     434           0 :         errno = EINVAL;
     435           0 :         return NULL;
     436             :     }
     437           0 :     res = realpath(cpath, cresolved_path);
     438           0 :     PyMem_Free(cpath);
     439           0 :     if (res == NULL)
     440           0 :         return NULL;
     441             : 
     442           0 :     wresolved_path = _Py_char2wchar(cresolved_path, &r);
     443           0 :     if (wresolved_path == NULL) {
     444           0 :         errno = EINVAL;
     445           0 :         return NULL;
     446             :     }
     447           0 :     if (resolved_path_size <= r) {
     448           0 :         PyMem_Free(wresolved_path);
     449           0 :         errno = EINVAL;
     450           0 :         return NULL;
     451             :     }
     452           0 :     wcsncpy(resolved_path, wresolved_path, resolved_path_size);
     453           0 :     PyMem_Free(wresolved_path);
     454           0 :     return resolved_path;
     455             : }
     456             : #endif
     457             : 
     458             : /* Get the current directory. size is the buffer size in wide characters
     459             :    including the null character. Decode the path from the locale encoding.
     460             :    Return NULL on error. */
     461             : 
     462             : wchar_t*
     463           0 : _Py_wgetcwd(wchar_t *buf, size_t size)
     464             : {
     465             : #ifdef MS_WINDOWS
     466             :     return _wgetcwd(buf, size);
     467             : #else
     468             :     char fname[PATH_MAX];
     469             :     wchar_t *wname;
     470             :     size_t len;
     471             : 
     472           0 :     if (getcwd(fname, PATH_MAX) == NULL)
     473           0 :         return NULL;
     474           0 :     wname = _Py_char2wchar(fname, &len);
     475           0 :     if (wname == NULL)
     476           0 :         return NULL;
     477           0 :     if (size <= len) {
     478           0 :         PyMem_Free(wname);
     479           0 :         return NULL;
     480             :     }
     481           0 :     wcsncpy(buf, wname, size);
     482           0 :     PyMem_Free(wname);
     483           0 :     return buf;
     484             : #endif
     485             : }
     486             : 
     487             : #endif

Generated by: LCOV version 1.10