// Fetch the file for a given inode block-by-block, printing the data func PrintFile(fs *minixfs.FileSystem, inode *minixfs.Inode) { blocksize := fs.Block_size filesize := uint(inode.Size) position := uint(0) for position < filesize { blocknum := fs.ReadMap(inode, position) block, err := fs.GetFullDataBlock(blocknum) if err != nil { fmt.Printf("Failed to get data block: %d - %s\n", blocknum, err) break } if filesize-position >= blocksize { fmt.Printf("%s", block.Data) } else { fmt.Printf("%s", block.Data[:filesize-position]) } position = position + blocksize } fmt.Printf("\n") }
func repl(filename string, fs *minixfs.FileSystem) { fmt.Println("Welcome to the minixfs explorer!") fmt.Printf("Attached to %s\n", filename) fmt.Printf("Magic number is 0x%x\n", fs.Magic) fmt.Printf("Block size: %d\n", fs.Block_size) fmt.Printf("Zone shift: %d\n", fs.Log_zone_size) fmt.Println("Enter '?' for a list of commands.") pwd := []string{} buf := bufio.NewReader(os.Stdin) for { repl: // Print the prompt fmt.Printf("/%s> ", strings.Join(pwd, "/")) // Read another line of input from stdin read, err := buf.ReadString('\n') if err != nil { fmt.Print("\n") break } tokens := strings.Fields(read) if len(tokens) == 0 { continue } switch tokens[0] { case "?": fmt.Println("Commands:") fmt.Println("\t?\thelp") fmt.Println("\tcat\tshow file contents") fmt.Println("\tcd\tchange directory") fmt.Println("\tls\tshow directory listing") fmt.Println("\tmkdir\tcreate a new directory") fmt.Println("\tpwd\tshow current directory") fmt.Println("\talloc_bit\tallocate an inode/zone bit") fmt.Println("\tfree_bit\tfree an inode/zone bit") case "alloc_bit": usage := false which := uint(0) if len(tokens) != 2 { usage = true } else { if tokens[1] == "imap" { which = minixfs.IMAP } else if tokens[1] == "zmap" { which = minixfs.ZMAP } else { usage = true } } if usage { fmt.Println("Usage: alloc_bit [zone|imap]") continue } b := fs.AllocBit(which, 0) fmt.Printf("Allocated %s bit number %d\n", tokens[1], b) case "cat": blocknum := uint(fs.WorkDir.Zone[0]) dir_block, err := fs.GetDirectoryBlock(blocknum) if err != nil { fmt.Printf("Failed getting directory block: %d - %s\n", blocknum, err) } // Loop and find a file with the given name filename := tokens[1] fileinum := uint(0) for _, dirent := range dir_block.Data { if dirent.Inum > 0 { strend := bytes.IndexByte(dirent.Name[:], 0) if strend == -1 { strend = len(dirent.Name) - 1 } ename := string(dirent.Name[:strend]) if ename == filename { fileinode, err := fs.GetInode(uint(dirent.Inum)) if err != nil { fmt.Printf("Failed getting inode: %d\n", dirent.Inum) break } if fileinode.IsRegular() { fileinum = uint(dirent.Inum) fmt.Printf("Found file %s at inode %d\n", filename, fileinum) fmt.Printf("Contents:\n") PrintFile(fs, fileinode) goto repl } } } } fmt.Printf("Could not find a file named '%s'\n", filename) case "cd": if len(tokens) < 2 { fmt.Println("Usage: cd dirname") continue } blocknum := uint(fs.WorkDir.Zone[0]) dir_block, err := fs.GetDirectoryBlock(blocknum) if err != nil { fmt.Printf("Failed getting directory block: %d - %s\n", blocknum, err) } // Search through the directory entries and find one that // matches dirname dirname := tokens[1] dirinum := uint(0) for _, dirent := range dir_block.Data { if dirent.Inum > 0 { strend := bytes.IndexByte(dirent.Name[:], 0) if strend == -1 { strend = len(dirent.Name) - 1 } ename := string(dirent.Name[:strend]) if ename == dirname { dirinode, err := fs.GetInode(uint(dirent.Inum)) if err != nil { fmt.Printf("Failed getting inode: %d\n", dirent.Inum) break } if dirinode.IsDirectory() { dirinum = uint(dirent.Inum) fmt.Printf("Found directory %s at inode %d\n", dirname, dirinum) break } } } } if dirinum == 0 { fmt.Printf("Did not find a directory matching '%s'\n", dirname) } else if dirinum == fs.WorkDir.Inum() { // This would change us to the same directory, do nothing continue } else { newinode, err := fs.GetInode(dirinum) if err != nil { fmt.Printf("Failed to load inode %d: %s\n", dirinum, err) continue } if dirname == ".." { pwd = pwd[:len(pwd)-1] } else { pwd = append(pwd, tokens[1]) } // Change the fs work directory to the current directory fs.WorkDir = newinode continue } case "free_bit": usage := false which := uint(0) bit := uint(0) if len(tokens) != 3 { usage = true } else { if tokens[1] == "imap" { which = minixfs.IMAP } else if tokens[1] == "zmap" { which = minixfs.ZMAP } else { usage = true } var err os.Error bit, err = strconv.Atoui(tokens[2]) if err != nil { usage = true } } if usage { fmt.Println("Usage: free_bit <zone|imap> <bitnum>") continue } fs.FreeBit(which, bit) fmt.Printf("Freed %s bit number %d\n", tokens[1], bit) case "ls": blocknum := uint(fs.WorkDir.Zone[0]) dir_block, err := fs.GetDirectoryBlock(blocknum) if err != nil { fmt.Printf("Failed getting directory block: %d - %s\n", blocknum, err) } for _, dirent := range dir_block.Data { if dirent.Inum > 0 { dirinode, err := fs.GetInode(uint(dirent.Inum)) if err != nil { fmt.Printf("Failed getting inode: %d\n", dirent.Inum) break } mode := ModeString(dirinode) fmt.Printf("%s\t%d\t%s\n", mode, dirinode.Nlinks, dirent.Name) } } case "mkdir": mkdir(fs, tokens) case "pwd": fmt.Printf("Current directory is /%s\n", strings.Join(pwd, "/")) default: fmt.Printf("%s is not a valid command\n", tokens[0]) } } }