aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <mail@cynapses.org>2009-07-25 11:54:21 +0200
committerAndreas Schneider <mail@cynapses.org>2009-07-25 12:34:25 +0200
commita1c7dd99bedf7a55484e7ed226af386f6f005a0b (patch)
tree198ae74e9411f80a5ba74403ce1db0c413998adb
parent11a6ed907d7d54a388ee1eb148803a326cee54f6 (diff)
downloadlibssh-a1c7dd99bedf7a55484e7ed226af386f6f005a0b.tar.gz
libssh-a1c7dd99bedf7a55484e7ed226af386f6f005a0b.tar.xz
libssh-a1c7dd99bedf7a55484e7ed226af386f6f005a0b.zip
Add sftp_readlink function.
-rw-r--r--include/libssh/sftp.h11
-rw-r--r--libssh/sftp.c74
2 files changed, 85 insertions, 0 deletions
diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h
index 8aede051..83fb40c3 100644
--- a/include/libssh/sftp.h
+++ b/include/libssh/sftp.h
@@ -606,6 +606,17 @@ int sftp_utimes(SFTP_SESSION *sftp, const char *file, const struct timeval *time
int sftp_symlink(SFTP_SESSION *sftp, const char *target, const char *dest);
/**
+ * @brief Read the value of a symbolic link.
+ *
+ * @param sftp The sftp session handle.
+ *
+ * @param path Specifies the path name of the symlink to be read.
+ *
+ * @return The target of the link, NULL on error.
+ */
+char *sftp_readlink(SFTP_SESSION *sftp, const char *path);
+
+/**
* @brief Canonicalize a sftp path.
*
* @param sftp The sftp session handle.
diff --git a/libssh/sftp.c b/libssh/sftp.c
index f0007d8c..e86a262b 100644
--- a/libssh/sftp.c
+++ b/libssh/sftp.c
@@ -2295,6 +2295,80 @@ int sftp_symlink(SFTP_SESSION *sftp, const char *target, const char *dest) {
return -1;
}
+char *sftp_readlink(SFTP_SESSION *sftp, const char *path) {
+ STATUS_MESSAGE *status = NULL;
+ SFTP_MESSAGE *msg = NULL;
+ STRING *path_s = NULL;
+ STRING *link_s = NULL;
+ BUFFER *buffer;
+ char *link;
+ u32 ignored;
+ u32 id;
+
+ if (sftp == NULL || path == NULL) {
+ return NULL;
+ }
+
+ buffer = buffer_new();
+ if (buffer == NULL) {
+ return NULL;
+ }
+
+ path_s = string_from_char(path);
+ if (path_s == NULL) {
+ buffer_free(buffer);
+ return NULL;
+ }
+
+ id = sftp_get_new_id(sftp);
+ if (buffer_add_u32(buffer, id) < 0 ||
+ buffer_add_ssh_string(buffer, path_s) < 0 ||
+ sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) {
+ buffer_free(buffer);
+ string_free(path_s);
+ return NULL;
+ }
+ buffer_free(buffer);
+ string_free(path_s);
+
+ while (msg == NULL) {
+ if (sftp_read_and_dispatch(sftp) < 0) {
+ return NULL;
+ }
+ msg = sftp_dequeue(sftp, id);
+ }
+
+ if (msg->packet_type == SSH_FXP_NAME) {
+ /* we don't care about "count" */
+ buffer_get_u32(msg->payload, &ignored);
+ /* we only care about the file name string */
+ link_s = buffer_get_ssh_string(msg->payload);
+ sftp_message_free(msg);
+ if (link_s == NULL) {
+ return NULL;
+ }
+ link = string_to_char(link_s);
+ string_free(link_s);
+
+ return link;
+ } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (status == NULL) {
+ return NULL;
+ }
+ ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
+ "SFTP server: %s", status->errormsg);
+ status_msg_free(status);
+ } else { /* this shouldn't happen */
+ ssh_set_error(sftp->session, SSH_FATAL,
+ "Received message %d when attempting to set stats", msg->packet_type);
+ sftp_message_free(msg);
+ }
+
+ return NULL;
+}
+
/* another code written by Nick */
char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path) {
STATUS_MESSAGE *status = NULL;