#include #include #include #include #include #include #include #include #include #include #include "types_protect.h" #include "types.h" #include "filsys.h" #include "ino.h" #include "disc_hdr.h" #include "dir.h" inline uint32_t get24(unsigned char *p) { return (p[0] << 16) | (p[1] << 8) | p[2]; } inline long offset_from_inode(int inn) { return (itod(inn) * BSIZE) + (sizeof(struct dinode) * itoo(inn)); } inline struct dinode *getinode(unsigned char *img, int inn) { return (struct dinode *)(img + offset_from_inode(inn)); } inline unsigned char *getblock(unsigned char *img, int bn) { return img + bn * BSIZE; } inline long getinoblockaddr(struct dinode *ino, int an) { return get24((unsigned char *)(ino->di_addr + an*3)); } inline int isdir(struct dinode *ino) { return ntohs(ino->di_mode) & S_IFDIR; } void print_lsl_nopath(unsigned char *img, int inn) { short mode; time_t mtime; struct dinode *ino = getinode(img, inn); int i; if(ino->di_nlink == 0) { return; } mode = ntohs(ino->di_mode); /* fprintf(stderr, "Mode: %o\n", mode); */ printf("%c", (mode&S_IFDIR)?'d':'-'); printf("%c%c%c", ((mode<<0)&S_IREAD)?'r':'-', ((mode<<0)&S_IWRITE)?'w':'-', ((mode<<0)&S_IEXEC)?'x':'-'); printf("%c%c%c", ((mode<<3)&S_IREAD)?'r':'-', ((mode<<3)&S_IWRITE)?'w':'-', ((mode<<3)&S_IEXEC)?'x':'-'); printf("%c%c%c", ((mode<<6)&S_IREAD)?'r':'-', ((mode<<6)&S_IWRITE)?'w':'-', ((mode<<6)&S_IEXEC)?'x':'-'); printf("% 3d", ntohs(ino->di_nlink)); printf("% 8d", ntohs(ino->di_uid)); printf("% 8d", ntohs(ino->di_gid)); printf("% 8d", ntohl(ino->di_size)); mtime = ntohl(ino->di_mtime); printf(" %s ", strtok(ctime(&mtime), "\n")); if(0) { for(i = 0; i < 13; i++) { fprintf(stdout, "%06x, ", getinoblockaddr(ino, i)); } } } void print_lsl(unsigned char *img, int inn) { print_lsl_nopath(img, inn); printf("%d\n", inn); } inline long getnumblocks(unsigned char *img, struct dinode *ino) { int i, nb = 0; if(getinoblockaddr(ino, 11) != 0 || getinoblockaddr(ino, 12) != 0) { fprintf(stderr, "Second-level indirect blocks not handled! Results will be truncated.\n"); } for(i = 0; i < 10; i++) { if(getinoblockaddr(ino, i) == 0) break; nb++; } if(getinoblockaddr(ino, 10) != 0) { unsigned char *block = getblock(img, getinoblockaddr(ino, 10)); for(i = 0; i < BSIZE / 4; i++) { if(*((long *)(block + i*4)) == 0) break; nb++; } } return nb; } inline long getblockaddr(unsigned char *img, struct dinode *ino, int bn) { if(bn < 10) { return getinoblockaddr(ino, bn); } return ntohl(*((long *)(getblock(img, getinoblockaddr(ino, 10)) + (bn - 10)*4))); } inline unsigned char *getdatafrompos(unsigned char *img, struct dinode *ino, int pos) { return getblock(img, getblockaddr(img, ino, (int)(pos / BSIZE))) + (pos % BSIZE); } inline long getnumdirs(struct dinode *ino) { return ntohl(ino->di_size) / sizeof(struct direct); } inline struct direct *getde(unsigned char *img, struct dinode *ino, int dn) { return (struct direct *)getdatafrompos(img, ino, dn * sizeof(struct direct)); } inline void getname(struct direct *de, char *name) { strncpy(name, (char *)de->d_name, DIRSIZ); name[DIRSIZ] = '\0'; } inline short getdino(struct direct *de) { return ntohs(de->d_ino); } void print_dir_debug(unsigned char *img, int inn) { struct dinode *ino = getinode(img, inn); struct direct *de; int numdirs = getnumdirs(ino); int dn; char name[DIRSIZ + 1]; /* fprintf(stderr, "Dir contains %d files, with entries in %d blocks.\n", numdirs, getnumblocks(img, ino)); */ for(dn = 0; dn < numdirs; dn++) { de = getde(img, ino, dn); getname(de, name); fprintf(stdout, "%04d % 4d [%s]\n", getdino(de), strlen(name), name); } } void print_dir_lsl(unsigned char *img, int inn, char *path, long *parents, int depth) { struct dinode *ino = getinode(img, inn); print_lsl_nopath(img, inn); printf("%s (inode %d)\n", path, inn); if(isdir(ino)) { struct direct *de; int dn, parentfound, numdirs = getnumdirs(ino); char *newpath, name[DIRSIZ + 1]; long *newparents; for(dn = 0; dn < numdirs; dn++) { de = getde(img, ino, dn); if(getdino(de) == 0) continue; getname(de, name); newpath=malloc(strlen(path) + strlen(name) + 5); sprintf(newpath, "%s/%s", path, name); newparents = malloc(sizeof(long) * (depth + 1)); if(parents != NULL) memcpy(newparents, parents, sizeof(long) * depth); newparents[depth] = inn; for(parentfound = 0; parentfound <= depth; parentfound++) { if(getdino(de) == newparents[parentfound]) break; } if(parentfound > depth) print_dir_lsl(img, getdino(de), newpath, newparents, depth + 1); free(newpath); free(newparents); } } } long find_file_inode(unsigned char *img, int inn, char *path) { struct dinode *ino = getinode(img, inn); struct direct *de; int numdirs = getnumdirs(ino); int dn; char name[DIRSIZ + 1]; if(!isdir(ino)) { return inn; } for(dn = 0; dn < numdirs; dn++) { char *tok; de = getde(img, ino, dn); getname(de, name); tok = strchr(path, '/'); if(!strncmp(path, name, tok==NULL?strlen(path):(tok-path))) { if(ntohs(de->d_ino) == 0) return -1; return find_file_inode(img, ntohs(de->d_ino), path + strlen(name) + 1); } } return 0; } void print_file(unsigned char *img, int inn) { struct dinode *ino = getinode(img, inn); long size = ntohl(ino->di_size); long numblocks = getnumblocks(img, ino); long bn, pos, left; fprintf(stderr, "Displaying file with inode %d, size %d, using %d blocks.\n", inn, size, numblocks); /* print_lsl(img, inn); */ for(bn = 0; bn < numblocks; bn++) { pos = bn * BSIZE; left = size - pos; /* fprintf(stdout, "\nDisplaying %d bytes from position %d in block %d.\n", left>BSIZE?BSIZE:left, pos, bn); */ fwrite(getdatafrompos(img, ino, pos), 1, left>BSIZE?BSIZE:left, stdout); } printf("\n"); } int main(int argc, char **argv) { int fdin; unsigned char *img; struct stat statbuf; struct filsys *sb; int o, i; int numinodes; int inn; if(argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } if( (fdin = open(argv[1], O_RDONLY)) < 0) { fprintf(stderr, "Can't open image %s for reading.\n", argv[1]); exit(2); } if(fstat(fdin, &statbuf) < 0) { fprintf(stderr, "Can't stat image %s.\n", argv[1]); exit(3); } img = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0); if(img == (void *) -1) { fprintf(stderr, "mmap error. go figure.\n"); exit(4); } sb = (struct filsys *)(img + BSIZE); if(ntohl(sb->s_magic) != FsMAGIC) { fprintf(stderr, "Bad magic! Bad! Bad! Go sit in the corner! Got 0x%08x, wanted 0x%08x.\n", ntohl(sb->s_magic), FsMAGIC); /* exit(5); */ } /* fprintf(stderr, "First data block: %d\n", ntohl(sb->s_isize) ); */ numinodes = (ntohl(sb->s_isize) - 2) * INOPB; /* fprintf(stderr, "Number of inodes: %d\n", numinodes ); */ /* for(inn = 2; inn < numinodes; inn++) { print_lsl(img, inn); } */ inn = atol(argv[2]); if(inn > 0) { /* fprintf(stderr, "Contents of file with inode %d:\n", inn); */ print_file(img, inn); } else if(argv[2][0] != '/') { for(inn = 2; inn < numinodes; inn++) { if(isdir(getinode(img, inn))) { print_lsl(img, inn); print_dir_debug(img, inn); } } print_dir_lsl(img, 2, argv[1], NULL, 0); } else { inn = find_file_inode(img, 2, argv[2] + 1); if(inn == 0) fprintf(stdout, "File %s not found!\n", argv[2]); else if(inn == -1) fprintf(stdout, "File %s was deleted.\n", argv[2]); else fprintf(stdout, "File %s has inode %d.\n", argv[2], inn); } munmap(img, statbuf.st_size); close(fdin); return 0; }