AUSAM/source/libc/tdu.c
#
/*
** Tdu calculates total disk usage (inodes and blocks) for the given directory
**
** the total number of files is available in the global "t_files"
** and likewise the total number of blocks in "t_blocks"
*/
#include <local-system>
#include <passwd.h>
#include <stat16.h>
struct statbuf __statb;
extern errno;
int __derror;
long _tdu();
long _malformed();
char *_nextpath();
unsigned _size();
long t_blocks;
long t_files;
char __pathname[200];
#define PATHEND (&__pathname[sizeof __pathname])
struct { int hiword; unsigned loword; };
tdu( dir )
register char *dir; /** pointer to directory to be totalled **/
{
int parino;
/*
** get inode of parent directory of "dir" (N.B. ".." is not good enough)
*/
{
register char *dp, *np;
char dbuf[SSIZ];
if ( (np = dir) == 0 || *np == 0 )
np = "/";
for ( dp = dbuf ; *dp++ = *np++ ; )
if ( dp >= &dbuf[SSIZ] )
{
printf( "%s: too long!\n", dir );
return( -1 );
}
while ( *--dp != '/' )
if ( dp <= dbuf )
{
printf( "Bad directory path: %s\n", dir );
return( -1 );
}
if ( dp == dbuf ) /* root! */
dp++;
*dp = 0;
if ( newstat( dbuf, &__statb ) < 0 )
{
printf( "Parent directory: " );
perror( dbuf );
return( -1 );
}
parino = __statb.sb_inumber;
}
/*
** move over to the user's home directory
*/
if ( newstat( dir , &__statb ) < 0 || chdir(dir) < 0 )
{
perror( dir );
return( -1 );
}
__derror = 0;
errno = 0;
t_blocks = 0;
t_files = 0;
return( _tdu( _nextpath( __pathname, dir ), parino ) >> 16 ); /* N.B. __statb set up above */
}
#define ERROR 0XFFFFFFFFL
struct
{
int f_ino;
char f_name[14];
char f_end;
}
__dirbuf;
/*
** "tdu" returns the disc usage of the current directory
** and all sub-directories.
** Inodes are weighted at IWEIGHT blocks.
** Links are shared equally.
*/
long _tdu( pathend, parino )
char *pathend;
unsigned parino;
{
register fd, i, posn;
long inodes, blocks, t;
unsigned dino;
if ( pathend == 0 )
return( ERROR );
dino = __statb.sb_inumber;
inodes = 0X10000;
t_files =+ 0X10000;
blocks.loword = 0;
blocks.hiword = _size();
t_blocks =+ blocks;
posn = 0;
__dirbuf.f_end = '\0';
loop:
if ( ((fd = open( __pathname , 0)) >= 0) && (seek( fd , posn , 0) >= 0) )
{
while ( (i = read( fd , &__dirbuf , 16 )) == 16 )
{
posn =+ i;
if ( __dirbuf.f_ino )
if ( newstat( __dirbuf.f_name , &__statb ) >= 0 )
{
if ( (__statb.sb_flags & IFTYP) == IFDIR )
{
if ( __statb.sb_inumber != dino && __statb.sb_inumber != parino )
{
if ( _dots() )
return( _malformed( "separate directory!" ) );
if ( posn <= 32 )
return( _malformed( "\".\" or \"..\" displaced!" ) );
if ( chdir( __dirbuf.f_name ) >= 0 )
{
close( fd );
blocks =+ _tdu( _nextpath( pathend, __dirbuf.f_name ), dino );
*pathend = 0;
chdir( __pathname );
if ( __derror )
return( ERROR );
goto loop;
}
else
return( _malformed() );
}
else
if ( posn > 32 )
return( _malformed( "link displaced" ) );
else
if ( !_dots() )
return( _malformed( "\".\" or \"..\" renamed!" ) );
}
else
{
/* fixed point arithmetic */
t = (0X10000 / (__statb.sb_nlinks&0377));
t_files =+ t;
inodes =+ t;
t = ((0X10000 * _size()) / (__statb.sb_nlinks&0377));
t_blocks =+ t;
blocks =+ t;
}
}
else
return( _malformed() );
}
close( fd );
if ( i )
return( _malformed( "bad length" ) );
return( blocks + inodes*IWEIGHT );
}
else
{
__dirbuf.f_name[0] = 0;
return( _malformed() );
}
}
unsigned _size()
{
register unsigned b, ib;
b = ((__statb.sb_size0 & 0377) << 7) + (((__statb.sb_size1 + 0777) >> 9) & 0177);
if ( ib = b>>3 )
{
b++;
if ( ib =>> 5 )
{
b =+ ib; /* indirect */
if ( ib > 8 )
b++; /* double indirect */
}
}
return( b );
}
long _malformed( s )
char *s;
{
extern errno;
putchar( '\n' );
printf( "MALFORMED DIRECTORY in %s\n\t", __pathname );
if ( errno )
perror( __dirbuf.f_name );
else
printf( "%s: %s\n", __dirbuf.f_name, s );
__derror++;
return( ERROR );
}
_dots()
{
register char *sp = __dirbuf.f_name;
if ( *sp++ == '.'
&& ( *sp == '\0'
|| ( *sp++ == '.' && *sp == '\0' )
)
)
return( 1 );
return( 0 );
}
char *_nextpath( at, name )
register char *at, *name;
{
if ( *name != '/' )
*at++ = '/';
do
if ( at >= PATHEND )
{
__derror++;
return( 0 );
}
while
( *at++ = *name++ );
return( --at );
}