Package org.jnode.command.file

Source Code of org.jnode.command.file.DuCommand$Walker

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.command.file;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
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 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. (not implemented";
    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). (not implemented";
    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). (not implemented";
    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'. (not tested)";
    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. (not implemented)";
    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'. (not tested)";
    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. (not implemented)";
    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";

    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);
        }

        if (argDerefArgs.isSet()) {
            logger.warn(argDerefArgs.getLabel() + " is currently not supported");
        }

        if (argOneFS.isSet()) {
            logger.warn(argOneFS.getLabel() + " is currently not supported");
        }

        if (argExcludeFrom.isSet()) {
            logger.warn(argExcludeFrom.getLabel() + " is currently not supported");
        }

        if (argDereference.isSet()) {
            logger.warn(argDereference.getLabel() + " is currently not supported");
        }

        if (argCountLinks.isSet()) {
            logger.warn(argCountLinks.getLabel() + " is currently not supported");
        }

        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();
            }

            if (argTotal.isSet()) {
                printSize("Total", total);
            }
        } else {
            new Walker(argMaxDepth, argExclude).walk(startPoints);
        }
    }

    private void printFileSize(final File filename, final long size) {
        if (argAll.isSet()) {
            out.println(sizeToString(size) + '\t' + filename);
        }
    }

    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);
            }
        }
    }

    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 String sizeToString(long size) {

        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);
        }

        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 Directory {
        private Directory parent = null;
        private File directory = null;
        private Stack<Directory> subDirs = null;
        private long size = 0;

        public Directory(Directory parent, File directory) {
            this.parent = parent;
            this.directory = directory;
            subDirs = new Stack<Directory>();
        }

        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;
        }

        public void addFile(File file) {
            if (!file.getParentFile().equals(directory)) {
                logger.warn("addFile: tried to add " + file + " to " + directory);
            }

            printFileSize(file, calc(file.length()));
            size += calc(file.length());
        }

        public Directory getParent() {

            long dirSize = size + calc(directory.length());
            // only the size for this directory + files
            // (in other words: excludes the size of subDirs)
            long subDirSize = 0;

            while (!subDirs.isEmpty()) {
                subDirSize += subDirs.pop().getSize();
            }

            printDirSize(directory, dirSize, subDirSize);

            size = dirSize + subDirSize;

            return parent;
        }

        public long getSize() {
            return size;
        }
       
        @Override
        public int hashCode() {
            return directory.hashCode();
        }

        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();
        }
    }

    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));
            }
        }

        public long getSize() {
            return totalSize;
        }

        @Override
        /**
         * Set the "root" Directory to the Starting Dir
         */
        protected void handleStartingDir(File file) throws IOException {
            log("starting dir: " + file);
            root = new Directory(null, file);
        }

        @Override
        /**
         * Calculate the "root" directory and reset the "current" directory .. we are done for now
         */
        protected void lastAction(boolean wasCancelled) {
            root.getParent();
            currentDir = null;
            totalSize = root.getSize();
        }

        @Override
        /**
         * add the currently handled directory/file to the correct position in the hierarchy
         */
        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);
        }
    }
}
TOP

Related Classes of org.jnode.command.file.DuCommand$Walker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.