5773096 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11/libssh]$ cat -n sftp.c
   1 /* scp.c contains the needed function to work with file transfer protocol over ssh*/
   2 /* don't look further if you believe this is just FTP over some tunnel. It IS different */
   3 /* This file contains code written by Nick Zitzmann */
   4 /*
   5 Copyright 2003 Aris Adamantiadis
   6 
   7 This file is part of the SSH Library
   8 
   9 The SSH Library is free software; you can redistribute it and/or modify
  10 it under the terms of the GNU Lesser General Public License as published by
  11 the Free Software Foundation; either version 2.1 of the License, or (at your
  12 option) any later version.
  13 
  14 The SSH Library is distributed in the hope that it will be useful, but
  15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  17 License for more details.
  18 
  19 You should have received a copy of the GNU Lesser General Public License
  20 along with the SSH Library; see the file COPYING.  If not, write to
  21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  22 MA 02111-1307, USA. */
  23 
  24 
  25 #include <string.h>
  26 #include <fcntl.h>
  27 #include <netdb.h>
  28 #include "libssh/priv.h"
  29 #include "libssh/ssh2.h"
  30 #include "libssh/sftp.h"
  31 #ifndef NO_SFTP
  32 /* here how it works : sftp commands are channeled by the ssh sftp subsystem. */
  33 /* every packet are sent/read using a SFTP_PACKET type structure. */
  34 /* into these packets, most of the server answers are messages having an ID and */
  35 /* having a message specific part. it is described by SFTP_MESSAGE */
  36 /* when reading a message, the sftp system puts it into the queue, so the process having asked for it */
  37 /* can fetch it, while continuing to read for other messages (it is inspecified in which order messages may */
  38 /* be sent back to the client */
  39 
  40 
  41 /* functions */
  42 static void sftp_packet_free(SFTP_PACKET *packet);
  43 void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg);
  44 static void sftp_message_free(SFTP_MESSAGE *msg);
  45 
  46 SFTP_SESSION *sftp_new(SSH_SESSION *session){
  47     SFTP_SESSION *sftp=malloc(sizeof(SFTP_SESSION));
  48     memset(sftp,0,sizeof(SFTP_SESSION));
  49     sftp->session=session;
  50     sftp->channel=open_session_channel(session,131000,32000);
  51     if(!sftp->channel){
  52         free(sftp);
  53         return NULL;
  54     }
  55     if(channel_request_sftp(sftp->channel)){
  56         sftp_free(sftp);
  57         return NULL;
  58     }
  59     return sftp;
  60 }
  61 
  62 void sftp_free(SFTP_SESSION *sftp){
  63     struct request_queue *ptr;
  64     channel_send_eof(sftp->channel);
  65     /* let libssh handle the channel closing from the server reply */
  66     ptr=sftp->queue;
  67     while(ptr){
  68         struct request_queue *old;
  69         sftp_message_free(ptr->message);
  70         old=ptr->next;
  71         free(ptr);
  72         ptr=old;
  73     }
  74     memset(sftp,0,sizeof(*sftp));
  75     free(sftp);
  76 }
  77 
  78 int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload){
  79     u32 size;
  80     buffer_add_data_begin(payload,&type,sizeof(u8));
  81     size=htonl(buffer_get_len(payload));
  82     buffer_add_data_begin(payload,&size,sizeof(u32));
  83     size=channel_write(sftp->channel,buffer_get(payload),buffer_get_len(payload));
  84     if(size != buffer_get_len(payload)){
  85         ssh_say(1,"had to write %d bytes, wrote only %d\n",buffer_get_len(payload),size);
  86     }
  87     return size;
  88 }
  89 
  90 SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp){
  91     SFTP_PACKET *packet=malloc(sizeof(SFTP_PACKET));
  92     u32 size;
  93     packet->sftp=sftp;
  94     packet->payload=buffer_new();
  95     if(channel_read(sftp->channel,packet->payload,4,0)<=0){
  96         buffer_free(packet->payload);
  97         free(packet);
  98         return NULL;
  99     }
 100     buffer_get_u32(packet->payload,&size);
 101     size=ntohl(size);
 102     if(channel_read(sftp->channel,packet->payload,1,0)<=0){
 103         buffer_free(packet->payload);
 104         free(packet);
 105         return NULL;
 106     }
 107     buffer_get_u8(packet->payload,&packet->type);
 108     if(size>1)
 109         if(channel_read(sftp->channel,packet->payload,size-1,0)<=0){
 110             buffer_free(packet->payload);
 111             free(packet);
 112             return NULL;
 113         }
 114     return packet;
 115 }
 116 
 117 static SFTP_MESSAGE *sftp_message_new(){
 118     SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE));
 119     memset(msg,0,sizeof(*msg));
 120     msg->payload=buffer_new();
 121     return msg;
 122 }
 123 
 124 static void sftp_message_free(SFTP_MESSAGE *msg){
 125     if(msg->payload)
 126         buffer_free(msg->payload);
 127     free(msg);
 128 }
 129 
 130 SFTP_MESSAGE *sftp_get_message(SFTP_PACKET *packet){
 131     SFTP_MESSAGE *msg=sftp_message_new();
 132     msg->sftp=packet->sftp;
 133     msg->packet_type=packet->type;
 134     if((packet->type!=SSH_FXP_STATUS)&&(packet->type!=SSH_FXP_HANDLE) &&
 135         (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS)
 136     && (packet->type != SSH_FXP_NAME)){
 137         ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"get_message : unknown packet type %d\n",packet->type);
 138         sftp_message_free(msg);
 139         return NULL;
 140     }
 141     if(buffer_get_u32(packet->payload,&msg->id)!=sizeof(u32)){
 142         ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"invalid packet %d : no ID",packet->type);
 143         sftp_message_free(msg);
 144         return NULL;
 145     }
 146     ssh_say(2,"packet with id %d type %d\n",msg->id,msg->packet_type);
 147     buffer_add_data(msg->payload,buffer_get_rest(packet->payload),buffer_get_rest_len(packet->payload));
 148     return msg;
 149 }
 150 
 151 int sftp_read_and_dispatch(SFTP_SESSION *session){
 152     SFTP_PACKET *packet;
 153     SFTP_MESSAGE *message=NULL;
 154     packet=sftp_packet_read(session);
 155     if(!packet)
 156         return -1; /* something nasty happened reading the packet */
 157     message=sftp_get_message(packet);
 158     sftp_packet_free(packet);
 159     if(!message)
 160         return -1;
 161     sftp_enqueue(session,message);
 162     return 0;
 163 }
 164 
 165 static void sftp_packet_free(SFTP_PACKET *packet){
 166     if(packet->payload)
 167         buffer_free(packet->payload);
 168     free(packet);
 169 }
 170 
 171 int sftp_init(SFTP_SESSION *sftp){
 172     SFTP_PACKET *packet;
 173     BUFFER *buffer=buffer_new();
 174     STRING *ext_name_s=NULL, *ext_data_s=NULL;
 175     char *ext_name,*ext_data;
 176     u32 version=htonl(LIBSFTP_VERSION);
 177     buffer_add_u32(buffer,version);
 178     sftp_packet_write(sftp,SSH_FXP_INIT,buffer);
 179     buffer_free(buffer);
 180     packet=sftp_packet_read(sftp);
 181     if(!packet)
 182         return -1;
 183     if(packet->type != SSH_FXP_VERSION){
 184         ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a %d messages instead of SSH_FXP_VERSION",packet->type);
 185         sftp_packet_free(packet);
 186         return -1;
 187     }
 188     buffer_get_u32(packet->payload,&version);
 189     version=ntohl(version);
 190     if(!(ext_name_s=buffer_get_ssh_string(packet->payload))||!(ext_data_s=buffer_get_ssh_string(packet->payload)))
 191         ssh_say(2,"sftp server version %d\n",version);
 192     else{
 193         ext_name=string_to_char(ext_name_s);
 194         ext_data=string_to_char(ext_data_s);
 195         ssh_say(2,"sftp server version %d (%s,%s)\n",version,ext_name,ext_data);
 196         free(ext_name);
 197         free(ext_data);
 198     }
 199     if(ext_name_s)
 200         free(ext_name_s);
 201     if(ext_data_s)
 202         free(ext_data_s);
 203     sftp_packet_free(packet);
 204     sftp->server_version=version;
 205     return 0;
 206 }
 207 
 208 REQUEST_QUEUE *request_queue_new(SFTP_MESSAGE *msg){
 209     REQUEST_QUEUE *queue=malloc(sizeof(REQUEST_QUEUE));
 210     memset(queue,0,sizeof(REQUEST_QUEUE));
 211     queue->message=msg;
 212     return queue;
 213 }
 214 
 215 void request_queue_free(REQUEST_QUEUE *queue){
 216     memset(queue,0,sizeof(*queue));
 217     free(queue);
 218 }
 219 
 220 void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg){
 221     REQUEST_QUEUE *queue=request_queue_new(msg);
 222     REQUEST_QUEUE *ptr;
 223     ssh_say(2,"queued msg type %d id %d\n",msg->id,msg->packet_type);
 224     if(!session->queue)
 225         session->queue=queue;
 226     else {
 227         ptr=session->queue;
 228         while(ptr->next){
 229             ptr=ptr->next; /* find end of linked list */
 230         }
 231         ptr->next=queue; /* add it on bottom */
 232     }
 233 }
 234 
 235 /* pulls of a message from the queue based on the ID. returns null if no message has been found */
 236 SFTP_MESSAGE *sftp_dequeue(SFTP_SESSION *session, u32 id){
 237     REQUEST_QUEUE *queue,*prev=NULL;
 238     SFTP_MESSAGE *msg;
 239     if(session->queue==NULL){
 240         return NULL;
 241     }
 242     queue=session->queue;
 243     while(queue){
 244         if(queue->message->id==id){
 245             /* remove from queue */
 246             if(prev==NULL){
 247                 session->queue=queue->next;
 248             } else {
 249                 prev->next=queue->next;
 250             }
 251             msg=queue->message;
 252             request_queue_free(queue);
 253             ssh_say(2,"dequeued msg id %d type %d\n",msg->id,msg->packet_type);
 254             return msg;
 255         }
 256         prev=queue;
 257         queue=queue->next;
 258     }
 259     return NULL;
 260 }
 261 
 262 /* assigns a new sftp ID for new requests and assures there is no collision between them. */
 263 u32 sftp_get_new_id(SFTP_SESSION *session){
 264     return ++session->id_counter;
 265 }
 266 
 267 STATUS_MESSAGE *parse_status_msg(SFTP_MESSAGE *msg){
 268     STATUS_MESSAGE *status;
 269     if(msg->packet_type != SSH_FXP_STATUS){
 270         ssh_set_error(msg->sftp->session, SSH_INVALID_DATA,"Not a ssh_fxp_status message passed in !");
 271         return NULL;
 272     }
 273     status=malloc(sizeof(STATUS_MESSAGE));
 274     memset(status,0,sizeof(*status));
 275     status->id=msg->id;
 276     if( (buffer_get_u32(msg->payload,&status->status)!= 4)
 277      || !(status->error=buffer_get_ssh_string(msg->payload)) ||
 278      !(status->lang=buffer_get_ssh_string(msg->payload))){
 279          if(status->error)
 280              free(status->error);
 281          /* status->lang never get allocated if something failed */
 282          free(status);
 283          ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"invalid SSH_FXP_STATUS message");
 284          return NULL;
 285     }
 286     status->status=ntohl(status->status);
 287     status->errormsg=string_to_char(status->error);
 288     status->langmsg=string_to_char(status->lang);
 289     return status;
 290 }
 291 
 292 void status_msg_free(STATUS_MESSAGE *status){
 293     if(status->errormsg)
 294         free(status->errormsg);
 295     if(status->error)
 296         free(status->error);
 297     if(status->langmsg)
 298         free(status->langmsg);
 299     if(status->lang)
 300         free(status->lang);
 301     free(status);
 302 }
 303 
 304 SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){
 305     SFTP_FILE *file;
 306     if(msg->packet_type != SSH_FXP_HANDLE){
 307         ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Not a ssh_fxp_handle message passed in !");
 308         return NULL;
 309     }
 310     file=malloc(sizeof(SFTP_FILE));
 311     memset(file,0,sizeof(*file));
 312     file->sftp=msg->sftp;
 313     file->handle=buffer_get_ssh_string(msg->payload);
 314     file->offset=0;
 315     file->eof=0;
 316     if(!file->handle){
 317         ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Invalid SSH_FXP_HANDLE message");
 318         free(file);
 319         return NULL;
 320     }
 321     return file;
 322 }
 323 
 324 SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){
 325     SFTP_DIR *dir=NULL;
 326     SFTP_FILE *file;
 327     STATUS_MESSAGE *status;
 328     SFTP_MESSAGE *msg=NULL;
 329     STRING *path_s;
 330     BUFFER *payload=buffer_new();
 331     u32 id=sftp_get_new_id(sftp);
 332     buffer_add_u32(payload,id);
 333     path_s=string_from_char(path);
 334     buffer_add_ssh_string(payload,path_s);
 335     free(path_s);
 336     sftp_packet_write(sftp,SSH_FXP_OPENDIR,payload);
 337     buffer_free(payload);
 338     while(!msg){
 339         if(sftp_read_and_dispatch(sftp))
 340             /* something nasty has happened */
 341             return NULL;
 342         msg=sftp_dequeue(sftp,id);
 343     }
 344     switch (msg->packet_type){
 345         case SSH_FXP_STATUS:
 346             status=parse_status_msg(msg);
 347             sftp_message_free(msg);
 348             if(!status)
 349                 return NULL;
 350             ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
 351             status_msg_free(status);
 352             return NULL;
 353         case SSH_FXP_HANDLE:
 354             file=parse_handle_msg(msg);
 355             sftp_message_free(msg);
 356             if(file){
 357                 dir=malloc(sizeof(SFTP_DIR));
 358                 memset(dir,0,sizeof(*dir));
 359                 dir->sftp=sftp;
 360                 dir->name=strdup(path);
 361                 dir->handle=file->handle;
 362                 free(file);
 363             }
 364             return dir;
 365         default:
 366             ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during opendir!",msg->packet_type);
 367             sftp_message_free(msg);
 368     }
 369     return NULL;
 370 }
 371 
 372 /* parse the attributes from a payload from some messages */
 373 /* i coded it on baselines from the protocol version 4. */
 374 /* please excuse me for the inaccuracy of the code. it isn't my fault, it's sftp draft's one */
 375 /* this code is dead anyway ... */
 376 /* version 4 specific code */
 377 SFTP_ATTRIBUTES *sftp_parse_attr_4(SFTP_SESSION *sftp,BUFFER *buf,int expectnames){
 378     u32 flags=0;
 379     SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
 380     STRING *owner=NULL;
 381     STRING *group=NULL;
 382     int ok=0;
 383     memset(attr,0,sizeof(*attr));
 384     /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */
 385     do {
 386         if(buffer_get_u32(buf,&flags)!=4)
 387             break;
 388         flags=ntohl(flags);
 389         attr->flags=flags;
 390         if(flags & SSH_FILEXFER_ATTR_SIZE){
 391             if(buffer_get_u64(buf,&attr->size)!=8)
 392                 break;
 393             attr->size=ntohll(attr->size);
 394         }
 395         if(flags & SSH_FILEXFER_ATTR_OWNERGROUP){
 396             if(!(owner=buffer_get_ssh_string(buf)))
 397                 break;
 398             if(!(group=buffer_get_ssh_string(buf)))
 399                 break;
 400         }
 401         if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
 402             if(buffer_get_u32(buf,&attr->permissions)!=4)
 403                 break;
 404             attr->permissions=ntohl(attr->permissions);
 405         }
 406         if(flags & SSH_FILEXFER_ATTR_ACCESSTIME){
 407             if(buffer_get_u64(buf,&attr->atime64)!=8)
 408                 break;
 409             attr->atime64=ntohll(attr->atime64);
 410         }
 411         if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
 412             if(buffer_get_u32(buf,&attr->atime_nseconds)!=4)
 413                 break;
 414             attr->atime_nseconds=ntohl(attr->atime_nseconds);
 415         }
 416         if(flags & SSH_FILEXFER_ATTR_CREATETIME){
 417             if(buffer_get_u64(buf,&attr->createtime)!=8)
 418                 break;
 419             attr->createtime=ntohll(attr->createtime);
 420         }
 421         if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
 422             if(buffer_get_u32(buf,&attr->createtime_nseconds)!=4)
 423                 break;
 424             attr->createtime_nseconds=ntohl(attr->createtime_nseconds);
 425         }
 426         if(flags & SSH_FILEXFER_ATTR_MODIFYTIME){
 427             if(buffer_get_u64(buf,&attr->mtime64)!=8)
 428                 break;
 429             attr->mtime64=ntohll(attr->mtime64);
 430         }
 431         if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
 432             if(buffer_get_u32(buf,&attr->mtime_nseconds)!=4)
 433                 break;
 434             attr->mtime_nseconds=ntohl(attr->mtime_nseconds);
 435         }
 436         if(flags & SSH_FILEXFER_ATTR_ACL){
 437             if(!(attr->acl=buffer_get_ssh_string(buf)))
 438                 break;
 439         }
 440         if (flags & SSH_FILEXFER_ATTR_EXTENDED){
 441             if(buffer_get_u32(buf,&attr->extended_count)!=4)
 442                 break;
 443             attr->extended_count=ntohl(attr->extended_count);
 444             while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf))
 445                     && (attr->extended_data=buffer_get_ssh_string(buf))){
 446                         attr->extended_count--;
 447             }
 448             if(attr->extended_count)
 449                 break;
 450         }
 451         ok=1;
 452     } while (0);
 453     if(!ok){
 454         /* break issued somewhere */
 455         if(owner)
 456             free(owner);
 457         if(group)
 458             free(group);
 459         if(attr->acl)
 460             free(attr->acl);
 461         if(attr->extended_type)
 462             free(attr->extended_type);
 463         if(attr->extended_data)
 464             free(attr->extended_data);
 465         free(attr);
 466         ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure");
 467         return NULL;
 468     }
 469     /* everything went smoothly */
 470     if(owner){
 471         attr->owner=string_to_char(owner);
 472         free(owner);
 473     }
 474     if(group){
 475         attr->group=string_to_char(group);
 476         free(group);
 477     }
 478     return attr;
 479 }
 480 
 481 /* Version 3 code. it is the only one really supported (the draft for the 4 misses clarifications) */
 482 /* maybe a paste of the draft is better than the code */
 483 /*
 484         uint32   flags
 485         uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE
 486         uint32   uid            present only if flag SSH_FILEXFER_ATTR_UIDGID
 487         uint32   gid            present only if flag SSH_FILEXFER_ATTR_UIDGID
 488         uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
 489         uint32   atime          present only if flag SSH_FILEXFER_ACMODTIME
 490         uint32   mtime          present only if flag SSH_FILEXFER_ACMODTIME
 491         uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
 492         string   extended_type
 493         string   extended_data
 494         ...      more extended data (extended_type - extended_data pairs),
 495                    so that number of pairs equals extended_count              */
 496 SFTP_ATTRIBUTES *sftp_parse_attr_3(SFTP_SESSION *sftp,BUFFER *buf,int expectname){
 497     u32 flags=0;
 498     STRING *name;
 499     STRING *longname;
 500     SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
 501     int ok=0;
 502     memset(attr,0,sizeof(*attr));
 503     /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */
 504     do {
 505         if(expectname){
 506             if(!(name=buffer_get_ssh_string(buf)))
 507                 break;
 508             attr->name=string_to_char(name);
 509             free(name);
 510             ssh_say(2,"name : %s\n",attr->name);
 511             if(!(longname=buffer_get_ssh_string(buf)))
 512                 break;
 513             attr->longname=string_to_char(longname);
 514             free(longname);
 515         }
 516         if(buffer_get_u32(buf,&flags)!=sizeof(u32))
 517             break;
 518         flags=ntohl(flags);
 519         attr->flags=flags;
 520         ssh_say(2,"flags : %.8lx\n",flags);
 521         if(flags & SSH_FILEXFER_ATTR_SIZE){
 522             if(buffer_get_u64(buf,&attr->size)!=sizeof(u64))
 523                 break;
 524             attr->size=ntohll(attr->size);
 525             ssh_say(2,"size : %lld\n",attr->size);
 526         }
 527         if(flags & SSH_FILEXFER_ATTR_UIDGID){
 528             if(buffer_get_u32(buf,&attr->uid)!=sizeof(u32))
 529                 break;
 530             if(buffer_get_u32(buf,&attr->gid)!=sizeof(u32))
 531                 break;
 532             attr->uid=ntohl(attr->uid);
 533             attr->gid=ntohl(attr->gid);
 534         }
 535         if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
 536             if(buffer_get_u32(buf,&attr->permissions)!=sizeof(u32))
 537                 break;
 538             attr->permissions=ntohl(attr->permissions);
 539         }
 540         if(flags & SSH_FILEXFER_ATTR_ACMODTIME){
 541             if(buffer_get_u32(buf,&attr->atime)!=sizeof(u32))
 542                 break;
 543             attr->atime=ntohl(attr->atime);
 544             if(buffer_get_u32(buf,&attr->mtime)!=sizeof(u32))
 545                 break;
 546             attr->mtime=ntohl(attr->mtime);
 547         }
 548         if (flags & SSH_FILEXFER_ATTR_EXTENDED){
 549             if(buffer_get_u32(buf,&attr->extended_count)!=sizeof(u32))
 550                 break;
 551             attr->extended_count=ntohl(attr->extended_count);
 552             while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf))
 553                     && (attr->extended_data=buffer_get_ssh_string(buf))){
 554                         attr->extended_count--;
 555             }
 556             if(attr->extended_count)
 557                 break;
 558         }
 559         ok=1;
 560     } while (0);
 561     if(!ok){
 562         /* break issued somewhere */
 563         if(attr->name)
 564             free(attr->name);
 565         if(attr->extended_type)
 566             free(attr->extended_type);
 567         if(attr->extended_data)
 568             free(attr->extended_data);
 569         free(attr);
 570         ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure");
 571         return NULL;
 572     }
 573     /* everything went smoothly */
 574     return attr;
 575 }
 576 
 577 void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr){
 578     u32 flags=(attr?attr->flags:0);
 579     flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS |
	SSH_FILEXFER_ATTR_ACMODTIME);
 580     buffer_add_u32(buffer,htonl(flags));
 581     if(attr){
 582         if (flags & SSH_FILEXFER_ATTR_SIZE)
 583         {
 584             buffer_add_u64(buffer, htonll(attr->size));
 585         }
 586         if(flags & SSH_FILEXFER_ATTR_UIDGID){
 587             buffer_add_u32(buffer,htonl(attr->uid));
 588             buffer_add_u32(buffer,htonl(attr->gid));
 589         }
 590         if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
 591             buffer_add_u32(buffer,htonl(attr->permissions));
 592         }
 593         if (flags & SSH_FILEXFER_ATTR_ACMODTIME)
 594         {
 595             buffer_add_u32(buffer, htonl(attr->atime));
 596             buffer_add_u32(buffer, htonl(attr->mtime));
 597         }
 598     }
 599 }
 600 
 601     
 602 SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname){
 603     switch(session->server_version){
 604         case 4:
 605             return sftp_parse_attr_4(session,buf,expectname);
 606         case 3:
 607             return sftp_parse_attr_3(session,buf,expectname);
 608         default:
 609             ssh_set_error(session->session,SSH_INVALID_DATA,"Version %d unsupported by client",session->server_version);
 610             return NULL;
 611     }
 612     return NULL;
 613 }
 614 
 615 int sftp_server_version(SFTP_SESSION *sftp){
 616     return sftp->server_version;
 617 }
 618 
 619 SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir){
 620     BUFFER *payload;
 621     u32 id;
 622     SFTP_MESSAGE *msg=NULL;
 623     STATUS_MESSAGE *status;
 624     SFTP_ATTRIBUTES *attr;
 625     if(!dir->buffer){
 626         payload=buffer_new();
 627         id=sftp_get_new_id(sftp);
 628         buffer_add_u32(payload,id);
 629         buffer_add_ssh_string(payload,dir->handle);
 630         sftp_packet_write(sftp,SSH_FXP_READDIR,payload);
 631         buffer_free(payload);
 632         ssh_say(2,"sent a ssh_fxp_readdir with id %d\n",id);
 633         while(!msg){
 634             if(sftp_read_and_dispatch(sftp))
 635                 /* something nasty has happened */
 636                 return NULL;
 637             msg=sftp_dequeue(sftp,id);
 638         }
 639         switch (msg->packet_type){
 640             case SSH_FXP_STATUS:
 641                 status=parse_status_msg(msg);
 642                 sftp_message_free(msg);
 643                 if(!status)
 644                     return NULL;
 645                 if(status->status==SSH_FX_EOF){
 646                     dir->eof=1;
 647                     status_msg_free(status);
 648                     return NULL;
 649                 }
 650                 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Unknown error status : %d",status->status);
 651                 status_msg_free(status);
 652                 return NULL;
 653             case SSH_FXP_NAME:
 654                 buffer_get_u32(msg->payload,&dir->count);
 655                 dir->count=ntohl(dir->count);
 656                 dir->buffer=msg->payload;
 657                 msg->payload=NULL;
 658                 sftp_message_free(msg);
 659                 break;
 660             default:
 661                 ssh_set_error(sftp->session,SSH_INVALID_DATA,"unsupported message back %d",msg->packet_type);
 662                 sftp_message_free(msg);
 663                 return NULL;
 664         }
 665     }
 666     /* now dir->buffer contains a buffer and dir->count != 0 */
 667     if(dir->count==0){
 668         ssh_set_error(sftp->session,SSH_INVALID_DATA,"Count of files sent by the server is zero, which is invalid, or
	libsftp bug");
 669         return NULL;
 670     }
 671     ssh_say(2,"Count is %d\n",dir->count);
 672     attr=sftp_parse_attr(sftp,dir->buffer,1);
 673     dir->count--;
 674     if(dir->count==0){
 675         buffer_free(dir->buffer);
 676         dir->buffer=NULL;
 677     }
 678     return attr;
 679 }
 680 
 681 int sftp_dir_eof(SFTP_DIR *dir){
 682     return (dir->eof);
 683 }
 684 
 685 void sftp_attributes_free(SFTP_ATTRIBUTES *file){
 686     if(file->name)
 687         free(file->name);
 688     if(file->longname)
 689         free(file->longname);
 690     if(file->acl)
 691         free(file->acl);
 692     if(file->extended_data)
 693         free(file->extended_data);
 694     if(file->extended_type)
 695         free(file->extended_type);
 696     if(file->group)
 697         free(file->group);
 698     if(file->owner)
 699         free(file->owner);
 700     free(file);
 701 }
 702 
 703 static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){
 704     SFTP_MESSAGE *msg=NULL;
 705     STATUS_MESSAGE *status;
 706     int id=sftp_get_new_id(sftp);
 707     int err=0;
 708     BUFFER *buffer=buffer_new();
 709     buffer_add_u32(buffer,id);
 710     buffer_add_ssh_string(buffer,handle);
 711     sftp_packet_write(sftp,SSH_FXP_CLOSE,buffer);
 712     buffer_free(buffer);
 713     while(!msg){
 714         if(sftp_read_and_dispatch(sftp))
 715         /* something nasty has happened */
 716             return -1;
 717         msg=sftp_dequeue(sftp,id);
 718     }
 719     switch (msg->packet_type){
 720         case SSH_FXP_STATUS:
 721             status=parse_status_msg(msg);
 722             sftp_message_free(msg);
 723             if(!status)
 724                 return -1;
 725             if(status->status != SSH_FX_OK){
 726                 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
 727                 err=-1;
 728             }
 729             status_msg_free(status);
 730             return err;
 731         default:
 732             ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during
	sftp_handle_close!",msg->packet_type);
 733             sftp_message_free(msg);
 734     }
 735     return -1;
 736 }
 737 
 738 int sftp_file_close(SFTP_FILE *file){
 739     int err=0;
 740     if(file->name)
 741         free(file->name);
 742     if(file->handle){
 743         err=sftp_handle_close(file->sftp,file->handle);
 744         free(file->handle);
 745     }
 746     free(file);
 747     return err;
 748 }
 749 
 750 int sftp_dir_close(SFTP_DIR *dir){
 751     int err=0;
 752     if(dir->name)
 753         free(dir->name);
 754     if(dir->handle){
 755         err=sftp_handle_close(dir->sftp,dir->handle);
 756         free(dir->handle);
 757     }
 758     if(dir->buffer)
 759         buffer_free(dir->buffer);
 760     free(dir);
 761     return err;
 762 }
 763 
 764 SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES *attr){
 765     SFTP_FILE *handle;
 766     SFTP_MESSAGE *msg=NULL;
 767     STATUS_MESSAGE *status;
 768     u32 flags=0;
 769     u32 id=sftp_get_new_id(sftp);
 770     BUFFER *buffer=buffer_new();
 771     STRING *filename;
 772     if(access & O_RDONLY)
 773         flags|=SSH_FXF_READ;
 774     if(access & O_WRONLY)
 775         flags |= SSH_FXF_WRITE;
 776     if(access & O_RDWR)
 777         flags|=(SSH_FXF_WRITE | SSH_FXF_READ);
 778     if(access & O_CREAT)
 779         flags |=SSH_FXF_CREAT;
 780     if(access & O_TRUNC)
 781         flags |=SSH_FXF_TRUNC;
 782     if(access & O_EXCL)
 783         flags |= SSH_FXF_EXCL;
 784     buffer_add_u32(buffer,id);
 785     filename=string_from_char(file);
 786     buffer_add_ssh_string(buffer,filename);
 787     free(filename);
 788     buffer_add_u32(buffer,htonl(flags));
 789     buffer_add_attributes(buffer,attr);
 790     sftp_packet_write(sftp,SSH_FXP_OPEN,buffer);
 791     buffer_free(buffer);
 792     while(!msg){
 793         if(sftp_read_and_dispatch(sftp))
 794         /* something nasty has happened */
 795             return NULL;
 796         msg=sftp_dequeue(sftp,id);
 797     }
 798     switch (msg->packet_type){
 799         case SSH_FXP_STATUS:
 800             status=parse_status_msg(msg);
 801             sftp_message_free(msg);
 802             if(!status)
 803                 return NULL;
 804             ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
 805             status_msg_free(status);
 806             return NULL;
 807         case SSH_FXP_HANDLE:
 808             handle=parse_handle_msg(msg);
 809             sftp_message_free(msg);
 810             return handle;
 811         default:
 812             ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during open!",msg->packet_type);
 813             sftp_message_free(msg);
 814     }
 815     return NULL; 
 816 }
 817 
 818 void sftp_file_set_nonblocking(SFTP_FILE *handle){
 819     handle->nonblocking=1;
 820 }
 821 void sftp_file_set_blocking(SFTP_FILE *handle){
 822     handle->nonblocking=0;
 823 }
 824 
 825 int sftp_read(SFTP_FILE *handle, void *data, int len){
 826     SFTP_MESSAGE *msg=NULL;
 827     STATUS_MESSAGE *status;
 828     SFTP_SESSION *sftp=handle->sftp;
 829     STRING *datastring;
 830     int id;
 831     int err=0;
 832     BUFFER *buffer;
 833     if(handle->eof)
 834         return 0; 
 835     buffer=buffer_new();
 836     id=sftp_get_new_id(handle->sftp);
 837     buffer_add_u32(buffer,id);
 838     buffer_add_ssh_string(buffer,handle->handle);
 839     buffer_add_u64(buffer,htonll(handle->offset));
 840     buffer_add_u32(buffer,htonl(len));
 841     sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer);
 842     buffer_free(buffer);
 843     while(!msg){
 844         if (handle->nonblocking){
 845             if(channel_poll(handle->sftp->channel,0)==0){
 846                 /* we cannot block */
 847                 return 0;
 848             }
 849         }
 850         if(sftp_read_and_dispatch(handle->sftp))
 851         /* something nasty has happened */
 852             return -1;
 853         msg=sftp_dequeue(handle->sftp,id);
 854     }
 855     switch (msg->packet_type){
 856         case SSH_FXP_STATUS:
 857             status=parse_status_msg(msg);
 858             sftp_message_free(msg);
 859             if(!status)
 860                 return -1;
 861             if(status->status != SSH_FX_EOF){
 862                 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
 863                 err=-1;
 864             }
 865             else
 866                 handle->eof=1;
 867             status_msg_free(status);
 868             return err?err:0;
 869         case SSH_FXP_DATA:
 870             datastring=buffer_get_ssh_string(msg->payload);
 871             sftp_message_free(msg);
 872             if(!datastring){
 873                 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received invalid DATA packet from sftp server");
 874                 return -1;
 875             }
 876             if(string_len(datastring)>len){
 877                 ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a too big DATA packet from sftp server : %d and
	asked for %d",
 878                     string_len(datastring),len);
 879                 free(datastring);
 880                 return -1;
 881             }
 882             len=string_len(datastring);
 883             handle->offset+=len;
 884             memcpy(data,datastring->string,len);
 885             free(datastring);
 886             return len;
 887         default:
 888             ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during read!",msg->packet_type);
 889             sftp_message_free(msg);
 890             return -1;
 891     }
 892     return -1; /* not reached */
 893 }
 894 
 895 int sftp_write(SFTP_FILE *file, void *data, int len){
 896     SFTP_MESSAGE *msg=NULL;
 897     STATUS_MESSAGE *status;
 898     STRING *datastring;
 899     SFTP_SESSION *sftp=file->sftp;
 900     int id;
 901     int err=0;
 902     BUFFER *buffer;
 903     buffer=buffer_new();
 904     id=sftp_get_new_id(file->sftp);
 905     buffer_add_u32(buffer,id);
 906     buffer_add_ssh_string(buffer,file->handle);
 907     buffer_add_u64(buffer,htonll(file->offset));
 908     datastring=string_new(len);
 909     string_fill(datastring,data,len);
 910     buffer_add_ssh_string(buffer,datastring);
 911     free(datastring);
 912     if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){
 913         ssh_say(1,"sftp_packet_write did not write as much data as expected\n");
 914     }
 915     buffer_free(buffer);
 916     while(!msg){
 917         if(sftp_read_and_dispatch(file->sftp))
 918         /* something nasty has happened */
 919             return -1;
 920         msg=sftp_dequeue(file->sftp,id);
 921     }
 922     switch (msg->packet_type){
 923         case SSH_FXP_STATUS:
 924             status=parse_status_msg(msg);
 925             sftp_message_free(msg);
 926             if(!status)
 927                 return -1;
 928             if(status->status != SSH_FX_OK){
 929                 ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
 930                 err=-1;
 931             }
 932             file->offset+=len;
 933             status_msg_free(status);
 934             return (err?err:len);
 935         default:
 936             ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during write!",msg->packet_type);
 937             sftp_message_free(msg);
 938             return -1;
 939     }
 940     return -1; /* not reached */
 941 }
 942 
 943 void sftp_seek(SFTP_FILE *file, int new_offset){
 944     file->offset=new_offset;
 945 }
 946 
 947 unsigned long sftp_tell(SFTP_FILE *file){
 948     return file->offset;
 949 }
 950 
 951 void sftp_rewind(SFTP_FILE *file){
 952     file->offset=0;
 953 }
 954 
 955 /* code written by Nick */
 956 int sftp_rm(SFTP_SESSION *sftp, char *file) {
 957     u32 id = sftp_get_new_id(sftp);
 958     BUFFER *buffer = buffer_new();
 959     STRING *filename = string_from_char(file);
 960     SFTP_MESSAGE *msg = NULL;
 961     STATUS_MESSAGE *status = NULL;
 962 
 963     buffer_add_u32(buffer, id);
 964     buffer_add_ssh_string(buffer, filename);
 965     free(filename);
 966     sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer);
 967     buffer_free(buffer);
 968     while (!msg) {
 969         if (sftp_read_and_dispatch(sftp)) {
 970             return -1;
 971         }
 972         msg = sftp_dequeue(sftp, id);
 973     }
 974     if (msg->packet_type == SSH_FXP_STATUS) {
 975          /* by specification, this command's only supposed to return SSH_FXP_STATUS */    
 976          status = parse_status_msg(msg);
 977          sftp_message_free(msg);
 978          if (!status)
 979              return -1;
 980          if (status->status != SSH_FX_OK) {
 981           /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
 982               ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
 983               status_msg_free(status);
 984               return -1;
 985          }
 986          status_msg_free(status);
 987          return 0;   /* at this point, everything turned out OK */
 988     } else {
 989         ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove file",
	msg->packet_type);
 990         sftp_message_free(msg);
 991     }
 992     return -1;
 993 }
 994 
 995 /* code written by Nick */
 996 int sftp_rmdir(SFTP_SESSION *sftp, char *directory) {
 997     u32 id = sftp_get_new_id(sftp);
 998     BUFFER *buffer = buffer_new();
 999     STRING *filename = string_from_char(directory);
1000     SFTP_MESSAGE *msg = NULL;
1001     STATUS_MESSAGE *status = NULL;
1002 
1003     buffer_add_u32(buffer, id);
1004     buffer_add_ssh_string(buffer, filename);
1005     free(filename);
1006     sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer);
1007     buffer_free(buffer);
1008     while (!msg) {
1009         if (sftp_read_and_dispatch(sftp))
1010         {
1011             return -1;
1012         }
1013         msg = sftp_dequeue(sftp, id);
1014     }
1015     if (msg->packet_type == SSH_FXP_STATUS) /* by specification, this command's only supposed to return SSH_FXP_STATUS
	*/
1016     {
1017         status = parse_status_msg(msg);
1018         sftp_message_free(msg);
1019         if (!status)
1020         {
1021             return -1;
1022         }
1023         else if (status->status != SSH_FX_OK)   /* status should be SSH_FX_OK if the command was successful, if it
	didn't, then there was an error */
1024         {
1025             ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
1026             status_msg_free(status);
1027             return -1;
1028         }
1029         status_msg_free(status);
1030         return 0;   /* at this point, everything turned out OK */
1031     }
1032     else
1033     {
1034         ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove directory",
	msg->packet_type);
1035         sftp_message_free(msg);
1036     }
1037     return -1;
1038 }
1039 
1040 /* Code written by Nick */
1041 int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) {
1042     u32 id = sftp_get_new_id(sftp);
1043     BUFFER *buffer = buffer_new();
1044     STRING *path = string_from_char(directory);
1045     SFTP_MESSAGE *msg = NULL;
1046     STATUS_MESSAGE *status = NULL;
1047 
1048     buffer_add_u32(buffer, id);
1049     buffer_add_ssh_string(buffer, path);
1050     free(path);
1051     buffer_add_attributes(buffer, attr);
1052     sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer);
1053     buffer_free(buffer);
1054     while (!msg) {
1055         if (sftp_read_and_dispatch(sftp))
1056             return -1;
1057         msg = sftp_dequeue(sftp, id);
1058     }
1059     if (msg->packet_type == SSH_FXP_STATUS) {
1060         /* by specification, this command's only supposed to return SSH_FXP_STATUS */
1061         status = parse_status_msg(msg);
1062         sftp_message_free(msg);
1063         if (!status)
1064             return -1;
1065         else
1066         if (status->status != SSH_FX_OK) {
1067             /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
1068             ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
1069             status_msg_free(status);
1070             return -1;
1071         }
1072         status_msg_free(status);
1073         return 0;   /* at this point, everything turned out OK */
1074     } else {
1075        ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to make directory",
	msg->packet_type);
1076        sftp_message_free(msg);
1077     }
1078     return -1;
1079 }
1080 
1081 /* code written by nick */
1082 int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) {
1083     u32 id = sftp_get_new_id(sftp);
1084     BUFFER *buffer = buffer_new();
1085     STRING *oldpath = string_from_char(original);
1086     STRING *newpath = string_from_char(newname);
1087     SFTP_MESSAGE *msg = NULL;
1088     STATUS_MESSAGE *status = NULL;
1089 
1090     buffer_add_u32(buffer, id);
1091     buffer_add_ssh_string(buffer, oldpath);
1092     free(oldpath);
1093     buffer_add_ssh_string(buffer, newpath);
1094     free(newpath);
1095     sftp_packet_write(sftp, SSH_FXP_RENAME, buffer);
1096     buffer_free(buffer);
1097     while (!msg) {
1098         if (sftp_read_and_dispatch(sftp))
1099             return -1;
1100         msg = sftp_dequeue(sftp, id);
1101     }
1102     if (msg->packet_type == SSH_FXP_STATUS) {
1103          /* by specification, this command's only supposed to return SSH_FXP_STATUS */
1104         status = parse_status_msg(msg);
1105         sftp_message_free(msg);
1106         if (!status)
1107             return -1;
1108         else if (status->status != SSH_FX_OK) {
1109                /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
1110             ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
1111             status_msg_free(status);
1112             return -1;
1113         }
1114         status_msg_free(status);
1115         return 0;   /* at this point, everything turned out OK */
1116     } else {
1117         ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to rename",
	msg->packet_type);
1118         sftp_message_free(msg);
1119     }
1120     return -1;
1121 }
1122 
1123 /* Code written by Nick */
1124 int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) {
1125     u32 id = sftp_get_new_id(sftp);
1126     BUFFER *buffer = buffer_new();
1127     STRING *path = string_from_char(file);
1128     SFTP_MESSAGE *msg = NULL;
1129     STATUS_MESSAGE *status = NULL;
1130 
1131     buffer_add_u32(buffer, id);
1132     buffer_add_ssh_string(buffer, path);
1133     free(path);
1134     buffer_add_attributes(buffer, attr);
1135     sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer);
1136     buffer_free(buffer);
1137     while (!msg) {
1138         if (sftp_read_and_dispatch(sftp))
1139             return -1;
1140         msg = sftp_dequeue(sftp, id);
1141     }
1142     if (msg->packet_type == SSH_FXP_STATUS) {
1143          /* by specification, this command's only supposed to return SSH_FXP_STATUS */
1144         status = parse_status_msg(msg);
1145         sftp_message_free(msg);
1146         if (!status)
1147             return -1;
1148         else if (status->status != SSH_FX_OK) {
1149                /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
1150             ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
1151             status_msg_free(status);
1152             return -1;
1153         }
1154         status_msg_free(status);
1155         return 0;   /* at this point, everything turned out OK */
1156     } else {
1157         ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats",
	msg->packet_type);
1158         sftp_message_free(msg);
1159     }
1160     return -1;
1161 }
1162 
1163 /* another code written by Nick */
1164 char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path)
1165 {
1166     u32 id = sftp_get_new_id(sftp);
1167     BUFFER *buffer = buffer_new();
1168     STRING *pathstr = string_from_char(path);
1169     STRING *name = NULL;
1170     SFTP_MESSAGE *msg = NULL;
1171     STATUS_MESSAGE *status = NULL;
1172     char *cname;
1173     u32 ignored;
1174     
1175     buffer_add_u32(buffer, id);
1176     buffer_add_ssh_string(buffer, pathstr);
1177     free(pathstr);
1178     sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer);
1179     buffer_free(buffer);
1180     while (!msg)
1181     {
1182         if (sftp_read_and_dispatch(sftp))
1183             return NULL;
1184         msg = sftp_dequeue(sftp, id);
1185     }
1186     if (msg->packet_type == SSH_FXP_NAME)   /* good response */
1187     {
1188         buffer_get_u32(msg->payload, &ignored); /* we don't care about "count" */
1189         name = buffer_get_ssh_string(msg->payload); /* we only care about the file name string */
1190         cname = string_to_char(name);
1191         free(name);
1192         return cname;
1193     }
1194     else if (msg->packet_type == SSH_FXP_STATUS)    /* bad response (error) */
1195     {
1196         status = parse_status_msg(msg);
1197         sftp_message_free(msg);
1198         if (!status)
1199             return NULL;
1200         ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
1201         status_msg_free(status);
1202     }
1203     else    /* this shouldn't happen */
1204     {
1205         ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats",
	msg->packet_type);
1206         sftp_message_free(msg);
1207     }
1208     return NULL;
1209 }
1210 
1211 SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){
1212     u32 id=sftp_get_new_id(sftp);
1213     BUFFER *buffer=buffer_new();
1214     STRING *pathstr= string_from_char(path);
1215     SFTP_MESSAGE *msg=NULL;
1216     STATUS_MESSAGE *status=NULL;
1217     SFTP_ATTRIBUTES *pattr=NULL;
1218 
1219     buffer_add_u32(buffer,id);
1220     buffer_add_ssh_string(buffer,pathstr);
1221     free(pathstr);
1222     sftp_packet_write(sftp,param,buffer);
1223     buffer_free(buffer);
1224     while(!msg){
1225         if(sftp_read_and_dispatch(sftp))
1226             return NULL;
1227         msg=sftp_dequeue(sftp,id);
1228     }
1229     if(msg->packet_type==SSH_FXP_ATTRS){
1230         pattr=sftp_parse_attr(sftp,msg->payload,0);
1231         return pattr;
1232     }
1233     if(msg->packet_type== SSH_FXP_STATUS){
1234         status=parse_status_msg(msg);
1235         sftp_message_free(msg);
1236         if(!status)
1237             return NULL;
1238         ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
1239         status_msg_free(status);
1240         return NULL;
1241     }
1242     ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received mesg %d during stat(),mesg->packet_type");
1243     sftp_message_free(msg);
1244     return NULL;
1245 }
1246 
1247 SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path){
1248     return sftp_xstat(session,path,SSH_FXP_STAT);
1249 }
1250 SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path){
1251     return sftp_xstat(session,path,SSH_FXP_LSTAT);
1252 }
1253 
1254 SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file) {
1255     u32 id=sftp_get_new_id(file->sftp);
1256     BUFFER *buffer=buffer_new();
1257     SFTP_MESSAGE *msg=NULL;
1258     STATUS_MESSAGE *status=NULL;
1259     SFTP_ATTRIBUTES *pattr=NULL;
1260 
1261     buffer_add_u32(buffer,id);
1262     buffer_add_ssh_string(buffer,file->handle);
1263     sftp_packet_write(file->sftp,SSH_FXP_FSTAT,buffer);
1264     buffer_free(buffer);
1265     while(!msg){
1266         if(sftp_read_and_dispatch(file->sftp))
1267             return NULL;
1268         msg=sftp_dequeue(file->sftp,id);
1269     }
1270     if(msg->packet_type==SSH_FXP_ATTRS){
1271         pattr=sftp_parse_attr(file->sftp,msg->payload,0);
1272         return pattr;
1273     }
1274     if(msg->packet_type== SSH_FXP_STATUS){
1275         status=parse_status_msg(msg);
1276         sftp_message_free(msg);
1277         if(!status)
1278             return NULL;
1279         ssh_set_error(file->sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
1280         status_msg_free(status);
1281         return NULL;
1282     }
1283     ssh_set_error(file->sftp->session,SSH_INVALID_DATA,"Received mesg %d during fstat(),mesg->packet_type");
1284     sftp_message_free(msg);
1285     return NULL;
1286 }
1287 
1288 
1289 #endif /* NO_SFTP */
5773097 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59