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

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 17:46:50