Mercurial > gftp.yaz
comparison lib/sshv2.c @ 1:8b1883341c6f
Initial revision
author | masneyb |
---|---|
date | Mon, 05 Aug 2002 19:46:57 +0000 |
parents | |
children | 83090328581e |
comparison
equal
deleted
inserted
replaced
0:674ed97069fd | 1:8b1883341c6f |
---|---|
1 /*****************************************************************************/ | |
2 /* sshv2.c - functions that will use the sshv2 protocol */ | |
3 /* Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org> */ | |
4 /* */ | |
5 /* This program is free software; you can redistribute it and/or modify */ | |
6 /* it under the terms of the GNU General Public License as published by */ | |
7 /* the Free Software Foundation; either version 2 of the License, or */ | |
8 /* (at your option) any later version. */ | |
9 /* */ | |
10 /* This program is distributed in the hope that it will be useful, */ | |
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | |
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | |
13 /* GNU General Public License for more details. */ | |
14 /* */ | |
15 /* You should have received a copy of the GNU General Public License */ | |
16 /* along with this program; if not, write to the Free Software */ | |
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ | |
18 /*****************************************************************************/ | |
19 | |
20 #include "gftp.h" | |
21 | |
22 #define SSH_MAX_HANDLE_SIZE 256 | |
23 #define SSH_MAX_STRING_SIZE 34000 | |
24 | |
25 typedef struct sshv2_attribs_tag | |
26 { | |
27 gint32 flags; | |
28 gint64 size; | |
29 gint32 uid; | |
30 gint32 gid; | |
31 gint32 perm; | |
32 gint32 atime; | |
33 gint32 mtime; | |
34 } sshv2_attribs; | |
35 | |
36 typedef struct sshv2_message_tag | |
37 { | |
38 gint32 length; | |
39 char command; | |
40 char *buffer, | |
41 *pos, | |
42 *end; | |
43 } sshv2_message; | |
44 | |
45 typedef struct sshv2_params_tag | |
46 { | |
47 char handle[SSH_MAX_HANDLE_SIZE + 4]; /* We'll encode the ID in here too */ | |
48 int handle_len, | |
49 dont_log_status : 1; /* For uploading files */ | |
50 sshv2_message message; | |
51 | |
52 gint32 id, | |
53 count; | |
54 #ifdef G_HAVE_GINT64 | |
55 gint64 offset; | |
56 #else | |
57 gint32 offset; | |
58 #endif | |
59 char *read_buffer; | |
60 } sshv2_params; | |
61 | |
62 | |
63 static void sshv2_destroy ( gftp_request * request ); | |
64 static int sshv2_connect ( gftp_request * request ); | |
65 static void sshv2_disconnect ( gftp_request * request ); | |
66 static gint32 sshv2_buffer_get_int32 ( gftp_request * request, | |
67 sshv2_message * buffer, | |
68 int expected_response ); | |
69 static char * sshv2_buffer_get_string ( gftp_request * request, | |
70 sshv2_message * buffer ); | |
71 static int sshv2_send_command ( gftp_request * request, | |
72 char type, | |
73 char *command, | |
74 gint32 len ); | |
75 static int sshv2_read_response ( gftp_request * request, | |
76 sshv2_message * message, | |
77 FILE * fd ); | |
78 static void sshv2_message_free ( sshv2_message * message ); | |
79 static void sshv2_log_command ( gftp_request * request, | |
80 gftp_logging_level level, | |
81 char type, | |
82 char *message, | |
83 size_t length ); | |
84 static int sshv2_end_transfer ( gftp_request * request ); | |
85 static int sshv2_list_files ( gftp_request * request ); | |
86 static int sshv2_get_next_file ( gftp_request * request, | |
87 gftp_file * fle, | |
88 FILE * fd ); | |
89 static int sshv2_chdir ( gftp_request * request, | |
90 const char *directory ); | |
91 static int sshv2_getcwd ( gftp_request * request ); | |
92 static int sshv2_rmdir ( gftp_request * request, | |
93 const char *directory ); | |
94 static int sshv2_rmfile ( gftp_request * request, | |
95 const char *file); | |
96 static int sshv2_chmod ( gftp_request * request, | |
97 const char *file, | |
98 int mode ); | |
99 static int sshv2_mkdir ( gftp_request * request, | |
100 const char *newdir ); | |
101 static int sshv2_rename ( gftp_request * request, | |
102 const char *oldname, | |
103 const char *newname ); | |
104 static int sshv2_set_file_time ( gftp_request * request, | |
105 const char *file, | |
106 time_t datetime ); | |
107 static off_t sshv2_get_file_size ( gftp_request * request, | |
108 const char *file ); | |
109 static long sshv2_get_file ( gftp_request * request, | |
110 const char *filename, | |
111 FILE * fd, | |
112 off_t startsize ); | |
113 static int sshv2_put_file ( gftp_request * request, | |
114 const char *filename, | |
115 FILE * fd, | |
116 off_t startsize, | |
117 off_t totalsize ); | |
118 static size_t sshv2_get_next_file_chunk ( gftp_request * request, | |
119 char *buf, | |
120 size_t size ); | |
121 static size_t sshv2_put_next_file_chunk ( gftp_request * request, | |
122 char *buf, | |
123 size_t size ); | |
124 | |
125 #define SSH_MY_VERSION 3 | |
126 | |
127 #define SSH_FXP_INIT 1 | |
128 #define SSH_FXP_VERSION 2 | |
129 #define SSH_FXP_OPEN 3 | |
130 #define SSH_FXP_CLOSE 4 | |
131 #define SSH_FXP_READ 5 | |
132 #define SSH_FXP_WRITE 6 | |
133 #define SSH_FXP_LSTAT 7 | |
134 #define SSH_FXP_FSTAT 8 | |
135 #define SSH_FXP_SETSTAT 9 | |
136 #define SSH_FXP_FSETSTAT 10 | |
137 #define SSH_FXP_OPENDIR 11 | |
138 #define SSH_FXP_READDIR 12 | |
139 #define SSH_FXP_REMOVE 13 | |
140 #define SSH_FXP_MKDIR 14 | |
141 #define SSH_FXP_RMDIR 15 | |
142 #define SSH_FXP_REALPATH 16 | |
143 #define SSH_FXP_STAT 17 | |
144 #define SSH_FXP_RENAME 18 | |
145 #define SSH_FXP_STATUS 101 | |
146 #define SSH_FXP_HANDLE 102 | |
147 #define SSH_FXP_DATA 103 | |
148 #define SSH_FXP_NAME 104 | |
149 #define SSH_FXP_ATTRS 105 | |
150 #define SSH_FXP_EXTENDED 200 | |
151 #define SSH_FXP_EXTENDED_REPLY 201 | |
152 | |
153 #define SSH_FILEXFER_ATTR_SIZE 0x00000001 | |
154 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002 | |
155 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 | |
156 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 | |
157 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 | |
158 | |
159 #define SSH_FXF_READ 0x00000001 | |
160 #define SSH_FXF_WRITE 0x00000002 | |
161 #define SSH_FXF_APPEND 0x00000004 | |
162 #define SSH_FXF_CREAT 0x00000008 | |
163 #define SSH_FXF_TRUNC 0x00000010 | |
164 #define SSH_FXF_EXCL 0x00000020 | |
165 | |
166 #define SSH_FX_OK 0 | |
167 #define SSH_FX_EOF 1 | |
168 #define SSH_FX_NO_SUCH_FILE 2 | |
169 #define SSH_FX_PERMISSION_DENIED 3 | |
170 #define SSH_FX_FAILURE 4 | |
171 #define SSH_FX_BAD_MESSAGE 5 | |
172 #define SSH_FX_NO_CONNECTION 6 | |
173 #define SSH_FX_CONNECTION_LOST 7 | |
174 #define SSH_FX_OP_UNSUPPORTED 8 | |
175 | |
176 | |
177 void | |
178 sshv2_init (gftp_request * request) | |
179 { | |
180 sshv2_params * params; | |
181 | |
182 g_return_if_fail (request != NULL); | |
183 | |
184 request->protonum = GFTP_SSHV2_NUM; | |
185 request->init = sshv2_init; | |
186 request->destroy = sshv2_destroy; | |
187 request->connect = sshv2_connect; | |
188 request->disconnect = sshv2_disconnect; | |
189 request->get_file = sshv2_get_file; | |
190 request->put_file = sshv2_put_file; | |
191 request->transfer_file = NULL; | |
192 request->get_next_file_chunk = sshv2_get_next_file_chunk; | |
193 request->put_next_file_chunk = sshv2_put_next_file_chunk; | |
194 request->end_transfer = sshv2_end_transfer; | |
195 request->list_files = sshv2_list_files; | |
196 request->get_next_file = sshv2_get_next_file; | |
197 request->set_data_type = NULL; | |
198 request->get_file_size = sshv2_get_file_size; | |
199 request->chdir = sshv2_chdir; | |
200 request->rmdir = sshv2_rmdir; | |
201 request->rmfile = sshv2_rmfile; | |
202 request->mkdir = sshv2_mkdir; | |
203 request->rename = sshv2_rename; | |
204 request->chmod = sshv2_chmod; | |
205 request->set_file_time = sshv2_set_file_time; | |
206 request->site = NULL; | |
207 request->parse_url = NULL; | |
208 request->url_prefix = "ssh2"; | |
209 request->protocol_name = "SSH2"; | |
210 request->need_hostport = 1; | |
211 request->need_userpass = ssh_need_userpass; | |
212 request->use_cache = 1; | |
213 request->use_threads = 1; | |
214 request->always_connected = 0; | |
215 request->protocol_data = g_malloc0 (sizeof (sshv2_params)); | |
216 gftp_set_config_options (request); | |
217 | |
218 params = request->protocol_data; | |
219 params->id = 1; | |
220 } | |
221 | |
222 | |
223 static void | |
224 sshv2_destroy (gftp_request * request) | |
225 { | |
226 g_return_if_fail (request != NULL); | |
227 g_return_if_fail (request->protonum == GFTP_SSHV2_NUM); | |
228 | |
229 g_free (request->protocol_data); | |
230 request->protocol_data = NULL; | |
231 } | |
232 | |
233 | |
234 static int | |
235 sshv2_connect (gftp_request * request) | |
236 { | |
237 char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6]; | |
238 int version, fdm, fds, s[2]; | |
239 sshv2_message message; | |
240 const gchar *errstr; | |
241 pid_t child; | |
242 | |
243 g_return_val_if_fail (request != NULL, -2); | |
244 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
245 g_return_val_if_fail (request->hostname != NULL, -2); | |
246 | |
247 if (request->sockfd != NULL) | |
248 return (0); | |
249 | |
250 request->logging_function (gftp_logging_misc, request->user_data, | |
251 _("Opening SSH connection to %s\n"), | |
252 request->hostname); | |
253 | |
254 /* Ugh!! We don't get a login banner from sftp-server, and if we are | |
255 using ssh-agent to cache a users password, then we won't receive | |
256 any initial text from the server, and we'll block. So I just send a | |
257 xsftp server banner over. I hope this works on most Unices */ | |
258 | |
259 if (request->sftpserv_path == NULL || | |
260 *request->sftpserv_path == '\0') | |
261 { | |
262 p1 = ""; | |
263 p2 = ' '; | |
264 } | |
265 else | |
266 { | |
267 p1 = request->sftpserv_path; | |
268 p2 = '/'; | |
269 } | |
270 | |
271 *port = '\0'; | |
272 exepath = g_strdup_printf ("echo -n xsftp ; %s%csftp-server", p1, p2); | |
273 args = make_ssh_exec_args (request, exepath, sshv2_use_sftp_subsys, port); | |
274 | |
275 if (ssh_use_askpass || sshv2_use_sftp_subsys) | |
276 { | |
277 fdm = fds = 0; | |
278 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0) | |
279 { | |
280 request->logging_function (gftp_logging_error, request->user_data, | |
281 _("Cannot create a socket pair: %s\n"), | |
282 g_strerror (errno)); | |
283 return (-2); | |
284 } | |
285 } | |
286 else | |
287 { | |
288 s[0] = s[1] = 0; | |
289 if ((fdm = ptym_open (pts_name)) < 0) | |
290 { | |
291 request->logging_function (gftp_logging_error, request->user_data, | |
292 _("Cannot open master pty %s: %s\n"), pts_name, | |
293 g_strerror (errno)); | |
294 return (-2); | |
295 } | |
296 } | |
297 | |
298 if ((child = fork ()) == 0) | |
299 { | |
300 setsid (); | |
301 if (ssh_use_askpass || sshv2_use_sftp_subsys) | |
302 { | |
303 close (s[0]); | |
304 fds = s[1]; | |
305 } | |
306 else | |
307 { | |
308 if ((fds = ptys_open (fdm, pts_name)) < 0) | |
309 { | |
310 printf ("Cannot open slave pts %s: %s\n", pts_name, | |
311 g_strerror (errno)); | |
312 return (-1); | |
313 } | |
314 close (fdm); | |
315 } | |
316 | |
317 tty_raw (fds); | |
318 dup2 (fds, 0); | |
319 dup2 (fds, 1); | |
320 dup2 (fds, 2); | |
321 if (!ssh_use_askpass && fds > 2) | |
322 close (fds); | |
323 execvp (ssh_prog_name != NULL && *ssh_prog_name != '\0' ? | |
324 ssh_prog_name : "ssh", args); | |
325 | |
326 tempstr = _("Error: Cannot execute ssh: "); | |
327 write (1, tempstr, strlen (tempstr)); | |
328 errstr = g_strerror (errno); | |
329 write (1, errstr, strlen (errstr)); | |
330 write (1, "\n", 1); | |
331 return (-1); | |
332 } | |
333 else if (child > 0) | |
334 { | |
335 if (ssh_use_askpass || sshv2_use_sftp_subsys) | |
336 { | |
337 close (s[1]); | |
338 fdm = s[0]; | |
339 } | |
340 tty_raw (fdm); | |
341 if (!sshv2_use_sftp_subsys) | |
342 { | |
343 tempstr = ssh_start_login_sequence (request, fdm); | |
344 if (!tempstr || | |
345 !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5, | |
346 "xsftp") == 0)) | |
347 { | |
348 request->logging_function (gftp_logging_error, request->user_data, | |
349 _("Error: Received wrong init string from server\n")); | |
350 g_free (args); | |
351 g_free (exepath); | |
352 return (-2); | |
353 } | |
354 g_free (tempstr); | |
355 } | |
356 g_free (args); | |
357 g_free (exepath); | |
358 | |
359 request->sockfd = request->datafd = fdopen (fdm, "rb"); | |
360 request->sockfd_write = fdopen (fdm, "wb"); | |
361 | |
362 version = htonl (SSH_MY_VERSION); | |
363 if (sshv2_send_command (request, SSH_FXP_INIT, (char *) &version, 4) < 0) | |
364 return (-2); | |
365 | |
366 memset (&message, 0, sizeof (message)); | |
367 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_VERSION) | |
368 { | |
369 request->logging_function (gftp_logging_error, request->user_data, | |
370 _("Received wrong response from server, disconnecting\n")); | |
371 sshv2_message_free (&message); | |
372 gftp_disconnect (request); | |
373 return (-2); | |
374 } | |
375 sshv2_message_free (&message); | |
376 | |
377 request->logging_function (gftp_logging_misc, request->user_data, | |
378 _("Successfully logged into SSH server %s\n"), | |
379 request->hostname); | |
380 } | |
381 else | |
382 { | |
383 request->logging_function (gftp_logging_error, request->user_data, | |
384 _("Cannot fork another process: %s\n"), | |
385 g_strerror (errno)); | |
386 g_free (args); | |
387 return (-1); | |
388 } | |
389 | |
390 sshv2_getcwd (request); | |
391 if (request->sockfd == NULL) | |
392 return (-2); | |
393 | |
394 return (0); | |
395 } | |
396 | |
397 | |
398 static void | |
399 sshv2_disconnect (gftp_request * request) | |
400 { | |
401 sshv2_params * params; | |
402 | |
403 g_return_if_fail (request != NULL); | |
404 g_return_if_fail (request->protonum == GFTP_SSHV2_NUM); | |
405 | |
406 params = request->protocol_data; | |
407 | |
408 if (request->sockfd != NULL) | |
409 { | |
410 request->logging_function (gftp_logging_misc, request->user_data, | |
411 _("Disconnecting from site %s\n"), | |
412 request->hostname); | |
413 fclose (request->sockfd); | |
414 request->sockfd = request->datafd = request->sockfd_write = NULL; | |
415 } | |
416 | |
417 if (params->message.buffer != NULL) | |
418 sshv2_message_free (¶ms->message); | |
419 } | |
420 | |
421 | |
422 static gint32 | |
423 sshv2_buffer_get_int32 (gftp_request * request, sshv2_message * message, | |
424 int expected_response) | |
425 { | |
426 gint32 ret; | |
427 | |
428 if (message->end - message->pos < 4) | |
429 { | |
430 request->logging_function (gftp_logging_error, request->user_data, | |
431 _("Received wrong response from server, disconnecting\n")); | |
432 sshv2_message_free (message); | |
433 gftp_disconnect (request); | |
434 return (-2); | |
435 } | |
436 | |
437 memcpy (&ret, message->pos, 4); | |
438 ret = ntohl (ret); | |
439 message->pos += 4; | |
440 | |
441 if (expected_response > 0 && ret != expected_response) | |
442 { | |
443 request->logging_function (gftp_logging_error, request->user_data, | |
444 _("Received wrong response from server, disconnecting\n")); | |
445 sshv2_message_free (message); | |
446 gftp_disconnect (request); | |
447 return (-2); | |
448 } | |
449 | |
450 return (ret); | |
451 } | |
452 | |
453 | |
454 static char * | |
455 sshv2_buffer_get_string (gftp_request * request, sshv2_message * message) | |
456 { | |
457 char *string; | |
458 gint32 len; | |
459 | |
460 if ((len = sshv2_buffer_get_int32 (request, message, -1)) < 0) | |
461 return (NULL); | |
462 | |
463 if (len > SSH_MAX_STRING_SIZE || (message->end - message->pos < len)) | |
464 { | |
465 request->logging_function (gftp_logging_error, request->user_data, | |
466 _("Received wrong response from server, disconnecting\n")); | |
467 sshv2_message_free (message); | |
468 gftp_disconnect (request); | |
469 return (NULL); | |
470 } | |
471 | |
472 string = g_malloc (len + 1); | |
473 memcpy (string, message->pos, len); | |
474 string[len] = '\0'; | |
475 message->pos += len; | |
476 return (string); | |
477 } | |
478 | |
479 | |
480 static int | |
481 sshv2_send_command (gftp_request * request, char type, char *command, | |
482 gint32 len) | |
483 { | |
484 char buf[34000]; | |
485 ssize_t wrote; | |
486 gint32 clen; | |
487 | |
488 if (len > 33995) | |
489 { | |
490 request->logging_function (gftp_logging_error, request->user_data, | |
491 _("Error: Message size %d too big\n"), len); | |
492 gftp_disconnect (request); | |
493 return (-1); | |
494 } | |
495 | |
496 clen = htonl (len + 1); | |
497 memcpy (buf, &clen, 4); | |
498 buf[4] = type; | |
499 memcpy (&buf[5], command, len); | |
500 buf[len + 5] = '\0'; | |
501 | |
502 #ifdef DEBUG | |
503 printf ("\rSending: "); | |
504 for (wrote=0; wrote<len + 5; wrote++) | |
505 printf ("%x ", buf[wrote]); | |
506 printf ("\n"); | |
507 #endif | |
508 | |
509 sshv2_log_command (request, gftp_logging_send, type, buf + 5, len); | |
510 | |
511 wrote = fwrite (buf, len + 5, 1, request->sockfd_write); | |
512 if (ferror (request->sockfd_write)) | |
513 { | |
514 request->logging_function (gftp_logging_error, request->user_data, | |
515 _("Error: Could not write to socket: %s\n"), | |
516 g_strerror (errno)); | |
517 gftp_disconnect (request); | |
518 return (-1); | |
519 } | |
520 | |
521 fflush (request->sockfd_write); | |
522 if (ferror (request->sockfd_write)) | |
523 { | |
524 request->logging_function (gftp_logging_error, request->user_data, | |
525 _("Error: Could not write to socket: %s\n"), | |
526 g_strerror (errno)); | |
527 gftp_disconnect (request); | |
528 return (-1); | |
529 } | |
530 return 0; | |
531 } | |
532 | |
533 | |
534 static int | |
535 sshv2_read_response (gftp_request * request, sshv2_message * message, | |
536 FILE * fd) | |
537 { | |
538 ssize_t numread; | |
539 char buf[5]; | |
540 | |
541 if (fd == NULL) | |
542 fd = request->sockfd; | |
543 | |
544 numread = fread (buf, 5, 1, fd); | |
545 if (ferror (fd)) | |
546 { | |
547 request->logging_function (gftp_logging_error, request->user_data, | |
548 _("Error: Could not read from socket: %s\n"), | |
549 g_strerror (errno)); | |
550 gftp_disconnect (request); | |
551 return (-1); | |
552 } | |
553 | |
554 #ifdef DEBUG | |
555 printf ("\rReceived: "); | |
556 for (numread=0; numread<5; numread++) | |
557 printf ("%x ", buf[numread]); | |
558 fflush (stdout); | |
559 #endif | |
560 | |
561 memcpy (&message->length, buf, 4); | |
562 message->length = ntohl (message->length); | |
563 if (message->length > 34000) | |
564 { | |
565 request->logging_function (gftp_logging_error, request->user_data, | |
566 _("Error: Message size %d too big from server\n"), | |
567 message->length); | |
568 memset (message, 0, sizeof (*message)); | |
569 gftp_disconnect (request); | |
570 return (-1); | |
571 } | |
572 message->command = buf[4]; | |
573 message->buffer = g_malloc (message->length); | |
574 | |
575 message->pos = message->buffer; | |
576 message->end = message->buffer + message->length - 1; | |
577 | |
578 numread = fread (message->buffer, message->length - 1, 1, fd); | |
579 if (ferror (fd)) | |
580 { | |
581 request->logging_function (gftp_logging_error, request->user_data, | |
582 _("Error: Could not read from socket: %s\n"), | |
583 g_strerror (errno)); | |
584 gftp_disconnect (request); | |
585 return (-1); | |
586 } | |
587 message->buffer[message->length - 1] = '\0'; | |
588 | |
589 #ifdef DEBUG | |
590 printf ("\rReceived: "); | |
591 for (numread=0; numread<message->length - 1; numread++) | |
592 printf ("%x ", message->buffer[numread]); | |
593 printf ("\n"); | |
594 #endif | |
595 | |
596 sshv2_log_command (request, gftp_logging_recv, message->command, | |
597 message->buffer, message->length); | |
598 | |
599 return (message->command); | |
600 } | |
601 | |
602 | |
603 static void | |
604 sshv2_message_free (sshv2_message * message) | |
605 { | |
606 if (message->buffer) | |
607 g_free (message->buffer); | |
608 memset (message, 0, sizeof (*message)); | |
609 } | |
610 | |
611 | |
612 static void | |
613 sshv2_log_command (gftp_request * request, gftp_logging_level level, | |
614 char type, char *message, size_t length) | |
615 { | |
616 gint32 id, num, attr, stattype; | |
617 char *descr, *pos, oldchar; | |
618 sshv2_params * params; | |
619 | |
620 params = request->protocol_data; | |
621 memcpy (&id, message, 4); | |
622 id = ntohl (id); | |
623 switch (type) | |
624 { | |
625 case SSH_FXP_INIT: | |
626 request->logging_function (level, request->user_data, | |
627 _("%d: Protocol Initialization\n"), id); | |
628 break; | |
629 case SSH_FXP_VERSION: | |
630 memcpy (&num, message, 4); | |
631 num = ntohl (num); | |
632 request->logging_function (level, request->user_data, | |
633 _("%d: Protocol version %d\n"), id, num); | |
634 break; | |
635 case SSH_FXP_OPEN: | |
636 memcpy (&num, message + 4, 4); | |
637 num = ntohl (num); | |
638 pos = message + 12 + num - 1; | |
639 oldchar = *pos; | |
640 *pos = '\0'; | |
641 request->logging_function (level, request->user_data, | |
642 _("%d: Open %s\n"), id, message + 8); | |
643 *pos = oldchar; | |
644 break; | |
645 case SSH_FXP_CLOSE: | |
646 request->logging_function (level, request->user_data, | |
647 _("%d: Close\n"), id); | |
648 case SSH_FXP_READ: | |
649 case SSH_FXP_WRITE: | |
650 break; | |
651 case SSH_FXP_OPENDIR: | |
652 request->logging_function (level, request->user_data, | |
653 _("%d: Open Directory %s\n"), id, | |
654 message + 8); | |
655 break; | |
656 case SSH_FXP_READDIR: | |
657 request->logging_function (level, request->user_data, | |
658 _("%d: Read Directory\n"), id); | |
659 break; | |
660 case SSH_FXP_REMOVE: | |
661 request->logging_function (level, request->user_data, | |
662 _("%d: Remove file %s\n"), id, | |
663 message + 8); | |
664 break; | |
665 case SSH_FXP_MKDIR: | |
666 request->logging_function (level, request->user_data, | |
667 _("%d: Make directory %s\n"), id, | |
668 message + 8); | |
669 break; | |
670 case SSH_FXP_RMDIR: | |
671 request->logging_function (level, request->user_data, | |
672 _("%d: Remove directory %s\n"), id, | |
673 message + 8); | |
674 break; | |
675 case SSH_FXP_REALPATH: | |
676 request->logging_function (level, request->user_data, | |
677 _("%d: Realpath %s\n"), id, | |
678 message + 8); | |
679 break; | |
680 case SSH_FXP_ATTRS: | |
681 request->logging_function (level, request->user_data, | |
682 _("%d: File attributes\n"), id); | |
683 break; | |
684 case SSH_FXP_STAT: | |
685 request->logging_function (level, request->user_data, | |
686 _("%d: Stat %s\n"), id, | |
687 message + 8); | |
688 break; | |
689 case SSH_FXP_SETSTAT: | |
690 memcpy (&num, message + 4, 4); | |
691 num = ntohl (num); | |
692 pos = message + 12 + num - 1; | |
693 oldchar = *pos; | |
694 *pos = '\0'; | |
695 memcpy (&stattype, message + 8 + num, 4); | |
696 stattype = ntohl (stattype); | |
697 memcpy (&attr, message + 12 + num, 4); | |
698 attr = ntohl (attr); | |
699 switch (stattype) | |
700 { | |
701 case SSH_FILEXFER_ATTR_PERMISSIONS: | |
702 request->logging_function (level, request->user_data, | |
703 _("%d: Chmod %s %o\n"), id, | |
704 message + 8, attr); | |
705 break; | |
706 case SSH_FILEXFER_ATTR_ACMODTIME: | |
707 request->logging_function (level, request->user_data, | |
708 _("%d: Utime %s %d\n"), id, | |
709 message + 8, attr); | |
710 } | |
711 *pos = oldchar; | |
712 break; | |
713 case SSH_FXP_STATUS: | |
714 if (params->dont_log_status) | |
715 break; | |
716 memcpy (&num, message + 4, 4); | |
717 num = ntohl (num); | |
718 switch (num) | |
719 { | |
720 case SSH_FX_OK: | |
721 descr = _("OK"); | |
722 break; | |
723 case SSH_FX_EOF: | |
724 descr = _("EOF"); | |
725 break; | |
726 case SSH_FX_NO_SUCH_FILE: | |
727 descr = _("No such file or directory"); | |
728 break; | |
729 case SSH_FX_PERMISSION_DENIED: | |
730 descr = _("Permission denied"); | |
731 break; | |
732 case SSH_FX_FAILURE: | |
733 descr = _("Failure"); | |
734 break; | |
735 case SSH_FX_BAD_MESSAGE: | |
736 descr = _("Bad message"); | |
737 break; | |
738 case SSH_FX_NO_CONNECTION: | |
739 descr = _("No connection"); | |
740 break; | |
741 case SSH_FX_CONNECTION_LOST: | |
742 descr = _("Connection lost"); | |
743 break; | |
744 case SSH_FX_OP_UNSUPPORTED: | |
745 descr = _("Operation unsupported"); | |
746 break; | |
747 default: | |
748 descr = _("Unknown message returned from server"); | |
749 break; | |
750 } | |
751 request->logging_function (level, request->user_data, | |
752 "%d: %s\n", id, descr); | |
753 break; | |
754 case SSH_FXP_HANDLE: | |
755 request->logging_function (level, request->user_data, | |
756 "%d: File handle\n", id); | |
757 break; | |
758 case SSH_FXP_DATA: | |
759 break; | |
760 case SSH_FXP_NAME: | |
761 memcpy (&num, message + 4, 4); | |
762 num = ntohl (num); | |
763 request->logging_function (level, request->user_data, | |
764 "%d: Filenames (%d entries)\n", id, | |
765 num); | |
766 break; | |
767 default: | |
768 request->logging_function (level, request->user_data, | |
769 "Command: %x\n", type); | |
770 } | |
771 } | |
772 | |
773 | |
774 static int | |
775 sshv2_end_transfer (gftp_request * request) | |
776 { | |
777 sshv2_params * params; | |
778 sshv2_message message; | |
779 gint32 len; | |
780 | |
781 g_return_val_if_fail (request != NULL, -2); | |
782 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
783 g_return_val_if_fail (request->datafd != NULL, -2); | |
784 | |
785 params = request->protocol_data; | |
786 if (params->message.buffer != NULL) | |
787 { | |
788 sshv2_message_free (¶ms->message); | |
789 params->count = 0; | |
790 } | |
791 | |
792 if (params->handle_len > 0) | |
793 { | |
794 len = htonl (params->id++); | |
795 memcpy (params->handle, &len, 4); | |
796 | |
797 if (sshv2_send_command (request, SSH_FXP_CLOSE, params->handle, | |
798 params->handle_len) < 0) | |
799 return (-2); | |
800 | |
801 memset (&message, 0, sizeof (message)); | |
802 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_STATUS) | |
803 { | |
804 request->logging_function (gftp_logging_error, request->user_data, | |
805 _("Received wrong response from server, disconnecting\n")); | |
806 sshv2_message_free (&message); | |
807 gftp_disconnect (request); | |
808 return (-2); | |
809 } | |
810 sshv2_message_free (&message); | |
811 params->handle_len = 0; | |
812 } | |
813 | |
814 if (params->read_buffer != NULL) | |
815 { | |
816 g_free (params->read_buffer); | |
817 params->read_buffer = NULL; | |
818 } | |
819 | |
820 return (0); | |
821 } | |
822 | |
823 | |
824 static int | |
825 sshv2_list_files (gftp_request * request) | |
826 { | |
827 sshv2_params * params; | |
828 sshv2_message message; | |
829 char *tempstr; | |
830 gint32 len; | |
831 | |
832 g_return_val_if_fail (request != NULL, -2); | |
833 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
834 g_return_val_if_fail (request->sockfd != NULL, -2); | |
835 | |
836 params = request->protocol_data; | |
837 | |
838 request->logging_function (gftp_logging_misc, request->user_data, | |
839 _("Retrieving directory listing...\n")); | |
840 | |
841 tempstr = g_malloc (strlen (request->directory) + 9); | |
842 | |
843 len = htonl (params->id++); | |
844 memcpy (tempstr, &len, 4); | |
845 | |
846 len = htonl (strlen (request->directory)); | |
847 memcpy (tempstr + 4, &len, 4); | |
848 strcpy (tempstr + 8, request->directory); | |
849 if (sshv2_send_command (request, SSH_FXP_OPENDIR, tempstr, | |
850 strlen (request->directory) + 8) < 0) | |
851 { | |
852 g_free (tempstr); | |
853 return (-2); | |
854 } | |
855 g_free (tempstr); | |
856 | |
857 memset (&message, 0, sizeof (message)); | |
858 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE) | |
859 { | |
860 request->logging_function (gftp_logging_error, request->user_data, | |
861 _("Received wrong response from server, disconnecting\n")); | |
862 sshv2_message_free (&message); | |
863 gftp_disconnect (request); | |
864 return (-2); | |
865 } | |
866 | |
867 if (message.length - 4 > SSH_MAX_HANDLE_SIZE) | |
868 { | |
869 request->logging_function (gftp_logging_error, request->user_data, | |
870 _("Error: Message size %d too big from server\n"), | |
871 message.length - 4); | |
872 sshv2_message_free (&message); | |
873 gftp_disconnect (request); | |
874 return (-1); | |
875 | |
876 } | |
877 | |
878 memset (params->handle, 0, 4); | |
879 memcpy (params->handle + 4, message.buffer + 4, message.length - 5); | |
880 params->handle_len = message.length - 1; | |
881 sshv2_message_free (&message); | |
882 params->count = 0; | |
883 return (0); | |
884 } | |
885 | |
886 | |
887 static int | |
888 sshv2_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd) | |
889 { | |
890 gint32 len, attrs, longnamelen; | |
891 int ret, i, count, retsize; | |
892 sshv2_params *params; | |
893 char *longname; | |
894 | |
895 g_return_val_if_fail (request != NULL, -2); | |
896 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
897 g_return_val_if_fail (fle != NULL, -2); | |
898 | |
899 params = request->protocol_data; | |
900 | |
901 if (request->last_dir_entry) | |
902 { | |
903 g_free (request->last_dir_entry); | |
904 request->last_dir_entry = NULL; | |
905 request->last_dir_entry_len = 0; | |
906 } | |
907 retsize = 0; | |
908 | |
909 if (params->count > 0) | |
910 ret = SSH_FXP_NAME; | |
911 else | |
912 { | |
913 if (!request->cached) | |
914 { | |
915 if (params->message.buffer != NULL) | |
916 sshv2_message_free (¶ms->message); | |
917 | |
918 len = htonl (params->id++); | |
919 memcpy (params->handle, &len, 4); | |
920 | |
921 if (sshv2_send_command (request, SSH_FXP_READDIR, params->handle, | |
922 params->handle_len) < 0) | |
923 return (-2); | |
924 } | |
925 | |
926 if ((ret = sshv2_read_response (request, ¶ms->message, fd)) < 0) | |
927 return (-2); | |
928 | |
929 if (!request->cached) | |
930 { | |
931 request->last_dir_entry = g_malloc (params->message.length + 4); | |
932 len = htonl (params->message.length); | |
933 memcpy (request->last_dir_entry, &len, 4); | |
934 request->last_dir_entry[4] = params->message.command; | |
935 memcpy (request->last_dir_entry + 5, params->message.buffer, | |
936 params->message.length - 1); | |
937 request->last_dir_entry_len = params->message.length + 4; | |
938 } | |
939 | |
940 if (ret == SSH_FXP_NAME) | |
941 { | |
942 params->message.pos = params->message.buffer + 4; | |
943 if ((params->count = sshv2_buffer_get_int32 (request, | |
944 ¶ms->message, -1)) < 0) | |
945 return (-2); | |
946 } | |
947 } | |
948 | |
949 if (ret == SSH_FXP_NAME) | |
950 { | |
951 if ((len = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0 || | |
952 params->message.pos + len > params->message.end) | |
953 return (-2); | |
954 | |
955 params->message.pos += len; | |
956 | |
957 if ((longnamelen = sshv2_buffer_get_int32 (request, | |
958 ¶ms->message, -1)) < 0 || | |
959 params->message.pos + longnamelen > params->message.end) | |
960 return (-2); | |
961 | |
962 longname = params->message.pos; | |
963 params->message.pos += longnamelen; | |
964 | |
965 if ((attrs = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
966 return (-2); | |
967 | |
968 if (attrs & SSH_FILEXFER_ATTR_SIZE) | |
969 { | |
970 params->message.pos += 8; | |
971 if (params->message.pos > params->message.end) | |
972 { | |
973 request->logging_function (gftp_logging_error, request->user_data, | |
974 _("Received wrong response from server, disconnecting\n")); | |
975 sshv2_message_free (¶ms->message); | |
976 gftp_disconnect (request); | |
977 return (-2); | |
978 } | |
979 } | |
980 | |
981 if (attrs & SSH_FILEXFER_ATTR_UIDGID) | |
982 { | |
983 params->message.pos += 8; | |
984 if (params->message.pos > params->message.end) | |
985 { | |
986 request->logging_function (gftp_logging_error, request->user_data, | |
987 _("Received wrong response from server, disconnecting\n")); | |
988 sshv2_message_free (¶ms->message); | |
989 gftp_disconnect (request); | |
990 return (-2); | |
991 } | |
992 } | |
993 | |
994 if (attrs & SSH_FILEXFER_ATTR_PERMISSIONS) | |
995 { | |
996 params->message.pos += 4; | |
997 if (params->message.pos > params->message.end) | |
998 { | |
999 request->logging_function (gftp_logging_error, request->user_data, | |
1000 _("Received wrong response from server, disconnecting\n")); | |
1001 sshv2_message_free (¶ms->message); | |
1002 gftp_disconnect (request); | |
1003 return (-2); | |
1004 } | |
1005 } | |
1006 | |
1007 if (attrs & SSH_FILEXFER_ATTR_ACMODTIME) | |
1008 { | |
1009 params->message.pos += 8; | |
1010 if (params->message.pos > params->message.end) | |
1011 { | |
1012 request->logging_function (gftp_logging_error, request->user_data, | |
1013 _("Received wrong response from server, disconnecting\n")); | |
1014 sshv2_message_free (¶ms->message); | |
1015 gftp_disconnect (request); | |
1016 return (-2); | |
1017 } | |
1018 } | |
1019 | |
1020 if (attrs & SSH_FILEXFER_ATTR_EXTENDED) | |
1021 { | |
1022 if ((count = sshv2_buffer_get_int32 (request, | |
1023 ¶ms->message, -1)) < 0) | |
1024 return (-2); | |
1025 | |
1026 for (i=0; i<count; i++) | |
1027 { | |
1028 if ((len = sshv2_buffer_get_int32 (request, | |
1029 ¶ms->message, -1)) < 0 || | |
1030 params->message.pos + len + 4 > params->message.end) | |
1031 return (-2); | |
1032 | |
1033 params->message.pos += len + 4; | |
1034 | |
1035 if ((len = sshv2_buffer_get_int32 (request, | |
1036 ¶ms->message, -1)) < 0 || | |
1037 params->message.pos + len + 4 > params->message.end) | |
1038 return (-2); | |
1039 | |
1040 params->message.pos += len + 4; | |
1041 } | |
1042 } | |
1043 | |
1044 longname[longnamelen] = '\0'; | |
1045 | |
1046 /* The commercial SSH2 puts a / and * after some entries */ | |
1047 if (longname[longnamelen - 1] == '*') | |
1048 longname[--longnamelen] = '\0'; | |
1049 if (longname[longnamelen - 1] == '/') | |
1050 longname[--longnamelen] = '\0'; | |
1051 | |
1052 if (gftp_parse_ls (longname, fle) != 0) | |
1053 { | |
1054 gftp_file_destroy (fle); | |
1055 return (-2); | |
1056 } | |
1057 retsize = strlen (longname); | |
1058 | |
1059 params->count--; | |
1060 } | |
1061 else if (ret == SSH_FXP_STATUS) | |
1062 { | |
1063 sshv2_message_free (¶ms->message); | |
1064 return (0); | |
1065 } | |
1066 else | |
1067 { | |
1068 request->logging_function (gftp_logging_error, request->user_data, | |
1069 _("Received wrong response from server, disconnecting\n")); | |
1070 sshv2_message_free (¶ms->message); | |
1071 gftp_disconnect (request); | |
1072 return (-2); | |
1073 } | |
1074 | |
1075 return (retsize); | |
1076 } | |
1077 | |
1078 | |
1079 static int | |
1080 sshv2_chdir (gftp_request * request, const char *directory) | |
1081 { | |
1082 sshv2_message message; | |
1083 sshv2_params * params; | |
1084 char *tempstr, *dir; | |
1085 gint32 num; | |
1086 size_t len; | |
1087 | |
1088 g_return_val_if_fail (request != NULL, -2); | |
1089 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1090 g_return_val_if_fail (request->datafd != NULL, -2); | |
1091 | |
1092 params = request->protocol_data; | |
1093 if (request->directory != directory) | |
1094 { | |
1095 if (*directory == '/') | |
1096 { | |
1097 len = strlen (directory) + 8; | |
1098 tempstr = g_malloc (len + 1); | |
1099 strcpy (tempstr + 8, directory); | |
1100 } | |
1101 else | |
1102 { | |
1103 len = strlen (directory) + strlen (request->directory) + 9; | |
1104 tempstr = g_malloc (len + 1); | |
1105 strcpy (tempstr + 8, request->directory); | |
1106 strcat (tempstr + 8, "/"); | |
1107 strcat (tempstr + 8, directory); | |
1108 } | |
1109 | |
1110 num = htonl (params->id++); | |
1111 memcpy (tempstr, &num, 4); | |
1112 | |
1113 num = htonl (len - 8); | |
1114 memcpy (tempstr + 4, &num, 4); | |
1115 if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len) < 0) | |
1116 { | |
1117 g_free (tempstr); | |
1118 return (-2); | |
1119 } | |
1120 g_free (tempstr); | |
1121 | |
1122 memset (&message, 0, sizeof (message)); | |
1123 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_NAME) | |
1124 { | |
1125 request->logging_function (gftp_logging_error, request->user_data, | |
1126 _("Received wrong response from server, disconnecting\n")); | |
1127 sshv2_message_free (&message); | |
1128 gftp_disconnect (request); | |
1129 return (-2); | |
1130 } | |
1131 | |
1132 message.pos += 4; | |
1133 if (sshv2_buffer_get_int32 (request, &message, 1) != 1) | |
1134 return (-2); | |
1135 | |
1136 if ((dir = sshv2_buffer_get_string (request, &message)) == NULL) | |
1137 return (-2); | |
1138 | |
1139 if (request->directory) | |
1140 g_free (request->directory); | |
1141 request->directory = dir; | |
1142 sshv2_message_free (&message); | |
1143 } | |
1144 | |
1145 return (0); | |
1146 } | |
1147 | |
1148 | |
1149 static int | |
1150 sshv2_getcwd (gftp_request * request) | |
1151 { | |
1152 sshv2_message message; | |
1153 sshv2_params * params; | |
1154 char *tempstr, *dir; | |
1155 gint32 num; | |
1156 size_t len; | |
1157 | |
1158 g_return_val_if_fail (request != NULL, -2); | |
1159 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1160 g_return_val_if_fail (request->datafd != NULL, -2); | |
1161 | |
1162 if (request->directory == NULL || *request->directory == '\0') | |
1163 dir = "."; | |
1164 else | |
1165 dir = request->directory; | |
1166 | |
1167 params = request->protocol_data; | |
1168 len = strlen (dir); | |
1169 tempstr = g_malloc (len + 9); | |
1170 strcpy (tempstr + 8, dir); | |
1171 | |
1172 num = htonl (params->id++); | |
1173 memcpy (tempstr, &num, 4); | |
1174 | |
1175 num = htonl (len); | |
1176 memcpy (tempstr + 4, &num, 4); | |
1177 if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len + 8) < 0) | |
1178 { | |
1179 g_free (tempstr); | |
1180 return (-2); | |
1181 } | |
1182 | |
1183 g_free (tempstr); | |
1184 if (request->directory) | |
1185 { | |
1186 g_free (request->directory); | |
1187 request->directory = NULL; | |
1188 } | |
1189 | |
1190 memset (&message, 0, sizeof (message)); | |
1191 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_NAME) | |
1192 { | |
1193 request->logging_function (gftp_logging_error, request->user_data, | |
1194 _("Received wrong response from server, disconnecting\n")); | |
1195 sshv2_message_free (&message); | |
1196 gftp_disconnect (request); | |
1197 return (-2); | |
1198 } | |
1199 | |
1200 message.pos += 4; | |
1201 if (sshv2_buffer_get_int32 (request, &message, 1) < 0) | |
1202 return (-2); | |
1203 | |
1204 if ((request->directory = sshv2_buffer_get_string (request, &message)) == NULL) | |
1205 return (-2); | |
1206 sshv2_message_free (&message); | |
1207 return (0); | |
1208 } | |
1209 | |
1210 | |
1211 static int | |
1212 sshv2_rmdir (gftp_request * request, const char *directory) | |
1213 { | |
1214 sshv2_params * params; | |
1215 sshv2_message message; | |
1216 char *tempstr; | |
1217 gint32 num; | |
1218 size_t len; | |
1219 | |
1220 g_return_val_if_fail (request != NULL, -2); | |
1221 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1222 g_return_val_if_fail (request->datafd != NULL, -2); | |
1223 g_return_val_if_fail (directory != NULL, -2); | |
1224 | |
1225 params = request->protocol_data; | |
1226 | |
1227 if (*directory == '/') | |
1228 { | |
1229 len = strlen (directory) + 8; | |
1230 tempstr = g_malloc (len + 1); | |
1231 strcpy (tempstr + 8, directory); | |
1232 } | |
1233 else | |
1234 { | |
1235 len = strlen (directory) + strlen (request->directory) + 9; | |
1236 tempstr = g_malloc (len + 1); | |
1237 strcpy (tempstr + 8, request->directory); | |
1238 strcat (tempstr + 8, "/"); | |
1239 strcat (tempstr + 8, directory); | |
1240 } | |
1241 | |
1242 num = htonl (params->id++); | |
1243 memcpy (tempstr, &num, 4); | |
1244 | |
1245 num = htonl (len - 8); | |
1246 memcpy (tempstr + 4, &num, 4); | |
1247 | |
1248 if (sshv2_send_command (request, SSH_FXP_RMDIR, tempstr, len) < 0) | |
1249 { | |
1250 g_free (tempstr); | |
1251 return (-2); | |
1252 } | |
1253 g_free (tempstr); | |
1254 | |
1255 memset (&message, 0, sizeof (message)); | |
1256 if (sshv2_read_response (request, &message, NULL) < 0) | |
1257 return (-2); | |
1258 | |
1259 message.pos += 4; | |
1260 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1261 return (-2); | |
1262 | |
1263 sshv2_message_free (&message); | |
1264 | |
1265 return (0); | |
1266 } | |
1267 | |
1268 | |
1269 static int | |
1270 sshv2_rmfile (gftp_request * request, const char *file) | |
1271 { | |
1272 sshv2_params * params; | |
1273 sshv2_message message; | |
1274 char *tempstr; | |
1275 gint32 num; | |
1276 size_t len; | |
1277 | |
1278 g_return_val_if_fail (request != NULL, -2); | |
1279 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1280 g_return_val_if_fail (request->datafd != NULL, -2); | |
1281 g_return_val_if_fail (file != NULL, -2); | |
1282 | |
1283 params = request->protocol_data; | |
1284 | |
1285 if (*file == '/') | |
1286 { | |
1287 len = strlen (file) + 8; | |
1288 tempstr = g_malloc (len + 1); | |
1289 strcpy (tempstr + 8, file); | |
1290 } | |
1291 else | |
1292 { | |
1293 len = strlen (file) + strlen (request->directory) + 9; | |
1294 tempstr = g_malloc (len + 1); | |
1295 strcpy (tempstr + 8, request->directory); | |
1296 strcat (tempstr + 8, "/"); | |
1297 strcat (tempstr + 8, file); | |
1298 } | |
1299 | |
1300 num = htonl (params->id++); | |
1301 memcpy (tempstr, &num, 4); | |
1302 | |
1303 num = htonl (len - 8); | |
1304 memcpy (tempstr + 4, &num, 4); | |
1305 | |
1306 if (sshv2_send_command (request, SSH_FXP_REMOVE, tempstr, len) < 0) | |
1307 { | |
1308 g_free (tempstr); | |
1309 return (-2); | |
1310 } | |
1311 g_free (tempstr); | |
1312 | |
1313 memset (&message, 0, sizeof (message)); | |
1314 if (sshv2_read_response (request, &message, NULL) < 0) | |
1315 return (-2); | |
1316 | |
1317 message.pos += 4; | |
1318 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1319 return (-2); | |
1320 | |
1321 sshv2_message_free (&message); | |
1322 | |
1323 return (0); | |
1324 } | |
1325 | |
1326 | |
1327 static int | |
1328 sshv2_chmod (gftp_request * request, const char *file, int mode) | |
1329 { | |
1330 char *tempstr, buf[10]; | |
1331 sshv2_params * params; | |
1332 sshv2_message message; | |
1333 gint32 num; | |
1334 size_t len; | |
1335 | |
1336 g_return_val_if_fail (request != NULL, -2); | |
1337 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1338 g_return_val_if_fail (request->datafd != NULL, -2); | |
1339 g_return_val_if_fail (file != NULL, -2); | |
1340 | |
1341 params = request->protocol_data; | |
1342 | |
1343 if (*file == '/') | |
1344 { | |
1345 len = strlen (file) + 16; | |
1346 tempstr = g_malloc (len + 1); | |
1347 strcpy (tempstr + 8, file); | |
1348 } | |
1349 else | |
1350 { | |
1351 len = strlen (file) + strlen (request->directory) + 17; | |
1352 tempstr = g_malloc (len + 1); | |
1353 strcpy (tempstr + 8, request->directory); | |
1354 strcat (tempstr + 8, "/"); | |
1355 strcat (tempstr + 8, file); | |
1356 } | |
1357 | |
1358 num = htonl (params->id++); | |
1359 memcpy (tempstr, &num, 4); | |
1360 | |
1361 num = htonl (len - 16); | |
1362 memcpy (tempstr + 4, &num, 4); | |
1363 | |
1364 num = htonl (SSH_FILEXFER_ATTR_PERMISSIONS); | |
1365 memcpy (tempstr + len - 8, &num, 4); | |
1366 | |
1367 g_snprintf (buf, sizeof (buf), "%d", mode); | |
1368 num = htonl (strtol (buf, NULL, 8)); | |
1369 memcpy (tempstr + len - 4, &num, 4); | |
1370 | |
1371 if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0) | |
1372 { | |
1373 g_free (tempstr); | |
1374 return (-2); | |
1375 } | |
1376 g_free (tempstr); | |
1377 | |
1378 memset (&message, 0, sizeof (message)); | |
1379 if (sshv2_read_response (request, &message, NULL) < 0) | |
1380 return (-2); | |
1381 | |
1382 message.pos += 4; | |
1383 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1384 return (-2); | |
1385 | |
1386 sshv2_message_free (&message); | |
1387 | |
1388 return (0); | |
1389 } | |
1390 | |
1391 | |
1392 static int | |
1393 sshv2_mkdir (gftp_request * request, const char *newdir) | |
1394 { | |
1395 sshv2_params * params; | |
1396 sshv2_message message; | |
1397 char *tempstr; | |
1398 gint32 num; | |
1399 size_t len; | |
1400 | |
1401 g_return_val_if_fail (request != NULL, -2); | |
1402 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1403 g_return_val_if_fail (request->datafd != NULL, -2); | |
1404 g_return_val_if_fail (newdir != NULL, -2); | |
1405 | |
1406 params = request->protocol_data; | |
1407 | |
1408 if (*newdir == '/') | |
1409 { | |
1410 len = strlen (newdir) + 12; | |
1411 tempstr = g_malloc (len + 1); | |
1412 strcpy (tempstr + 8, newdir); | |
1413 } | |
1414 else | |
1415 { | |
1416 len = strlen (newdir) + strlen (request->directory) + 13; | |
1417 tempstr = g_malloc (len + 1); | |
1418 strcpy (tempstr + 8, request->directory); | |
1419 strcat (tempstr + 8, "/"); | |
1420 strcat (tempstr + 8, newdir); | |
1421 } | |
1422 | |
1423 num = htonl (params->id++); | |
1424 memcpy (tempstr, &num, 4); | |
1425 | |
1426 num = htonl (len - 12); | |
1427 memcpy (tempstr + 4, &num, 4); | |
1428 memset (tempstr + len - 4, 0, 4); /* attributes */ | |
1429 | |
1430 if (sshv2_send_command (request, SSH_FXP_MKDIR, tempstr, len) < 0) | |
1431 { | |
1432 g_free (tempstr); | |
1433 return (-2); | |
1434 } | |
1435 g_free (tempstr); | |
1436 | |
1437 memset (&message, 0, sizeof (message)); | |
1438 if (sshv2_read_response (request, &message, NULL) < 0) | |
1439 return (-2); | |
1440 | |
1441 message.pos += 4; | |
1442 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1443 return (-2); | |
1444 | |
1445 sshv2_message_free (&message); | |
1446 | |
1447 return (0); | |
1448 } | |
1449 | |
1450 | |
1451 static int | |
1452 sshv2_rename (gftp_request * request, const char *oldname, const char *newname) | |
1453 { | |
1454 char *tempstr, *oldstr, *newstr; | |
1455 sshv2_params * params; | |
1456 sshv2_message message; | |
1457 gint32 num; | |
1458 size_t oldlen, newlen; | |
1459 | |
1460 g_return_val_if_fail (request != NULL, -2); | |
1461 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1462 g_return_val_if_fail (request->datafd != NULL, -2); | |
1463 g_return_val_if_fail (oldname != NULL, -2); | |
1464 g_return_val_if_fail (newname != NULL, -2); | |
1465 | |
1466 params = request->protocol_data; | |
1467 | |
1468 if (*oldname == '/') | |
1469 { | |
1470 oldlen = strlen (oldname); | |
1471 oldstr = g_strconcat (oldname, NULL); | |
1472 } | |
1473 else | |
1474 { | |
1475 oldlen = strlen (request->directory) + strlen (oldname) + 1; | |
1476 oldstr = g_strconcat (request->directory, "/", oldname, NULL); | |
1477 } | |
1478 | |
1479 if (*newname == '/') | |
1480 { | |
1481 newlen = strlen (newname); | |
1482 newstr = g_strconcat (newname, NULL); | |
1483 } | |
1484 else | |
1485 { | |
1486 newlen = strlen (request->directory) + strlen (newname) + 1; | |
1487 newstr = g_strconcat (request->directory, "/", newname, NULL); | |
1488 } | |
1489 | |
1490 tempstr = g_malloc (oldlen + newlen + 13); | |
1491 num = htonl (params->id++); | |
1492 memcpy (tempstr, &num, 4); | |
1493 | |
1494 num = htonl (oldlen); | |
1495 memcpy (tempstr + 4, &num, 4); | |
1496 strcpy (tempstr + 8, oldstr); | |
1497 | |
1498 num = htonl (newlen); | |
1499 memcpy (tempstr + 8 + oldlen, &num, 4); | |
1500 strcpy (tempstr + 12 + oldlen, newstr); | |
1501 | |
1502 if (sshv2_send_command (request, SSH_FXP_RENAME, tempstr, oldlen + newlen + 12) < 0) | |
1503 { | |
1504 g_free (tempstr); | |
1505 return (-2); | |
1506 } | |
1507 g_free (tempstr); | |
1508 | |
1509 memset (&message, 0, sizeof (message)); | |
1510 if (sshv2_read_response (request, &message, NULL) < 0) | |
1511 return (-2); | |
1512 | |
1513 message.pos += 4; | |
1514 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1515 return (-2); | |
1516 | |
1517 sshv2_message_free (&message); | |
1518 | |
1519 return (0); | |
1520 } | |
1521 | |
1522 | |
1523 static int | |
1524 sshv2_set_file_time (gftp_request * request, const char *file, time_t datetime) | |
1525 { | |
1526 sshv2_params * params; | |
1527 sshv2_message message; | |
1528 char *tempstr; | |
1529 gint32 num; | |
1530 size_t len; | |
1531 | |
1532 g_return_val_if_fail (request != NULL, -2); | |
1533 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1534 g_return_val_if_fail (request->datafd != NULL, -2); | |
1535 g_return_val_if_fail (file != NULL, -2); | |
1536 | |
1537 params = request->protocol_data; | |
1538 | |
1539 if (*file == '/') | |
1540 { | |
1541 len = strlen (file) + 20; | |
1542 tempstr = g_malloc (len + 1); | |
1543 strcpy (tempstr + 8, file); | |
1544 } | |
1545 else | |
1546 { | |
1547 len = strlen (file) + strlen (request->directory) + 21; | |
1548 tempstr = g_malloc (len + 1); | |
1549 strcpy (tempstr + 8, request->directory); | |
1550 strcat (tempstr + 8, "/"); | |
1551 strcat (tempstr + 8, file); | |
1552 } | |
1553 | |
1554 num = htonl (params->id++); | |
1555 memcpy (tempstr, &num, 4); | |
1556 | |
1557 num = htonl (len - 20); | |
1558 memcpy (tempstr + 4, &num, 4); | |
1559 | |
1560 num = htonl (SSH_FILEXFER_ATTR_ACMODTIME); | |
1561 memcpy (tempstr + len - 12, &num, 4); | |
1562 | |
1563 num = htonl (datetime); | |
1564 memcpy (tempstr + len - 8, &num, 4); | |
1565 | |
1566 num = htonl (datetime); | |
1567 memcpy (tempstr + len - 4, &num, 4); | |
1568 | |
1569 if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0) | |
1570 { | |
1571 g_free (tempstr); | |
1572 return (-2); | |
1573 } | |
1574 g_free (tempstr); | |
1575 | |
1576 memset (&message, 0, sizeof (message)); | |
1577 if (sshv2_read_response (request, &message, NULL) < 0) | |
1578 return (-2); | |
1579 | |
1580 message.pos += 4; | |
1581 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1582 return (-2); | |
1583 | |
1584 sshv2_message_free (&message); | |
1585 | |
1586 return (0); | |
1587 } | |
1588 | |
1589 | |
1590 static off_t | |
1591 sshv2_get_file_size (gftp_request * request, const char *file) | |
1592 { | |
1593 gint32 len, highnum, lownum, attrs, num; | |
1594 sshv2_params * params; | |
1595 char *tempstr; | |
1596 #ifdef G_HAVE_GINT64 | |
1597 gint64 ret; | |
1598 #endif | |
1599 | |
1600 g_return_val_if_fail (request != NULL, -2); | |
1601 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1602 g_return_val_if_fail (request->datafd != NULL, -2); | |
1603 g_return_val_if_fail (file != NULL, -2); | |
1604 | |
1605 params = request->protocol_data; | |
1606 | |
1607 if (*file == '/') | |
1608 { | |
1609 len = strlen (file); | |
1610 tempstr = g_malloc (len + 9); | |
1611 strcpy (tempstr + 8, file); | |
1612 } | |
1613 else | |
1614 { | |
1615 len = strlen (file) + strlen (request->directory) + 1; | |
1616 tempstr = g_malloc (len + 9); | |
1617 strcpy (tempstr + 8, request->directory); | |
1618 strcat (tempstr + 8, "/"); | |
1619 strcat (tempstr + 8, file); | |
1620 } | |
1621 | |
1622 num = htonl (params->id++); | |
1623 memcpy (tempstr, &num, 4); | |
1624 | |
1625 num = htonl (len); | |
1626 memcpy (tempstr + 4, &num, 4); | |
1627 | |
1628 if (sshv2_send_command (request, SSH_FXP_STAT, tempstr, len + 8) < 0) | |
1629 { | |
1630 g_free (tempstr); | |
1631 return (-2); | |
1632 } | |
1633 g_free (tempstr); | |
1634 | |
1635 memset (¶ms->message, 0, sizeof (params->message)); | |
1636 if (sshv2_read_response (request, ¶ms->message, NULL) != SSH_FXP_ATTRS) | |
1637 { | |
1638 request->logging_function (gftp_logging_error, request->user_data, | |
1639 _("Received wrong response from server, disconnecting\n")); | |
1640 sshv2_message_free (¶ms->message); | |
1641 gftp_disconnect (request); | |
1642 return (-2); | |
1643 } | |
1644 | |
1645 if (params->message.length < 5) | |
1646 return (-2); | |
1647 params->message.pos += 4; | |
1648 | |
1649 if ((attrs = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
1650 return (-2); | |
1651 | |
1652 if (attrs & SSH_FILEXFER_ATTR_SIZE) | |
1653 { | |
1654 if ((highnum = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
1655 return (-2); | |
1656 | |
1657 if ((lownum = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
1658 return (-2); | |
1659 | |
1660 sshv2_message_free (¶ms->message); | |
1661 | |
1662 #if G_HAVE_GINT64 | |
1663 ret = (gint64) lownum | ((gint64) highnum >> 32); | |
1664 return (ret); | |
1665 #else | |
1666 return (lownum); | |
1667 #endif | |
1668 } | |
1669 | |
1670 sshv2_message_free (¶ms->message); | |
1671 | |
1672 return (0); | |
1673 | |
1674 } | |
1675 | |
1676 | |
1677 static long | |
1678 sshv2_get_file (gftp_request * request, const char *file, FILE * fd, | |
1679 off_t startsize) | |
1680 { | |
1681 sshv2_params * params; | |
1682 sshv2_message message; | |
1683 char *tempstr; | |
1684 size_t stlen; | |
1685 gint32 num; | |
1686 | |
1687 g_return_val_if_fail (request != NULL, -2); | |
1688 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1689 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1690 /* fd ignored for this protocol */ | |
1691 | |
1692 params = request->protocol_data; | |
1693 params->offset = startsize; | |
1694 | |
1695 if (*file == '/') | |
1696 { | |
1697 stlen = strlen (file); | |
1698 tempstr = g_malloc (stlen + 16); | |
1699 strcpy (tempstr + 8, file); | |
1700 } | |
1701 else | |
1702 { | |
1703 stlen = strlen (file) + strlen (request->directory) + 1; | |
1704 tempstr = g_malloc (stlen + 16); | |
1705 strcpy (tempstr + 8, request->directory); | |
1706 strcat (tempstr + 8, "/"); | |
1707 strcat (tempstr + 8, file); | |
1708 } | |
1709 | |
1710 num = htonl (params->id++); | |
1711 memcpy (tempstr, &num, 4); | |
1712 | |
1713 num = htonl (stlen); | |
1714 memcpy (tempstr + 4, &num, 4); | |
1715 | |
1716 num = htonl (SSH_FXF_READ); | |
1717 memcpy (tempstr + 8 + stlen, &num, 4); | |
1718 | |
1719 memset (tempstr + 12 + stlen, 0, 4); | |
1720 | |
1721 if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0) | |
1722 { | |
1723 g_free (tempstr); | |
1724 return (-2); | |
1725 } | |
1726 | |
1727 g_free (tempstr); | |
1728 memset (&message, 0, sizeof (message)); | |
1729 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE) | |
1730 { | |
1731 request->logging_function (gftp_logging_error, request->user_data, | |
1732 _("Received wrong response from server, disconnecting\n")); | |
1733 sshv2_message_free (&message); | |
1734 gftp_disconnect (request); | |
1735 return (-2); | |
1736 } | |
1737 | |
1738 if (message.length - 4 > SSH_MAX_HANDLE_SIZE) | |
1739 { | |
1740 request->logging_function (gftp_logging_error, request->user_data, | |
1741 _("Error: Message size %d too big from server\n"), | |
1742 message.length - 4); | |
1743 sshv2_message_free (&message); | |
1744 gftp_disconnect (request); | |
1745 return (-1); | |
1746 | |
1747 } | |
1748 | |
1749 memset (params->handle, 0, 4); | |
1750 memcpy (params->handle + 4, message.buffer+ 4, message.length - 5); | |
1751 params->handle_len = message.length - 1; | |
1752 sshv2_message_free (&message); | |
1753 | |
1754 return (sshv2_get_file_size (request, file)); | |
1755 } | |
1756 | |
1757 | |
1758 static int | |
1759 sshv2_put_file (gftp_request * request, const char *file, FILE * fd, | |
1760 off_t startsize, off_t totalsize) | |
1761 { | |
1762 sshv2_params * params; | |
1763 sshv2_message message; | |
1764 char *tempstr; | |
1765 size_t stlen; | |
1766 gint32 num; | |
1767 | |
1768 g_return_val_if_fail (request != NULL, -2); | |
1769 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1770 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1771 /* fd ignored for this protocol */ | |
1772 | |
1773 params = request->protocol_data; | |
1774 params->offset = 0; | |
1775 | |
1776 if (*file == '/') | |
1777 { | |
1778 stlen = strlen (file); | |
1779 tempstr = g_malloc (stlen + 16); | |
1780 strcpy (tempstr + 8, file); | |
1781 } | |
1782 else | |
1783 { | |
1784 stlen = strlen (file) + strlen (request->directory) + 1; | |
1785 tempstr = g_malloc (stlen + 16); | |
1786 strcpy (tempstr + 8, request->directory); | |
1787 strcat (tempstr + 8, "/"); | |
1788 strcat (tempstr + 8, file); | |
1789 } | |
1790 | |
1791 num = htonl (params->id++); | |
1792 memcpy (tempstr, &num, 4); | |
1793 | |
1794 num = htonl (stlen); | |
1795 memcpy (tempstr + 4, &num, 4); | |
1796 | |
1797 if (startsize > 0) | |
1798 num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_APPEND); | |
1799 else | |
1800 num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC); | |
1801 memcpy (tempstr + 8 + stlen, &num, 4); | |
1802 | |
1803 memset (tempstr + 12 + stlen, 0, 4); | |
1804 | |
1805 if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0) | |
1806 { | |
1807 g_free (tempstr); | |
1808 return (-2); | |
1809 } | |
1810 | |
1811 g_free (tempstr); | |
1812 memset (&message, 0, sizeof (message)); | |
1813 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE) | |
1814 { | |
1815 request->logging_function (gftp_logging_error, request->user_data, | |
1816 _("Received wrong response from server, disconnecting\n")); | |
1817 sshv2_message_free (&message); | |
1818 gftp_disconnect (request); | |
1819 return (-2); | |
1820 } | |
1821 | |
1822 if (message.length - 4 > SSH_MAX_HANDLE_SIZE) | |
1823 { | |
1824 request->logging_function (gftp_logging_error, request->user_data, | |
1825 _("Error: Message size %d too big from server\n"), | |
1826 message.length - 4); | |
1827 sshv2_message_free (&message); | |
1828 gftp_disconnect (request); | |
1829 return (-1); | |
1830 | |
1831 } | |
1832 | |
1833 memset (params->handle, 0, 4); | |
1834 memcpy (params->handle + 4, message.buffer+ 4, message.length - 5); | |
1835 params->handle_len = message.length - 1; | |
1836 sshv2_message_free (&message); | |
1837 | |
1838 return (0); | |
1839 } | |
1840 | |
1841 | |
1842 static size_t | |
1843 sshv2_get_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1844 { | |
1845 sshv2_params * params; | |
1846 sshv2_message message; | |
1847 gint32 num; | |
1848 | |
1849 #ifdef G_HAVE_GINT64 | |
1850 gint64 offset; | |
1851 #else | |
1852 gint32 offset; | |
1853 #endif | |
1854 | |
1855 g_return_val_if_fail (request != NULL, -2); | |
1856 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1857 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1858 g_return_val_if_fail (buf != NULL, -2); | |
1859 | |
1860 params = request->protocol_data; | |
1861 | |
1862 if (params->read_buffer == NULL) | |
1863 { | |
1864 params->read_buffer = g_malloc (params->handle_len + 12); | |
1865 num = htonl (params->handle_len); | |
1866 memcpy (params->read_buffer, params->handle, params->handle_len); | |
1867 } | |
1868 | |
1869 num = htonl (params->id++); | |
1870 memcpy (params->read_buffer, &num, 4); | |
1871 | |
1872 #ifdef G_HAVE_GINT64 | |
1873 offset = hton64 (params->offset); | |
1874 memcpy (params->read_buffer + params->handle_len, &offset, 8); | |
1875 #else | |
1876 memset (params->read_buffer + params->handle_len, 0, 4); | |
1877 offset = htonl (params->offset); | |
1878 memcpy (params->read_buffer + params->handle_len + 4, &offset, 4); | |
1879 #endif | |
1880 | |
1881 num = htonl (size); | |
1882 memcpy (params->read_buffer + params->handle_len + 8, &num, 4); | |
1883 | |
1884 if (sshv2_send_command (request, SSH_FXP_READ, params->read_buffer, params->handle_len + 12) < 0) | |
1885 return (-2); | |
1886 | |
1887 memset (&message, 0, sizeof (message)); | |
1888 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_DATA) | |
1889 { | |
1890 message.pos += 4; | |
1891 if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0) | |
1892 return (-2); | |
1893 sshv2_message_free (&message); | |
1894 if (num != SSH_FX_EOF) | |
1895 { | |
1896 request->logging_function (gftp_logging_error, request->user_data, | |
1897 _("Received wrong response from server, disconnecting\n")); | |
1898 gftp_disconnect (request); | |
1899 return (-2); | |
1900 } | |
1901 return (0); | |
1902 } | |
1903 | |
1904 memcpy (&num, message.buffer + 4, 4); | |
1905 num = ntohl (num); | |
1906 if (num > size) | |
1907 { | |
1908 request->logging_function (gftp_logging_error, request->user_data, | |
1909 _("Error: Message size %d too big from server\n"), | |
1910 num); | |
1911 sshv2_message_free (&message); | |
1912 gftp_disconnect (request); | |
1913 return (-1); | |
1914 | |
1915 } | |
1916 | |
1917 memcpy (buf, message.buffer + 8, num); | |
1918 sshv2_message_free (&message); | |
1919 params->offset += num; | |
1920 return (num); | |
1921 } | |
1922 | |
1923 | |
1924 static size_t | |
1925 sshv2_put_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1926 { | |
1927 sshv2_params * params; | |
1928 sshv2_message message; | |
1929 char tempstr[32768]; | |
1930 gint32 num; | |
1931 int ret; | |
1932 | |
1933 #ifdef G_HAVE_GINT64 | |
1934 gint64 offset; | |
1935 #else | |
1936 gint32 offset; | |
1937 #endif | |
1938 | |
1939 g_return_val_if_fail (request != NULL, -2); | |
1940 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1941 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1942 g_return_val_if_fail (buf != NULL, -2); | |
1943 g_return_val_if_fail (size <= 32500, -2); | |
1944 | |
1945 params = request->protocol_data; | |
1946 | |
1947 num = htonl (params->handle_len); | |
1948 memcpy (tempstr, params->handle, params->handle_len); | |
1949 | |
1950 num = htonl (params->id++); | |
1951 memcpy (tempstr, &num, 4); | |
1952 | |
1953 #ifdef G_HAVE_GINT64 | |
1954 offset = hton64 (params->offset); | |
1955 memcpy (tempstr + params->handle_len, &offset, 8); | |
1956 #else | |
1957 memset (tempstr + params->handle_len, 0, 4); | |
1958 offset = htonl (params->offset); | |
1959 memcpy (tempstr + params->handle_len + 4, &offset, 4); | |
1960 #endif | |
1961 | |
1962 num = htonl (size); | |
1963 memcpy (tempstr + params->handle_len + 8, &num, 4); | |
1964 memcpy (tempstr + params->handle_len + 12, buf, size); | |
1965 | |
1966 if (sshv2_send_command (request, SSH_FXP_WRITE, tempstr, params->handle_len + size + 12) < 0) | |
1967 { | |
1968 g_free (tempstr); | |
1969 return (-2); | |
1970 } | |
1971 | |
1972 memset (&message, 0, sizeof (message)); | |
1973 params->dont_log_status = 1; | |
1974 ret = sshv2_read_response (request, &message, NULL); | |
1975 params->dont_log_status = 0; | |
1976 if (ret != SSH_FXP_STATUS) | |
1977 { | |
1978 request->logging_function (gftp_logging_error, request->user_data, | |
1979 _("Received wrong response from server, disconnecting\n")); | |
1980 sshv2_message_free (&message); | |
1981 gftp_disconnect (request); | |
1982 return (-2); | |
1983 } | |
1984 | |
1985 message.pos += 4; | |
1986 if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0) | |
1987 return (-2); | |
1988 sshv2_message_free (&message); | |
1989 | |
1990 if (num == SSH_FX_EOF) | |
1991 return (0); | |
1992 else if (num != SSH_FX_OK) | |
1993 return (-1); | |
1994 | |
1995 params->offset += size; | |
1996 return (size); | |
1997 } | |
1998 |