
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#define FILE_NAME  "thedisk"

struct Superblock {
   int initialized ;
   int fat_base ;
   int fat_entries ;
   int root_dir_base ;
   int root_dir_entries ;
} ;

#define DIR_TYPE_EMPTY 0
#define DIR_TYPE_FILE 1

struct Dirent {
    char name[8] ;
    char ext[3] ;
    char type ; 
    int length ;
} ;

int fh ;
struct Superblock sb ;

void printSuperblock( struct Superblock * sbp ) {
   printf("%d %d %d %d %d\n", sbp->initialized,
    sbp->fat_base, sbp->fat_entries, sbp->root_dir_base,
    sbp->root_dir_entries ) ;
}

void superblockInitialize( struct Superblock * sbp ) {
    sbp->initialized = 1 ;
    sbp->fat_base = 256 ;
    sbp->fat_entries = 1024 ;
    sbp->root_dir_base = 4352 ;
    sbp->root_dir_entries = 128 ;
}

void getRootdirEntry( int entrynumber, struct Dirent * de ) {
/* read the root directory entry entrynumber into the buffer de */
    int loc ;
    loc = sb.root_dir_base + sizeof(struct Dirent) * entrynumber ;
    lseek( fh, loc, SEEK_SET ) ;
    read( fh, de, sizeof(struct Dirent) ) ;
}

void setRootdirEntry( int entrynumber, struct Dirent * de ) {
/* read the root directory entry entrynumber into the buffer de */
    int loc ;
    loc = sb.root_dir_base + sizeof(struct Dirent) * entrynumber ;
    lseek( fh, loc, SEEK_SET ) ;
    write( fh, de, sizeof(struct Dirent) ) ;
}

void listRootDir() {
    int i ;
    int j ;
    struct Dirent de ;
    for ( i=0; i<sb.root_dir_entries; i++ ) {
        getRootdirEntry( i, &de ) ;
          if (de.type) {
            j = 0 ;
            while ( j<8 && de.name[j] ) { printf("%c",de.name[j]) ; j++; }
            printf(".") ;
            j = 0 ;
            while ( j<3 && de.ext[j] ) { printf("%c",de.ext[j]) ; j++; }
            printf(" length: %d\n", de.length ) ;
          }
    }
}

int findEmptyRootDirent() {
    int i ;
    struct Dirent de ;
    for (i=0;i<sb.root_dir_entries;i++) {
        getRootdirEntry(i,&de) ;
        if ( !de.type ) return i ;
    }
    return -1 ;
}

void makeDirent( char * name ) {
    int i ;
    struct Dirent de ;

    for ( i=0; i<8; i++ ) de.name[i] = '\0' ;
    i = 0 ;
    while ( *name ) {
       if ( i>=8 ) break ;
       if ( *name=='.' ) break ;
       de.name[i++] = *name ;
       name++ ;
    }
    for ( i=0; i<3; i++ ) de.ext[i] = '\0' ;

    de.length = 0 ;
    de.type = DIR_TYPE_FILE ;
    /* find an empty slot */
    i = findEmptyRootDirent() ;
    setRootdirEntry( i, &de ) ;
}

int main(int argc, char * argv[]) {
   
   int err ;

   /* open the pseudo-disk */
   fh = open(FILE_NAME,O_RDWR) ;
   /* seek to the superblock location */
   lseek( fh, 0, SEEK_SET ) ;
   /* read in the superblock */
   read( fh, &sb, sizeof(struct Superblock) ) ;
   printSuperblock( &sb ) ;
   
   if ( !sb.initialized ) {
       superblockInitialize( &sb ) ;
       lseek( fh, 0, SEEK_SET ) ;
       err = write( fh, &sb, sizeof(struct Superblock) ) ;
       if ( err ) {
           perror("") ;
           exit(0) ;
       }
   }

   printSuperblock( &sb ) ;
   makeDirent("hello") ;
   listRootDir() ;

}



