From: John Darrington Date: Fri, 15 Jun 2012 18:29:24 +0000 (+0200) Subject: ext-array.c: Ensure that fseek is called before switching between read and write. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=987428608748d573aa3378725e929823f45b7a81 ext-array.c: Ensure that fseek is called before switching between read and write. ANSI C requires that a file positioning function (eg seek) occurs before a switch from reading to writing a stream (or vici-versa). We had not been doing this. This had caused problems which manifested themselves on Windows operating systems, by mysteriously failing to write the stream (and thus truncating the datafile). This change corrects this. Thanks to Harry Thijssen and Henry Gong for their very valuable assistance tracking down the cause of this problem. Reviewed-by: Ben Pfaff --- diff --git a/src/libpspp/ext-array.c b/src/libpspp/ext-array.c index 57ff8e4a7d..e5287fcc75 100644 --- a/src/libpspp/ext-array.c +++ b/src/libpspp/ext-array.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,6 +36,12 @@ #include "gettext.h" #define _(msgid) gettext (msgid) +enum op + { + OP_WRITE, /* writing */ + OP_READ /* reading */ + }; + struct ext_array { FILE *file; /* Underlying file. */ @@ -45,6 +51,9 @@ struct ext_array the stream buffer, making the common case of sequential access to cases unreasonably slow. */ off_t position; + + /* The most recent operation performed */ + enum op op; }; /* Creates and returns a new external array. */ @@ -56,6 +65,7 @@ ext_array_create (void) if (ea->file == NULL) error (0, errno, _("failed to create temporary file")); ea->position = 0; + ea->op = OP_WRITE; return ea; } @@ -80,13 +90,12 @@ ext_array_destroy (struct ext_array *ea) Returns true if the seek is successful and EA is not otherwise tainted, false otherwise. */ static bool -do_seek (const struct ext_array *ea_, off_t offset) +do_seek (const struct ext_array *ea_, off_t offset, enum op op) { struct ext_array *ea = CONST_CAST (struct ext_array *, ea_); - if (!ext_array_error (ea)) { - if (ea->position == offset) + if (ea->position == offset && ea->op == op) return true; else if (fseeko (ea->file, offset, SEEK_SET) == 0) { @@ -121,6 +130,7 @@ do_read (const struct ext_array *ea_, void *buffer, size_t bytes) return false; } ea->position += bytes; + ea->op = OP_READ; return true; } @@ -138,6 +148,7 @@ do_write (struct ext_array *ea, const void *buffer, size_t bytes) return false; } ea->position += bytes; + ea->op = OP_WRITE; return true; } @@ -146,16 +157,17 @@ do_write (struct ext_array *ea, const void *buffer, size_t bytes) bool ext_array_read (const struct ext_array *ea, off_t offset, size_t n, void *data) { - return do_seek (ea, offset) && do_read (ea, data, n); + return do_seek (ea, offset, OP_READ) && do_read (ea, data, n); } + /* Writes the N bytes in DATA to EA at byte offset OFFSET. Returns true if successful, false on failure. */ bool ext_array_write (struct ext_array *ea, off_t offset, size_t n, const void *data) { - return do_seek (ea, offset) && do_write (ea, data, n); + return do_seek (ea, offset, OP_WRITE) && do_write (ea, data, n); } /* Returns true if an error has occurred in I/O on EA,