[BACK]Return to sftp-client.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.1

1.1     ! djm         1: /*
        !             2:  * Copyright (c) 2001 Damien Miller.  All rights reserved.
        !             3:  *
        !             4:  * Redistribution and use in source and binary forms, with or without
        !             5:  * modification, are permitted provided that the following conditions
        !             6:  * are met:
        !             7:  * 1. Redistributions of source code must retain the above copyright
        !             8:  *    notice, this list of conditions and the following disclaimer.
        !             9:  * 2. Redistributions in binary form must reproduce the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer in the
        !            11:  *    documentation and/or other materials provided with the distribution.
        !            12:  *
        !            13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            14:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            15:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            16:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            17:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            18:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            19:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            20:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            21:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            22:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            23:  */
        !            24:
        !            25: /* XXX: memleaks */
        !            26: /* XXX: signed vs unsigned */
        !            27: /* XXX: redesign to allow concurrent overlapped operations */
        !            28: /* XXX: we use fatal too much, error may be more appropriate in places */
        !            29: /* XXX: copy between two remote sites */
        !            30:
        !            31: #include "includes.h"
        !            32: RCSID("$OpenBSD$");
        !            33:
        !            34: #include "ssh.h"
        !            35: #include "buffer.h"
        !            36: #include "bufaux.h"
        !            37: #include "getput.h"
        !            38: #include "xmalloc.h"
        !            39: #include "log.h"
        !            40: #include "atomicio.h"
        !            41: #include "pathnames.h"
        !            42:
        !            43: #include "sftp.h"
        !            44: #include "sftp-common.h"
        !            45: #include "sftp-client.h"
        !            46:
        !            47: /* How much data to read/write at at time during copies */
        !            48: /* XXX: what should this be? */
        !            49: #define COPY_SIZE      8192
        !            50:
        !            51: void
        !            52: send_msg(int fd, Buffer *m)
        !            53: {
        !            54:        int mlen = buffer_len(m);
        !            55:        int len;
        !            56:        Buffer oqueue;
        !            57:
        !            58:        buffer_init(&oqueue);
        !            59:        buffer_put_int(&oqueue, mlen);
        !            60:        buffer_append(&oqueue, buffer_ptr(m), mlen);
        !            61:        buffer_consume(m, mlen);
        !            62:
        !            63:        len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
        !            64:        if (len <= 0)
        !            65:                fatal("Couldn't send packet: %s", strerror(errno));
        !            66:
        !            67:        buffer_free(&oqueue);
        !            68: }
        !            69:
        !            70: void
        !            71: get_msg(int fd, Buffer *m)
        !            72: {
        !            73:        u_int len, msg_len;
        !            74:        unsigned char buf[4096];
        !            75:
        !            76:        len = atomicio(read, fd, buf, 4);
        !            77:        if (len != 4)
        !            78:                fatal("Couldn't read packet: %s", strerror(errno));
        !            79:
        !            80:        msg_len = GET_32BIT(buf);
        !            81:        if (msg_len > 256 * 1024)
        !            82:                fatal("Received message too long %d", msg_len);
        !            83:
        !            84:        while (msg_len) {
        !            85:                len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
        !            86:                if (len <= 0)
        !            87:                        fatal("Couldn't read packet: %s", strerror(errno));
        !            88:
        !            89:                msg_len -= len;
        !            90:                buffer_append(m, buf, len);
        !            91:        }
        !            92: }
        !            93:
        !            94: void
        !            95: send_string_request(int fd, u_int id, u_int code, char *s,
        !            96:     u_int len)
        !            97: {
        !            98:        Buffer msg;
        !            99:
        !           100:        buffer_init(&msg);
        !           101:        buffer_put_char(&msg, code);
        !           102:        buffer_put_int(&msg, id);
        !           103:        buffer_put_string(&msg, s, len);
        !           104:        send_msg(fd, &msg);
        !           105:        debug3("Sent message fd %d T:%d I:%d", fd, code, id);
        !           106:        buffer_free(&msg);
        !           107: }
        !           108:
        !           109: void
        !           110: send_string_attrs_request(int fd, u_int id, u_int code, char *s,
        !           111:     u_int len, Attrib *a)
        !           112: {
        !           113:        Buffer msg;
        !           114:
        !           115:        buffer_init(&msg);
        !           116:        buffer_put_char(&msg, code);
        !           117:        buffer_put_int(&msg, id);
        !           118:        buffer_put_string(&msg, s, len);
        !           119:        encode_attrib(&msg, a);
        !           120:        send_msg(fd, &msg);
        !           121:        debug3("Sent message fd %d T:%d I:%d", fd, code, id);
        !           122:        buffer_free(&msg);
        !           123: }
        !           124:
        !           125: u_int
        !           126: get_status(int fd, int expected_id)
        !           127: {
        !           128:        Buffer msg;
        !           129:        u_int type, id, status;
        !           130:
        !           131:        buffer_init(&msg);
        !           132:        get_msg(fd, &msg);
        !           133:        type = buffer_get_char(&msg);
        !           134:        id = buffer_get_int(&msg);
        !           135:
        !           136:        if (id != expected_id)
        !           137:                fatal("ID mismatch (%d != %d)", id, expected_id);
        !           138:        if (type != SSH2_FXP_STATUS)
        !           139:                fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
        !           140:                    SSH2_FXP_STATUS, type);
        !           141:
        !           142:        status = buffer_get_int(&msg);
        !           143:        buffer_free(&msg);
        !           144:
        !           145:        debug3("SSH2_FXP_STATUS %d", status);
        !           146:
        !           147:        return(status);
        !           148: }
        !           149:
        !           150: char *
        !           151: get_handle(int fd, u_int expected_id, u_int *len)
        !           152: {
        !           153:        Buffer msg;
        !           154:        u_int type, id;
        !           155:        char *handle;
        !           156:
        !           157:        buffer_init(&msg);
        !           158:        get_msg(fd, &msg);
        !           159:        type = buffer_get_char(&msg);
        !           160:        id = buffer_get_int(&msg);
        !           161:
        !           162:        if (id != expected_id)
        !           163:                fatal("ID mismatch (%d != %d)", id, expected_id);
        !           164:        if (type == SSH2_FXP_STATUS) {
        !           165:                int status = buffer_get_int(&msg);
        !           166:
        !           167:                error("Couldn't get handle: %s", fx2txt(status));
        !           168:                return(NULL);
        !           169:        } else if (type != SSH2_FXP_HANDLE)
        !           170:                fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
        !           171:                    SSH2_FXP_HANDLE, type);
        !           172:
        !           173:        handle = buffer_get_string(&msg, len);
        !           174:        buffer_free(&msg);
        !           175:
        !           176:        return(handle);
        !           177: }
        !           178:
        !           179: Attrib *
        !           180: get_decode_stat(int fd, u_int expected_id)
        !           181: {
        !           182:        Buffer msg;
        !           183:        u_int type, id;
        !           184:        Attrib *a;
        !           185:
        !           186:        buffer_init(&msg);
        !           187:        get_msg(fd, &msg);
        !           188:
        !           189:        type = buffer_get_char(&msg);
        !           190:        id = buffer_get_int(&msg);
        !           191:
        !           192:        debug3("Received stat reply T:%d I:%d", type, id);
        !           193:        if (id != expected_id)
        !           194:                fatal("ID mismatch (%d != %d)", id, expected_id);
        !           195:        if (type == SSH2_FXP_STATUS) {
        !           196:                int status = buffer_get_int(&msg);
        !           197:
        !           198:                error("Couldn't stat remote file: %s", fx2txt(status));
        !           199:                return(NULL);
        !           200:        } else if (type != SSH2_FXP_ATTRS) {
        !           201:                fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
        !           202:                    SSH2_FXP_ATTRS, type);
        !           203:        }
        !           204:        a = decode_attrib(&msg);
        !           205:        buffer_free(&msg);
        !           206:
        !           207:        return(a);
        !           208: }
        !           209:
        !           210: int
        !           211: do_init(int fd_in, int fd_out)
        !           212: {
        !           213:        int type, version;
        !           214:        Buffer msg;
        !           215:
        !           216:        buffer_init(&msg);
        !           217:        buffer_put_char(&msg, SSH2_FXP_INIT);
        !           218:        buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
        !           219:        send_msg(fd_out, &msg);
        !           220:
        !           221:        buffer_clear(&msg);
        !           222:
        !           223:        get_msg(fd_in, &msg);
        !           224:
        !           225:        /* Expecting a VERSION reply */
        !           226:        if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
        !           227:                error("Invalid packet back from SSH2_FXP_INIT (type %d)",
        !           228:                    type);
        !           229:                buffer_free(&msg);
        !           230:                return(-1);
        !           231:        }
        !           232:        version = buffer_get_int(&msg);
        !           233:
        !           234:        debug2("Remote version: %d", version);
        !           235:
        !           236:        /* Check for extensions */
        !           237:        while (buffer_len(&msg) > 0) {
        !           238:                char *name = buffer_get_string(&msg, NULL);
        !           239:                char *value = buffer_get_string(&msg, NULL);
        !           240:
        !           241:                debug2("Init extension: \"%s\"", name);
        !           242:                xfree(name);
        !           243:                xfree(value);
        !           244:        }
        !           245:
        !           246:        buffer_free(&msg);
        !           247:        return(0);
        !           248: }
        !           249:
        !           250: int
        !           251: do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
        !           252: {
        !           253:        u_int id, status;
        !           254:        Buffer msg;
        !           255:
        !           256:        buffer_init(&msg);
        !           257:
        !           258:        id = arc4random();
        !           259:        buffer_put_char(&msg, SSH2_FXP_CLOSE);
        !           260:        buffer_put_int(&msg, id);
        !           261:        buffer_put_string(&msg, handle, handle_len);
        !           262:        send_msg(fd_out, &msg);
        !           263:        debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
        !           264:
        !           265:        status = get_status(fd_in, id);
        !           266:        if (status != SSH2_FX_OK)
        !           267:                error("Couldn't close file: %s", fx2txt(status));
        !           268:
        !           269:        buffer_free(&msg);
        !           270:
        !           271:        return(status);
        !           272: }
        !           273:
        !           274: int
        !           275: do_ls(int fd_in, int fd_out, char *path)
        !           276: {
        !           277:        Buffer msg;
        !           278:        u_int type, id, handle_len, i, expected_id;
        !           279:        char *handle;
        !           280:
        !           281:        id = arc4random();
        !           282:
        !           283:        buffer_init(&msg);
        !           284:        buffer_put_char(&msg, SSH2_FXP_OPENDIR);
        !           285:        buffer_put_int(&msg, id);
        !           286:        buffer_put_cstring(&msg, path);
        !           287:        send_msg(fd_out, &msg);
        !           288:
        !           289:        buffer_clear(&msg);
        !           290:
        !           291:        handle = get_handle(fd_in, id, &handle_len);
        !           292:        if (handle == NULL)
        !           293:                return(-1);
        !           294:
        !           295:        for(;;) {
        !           296:                int count;
        !           297:
        !           298:                expected_id = ++id;
        !           299:
        !           300:                debug3("Sending SSH2_FXP_READDIR I:%d", id);
        !           301:
        !           302:                buffer_clear(&msg);
        !           303:                buffer_put_char(&msg, SSH2_FXP_READDIR);
        !           304:                buffer_put_int(&msg, id);
        !           305:                buffer_put_string(&msg, handle, handle_len);
        !           306:                send_msg(fd_out, &msg);
        !           307:
        !           308:                buffer_clear(&msg);
        !           309:
        !           310:                get_msg(fd_in, &msg);
        !           311:
        !           312:                type = buffer_get_char(&msg);
        !           313:                id = buffer_get_int(&msg);
        !           314:
        !           315:                debug3("Received reply T:%d I:%d", type, id);
        !           316:
        !           317:                if (id != expected_id)
        !           318:                        fatal("ID mismatch (%d != %d)", id, expected_id);
        !           319:
        !           320:                if (type == SSH2_FXP_STATUS) {
        !           321:                        int status = buffer_get_int(&msg);
        !           322:
        !           323:                        debug3("Received SSH2_FXP_STATUS %d", status);
        !           324:
        !           325:                        if (status == SSH2_FX_EOF) {
        !           326:                                break;
        !           327:                        } else {
        !           328:                                error("Couldn't read directory: %s",
        !           329:                                    fx2txt(status));
        !           330:                                do_close(fd_in, fd_out, handle, handle_len);
        !           331:                                return(NULL);
        !           332:                        }
        !           333:                } else if (type != SSH2_FXP_NAME)
        !           334:                        fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
        !           335:                            SSH2_FXP_NAME, type);
        !           336:
        !           337:                count = buffer_get_int(&msg);
        !           338:                debug3("Received %i SSH2_FXP_NAME responses", count);
        !           339:                for(i = 0; i < count; i++) {
        !           340:                        char *filename, *longname;
        !           341:                        Attrib *a;
        !           342:
        !           343:                        filename = buffer_get_string(&msg, NULL);
        !           344:                        longname = buffer_get_string(&msg, NULL);
        !           345:                        a = decode_attrib(&msg);
        !           346:
        !           347:                        printf("%s\n", longname);
        !           348:
        !           349:                        xfree(filename);
        !           350:                        xfree(longname);
        !           351:                }
        !           352:        }
        !           353:
        !           354:        buffer_free(&msg);
        !           355:        do_close(fd_in, fd_out, handle, handle_len);
        !           356:        xfree(handle);
        !           357:
        !           358:        return(0);
        !           359: }
        !           360:
        !           361: int
        !           362: do_rm(int fd_in, int fd_out, char *path)
        !           363: {
        !           364:        u_int status, id;
        !           365:
        !           366:        debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
        !           367:
        !           368:        id = arc4random();
        !           369:        send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
        !           370:        status = get_status(fd_in, id);
        !           371:        if (status != SSH2_FX_OK)
        !           372:                error("Couldn't delete file: %s", fx2txt(status));
        !           373:        return(status);
        !           374: }
        !           375:
        !           376: int
        !           377: do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
        !           378: {
        !           379:        u_int status, id;
        !           380:
        !           381:        id = arc4random();
        !           382:        send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
        !           383:            strlen(path), a);
        !           384:
        !           385:        status = get_status(fd_in, id);
        !           386:        if (status != SSH2_FX_OK)
        !           387:                error("Couldn't create directory: %s", fx2txt(status));
        !           388:
        !           389:        return(status);
        !           390: }
        !           391:
        !           392: int
        !           393: do_rmdir(int fd_in, int fd_out, char *path)
        !           394: {
        !           395:        u_int status, id;
        !           396:
        !           397:        id = arc4random();
        !           398:        send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
        !           399:
        !           400:        status = get_status(fd_in, id);
        !           401:        if (status != SSH2_FX_OK)
        !           402:                error("Couldn't remove directory: %s", fx2txt(status));
        !           403:
        !           404:        return(status);
        !           405: }
        !           406:
        !           407: Attrib *
        !           408: do_stat(int fd_in, int fd_out, char *path)
        !           409: {
        !           410:        u_int id;
        !           411:
        !           412:        id = arc4random();
        !           413:        send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
        !           414:        return(get_decode_stat(fd_in, id));
        !           415: }
        !           416:
        !           417: Attrib *
        !           418: do_lstat(int fd_in, int fd_out, char *path)
        !           419: {
        !           420:        u_int id;
        !           421:
        !           422:        id = arc4random();
        !           423:        send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
        !           424:        return(get_decode_stat(fd_in, id));
        !           425: }
        !           426:
        !           427: Attrib *
        !           428: do_fstat(int fd_in, int fd_out, char *handle,
        !           429:     u_int handle_len)
        !           430: {
        !           431:        u_int id;
        !           432:
        !           433:        id = arc4random();
        !           434:        send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
        !           435:        return(get_decode_stat(fd_in, id));
        !           436: }
        !           437:
        !           438: int
        !           439: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
        !           440: {
        !           441:        u_int status, id;
        !           442:
        !           443:        id = arc4random();
        !           444:        send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
        !           445:            strlen(path), a);
        !           446:
        !           447:        status = get_status(fd_in, id);
        !           448:        if (status != SSH2_FX_OK)
        !           449:                error("Couldn't setstat on \"%s\": %s", path,
        !           450:                    fx2txt(status));
        !           451:
        !           452:        return(status);
        !           453: }
        !           454:
        !           455: int
        !           456: do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
        !           457:     Attrib *a)
        !           458: {
        !           459:        u_int status, id;
        !           460:
        !           461:        id = arc4random();
        !           462:        send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
        !           463:            handle_len, a);
        !           464:
        !           465:        status = get_status(fd_in, id);
        !           466:        if (status != SSH2_FX_OK)
        !           467:                error("Couldn't fsetstat: %s", fx2txt(status));
        !           468:
        !           469:        return(status);
        !           470: }
        !           471:
        !           472: char *
        !           473: do_realpath(int fd_in, int fd_out, char *path)
        !           474: {
        !           475:        Buffer msg;
        !           476:        u_int type, expected_id, count, id;
        !           477:        char *filename, *longname;
        !           478:        Attrib *a;
        !           479:
        !           480:        expected_id = id = arc4random();
        !           481:        send_string_request(fd_out, id, SSH2_FXP_REALPATH, path,
        !           482:            strlen(path));
        !           483:
        !           484:        buffer_init(&msg);
        !           485:
        !           486:        get_msg(fd_in, &msg);
        !           487:        type = buffer_get_char(&msg);
        !           488:        id = buffer_get_int(&msg);
        !           489:
        !           490:        if (id != expected_id)
        !           491:                fatal("ID mismatch (%d != %d)", id, expected_id);
        !           492:
        !           493:        if (type == SSH2_FXP_STATUS) {
        !           494:                u_int status = buffer_get_int(&msg);
        !           495:
        !           496:                error("Couldn't canonicalise: %s", fx2txt(status));
        !           497:                return(NULL);
        !           498:        } else if (type != SSH2_FXP_NAME)
        !           499:                fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
        !           500:                    SSH2_FXP_NAME, type);
        !           501:
        !           502:        count = buffer_get_int(&msg);
        !           503:        if (count != 1)
        !           504:                fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
        !           505:
        !           506:        filename = buffer_get_string(&msg, NULL);
        !           507:        longname = buffer_get_string(&msg, NULL);
        !           508:        a = decode_attrib(&msg);
        !           509:
        !           510:        debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
        !           511:
        !           512:        xfree(longname);
        !           513:
        !           514:        buffer_free(&msg);
        !           515:
        !           516:        return(filename);
        !           517: }
        !           518:
        !           519: int
        !           520: do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
        !           521: {
        !           522:        Buffer msg;
        !           523:        u_int status, id;
        !           524:
        !           525:        buffer_init(&msg);
        !           526:
        !           527:        /* Send rename request */
        !           528:        id = arc4random();
        !           529:        buffer_put_char(&msg, SSH2_FXP_RENAME);
        !           530:        buffer_put_int(&msg, id);
        !           531:        buffer_put_cstring(&msg, oldpath);
        !           532:        buffer_put_cstring(&msg, newpath);
        !           533:        send_msg(fd_out, &msg);
        !           534:        debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
        !           535:            newpath);
        !           536:        buffer_free(&msg);
        !           537:
        !           538:        status = get_status(fd_in, id);
        !           539:        if (status != SSH2_FX_OK)
        !           540:                error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
        !           541:                    fx2txt(status));
        !           542:
        !           543:        return(status);
        !           544: }
        !           545:
        !           546: int
        !           547: do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
        !           548:     int pflag)
        !           549: {
        !           550:        int local_fd;
        !           551:        u_int expected_id, handle_len, mode, type, id;
        !           552:        u_int64_t offset;
        !           553:        char *handle;
        !           554:        Buffer msg;
        !           555:        Attrib junk, *a;
        !           556:
        !           557:        a = do_stat(fd_in, fd_out, remote_path);
        !           558:        if (a == NULL)
        !           559:                return(-1);
        !           560:
        !           561:        /* XXX: should we preserve set[ug]id? */
        !           562:        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
        !           563:                mode = S_IWRITE | (a->perm & 0777);
        !           564:        else
        !           565:                mode = 0666;
        !           566:
        !           567:        local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
        !           568:        if (local_fd == -1) {
        !           569:                error("Couldn't open local file \"%s\" for writing: %s",
        !           570:                    local_path, strerror(errno));
        !           571:                return(errno);
        !           572:        }
        !           573:
        !           574:        /* Override umask and utimes if asked */
        !           575:        if (pflag && fchmod(local_fd, mode) == -1)
        !           576:                error("Couldn't set mode on \"%s\": %s", local_path,
        !           577:                    strerror(errno));
        !           578:        if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
        !           579:                struct timeval tv;
        !           580:
        !           581:                tv.tv_sec = a->atime;
        !           582:                tv.tv_usec = a->mtime;
        !           583:                if (utimes(local_path, &tv) == -1)
        !           584:                        error("Can't set times on \"%s\": %s", local_path,
        !           585:                            strerror(errno));
        !           586:        }
        !           587:
        !           588:        buffer_init(&msg);
        !           589:
        !           590:        /* Send open request */
        !           591:        id = arc4random();
        !           592:        buffer_put_char(&msg, SSH2_FXP_OPEN);
        !           593:        buffer_put_int(&msg, id);
        !           594:        buffer_put_cstring(&msg, remote_path);
        !           595:        buffer_put_int(&msg, SSH2_FXF_READ);
        !           596:        attrib_clear(&junk); /* Send empty attributes */
        !           597:        encode_attrib(&msg, &junk);
        !           598:        send_msg(fd_out, &msg);
        !           599:        debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
        !           600:
        !           601:        handle = get_handle(fd_in, id, &handle_len);
        !           602:        if (handle == NULL) {
        !           603:                buffer_free(&msg);
        !           604:                close(local_fd);
        !           605:                return(-1);
        !           606:        }
        !           607:
        !           608:        /* Read from remote and write to local */
        !           609:        offset = 0;
        !           610:        for(;;) {
        !           611:                u_int len;
        !           612:                char *data;
        !           613:
        !           614:                expected_id = ++id;
        !           615:
        !           616:                buffer_clear(&msg);
        !           617:                buffer_put_char(&msg, SSH2_FXP_READ);
        !           618:                buffer_put_int(&msg, id);
        !           619:                buffer_put_string(&msg, handle, handle_len);
        !           620:                buffer_put_int64(&msg, offset);
        !           621:                buffer_put_int(&msg, COPY_SIZE);
        !           622:                send_msg(fd_out, &msg);
        !           623:                debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
        !           624:                    id, offset, COPY_SIZE);
        !           625:
        !           626:                buffer_clear(&msg);
        !           627:
        !           628:                get_msg(fd_in, &msg);
        !           629:                type = buffer_get_char(&msg);
        !           630:                id = buffer_get_int(&msg);
        !           631:                debug3("Received reply T:%d I:%d", type, id);
        !           632:                if (id != expected_id)
        !           633:                        fatal("ID mismatch (%d != %d)", id, expected_id);
        !           634:                if (type == SSH2_FXP_STATUS) {
        !           635:                        int status = buffer_get_int(&msg);
        !           636:
        !           637:                        if (status == SSH2_FX_EOF)
        !           638:                                break;
        !           639:                        else {
        !           640:                                error("Couldn't read from remote "
        !           641:                                    "file \"%s\" : %s", remote_path,
        !           642:                                     fx2txt(status));
        !           643:                                do_close(fd_in, fd_out, handle, handle_len);
        !           644:                                xfree(handle);
        !           645:                                close(local_fd);
        !           646:                                buffer_free(&msg);
        !           647:                                return(status);
        !           648:                        }
        !           649:                } else if (type != SSH2_FXP_DATA) {
        !           650:                        fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
        !           651:                            SSH2_FXP_DATA, type);
        !           652:                }
        !           653:
        !           654:                data = buffer_get_string(&msg, &len);
        !           655:                if (len > COPY_SIZE)
        !           656:                        fatal("Received more data than asked for %d > %d",
        !           657:                            len, COPY_SIZE);
        !           658:
        !           659:                debug3("In read loop, got %d offset %lld", len, offset);
        !           660:                if (atomicio(write, local_fd, data, len) != len) {
        !           661:                        error("Couldn't write to \"%s\": %s", local_path,
        !           662:                            strerror(errno));
        !           663:                        do_close(fd_in, fd_out, handle, handle_len);
        !           664:                        xfree(handle);
        !           665:                        close(local_fd);
        !           666:                        xfree(data);
        !           667:                        buffer_free(&msg);
        !           668:                        return(-1);
        !           669:                }
        !           670:
        !           671:                offset += len;
        !           672:                xfree(data);
        !           673:        }
        !           674:        xfree(handle);
        !           675:        buffer_free(&msg);
        !           676:        close(local_fd);
        !           677:
        !           678:        return(do_close(fd_in, fd_out, handle, handle_len));
        !           679: }
        !           680:
        !           681: int
        !           682: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
        !           683:     int pflag)
        !           684: {
        !           685:        int local_fd;
        !           686:        u_int handle_len, id;
        !           687:        u_int64_t offset;
        !           688:        char *handle;
        !           689:        Buffer msg;
        !           690:        struct stat sb;
        !           691:        Attrib a;
        !           692:
        !           693:        if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
        !           694:                error("Couldn't open local file \"%s\" for reading: %s",
        !           695:                    local_path, strerror(errno));
        !           696:                return(-1);
        !           697:        }
        !           698:        if (fstat(local_fd, &sb) == -1) {
        !           699:                error("Couldn't fstat local file \"%s\": %s",
        !           700:                    local_path, strerror(errno));
        !           701:                close(local_fd);
        !           702:                return(-1);
        !           703:        }
        !           704:        stat_to_attrib(&sb, &a);
        !           705:
        !           706:        a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
        !           707:        a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
        !           708:        a.perm &= 0777;
        !           709:        if (!pflag)
        !           710:                a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
        !           711:
        !           712:        buffer_init(&msg);
        !           713:
        !           714:        /* Send open request */
        !           715:        id = arc4random();
        !           716:        buffer_put_char(&msg, SSH2_FXP_OPEN);
        !           717:        buffer_put_int(&msg, id);
        !           718:        buffer_put_cstring(&msg, remote_path);
        !           719:        buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
        !           720:        encode_attrib(&msg, &a);
        !           721:        send_msg(fd_out, &msg);
        !           722:        debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
        !           723:
        !           724:        buffer_clear(&msg);
        !           725:
        !           726:        handle = get_handle(fd_in, id, &handle_len);
        !           727:        if (handle == NULL) {
        !           728:                close(local_fd);
        !           729:                buffer_free(&msg);
        !           730:                return(-1);
        !           731:        }
        !           732:
        !           733:        /* Override umask and utimes if asked */
        !           734:        if (pflag)
        !           735:                do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
        !           736:
        !           737:        /* Read from local and write to remote */
        !           738:        offset = 0;
        !           739:        for(;;) {
        !           740:                int len;
        !           741:                char data[COPY_SIZE];
        !           742:                u_int status;
        !           743:
        !           744:                /*
        !           745:                 * Can't use atomicio here because it returns 0 on EOF, thus losing
        !           746:                 * the last block of the file
        !           747:                 */
        !           748:                do
        !           749:                        len = read(local_fd, data, COPY_SIZE);
        !           750:                while ((len == -1) && (errno == EINTR || errno == EAGAIN));
        !           751:
        !           752:                if (len == -1)
        !           753:                        fatal("Couldn't read from \"%s\": %s", local_path,
        !           754:                            strerror(errno));
        !           755:                if (len == 0)
        !           756:                        break;
        !           757:
        !           758:                buffer_clear(&msg);
        !           759:                buffer_put_char(&msg, SSH2_FXP_WRITE);
        !           760:                buffer_put_int(&msg, ++id);
        !           761:                buffer_put_string(&msg, handle, handle_len);
        !           762:                buffer_put_int64(&msg, offset);
        !           763:                buffer_put_string(&msg, data, len);
        !           764:                send_msg(fd_out, &msg);
        !           765:                debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
        !           766:                    id, offset, len);
        !           767:
        !           768:                status = get_status(fd_in, id);
        !           769:                if (status != SSH2_FX_OK) {
        !           770:                        error("Couldn't write to remote file \"%s\": %s",
        !           771:                            remote_path, fx2txt(status));
        !           772:                        do_close(fd_in, fd_out, handle, handle_len);
        !           773:                        xfree(handle);
        !           774:                        close(local_fd);
        !           775:                        return(-1);
        !           776:                }
        !           777:                debug3("In write loop, got %d offset %lld", len, offset);
        !           778:
        !           779:                offset += len;
        !           780:        }
        !           781:        xfree(handle);
        !           782:        buffer_free(&msg);
        !           783:
        !           784:        if (close(local_fd) == -1) {
        !           785:                error("Couldn't close local file \"%s\": %s", local_path,
        !           786:                    strerror(errno));
        !           787:                do_close(fd_in, fd_out, handle, handle_len);
        !           788:                return(-1);
        !           789:        }
        !           790:
        !           791:        return(do_close(fd_in, fd_out, handle, handle_len));
        !           792: }