diff options
author | Andreas Schneider <mail@cynapses.org> | 2008-12-22 09:50:40 +0000 |
---|---|---|
committer | Andreas Schneider <mail@cynapses.org> | 2008-12-22 09:50:40 +0000 |
commit | c3e026c3034d5d51f011a75b191f46c3891069cf (patch) | |
tree | e8a5e16a5443bfa2fb0de3d682934b82cd164782 | |
parent | a104c2eda38d2fbf81285e0223ed755783792169 (diff) | |
download | libssh-c3e026c3034d5d51f011a75b191f46c3891069cf.tar.gz libssh-c3e026c3034d5d51f011a75b191f46c3891069cf.tar.xz libssh-c3e026c3034d5d51f011a75b191f46c3891069cf.zip |
Create POSIX like sftp functions.
This breaks the API and will be libssh 0.3.
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@195 7dcaeef0-15fb-0310-b436-a5af3365683c
-rw-r--r-- | include/libssh/priv.h | 6 | ||||
-rw-r--r-- | include/libssh/sftp.h | 30 | ||||
-rw-r--r-- | libssh/sftp.c | 100 | ||||
-rw-r--r-- | sample.c | 18 |
4 files changed, 117 insertions, 37 deletions
diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 3df07b7..c7afb42 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -636,6 +636,12 @@ int ssh_handle_packets(SSH_SESSION *session); #define enter_function() _enter_function(session) #define leave_function() _leave_function(session) +/** Zero a structure */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/** Zero a structure given a pointer to the structure */ +#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0) + #ifdef HAVE_LIBGCRYPT /* gcrypt_missing.c */ int my_gcry_dec2bn(bignum *bn, const char *data); diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h index a697baa..db3e9dd 100644 --- a/include/libssh/sftp.h +++ b/include/libssh/sftp.h @@ -26,6 +26,12 @@ MA 02111-1307, USA. */ extern "C" { #endif +#ifdef __GNUC__ +#define SFTP_DEPRECATED __attribute__ ((deprecated)) +#else +#define SFTP_DEPRECATED +#endif + typedef struct sftp_session_struct { SSH_SESSION *session; CHANNEL *channel; @@ -143,23 +149,27 @@ SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, const char *path); /* sftp_lstat stats a file but doesn't follow symlinks */ SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file); void sftp_attributes_free(SFTP_ATTRIBUTES *file); -int sftp_dir_close(SFTP_DIR *dir); -int sftp_file_close(SFTP_FILE *file); +int sftp_closedir(SFTP_DIR *dir); +int sftp_close(SFTP_FILE *file); /* access are the sames than the ones from ansi fopen() */ -SFTP_FILE *sftp_open(SFTP_SESSION *session, const char *file, int access, SFTP_ATTRIBUTES *attr); -int sftp_read(SFTP_FILE *file, void *dest, int len); +SFTP_FILE *sftp_open(SFTP_SESSION *session, const char *file, int access, mode_t mode); +ssize_t sftp_read(SFTP_FILE *file, void *buf, size_t count); u32 sftp_async_read_begin(SFTP_FILE *file, int len); int sftp_async_read(SFTP_FILE *file, void *data, int len, u32 id); -int sftp_write(SFTP_FILE *file, const void *source, int len); +ssize_t sftp_write(SFTP_FILE *file, const void *buf, size_t count); void sftp_seek(SFTP_FILE *file, int new_offset); void sftp_seek64(SFTP_FILE *file, u64 new_offset); unsigned long sftp_tell(SFTP_FILE *file); void sftp_rewind(SFTP_FILE *file); -int sftp_rm(SFTP_SESSION *sftp, char *file); +int sftp_rm(SFTP_SESSION *sftp, const char *file) SFTP_DEPRECATED; +int sftp_unlink(SFTP_SESSION *sftp, const char *file); int sftp_rmdir(SFTP_SESSION *sftp, const char *directory); -int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, SFTP_ATTRIBUTES *attr); +int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, mode_t mode); int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname); int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr); +int sftp_chown(SFTP_SESSION *sftp, const char *file, uid_t owner, gid_t group); +int sftp_chmod(SFTP_SESSION *sftp, const char *file, mode_t mode); +int sftp_utimes(SFTP_SESSION *sftp, const char *file, const struct timeval *times); char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path); #ifndef NO_SERVER @@ -270,6 +280,11 @@ void sftp_handle_remove(SFTP_SESSION *sftp, void *handle); #define SSH_FXF_EXCL 0x20 #define SSH_FXF_TEXT 0x40 +/* rename flags */ +#define SSH_FXF_RENAME_OVERWRITE 0x00000001 +#define SSH_FXF_RENAME_ATOMIC 0x00000002 +#define SSH_FXF_RENAME_NATIVE 0x00000004 + #define SFTP_OPEN SSH_FXP_OPEN #define SFTP_CLOSE SSH_FXP_CLOSE #define SFTP_READ SSH_FXP_READ @@ -290,6 +305,7 @@ void sftp_handle_remove(SFTP_SESSION *sftp, void *handle); #define SFTP_SYMLINK SSH_FXP_SYMLINK + #ifdef __cplusplus } ; #endif diff --git a/libssh/sftp.c b/libssh/sftp.c index ff2f7d9..17b83a6 100644 --- a/libssh/sftp.c +++ b/libssh/sftp.c @@ -896,7 +896,7 @@ static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){ * \returns SSH_ERROR An error happened * \see sftp_file_open() */ -int sftp_file_close(SFTP_FILE *file){ +int sftp_close(SFTP_FILE *file){ int err=SSH_NO_ERROR; if(file->name) free(file->name); @@ -904,6 +904,7 @@ int sftp_file_close(SFTP_FILE *file){ err=sftp_handle_close(file->sftp,file->handle); free(file->handle); } + /* FIXME: check server response and implement errno */ free(file); return err; } @@ -914,7 +915,7 @@ int sftp_file_close(SFTP_FILE *file){ * \returns SSH_ERROR An error happened * \see sftp_opendir() */ -int sftp_dir_close(SFTP_DIR *dir){ +int sftp_closedir(SFTP_DIR *dir){ int err=SSH_NO_ERROR; if(dir->name) free(dir->name); @@ -922,6 +923,7 @@ int sftp_dir_close(SFTP_DIR *dir){ err=sftp_handle_close(dir->sftp,dir->handle); free(dir->handle); } + /* FIXME: check server response and implement errno */ if(dir->buffer) buffer_free(dir->buffer); free(dir); @@ -931,14 +933,20 @@ int sftp_dir_close(SFTP_DIR *dir){ /** \brief Open a remote file * \todo please complete doc */ -SFTP_FILE *sftp_open(SFTP_SESSION *sftp, const char *file, int access, SFTP_ATTRIBUTES *attr){ +SFTP_FILE *sftp_open(SFTP_SESSION *sftp, const char *file, int access, mode_t mode){ SFTP_FILE *handle; SFTP_MESSAGE *msg=NULL; STATUS_MESSAGE *status; + SFTP_ATTRIBUTES attr; u32 flags=0; u32 id=sftp_get_new_id(sftp); BUFFER *buffer=buffer_new(); STRING *filename; + + ZERO_STRUCT(attr); + attr.permissions = mode; + attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; + if(access == O_RDONLY) flags|=SSH_FXF_READ; // if any of the other flag is set, READ should not be set initialy if(access & O_WRONLY) @@ -956,7 +964,7 @@ SFTP_FILE *sftp_open(SFTP_SESSION *sftp, const char *file, int access, SFTP_ATTR buffer_add_ssh_string(buffer,filename); free(filename); buffer_add_u32(buffer,htonl(flags)); - buffer_add_attributes(buffer,attr); + buffer_add_attributes(buffer,&attr); sftp_packet_write(sftp,SSH_FXP_OPEN,buffer); buffer_free(buffer); while(!msg){ @@ -993,7 +1001,7 @@ void sftp_file_set_blocking(SFTP_FILE *handle){ handle->nonblocking=0; } -int sftp_read(SFTP_FILE *handle, void *data, int len){ +ssize_t sftp_read(SFTP_FILE *handle, void *buf, size_t count){ SFTP_MESSAGE *msg=NULL; STATUS_MESSAGE *status; SFTP_SESSION *sftp=handle->sftp; @@ -1008,7 +1016,7 @@ int sftp_read(SFTP_FILE *handle, void *data, int len){ buffer_add_u32(buffer,id); buffer_add_ssh_string(buffer,handle->handle); buffer_add_u64(buffer,htonll(handle->offset)); - buffer_add_u32(buffer,htonl(len)); + buffer_add_u32(buffer,htonl(count)); sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer); buffer_free(buffer); while(!msg){ @@ -1048,17 +1056,17 @@ int sftp_read(SFTP_FILE *handle, void *data, int len){ ssh_set_error(sftp->session,SSH_FATAL,"Received invalid DATA packet from sftp server"); return -1; } - if(string_len(datastring)>len){ + if(string_len(datastring) > count){ ssh_set_error(sftp->session,SSH_FATAL,"Received a too big DATA packet from sftp server : %d and asked for %d", - string_len(datastring),len); + string_len(datastring), count); free(datastring); return -1; } - len=string_len(datastring); - handle->offset+=len; - memcpy(data,datastring->string,len); + count = string_len(datastring); + handle->offset+= count; + memcpy(buf, datastring->string, count); free(datastring); - return len; + return count; default: ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type); sftp_message_free(msg); @@ -1195,7 +1203,7 @@ int sftp_async_read(SFTP_FILE *file, void *data, int size, u32 id){ sftp_leave_function(); } -int sftp_write(SFTP_FILE *file, const void *data, int len){ +ssize_t sftp_write(SFTP_FILE *file, const void *buf, size_t count){ SFTP_MESSAGE *msg=NULL; STATUS_MESSAGE *status; STRING *datastring; @@ -1208,8 +1216,8 @@ int sftp_write(SFTP_FILE *file, const void *data, int len){ buffer_add_u32(buffer,id); buffer_add_ssh_string(buffer,file->handle); buffer_add_u64(buffer,htonll(file->offset)); - datastring=string_new(len); - string_fill(datastring,data,len); + datastring=string_new(count); + string_fill(datastring, buf, count); buffer_add_ssh_string(buffer,datastring); free(datastring); if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){ @@ -1231,14 +1239,14 @@ int sftp_write(SFTP_FILE *file, const void *data, int len){ sftp_set_errno(sftp, status->status); switch (status->status) { case SSH_FX_OK: - file->offset+=len; + file->offset += count; status_msg_free(status); - return err ? err : len; + return err ? err : count; default: break; } ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); - file->offset+=len; + file->offset += count; status_msg_free(status); return -1; default: @@ -1264,8 +1272,12 @@ void sftp_rewind(SFTP_FILE *file){ file->offset=0; } +int sftp_rm(SFTP_SESSION *sftp, const char *file) { + return sftp_unlink(sftp, file); +} + /* code written by Nick */ -int sftp_rm(SFTP_SESSION *sftp, char *file) { +int sftp_unlink(SFTP_SESSION *sftp, const char *file) { u32 id = sftp_get_new_id(sftp); BUFFER *buffer = buffer_new(); STRING *filename = string_from_char(file); @@ -1357,18 +1369,23 @@ int sftp_rmdir(SFTP_SESSION *sftp, const char *directory) { } /* Code written by Nick */ -int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, SFTP_ATTRIBUTES *attr) { +int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, mode_t mode) { u32 id = sftp_get_new_id(sftp); BUFFER *buffer = buffer_new(); STRING *path = string_from_char(directory); SFTP_MESSAGE *msg = NULL; STATUS_MESSAGE *status = NULL; + SFTP_ATTRIBUTES attr; SFTP_ATTRIBUTES *errno_attr = NULL; + ZERO_STRUCT(attr); + attr.permissions = mode; + attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; + buffer_add_u32(buffer, id); buffer_add_ssh_string(buffer, path); free(path); - buffer_add_attributes(buffer, attr); + buffer_add_attributes(buffer, &attr); sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer); buffer_free(buffer); while (!msg) { @@ -1428,6 +1445,8 @@ int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname) { free(oldpath); buffer_add_ssh_string(buffer, newpath); free(newpath); + /* POSIX rename atomically replaces newpath, we should do the same */ + buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE); sftp_packet_write(sftp, SSH_FXP_RENAME, buffer); buffer_free(buffer); while (!msg) { @@ -1504,6 +1523,45 @@ int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr) { return -1; } +int sftp_chown(SFTP_SESSION *sftp, const char *file, uid_t owner, gid_t group) { + SFTP_ATTRIBUTES attr; + + ZERO_STRUCT(attr); + + attr.uid = owner; + attr.gid = group; + attr.flags = SSH_FILEXFER_ATTR_OWNERGROUP; + + return sftp_setstat(sftp, file, &attr); +} + +int sftp_chmod(SFTP_SESSION *sftp, const char *file, mode_t mode) { + SFTP_ATTRIBUTES attr; + + ZERO_STRUCT(attr); + attr.permissions = mode; + attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; + + return sftp_setstat(sftp, file, &attr); +} + +int sftp_utimes(SFTP_SESSION *sftp, const char *file, const struct timeval *times) { + SFTP_ATTRIBUTES attr; + + ZERO_STRUCT(attr); + + attr.atime = times[0].tv_sec; + attr.atime_nseconds = times[0].tv_usec; + + attr.mtime = times[1].tv_sec; + attr.mtime_nseconds = times[1].tv_usec; + + attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME | + SSH_FILEXFER_ATTR_SUBSECOND_TIMES; + + return sftp_setstat(sftp, file, &attr); +} + /* another code written by Nick */ char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path) { @@ -290,20 +290,20 @@ void do_sftp(SSH_SESSION *session){ ssh_say(0,"error : %s\n",ssh_get_error(session)); return; } - if(sftp_dir_close(dir)){ + if(sftp_closedir(dir)){ ssh_say(0,"Error : %s\n",ssh_get_error(session)); return; } /* this will open a file and copy it into your /home directory */ /* the small buffer size was intended to stress the library. of course, you can use a buffer till 20kbytes without problem */ - fichier=sftp_open(sftp,"/usr/bin/ssh",O_RDONLY,NULL); + fichier=sftp_open(sftp,"/usr/bin/ssh",O_RDONLY, 0); if(!fichier){ ssh_say(0,"Error opening /usr/bin/ssh : %s\n",ssh_get_error(session)); return; } /* open a file for writing... */ - to=sftp_open(sftp,"ssh-copy",O_WRONLY | O_CREAT,NULL); + to=sftp_open(sftp,"ssh-copy",O_WRONLY | O_CREAT, 0); if(!to){ ssh_say(0,"Error opening ssh-copy for writing : %s\n",ssh_get_error(session)); return; @@ -316,11 +316,11 @@ void do_sftp(SSH_SESSION *session){ } printf("finished\n"); if(len<0) - ssh_say(0,"Error reading file : %s\n",ssh_get_error(session)); - sftp_file_close(fichier); - sftp_file_close(to); - printf("fichiers ferm�\n"); - to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT,NULL); + ssh_say(0,"Error reading file : %s\n",ssh_get_error(session)); + sftp_close(fichier); + sftp_close(to); + printf("fichiers ferm\n"); + to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT, 0644); for(i=0;i<1000;++i){ len=sftp_write(to,data,8000); printf("wrote %d bytes\n",len); @@ -328,7 +328,7 @@ void do_sftp(SSH_SESSION *session){ printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session)); } } - sftp_file_close(to); + sftp_close(to); /* close the sftp session */ sftp_free(sftp); printf("session sftp termin�\n"); |