Package org.jnode.command.file

Source Code of org.jnode.command.file.DeleteCommand

/*
* $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.PrintWriter;
import java.io.Reader;
import java.io.IOException;

import javax.naming.NameNotFoundException;

import org.jnode.command.util.IOUtils;
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;
/**
* Delete a file or a empty directory
*
* @author Guillaume BINET (gbin@users.sourceforge.net)
* @author Andreas H\u00e4nel
* @author Levente S\u00e1ntha
* @author Martin Husted Hartvig (hagar at jnode.org)
* @author crawley@jnode.org
* @author chris boertien
* @see <a href="http://www.opengroup.org/onlinepubs/009695399/utilities/rm.html">POSIX "rm" command</a>
*/
public class DeleteCommand extends AbstractCommand {
   
    private static final String help_file = "the files or directories to be deleted";
    private static final String help_recurse = "if set, any directories are deleted recursively";
    private static final String help_force = "ignore non-existant files, never prompt";
    private static final String help_interact = "prompt before every delete";
    private static final String help_verbose = "give information on what is happening";
    private static final String help_onefs = "If recursively deleting, do not recurse into directories that reside" +
                                             "on a different file system";                              
    private static final String help_super = "Delete files or directories";
    private static final String str_not_exist = "File or Directory does not exist";
    private static final String str_is_dir = "Is a directory";
    private static final String str_is_dot = "Directory is '.' or '..'";
    private static final String str_is_mount = "Directory is a mount point";
    private static final String str_not_empty = "Directory is not empty";
    private static final String fmt_skip = "Skipping '%s' %s%n";
    private static final String fmt_removed_file = "Removed '%s'";
    private static final String fmt_removed_dir = "Removed directory '%s'";
    private static final String fmt_not_removed = "'%s' was not removed";
    private static final String fmt_ask_remove_file = "Remove regular file '%s'? [yes/no] ";
    private static final String fmt_ask_descend = "Descend into directory '%s'? [yes/no]";
    private static final String fmt_ask_remove_dir = "Remove directory '%s'? [yes/no]";

    private final FileArgument argPaths;
    private final FlagArgument flagRecurse;
    private final FlagArgument flagForce;
    private final FlagArgument flagInteract;
    private final FlagArgument flagVerbose;
    private final FlagArgument flagOneFS;
   
    private FileSystemService fss;
    private PrintWriter err;
    private PrintWriter out;
    private Reader in;
    private boolean recursive;
    private boolean force;
    private boolean interactive;
    private boolean verbose;
    private boolean onefs;

    public DeleteCommand() {
        super(help_super);
        argPaths     = new FileArgument("paths", Argument.MANDATORY | Argument.MULTIPLE | Argument.EXISTING, help_file);
        flagRecurse  = new FlagArgument("recursive", Argument.OPTIONAL, help_recurse);
        flagForce    = new FlagArgument("force", Argument.OPTIONAL, help_force);
        flagInteract = new FlagArgument("interactive", Argument.OPTIONAL, help_interact);
        flagVerbose  = new FlagArgument("verbose", Argument.OPTIONAL, help_verbose);
        flagOneFS    = new FlagArgument("onefs", 0, help_onefs);
        registerArguments(argPaths, flagRecurse, flagForce, flagInteract, flagVerbose, flagOneFS);
    }

    public static void main(String[] args) throws Exception {
        new DeleteCommand().execute(args);
    }

    public void execute() throws NameNotFoundException {
        // Lookup the Filesystem service
        fss = InitialNaming.lookup(FileSystemService.NAME);
       
        recursive    = flagRecurse.isSet();
        force        = flagForce.isSet();
        interactive  = flagInteract.isSet();
        verbose      = flagVerbose.isSet();
        onefs        = flagOneFS.isSet();
        File[] paths = argPaths.getValues();
       
        err = getError().getPrintWriter();
        out = getOutput().getPrintWriter();
        in = getInput().getReader();
       
        boolean ok = true;
        for (File file : paths) {
            ok &= deleteFile(file);
        }
        if (!ok) {
            exit(1);
        }
    }
   
    private boolean deleteFile(File file) {
        // We have to be careful about how we handle race conditions, especially
        // considering the depth-first nature of recursive file deletion. If this
        // method gets called on a file, and the file does not exist, then we assume
        // some other process has beat us to it. The command line only allows existing
        // files to be input.
       
        boolean deleteOk;
        boolean prompt;
       
        if (!file.exists()) {
            // someone beat us to the delete() call, return gracefully.
            return skip(str_not_exist, file) || true;
        }
       
        // A note about 'interactive' mode. It is _not_ an error
        // if stdin is not a tty. It is possible to send responses
        // via a pipe. This is why we only check for a tty stdin
        // if interactive was not set.
        prompt = (!force && (interactive || (!isWriteable(file) && getInput().isTTY())));
       
        if (file.isDirectory()) {
            // This is written to match the POSIX behavior in rm Description Section 2
            if (!recursive) {
                return skip(str_is_dir, file);
            }
            if (file.getName().equals("..") || file.getName().equals(".")) {
                return skip(str_is_dot, file);
            }
            if (prompt) {
                if (!prompt(String.format(fmt_ask_descend, file))) {
                    return skip("", file);
                }
            }
            // According to the POSIX spec, there is no provision for recursive deletion
            // that spans into another file system. The GNU rm utility provides the ability
            // to stop recursive deleting from entering another file system. If that flag
            // is not set, then we will continue to delete files within that file system
            // but the deleting of the directory that is the mount will probably fail because
            // it is in use.
            if (!checkMount(file)) {
                return skip(str_is_mount, file);
            }
            deleteOk = true;
            for (File f : file.listFiles()) {
                String name = f.getName();
                if (!name.equals(".") && !name.equals("..")) {
                    deleteOk &= deleteFile(f);
                }
            }
            if (!deleteOk) {
                return skip(str_not_empty, file);
            }
            if (prompt) {
                if (!prompt(String.format(fmt_ask_remove_dir, file))) {
                    return skip("", file);
                }
            }
            return rmdir(file);
        } else {
            if (prompt) {
                if (!prompt(String.format(fmt_ask_remove_file, file))) {
                    return skip("", file);
                }
            }
            return unlink(file);
        }
    }
   
    private boolean prompt(String s) {
        return IOUtils.promptYesOrNo(in, out, s);
    }
   
    private boolean checkMount(File file) {
        // This is wrong, as the directory might have been given on the
        // command line, which means regardless of the value of onefs, we will continue.
        // The proper way would be to check that this directory resides on the same file
        // system as the directory given on the command line.
        if (onefs) {
            try {
                if (fss.isMount(file.getCanonicalPath())) {
                    return false;
                }
            } catch (IOException e) {
                return false;
            }
        }
        return true;
    }
   
    private boolean isWriteable(File file) {
        try {
            return file.canWrite();
        } catch (SecurityException e) {
            return false;
        }
    }
   
    private boolean rmdir(File file) {
        if (!file.delete()) {
            return error(fmt_not_removed, file);
        }
        if (verbose) {
            out.format(fmt_removed_dir, file);
        }
        return true;
    }
   
    private boolean unlink(File file) {
        if (!file.delete()) {
            return error(fmt_not_removed, file);
        }
        if (verbose) {
            out.format(fmt_removed_file, file);
        }
        return true;
    }
   
    private boolean skip(String msg, File file) {
        if (!force) {
            err.format(fmt_skip, file, msg);
        }
        return false;
    }
   
    private boolean error(String msg, Object... args) {
        if (verbose) {
            err.format(msg, args);
        }
        return false;
    }
}
TOP

Related Classes of org.jnode.command.file.DeleteCommand

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.