Logo  

CS471/571 - Operating Systems

Displaying exercises/e6/solution/fcp.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 *readlocalfile(char *path, int *size);
int allocblock(void);
int findino(char **paths, int index, int ino);
char *readfile(int ino, int *size);
void writefile(struct dinode *di, char *data);
int readino(int ino, struct dinode *di);
int writeino(int ino, struct dinode *di);
int lread(int bpos, void *buf, int size);
int lwrite(int bpos, void *buf, int size);

int fsfd;
struct superblock sb;
char bmap[BSIZE];
int indirect[NINDIRECT];

int main(int argc, char *argv[])
{
  char *paths[10];
  int dirino, ino, size, dirsize, i = 0;
  if (argc < 3) {
    printf("Usage:fcp <image> <local file> [<dest dir>]\n");
    return 1;
  }
  if ((fsfd = open(argv[1], O_RDWR)) < 0) {
    perror(argv[1]);
    return 1;
  }

//  printf("Reading localfile...\n");
  char *data = readlocalfile(argv[2], &size);
  if (data == NULL) return 1;

//  printf("Reading superblock and block bitmap...\n");
  if (lread(1 * BSIZE, &sb, sizeof(sb)) != sizeof(sb)) return 1;
  if (lread(sb.bmapstart * BSIZE, bmap, BSIZE) != BSIZE) return 1;

  if (argc > 3) {
    char *path = argv[3], *s;
    if (strchr(path, '/') != NULL) {
      for(s=strtok(path, "/"); s; s=strtok(NULL, "/"))
	paths[i++] = s;
    } else paths[i++] = path;
    paths[i] = NULL;
    dirino = findino(paths, 0, 1);
    if (dirino <= 0) {
      printf("Directory not found.\n");
      return 1;
    }
  } else dirino = 1;

//  printf("Inserting file into directory inode %d...\n", dirino);

  struct dinode di, diri;
  readino(dirino, &diri);
  char *dirdata = readfile(dirino, &dirsize);

  struct dirent *de = (struct dirent *)dirdata;
  while(de->inum != 0) de++;
  strncpy(de->name, argv[2], DIRSIZ-1);

  for(ino = 2; ino < sb.ninodes; ino++) {
    readino(ino, &di);
    if (di.nlink == 0) break;
  }
  de->inum = ino;

  memset(&di, 0, sizeof(di));
  di.type  = 2; // FILE
  di.size  = size;
  di.nlink = 1;
  di.major = di.minor = 0;

  memset(indirect, 0, sizeof(indirect));
  for(int blkno = 0, wr = 0; wr < size; blkno++, wr += BSIZE) {
    int baddr = allocblock();
    if (blkno >= NDIRECT) {
      if (blkno == NDIRECT) {
	di.addrs[NDIRECT] = baddr;
	baddr = allocblock();
      }
      indirect[blkno-NDIRECT] = baddr;
    } else di.addrs[blkno] = baddr;
  }

//  printf("Writing out data...\n");
  writeino(ino, &di);

//  printf("Writing file...\n");
  writefile(&di, data);

//  printf("Updating directory file...\n");
  writefile(&diri, dirdata);

//  printf("Updating block bitmap...\n");
  lwrite(sb.bmapstart * BSIZE, bmap, BSIZE);

  return 0;
}


int allocblock(void)
{
  static int low = 0;

  while (low < sb.size) {
    int inuse = bmap[low>>3] & (1<<(low&7))? 1 : 0;
    if (!inuse) {
      bmap[low>>3] |= (1<<(low&7));
      return low;
    }
    low++;
  }
  printf("Not enough room for file!\n");
  exit(1);
}


char *readlocalfile(char *path, int *size)
{
  int fd = open(path, O_RDONLY);
  if (fd < 0) {
    perror("readlocalfile");
    return NULL;
  }
  struct stat st;
  fstat(fd, &st);

  char *data = malloc((*size = st.st_size)+1);
  int n = read(fd, data, st.st_size);
  if (n != st.st_size) {
    printf("Read %d, expected %d\n", n, st.st_size);
  }
  close(fd);

  return data;
}

// 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));
  return lread(inoloc, di, sizeof(struct dinode));
}

int writeino(int ino, struct dinode *di)
{
  int inoloc = (sb.inodestart*BSIZE)+(ino*sizeof(struct dinode));
  return lwrite(inoloc, 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;
}

void writefile(struct dinode *di, char *data)
{
  int wr = 0, sz = di->size, blk = 0, db;

  if (di->addrs[NDIRECT]) lwrite(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;
    lwrite(db * BSIZE, data+wr, mx);

    wr += mx;
    sz -= mx;
  }
}

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

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