jason@violet.berkeley.edu (/violet_n/jason) (10/30/86)
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; } }