
/* List a directory of a UCSD volume */
/* Copyright 1994 Syndesis Corporation, by John Foust <jfoust@threedee.com> */
/* July 12, 1990 */

#include <stdio.h>
#include <string.h>

#include "diskdecl.h"

#include "ucsddecl.h"
#define PRIMARY
#include "ucsdvars.h"


/* An array of file descriptors */

ucsdDirEntry dir[ UCSD_MAX_DIR_ENTRIES ];     /* 77 * 26 bytes = 2002 */


/* Print a directory of this disk image */

int main( int argc, char **argv )
{
USHORT lerr;
short each;
short freespace;
char inname[128];
FILE *infp;
ucsdDirRoot dirRoot;
ucsdDirEntry *eachEntry;
long filesize;
long actualBytes;
short totalUsed;


    infp = NULL;

    if (argc == 2) {
        strcpy( inname, argv[1] );
    }
    else {
        puts( "Lists directories of UCSD disk image files" );
        puts( "Usage: td imagefilename" );
        goto out;
    }

    /* Open input file from command line */
    printf( "\nDirectory of UCSD disk image file '%s'\n\n", inname );
    infp = fopen( inname, "rb" );
    if (infp == NULL) {
        puts("Couldn't open file.");
        goto out;
    }

    /* Check size of disk image */
    {
    long odd;
    long blocks;

    fseek( infp, 0, 2 );
    filesize = ftell( infp );
    fseek( infp, 0, 0 );

    /* Check if a natural UCSD disk size */
    odd = filesize % UCSD_BLK_SIZE;
    blocks = filesize / UCSD_BLK_SIZE;

    if (odd != 0) {
        printf( "Error: File size is not modulo block size, odd %ld\n", odd );
    }

    /* Double-sided, Double-density (2280 blocks) */
    if (filesize == 1167360 && odd == 0 && blocks == 2280) {
        printf( "DSDD" );
    }
    /* Single-sided, Double-density (1140 blocks) */
    else if (filesize == 583680 && odd == 0 && blocks == 1140) {
        printf( "SSDD" );
    }
    /* Single-sided, Single-density (494 blocks) */
    else if (filesize == 252928 && odd == 0 && blocks == 494) {
        printf( "SSSD" );
    }
    /* USUS .svol (1600 blocks) */
    else if (filesize == 819200 && odd == 0 && blocks == 1600) {
        printf( "large SVOL" );
    }
    /* USUS .svol (495 blocks) */
    else if (filesize == 253440 && odd == 0 && blocks == 495) {
        printf( "small SVOL" );
    }
    else {
        printf( "Unknown density," );
    }
    printf( " disk image size %ld, %ld blocks of %d bytes each\n", 
        filesize,  blocks, UCSD_BLK_SIZE );
    }

    /* Read volume info */
    if ((lerr=ucsdReadVolInfo( infp, &dirRoot )) != TE_NOERROR) {
        puts( "Failed on volume info." );
        goto out;
    }

    /* Read file directory info */
    if ((lerr=ucsdReadFileInfo( infp, dir )) != TE_NOERROR) {
        puts( "Failed on file info." );
        goto out;
    }

    /* Calculate free space on volume */
    freespace = ucsdCalcFreeSpace( &dirRoot, dir );

    /* Print volume info header */
    if ((lerr=ucsdPrintVolInfo( &dirRoot, freespace )) != TE_NOERROR) {
        goto out;
    }

    /* Print each entry */
    totalUsed = 0;
    eachEntry = dir;
    for (each=0; each<dirRoot.numFiles; each++) {

        /* Convert each filename from Pascal string to C string */
        unPascalStr( &eachEntry->fileName[0] );

        /* Print info */
        printf( "%2hd:", each+1 );
        printf( " %-15s", eachEntry->fileName );
        printf( " %s", ucsdTypeStr( eachEntry->fileKind ) );
        printf( " %2d-%3s-%2d", 
                ucsdDAY(eachEntry->lastAccess),
                ucsdMonthStr( (short) (ucsdMONTH(eachEntry->lastAccess)) ),
                ucsdYEAR( eachEntry->lastAccess) );

        /* Running total of blocks used */
        totalUsed += (eachEntry->lastBlk - eachEntry->firstBlk);

        /* Range and count of blocks consumed by file */
        printf( " %4d-%4d(%4d),", 
            eachEntry->firstBlk, eachEntry->lastBlk, 
            (eachEntry->lastBlk - eachEntry->firstBlk) );

        /* Block bytes plus bytes in last block */
        printf( " %5d+%3d=", 
            (eachEntry->lastBlk - eachEntry->firstBlk) * UCSD_BLK_SIZE, eachEntry->lastByte );

        /* Actual number of bytes in file */
        actualBytes = (eachEntry->lastBlk - eachEntry->firstBlk) * UCSD_BLK_SIZE + eachEntry->lastByte;
        printf( " %5d bytes\n", actualBytes );

        eachEntry ++;
    }

out:
    if (infp != NULL) {
        fclose( infp );
        infp = NULL;
    }

    return 0;
}


/* Improvements:
DOS and ls -l style output,
sort entries by date/size/filename,
add precise byte count of files,
add CRC of files for quick-comparing whether files are same,
ignore standard system files,
function to display which files are missing from disk image
in case it was truncated

Could merge this with the RT-11 reader, and simply
convert the filesystem entries to a common format struct,
and then all the other utility functions could operate
on the same data.

Has bugs on disks like Plocher "util" disk, where last file
isn't properly converted to a text file?

Also fails when accidentally give TD a RT-11 volume instead.
Merging should auto-detect which disk type is here.

from recover.text:
DUPLICATE DIRECTORIES: Disks should, in general, always have a duplicate
directory.  You can tell if this exists by looking at an extended directory
listing.  The first file of such a disk will start on block 10, otherwise it
will start at block 6.  If your disk does not have a duplicate, and you would
like to add this, you can do so by executing MARKDUPDIR. You must first make
sure that blocks 6-9 on the disk are free (e.g. by transferring the first file
on the disk out of the way).

  Need to handle disk images that contain logical or physical images,
as well as Anadisk-style eight-char header sectors.

  Need to rewrite all disk access as low-level functions that
handle these three modes of disk image.  Write a tool that translates
between them, turning logical to physical, or logical to Anadisk.
*/

