|
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;
}
|