📄 ssh_ftp.c
字号:
if(id != expected_id) { ftp_err("ID mismatch (%d != %d)\n", id, expected_id); return -1; } if(type == SSH2_FXP_STATUS) { int status = buffer_get_int(&msg); if(status == SSH2_FX_EOF) { break; } else { ftp_err("Couldn't read directory: %s\n", fx2txt(status)); ssh_close(handle, handle_len); return status; } } else if(type != SSH2_FXP_NAME) { ftp_err("Expected SSH2_FXP_NAME (%d) packet, got %s (%d)\n", SSH2_FXP_NAME, ssh_reply2txt(type), type); } count = buffer_get_int(&msg); if(count == 0) break; for(i = 0; i < count; i++) { char *filename, *longname; Attrib *a; filename = buffer_get_string(&msg, NULL); longname = buffer_get_string(&msg, NULL); a = decode_attrib(&msg); if(dir) { *dir = xrealloc(*dir, sizeof(**dir) * (ents + 2)); (*dir)[ents] = xmalloc(sizeof(***dir)); (*dir)[ents]->filename = xstrdup(filename); (*dir)[ents]->longname = xstrdup(longname); memcpy(&(*dir)[ents]->a, a, sizeof(*a)); (*dir)[++ents] = NULL; } free(filename); free(longname); } } buffer_free(&msg); ssh_close(handle, handle_len); free(handle); return 0;}void ssh_free_dirents(SFTP_DIRENT **s){ int i; for(i = 0; s[i]; i++) { free(s[i]->filename); free(s[i]->longname); free(s[i]); } free(s);}int ssh_close(char *handle, u_int handle_len){ u_int id, status; Buffer msg; buffer_init(&msg); id = ftp->ssh_id++; buffer_put_char(&msg, SSH2_FXP_CLOSE); buffer_put_int(&msg, id); buffer_put_string(&msg, handle, handle_len); if(ssh_cmd(&msg) == -1) return -1; status = ssh_get_status(id); if(status != SSH2_FX_OK) ftp_err("Couldn't close file: %s\n", fx2txt(status)); buffer_free(&msg); return status;}Attrib *ssh_get_decode_stat(u_int expected_id){ Buffer msg; u_int type, id; Attrib *a; buffer_init(&msg); if(ssh_reply(&msg) == -1) return 0; type = buffer_get_char(&msg); id = buffer_get_int(&msg); if(id != expected_id) { ftp_err("ID mismatch (%d != %d)\n", id, expected_id); return 0; } if(type == SSH2_FXP_STATUS) { int status = buffer_get_int(&msg); ftp_err("Couldn't stat remote file: %s\n", fx2txt(status)); return 0; } else if (type != SSH2_FXP_ATTRS) { ftp_err("Expected SSH2_FXP_ATTRS (%d) packet, got %s (%d)\n", SSH2_FXP_ATTRS, ssh_reply2txt(type), type); return 0; } a = decode_attrib(&msg); buffer_free(&msg); return(a);}void ssh_send_string_request(u_int id, u_int code, const char *s, u_int len){ Buffer msg; buffer_init(&msg); buffer_put_char(&msg, code); buffer_put_int(&msg, id); buffer_put_string(&msg, s, len); ssh_cmd(&msg); buffer_free(&msg);}void ssh_send_string_attrs_request(u_int id, u_int code, const char *s, u_int len, Attrib *a){ Buffer msg; buffer_init(&msg); buffer_put_char(&msg, code); buffer_put_int(&msg, id); buffer_put_string(&msg, s, len); encode_attrib(&msg, a); ssh_cmd(&msg); buffer_free(&msg);}u_int ssh_get_status(int expected_id){ Buffer msg; u_int type, id, status; buffer_init(&msg); if(ssh_reply(&msg) == -1) return -1; type = buffer_get_char(&msg); id = buffer_get_int(&msg); if (id != expected_id) { ftp_err("ID mismatch (%d != %d)\n", id, expected_id); return -1; } if (type != SSH2_FXP_STATUS) { ftp_err("Expected SSH2_FXP_STATUS(%d) packet, got %s (%d)\n", SSH2_FXP_STATUS, ssh_reply2txt(type), type); return -1; } status = buffer_get_int(&msg); buffer_free(&msg); ftp->ssh_last_status = status; return status;}int ssh_recv_binary(const char *remote_path, FILE *local_fp, ftp_transfer_func hookf, u_int64_t offset){ u_int expected_id, handle_len, mode, type, id;/* u_int64_t offset;*/ char *handle; Buffer msg; Attrib junk, *a; int status; time_t then = time(0) - 1; ftp_set_close_handler(); if(hookf) hookf(&ftp->ti); ftp->ti.begin = false; a = ssh_stat(remote_path); if(a == 0) return -1; /* XXX: should we preserve set[ug]id? */ if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) mode = S_IWRITE | (a->perm & 0777); else mode = 0666; if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && (a->perm & S_IFDIR)) { ftp_err("Cannot download a directory: %s\n", remote_path); return -1; } buffer_init(&msg); /* Send open request */ id = ftp->ssh_id++; buffer_put_char(&msg, SSH2_FXP_OPEN); buffer_put_int(&msg, id); buffer_put_cstring(&msg, remote_path); buffer_put_int(&msg, SSH2_FXF_READ); attrib_clear(&junk); /* Send empty attributes */ encode_attrib(&msg, &junk); ssh_cmd(&msg); handle = ssh_get_handle(id, &handle_len); if(handle == 0) { buffer_free(&msg); return -1; } /* Read from remote and write to local *//* offset = 0;*/ while(true) { u_int len; char *data; id = expected_id = ftp->ssh_id++; buffer_clear(&msg); buffer_put_char(&msg, SSH2_FXP_READ); buffer_put_int(&msg, id); buffer_put_string(&msg, handle, handle_len); buffer_put_int64(&msg, offset); buffer_put_int(&msg, COPY_SIZE); ssh_cmd(&msg); buffer_clear(&msg); ssh_reply(&msg); type = buffer_get_char(&msg); id = buffer_get_int(&msg); if(id != expected_id) { ftp_err("ID mismatch (%d != %d)\n", id, expected_id); return -1; } if(type == SSH2_FXP_STATUS) { status = buffer_get_int(&msg); if (status == SSH2_FX_EOF) break; else { ftp_err("Couldn't read from remote " "file \"%s\" : %s\n", remote_path, fx2txt(status)); ssh_close(handle, handle_len); goto done; } } else if (type != SSH2_FXP_DATA) { ftp_err("Expected SSH2_FXP_DATA(%d) packet, got %s (%d)\n", SSH2_FXP_DATA, ssh_reply2txt(type), type); return -1; } data = buffer_get_string(&msg, &len); if (len > COPY_SIZE) { ftp_err("Received more data than asked for %d > %d\n", len, COPY_SIZE); return -1; } if(ftp_sigints() > 0) { ftp_trace("break due to sigint\n"); break; } if(atomicio(write, fileno(local_fp), data, len) != len) { ftp_err("Couldn't write: %s\n", strerror(errno)); ssh_close(handle, handle_len); ftp->ti.ioerror = true; status = -1; free(data); goto done; } offset += len; free(data); ftp->ti.size += len; if(hookf) { time_t now = time(0); if(now > then) { hookf(&ftp->ti); then = now; } } } status = ssh_close(handle, handle_len); ftp_set_close_handler();done: buffer_free(&msg); free(handle); return status;}int ssh_send_binary(const char *remote_path, FILE *local_fp, ftp_transfer_func hookf, u_int64_t offset){ u_int handle_len, id;/* u_int64_t offset;*/ char *handle; Buffer msg; Attrib a; int status; time_t then = time(0) - 1; struct stat sb; ftp_set_close_handler(); if(hookf) hookf(&ftp->ti); ftp->ti.begin = false; if(fstat(fileno(local_fp), &sb) == -1) { ftp_err("Couldn't fstat local file: %s\n", strerror(errno)); return -1; } stat_to_attrib(&sb, &a); a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; a.perm &= 0777; a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; buffer_init(&msg); /* Send open request */ id = ftp->ssh_id++; buffer_put_char(&msg, SSH2_FXP_OPEN); buffer_put_int(&msg, id); buffer_put_cstring(&msg, remote_path); /* if offset > 0, we are either appending or resuming a previous * download, so we should not truncate the file */ buffer_put_int(&msg, SSH2_FXF_WRITE | SSH2_FXF_CREAT | (offset == 0 ? SSH2_FXF_TRUNC : 0)); encode_attrib(&msg, &a); ssh_cmd(&msg); buffer_clear(&msg); handle = ssh_get_handle(id, &handle_len); if(handle == 0) { buffer_free(&msg); return -1; } /* Read from local and write to remote */ while(true) { int len; char data[COPY_SIZE]; /* * Can't use atomicio here because it returns 0 on EOF, thus losing * the last block of the file */ do len = read(fileno(local_fp), data, COPY_SIZE); while((len == -1) && (errno == EINTR || errno == EAGAIN)); if(len == -1) { ftp_err("Couldn't read from file: %s\n", strerror(errno)); return -1; } if(len == 0) break; buffer_clear(&msg); buffer_put_char(&msg, SSH2_FXP_WRITE); buffer_put_int(&msg, ++id); buffer_put_string(&msg, handle, handle_len); buffer_put_int64(&msg, offset); buffer_put_string(&msg, data, len); ssh_cmd(&msg); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't write to remote file \"%s\": %s\n", remote_path, fx2txt(status)); ssh_close(handle, handle_len); goto done; } offset += len; ftp->ti.size += len; if(hookf) { time_t now = time(0); if(now > then) { hookf(&ftp->ti); then = now; } } } status = ssh_close(handle, handle_len);done: free(handle); buffer_free(&msg); return status;}char *ssh_readlink(char *path){ Buffer msg; u_int type, expected_id, count, id; char *filename, *longname; Attrib *a; expected_id = id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_READLINK, path, strlen(path)); buffer_init(&msg); if(ssh_reply(&msg) == -1) return 0; type = buffer_get_char(&msg); id = buffer_get_int(&msg); if(id != expected_id) { ftp_err("ID mismatch (%d != %d)", id, expected_id); return 0; } if(type == SSH2_FXP_STATUS) { u_int status = buffer_get_int(&msg); ftp_err("Couldn't readlink: %s", fx2txt(status)); return 0; } else if(type != SSH2_FXP_NAME) { ftp_err("Expected SSH2_FXP_NAME (%d) packet, got %s (%d)", SSH2_FXP_NAME, ssh_reply2txt(type), type); return 0; } count = buffer_get_int(&msg); if(count != 1) { ftp_err("Got multiple names (%d) from SSH2_FXP_READLINK", count); return 0; } filename = buffer_get_string(&msg, 0); longname = buffer_get_string(&msg, 0); a = decode_attrib(&msg); free(longname); buffer_free(&msg); return filename;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -