/** * 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.LinkedList; import org.apache.hadoop.hdfs.server.namenode.INode; /** * 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. */ public class LsImageVisitor extends TextWriterImageVisitor { final private LinkedList<ImageElement> elemQ = new LinkedList<ImageElement>(); private int numBlocks; private String perms; private String replication; private String username; private String group; private long filesize; private String modTime; private String path; private String linkTarget; private String type; private String hardlinkId; private boolean printHardlinkId = false; private boolean inInode = false; final private StringBuilder sb = new StringBuilder(); public LsImageVisitor(String filename) throws IOException { super(filename); } public LsImageVisitor(String filename, boolean printToScreen) throws IOException { super(filename, printToScreen); } public LsImageVisitor(String filename, boolean printToScreen, int numberOfParts, boolean printHardlinkId) throws IOException { super(filename, printToScreen, numberOfParts); this.printHardlinkId = printHardlinkId; } /** * Start a new line of output, reset values. */ private void newLine() { numBlocks = 0; perms = username = group = path = linkTarget = replication = hardlinkId = ""; filesize = 0l; type = INode.INodeType.REGULAR_INODE.toString(); 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 widthHardlinkId = 10; private final static int widthMod = 10; private final static String SPACE = " "; private void printLine() throws IOException { boolean hardlinktype = type.equals(INode.INodeType.HARDLINKED_INODE.toString()); String file = (numBlocks < 0 ) ? "d" : ( (hardlinktype) ? "h" : "-"); sb.append(file); sb.append(perms); if (0 != linkTarget.length()) { path = path + " -> " + linkTarget; } printString(replication.equals("0") ? "-" : replication, widthRepl, sb); if (printHardlinkId) { printString(file.equals("h") ? hardlinkId : "-", widthHardlinkId, sb); } printString(username, widthUser, sb); printString(group, widthGroup, sb); printString(Long.toString(filesize), widthSize, sb); printString(modTime, widthMod, sb); printString(path, 0, sb); sb.append("\n"); write(sb.toString()); sb.setLength(0); // clear string builder inInode = false; } private void printString(String s, int width, StringBuilder sb) { int filler = Math.max(0, width - s.length()); // insert an extra space for (int i = 0; i < filler + 1; i++) { sb.append(SPACE); } sb.append(s); } @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(); super.rollIfNeeded(); } } @Override void visit(ImageElement element, long value) throws IOException { if(inInode) { switch(element) { case NUM_BYTES: filesize += value; break; case MODIFICATION_TIME: visit(element, ImageLoaderCurrent.formatDate(value)); break; // these elements are not processed by LsImageVisitor // we can discard them prior to converting to String case ACCESS_TIME: case NS_QUOTA: case DS_QUOTA: case BLOCK_SIZE: case BLOCK_ID: case GENERATION_STAMP: break; default: visit(element, Long.toString(value)); } } } // 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 = 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; case INODE_TYPE: type = value; break; case INODE_HARDLINK_ID: hardlinkId = 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); } @Override void visitEnclosingElement(ImageElement element, ImageElement key, int value) throws IOException { elemQ.push(element); if(element == ImageElement.INODE) newLine(); else if (element == ImageElement.BLOCKS) numBlocks = value; } }