Package cu.ftpd.modules.nukehandler

Source Code of cu.ftpd.modules.nukehandler.NukeHandler

/**
* Copyright (c) 2007, Markus Jevring <markus@jevring.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. The names of the contributors may not be used to endorse or promote
*    products derived from this software without specific prior written
*    permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/

package cu.ftpd.modules.nukehandler;

import cu.ftpd.filesystem.filters.ForbiddenFilesFilter;
import cu.ftpd.filesystem.metadata.Directory;
import cu.ftpd.filesystem.metadata.Metadata;
import cu.ftpd.logging.Logging;
import cu.ftpd.user.User;
import cu.ftpd.user.userbases.NoSuchUserException;
import cu.ftpd.modules.nukehandler.NukeException;
import cu.ftpd.modules.nukehandler.Nuke;
import cu.ftpd.Server;
import cu.ftpd.ServiceManager;

import java.io.*;
import java.security.AccessControlException;
import java.util.HashMap;
import java.util.Map;
import java.text.MessageFormat;

/**
* @author Markus Jevring <markus@jevring.net>
* @since 2007-okt-08 : 23:36:30
* @version $Id: NukeHandler.java 292 2009-03-04 19:44:36Z jevring $
*/
public class NukeHandler {
    private File logfile;
    protected PrintWriter nukelog;
    protected final Object logLock = new Object();

    // releasename, section, nuker, size, multiplier, reason, victims(formatted string, user1:group/bytesMB user1:group/bytesMB)
    protected static final MessageFormat nuke = new MessageFormat("NUKE: \"{0}\" \"{1}\" \"{2}\" \"{3}\" \"{4}\" \"{5}\" \"{6}\"");
    // releasename, section, unnuker, reason
    protected static final MessageFormat unnuke = new MessageFormat("UNNUKE: \"{0}\" \"{1}\" \"{2}\" \"{3}\"");

    public NukeHandler(String logfilePath) throws IOException {
        // maybe 'site nukes [username=user] [section=section] [dir=dir] [number=10{default=10}}'
        logfile = new File(logfilePath);
        try {
            nukelog = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logfile, true))));
        } catch (IOException e) {
            throw new IOException("Could not open nuke log for writing: " + e.getMessage(), e);
        }
    }

    protected NukeHandler() {
    }

    public void shutdown() {
        synchronized(logLock) {
            nukelog.close();
        }
    }

    protected void log(String message) {
        synchronized(logLock) {
            nukelog.println(message);
            nukelog.flush();
        }
    }

    public void logNukeToEventLog(Nuke n) {
        Logging.getEventLog().log(nuke.format(new Object[]{n.getReleaseName(), n.getSection(), n.getNuker(), n.getSize(), n.getMultiplier(), n.getReason(), n.getVictims()}));
    }
    public void logUnnukeToEventLog(String releaseName, String section, String unnuker, String reason) {
        Logging.getEventLog().log(unnuke.format(new String[]{releaseName, section, unnuker, reason}));
    }

    /*
    It would be AWESOME if we ran the statistics and the logging in a database. then other scripts could query it as well.

     */

    private int calculateNukeSize(File nukedDir, HashMap<String, Long> victims) {
        int totalBytesNuked = 0;
        Directory dir = ServiceManager.getServices().getMetadataHandler().getDirectory(nukedDir);
        Metadata metadata;
        Long bytesForUser;
        for (File file : nukedDir.listFiles(new ForbiddenFilesFilter())) {
            if (file.isDirectory()) {
                totalBytesNuked += calculateNukeSize(file, victims);
            } else {
                totalBytesNuked += file.length();
                metadata = dir.getMetadata(file.getName());
                if (metadata != null) { // if there's no user information for this file, then we don't do anything about it
                    bytesForUser = victims.get(metadata.getUsername());
                    if (bytesForUser == null) {
                        bytesForUser = 0L;
                    }
                    victims.put(metadata.getUsername(), bytesForUser + file.length()); // update the value for the user
                }
            }
        }
        return totalBytesNuked;
    }

    public boolean nuke(String realPwd, String section, String releaseName, int multiplier, String nuker, String reason) throws FileNotFoundException, AccessControlException, NukeException {
        // if you think it isn't removing credits, make sure the person doesn't have leech
        // this will fail if someone has an open file handle in this dir, so make sure to kill every access to this dir when doing a nuke (and a nrfr+rnto, for that matter)
        File originalDir = new File(realPwd, releaseName);
        if (originalDir.exists() && originalDir.isDirectory()) {
            File nukedDir = new File(realPwd, "[NUKED]-" + releaseName);
            boolean ok = originalDir.renameTo(nukedDir);
            if (ok) {
                // create reason dir:
                File reasonDir = new File(nukedDir, "NUKED " + multiplier + "x by " + nuker + " - " + reason);
                reasonDir.mkdir();
                // only calculate credit loss etc. if we actually suceeded in nuking the dir

                nukedDir.setWritable(false); // this will prevent new uploads in the directory

                HashMap<String, Long> victims = new HashMap<String, Long>();

                ServiceManager.getServices().getMetadataHandler().move(originalDir, nukedDir, null, null);
                long totalBytesNuked = calculateNukeSize(nukedDir, victims);
                String nukees = "{";
                for (Map.Entry<String, Long> victim : victims.entrySet()) {
                    try {
                        User user = ServiceManager.getServices().getUserbase().getUser(victim.getKey());
                        long credits = 0;
                        if (!user.hasLeech()) {
                            credits = victim.getValue() * multiplier;
                            user.takeCredits(credits);
                        }
                        nukees +=  user.getUsername() + '/' + user.getPrimaryGroup() + '/' + credits + '|';
                    } catch (NoSuchUserException e) {
                        // just skip this user if it doesn't exist anymore
                    }
                }
                nukees += "}";

                logNukeToEventLog(new Nuke(releaseName, section, nuker, totalBytesNuked, multiplier, reason, nukees));
                log("NUKE;" + releaseName + ';' + section + ';' + nuker + ';' + totalBytesNuked + ';' + multiplier + ';' + reason + ';' + nukees + ';' + realPwd + ';' + System.currentTimeMillis());
                return true;
            } else {
                Logging.getErrorLog().reportError("Failed to nuke directory: directory could not be renamed: " + originalDir.getAbsolutePath());
                throw new NukeException("Failed to nuke directory: directory could not be renamed: " + originalDir.getName()); // only disclose the name here, lest we reveal any information about the underlying system
            }
        } else {
            throw new FileNotFoundException("File not found: " + releaseName);
        }
    }

    public boolean unnuke(String realPwd, String section, String releaseName, String unnuker, String reason) throws IOException, AccessControlException, NukeException {
        releaseName = releaseName.replaceFirst("^\\[NUKED\\]-(.*)","$1");
        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(new FileInputStream(logfile)));
            String lastNuke = null;
            String line;
            while ((line = in.readLine()) != null) {
                if (line.contains("NUKE") && line.contains(releaseName) &&  line.contains(realPwd)) {
                    // check release name first, which will mach MUCH less often than "NUKE"
                    lastNuke = line;
                }
                // keep on going to the end, so we find the last one.
            }
            if (lastNuke != null) {
                String[] nuke = lastNuke.split(";");
                if (nuke.length == 10) {
                    // rename the dir back (the only way to get this path is if we have the full path in the log, so this needs to be added)
                    File originalDir = new File(realPwd, releaseName);
                    File nukedDir = new File(realPwd, "[NUKED]-" + releaseName);
                    boolean ok = nukedDir.renameTo(originalDir);
                    if (ok) {
                        originalDir.setWritable(true); // make the directory writable again
                        // remove reason dir:
                        File reasonDir = new File(originalDir, "NUKED " + nuke[5] + "x by " + nuke[3] + " - " + nuke[6]); // this is a bit ugly and unstable, make this nicer.
                        //System.out.println("trying to delete " + reasonDir.getAbsolutePath());
                        reasonDir.delete();
                        // restore the credits of the users
                        nuke[7] = nuke[7].substring(1, nuke[7].length() - 1); // remove the leading and trailing '{' '}'
                        String[] nukees = nuke[7].split("\\|");
                        for (int i = 0; i < nukees.length; i++) {
                            String[] nukee = nukees[i].split("/");
                            try {
                                User user = ServiceManager.getServices().getUserbase().getUser(nukee[0]);
                                long credits = Long.parseLong(nukee[2]);
                                //System.out.println("giving back " + credits +" to user " + user.getUsername());
                                user.giveCredits(credits);
                            } catch (NoSuchUserException e) {
                                // this user doesn't exist anymore, skip it
                            }
                        }
                        logUnnukeToEventLog(releaseName, section, unnuker, reason);
                        log("UNNUKE;" + releaseName + ';' + section + ';' + unnuker + ';' + reason + ';' + System.currentTimeMillis());
                        return true;
                    } else {
                        Logging.getErrorLog().reportError("Failed to unnuke directory: directory could not be renamed: " + nukedDir.getAbsolutePath());
                        throw new NukeException("Failed to unnuke directory: directory could not be renamed: " + nukedDir.getName());
                    }
                } else {
                    System.err.println("Malformed nuke line: " + lastNuke);
                    throw new NukeException("Malformed nuke line");
                }
            } else {
                throw new NukeException("Release not found in nukelog.");
            }
        } catch (IOException e) {
            Logging.getErrorLog().reportCritical("Could not read nukelog: " + e.getMessage());
            throw e;
        } finally {
            if (in != null) {
                in.close();
            }
        }
    }
}
TOP

Related Classes of cu.ftpd.modules.nukehandler.NukeHandler

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.