⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sftp-client.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (status != SSH2_FX_OK)		error("Couldn't fsetstat: %s", fx2txt(status));	return(status);}char *do_realpath(struct sftp_conn *conn, char *path){	Buffer msg;	u_int type, expected_id, count, id;	char *filename, *longname;	Attrib *a;	expected_id = id = conn->msg_id++;	send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,	    strlen(path));	buffer_init(&msg);	get_msg(conn->fd_in, &msg);	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	if (id != expected_id)		fatal("ID mismatch (%d != %d)", id, expected_id);	if (type == SSH2_FXP_STATUS) {		u_int status = buffer_get_int(&msg);		error("Couldn't canonicalise: %s", fx2txt(status));		return(NULL);	} else if (type != SSH2_FXP_NAME)		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",		    SSH2_FXP_NAME, type);	count = buffer_get_int(&msg);	if (count != 1)		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);	filename = buffer_get_string(&msg, NULL);	longname = buffer_get_string(&msg, NULL);	a = decode_attrib(&msg);	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);	xfree(longname);	buffer_free(&msg);	return(filename);}intdo_rename(struct sftp_conn *conn, char *oldpath, char *newpath){	Buffer msg;	u_int status, id;	buffer_init(&msg);	/* Send rename request */	id = conn->msg_id++;	buffer_put_char(&msg, SSH2_FXP_RENAME);	buffer_put_int(&msg, id);	buffer_put_cstring(&msg, oldpath);	buffer_put_cstring(&msg, newpath);	send_msg(conn->fd_out, &msg);	debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,	    newpath);	buffer_free(&msg);	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,		    newpath, fx2txt(status));	return(status);}intdo_symlink(struct sftp_conn *conn, char *oldpath, char *newpath){	Buffer msg;	u_int status, id;	if (conn->version < 3) {		error("This server does not support the symlink operation");		return(SSH2_FX_OP_UNSUPPORTED);	}	buffer_init(&msg);	/* Send rename request */	id = conn->msg_id++;	buffer_put_char(&msg, SSH2_FXP_SYMLINK);	buffer_put_int(&msg, id);	buffer_put_cstring(&msg, oldpath);	buffer_put_cstring(&msg, newpath);	send_msg(conn->fd_out, &msg);	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,	    newpath);	buffer_free(&msg);	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,		    newpath, fx2txt(status));	return(status);}char *do_readlink(struct sftp_conn *conn, char *path){	Buffer msg;	u_int type, expected_id, count, id;	char *filename, *longname;	Attrib *a;	expected_id = id = conn->msg_id++;	send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,	    strlen(path));	buffer_init(&msg);	get_msg(conn->fd_in, &msg);	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	if (id != expected_id)		fatal("ID mismatch (%d != %d)", id, expected_id);	if (type == SSH2_FXP_STATUS) {		u_int status = buffer_get_int(&msg);		error("Couldn't readlink: %s", fx2txt(status));		return(NULL);	} else if (type != SSH2_FXP_NAME)		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",		    SSH2_FXP_NAME, type);	count = buffer_get_int(&msg);	if (count != 1)		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);	filename = buffer_get_string(&msg, NULL);	longname = buffer_get_string(&msg, NULL);	a = decode_attrib(&msg);	debug3("SSH_FXP_READLINK %s -> %s", path, filename);	xfree(longname);	buffer_free(&msg);	return(filename);}static voidsend_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,    char *handle, u_int handle_len){	Buffer msg;	buffer_init(&msg);	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, len);	send_msg(fd_out, &msg);	buffer_free(&msg);}intdo_download(struct sftp_conn *conn, char *remote_path, char *local_path,    int pflag){	Attrib junk, *a;	Buffer msg;	char *handle;	int local_fd, status, num_req, max_req, write_error;	int read_error, write_errno;	u_int64_t offset, size;	u_int handle_len, mode, type, id, buflen;	struct request {		u_int id;		u_int len;		u_int64_t offset;		TAILQ_ENTRY(request) tq;	};	TAILQ_HEAD(reqhead, request) requests;	struct request *req;	TAILQ_INIT(&requests);	a = do_stat(conn, remote_path, 0);	if (a == NULL)		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)) {		error("Cannot download a directory: %s", remote_path);		return(-1);	}	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)		size = a->size;	else		size = 0;	buflen = conn->transfer_buflen;	buffer_init(&msg);	/* Send open request */	id = conn->msg_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);	send_msg(conn->fd_out, &msg);	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);	handle = get_handle(conn->fd_in, id, &handle_len);	if (handle == NULL) {		buffer_free(&msg);		return(-1);	}	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);	if (local_fd == -1) {		error("Couldn't open local file \"%s\" for writing: %s",		    local_path, strerror(errno));		buffer_free(&msg);		xfree(handle);		return(-1);	}	/* Read from remote and write to local */	write_error = read_error = write_errno = num_req = offset = 0;	max_req = 1;	while (num_req > 0 || max_req > 0) {		char *data;		u_int len;		/* Send some more requests */		while (num_req < max_req) {			debug3("Request range %llu -> %llu (%d/%d)",			    (unsigned long long)offset,			    (unsigned long long)offset + buflen - 1,			    num_req, max_req);			req = xmalloc(sizeof(*req));			req->id = conn->msg_id++;			req->len = buflen;			req->offset = offset;			offset += buflen;			num_req++;			TAILQ_INSERT_TAIL(&requests, req, tq);			send_read_request(conn->fd_out, req->id, req->offset,			    req->len, handle, handle_len);		}		buffer_clear(&msg);		get_msg(conn->fd_in, &msg);		type = buffer_get_char(&msg);		id = buffer_get_int(&msg);		debug3("Received reply T:%d I:%d R:%d", type, id, max_req);		/* Find the request in our queue */		for(req = TAILQ_FIRST(&requests);		    req != NULL && req->id != id;		    req = TAILQ_NEXT(req, tq))			;		if (req == NULL)			fatal("Unexpected reply %u", id);		switch (type) {		case SSH2_FXP_STATUS:			status = buffer_get_int(&msg);			if (status != SSH2_FX_EOF)				read_error = 1;			max_req = 0;			TAILQ_REMOVE(&requests, req, tq);			xfree(req);			num_req--;			break;		case SSH2_FXP_DATA:			data = buffer_get_string(&msg, &len);			debug3("Received data %llu -> %llu",			    (unsigned long long)req->offset,			    (unsigned long long)req->offset + len - 1);			if (len > req->len)				fatal("Received more data than asked for "				      "%d > %d", len, req->len);			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||			     atomicio(write, local_fd, data, len) != len) &&			    !write_error) {				write_errno = errno;				write_error = 1;				max_req = 0;			}			xfree(data);			if (len == req->len) {				TAILQ_REMOVE(&requests, req, tq);				xfree(req);				num_req--;			} else {				/* Resend the request for the missing data */				debug3("Short data block, re-requesting "				    "%llu -> %llu (%2d)",				    (unsigned long long)req->offset + len,				    (unsigned long long)req->offset +				    req->len - 1, num_req);				req->id = conn->msg_id++;				req->len -= len;				req->offset += len;				send_read_request(conn->fd_out, req->id,				    req->offset, req->len, handle, handle_len);				/* Reduce the request size */				if (len < buflen)					buflen = MAX(MIN_READ_SIZE, len);			}			if (max_req > 0) { /* max_req = 0 iff EOF received */				if (size > 0 && offset > size) {					/* Only one request at a time					 * after the expected EOF */					debug3("Finish at %llu (%2d)",					    (unsigned long long)offset,					    num_req);					max_req = 1;				}				else if (max_req < conn->num_requests + 1) {					++max_req;				}			}			break;		default:			fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",			    SSH2_FXP_DATA, type);		}	}	/* Sanity check */	if (TAILQ_FIRST(&requests) != NULL)		fatal("Transfer complete, but requests still in queue");	if (read_error) {		error("Couldn't read from remote file \"%s\" : %s",		    remote_path, fx2txt(status));		do_close(conn, handle, handle_len);	} else if (write_error) {		error("Couldn't write to \"%s\": %s", local_path,		    strerror(write_errno));		status = -1;		do_close(conn, handle, handle_len);	} else {		status = do_close(conn, handle, handle_len);		/* Override umask and utimes if asked */#ifdef HAVE_FCHMOD		if (pflag && fchmod(local_fd, mode) == -1)#else 		if (pflag && chmod(local_path, mode) == -1)#endif /* HAVE_FCHMOD */			error("Couldn't set mode on \"%s\": %s", local_path,			      strerror(errno));		if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {			struct timeval tv[2];			tv[0].tv_sec = a->atime;			tv[1].tv_sec = a->mtime;			tv[0].tv_usec = tv[1].tv_usec = 0;			if (utimes(local_path, tv) == -1)				error("Can't set times on \"%s\": %s",				      local_path, strerror(errno));		}	}	close(local_fd);	buffer_free(&msg);	xfree(handle);	return(status);}intdo_upload(struct sftp_conn *conn, char *local_path, char *remote_path,    int pflag){	int local_fd, status;	u_int handle_len, id, type;	u_int64_t offset;	char *handle, *data;	Buffer msg;	struct stat sb;	Attrib a;	u_int32_t startid;	u_int32_t ackid;	struct outstanding_ack {		u_int id;		u_int len;		u_int64_t offset;		TAILQ_ENTRY(outstanding_ack) tq;	};	TAILQ_HEAD(ackhead, outstanding_ack) acks;	struct outstanding_ack *ack;	TAILQ_INIT(&acks);	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {		error("Couldn't open local file \"%s\" for reading: %s",		    local_path, strerror(errno));		return(-1);	}	if (fstat(local_fd, &sb) == -1) {		error("Couldn't fstat local file \"%s\": %s",		    local_path, strerror(errno));		close(local_fd);		return(-1);	}	stat_to_attrib(&sb, &a);	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;	a.perm &= 0777;	if (!pflag)		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;	buffer_init(&msg);	/* Send open request */	id = conn->msg_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_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);	encode_attrib(&msg, &a);	send_msg(conn->fd_out, &msg);	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);	buffer_clear(&msg);	handle = get_handle(conn->fd_in, id, &handle_len);	if (handle == NULL) {		close(local_fd);		buffer_free(&msg);		return(-1);	}	startid = ackid = id + 1;	data = xmalloc(conn->transfer_buflen);	/* Read from local and write to remote */	offset = 0;	for (;;) {		int len;		/*		 * Can't use atomicio here because it returns 0 on EOF, thus losing		 * the last block of the file		 */		do			len = read(local_fd, data, conn->transfer_buflen);		while ((len == -1) && (errno == EINTR || errno == EAGAIN));		if (len == -1)			fatal("Couldn't read from \"%s\": %s", local_path,			    strerror(errno));		if (len != 0) {			ack = xmalloc(sizeof(*ack));			ack->id = ++id;			ack->offset = offset;			ack->len = len;			TAILQ_INSERT_TAIL(&acks, ack, tq);			buffer_clear(&msg);			buffer_put_char(&msg, SSH2_FXP_WRITE);			buffer_put_int(&msg, ack->id);			buffer_put_string(&msg, handle, handle_len);			buffer_put_int64(&msg, offset);			buffer_put_string(&msg, data, len);			send_msg(conn->fd_out, &msg);			debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",			       id, (unsigned long long)offset, len);		} else if (TAILQ_FIRST(&acks) == NULL)			break;		if (ack == NULL)			fatal("Unexpected ACK %u", id);		if (id == startid || len == 0 ||		    id - ackid >= conn->num_requests) {			u_int r_id;			buffer_clear(&msg);			get_msg(conn->fd_in, &msg);			type = buffer_get_char(&msg);			r_id = buffer_get_int(&msg);			if (type != SSH2_FXP_STATUS)				fatal("Expected SSH2_FXP_STATUS(%d) packet, "				    "got %d", SSH2_FXP_STATUS, type);			status = buffer_get_int(&msg);			debug3("SSH2_FXP_STATUS %d", status);			/* Find the request in our queue */			for(ack = TAILQ_FIRST(&acks);			    ack != NULL && ack->id != r_id;			    ack = TAILQ_NEXT(ack, tq))				;			if (ack == NULL)				fatal("Can't find request for ID %d", r_id);			TAILQ_REMOVE(&acks, ack, tq);			if (status != SSH2_FX_OK) {				error("Couldn't write to remote file \"%s\": %s",				      remote_path, fx2txt(status));				do_close(conn, handle, handle_len);				close(local_fd);				goto done;			}			debug3("In write loop, ack for %u %d bytes at %llu",			   ack->id, ack->len, (unsigned long long)ack->offset);			++ackid;			free(ack);		}		offset += len;	}	xfree(data);	if (close(local_fd) == -1) {		error("Couldn't close local file \"%s\": %s", local_path,		    strerror(errno));		do_close(conn, handle, handle_len);		status = -1;		goto done;	}	/* Override umask and utimes if asked */	if (pflag)		do_fsetstat(conn, handle, handle_len, &a);	status = do_close(conn, handle, handle_len);done:	xfree(handle);	buffer_free(&msg);	return(status);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -