Package net.schmizz.sshj.xfer.scp

Source Code of net.schmizz.sshj.xfer.scp.SCPDownloadClient

/*
* Copyright 2010-2012 sshj contributors, Cyril Ledru
*
* Licensed 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 net.schmizz.sshj.xfer.scp;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
import net.schmizz.sshj.userauth.password.PasswordFinder;
import net.schmizz.sshj.userauth.password.PasswordUtils;
import net.schmizz.sshj.xfer.FileSystemFile;
import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.TransferListener;
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;

/** Support for uploading files over a connected link using SCP. */
public final class SCPDownloadClient {

    private boolean recursiveMode = true;

    private final SCPEngine engine;

    public static void main(String[] args)
            throws IOException {
        SSHClient ssh = new SSHClient();
        // ssh.useCompression(); // Can lead to significant speedup (needs JZlib in classpath)
        ssh.loadKnownHosts();
        ssh.connect("dev4");
        try {
          PasswordFinder password = PasswordUtils.createOneOff("Reishee1".toCharArray());
          final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
          final KeyProvider keyProvider = ssh.loadKeys(base + "id_dsa", password);
         
          final String user = System.getProperty("user.name");
          ssh.authPublickey(user, keyProvider);
         
            ssh.newSCPFileTransfer().download("/home/erikb/ninja.sh", new FileSystemFile("/tmp/"));
        } finally {
            ssh.disconnect();
        }
    }   

    SCPDownloadClient(SCPEngine engine) {
        this.engine = engine;
    }

    /** Download a file from {@code sourcePath} on the connected host to {@code targetPath} locally. */
    public synchronized int copy(String sourcePath, LocalDestFile targetFile)
            throws IOException {
        engine.cleanSlate();
        try {
            startCopy(sourcePath, targetFile);
        } finally {
            engine.exit();
        }
        return engine.getExitStatus();
    }

    public boolean getRecursiveMode() {
        return recursiveMode;
    }

    public void setRecursiveMode(boolean recursive) {
        this.recursiveMode = recursive;
    }

    void startCopy(String sourcePath, LocalDestFile targetFile)
            throws IOException {
        List<Arg> args = new LinkedList<Arg>();
        args.add(Arg.SOURCE);
        args.add(Arg.QUIET);
        args.add(Arg.PRESERVE_TIMES);
        if (recursiveMode)
            args.add(Arg.RECURSIVE);
        engine.execSCPWith(args, sourcePath);

        engine.signal("Start status OK");

        String msg = engine.readMessage();
        do
            process(engine.getTransferListener(), null, msg, targetFile);
        while (!(msg = engine.readMessage()).isEmpty());
    }

    private long parseLong(String longString, String valType)
            throws SCPException {
        try {
            return Long.parseLong(longString);
        } catch (NumberFormatException nfe) {
            throw new SCPException("Could not parse " + valType + " from `" + longString + "`", nfe);
        }
    }

    /* e.g. "C0644" -> 0644; "D0755" -> 0755 */

    private int parsePermissions(String cmd)
            throws SCPException {
        if (cmd.length() != 5)
            throw new SCPException("Could not parse permissions from `" + cmd + "`");
        return Integer.parseInt(cmd.substring(1), 8);
    }

    private boolean process(TransferListener listener, String bufferedTMsg, String msg, LocalDestFile f)
            throws IOException {
        if (msg.length() < 1)
            throw new SCPException("Could not parse message `" + msg + "`");

        switch (msg.charAt(0)) {

            case 'T':
                engine.signal("ACK: T");
                process(listener, msg, engine.readMessage(), f);
                break;

            case 'C':
                processFile(listener, msg, bufferedTMsg, f);
                break;

            case 'D':
                processDirectory(listener, msg, bufferedTMsg, f);
                break;

            case 'E':
                return true;

            case (char) 1:
            case (char) 2:
                throw new SCPException("Remote SCP command returned error: " + msg.substring(1));

            default:
                final String err = "Unrecognized message: `" + msg + "`";
                engine.sendMessage((char) 2 + err);
                throw new SCPException(err);
        }

        return false;
    }

    private void processDirectory(TransferListener listener, String dMsg, String tMsg, LocalDestFile f)
            throws IOException {
        final List<String> dMsgParts = tokenize(dMsg, 3, true); // D<perms> 0 <dirname>
        final long length = parseLong(dMsgParts.get(1), "dir length");
        final String dirname = dMsgParts.get(2);
        if (length != 0)
            throw new IOException("Remote SCP command sent strange directory length: " + length);

        final TransferListener dirListener = listener.directory(dirname);
        {
            f = f.getTargetDirectory(dirname);
            engine.signal("ACK: D");
            do {
            } while (!process(dirListener, null, engine.readMessage(), f));
            setAttributes(f, parsePermissions(dMsgParts.get(0)), tMsg);
            engine.signal("ACK: E");
        }
    }

    private void processFile(TransferListener listener, String cMsg, String tMsg, LocalDestFile f)
            throws IOException {
        final List<String> cMsgParts = tokenize(cMsg, 3, true); // C<perms> <size> <filename>
        final long length = parseLong(cMsgParts.get(1), "length");
        final String filename = cMsgParts.get(2);
        {
            f = f.getTargetFile(filename);
            engine.signal("Remote can start transfer");
            final OutputStream dest = f.getOutputStream();
            try {
                engine.transferFromRemote(listener.file(filename, length), dest, length);
            } finally {
                IOUtils.closeQuietly(dest);
            }
            engine.check("Remote agrees transfer done");
            setAttributes(f, parsePermissions(cMsgParts.get(0)), tMsg);
            engine.signal("Transfer done");
        }
    }

    private void setAttributes(LocalDestFile f, int perms, String tMsg)
            throws IOException {
        f.setPermissions(perms);
        if (tMsg != null) {
            List<String> tMsgParts = tokenize(tMsg, 4, false); // e.g. T<mtime> 0 <atime> 0
            f.setLastModifiedTime(parseLong(tMsgParts.get(0).substring(1), "last modified time"));
            f.setLastAccessedTime(parseLong(tMsgParts.get(2), "last access time"));
        }
    }

    private static List<String> tokenize(String msg, int totalParts, boolean consolidateTail)
            throws IOException {
        List<String> parts = Arrays.asList(msg.split(" "));
        if (parts.size() < totalParts ||
                (!consolidateTail && parts.size() != totalParts))
            throw new IOException("Could not parse message received from remote SCP: " + msg);

        if (consolidateTail && totalParts < parts.size()) {
            final StringBuilder sb = new StringBuilder(parts.get(totalParts - 1));
            for (int i = totalParts; i < parts.size(); i++) {
                sb.append(" ").append(parts.get(i));
            }
            parts = new ArrayList<String>(parts.subList(0, totalParts - 1));
            parts.add(sb.toString());
        }

        return parts;
    }

}
TOP

Related Classes of net.schmizz.sshj.xfer.scp.SCPDownloadClient

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.