diff options
Diffstat (limited to 'Objects/fileobject.c')
-rw-r--r-- | Objects/fileobject.c | 140 |
1 files changed, 66 insertions, 74 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c index bddd81e93a..cdcacc41af 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -96,7 +96,7 @@ dircheck(PyFileObject* f) #else char *msg = "Is a directory"; #endif - PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(is)", + PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(is)", EISDIR, msg); PyErr_SetObject(PyExc_IOError, exc); Py_XDECREF(exc); @@ -137,7 +137,7 @@ fill_file_fields(PyFileObject *f, FILE *fp, char *name, char *mode, #endif Py_INCREF(Py_None); f->f_encoding = Py_None; - + if (f->f_name == NULL || f->f_mode == NULL) return NULL; f->f_fp = fp; @@ -189,8 +189,8 @@ open_the_file(PyFileObject *f, char *name, char *mode) #endif #ifdef MS_WINDOWS if (PyUnicode_Check(f->f_name)) { - PyObject *wmode; - wmode = PyUnicode_DecodeASCII(mode, strlen(mode), NULL); + PyObject *wmode; + wmode = PyUnicode_DecodeASCII(mode, strlen(mode), NULL); if (f->f_name && wmode) { Py_BEGIN_ALLOW_THREADS /* PyUnicode_AS_UNICODE OK without thread @@ -529,18 +529,33 @@ file_seek(PyFileObject *f, PyObject *args) static PyObject * file_truncate(PyFileObject *f, PyObject *args) { - int ret; Py_off_t newsize; - PyObject *newsizeobj; + PyObject *newsizeobj = NULL; + Py_off_t initialpos; + int ret; if (f->f_fp == NULL) return err_closed(); - newsizeobj = NULL; if (!PyArg_UnpackTuple(args, "truncate", 0, 1, &newsizeobj)) return NULL; + /* Get current file position. If the file happens to be open for + * update and the last operation was an input operation, C doesn't + * define what the later fflush() will do, but we promise truncate() + * won't change the current position (and fflush() *does* change it + * then at least on Windows). The easiest thing is to capture + * current pos now and seek back to it at the end. + */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + initialpos = _portable_ftell(f->f_fp); + Py_END_ALLOW_THREADS + if (initialpos == -1) + goto onioerror; + /* Set newsize to current postion if newsizeobj NULL, else to the - specified value. */ + * specified value. + */ if (newsizeobj != NULL) { #if !defined(HAVE_LARGEFILE_SUPPORT) newsize = PyInt_AsLong(newsizeobj); @@ -552,17 +567,13 @@ file_truncate(PyFileObject *f, PyObject *args) if (PyErr_Occurred()) return NULL; } - else { - /* Default to current position. */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - newsize = _portable_ftell(f->f_fp); - Py_END_ALLOW_THREADS - if (newsize == -1) - goto onioerror; - } + else /* default to current position */ + newsize = initialpos; - /* Flush the file. */ + /* Flush the stream. We're mixing stream-level I/O with lower-level + * I/O, and a flush may be necessary to synch both platform views + * of the current file state. + */ Py_BEGIN_ALLOW_THREADS errno = 0; ret = fflush(f->f_fp); @@ -574,66 +585,47 @@ file_truncate(PyFileObject *f, PyObject *args) /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, so don't even try using it. */ { - Py_off_t current; /* current file position */ HANDLE hFile; - int error; - /* current <- current file postion. */ - if (newsizeobj == NULL) - current = newsize; - else { - Py_BEGIN_ALLOW_THREADS - errno = 0; - current = _portable_ftell(f->f_fp); - Py_END_ALLOW_THREADS - if (current == -1) - goto onioerror; - } - - /* Move to newsize. */ - if (current != newsize) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - error = _portable_fseek(f->f_fp, newsize, SEEK_SET) - != 0; - Py_END_ALLOW_THREADS - if (error) - goto onioerror; - } + /* Have to move current pos to desired endpoint on Windows. */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; + Py_END_ALLOW_THREADS + if (ret) + goto onioerror; /* Truncate. Note that this may grow the file! */ Py_BEGIN_ALLOW_THREADS errno = 0; hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); - error = hFile == (HANDLE)-1; - if (!error) { - error = SetEndOfFile(hFile) == 0; - if (error) + ret = hFile == (HANDLE)-1; + if (ret == 0) { + ret = SetEndOfFile(hFile) == 0; + if (ret) errno = EACCES; } Py_END_ALLOW_THREADS - if (error) + if (ret) goto onioerror; - - /* Restore original file position. */ - if (current != newsize) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - error = _portable_fseek(f->f_fp, current, SEEK_SET) - != 0; - Py_END_ALLOW_THREADS - if (error) - goto onioerror; - } } #else Py_BEGIN_ALLOW_THREADS errno = 0; ret = ftruncate(fileno(f->f_fp), newsize); Py_END_ALLOW_THREADS - if (ret != 0) goto onioerror; + if (ret != 0) + goto onioerror; #endif /* !MS_WINDOWS */ + /* Restore original file position. */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0; + Py_END_ALLOW_THREADS + if (ret) + goto onioerror; + Py_INCREF(Py_None); return Py_None; @@ -866,7 +858,7 @@ file_readinto(PyFileObject *f, PyObject *args) while (ntodo > 0) { Py_BEGIN_ALLOW_THREADS errno = 0; - nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp, + nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp, (PyObject *)f); Py_END_ALLOW_THREADS if (nnow == 0) { @@ -1137,8 +1129,8 @@ get_line(PyFileObject *f, int n) if (skipnextlf ) { skipnextlf = 0; if (c == '\n') { - /* Seeing a \n here with - * skipnextlf true means we + /* Seeing a \n here with + * skipnextlf true means we * saw a \r before. */ newlinetypes |= NEWLINE_CRLF; @@ -1734,8 +1726,8 @@ get_newlines(PyFileObject *f, void *closure) case NEWLINE_CR|NEWLINE_LF|NEWLINE_CRLF: return Py_BuildValue("(sss)", "\r", "\n", "\r\n"); default: - PyErr_Format(PyExc_SystemError, - "Unknown newlines value 0x%x\n", + PyErr_Format(PyExc_SystemError, + "Unknown newlines value 0x%x\n", f->f_newlinetypes); return NULL; } @@ -1745,7 +1737,7 @@ get_newlines(PyFileObject *f, void *closure) static PyGetSetDef file_getsetlist[] = { {"closed", (getter)get_closed, NULL, "True if the file is closed"}, #ifdef WITH_UNIVERSAL_NEWLINES - {"newlines", (getter)get_newlines, NULL, + {"newlines", (getter)get_newlines, NULL, "end-of-line convention used in this file"}, #endif {0}, @@ -1760,8 +1752,8 @@ drop_readahead(PyFileObject *f) } } -/* Make sure that file has a readahead buffer with at least one byte - (unless at EOF) and no more than bufsize. Returns negative value on +/* Make sure that file has a readahead buffer with at least one byte + (unless at EOF) and no more than bufsize. Returns negative value on error */ static int readahead(PyFileObject *f, int bufsize) @@ -1769,7 +1761,7 @@ readahead(PyFileObject *f, int bufsize) int chunksize; if (f->f_buf != NULL) { - if( (f->f_bufend - f->f_bufptr) >= 1) + if( (f->f_bufend - f->f_bufptr) >= 1) return 0; else drop_readahead(f); @@ -1796,8 +1788,8 @@ readahead(PyFileObject *f, int bufsize) } /* Used by file_iternext. The returned string will start with 'skip' - uninitialized bytes followed by the remainder of the line. Don't be - horrified by the recursive call: maximum recursion depth is limited by + uninitialized bytes followed by the remainder of the line. Don't be + horrified by the recursive call: maximum recursion depth is limited by logarithmic buffer growth to about 50 even when reading a 1gb line. */ static PyStringObject * @@ -1809,11 +1801,11 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) int len; if (f->f_buf == NULL) - if (readahead(f, bufsize) < 0) + if (readahead(f, bufsize) < 0) return NULL; len = f->f_bufend - f->f_bufptr; - if (len == 0) + if (len == 0) return (PyStringObject *) PyString_FromStringAndSize(NULL, skip); bufptr = memchr(f->f_bufptr, '\n', len); @@ -1822,7 +1814,7 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) len = bufptr - f->f_bufptr; s = (PyStringObject *) PyString_FromStringAndSize(NULL, skip+len); - if (s == NULL) + if (s == NULL) return NULL; memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); f->f_bufptr = bufptr; @@ -2079,7 +2071,7 @@ PyFile_WriteObject(PyObject *v, PyObject *f, int flags) return -1; } #ifdef Py_USING_UNICODE - if ((flags & Py_PRINT_RAW) && + if ((flags & Py_PRINT_RAW) && PyUnicode_Check(v) && enc != Py_None) { char *cenc = PyString_AS_STRING(enc); value = PyUnicode_AsEncodedString(v, cenc, "strict"); |