#include #include #include #include #include #include #include #include #include #include #if !defined(SBLOCKSIZE) && defined(SBSIZE) #define SBLOCKSIZE SBSIZE #define ufs1_dinode dinode #define SBLOCK_UFS1 8192 #define FS_UFS1_MAGIC FS_MAGIC #endif #include "strnlen.h" extern const char *__progname; typedef unsigned long long int ULLI; static int fd; static int ino; static int bflag = 0; static int dflag = 0; static int Dflag = 0; static int fflag = 0; static int pflag = 0; static char sbbuf[SBLOCKSIZE] __attribute__((__aligned__(__alignof__(struct fs)))); #define sb ((struct fs *)&sbbuf[0]) static char *inobuf; static struct ufs1_dinode *di; static char *fileblk; static char *indirblk1; static char *indirblk2; static char *indirblk3; static char **indirblks[3] = { &indirblk1, &indirblk2, &indirblk3 }; static int oindent; static int ocol; static off_t printdbno(struct ufs1_dinode *di, ULLI bn, off_t o) { char *t; int n; int ws; n = asprintf(&t,"%llu",pflag?fsbtodb(sb,bn):bn); if (n+ocol > 72) { printf("\n"); ocol = 0; } ws = ocol ? 1 : oindent; printf("%*s%s",ws,"",t); free(t); ocol += ws + n; return(sblksize(sb,di->di_size,lblkno(sb,o))); } static void newline(void) { if (ocol) { printf("\n"); ocol = 0; } } static off_t blkseek(int fd, unsigned long int blkno) { #ifdef LB_SET if (blkno > (0x7fffffff/DEV_BSIZE)) { return(lseek(fd,blkno,LB_SET)); } else #else { return(lseek(fd,512*(off_t)blkno,L_SET)); } #endif } static void readblock(ULLI bn, char *buf) { int i; if (blkseek(fd,fsbtodb(sb,bn)) < 0) { fprintf(stderr,"seek to block %llu: %s\n",bn,strerror(errno)); exit(1); } errno = 0; i = read(fd,buf,sb->fs_bsize); if (i < 0) { fprintf(stderr,"can't read block %llu: %s\n",bn,strerror(errno)); exit(1); } else if (i != sb->fs_bsize) { fprintf(stderr,"warning: reading block %llu: short read (wanted %d, got %d)\n", bn,sb->fs_bsize,i); bzero(buf+i,sb->fs_bsize-i); } } static off_t printibno(struct ufs1_dinode *di, ULLI bn, off_t o, int lev) { int i; off_t j; off_t tot; if (lev < 0) return(printdbno(di,bn,o)); if (bn == 0) bzero(*indirblks[lev],sb->fs_bsize); else readblock(bn,*indirblks[lev]); tot = 0; newline(); printf("%*s%llu=(\n",oindent,"",pflag?fsbtodb(sb,bn):bn); oindent += 4; for (i=0;i= di->di_size) break; j = printibno(di,((u_int32_t *)*indirblks[lev])[i],o,lev-1); o += j; tot += j; } oindent -= 4; newline(); printf("%*s)\n",oindent,""); return(tot); } static void printblknos(struct ufs1_dinode *di) { int i; int j; off_t o; printf("data blocks:\n"); oindent = 2; ocol = 0; o = 0; j = 0; for (i=0;i= di->di_size) goto out; o += printdbno(di,di->di_db[i],o); } newline(); for (i=0;i= di->di_size) goto out; o += printibno(di,di->di_ib[i],o,i); } out:; printf("\n"); } static off_t dumpblk(struct ufs1_dinode *di, int bn, off_t o) { int sz; if (bn == 0) bzero(&fileblk[0],sizeof(fileblk)); else readblock(bn,&fileblk[0]); sz = sblksize(sb,di->di_size,lblkno(sb,o)); if (o >= di->di_size) return(0); if (di->di_size-o < sz) sz = di->di_size - o; if (sz < 0) sz = 0; write(fileno(stdout),&fileblk[0],sz); return(sz); } static off_t dumpiblk(struct ufs1_dinode *di, int bn, off_t o, int lev) { int i; off_t j; off_t tot; if (lev < 0) return(dumpblk(di,bn,o)); if (bn == 0) bzero(*indirblks[lev],sb->fs_bsize); else readblock(bn,*indirblks[lev]); tot = 0; for (i=0;idi_db[i],o); if (j == 0) return; o += j; } for (i=0;idi_ib[i],o,i); if (j == 0) return; o += j; } } static void dumplink(struct ufs1_dinode *di) { if (di->di_size <= (NDADDR+NIADDR)*sizeof(u_int32_t)) { int len; len = strnlen((char *)&di->di_db[0],(NDADDR+NIADDR)*sizeof(u_int32_t)); if (len == di->di_size) { if (len > 0) printf("%.*s",len,(char *)&di->di_db[0]); return; } } dumpdata(di); } static off_t dumpdirblk(struct ufs1_dinode *di, int bn, off_t o) { int sz; char *p; char *e; struct direct *d; int i; if (bn == 0) bzero(&fileblk[0],sizeof(fileblk)); else readblock(bn,&fileblk[0]); sz = sblksize(sb,di->di_size,lblkno(sb,o)); if (o >= di->di_size) return(0); if (di->di_size-o < sz) sz = di->di_size - o; p = &fileblk[0]; e = &fileblk[sz]; while (p < e) { if (e-p < 9) { printf("[%d unclaimed byte%s]\n",(int)(e-p),(e-p==1)?"":"s"); p = e; continue; } d = (struct direct *) p; if (d->d_reclen < DIRSIZ(NEWDIRFMT,d,0)) { printf("[entry requires %d bytes, but claims only %d]\n",(int)DIRSIZ(NEWDIRFMT,d,0),d->d_reclen); p = e; continue; } if (e-p < d->d_reclen) { printf("[entry claims %d (%d) bytes, but only %d remain]\n",(int)DIRSIZ(NEWDIRFMT,d,0),d->d_reclen,(int)(e-p)); p = e; continue; } for (i=0;(i<=d->d_namlen)&&d->d_name[i];i++) ; if (d->d_name[i]) { printf("[missing null terminator: inode %d name %.*s...]\n",d->d_ino,d->d_namlen,&d->d_name[0]); p = e; continue; } printf("%7d %7d %s\n",d->d_reclen,d->d_ino,&d->d_name[0]); p += d->d_reclen; } return(sz); } static off_t dumpidirblk(struct ufs1_dinode *di, int bn, off_t o, int lev) { int i; off_t j; off_t tot; if (lev < 0) return(dumpdirblk(di,bn,o)); if (bn == 0) bzero(*indirblks[lev],sb->fs_bsize); else readblock(bn,*indirblks[lev]); tot = 0; for (i=0;idi_db[i],o); if (j == 0) return; o += j; } for (i=0;idi_ib[i],o,i); if (j == 0) return; o += j; } } static void allocbufs(void) { inobuf = malloc(sb->fs_bsize); fileblk = malloc(sb->fs_bsize); indirblk1 = malloc(sb->fs_bsize); indirblk2 = malloc(sb->fs_bsize); indirblk3 = malloc(sb->fs_bsize); } int main(int, char **); int main(int ac, char **av) { int i; while (ac > 1) { ac --; av ++; if (!strcmp(av[0],"-b")) { bflag = 1; continue; } if (!strcmp(av[0],"-d")) { dflag = 1; continue; } if (!strcmp(av[0],"-D")) { Dflag = 1; continue; } if (!strcmp(av[0],"-f")) { fflag = 1; continue; } if (!strcmp(av[0],"-p")) { pflag = 1; continue; } break; } if (ac != 2) { fprintf(stderr,"Usage: %s filesystem inumber\n",__progname); exit(1); } fd = open(av[0],O_RDONLY,0); if (fd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,av[0],strerror(errno)); exit(1); } ino = atoi(av[1]); if (ino < 1) exit(1); if (blkseek(fd,SBLOCK_UFS1>>9) < 0) { fprintf(stderr,"%s: sb seek: %s\n",__progname,strerror(errno)); exit(1); } if (read(fd,&sbbuf[0],SBLOCKSIZE) != SBLOCKSIZE) { printf("%s: can't read sblock\n",av[1]); exit(1); } if (sb->fs_magic != FS_UFS1_MAGIC) { printf("%s: bad magic number\n",av[1]); exit(1); } allocbufs(); if (blkseek(fd,fsbtodb(sb,ino_to_fsba(sb,ino))) < 0) { fprintf(stderr,"%s: ino seek: %s\n",__progname,strerror(errno)); exit(1); } errno = 0; if (read(fd,(char *)&inobuf[0],sb->fs_bsize) != sb->fs_bsize) { if (errno) { fprintf(stderr,"%s: ino read: %s\n",__progname,strerror(errno)); } else { fprintf(stderr,"%s: short ino read\n",__progname); } exit(1); } di = (struct ufs1_dinode *)&inobuf[ino_to_fsbo(sb,ino)*sizeof(struct ufs1_dinode)]; if (! dflag) { printf("ino %d in %s\n",ino,av[0]); printf(" mode 0%06o\n",(int)di->di_mode); printf(" nlink %d\n",(int)di->di_nlink); printf(" uid %d\n",(int)di->di_uid); printf(" gid %d\n",(int)di->di_gid); printf(" size %d\n",(int)di->di_size); printf(" atime %lu = %.24s\n",(unsigned long int)di->di_atime,ctime((void *)&di->di_atime)); printf(" mtime %lu = %.24s\n",(unsigned long int)di->di_mtime,ctime((void *)&di->di_mtime)); printf(" ctime %lu = %.24s\n",(unsigned long int)di->di_ctime,ctime((void *)&di->di_ctime)); printf(" db"); for (i=0;idi_db[i]); } printf("\n"); printf(" ib"); for (i=0;idi_ib[i]); } printf("\n"); printf(" blocks %u\n",(unsigned int)di->di_blocks); printf(" gen %u\n",(unsigned int)di->di_gen); } if (bflag) { switch (di->di_mode&IFMT) { case IFREG: case IFLNK: case IFDIR: printblknos(di); break; case IFSOCK: case IFCHR: case IFBLK: printf("no data blocks\n"); break; default: if (! dflag) printf("UNKNOWN TYPE\n"); break; } } else { switch (di->di_mode&IFMT) { case IFREG: if (! dflag) printf("DATA\n"); if (! Dflag) dumpdata(di); break; case IFLNK: if (! dflag) printf("SYMBOLIC LINK"); if (! Dflag) { if (fflag) { printf("\n"); dumplink(di); } else { printf(" TO "); dumplink(di); printf("\n"); } } else { printf("\n"); } break; case IFDIR: if (! dflag) printf("DIRECTORY\n"); if (! Dflag) { if (fflag) { dumpdata(di); } else { dumpdirdata(di); } } break; case IFSOCK: if (! dflag) printf("SOCKET\n"); break; case IFCHR: if (! dflag) printf("CHARACTER SPECIAL (%d,%d)\n",major(di->di_rdev),minor(di->di_rdev)); break; case IFBLK: if (! dflag) printf("BLOCK SPECIAL (%d,%d)\n",major(di->di_rdev),minor(di->di_rdev)); break; default: if (! dflag) printf("UNKNOWN TYPE\n"); if (fflag) dumpdata(di); break; } } exit(0); }