1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-12-02 01:17:52 +03:00

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
This commit is contained in:
Andreas Schneider
2008-12-22 09:50:40 +00:00
parent a104c2eda3
commit c3e026c303
4 changed files with 117 additions and 37 deletions

View File

@@ -636,6 +636,12 @@ int ssh_handle_packets(SSH_SESSION *session);
#define enter_function() _enter_function(session) #define enter_function() _enter_function(session)
#define leave_function() _leave_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 #ifdef HAVE_LIBGCRYPT
/* gcrypt_missing.c */ /* gcrypt_missing.c */
int my_gcry_dec2bn(bignum *bn, const char *data); int my_gcry_dec2bn(bignum *bn, const char *data);

View File

@@ -26,6 +26,12 @@ MA 02111-1307, USA. */
extern "C" { extern "C" {
#endif #endif
#ifdef __GNUC__
#define SFTP_DEPRECATED __attribute__ ((deprecated))
#else
#define SFTP_DEPRECATED
#endif
typedef struct sftp_session_struct { typedef struct sftp_session_struct {
SSH_SESSION *session; SSH_SESSION *session;
CHANNEL *channel; 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_lstat stats a file but doesn't follow symlinks */
SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file); SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file);
void sftp_attributes_free(SFTP_ATTRIBUTES *file); void sftp_attributes_free(SFTP_ATTRIBUTES *file);
int sftp_dir_close(SFTP_DIR *dir); int sftp_closedir(SFTP_DIR *dir);
int sftp_file_close(SFTP_FILE *file); int sftp_close(SFTP_FILE *file);
/* access are the sames than the ones from ansi fopen() */ /* 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); SFTP_FILE *sftp_open(SFTP_SESSION *session, const char *file, int access, mode_t mode);
int sftp_read(SFTP_FILE *file, void *dest, int len); ssize_t sftp_read(SFTP_FILE *file, void *buf, size_t count);
u32 sftp_async_read_begin(SFTP_FILE *file, int len); 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_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_seek(SFTP_FILE *file, int new_offset);
void sftp_seek64(SFTP_FILE *file, u64 new_offset); void sftp_seek64(SFTP_FILE *file, u64 new_offset);
unsigned long sftp_tell(SFTP_FILE *file); unsigned long sftp_tell(SFTP_FILE *file);
void sftp_rewind(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_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_rename(SFTP_SESSION *sftp, const char *original, const char *newname);
int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr); 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); char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path);
#ifndef NO_SERVER #ifndef NO_SERVER
@@ -270,6 +280,11 @@ void sftp_handle_remove(SFTP_SESSION *sftp, void *handle);
#define SSH_FXF_EXCL 0x20 #define SSH_FXF_EXCL 0x20
#define SSH_FXF_TEXT 0x40 #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_OPEN SSH_FXP_OPEN
#define SFTP_CLOSE SSH_FXP_CLOSE #define SFTP_CLOSE SSH_FXP_CLOSE
#define SFTP_READ SSH_FXP_READ #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 #define SFTP_SYMLINK SSH_FXP_SYMLINK
#ifdef __cplusplus #ifdef __cplusplus
} ; } ;
#endif #endif

View File

@@ -896,7 +896,7 @@ static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){
* \returns SSH_ERROR An error happened * \returns SSH_ERROR An error happened
* \see sftp_file_open() * \see sftp_file_open()
*/ */
int sftp_file_close(SFTP_FILE *file){ int sftp_close(SFTP_FILE *file){
int err=SSH_NO_ERROR; int err=SSH_NO_ERROR;
if(file->name) if(file->name)
free(file->name); free(file->name);
@@ -904,6 +904,7 @@ int sftp_file_close(SFTP_FILE *file){
err=sftp_handle_close(file->sftp,file->handle); err=sftp_handle_close(file->sftp,file->handle);
free(file->handle); free(file->handle);
} }
/* FIXME: check server response and implement errno */
free(file); free(file);
return err; return err;
} }
@@ -914,7 +915,7 @@ int sftp_file_close(SFTP_FILE *file){
* \returns SSH_ERROR An error happened * \returns SSH_ERROR An error happened
* \see sftp_opendir() * \see sftp_opendir()
*/ */
int sftp_dir_close(SFTP_DIR *dir){ int sftp_closedir(SFTP_DIR *dir){
int err=SSH_NO_ERROR; int err=SSH_NO_ERROR;
if(dir->name) if(dir->name)
free(dir->name); free(dir->name);
@@ -922,6 +923,7 @@ int sftp_dir_close(SFTP_DIR *dir){
err=sftp_handle_close(dir->sftp,dir->handle); err=sftp_handle_close(dir->sftp,dir->handle);
free(dir->handle); free(dir->handle);
} }
/* FIXME: check server response and implement errno */
if(dir->buffer) if(dir->buffer)
buffer_free(dir->buffer); buffer_free(dir->buffer);
free(dir); free(dir);
@@ -931,14 +933,20 @@ int sftp_dir_close(SFTP_DIR *dir){
/** \brief Open a remote file /** \brief Open a remote file
* \todo please complete doc * \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_FILE *handle;
SFTP_MESSAGE *msg=NULL; SFTP_MESSAGE *msg=NULL;
STATUS_MESSAGE *status; STATUS_MESSAGE *status;
SFTP_ATTRIBUTES attr;
u32 flags=0; u32 flags=0;
u32 id=sftp_get_new_id(sftp); u32 id=sftp_get_new_id(sftp);
BUFFER *buffer=buffer_new(); BUFFER *buffer=buffer_new();
STRING *filename; STRING *filename;
ZERO_STRUCT(attr);
attr.permissions = mode;
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
if(access == O_RDONLY) if(access == O_RDONLY)
flags|=SSH_FXF_READ; // if any of the other flag is set, READ should not be set initialy flags|=SSH_FXF_READ; // if any of the other flag is set, READ should not be set initialy
if(access & O_WRONLY) 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); buffer_add_ssh_string(buffer,filename);
free(filename); free(filename);
buffer_add_u32(buffer,htonl(flags)); buffer_add_u32(buffer,htonl(flags));
buffer_add_attributes(buffer,attr); buffer_add_attributes(buffer,&attr);
sftp_packet_write(sftp,SSH_FXP_OPEN,buffer); sftp_packet_write(sftp,SSH_FXP_OPEN,buffer);
buffer_free(buffer); buffer_free(buffer);
while(!msg){ while(!msg){
@@ -993,7 +1001,7 @@ void sftp_file_set_blocking(SFTP_FILE *handle){
handle->nonblocking=0; 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; SFTP_MESSAGE *msg=NULL;
STATUS_MESSAGE *status; STATUS_MESSAGE *status;
SFTP_SESSION *sftp=handle->sftp; 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_u32(buffer,id);
buffer_add_ssh_string(buffer,handle->handle); buffer_add_ssh_string(buffer,handle->handle);
buffer_add_u64(buffer,htonll(handle->offset)); 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); sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer);
buffer_free(buffer); buffer_free(buffer);
while(!msg){ 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"); ssh_set_error(sftp->session,SSH_FATAL,"Received invalid DATA packet from sftp server");
return -1; 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", 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); free(datastring);
return -1; return -1;
} }
len=string_len(datastring); count = string_len(datastring);
handle->offset+=len; handle->offset+= count;
memcpy(data,datastring->string,len); memcpy(buf, datastring->string, count);
free(datastring); free(datastring);
return len; return count;
default: default:
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type); ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
@@ -1195,7 +1203,7 @@ int sftp_async_read(SFTP_FILE *file, void *data, int size, u32 id){
sftp_leave_function(); 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; SFTP_MESSAGE *msg=NULL;
STATUS_MESSAGE *status; STATUS_MESSAGE *status;
STRING *datastring; STRING *datastring;
@@ -1208,8 +1216,8 @@ int sftp_write(SFTP_FILE *file, const void *data, int len){
buffer_add_u32(buffer,id); buffer_add_u32(buffer,id);
buffer_add_ssh_string(buffer,file->handle); buffer_add_ssh_string(buffer,file->handle);
buffer_add_u64(buffer,htonll(file->offset)); buffer_add_u64(buffer,htonll(file->offset));
datastring=string_new(len); datastring=string_new(count);
string_fill(datastring,data,len); string_fill(datastring, buf, count);
buffer_add_ssh_string(buffer,datastring); buffer_add_ssh_string(buffer,datastring);
free(datastring); free(datastring);
if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){ 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); sftp_set_errno(sftp, status->status);
switch (status->status) { switch (status->status) {
case SSH_FX_OK: case SSH_FX_OK:
file->offset+=len; file->offset += count;
status_msg_free(status); status_msg_free(status);
return err ? err : len; return err ? err : count;
default: default:
break; break;
} }
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg); ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
file->offset+=len; file->offset += count;
status_msg_free(status); status_msg_free(status);
return -1; return -1;
default: default:
@@ -1264,8 +1272,12 @@ void sftp_rewind(SFTP_FILE *file){
file->offset=0; file->offset=0;
} }
int sftp_rm(SFTP_SESSION *sftp, const char *file) {
return sftp_unlink(sftp, file);
}
/* code written by Nick */ /* 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); u32 id = sftp_get_new_id(sftp);
BUFFER *buffer = buffer_new(); BUFFER *buffer = buffer_new();
STRING *filename = string_from_char(file); STRING *filename = string_from_char(file);
@@ -1357,18 +1369,23 @@ int sftp_rmdir(SFTP_SESSION *sftp, const char *directory) {
} }
/* Code written by Nick */ /* 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); u32 id = sftp_get_new_id(sftp);
BUFFER *buffer = buffer_new(); BUFFER *buffer = buffer_new();
STRING *path = string_from_char(directory); STRING *path = string_from_char(directory);
SFTP_MESSAGE *msg = NULL; SFTP_MESSAGE *msg = NULL;
STATUS_MESSAGE *status = NULL; STATUS_MESSAGE *status = NULL;
SFTP_ATTRIBUTES attr;
SFTP_ATTRIBUTES *errno_attr = NULL; SFTP_ATTRIBUTES *errno_attr = NULL;
ZERO_STRUCT(attr);
attr.permissions = mode;
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
buffer_add_u32(buffer, id); buffer_add_u32(buffer, id);
buffer_add_ssh_string(buffer, path); buffer_add_ssh_string(buffer, path);
free(path); free(path);
buffer_add_attributes(buffer, attr); buffer_add_attributes(buffer, &attr);
sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer); sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer);
buffer_free(buffer); buffer_free(buffer);
while (!msg) { while (!msg) {
@@ -1428,6 +1445,8 @@ int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname) {
free(oldpath); free(oldpath);
buffer_add_ssh_string(buffer, newpath); buffer_add_ssh_string(buffer, newpath);
free(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); sftp_packet_write(sftp, SSH_FXP_RENAME, buffer);
buffer_free(buffer); buffer_free(buffer);
while (!msg) { while (!msg) {
@@ -1504,6 +1523,45 @@ int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr) {
return -1; 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 */ /* another code written by Nick */
char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path) char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path)
{ {

View File

@@ -290,20 +290,20 @@ void do_sftp(SSH_SESSION *session){
ssh_say(0,"error : %s\n",ssh_get_error(session)); ssh_say(0,"error : %s\n",ssh_get_error(session));
return; return;
} }
if(sftp_dir_close(dir)){ if(sftp_closedir(dir)){
ssh_say(0,"Error : %s\n",ssh_get_error(session)); ssh_say(0,"Error : %s\n",ssh_get_error(session));
return; return;
} }
/* this will open a file and copy it into your /home directory */ /* 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 */ /* 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){ if(!fichier){
ssh_say(0,"Error opening /usr/bin/ssh : %s\n",ssh_get_error(session)); ssh_say(0,"Error opening /usr/bin/ssh : %s\n",ssh_get_error(session));
return; return;
} }
/* open a file for writing... */ /* 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){ if(!to){
ssh_say(0,"Error opening ssh-copy for writing : %s\n",ssh_get_error(session)); ssh_say(0,"Error opening ssh-copy for writing : %s\n",ssh_get_error(session));
return; return;
@@ -317,10 +317,10 @@ void do_sftp(SSH_SESSION *session){
printf("finished\n"); printf("finished\n");
if(len<0) if(len<0)
ssh_say(0,"Error reading file : %s\n",ssh_get_error(session)); ssh_say(0,"Error reading file : %s\n",ssh_get_error(session));
sftp_file_close(fichier); sftp_close(fichier);
sftp_file_close(to); sftp_close(to);
printf("fichiers ferm<EFBFBD>\n"); printf("fichiers ferm\n");
to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT,NULL); to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT, 0644);
for(i=0;i<1000;++i){ for(i=0;i<1000;++i){
len=sftp_write(to,data,8000); len=sftp_write(to,data,8000);
printf("wrote %d bytes\n",len); 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)); printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session));
} }
} }
sftp_file_close(to); sftp_close(to);
/* close the sftp session */ /* close the sftp session */
sftp_free(sftp); sftp_free(sftp);
printf("session sftp termin<69>\n"); printf("session sftp termin<69>\n");