The attached patch fixes multiple issues with writeBckVersion():
 - Use correct types (size_t+ssize_t versus int)
 - Removed very odd casts
 - Don't read+write whole file in one go as the doubles memory requirements 
for large files.
 - Fix file permissions on backup file.
 - IBM_FWRITE_BUG workaround removed because it is not special anymore.

WriteBackupFile() probably needs same treatment, but I am not sure if VMS 
supports file-descriptor-based I/O.

--- nedit.isj5/source/file.c    2007-10-08 22:22:59.000000000 +0200
+++ nedit.isj6/source/file.c    2007-10-14 13:52:50.000000000 +0200
@@ -1180,13 +1180,13 @@
 #ifndef VMS
     char fullname[MAXPATHLEN], bckname[MAXPATHLEN];
     struct stat statbuf;
-    FILE *inFP, *outFP;
-    int fd, fileLen;
-    char *fileString;
+    int in_fd, out_fd;
+    char *io_buffer;
+#define IO_BUFFER_SIZE ((size_t)(1024*1024))
 
     /* Do only if version backups are turned on */
     if (!window->saveOldVersion) {
-       return False;
+        return FALSE;
     }
     
     /* Get the full name of the file */
@@ -1194,7 +1194,7 @@
     strcat(fullname, window->filename);
     
     /* Generate name for old version */
-    if ((int)(strlen(fullname) + 5) > (int)MAXPATHLEN)
+    if ((strlen(fullname) + 5) > (size_t)MAXPATHLEN)
     {
         return bckError(window, "file name too long", window->filename);
     }
@@ -1202,65 +1202,76 @@
 
     /* Delete the old backup file */
     /* Errors are ignored; we'll notice them later. */
-    unlink(bckname);
+    remove(bckname);
 
     /* open the file being edited.  If there are problems with the
        old file, don't bother the user, just skip the backup */
-    inFP = fopen(fullname, "rb");
-    if (inFP == NULL) {
+    in_fd = open(fullname, O_RDONLY);
+    if (in_fd<0) {
        return FALSE;
     }
 
-    /* find the length of the file */
-    if (fstat(fileno(inFP), &statbuf) != 0) {
+    /* Get permissions of the file.
+       We preserve the normal permissions but not ownership, extended
+       attributes, et cetera. */
+    if (fstat(in_fd, &statbuf) != 0) {
        return FALSE;
     }
-    fileLen = statbuf.st_size;
 
-    /* open the file exclusive and with restrictive permissions. */
-    if ((fd = open(bckname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR | S_IWUSR)) < 0
-        || (outFP = fdopen(fd, "wb")) == NULL) {
-       fclose(inFP);
+    /* open the destination file exclusive and with restrictive permissions. */
+    out_fd = open(bckname, O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, S_IRUSR | S_IWUSR);
+    if (out_fd < 0) {
         return bckError(window, "Error open backup file", bckname);
     }
-    
-    /* Allocate space for the whole contents of the file */
-    fileString = (char *)malloc(fileLen);
-    if (fileString == NULL) {
-       fclose(inFP);
-       fclose(outFP);
+
+    /* Set permissions on new file */
+    if (fchmod(out_fd, statbuf.st_mode) != 0) {
+        close(in_fd);
+        close(out_fd);
+        remove(bckname);
+        return bckError(window, "fchmod() failed", bckname);
+    }
+
+    /* Allocate I/O buffer */
+    io_buffer = (char *)malloc(IO_BUFFER_SIZE);
+    if (io_buffer == NULL) {
+        close(in_fd);
+        close(out_fd);
+        remove(bckname);
        return bckError(window, "out of memory", bckname);
     }
-    
-    /* read the file into fileString */
-    fread(fileString, sizeof(char), fileLen, inFP);
-    if (ferror(inFP)) {
-       fclose(inFP);
-       fclose(outFP);
-       free(fileString);
-       return FALSE;
+
+    /* copy loop */
+    for(;;) {
+        ssize_t bytes_read;
+        ssize_t bytes_written;
+        bytes_read = read(in_fd, io_buffer, IO_BUFFER_SIZE);
+        if (bytes_read<0) {
+            close(in_fd);
+            close(out_fd);
+            remove(bckname);
+            free(io_buffer);
+            return bckError(window, "read() error", window->filename);
+        }
+        if (bytes_read==0)
+            break; /* EOF */
+        /* write to the file */
+        bytes_written = write(out_fd, io_buffer, (size_t)bytes_read);
+        if (bytes_written!=bytes_read) {
+            close(in_fd);
+            close(out_fd);
+            remove(bckname);
+            free(io_buffer);
+            return bckError(window, errorString(), bckname);
+        }
     }
- 
-    /* close the input file, ignore any errors */
-    fclose(inFP);
 
-    /* write to the file */
-#ifdef IBM_FWRITE_BUG
-    write(fileno(outFP), fileString, fileLen);
-#else
-    fwrite(fileString, sizeof(char), fileLen, outFP);
-#endif
-    if (ferror(outFP)) {
-       fclose(outFP);
-       remove(bckname);
-        free(fileString);
-       return bckError(window, errorString(), bckname);
-    }
-    free(fileString);
-    
-    /* close the file */
-    if (fclose(outFP) != 0)
-       return bckError(window, errorString(), bckname);
+    /* close the input and output files */
+    close(in_fd);
+    close(out_fd);
+
+    free(io_buffer);
+
 #endif /* VMS */
        
     return FALSE;
-- 
NEdit Develop mailing list - [email protected]
http://www.nedit.org/mailman/listinfo/develop

Reply via email to