From: <ls...@us...> - 2009-11-23 17:09:15
|
Revision: 5688 http://jnode.svn.sourceforge.net/jnode/?rev=5688&view=rev Author: lsantha Date: 2009-11-23 17:09:02 +0000 (Mon, 23 Nov 2009) Log Message: ----------- Extensions to du command. Applied patch by Mario Zsilak. Modified Paths: -------------- trunk/cli/descriptors/org.jnode.command.file.xml trunk/cli/src/commands/org/jnode/command/file/DuCommand.java Modified: trunk/cli/descriptors/org.jnode.command.file.xml =================================================================== --- trunk/cli/descriptors/org.jnode.command.file.xml 2009-10-23 08:21:09 UTC (rev 5687) +++ trunk/cli/descriptors/org.jnode.command.file.xml 2009-11-23 17:09:02 UTC (rev 5688) @@ -151,14 +151,29 @@ <argument argLabel="path" description="list a file or directory"/> </syntax> <syntax alias="du"> - <sequence description="print file sizes"> + <sequence description="Disk Usage - report the amount of disk space used by the specified directory and for each subdirectory."> <repeat minCount="0"> <argument argLabel="directory" description="directory to start printing sizes recursively"/> </repeat> <optionSet> - <option argLabel="sum" shortName="s" longName="summarize"/> - <option argLabel="all" shortName="a" longName="all"/> - <option argLabel="human-readable" shortName="h" longName="human-readable"/> + <option argLabel="all" shortName="a" longName="all"/> + <option argLabel="block-size-1" shortName="b" longName="bytes"/> + <option argLabel="total" shortName="c" longName="total"/> + <option argLabel="derefArgs" shortName="D" longName="dereference-args"/> + <option argLabel="human-readable-1024" shortName="h" longName="human-readable"/> + <option argLabel="human-readable-1000" shortName="H" longName="si"/> + <option argLabel="block-size-1024" shortName="k" longName="kilobytes"/> + <option argLabel="count-links" shortName="l" longName="count-links"/> + <option argLabel="dereference" shortName="L" longName="dereference"/> + <option argLabel="max-depth" shortName="" longName="max-depth"/> <!-- max-depth has no shortname --> + <option argLabel="block-size-1024x1024" shortName="m" longName="megabytes"/> + <option argLabel="summarize" shortName="s" longName="summarize"/> + <option argLabel="separate-dirs" shortName="S" longName="separate-dirs"/> + <option argLabel="one-file-system" shortName="x" longName="one-file-system"/> <!-- can't test this currently --> + <option argLabel="exclude" shortName="" longName="exclude"/> <!-- exclude has no shortname --> + <option argLabel="exclude-from" shortName="X" longName="exclude-from"/> + <option argLabel="block-size-custom" shortName="B" longName="block-size"/> <!-- not in man page, but works on unix like systems --> + <option argLabel="filesystem-block-size" shortName="" longName="fs-block-size"/> <!-- not in man page, but works on unix like systems --> </optionSet> </sequence> </syntax> Modified: trunk/cli/src/commands/org/jnode/command/file/DuCommand.java =================================================================== --- trunk/cli/src/commands/org/jnode/command/file/DuCommand.java 2009-10-23 08:21:09 UTC (rev 5687) +++ trunk/cli/src/commands/org/jnode/command/file/DuCommand.java 2009-11-23 17:09:02 UTC (rev 5688) @@ -1,5 +1,5 @@ /* - * $Id: CdCommand.java 4975 2009-02-02 08:30:52Z lsantha $ + * $Id: DuCommand.java 4975 2009-02-02 08:30:52Z lsantha $ * * Copyright (C) 2003-2009 JNode.org * @@ -22,175 +22,475 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.util.Map; -import java.util.NavigableMap; -import java.util.TreeMap; -import java.util.Map.Entry; +import java.util.Stack; +import javax.naming.NameNotFoundException; + +import org.apache.log4j.Logger; import org.jnode.command.util.AbstractDirectoryWalker; +import org.jnode.driver.Device; +import org.jnode.driver.block.FSBlockDeviceAPI; +import org.jnode.fs.service.FileSystemService; +import org.jnode.naming.InitialNaming; import org.jnode.shell.AbstractCommand; import org.jnode.shell.syntax.Argument; import org.jnode.shell.syntax.FileArgument; import org.jnode.shell.syntax.FlagArgument; +import org.jnode.shell.syntax.IntegerArgument; +import org.jnode.shell.syntax.StringArgument; import org.jnode.util.NumberUtils; +import org.jnode.vm.VmExit; -/* +/** * @author Alexander Kerner + * @author Mario Zsilak */ public class DuCommand extends AbstractCommand { - - private static final String err_perm = "Permission denied for '%s'%n"; - - private abstract class Walker extends AbstractDirectoryWalker { - protected final TreeMap<File, Long> map = new TreeMap<File, Long>(); - protected final boolean humanReadable; + private static final String HELP_SUPER = + "With no arguments, `du' reports the disk space for the current directory. Normally the disk space is printed in units of 1024 bytes, but this can be overridden"; + private static final String HELP_DIR = "directory to start printing sizes recursively"; + private static final String HELP_ALL = "Show counts for all files, not just directories."; + private static final String HELP_BLOCK_SIZE_1 = + "Print sizes in bytes, overriding the default block size"; + private static final String HELP_TOTAL = + "Print a grand total of all arguments after all arguments have been processed. This can be used to find out the total disk usage of a given set of files or directories."; + private static final String HELP_DEREF_ARGS = + "Dereference symbolic links that are command line arguments. Does not affect other symbolic links. This is helpful for finding out the disk usage of directories, such as `/usr/tmp', which are often symbolic links."; + private static final String HELP_HUMAN_READABLE_1024 = + "Append a size letter such as `M' for megabytes to each size. Powers of 1024 are used, not 1000; `M' stands for 1,048,576 bytes. Use the `-H' or `--si' option if you prefer powers of 1000."; + private static final String HELP_HUMAN_READABLE_1000 = + "Append a size letter such as `M' for megabytes to each size. (SI is the International System of Units, which defines these letters as prefixes.) Powers of 1000 are used, not 1024; `M' stands for 1,000,000 bytes. Use the `-h' or `--human-readable' option if you prefer powers of 1024."; + private static final String HELP_BLOCK_SIZE_1024 = + "Print sizes in 1024-byte blocks, overriding the default block size"; + private static final String HELP_COUNT_LINKS = + "Count the size of all files, even if they have appeared already (as a hard link)."; + private static final String HELP_DEREF = + "Dereference symbolic links (show the disk space used by the file or directory that the link points to instead of the space used by the link)."; + private static final String HELP_MAX_DEPTH = + "Show the total for each directory (and file if -all) that is at most MAX_DEPTH levels down from the root of the hierarchy. The root is at level 0, so `du --max-depth=0' is equivalent to `du -s'."; + private static final String HELP_BLOCK_SIZE_1024x1024 = + "Print sizes in megabyte (that is, 1,048,576-byte) blocks."; + private static final String HELP_SUM = "Display only a total for each argument."; + private static final String HELP_SEPERATE_DIRS = + "Report the size of each directory separately, not including the sizes of subdirectories."; + private static final String HELP_ONE_FS = + "Skip directories that are on different filesystems from the one that the argument being processed is on."; + private static final String HELP_EXCLUDE = + "When recursing, skip subdirectories or files matching PAT. For example, `du --exclude='*.o'' excludes files whose names end in `.o'."; + private static final String HELP_EXCLUDE_FROM = + "Like `--exclude', except take the patterns to exclude from FILE, one per line. If FILE is `-', take the patterns from standard input."; + private static final String HELP_BLOCK_SIZE_CUSTOM = + "Print sizes in the user defined block size, overriding the default block size"; + private static final String HELP_FS_BLOCK_SIZE = + "Overrides the filesystem block size -- use it for testing"; - Walker(boolean humanReadable) { - this.humanReadable = humanReadable; + private final FileArgument argDir = + new FileArgument("directory", + Argument.OPTIONAL | Argument.MULTIPLE | Argument.EXISTING, HELP_DIR); + private final FlagArgument argAll = new FlagArgument("all", Argument.OPTIONAL, HELP_ALL); + private final FlagArgument argBlockSize_1 = + new FlagArgument("block-size-1", Argument.OPTIONAL, HELP_BLOCK_SIZE_1); + private final FlagArgument argTotal = new FlagArgument("total", Argument.OPTIONAL, HELP_TOTAL); + private final FlagArgument argDerefArgs = + new FlagArgument("derefArgs", Argument.OPTIONAL, HELP_DEREF_ARGS); + private final FlagArgument argHumanReadable_1024 = + new FlagArgument("human-readable-1024", Argument.OPTIONAL, HELP_HUMAN_READABLE_1024); + private final FlagArgument argHumanReadable_1000 = + new FlagArgument("human-readable-1000", Argument.OPTIONAL, HELP_HUMAN_READABLE_1000); + private final FlagArgument argBlockSize_1024 = + new FlagArgument("block-size-1024", Argument.OPTIONAL, HELP_BLOCK_SIZE_1024); + private final FlagArgument argCountLinks = + new FlagArgument("count-links", Argument.OPTIONAL, HELP_COUNT_LINKS); + private final FlagArgument argDereference = + new FlagArgument("dereference", Argument.OPTIONAL, HELP_DEREF); + private final IntegerArgument argMaxDepth = + new IntegerArgument("max-depth", Argument.OPTIONAL, HELP_MAX_DEPTH); + private final FlagArgument argBlockSize_1024x1024 = + new FlagArgument("block-size-1024x1024", Argument.OPTIONAL, HELP_BLOCK_SIZE_1024x1024); + private final FlagArgument argSum = new FlagArgument("summarize", Argument.OPTIONAL, HELP_SUM); + private final FlagArgument argSeperateDirs = + new FlagArgument("separate-dirs", Argument.OPTIONAL, HELP_SEPERATE_DIRS); + private static final FlagArgument argOneFS = + new FlagArgument("one-file-system", Argument.OPTIONAL, HELP_ONE_FS); + private final StringArgument argExclude = + new StringArgument("exclude", Argument.OPTIONAL, HELP_EXCLUDE); + private static final StringArgument argExcludeFrom = + new StringArgument("exclude-from", Argument.OPTIONAL, HELP_EXCLUDE_FROM); + private final IntegerArgument argBlockSize_Custom = + new IntegerArgument("block-size-custom", Argument.OPTIONAL, HELP_BLOCK_SIZE_CUSTOM); + private final IntegerArgument argFilesystemBlockSize = + new IntegerArgument("filesystem-block-size", Argument.OPTIONAL, HELP_FS_BLOCK_SIZE); + + private static final String ERR_PERMISSION = "Permission denied for '%s'%n"; + + private static final int DEFAULT_FILESYSTEM_BLOCK_SIZE = 1024; + private static final int DEFAULT_DISPLAY_BLOCK_SIZE = 1024; + + private Logger logger = Logger.getLogger(getClass()); + + private int fsBlockSize; + private int displayBlockSize; + private PrintWriter out; + private PrintWriter err; + + public static void main(String[] args) throws IOException { + new DuCommand().execute(); + } + + public DuCommand() { + super(HELP_SUPER); + registerArguments(argDir, argAll, argBlockSize_1, argTotal, argDerefArgs, + argHumanReadable_1024, argHumanReadable_1000, argBlockSize_1024, argCountLinks, + argDereference, argMaxDepth, argBlockSize_1024x1024, argSum, argSeperateDirs, + argOneFS, argExclude, argExcludeFrom, argBlockSize_Custom, argFilesystemBlockSize); + } + + public void execute() throws IOException { + + Walker walker = null; + File[] startPoints = null; + + out = getOutput().getPrintWriter(); + err = getError().getPrintWriter(); + + if (argAll.isSet() && argSum.isSet()) { + err.println("Summarize and show all not possible at the some time!"); + throw new VmExit(1); } - @Override - public void handleDir(File file) { - handleAll(file); + if (argDerefArgs.isSet()) { + logger.warn(argDerefArgs.getLabel() + " is currently not supported"); } - @Override - public void handleFile(File file) { - handleAll(file); + if (argOneFS.isSet()) { + logger.warn(argOneFS.getLabel() + " is currently not supported"); } - - @Override - protected void handleRestrictedFile(File file) throws IOException { - err.format(err_perm, file); + + if (argExcludeFrom.isSet()) { + logger.warn(argExcludeFrom.getLabel() + " is currently not supported"); } - private void handleAll(File file) { - map.put(file, file.length()); + if (argDereference.isSet()) { + logger.warn(argDereference.getLabel() + " is currently not supported"); } - protected TreeMap<File, Long> summariseIt(TreeMap<File, Long> map) { - TreeMap<File, Long> result = new TreeMap<File, Long>(); - NavigableMap<File, Long> navMap = map.descendingMap(); - Long tmpSize = 0L; - while (navMap.size() != 0) { - Entry<File, Long> e = navMap.pollFirstEntry(); - File key = e.getKey(); - Long value = e.getValue(); - tmpSize += key.length(); + if (argCountLinks.isSet()) { + logger.warn(argCountLinks.getLabel() + " is currently not supported"); + } - if (key.isFile()) { - result.put(key, value); - } else if (key.isDirectory()) { - result.put(key, tmpSize); - } else { - // ignore unknown file type - } + startPoints = argDir.getValues(); + + if (startPoints.length == 0) { + startPoints = new File[] {new File(System.getProperty("user.dir"))}; + } + + if (argFilesystemBlockSize.isSet()) + fsBlockSize = argFilesystemBlockSize.getValue(); + else { + fsBlockSize = getFsBlockSize(startPoints[0]); + } + + if (argBlockSize_Custom.isSet()) { + displayBlockSize = argBlockSize_Custom.getValue(); + } else if (argBlockSize_1024x1024.isSet()) { + displayBlockSize = 1024 * 1024; + } else if (argBlockSize_1024.isSet()) { + displayBlockSize = 1024; + } else if (argBlockSize_1.isSet()) { + displayBlockSize = 1; + } else { + displayBlockSize = DEFAULT_DISPLAY_BLOCK_SIZE; + } + + if (argSum.isSet() || argTotal.isSet()) { + + long total = 0; + + for (File start : startPoints) { + walker = new Walker(argMaxDepth, argExclude); + walker.walk(start); + + printSize(start.getAbsolutePath(), walker.getSize()); + total += walker.getSize(); } - return result; + + if (argTotal.isSet()) { + printSize("Total", total); + } + } else { + new Walker(argMaxDepth, argExclude).walk(startPoints); } } - private class AllWalker extends Walker { + private void printFileSize(final File filename, final long size) { + if (argAll.isSet()) { + out.println(size + "\t" + filename); + } + } - AllWalker(boolean humanReadable) { - super(humanReadable); + private void printDirSize(final File filename, final long dirSizeOnly, final long subDirSize) { + if (!argSum.isSet()) { + if (argSeperateDirs.isSet()) { + out.println(sizeToString(dirSizeOnly) + "\t" + filename); + } else { + out.println(sizeToString(dirSizeOnly + subDirSize) + "\t" + filename); + } } + } - @Override - protected void lastAction(boolean wasCancelled) { - Map<File, Long> summarisedMap = summariseIt(map); - for (Entry<File, Long> e : summarisedMap.entrySet()) { - if (humanReadable) - out.println(NumberUtils.toBinaryByte(e.getValue()) + "\t" + e.getKey()); - else - out.println(e.getValue() + "\t" + e.getKey()); + private void printSize(final String filename, final long size) { + out.println(sizeToString(size) + "\t" + filename); + } + + private void log(String message) { + // logger.debug(message); + } + + /** + * should be in NumberUtils I guess + * + * @param lenght in bytes of the file / directory + * @return the number of blocks it uses up depending on the int + * displayBlockSize + */ + private long calc(long bytes) { + + double factor = fsBlockSize / displayBlockSize; + long ret = -1; + + if (fsBlockSize > displayBlockSize) { + if (bytes % displayBlockSize == 0) { + ret = bytes / displayBlockSize; + } else { + ret = (long) ((bytes / (fsBlockSize) + 1) * factor); } + } else { + if (bytes % displayBlockSize == 0) { + ret = bytes / displayBlockSize; + } else { + ret = (long) ((bytes / (displayBlockSize) + 1)); + } } + + return ret; } - private class OnlyDirsWalker extends Walker { + private String sizeToString(long size) { - OnlyDirsWalker(boolean humanReadable) { - super(humanReadable); + String retValue = null; + + if (argHumanReadable_1024.isSet()) { + retValue = NumberUtils.toBinaryByte(size); + } else if (argHumanReadable_1000.isSet()) { + retValue = NumberUtils.toDecimalByte(size); + } else { + retValue = String.valueOf(size); } - @Override - protected void lastAction(boolean wasCancelled) { - Map<File, Long> summarisedMap = summariseIt(map); - for (Entry<File, Long> e : summarisedMap.entrySet()) { - if (e.getKey().isDirectory()) { - if (humanReadable) - out.println(NumberUtils.toBinaryByte(e.getValue()) + "\t" + e.getKey()); - else - out.println(e.getValue() + "\t" + e.getKey()); + return retValue; + } + + /** + * taken from the DfCommand + */ + private int getFsBlockSize(File file) throws IOException { + + int retValue = DEFAULT_FILESYSTEM_BLOCK_SIZE; // default block size + FileSystemService fss = null; + Device device = null; + String path = null; + String mp = null; + + try { + fss = InitialNaming.lookup(FileSystemService.NAME); + path = file.getCanonicalPath(); + mp = null; + + for (String mountPoint : fss.getMountPoints().keySet()) { + if (path.startsWith(mountPoint)) { + if (mp != null) { + if (!mp.startsWith(mountPoint)) { + continue; + } + } + mp = mountPoint; } } + + if (mp != null) { + device = fss.getMountPoints().get(mp).getDevice(); + + if (device instanceof FSBlockDeviceAPI) { + retValue = ((FSBlockDeviceAPI) device).getSectorSize(); + + } else { + logger.warn("No FSBlockDeviceAPI device for device" + device); + logger.info("Using default block-size: " + DEFAULT_FILESYSTEM_BLOCK_SIZE); + logger.info("override with --fs-block-size"); + } + } else { + + logger.warn("No mount point found for " + path); + + for (String mountPoint : fss.getMountPoints().keySet()) { + logger.warn("mountpoints on system: " + mountPoint); + } + + logger.info("Using default block-size: " + DEFAULT_FILESYSTEM_BLOCK_SIZE); + logger.info("override with --fs-block-size"); + } + + } catch (NameNotFoundException e) { + logger.warn("FileSystemService lookup failed ...", e); + logger.info("Using default block-size: " + DEFAULT_FILESYSTEM_BLOCK_SIZE); + logger.info("override with --fs-block-size"); } + + return retValue; } - private class TotalWalker extends Walker { + private class Directory { + private Directory parent = null; + private File directory = null; + private Stack<Directory> subDirs = null; + private long size = 0; - TotalWalker(boolean humanReadable) { - super(humanReadable); + public Directory(Directory parent, File directory) { + this.parent = parent; + this.directory = directory; + subDirs = new Stack<Directory>(); } - @Override - protected void lastAction(boolean wasCancelled) { - TreeMap<File, Long> summarisedMap = summariseIt(map); - Entry<File, Long> e = summarisedMap.firstEntry(); - if (humanReadable) - out.println(NumberUtils.toBinaryByte(e.getValue()) + "\t" + e.getKey()); - else - out.println(e.getValue() + "\t" + e.getKey()); + public Directory addDirectory(File file) { + Directory retValue = null; + if (file.getParentFile().equals(directory)) { + retValue = new Directory(this, file); + subDirs.push(retValue); + } else { + logger.warn("addDirectory: tried to add " + file + " to " + directory); + } + + return retValue; } - } - private PrintWriter out; - private PrintWriter err; + public void addFile(File file) { + if (!file.getParentFile().equals(directory)) { + logger.warn("addFile: tried to add " + file + " to " + directory); + } - private static final String HELP_TOTAL = "display only a total for each argument"; - private static final String HELP_ALL = "write counts for all files, not just directories"; - private static final String HELP_SUPER = "print file sizes"; - private static final String HELP_DIR = "directory to start printing sizes"; - private static final String HELP_HUMAN_READABLE = "print sizes in human readable format (e.g., 1K 234M 2G)"; + printFileSize(file, calc(file.length())); + size += calc(file.length()); + } - private final FlagArgument totalArg; - private final FlagArgument allArg; - private final FileArgument dirArg; - private final FlagArgument humanReadableArg; + public Directory getParent() { - public DuCommand() { - super(HELP_SUPER); - totalArg = new FlagArgument("sum", Argument.OPTIONAL, HELP_TOTAL); - allArg = new FlagArgument("all", Argument.OPTIONAL, HELP_ALL); - dirArg = new FileArgument("directory", Argument.OPTIONAL | Argument.MULTIPLE, HELP_DIR); - humanReadableArg = new FlagArgument("human-readable", Argument.OPTIONAL, HELP_HUMAN_READABLE); - registerArguments(totalArg, allArg, humanReadableArg, dirArg); - } + long dirSize = size + calc(directory.length()); // only the size for + // this directory + + // files (in other + // words: excludes + // the size of + // subDirs) + long subDirSize = 0; - public static void main(String[] args) throws IOException { - new DuCommand().execute(); + while (!subDirs.isEmpty()) { + subDirSize += subDirs.pop().getSize(); + } + + printDirSize(directory, dirSize, subDirSize); + + size = dirSize + subDirSize; + + return parent; + } + + public long getSize() { + return size; + } + + public boolean equals(Object other) { + boolean retValue = false; + + if (other instanceof Directory) { + retValue = (other != null && ((Directory) other).directory.equals(this.directory)); + } else if (other instanceof File) { + retValue = (other != null && ((File) other).equals(this.directory)); + } + + return retValue; + } + + @Override + public String toString() { + return directory.toString(); + } } - public void execute() throws IOException { - out = getOutput().getPrintWriter(); - err = getError().getPrintWriter(); - Walker walker = null; - if (totalArg.isSet()) { - walker = new TotalWalker(humanReadableArg.isSet()); - } else if (allArg.isSet()) { - walker = new AllWalker(humanReadableArg.isSet()); - } else { - walker = new OnlyDirsWalker(humanReadableArg.isSet()); + private class Walker extends AbstractDirectoryWalker { + + long totalSize; + protected Directory root = null; + protected Directory currentDir = null; + + private Walker(IntegerArgument argMaxDepth, StringArgument argExclude) { + super(); + + if (argMaxDepth.isSet()) { + super.setMaxDepth(argMaxDepth.getValue().longValue()); + } + + if (argExclude.isSet()) { + super.addFilter(new RegexPatternFilter(argExclude.getValue(), true)); + } } - - if (dirArg.isSet()) { - walker.walk(dirArg.getValues()); - } else { - walker.walk(new File(System.getProperty("user.dir"))); + + public long getSize() { + return totalSize; } + + @Override + protected void handleStartingDir(File file) throws IOException { + log("starting dir: " + file); + root = new Directory(null, file); + } + + @Override + protected void lastAction(boolean wasCancelled) { + root.getParent(); + totalSize = root.getSize(); + } + + @Override + public void handleDir(File file) { + log("handleDir: " + file); + + if (currentDir == null || currentDir.equals(file)) { + currentDir = root; + return; + } + + while (!currentDir.equals(file.getParentFile())) { + log("in while"); + currentDir = currentDir.getParent(); + } + + currentDir = currentDir.addDirectory(file); + } + + @Override + public void handleFile(File file) { + log("handleFile: " + file); + + while (!currentDir.equals(file.getParentFile())) { + currentDir = currentDir.getParent(); + } + currentDir.addFile(file); + } + + @Override + protected void handleRestrictedFile(File file) throws IOException { + err.format(ERR_PERMISSION, file); + } } } - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |