* Copyright (c) 1988 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1988 Regents of the University of California.\n\
static char sccsid
[] = "@(#)fsdb.c 5.3 (Berkeley) 6/18/88";
* fsdb - file system debugger
* usage: fsdb [options] special
* -o override some error conditions
* -p"string" set prompt to string
* Never changing defines.
#define OCTAL 8 /* octal base */
#define DECIMAL 10 /* decimal base */
#define HEX 16 /* hexadecimal base */
#define NBUF 10 /* number of cache buffers */
#define PROMPTSIZE 80 /* size of user definable prompt */
#define MAXFILES 40000 /* max number of files ls can handle */
#define FIRST_DEPTH 10 /* default depth for find and ls */
#define SECOND_DEPTH 100 /* second try at depth (maximum) */
#define INPUTBUFFER 1040 /* size of input buffer */
#define BYTESPERLINE 16 /* bytes per line of /dxo output */
#define NREG 36 /* number of save registers */
* Values dependent on sizes of structs and such.
#define NUMB 3 /* these three are arbitrary, */
#define BLOCK 5 /* but must be different from */
#define FRAGMENT 7 /* the rest (hence odd). */
#define BITSPERCHAR 8 /* couldn't find it anywhere */
#define CHAR (sizeof (char))
#define SHORT (sizeof (short))
#define LONG (sizeof (long))
#define INODE (sizeof (struct dinode))
#define DIRECTORY (sizeof (struct direct))
#define CGRP (sizeof (struct cg))
#define SB (sizeof (struct fs))
#define BLKSIZE (fs->fs_bsize) /* for clarity */
#define FRGSIZE (fs->fs_fsize)
#define BLKSHIFT (fs->fs_bshift)
#define FRGSHIFT (fs->fs_fshift)
* Messy macros that would otherwise clutter up such glamorous code.
#define itob(i) ((itod(fs, (i)) << FRGSHIFT) + itoo(fs, (i)) * INODE)
#define min(x, y) ((x) < (y) ? (x) : (y))
#define STRINGSIZE(d) ((long)d->d_reclen - \
((long)&d->d_name[0] - (long)&d->d_ino))
#define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\
(((c) >= 'A')&&((c) <= 'Z')))
#define digit(c) (((c) >= '0') && ((c) <= '9'))
#define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F'))
#define hexletter(c) (((c) >= 'a') && ((c) <= 'f'))
#define octaldigit(c) (((c) >= '0') && ((c) <= '7'))
#define uppertolower(c) ((c) - 'A' + 'a')
#define hextodigit(c) ((c) - 'a' + 10)
#define numtodigit(c) ((c) - '0')
#define loword(X) (((ushort *)&X)[1])
#define lobyte(X) (((unsigned char *)&X)[1])
* buffer cache structure.
* used to hold save registers (see '<' and '>').
* cd, find, and ls use this to hold filenames. Each filename is broken
* up by a slash. In other words, /usr/src/adm would have a len field
* of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
* src, and adm components of the pathname.
long len
; /* number of components */
char flag
; /* flag if using SECOND_DEPTH allocator */
char find
; /* flag if found by find */
char **fname
; /* hold components of pathname */
struct fs filesystem
, *fs
; /* super block */
char *input_path
[MAXPATHLEN
];
char *stack_path
[MAXPATHLEN
];
char *current_path
[MAXPATHLEN
];
char input_buffer
[INPUTBUFFER
];
char PROMPT
[PROMPTSIZE
] = "> ";
short acting_on_directory
;
extern char *malloc(), *calloc();
char *getblk(), *fmtentry();
long get(), bmap(), expr(), term(), getnumb();
unsigned long *print_check();
* main - lines are read up to the unprotected ('\') newline and
* held in an input buffer. Characters may be read from the
* input buffer using getachar() and unread using ungetachar().
* Reading the whole line ahead allows the use of debuggers
* which would otherwise be impossible since the debugger
* and fsdb could not share stdin.
register short i
, j
, *iptr
;
register struct direct
*dirp
;
while (argc
>1 && argv
[1][0] == '-') {
if (strcmp("-?", argv
[1]) == 0)
if (strcmp("-o", argv
[1]) == 0) {
printf("error checking off\n");
if (strncmp("-p", argv
[1],2) == 0) {
if (strcmp("-w", argv
[1]) == 0) {
wrtflag
= 2; /* suitable for open */
printf("usage: %s [options] special\n", progname
);
printf("\t-? display usage\n");
printf("\t-o override some error conditions\n");
printf("\t-p\"string\" set prompt to string\n");
printf("\t-w open for write\n");
* Attempt to open the special file.
if ((fd
= open(argv
[1],wrtflag
)) < 0) {
* Read in the super block and validate (not too picky).
if (lseek(fd
, SBLOCK
* DEV_BSIZE
, 0) == -1) {
if (read(fd
, &filesystem
, sizeof filesystem
) != sizeof filesystem
) {
printf("%s: cannot read superblock\n", argv
[1]);
if (fs
->fs_magic
!= FS_MAGIC
) {
printf("%s: Bad magic number in file system\n", argv
[1]);
if (fs
->fs_postblformat
== FS_42POSTBLFMT
)
printf("fsdb of %s %s -- last mounted on %s\n",
argv
[1], wrtflag
? "(Opened for write)" : "(Read only)",
* Malloc buffers and set up cache.
buffers
= malloc(NBUF
* BLKSIZE
);
bhdr
.fwd
= bhdr
.back
= &bhdr
;
bp
->blkaddr
= buffers
+ (i
* BLKSIZE
);
* Malloc filenames structure. The space for the actual filenames
* is allocated as it needs it.
filenames
= (struct filenames
*)calloc(MAXFILES
,
sizeof (struct filenames
));
printf("out of memory\n");
* Malloc a few filenames (needed by pwd for example).
for (i
= 0; i
< MAXPATHLEN
; i
++) {
input_path
[i
] = calloc(1, MAXNAMLEN
);
stack_path
[i
] = calloc(1, MAXNAMLEN
);
current_path
[i
] = calloc(1, MAXNAMLEN
);
if (current_path
[i
] == NULL
) {
printf("out of memory\n");
* Main loop and case statement. If an error condition occurs
* initialization and recovery is attempted.
freemem(filenames
, nfiles
);
cur_bytes
= errcur_bytes
;
switch (c
= getachar()) {
case '\n': /* command end */
freemem(filenames
, nfiles
);
if (should_print
&& laststyle
== '=') {
errcur_bytes
= cur_bytes
;
getdirslot(dirslot
+1)) == 0)
if ((addr
=cgrp_check(cur_cgrp
)) == 0) {
fprnt(laststyle
, lastpo
);
c_count
= colon
= acting_on_inode
= 0;
errcur_bytes
= cur_bytes
;
case '(': /* numeric expression or unknown command */
if (digit(c
) || c
== '(') {
printf("unknown command or bad syntax\n");
case '?': /* general print facilities */
case ';': /* command separator and . */
case ':': /* command indicator */
case ',': /* count indicator */
if ((c
= getachar()) == '*') {
case '+': /* address addition */
errcur_bytes
= cur_bytes
;
addr
= getdirslot(dirslot
+ temp
);
if ((addr
= cgrp_check(cur_cgrp
)) == 0) {
cur_bytes
+= temp
* objsz
;
case '-': /* address subtraction */
errcur_bytes
= cur_bytes
;
addr
= getdirslot(dirslot
- temp
);
if ((addr
= cgrp_check(cur_cgrp
)) == 0) {
cur_bytes
-= temp
* objsz
;
case '*': /* address multiplication */
if (objsz
!= INODE
&& objsz
!= DIRECTORY
)
case '%': /* address division */
printf("divide by zero\n");
if (objsz
!= INODE
&& objsz
!= DIRECTORY
)
case '=': { /* assignment operation */
if (acting_on_inode
== 1) {
if (c
!= 'o' && c
!= 'd' && c
!= 'x' &&
c
!= 'O' && c
!= 'D' && c
!= 'X') {
if (acting_on_inode
== 2)
} else if (acting_on_inode
)
errcur_bytes
= cur_bytes
;
case '"': /* character string */
cur_bytes
= blkoff(fs
, addr
);
if (objsz
==DIRECTORY
|| objsz
==INODE
)
case '+': /* =+ operator */
case '-': /* =- operator */
printf("%s", ctime(&value
));
if (objsz
== DIRECTORY
) {
print(value
& 0177777L, 12, -8, 0);
print(addr
& 0177777L, 12, -8, 0);
default: /* regular assignment */
printf("syntax error\n");
case '>': /* save current address */
if (!letter(c
) && !digit(c
)) {
printf("invalid register specification, ");
printf("must be letter or digit\n");
regs
[c
].sv_value
= value
;
regs
[c
].sv_objsz
= objsz
;
case '<': /* restore saved address */
if (!letter(c
) && !digit(c
)) {
printf("invalid register specification, ");
printf("must be letter or digit\n");
value
= regs
[c
].sv_value
;
objsz
= regs
[c
].sv_objsz
;
if (match("at", 2)) { /* access time */
&((struct dinode
*)cur_ino
)->di_atime
;
if (match("block", 2)) { /* block conversion */
addr
= value
<< FRGSHIFT
;
if (match("bs", 2)) { /* block size */
if (icheck(cur_ino
) == 0)
&((struct dinode
*)cur_ino
)->di_blocks
;
if (match("base", 2)) { /* change/show base */
if ((c
= getachar()) == '\n') {
printf("invalid base\n");
if (match("cd", 2)) { /* change directory */
if ((c
= getachar()) == '\n') {
restore_inode(filenames
->ino
);
if ((mode
= icheck(addr
)) == 0)
if ((mode
& IFMT
) != IFDIR
) {
print_path(input_path
, input_pathp
);
printf(" not a directory\n");
for (i
= 0; i
<= top
->len
; i
++)
current_pathp
= top
->len
;
if (match("cg", 2)) { /* cylinder group */
if (value
> fs
->fs_ncg
- 1) {
printf("maximum cylinder group is ");
print(fs
->fs_ncg
- 1, 8, -8, 0);
addr
= cgtod(fs
, cur_cgrp
) << FRGSHIFT
;
if (match("ct", 2)) { /* creation time */
&((struct dinode
*)cur_ino
)->di_ctime
;
if (match("directory", 2)) { /* directory offsets */
addr
= getdirslot(value
);
if (match("db", 2)) { /* direct block */
printf("direct blocks are 0 to ");
print(NDADDR
- 1, 0, 0, 0);
&((struct dinode
*)cur_ino
)->di_db
[value
];
cur_bytes
= (value
) * BLKSIZE
;
if (!value
&& !override
) {
printf("non existent block\n");
if (match("find", 3)) { /* find command */
if (match("fragment", 2)) { /* fragment conv. */
if (min(blocksize
, filesize
) - cur_bytes
>
blocksize
= cur_bytes
+ FRGSIZE
;
filesize
= blocksize
* 2;
addr
= value
<< FRGSHIFT
;
if (match("file", 4)) { /* access as file */
if ((mode
= icheck(addr
)) == 0)
if ((mode
& IFCHR
) && !override
) {
printf("special device\n");
if ((addr
= (bmap(value
) << FRGSHIFT
)) == 0)
if (match("fill", 4)) { /* fill */
if (objsz
== INODE
|| objsz
== DIRECTORY
) {
printf("can't fill inode or directory\n");
if (match("gid", 1)) { /* group id */
&((struct dinode
*)cur_ino
)->di_gid
;
if (match("inode", 2)) { /* i# to inode conversion */
if (match("ib", 2)) { /* indirect block */
printf("indirect blocks are 0 to ");
print(NIADDR
- 1, 0, 0, 0);
&((struct dinode
*)cur_ino
)->di_ib
[value
];
cur_bytes
= (NDADDR
- 1) * BLKSIZE
;
for (i
= 0; i
< value
; i
++) {
temp
*= NINDIR(fs
) * BLKSIZE
;
if (!value
&& !override
) {
printf("non existent block\n");
if (match("ls", 2)) { /* ls command */
recursive
= long_list
= 0;
if ((c
= getachar()) == '-') {
if ((c
= getachar()) == 'R') {
printf("unknown option ");
if ((c
= getachar()) == '\n') {
if (error
|| nfiles
== 0) {
qsort((char *)filenames
, nfiles
,
sizeof (struct filenames
), ffcmp
);
ls(filenames
, filenames
+ (nfiles
- 1), 0);
if (match("ln", 2)) { /* link count */
&((struct dinode
*)cur_ino
)->di_nlink
;
if ((mode
= icheck(addr
)) == 0)
if (match("mt", 2)) { /* modification time */
&((struct dinode
*)cur_ino
)->di_mtime
;
if (match("md", 2)) { /* mode */
&((struct dinode
*)cur_ino
)->di_mode
;
if (match("maj", 2)) { /* major device number */
&((struct dinode
*)cur_ino
)->di_db
[1];
if (match("min", 2)) { /* minor device number */
&((struct dinode
*)cur_ino
)->di_db
[0];
if (match("nm", 1)) { /* directory name */
if ((cptr
= getblk(addr
)) == 0)
dirp
= (struct direct
*)(cptr
+blkoff(fs
, addr
));
stringsize
= (long)dirp
->d_reclen
-
((long)&dirp
->d_name
[0] - (long)&dirp
->d_ino
);
&((struct direct
*)addr
)->d_name
[0];
if (match("override", 1)) { /* override flip flop */
if (override
= !override
)
printf("error checking off\n");
printf("error checking on\n");
if (match("pwd", 2)) { /* print working dir */
print_path(current_path
, current_pathp
);
if (match("prompt", 2)) { /* change prompt */
if ((c
= getachar()) != '=') {
if ((c
= getachar()) != '"') {
printf("missing '\"'\n");
while ((c
= getachar()) != '"' &&
printf("string too long\n");
if (match("quit", 1)) { /* quit */
if ((c
= getachar()) != '\n') {
if (match("sb", 2)) { /* super block */
if (value
> fs
->fs_ncg
- 1) {
printf("maximum super block is ");
print(fs
->fs_ncg
- 1, 8, -8, 0);
addr
= cgsblock(fs
, cur_cgrp
) << FRGSHIFT
;
if (match("sz", 2)) { /* file size */
&((struct dinode
*)cur_ino
)->di_size
;
if (match("uid", 1)) { /* user id */
&((struct dinode
*)cur_ino
)->di_uid
;
case 'F': /* buffer status (internal use only) */
for (bp
= bhdr
.fwd
; bp
!= &bhdr
; bp
= bp
->fwd
)
printf("%8x %d\n",bp
->blkno
,bp
->valid
);
printf("# commands\t\t%d\n", commands
);
printf("# read requests\t\t%d\n", read_requests
);
printf("# actual disk reads\t%d\n", actual_disk_reads
);
printf("a colon should precede a command\n");
printf("more letters needed to distinguish command\n");
* getachar - get next character from input buffer.
return(input_buffer
[input_pointer
++]);
* ungetachar - return character to input buffer.
if (input_pointer
== 0) {
printf("internal problem maintaining input buffer\n");
input_buffer
[--input_pointer
] = c
;
* getnextinput - display the prompt and read an input line.
* An input line is up to 128 characters terminated by the newline
* character. Handle overflow, shell escape, and eof.
register short pid
, rpid
;
while ((c
= getc(stdin
)) != '\n' && !(c
== '!' && i
== 0) &&
!feof(stdin
) && i
<= INPUTBUFFER
- 2)
if (input_buffer
[i
- 1] == '\\') {
if ((pid
= fork()) == 0) {
execl("/bin/sh", "sh", "-t", 0);
while ((rpid
= wait(&retcode
)) != pid
&& rpid
!= -1)
printf("input truncated to 128 characters\n");
* eat_spaces - read extraneous spaces.
while ((c
= getachar()) == ' ')
* restore_inode - set up all inode indicators so inum is now
errinum
= cur_inum
= inum
;
addr
= errino
= cur_ino
= itob(inum
);
* match - return false if the input does not match string up to
* upto letters. Then proceed to chew up extraneous letters.
register int i
, length
= strlen(string
) - 1;
if ((c
= getachar()) != *string
) {
for (i
= save_upto
- upto
; i
; i
--) {
if ((c
= getachar()) != *string
) {
* expr - expression evaluator. Will evaluate expressions from
* left to right with no operator precedence. Parentheses may
register long numb
= 0, temp
;
printf("divide by zero\n");
* term - used by expression evaluator to get an operand.
switch (c
= getachar()) {
* getnumb - read a number from the input stream. A leading
* zero signifies octal interpretation, a leading '0x'
* signifies hexadecimal, and a leading '0t' signifies
* decimal. If the first character is a character,
long number
= 0, tbase
, num
;
if ((c
= getachar()) == 'x')
number
= number
* tbase
+ num
;
* find - the syntax is almost identical to the unix command.
* find dir [-name pattern] [-inum number]
* Note: only one of -name or -inum may be used at a time.
* Also, the -print is not needed (implied).
register struct filenames
*fn
;
print_path(input_path
, input_pathp
);
restore_inode(filenames
->ino
);
freemem(filenames
, nfiles
);
if ((mode
= icheck(addr
)) == 0)
if ((mode
& IFMT
) != IFDIR
) {
print_path(input_path
, input_pathp
);
printf(" not a directory\n");
if ((c
= getachar()) != '-') {
find_by_name
= find_by_inode
= 0;
} else if (match("inum", 4)) {
while ((c
= getachar()) != '\n')
printf("use -name or -inum with find\n");
for (fn
= filenames
; fn
<= top
; fn
++) {
print(fn
->ino
, 12, -8, 0);
print_path(fn
->fname
, fn
->len
);
* ls - do an ls. Should behave exactly as ls(1).
* Only -R and -l is supported and -l gives different results.
struct filenames
*fn0
, *fnlast
;
register struct filenames
*fn
, *fnn
;
qsort((char *)fn0
, fnlast
- fn0
+ 1,
sizeof (struct filenames
), fcmp
);
for (fnn
= fn
, fn
++; fn
<= fnlast
; fnn
= fn
, fn
++) {
if (fnn
->len
!= fn
->len
&& level
== fnn
->len
- 1)
if (strcmp(fn
->fname
[level
], fnn
->fname
[level
]))
if (fn0
->len
&& level
!= fn0
->len
- 1)
print_path(fn0
->fname
, fn0
->len
- 1);
qsort((char *)fn0
, fnn
- fn0
+ 1,
sizeof (struct filenames
), fcmp
);
* formatf - code lifted from ls.
register struct filenames
*fn0
, *fnlast
;
register struct filenames
*fn
;
int width
= 0, w
, nentry
= fnlast
- fn0
+ 1;
int i
, j
, columns
, lines
;
for (fn
= fn0
; fn
<= fnlast
; fn
++) {
int len
= strlen(fn
->fname
[cmp_level
]) + 2;
width
= (width
+ 8) &~ 7;
lines
= (nentry
+ columns
- 1) / columns
;
for (i
= 0; i
< lines
; i
++) {
for (j
= 0; j
< columns
; j
++) {
fn
= fn0
+ j
* lines
+ i
;
print(fn
->ino
, 12, -8, 0);
if (fn
+ lines
> fnlast
) {
* fmtentry - code lifted from ls.
register struct filenames
*fn
;
static char fmtres
[BUFSIZ
];
register struct dinode
*ip
;
register char *cptr
, *cp
, *dp
;
for (cp
= fn
->fname
[cmp_level
]; *cp
; cp
++) {
if (*cp
< ' ' || *cp
>= 0177)
if ((cptr
= getblk(addr
)) == 0)
cptr
+= blkoff(fs
, addr
);
ip
= (struct dinode
*)cptr
;
switch (ip
->di_mode
& IFMT
) {
* fcmp - routine used by qsort. Will sort first by name, then
* then by pathname length if names are equal. Uses global
* cmp_level to tell what component of the path name we are comparing.
register struct filenames
*f1
, *f2
;
if ((value
= strcmp(f1
->fname
[cmp_level
], f2
->fname
[cmp_level
])))
return (f1
->len
- f2
->len
);
* ffcmp - routine used by qsort. Sort only by pathname length.
register struct filenames
*f1
, *f2
;
return (f1
->len
- f2
->len
);
* parse - set up the call to follow_path.
stack_pathp
= input_pathp
= -1;
if ((c
= getachar()) == '/') {
while ((c
= getachar()) == '/')
if ((c
= getachar()) == '\n') {
stack_pathp
= current_pathp
;
input_pathp
= current_pathp
;
for (i
= 0; i
<= current_pathp
; i
++) {
strcpy(input_path
[i
], current_path
[i
]);
strcpy(stack_path
[i
], current_path
[i
]);
follow_path(stack_pathp
+ 1, cur_inum
);
* follow_path - called by cd, find, and ls.
* input_path holds the name typed by the user.
* stack_path holds the name at the current depth.
register struct direct
*dirp
;
register char **ccptr
, *cptr
, c
;
struct filenames
*tos
, *bos
, *fn
, *fnn
, *fnnn
;
if ((mode
= icheck(addr
)) == 0)
if ((mode
& IFMT
) != IFDIR
)
while (cur_bytes
< filesize
) {
if (block
== 0 || bcomp(addr
)) {
if ((addr
= (bmap(block
++) << FRGSHIFT
)) == 0)
if ((cptr
= getblk(addr
)) == 0)
cptr
+= blkoff(fs
, addr
);
dirp
= (struct direct
*)cptr
;
if (level
> input_pathp
|| doing_find
||
compare(input_path
[level
], &dirp
->d_name
[0], 1)) {
if (++top
- filenames
>= MAXFILES
) {
printf("too many files\n");
top
->fname
= (char **)calloc(FIRST_DEPTH
, sizeof (char **));
printf("out of memory\n");
if (compare(input_path
[0], &dirp
->d_name
[0], 1))
} else if (find_by_inode
)
if (find_ino
== dirp
->d_ino
)
if (top
->len
+ 1 >= FIRST_DEPTH
&& top
->flag
== 0) {
ccptr
= (char **)calloc(SECOND_DEPTH
, sizeof (char **));
printf("out of memory\n");
for (i
= 0; i
< FIRST_DEPTH
; i
++)
ccptr
[i
] = top
->fname
[i
];
free((char *)top
->fname
);
if (top
->len
>= SECOND_DEPTH
) {
printf("maximum depth exceeded, try to cd lower\n");
for (i
= 0; i
<= stack_pathp
; i
++) {
top
->fname
[i
]=calloc(1, strlen(stack_path
[i
])+1);
if (top
->fname
[i
] == 0) {
printf("out of memory\n");
strcpy(top
->fname
[i
], stack_path
[i
]);
* Check for '.' or '..' typed.
if ((level
<= input_pathp
) &&
(strcmp(input_path
[level
], ".") == 0 ||
strcmp(input_path
[level
], "..") == 0)) {
if (strcmp(input_path
[level
],"..") == 0 &&
free(top
->fname
[top
->len
]);
if (!doing_cd
&& !doing_find
) {
for (fn
= filenames
; fn
< top
; fn
++) {
if (fn
->ino
== dirp
->d_ino
&&
fn
->len
== stack_pathp
+ 1) {
for (i
= 0; i
< fn
->len
; i
++)
if (strcmp(fn
->fname
[i
], stack_path
[i
]))
strcmp(fn
->fname
[i
], dirp
->d_name
))
top
->fname
[top
->len
] = calloc(1,
strlen(&dirp
->d_name
[0])+1);
if (top
->fname
[top
->len
] == 0) {
printf("out of memory\n");
strcpy(top
->fname
[top
->len
], &dirp
->d_name
[0]);
cur_bytes
+= dirp
->d_reclen
;
if ((doing_cd
&& level
== input_pathp
) ||
(!recursive
&& !doing_find
&& level
> input_pathp
))
* Check newly added entries to determine if further expansion
for (fn
= tos
; fn
<= bos
; fn
++) {
* Avoid '.' and '..' if beyond input.
if ((recursive
|| doing_find
) && (level
> input_pathp
) &&
(strcmp(fn
->fname
[fn
->len
], ".") == 0 ||
strcmp(fn
->fname
[fn
->len
], "..") == 0))
if ((mode
= icheck(cur_ino
)) == 0)
if ((mode
& IFMT
) == IFDIR
|| level
< input_pathp
) {
* Set up current depth, remove current entry and
for (i
= 0; i
<= fn
->len
; i
++)
strcpy(stack_path
[i
], fn
->fname
[i
]);
(!recursive
|| (recursive
&& level
<= input_pathp
))) {
* Remove current entry by moving others up.
for (fnnn
= fnn
, fnn
++; fnn
<= top
; fnnn
= fnn
, fnn
++) {
if (fnnn
->len
+ 1 < FIRST_DEPTH
) {
fnnn
->fname
= (char **)calloc(FIRST_DEPTH
,
} else if (fnnn
->len
< SECOND_DEPTH
) {
fnnn
->fname
= (char **)calloc(SECOND_DEPTH
,
printf("maximum depth exceeded, ");
printf("try to cd lower\n");
for (i
= 0; i
<= fnn
->len
; i
++)
fnnn
->fname
[i
] = fnn
->fname
[i
];
follow_path(level
+ 1, cur_inum
);
* getname - break up the pathname entered by the user into components.
if ((c
= getachar()) == '\n') {
for (i
= 0; i
< MAXNAMLEN
; i
++)
input_path
[input_pathp
][i
] = '\0';
if (strlen(input_path
[input_pathp
]) + 1 >= MAXNAMLEN
) {
printf("maximum name length exceeded, ");
input_path
[input_pathp
][strlen(input_path
[input_pathp
])] = c
;
input_path
[input_pathp
][strlen(input_path
[input_pathp
])] =
if (c
== ' ' || c
== '\n') {
if (!doing_find
&& c
== '/') {
if (++input_pathp
>= MAXPATHLEN
) {
printf("maximum path length exceeded, ");
if (strlen(input_path
[input_pathp
]) >= MAXNAMLEN
) {
printf("maximum name length exceeded, truncating\n");
input_path
[input_pathp
][strlen(input_path
[input_pathp
])] = c
;
* compare - check if a filename matches the pattern entered by the user.
* Handles '*', '?', and '[]'.
compare(s1
, s2
, at_start
)
if (at_start
&& s
== s2
&& !letter(*s2
) && !digit(*s2
))
if (at_start
&& s
== s2
&& !letter(*s2
) && !digit(*s2
))
* freemem - free the memory allocated to the filenames structure.
for (i
= 0; i
< numb
; i
++, p
++) {
for (j
= 0; j
<= p
->len
; j
++)
* print_path - print the pathname held in p.
for (i
= 0; i
< pntr
; i
++)
* fill - fill a section with a value or string.
* addr,count:fill=[value, "string"].
short eof_flag
, end
= 0, eof
= 0;
long temp
, tcount
, taddr
;
printf("not opened for write '-w'\n");
if ((cptr
= getblk(addr
)) == 0)
cur_bytes
-= taddr
- addr
;
cptr
+= blkoff(fs
, addr
);
tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
for (i
= 0; i
< tcount
; i
++) {
addr
+= (tcount
- 1) * objsz
;
cur_bytes
+= (tcount
- 1) * objsz
;
printf("end of block\n");
* get - read a byte, short or long from the file system.
* The entire block containing the desired item is read
* and the appropriate data is extracted and returned.
if (objsz
== INODE
|| objsz
== SHORT
)
else if (objsz
== DIRECTORY
|| objsz
== LONG
)
if ((bptr
= getblk(temp
)) == 0)
bptr
+= blkoff(fs
, temp
);
return((long)(*(short *)bptr
));
* cgrp_check - make sure that we don't bump the cylinder group
* beyond the total number of cylinder groups or before the start.
printf("beginning of cylinder groups\n");
printf("beginning of super blocks\n");
if (cgrp
>= fs
->fs_ncg
) {
printf("end of cylinder groups\n");
printf("end of super blocks\n");
return(cgtod(fs
, cgrp
) << FRGSHIFT
);
return(cgsblock(fs
, cgrp
) << FRGSHIFT
);
* icheck - make sure we can read the block containing the inode
* and determine the filesize (0 if inode not allocated). Return
* 0 if error otherwise return the mode.
register struct dinode
*ip
;
if ((cptr
= getblk(address
)) == 0)
cptr
+= blkoff(fs
, address
);
ip
= (struct dinode
*)cptr
;
if ((ip
->di_mode
& IFMT
) == 0) {
printf("inode not allocated\n");
blocksize
= filesize
= 0;
blocksize
= filesize
* 2;
* getdirslot - get the address of the directory slot desired.
register struct direct
*dirp
;
char *string
= &scratch
[0];
short bod
= 0, mode
, temp
;
if ((cptr
= getblk(addr
)) == 0)
cptr
+= blkoff(fs
, addr
);
dirp
= (struct direct
*)cptr
;
for (dirslot
= 0; dirslot
< slot
; dirslot
++) {
dirp
= (struct direct
*)cptr
;
if (blocksize
> filesize
) {
if (cur_bytes
+ dirp
->d_reclen
>= filesize
) {
errcur_bytes
= cur_bytes
;
stringsize
= STRINGSIZE(dirp
);
if (cur_bytes
+ dirp
->d_reclen
>= blocksize
) {
printf("end of %s\n", string
);
errcur_bytes
= cur_bytes
;
stringsize
= STRINGSIZE(dirp
);
cur_bytes
+= dirp
->d_reclen
;
if (blocksize
> filesize
)
printf("beginning of file\n");
printf("beginning of %s\n", string
);
errcur_bytes
= cur_bytes
;
stringsize
= STRINGSIZE(dirp
);
if ((mode
= icheck(addr
)) == 0)
if (!override
&& (mode
& IFDIR
) == 0) {
printf("inode is not a directory\n");
if (i
== 0 || bcomp(addr
)) {
if ((addr
=(bmap(i
++) << FRGSHIFT
)) == 0)
if ((cptr
= getblk(addr
)) == 0)
cptr
+= blkoff(fs
, addr
);
dirp
= (struct direct
*)cptr
;
if (cur_bytes
+ dirp
->d_reclen
>= filesize
) {
dirslot
= slot
- temp
- 1;
errcur_bytes
= cur_bytes
;
stringsize
= STRINGSIZE(dirp
);
cur_bytes
+= dirp
->d_reclen
;
printf("beginning of file\n");
errcur_bytes
= cur_bytes
;
stringsize
= STRINGSIZE(dirp
);
* putf - print a byte as an ascii character if possible.
* The exceptions are tabs, newlines, backslashes
* and nulls which are printed as the standard C
* language escapes. Characters which are not
* recognized are printed as \?.
if (c
<=037 || c
>=0177 || c
=='\\') {
* put - write an item into the buffer for the current address
* block. The value is checked to make sure that it will
* fit in the size given without truncation. If successful,
* the entire block is written back to the file system.
register char *bptr
, *sbptr
;
printf("not opened for write '-w'\n");
if ((sbptr
= getblk(addr
)) == 0)
bptr
= sbptr
+ blkoff(fs
, addr
);
olditem
= (long)*(short *)bptr
;
*bptr
= lobyte(loword(item
));
if ((s_err
= lseek(fd
, addr
& fs
->fs_bmask
, 0)) == -1) {
printf("seek error : %x\n",addr
);
if ((nbytes
= write(fd
, sbptr
, BLKSIZE
)) != BLKSIZE
) {
printf("write error : addr = %x\n",addr
);
printf(" : s_err = %x\n",s_err
);
printf(" : nbytes = %x\n",nbytes
);
if (!acting_on_inode
&& objsz
!= INODE
&& objsz
!= DIRECTORY
) {
print(olditem
, 8, -8, 0);
if (objsz
== DIRECTORY
) {
* getblk - check if the desired block is in the file system.
* Search the incore buffers to see if the block is already
* available. If successful, unlink the buffer control block
* from its position in the buffer list and re-insert it at
* the head of the list. If failure, use the last buffer
* in the list for the desired block. Again, this control
* block is placed at the head of the list. This process
* will leave commonly requested blocks in the in-core buffers.
* Finally, a pointer to the buffer is returned.
block
= lblkno(fs
, address
);
if (block
>= fragstoblks(fs
, fs
->fs_size
)) {
printf("block exceeds maximum block in file system\n");
for (bp
=bhdr
.fwd
; bp
!= &bhdr
; bp
=bp
->fwd
)
if (bp
->valid
&& bp
->blkno
==block
)
if ((s_err
= lseek(fd
, address
& fs
->fs_bmask
, 0)) == -1) {
printf("seek error : %x\n",address
);
if ((nbytes
= read(fd
, bp
->blkaddr
, BLKSIZE
)) != BLKSIZE
) {
printf("read error : addr = %x\n",address
);
printf(" : s_err = %x\n",s_err
);
printf(" : nbytes = %x\n",nbytes
);
xit
: bp
->back
->fwd
= bp
->fwd
;
bp
->fwd
->back
= bp
->back
;
* insert - place the designated buffer control block
* at the head of the linked list of buffers.
* err - called on interrupts. Set the current address
* back to the last address stored in erraddr. Reset all
* appropriate flags. A reset call is made to return
freemem(filenames
, nfiles
);
cur_bytes
= errcur_bytes
;
* devcheck - check that the given mode represents a
* special device. The IFCHR bit is on for both
* character and block devices.
printf("not character or block device\n");
* nullblk - return error if address is zero. This is done
* to prevent block 0 from being used as an indirect block
* for a large file or as a data block for a small file.
printf("non existent block\n");
* puta - put ascii characters into a buffer. The string
* terminates with a quote or newline. The leading quote,
* which is optional for directory names, was stripped off
* by the assignment case in the main loop.
long maxchars
, s_err
, nbytes
, temp
;
long taddr
= addr
, tcount
= 0, item
, olditem
= 0;
printf("not opened for write '-w'\n");
if ((sbptr
= getblk(addr
)) == 0)
cptr
= sbptr
+ blkoff(fs
, addr
);
if (objsz
== DIRECTORY
) {
maxchars
= stringsize
- 1;
} else if (objsz
== INODE
)
maxchars
= objsz
- (addr
- cur_ino
);
maxchars
= min(blocksize
- cur_bytes
, filesize
- cur_bytes
);
while ((c
= getachar()) != '"') {
if (tcount
>= maxchars
) {
printf("string too long\n");
else if (acting_on_inode
|| objsz
== INODE
)
errcur_bytes
= cur_bytes
;
switch (c
= getachar()) {
if (objsz
== DIRECTORY
&& acting_on_directory
)
for (i
= tcount
; i
<= maxchars
; i
++)
if ((s_err
= lseek(fd
, addr
& fs
->fs_bmask
, 0)) == -1) {
printf("seek error : %x\n",addr
);
if ((nbytes
= write(fd
, sbptr
, BLKSIZE
)) != BLKSIZE
) {
printf("write error : addr = %x\n",addr
);
printf(" : s_err = %x\n",s_err
);
printf(" : nbytes = %x\n",nbytes
);
if (!acting_on_inode
&& objsz
!= INODE
&& objsz
!= DIRECTORY
) {
cur_bytes
-= taddr
- addr
;
tcount
= LONG
- (taddr
- addr
);
if ((cptr
= getblk(addr
)) == 0)
cptr
+= blkoff(fs
, addr
);
olditem
<<= tcount
* BITSPERCHAR
;
for (i
= 0; i
< (tcount
*BITSPERCHAR
); i
++)
olditem
+= item
& (temp
- 1);
item
= (long)*(short *)cptr
;
olditem
<<= tcount
* BITSPERCHAR
;
for (i
= 0; i
< (tcount
* BITSPERCHAR
); i
++)
olditem
+= item
& (temp
- 1);
print(olditem
, 8, -8, 0);
if (objsz
== DIRECTORY
) {
* fprnt - print data. 'count' elements are printed where '*' will
* print an entire blocks worth or up to the eof, whichever
* occurs first. An error will occur if crossing a block boundary
* is attempted since consecutive blocks don't usually have
* meaning. Current print types:
* / b - print as bytes (base sensitive)
* c - print as characters
* o O - print as octal shorts (longs)
* d D - print as decimal shorts (longs)
* x X - print as hexadecimal shorts (longs)
* ? c - print as cylinder groups
* d - print as directories
* s - print as super blocks
register struct direct
*dirp
;
register struct dinode
*ip
;
long tinode
, tcount
, temp
, taddr
;
short offset
, mode
, end
= 0, eof
= 0, eof_flag
;
offset
= blkoff(fs
, addr
);
case 'c': /* print as characters */
if ((cptr
= getblk(addr
)) == 0)
tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
for (i
=0; tcount
--; i
++) {
errcur_bytes
= cur_bytes
;
printf("end of block\n");
printf("end of fragment\n");
case 'o': /* print as octal shorts */
case 'd': /* print as decimal shorts */
case 'x': /* print as hex shorts */
if ((cptr
= getblk(addr
)) == 0)
cur_bytes
-= taddr
- addr
;
cptr
+= blkoff(fs
, addr
);
sptr
= (unsigned short *)cptr
;
tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
for (i
=0; tcount
--; i
++) {
sptr
= (unsigned short *)
print_check(sptr
, &tcount
, tbase
, i
);
errcur_bytes
= cur_bytes
;
printf("end of block\n");
printf("end of fragment\n");
case 'O': /* print as octal longs */
case 'D': /* print as decimal longs */
case 'X': /* print as hex longs */
if ((cptr
= getblk(addr
)) == 0)
cur_bytes
-= taddr
- addr
;
cptr
+= blkoff(fs
, addr
);
lptr
= (unsigned long *)cptr
;
tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
for (i
=0; tcount
--; i
++) {
print_check(lptr
, &tcount
, tbase
, i
);
printf("%011o ",*lptr
++);
printf("%010u ",*lptr
++);
errcur_bytes
= cur_bytes
;
printf("end of block\n");
printf("end of fragment\n");
printf("no such print option\n");
case 'c': /* print as cylinder group */
if (cur_cgrp
+ count
> fs
->fs_ncg
) {
tcount
= fs
->fs_ncg
- cur_cgrp
;
errcur_bytes
= cur_bytes
;
addr
= cgtod(fs
, cur_cgrp
)
if ((cptr
= getblk(addr
)) == 0) {
cptr
+= blkoff(fs
, addr
);
cur_cgrp
= cg
->cg_cgx
+ 1;
if (cur_cgrp
+ count
- 1 > fs
->fs_ncg
) {
tcount
= fs
->fs_ncg
- cur_cgrp
;
if (!override
&& !cg_chkmagic(cg
)) {
printf("invalid cylinder group ");
printf("end of cylinder groups\n");
case 'd': /* print as directories */
if ((cptr
= getblk(addr
)) == 0)
printf("address must be at the ");
printf("beginning of a fragment\n");
while (tcount
-- && cur_bytes
< filesize
&&
cur_bytes
< blocksize
&& !bcomp(addr
)) {
dirp
= (struct direct
*)cptr
;
print(tinode
, 12, -8, 0);
printf("%s\n",&dirp
->d_name
[0]);
errcur_bytes
= cur_bytes
;
cur_bytes
+= dirp
->d_reclen
;
cur_bytes
= errcur_bytes
;
stringsize
= STRINGSIZE(dirp
);
if (tcount
>= 0 && !star
) {
printf("end of fragment\n");
printf("end of block\n");
printf("end of directory\n");
case 'i': /* print as inodes */
if ((ip
= (struct dinode
*)getblk(addr
)) == 0)
for (i
=1; i
< fs
->fs_ncg
; i
++)
if (addr
< (cgimin(fs
,i
) << FRGSHIFT
))
temp
= (addr
- (cgimin(fs
,i
) << FRGSHIFT
)) >> FRGSHIFT
;
temp
= (i
* fs
->fs_ipg
) + fragstoblks(fs
,temp
) *
if (count
+ offset
> INOPB(fs
)) {
tcount
= INOPB(fs
) - offset
;
for (i
=0; tcount
--; ip
++, temp
++) {
if ((mode
= icheck(addr
)) == 0)
for (mode
= mode
<< 4; *++p
; mode
= mode
<< 1) {
print(ip
->di_uid
,8,-4,0);
print(ip
->di_gid
,8,-4,0);
print(ip
->di_nlink
,8,-4,0);
print(ip
->di_blocks
,12,-8,0);
print(ip
->di_size
,12,-8,0);
if (ip
->di_mode
& IFCHR
) {
print(ip
->di_db
[1] & 0377,4,-2,0);
print(ip
->di_db
[0] & 0377,4,-2,0);
for (i
= 0; i
< NDADDR
; ) {
print(ip
->di_db
[i
],11,-8,0);
for (i
= 0; i
< NIADDR
; i
++) {
print(ip
->di_ib
[i
],11,-8,0);
if (c
== '?' && !override
) {
printf(" is unallocated\n");
cur_ino
= erraddr
= addr
;
errcur_bytes
= cur_bytes
;
cur_bytes
= errcur_bytes
;
printf("end of block\n");
case 's': /* print as super block */
addr
= SBLOCK
* DEV_BSIZE
;
if (cur_cgrp
+ count
> fs
->fs_ncg
) {
tcount
= fs
->fs_ncg
- cur_cgrp
;
cur_bytes
= errcur_bytes
;
addr
= cgsblock(fs
, cur_cgrp
)
if ((cptr
= getblk(addr
)) == 0) {
cptr
+= blkoff(fs
, addr
);
for (i
= 0; i
< fs
->fs_ncg
; i
++)
if (addr
== cgsblock(fs
, i
) <<
if (cur_cgrp
+ count
- 1 > fs
->fs_ncg
) {
tcount
= fs
->fs_ncg
- cur_cgrp
;
if (sb
->fs_magic
!= FS_MAGIC
) {
printf("invalid super block ");
printf("\tsuper block:\n");
printf("\tsuper block in cylinder ");
print(cur_cgrp
- 1, 0, 0, 0);
printf("end of super blocks\n");
printf("no such print option\n");
* valid_addr - call check_addr to validate the current address.
short eof_flag
, end
= 0, eof
= 0;
if (blocksize
> filesize
) {
printf("beginning of file\n");
printf("beginning of block\n");
printf("beginning of fragment\n");
check_addr(1, &end
, &eof
, (filesize
< blocksize
));
printf("beginning of block\n");
printf("beginning of fragment\n");
printf("end of block\n");
printf("end of fragment\n");
* check_addr - check if the address crosses the end of block or
* end of file. Return the proper count.
check_addr(eof_flag
, end
, eof
, keep_on
)
short eof_flag
, *end
, *eof
, keep_on
;
long temp
, tcount
= count
, taddr
= addr
, tcur_bytes
= cur_bytes
;
if (bcomp(addr
+ count
* objsz
- 1) ||
(keep_on
&& taddr
< (bmap(cur_block
) << FRGSHIFT
))) {
temp
= cur_block
- lblkno(fs
, cur_bytes
);
if ((addr
= bmap(cur_block
) << FRGSHIFT
) == 0) {
temp
= tcur_bytes
- cur_bytes
;
if (cur_bytes
>= filesize
) {
temp
= lblkno(fs
, cur_bytes
) - cur_block
;
if ((addr
= bmap(cur_block
) << FRGSHIFT
) == 0) {
temp
= tcur_bytes
- cur_bytes
;
tcount
= (blkroundup(fs
, addr
+1)-addr
) / objsz
;
if (blocksize
> filesize
) {
if (cur_bytes
>= filesize
) {
} else if (tcount
> (filesize
- cur_bytes
) / objsz
) {
tcount
= (filesize
- cur_bytes
) / objsz
;
if (!star
|| tcount
== 0)
if (cur_bytes
>= blocksize
) {
} else if (tcount
> (blocksize
- cur_bytes
) / objsz
) {
tcount
= (blocksize
- cur_bytes
) / objsz
;
if (!star
|| tcount
== 0)
* print_check - check if the index needs to be printed and delete
* rows of zeros from the output.
print_check(lptr
, tcount
, tbase
, i
)
register int j
, k
, temp
= BYTESPERLINE
/ objsz
;
unsigned short *tsptr
, *sptr
;
sptr
= (unsigned short *)lptr
;
if (*tcount
>= temp
- 1) {
if (j
> (i
+ temp
- 1)) {
cur_bytes
+= BYTESPERLINE
;
return((unsigned long *)sptr
);
* index - print a byte index for the printout in base b
* print - print out the value to digits places with/without
* leading zeros and right/left justified in the current base.
print(value
, fieldsz
, digits
, lead
)
int value
, fieldsz
, digits
, lead
;
register int i
, left
= 0;
char mode
= BASE
[base
- OCTAL
];
char *string
= &scratch
[0];
digits
= digits
+ (digits
- 1)/((base
>> 1) - 1) + 1;
sprintf(string
, "%%%c%d%d.%d%c",
'-', 0, digits
, lead
, mode
);
sprintf(string
, "%%%d%d.%d%c", 0, digits
, lead
, mode
);
sprintf(string
, "%%%c%d%c", '-', digits
, mode
);
sprintf(string
, "%%%d%c", digits
, mode
);
for (i
= 0; i
< fieldsz
- digits
; i
++)
* Print out the contents of a superblock.
if (fs
->fs_postblformat
== FS_42POSTBLFMT
)
printf("magic\t%x\tformat\t%s\ttime\t%s", fs
->fs_magic
,
fs
->fs_postblformat
== FS_42POSTBLFMT
? "static" : "dynamic",
printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
fs
->fs_cstotal
.cs_nbfree
, fs
->fs_cstotal
.cs_ndir
,
fs
->fs_cstotal
.cs_nifree
, fs
->fs_cstotal
.cs_nffree
);
printf("ncg\t%d\tncyl\t%d\tsize\t%d\tblocks\t%d\n",
fs
->fs_ncg
, fs
->fs_ncyl
, fs
->fs_size
, fs
->fs_dsize
);
printf("bsize\t%d\tshift\t%d\tmask\t0x%08x\n",
fs
->fs_bsize
, fs
->fs_bshift
, fs
->fs_bmask
);
printf("fsize\t%d\tshift\t%d\tmask\t0x%08x\n",
fs
->fs_fsize
, fs
->fs_fshift
, fs
->fs_fmask
);
printf("frag\t%d\tshift\t%d\tfsbtodb\t%d\n",
fs
->fs_frag
, fs
->fs_fragshift
, fs
->fs_fsbtodb
);
printf("cpg\t%d\tbpg\t%d\tfpg\t%d\tipg\t%d\n",
fs
->fs_cpg
, fs
->fs_fpg
/ fs
->fs_frag
, fs
->fs_fpg
, fs
->fs_ipg
);
printf("minfree\t%d%%\toptim\t%s\tmaxcontig %d\tmaxbpg\t%d\n",
fs
->fs_minfree
, fs
->fs_optim
== FS_OPTSPACE
? "space" : "time",
fs
->fs_maxcontig
, fs
->fs_maxbpg
);
printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
fs
->fs_rotdelay
, fs
->fs_headswitch
, fs
->fs_trkseek
, fs
->fs_rps
);
printf("ntrak\t%d\tnsect\t%d\tnpsect\t%d\tspc\t%d\n",
fs
->fs_ntrak
, fs
->fs_nsect
, fs
->fs_npsect
, fs
->fs_spc
);
printf("trackskew %d\tinterleave %d\n",
fs
->fs_trackskew
, fs
->fs_interleave
);
printf("nindir\t%d\tinopb\t%d\tnspf\t%d\n",
fs
->fs_nindir
, fs
->fs_inopb
, fs
->fs_nspf
);
printf("sblkno\t%d\tcblkno\t%d\tiblkno\t%d\tdblkno\t%d\n",
fs
->fs_sblkno
, fs
->fs_cblkno
, fs
->fs_iblkno
, fs
->fs_dblkno
);
printf("sbsize\t%d\tcgsize\t%d\tcgoffset %d\tcgmask\t0x%08x\n",
fs
->fs_sbsize
, fs
->fs_cgsize
, fs
->fs_cgoffset
, fs
->fs_cgmask
);
printf("csaddr\t%d\tcssize\t%d\tshift\t%d\tmask\t0x%08x\n",
fs
->fs_csaddr
, fs
->fs_cssize
, fs
->fs_csshift
, fs
->fs_csmask
);
printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\n",
fs
->fs_cgrotor
, fs
->fs_fmod
, fs
->fs_ronly
);
printf("blocks available in each of %d rotational positions",
printf("insufficient space to maintain rotational tables\n");
for (c
= 0; c
< fs
->fs_cpc
; c
++) {
printf("\ncylinder number %d:", c
);
for (i
= 0; i
< fs
->fs_nrpos
; i
++) {
if (fs_postbl(fs
, c
)[i
] == -1)
printf("\n position %d:\t", i
);
for (j
= fs_postbl(fs
, c
)[i
], k
= 1; ;
j
+= fs_rotbl(fs
)[j
], k
++) {
if (fs_rotbl(fs
)[j
] == 0)
printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
for (i
= 0, j
= 0; i
< fs
->fs_cssize
; i
+= fs
->fs_bsize
, j
++) {
size
= fs
->fs_cssize
- i
< fs
->fs_bsize
?
fs
->fs_cssize
- i
: fs
->fs_bsize
;
fs
->fs_csp
[j
] = (struct csum
*)calloc(1, size
);
lseek(fd
, fsbtodb(fs
, (fs
->fs_csaddr
+ j
* fs
->fs_frag
)) *
fs
->fs_fsize
/ fsbtodb(fs
, 1), 0);
if (read(fd
, fs
->fs_csp
[j
], size
) != size
) {
for (i
= 0; i
< fs
->fs_ncg
; i
++) {
struct csum
*cs
= &fs
->fs_cs(fs
, i
);
cs
->cs_nbfree
, cs
->cs_ndir
, cs
->cs_nifree
, cs
->cs_nffree
);
if (fs
->fs_ncyl
% fs
->fs_cpg
) {
printf("cylinders in last group %d\n",
i
= fs
->fs_ncyl
% fs
->fs_cpg
);
printf("blocks in last group %d\n",
i
* fs
->fs_spc
/ NSPB(fs
));
* Print out the contents of a cylinder group.
printf("\ncg %d:\n", cg
->cg_cgx
);
printf("magic\t%x\ttell\t%x\ttime\t%s",
fs
->fs_postblformat
== FS_42POSTBLFMT
?
((struct ocg
*)cg
)->cg_magic
: cg
->cg_magic
,
fsbtodb(fs
, cgtod(fs
, cg
->cg_cgx
)) * fs
->fs_fsize
/ fsbtodb(fs
, 1),
printf("cgx\t%d\tncyl\t%d\tniblk\t%d\tndblk\t%d\n",
cg
->cg_cgx
, cg
->cg_ncyl
, cg
->cg_niblk
, cg
->cg_ndblk
);
printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
cg
->cg_cs
.cs_nbfree
, cg
->cg_cs
.cs_ndir
,
cg
->cg_cs
.cs_nifree
, cg
->cg_cs
.cs_nffree
);
printf("rotor\t%d\tirotor\t%d\tfrotor\t%d\nfrsum",
cg
->cg_rotor
, cg
->cg_irotor
, cg
->cg_frotor
);
for (i
= 1, j
= 0; i
< fs
->fs_frag
; i
++) {
printf("\t%d", cg
->cg_frsum
[i
]);
j
+= i
* cg
->cg_frsum
[i
];
printf("\nsum of frsum: %d\niused:\t", j
);
pbits(cg_inosused(cg
), fs
->fs_ipg
);
pbits(cg_blksfree(cg
), fs
->fs_fpg
);
for (i
= 0; i
< fs
->fs_cpg
; i
++) {
if (cg_blktot(cg
)[i
] == 0)
printf(" c%d:\t(%d)\t", i
, cg_blktot(cg
)[i
]);
for (j
= 0; j
< fs
->fs_nrpos
; j
++) {
fs_postbl(fs
, i
% fs
->fs_cpc
)[j
] == -1)
printf(" %d", cg_blks(fs
, cg
, i
)[j
]);
* Print out the contents of a bit array.
for (i
= 0; i
< max
; i
++)
printf(",%s", count
% 6 ? " " : "\n\t");
while ((i
+1)<max
&& isset(cp
, i
+1))
* bcomp - used to check for block over/under flows when stepping through
if (lblkno(fs
, addr
) == (bhdr
.fwd
)->blkno
)
* bmap - maps the logical block number of a file into
* the corresponding physical block on the file
register struct dinode
*ip
;
ip
= (struct dinode
*)cur_ino
;
addr
= (long)&ip
->di_db
[bn
];
cur_bytes
= bn
* BLKSIZE
;
return(nullblk(nb
=get(LONG
)) ? 0L : nb
);
for (j
= NIADDR
; j
> 0; j
--) {
printf("file too big\n");
addr
= (long)&ip
->di_ib
[NIADDR
- j
];
for (; j
<= NIADDR
; j
++) {
addr
= (nb
<< FRGSHIFT
) + ((bn
/ sh
) % NINDIR(fs
)) * LONG
;
if (nullblk(nb
= get(LONG
)))