/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hdfs.tools.offlineImageViewer; import java.io.IOException; import java.util.Formatter; import java.util.LinkedList; /** * LsImageVisitor displays the blocks of the namespace in a format very similar * to the output of ls/lsr. Entries are marked as directories or not, * permissions listed, replication, username and groupname, along with size, * modification date and full path. * * Note: A significant difference between the output of the lsr command * and this image visitor is that this class cannot sort the file entries; * they are listed in the order they are stored within the fsimage file. * Therefore, the output of this class cannot be directly compared to the * output of the lsr command. */ class LsImageVisitor extends TextWriterImageVisitor { final private LinkedList<ImageElement> elemQ = new LinkedList<ImageElement>(); private int numBlocks; private String perms; private int replication; private String username; private String group; private long filesize; private String modTime; private String path; private String linkTarget; private boolean inInode = false; final private StringBuilder sb = new StringBuilder(); final private Formatter formatter = new Formatter(sb); public LsImageVisitor(String filename) throws IOException { super(filename); } public LsImageVisitor(String filename, boolean printToScreen) throws IOException { super(filename, printToScreen); } /** * Start a new line of output, reset values. */ private void newLine() { numBlocks = 0; perms = username = group = path = linkTarget = ""; filesize = 0l; replication = 0; inInode = true; } /** * All the values have been gathered. Print them to the console in an * ls-style format. */ private final static int widthRepl = 2; private final static int widthUser = 8; private final static int widthGroup = 10; private final static int widthSize = 10; private final static int widthMod = 10; private final static String lsStr = " %" + widthRepl + "s %" + widthUser + "s %" + widthGroup + "s %" + widthSize + "d %" + widthMod + "s %s"; private void printLine() throws IOException { sb.append(numBlocks < 0 ? "d" : "-"); sb.append(perms); if (0 != linkTarget.length()) { path = path + " -> " + linkTarget; } formatter.format(lsStr, replication > 0 ? replication : "-", username, group, filesize, modTime, path); sb.append("\n"); write(sb.toString()); sb.setLength(0); // clear string builder inInode = false; } @Override void start() throws IOException {} @Override void finish() throws IOException { super.finish(); } @Override void finishAbnormally() throws IOException { System.out.println("Input ended unexpectedly."); super.finishAbnormally(); } @Override void leaveEnclosingElement() throws IOException { ImageElement elem = elemQ.pop(); if(elem == ImageElement.INODE) printLine(); } // Maintain state of location within the image tree and record // values needed to display the inode in ls-style format. @Override void visit(ImageElement element, String value) throws IOException { if(inInode) { switch(element) { case INODE_PATH: if(value.equals("")) path = "/"; else path = value; break; case PERMISSION_STRING: perms = value; break; case REPLICATION: replication = Integer.valueOf(value); break; case USER_NAME: username = value; break; case GROUP_NAME: group = value; break; case NUM_BYTES: filesize += Long.valueOf(value); break; case MODIFICATION_TIME: modTime = value; break; case SYMLINK: linkTarget = value; break; default: // This is OK. We're not looking for all the values. break; } } } @Override void visitEnclosingElement(ImageElement element) throws IOException { elemQ.push(element); if(element == ImageElement.INODE) newLine(); } @Override void visitEnclosingElement(ImageElement element, ImageElement key, String value) throws IOException { elemQ.push(element); if(element == ImageElement.INODE) newLine(); else if (element == ImageElement.BLOCKS) numBlocks = Integer.valueOf(value); } }