A file truncate routine (looks like the 4.x, x>=2 BSD truncate system call)
/violet_n/jason
jason at violet.berkeley.edu
Thu Oct 30 12:02:34 AEST 1986
This is a simple routine to mimic the 4.x truncate system call.
The differences are:
1: You need file size + truncate to size free on the device the file resizes on.
2: you need to have the same euid and egid as the file to truncate (it could be smarter)
3: crashes would leave artifacts around (a tmp file)
4: worst case crash--- you could be left with only the tmpfile [with all the data you want in it].
4.a: This is a bit shaky, as it would have just finished writing into this file, and it is probably not sync'd yet.
---cut here---
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
main( argc, argv )
int argc;
char **argv;
{
extern int errno;
if( argc < 3 ) {
fprintf( stderr, "Usage:%s file size [file size [file size...]]\n", argv[0] );
exit( 1 );
}
for( argc--, argv++; argc > 1; argc-=2, argv+=2 ) {
errno = 0;
if( truncate( argv[0], atoi( argv[1] )) == -1 ) {
fprintf( stderr, "file %s %d truncate failed\n", argv[0], atoi( argv[1] ) );
if( errno ) {
perror("" );
}
}
}
exit( 0 );
}
#define TMPNAME "tmpXXXXXX"
truncate( name, size )
char *name;
int size;
{
char* mktemp();
char* rindex();
char* malloc();
char *Myname; /* Temp file name */
char *slash; /* Where the last '/' is in Myname */
FILE* fopen();
FILE* fdopen();
FILE *InFd;
FILE *OutFd;
int RawFd;
int c;
char IoBuf[BUFSIZ];
struct stat StatBuf;
if( stat( name, &StatBuf ) == -1 ) {
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "stat of %s failed\n", name );
#endif /* TRUNC_DEBUG */
return -1;
}
if( StatBuf.st_size <= size ) {
return 1;
}
if( StatBuf.st_uid != geteuid() || StatBuf.st_gid != getegid() ) {
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
if( StatBuf.st_uid != geteuid() ) {
fprintf( stderr, "file uid %d, euid %d\n", StatBuf.st_uid, geteuid() );
}
if( StatBuf.st_gid != getegid() ) {
fprintf( stderr, "file gid %d, egid %d\n", StatBuf.st_gid, getegid() );
}
#endif /* TRUNC_DEBUG */
return -1;
}
if( !(Myname = malloc( strlen(name) + 1 + strlen( TMPNAME ) )) ) {
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "malloc failed" );
#endif /* TRUNC_DEBUG */
return -1;
}
(void) strcpy( Myname, name );
slash = rindex( Myname, '/' );
if( *slash && *(slash+1) ) {
(void) strcpy( (slash+1), mktemp( TMPNAME ));
} else {
(void) strcpy( Myname, mktemp( TMPNAME )); /* Not a path, just a file name */
}
if( (RawFd = creat( Myname, (StatBuf.st_mode & (~S_IFMT)))) == -1 ) {
(void) free( Myname );
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "creat on %s failed", Myname );
#endif /* TRUNC_DEBUG */
return -1;
}
if( !(OutFd = fdopen( RawFd, "w" )) ) {
(void) free( Myname );
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "fdopen failed" );
#endif /* TRUNC_DEBUG */
return -1;
}
if( !(InFd = fopen( name, "r" )) ) {
(void) free( Myname );
(void) fclose( OutFd );
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "fopen of %s failed\n", name );
#endif /* TRUNC_DEBUG */
return -1;
}
for( ; size> 0 && (c = fgetc(InFd)) != EOF && ! ferror( InFd ) && ! ferror( OutFd ); size-- ) {
(void) fputc( c, OutFd );
}
(void) fclose( InFd );
(void) fclose( OutFd );
if( size != 0 && !feof( InFd ) ) {
(void) unlink( Myname );
(void) free( Myname );
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "size is %d\n", size );
#endif /* TRUNC_DEBUG */
return -1;
} else {
if( unlink( name ) == -1 ) {
(void) unlink( Myname );
(void) free( Myname );
#ifdef TRUNC_DEBUG /* TRUNC_DEBUG */
fprintf( stderr, "unlink of %s failed\n", name );
#endif /* TRUNC_DEBUG */
return -1;
}
if( rename( Myname, name ) == -1 ) {
(void) free( Myname );
#ifdef TRUNC_DEBUG
fprintf( stderr, "rename of %s to %s failed\n", Myname, name );
#endif /* TRUNC_DEBUG */
return -1;
}
return 0;
}
}
More information about the Comp.sources.unix
mailing list