views:

281

answers:

3

I have a bit of code that reads a directory for files to process. I currently use the dirent.h,opendir(),readdir() methods of doing this. I have been told that I need to do the same thing, only now it is a directory on a remote machine with SSH/SFTP access.

The only way (that I can think of) to do the same thing, without changing anything in the system except my source code, is to run a "ssh user@host ls" command, parse, and process based on the parsers results.

The real question here is, are there ways of doing opendir(), readdir() (or something similar) through SSH/SFTP?

+1  A: 

The easiest way, if you're on Linux or Mac OS X (or some BSDs) would be to use sshfs to attach it to the filesystem. Most filesystem calls will then just work directly without modification.

Otherwise you can look at sshfs's source for hints about how it does things.

bdonlan
+1  A: 

Yes, SFTP has a protocol for doing this. Read through the most recent document here: http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/

Chris Jester-Young
Is this implemented anywhere?
Crazy Chenz
It concerns me that OpenSSH doesn't seem to have a stable API or any API documentation except in-code remarks.
Crazy Chenz
sshfs just runs ssh as a separate process and speaks raw SFTP over a pipe, obviating the need for a stable API
bdonlan
OpenSSH implements a network protocol, not an API - there is no standard SSH API. sshfs is one alternative, otherwise you need to use an SFTP client library.
Bruce Blackshaw
A: 

As of OpenSSH 5.1, there is a limited implementation to do this. It does not fully implement the File XFER standard. So I cannot check for things like the file types, but I can scan for the filenames themselves... Using the "sftp.c" code in OpenSSH source I just threw together an adhoc main() that could be changed as needed... I hope that this question can be more thoughly answered at a later date.

/* Username is a NULL terminated string
   Host is a NULL terminated string indicating remote IP */
void setup_args(arglist *args, char *username, char *host)
{
        // Arg init allocation
        memset(args, '\0', sizeof(*args));
        args->list = NULL;

        // Arg setup
        addargs(args, "%s", "/usr/bin/ssh");
        addargs(args, "%s", "-oForwardX11 no");
        addargs(args, "%s", "-oForwardAgent no");
        addargs(args, "%s", "-oPermitLocalCommand no");
        addargs(args, "%s", "-oClearAllForwardings yes");
        addargs(args, "%s%s", "-l", username);
        addargs(args, "%s", "-oProtocol 2");
        addargs(args, "%s", "-s");
        addargs(args, "%s", host);
        addargs(args, "%s", "sftp");
}
void run_program()
{
        // Setup connection parameters.
        int in, out; // The IO file descriptors.
        arglist args;
        setup_args(&args, "chenz", "172.16.22.128");
        connect_to_server("/usr/bin/ssh", args.list, &in, &out);
        freeargs(&args);

        // Create connection
        struct sftp_conn *conn;
        conn = do_init(in, out, copy_buffer_len, num_requests);
        if (conn == NULL)
                fatal("Couldn't initialise connection to server");

        //Get the current directory
        char *pwd;
        pwd = do_realpath(conn, ".");
        printf("PWD: %s\n", pwd);
        if (pwd == NULL)
                fatal("Need cwd");

        SFTP_DIRENT** dirent;
        do_readdir(conn, "/home/chenz", &dirent);
        int i = 0;
        while (dirent[i] != 0) {
                printf("filename: %s\n", dirent[i]->filename);
                printf("longname: %s\n", dirent[i]->longname);
                printf("attrib:\n", dirent[i]->a);
                i++;
        }

        // Clean up file descriptors
        close(in);
        close(out);

        // Wait for kill signal and exit
        while (waitpid(sshpid, NULL, 0) == -1)
                if (errno != EINTR)
                        fatal("Couldn't wait for ssh process: %s",
                            strerror(errno));

        //exit(err == 0 ? 0 : 1);
        exit(0);
 }
Crazy Chenz