1 /***************************************************************
2 ** File access routines based on ANSI C (no Unix stuff).
4 ** This file is part of pForth
6 ** Permission to use, copy, modify, and/or distribute this
7 ** software for any purpose with or without fee is hereby granted.
9 ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12 ** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 ** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 ** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
15 ** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 ** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 ****************************************************************/
20 #include "../pf_all.h"
24 #include <limits.h> /* For LONG_MAX */
28 /* Copy SIZE bytes from File FROM to File TO. Return non-FALSE on error. */
29 static bool_t CopyFile( FileStream *From, FileStream *To, long Size)
34 char *Buffer = pfAllocMem( BufSize );
39 size_t N = MIN( Diff, BufSize );
40 if( fread( Buffer, 1, N, From ) < N ) goto cleanup;
41 if( fwrite( Buffer, 1, N, To ) < N ) goto cleanup;
52 /* Shrink the file FILE to NEWSIZE. Return non-FALSE on error.
54 * There's no direct way to do this in ANSI C. The closest thing we
55 * have is freopen(3), which truncates a file to zero length if we use
56 * "w+b" as mode argument. So we do this:
58 * 1. copy original content to temporary file
59 * 2. re-open and truncate FILE
60 * 3. copy the temporary file to FILE
62 * Unfortunately, "w+b" may not be the same mode as the original mode
63 * of FILE. I don't see a away to avoid this, though.
65 * We call freopen with NULL as path argument, because we don't know
66 * the actual file-name. It seems that the trick with path=NULL is
67 * not part of C89 but it's in C99.
69 static bool_t TruncateFile( FileStream *File, long Newsize )
72 if( fseek( File, 0, SEEK_SET ) == 0)
74 FileStream *TmpFile = tmpfile();
77 if( CopyFile( File, TmpFile, Newsize )) goto cleanup;
78 if( fseek( TmpFile, 0, SEEK_SET ) != 0 ) goto cleanup;
79 if( freopen( NULL, "w+b", File ) == NULL ) goto cleanup;
80 if( CopyFile( TmpFile, File, Newsize )) goto cleanup;
90 /* Write DIFF 0 bytes to FILE. Return non-FALSE on error. */
91 static bool_t ExtendFile( FileStream *File, size_t Diff )
95 char * Buffer = pfAllocMem( BufSize );
98 pfSetMemory( Buffer, 0, BufSize );
101 size_t N = MIN( Diff, BufSize );
102 if( fwrite( Buffer, 1, N, File ) < N ) goto cleanup;
112 ThrowCode sdResizeFile( FileStream *File, uint64_t Size )
115 if( Size <= LONG_MAX )
117 long Newsize = (long) Size;
118 if( fseek( File, 0, SEEK_END ) == 0 )
120 long Oldsize = ftell( File );
123 Error = ( Oldsize <= Newsize
124 ? ExtendFile( File, Newsize - Oldsize )
125 : TruncateFile( File, Newsize ));
129 return Error ? THROW_RESIZE_FILE : 0;
132 #endif /* !PF_NO_FILEIO */