#include #include #include #include #include #include #include #include #include #include #include #include #include struct buf *bread(); struct buf b; char bc[BSIZE]; int bflag; main(argc, argv) char *argv[]; { struct dinode di; struct inode i; struct proc p; struct user u; struct text x; struct pte *pte; int j,k,l; if (argc > 1 && !strcmp(argv[1], "-b")) argc--, argv++, bflag++; if (argc != 3) { fprintf(stderr, "usage: copyout [ -b ] inum disk\n"); exit(1); } close(0); if (open(argv[2], 0) != 0) { perror(argv[2]); exit(1); } lseek(0, itod(atoi(argv[1])) * BSIZE + itoo(atoi(argv[1])) * sizeof (di), 0); if (read(0, &di, sizeof (di)) != sizeof (di)) { fprintf(stderr, "error reading inode "); perror(argv[1]); exit(1); } i.i_dev = 0; i.i_number = atoi(argv[1]); i.i_flag = ILOCK; i.i_count = 1; i.i_un.i_lastr = 0; i.i_mode = di.di_mode; i.i_nlink = di.di_nlink; i.i_uid = di.di_uid; i.i_size = di.di_size; l3tol(i.i_un.i_addr, di.di_addr, NADDR); p.p_textp = &x; x.x_iptr = &i; b.b_un.b_addr = bc; pte = (struct pte *)calloc(btoc(i.i_size), sizeof (struct pte)); if (pte == NULL) { fprintf(stderr, "Not enough core for block pointers\n"); exit(1); } vinizfod(&p, pte, 0, (btoc(i.i_size)+(CLSIZE-1)) / CLSIZE); l = i.i_size; for (j = 0; j < (btoc(i.i_size)+(CLSIZE-1)) / CLSIZE; j++) if (bflag) printf("#%d: block %d\n", j, pte[j].pg_pfnum); else { k = imin(l, BSIZE); write(1, bread(0, pte[j].pg_pfnum)->b_un.b_words, k); brelse(&b); l -= BSIZE; } exit(0); } int bused; struct buf * bread(dev, blk) { if (bused) abort(); bused = 1; printf("getblk %x\n", blk); lseek(0, blk * BSIZE, 0); if (read(0, b.b_un.b_addr, BSIZE) != BSIZE) { printf("block %d: ", blk); perror("bread"); } return (&b); } brelse(bp) struct buf *bp; { if (bp != &b) abort(); bused = 0; } struct buf *vbmap(); /* * Initialize the page tables for paging from an inode, * by scouring up the indirect blocks in order. */ vinizfod(p, pte, bstart, count) struct proc *p; register struct pte *pte; daddr_t bstart; int count; { register struct inode *ip = p->p_textp->x_iptr; register int i; struct buf *bp; int indx; register daddr_t *pp; while (count > 0) { if (bstart < NADDR - 3) { pte++->pg_pfnum = ip->i_un.i_addr[bstart]; bstart++; count--; } else { bp = vbmap(ip, bstart); indx = (bstart - (NADDR - 3)) % NINDIR; i = imin(NINDIR - indx, count); bstart += i; count -= i; if (bp) { pp = &bp->b_un.b_daddr[indx]; do pte++->pg_pfnum = *pp++; while (--i > 0); brelse(bp); } else pte += i; } } } /* * Vbmap returns a block full of indirect pointers for a given block offset * in a file. It returns 0 if a missing address block was encountered, * in which case the pages can be normal zfod pages. */ struct buf * vbmap(ip, bn) register struct inode *ip; daddr_t bn; { register i; struct buf *bp; int j, sh; daddr_t nb; dev_t dev = ip->i_dev; if (bn < NADDR-3) panic("vbmap"); /* * addresses NADDR-3, NADDR-2, and NADDR-1 * have single, double, triple indirect blocks. * the first step is to determine * how many levels of indirection. */ sh = 0; nb = 1; bn -= NADDR-3; for (j = 3; j > 0; j--) { sh += NSHIFT; nb <<= NSHIFT; if(bn < nb) break; bn -= nb; } if (j == 0) goto noblk; /* * fetch the address from the inode */ nb = ip->i_un.i_addr[NADDR-j]; /* * fetch through the indirect blocks */ for (;;) { if (nb == 0) return ((daddr_t)0); bp = bread(dev, nb); if (bp->b_flags & B_ERROR) { brelse(bp); goto noblk; } if (j == 3) break; j++; sh -= NSHIFT; i = (bn>>sh) & NMASK; nb = bp->b_un.b_daddr[i]; brelse(bp); if (nb == 0) goto noblk; } return (bp); noblk: return ((struct buf *)0); } imin(a,b) { return (a