Logo  

CS471/571 - Operating Systems

Displaying exercises/e6/solution/fcat.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "fs.h"

char bdata[BSIZE];

int findino(char **paths, int index, int ino);
char *readfile(int ino, int *size);
int readino(int ino, struct dinode *di);
int lread(int bpos, void *buf, int size);

struct superblock sb;
int fsfd;

int main(int argc, char *argv[])
{
  int size, i = 0;
  if (argc < 3) {
    printf("Usage:fcat <image> <file>\n");
    return 1;
  }
  if ((fsfd = open(argv[1], O_RDWR)) < 0) {
    perror(argv[1]);
    exit(1);
  }
  char *path = argv[2], *paths[10], *s;

  if (lread(1 * BSIZE, &sb, sizeof(sb)) != sizeof(sb)) return 1;
  
  if (strchr(path, '/') != NULL) {
    for(s=strtok(path, "/"); s; s=strtok(NULL, "/"))
      paths[i++] = s;
  } else paths[i++] = path;
  paths[i] = NULL;

  int ino = findino(paths, 0, 1);
  if (ino <= 0) {
    printf("File not found\n");
    return 1;
  }

//  fprintf(stderr,"Reading inode %d\n", ino);
  char *data = readfile(ino, &size);
  for(int i=0; i < size; i++)
    putchar(data[i]);

  return 0;
}

// struct dirent {
//   ushort inum;
//   char name[DIRSIZ];
// };

int findino(char **paths, int index, int ino)
{
  int size;
  struct dirent *de = (struct dirent *)readfile(ino, &size);
  
  for(int dp=0; dp < size; de++, dp += sizeof(struct dirent)) {
    if (de->inum == 0) continue;
    if (strcmp(de->name, paths[index]) == 0) {
      if (paths[index+1] != NULL) return findino(paths, index+1, de->inum);
      return de->inum;
    }
  }
  return -1;
}

int readino(int ino, struct dinode *di)
{
  int inoloc = (sb.inodestart*BSIZE)+(ino*sizeof(struct dinode));
  if (lseek(fsfd, inoloc, SEEK_SET) != inoloc) {
    perror("lseek");
    return -1;
  }
  return read(fsfd, di, sizeof(struct dinode));
}

char *readfile(int ino, int *size)
{
  struct dinode di;
  char buf[BSIZE];
  uint indirect[NINDIRECT];

  readino(ino, &di);
  if (di.nlink == 0) return NULL;

  int sz = di.size, rd = 0;
  int blks = sz/BSIZE, blk = 0, db;

  char *data = malloc(di.size);

  if (blks >= NDIRECT) lread(di.addrs[NDIRECT] * BSIZE, indirect, BSIZE);

  for(blk = 0; sz > 0; blk++) {
    if (blk < NDIRECT) db = di.addrs[blk];
    else db = indirect[blk-NDIRECT];

    int mx = sz < BSIZE? sz: BSIZE;
    lread(db * BSIZE, data+rd, mx);

    rd += mx;
    sz -= mx;
  }

  *size = rd;
  return data;
}

int lread(int bpos, void *buf, int size)
{
  int n;
  if (lseek(fsfd, bpos, SEEK_SET) != bpos) {
    perror("lseek");
    return -1;
  }
  if ( (n = read(fsfd, buf, size)) < 0) {
    perror("read");
    return -1;
  }
  return n;
}