Work around ftruncate implementations that don't support extending

files.
This commit is contained in:
Alexandre Julliard 2002-01-29 02:51:12 +00:00
parent 5d93b6ede9
commit 86e5efb6b3
1 changed files with 41 additions and 17 deletions

View File

@ -456,29 +456,46 @@ static int set_file_pointer( handle_t handle, unsigned int *low, int *high, int
return 1; return 1;
} }
static int truncate_file( handle_t handle ) /* extend a file beyond the current end of file */
static int extend_file( struct file *file, off_t size )
{ {
struct file *file; static const char zero;
off_t result;
if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE ))) /* extend the file one byte beyond the requested size and then truncate it */
return 0; /* this should work around ftruncate implementations that can't extend files */
if (((result = lseek( file->obj.fd, 0, SEEK_CUR )) == -1) || if ((lseek( file->obj.fd, size, SEEK_SET ) != -1) &&
(ftruncate( file->obj.fd, result ) == -1)) (write( file->obj.fd, &zero, 1 ) != -1))
{ {
file_set_error(); ftruncate( file->obj.fd, size );
release_object( file );
return 0;
}
release_object( file );
return 1; return 1;
}
file_set_error();
return 0;
}
/* truncate file at current position */
static int truncate_file( struct file *file )
{
int ret = 0;
off_t pos = lseek( file->obj.fd, 0, SEEK_CUR );
off_t eof = lseek( file->obj.fd, 0, SEEK_END );
if (eof < pos) ret = extend_file( file, pos );
else
{
if (ftruncate( file->obj.fd, pos ) != -1) ret = 1;
else file_set_error();
}
lseek( file->obj.fd, pos, SEEK_SET ); /* restore file pos */
return ret;
} }
/* try to grow the file to the specified size */ /* try to grow the file to the specified size */
int grow_file( struct file *file, int size_high, int size_low ) int grow_file( struct file *file, int size_high, int size_low )
{ {
int ret = 0;
struct stat st; struct stat st;
off_t size = size_low + (((off_t)size_high)<<32); off_t old_pos, size = size_low + (((off_t)size_high)<<32);
if (fstat( file->obj.fd, &st ) == -1) if (fstat( file->obj.fd, &st ) == -1)
{ {
@ -486,9 +503,10 @@ int grow_file( struct file *file, int size_high, int size_low )
return 0; return 0;
} }
if (st.st_size >= size) return 1; /* already large enough */ if (st.st_size >= size) return 1; /* already large enough */
if (ftruncate( file->obj.fd, size ) != -1) return 1; old_pos = lseek( file->obj.fd, 0, SEEK_CUR ); /* save old pos */
file_set_error(); ret = extend_file( file, size );
return 0; lseek( file->obj.fd, old_pos, SEEK_SET ); /* restore file pos */
return ret;
} }
static int set_file_time( handle_t handle, time_t access_time, time_t write_time ) static int set_file_time( handle_t handle, time_t access_time, time_t write_time )
@ -604,7 +622,13 @@ DECL_HANDLER(set_file_pointer)
/* truncate (or extend) a file */ /* truncate (or extend) a file */
DECL_HANDLER(truncate_file) DECL_HANDLER(truncate_file)
{ {
truncate_file( req->handle ); struct file *file;
if ((file = get_file_obj( current->process, req->handle, GENERIC_WRITE )))
{
truncate_file( file );
release_object( file );
}
} }
/* flush a file buffers */ /* flush a file buffers */