Mercurial > gftp.yaz
annotate lib/sshv2.c @ 15:82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
author | masneyb |
---|---|
date | Wed, 04 Sep 2002 13:02:15 +0000 |
parents | 83090328581e |
children | c8ec7877432e |
rev | line source |
---|---|
1 | 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 | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
359 if ((request->sockfd = fdopen (fdm, "rb+")) == NULL) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
360 { |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
361 request->logging_function (gftp_logging_error, request->user_data, |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
362 _("Cannot fdopen() socket: %s\n"), |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
363 g_strerror (errno)); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
364 close (fdm); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
365 return (-2); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
366 } |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
367 |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
368 if ((request->sockfd_write = fdopen (fdm, "wb+")) == NULL) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
369 { |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
370 request->logging_function (gftp_logging_error, request->user_data, |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
371 _("Cannot fdopen() socket: %s\n"), |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
372 g_strerror (errno)); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
373 gftp_disconnect (request); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
374 return (-2); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
375 } |
1 | 376 |
377 version = htonl (SSH_MY_VERSION); | |
378 if (sshv2_send_command (request, SSH_FXP_INIT, (char *) &version, 4) < 0) | |
379 return (-2); | |
380 | |
381 memset (&message, 0, sizeof (message)); | |
382 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_VERSION) | |
383 { | |
384 request->logging_function (gftp_logging_error, request->user_data, | |
385 _("Received wrong response from server, disconnecting\n")); | |
386 sshv2_message_free (&message); | |
387 gftp_disconnect (request); | |
388 return (-2); | |
389 } | |
390 sshv2_message_free (&message); | |
391 | |
392 request->logging_function (gftp_logging_misc, request->user_data, | |
393 _("Successfully logged into SSH server %s\n"), | |
394 request->hostname); | |
395 } | |
396 else | |
397 { | |
398 request->logging_function (gftp_logging_error, request->user_data, | |
399 _("Cannot fork another process: %s\n"), | |
400 g_strerror (errno)); | |
401 g_free (args); | |
402 return (-1); | |
403 } | |
404 | |
405 sshv2_getcwd (request); | |
406 if (request->sockfd == NULL) | |
407 return (-2); | |
408 | |
409 return (0); | |
410 } | |
411 | |
412 | |
413 static void | |
414 sshv2_disconnect (gftp_request * request) | |
415 { | |
416 sshv2_params * params; | |
417 | |
418 g_return_if_fail (request != NULL); | |
419 g_return_if_fail (request->protonum == GFTP_SSHV2_NUM); | |
420 | |
421 params = request->protocol_data; | |
422 | |
423 if (request->sockfd != NULL) | |
424 { | |
425 request->logging_function (gftp_logging_misc, request->user_data, | |
426 _("Disconnecting from site %s\n"), | |
427 request->hostname); | |
428 fclose (request->sockfd); | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
1
diff
changeset
|
429 request->sockfd = request->sockfd_write = NULL; |
1 | 430 } |
431 | |
432 if (params->message.buffer != NULL) | |
433 sshv2_message_free (¶ms->message); | |
434 } | |
435 | |
436 | |
437 static gint32 | |
438 sshv2_buffer_get_int32 (gftp_request * request, sshv2_message * message, | |
439 int expected_response) | |
440 { | |
441 gint32 ret; | |
442 | |
443 if (message->end - message->pos < 4) | |
444 { | |
445 request->logging_function (gftp_logging_error, request->user_data, | |
446 _("Received wrong response from server, disconnecting\n")); | |
447 sshv2_message_free (message); | |
448 gftp_disconnect (request); | |
449 return (-2); | |
450 } | |
451 | |
452 memcpy (&ret, message->pos, 4); | |
453 ret = ntohl (ret); | |
454 message->pos += 4; | |
455 | |
456 if (expected_response > 0 && ret != expected_response) | |
457 { | |
458 request->logging_function (gftp_logging_error, request->user_data, | |
459 _("Received wrong response from server, disconnecting\n")); | |
460 sshv2_message_free (message); | |
461 gftp_disconnect (request); | |
462 return (-2); | |
463 } | |
464 | |
465 return (ret); | |
466 } | |
467 | |
468 | |
469 static char * | |
470 sshv2_buffer_get_string (gftp_request * request, sshv2_message * message) | |
471 { | |
472 char *string; | |
473 gint32 len; | |
474 | |
475 if ((len = sshv2_buffer_get_int32 (request, message, -1)) < 0) | |
476 return (NULL); | |
477 | |
478 if (len > SSH_MAX_STRING_SIZE || (message->end - message->pos < len)) | |
479 { | |
480 request->logging_function (gftp_logging_error, request->user_data, | |
481 _("Received wrong response from server, disconnecting\n")); | |
482 sshv2_message_free (message); | |
483 gftp_disconnect (request); | |
484 return (NULL); | |
485 } | |
486 | |
487 string = g_malloc (len + 1); | |
488 memcpy (string, message->pos, len); | |
489 string[len] = '\0'; | |
490 message->pos += len; | |
491 return (string); | |
492 } | |
493 | |
494 | |
495 static int | |
496 sshv2_send_command (gftp_request * request, char type, char *command, | |
497 gint32 len) | |
498 { | |
499 char buf[34000]; | |
500 ssize_t wrote; | |
501 gint32 clen; | |
502 | |
503 if (len > 33995) | |
504 { | |
505 request->logging_function (gftp_logging_error, request->user_data, | |
506 _("Error: Message size %d too big\n"), len); | |
507 gftp_disconnect (request); | |
508 return (-1); | |
509 } | |
510 | |
511 clen = htonl (len + 1); | |
512 memcpy (buf, &clen, 4); | |
513 buf[4] = type; | |
514 memcpy (&buf[5], command, len); | |
515 buf[len + 5] = '\0'; | |
516 | |
517 #ifdef DEBUG | |
518 printf ("\rSending: "); | |
519 for (wrote=0; wrote<len + 5; wrote++) | |
520 printf ("%x ", buf[wrote]); | |
521 printf ("\n"); | |
522 #endif | |
523 | |
524 sshv2_log_command (request, gftp_logging_send, type, buf + 5, len); | |
525 | |
526 wrote = fwrite (buf, len + 5, 1, request->sockfd_write); | |
527 if (ferror (request->sockfd_write)) | |
528 { | |
529 request->logging_function (gftp_logging_error, request->user_data, | |
530 _("Error: Could not write to socket: %s\n"), | |
531 g_strerror (errno)); | |
532 gftp_disconnect (request); | |
533 return (-1); | |
534 } | |
535 | |
536 fflush (request->sockfd_write); | |
537 if (ferror (request->sockfd_write)) | |
538 { | |
539 request->logging_function (gftp_logging_error, request->user_data, | |
540 _("Error: Could not write to socket: %s\n"), | |
541 g_strerror (errno)); | |
542 gftp_disconnect (request); | |
543 return (-1); | |
544 } | |
545 return 0; | |
546 } | |
547 | |
548 | |
549 static int | |
550 sshv2_read_response (gftp_request * request, sshv2_message * message, | |
551 FILE * fd) | |
552 { | |
553 ssize_t numread; | |
554 char buf[5]; | |
555 | |
556 if (fd == NULL) | |
557 fd = request->sockfd; | |
558 | |
559 numread = fread (buf, 5, 1, fd); | |
560 if (ferror (fd)) | |
561 { | |
562 request->logging_function (gftp_logging_error, request->user_data, | |
563 _("Error: Could not read from socket: %s\n"), | |
564 g_strerror (errno)); | |
565 gftp_disconnect (request); | |
566 return (-1); | |
567 } | |
568 | |
569 #ifdef DEBUG | |
570 printf ("\rReceived: "); | |
571 for (numread=0; numread<5; numread++) | |
572 printf ("%x ", buf[numread]); | |
573 fflush (stdout); | |
574 #endif | |
575 | |
576 memcpy (&message->length, buf, 4); | |
577 message->length = ntohl (message->length); | |
578 if (message->length > 34000) | |
579 { | |
580 request->logging_function (gftp_logging_error, request->user_data, | |
581 _("Error: Message size %d too big from server\n"), | |
582 message->length); | |
583 memset (message, 0, sizeof (*message)); | |
584 gftp_disconnect (request); | |
585 return (-1); | |
586 } | |
587 message->command = buf[4]; | |
588 message->buffer = g_malloc (message->length); | |
589 | |
590 message->pos = message->buffer; | |
591 message->end = message->buffer + message->length - 1; | |
592 | |
593 numread = fread (message->buffer, message->length - 1, 1, fd); | |
594 if (ferror (fd)) | |
595 { | |
596 request->logging_function (gftp_logging_error, request->user_data, | |
597 _("Error: Could not read from socket: %s\n"), | |
598 g_strerror (errno)); | |
599 gftp_disconnect (request); | |
600 return (-1); | |
601 } | |
602 message->buffer[message->length - 1] = '\0'; | |
603 | |
604 #ifdef DEBUG | |
605 printf ("\rReceived: "); | |
606 for (numread=0; numread<message->length - 1; numread++) | |
607 printf ("%x ", message->buffer[numread]); | |
608 printf ("\n"); | |
609 #endif | |
610 | |
611 sshv2_log_command (request, gftp_logging_recv, message->command, | |
612 message->buffer, message->length); | |
613 | |
614 return (message->command); | |
615 } | |
616 | |
617 | |
618 static void | |
619 sshv2_message_free (sshv2_message * message) | |
620 { | |
621 if (message->buffer) | |
622 g_free (message->buffer); | |
623 memset (message, 0, sizeof (*message)); | |
624 } | |
625 | |
626 | |
627 static void | |
628 sshv2_log_command (gftp_request * request, gftp_logging_level level, | |
629 char type, char *message, size_t length) | |
630 { | |
631 gint32 id, num, attr, stattype; | |
632 char *descr, *pos, oldchar; | |
633 sshv2_params * params; | |
634 | |
635 params = request->protocol_data; | |
636 memcpy (&id, message, 4); | |
637 id = ntohl (id); | |
638 switch (type) | |
639 { | |
640 case SSH_FXP_INIT: | |
641 request->logging_function (level, request->user_data, | |
642 _("%d: Protocol Initialization\n"), id); | |
643 break; | |
644 case SSH_FXP_VERSION: | |
645 memcpy (&num, message, 4); | |
646 num = ntohl (num); | |
647 request->logging_function (level, request->user_data, | |
648 _("%d: Protocol version %d\n"), id, num); | |
649 break; | |
650 case SSH_FXP_OPEN: | |
651 memcpy (&num, message + 4, 4); | |
652 num = ntohl (num); | |
653 pos = message + 12 + num - 1; | |
654 oldchar = *pos; | |
655 *pos = '\0'; | |
656 request->logging_function (level, request->user_data, | |
657 _("%d: Open %s\n"), id, message + 8); | |
658 *pos = oldchar; | |
659 break; | |
660 case SSH_FXP_CLOSE: | |
661 request->logging_function (level, request->user_data, | |
662 _("%d: Close\n"), id); | |
663 case SSH_FXP_READ: | |
664 case SSH_FXP_WRITE: | |
665 break; | |
666 case SSH_FXP_OPENDIR: | |
667 request->logging_function (level, request->user_data, | |
668 _("%d: Open Directory %s\n"), id, | |
669 message + 8); | |
670 break; | |
671 case SSH_FXP_READDIR: | |
672 request->logging_function (level, request->user_data, | |
673 _("%d: Read Directory\n"), id); | |
674 break; | |
675 case SSH_FXP_REMOVE: | |
676 request->logging_function (level, request->user_data, | |
677 _("%d: Remove file %s\n"), id, | |
678 message + 8); | |
679 break; | |
680 case SSH_FXP_MKDIR: | |
681 request->logging_function (level, request->user_data, | |
682 _("%d: Make directory %s\n"), id, | |
683 message + 8); | |
684 break; | |
685 case SSH_FXP_RMDIR: | |
686 request->logging_function (level, request->user_data, | |
687 _("%d: Remove directory %s\n"), id, | |
688 message + 8); | |
689 break; | |
690 case SSH_FXP_REALPATH: | |
691 request->logging_function (level, request->user_data, | |
692 _("%d: Realpath %s\n"), id, | |
693 message + 8); | |
694 break; | |
695 case SSH_FXP_ATTRS: | |
696 request->logging_function (level, request->user_data, | |
697 _("%d: File attributes\n"), id); | |
698 break; | |
699 case SSH_FXP_STAT: | |
700 request->logging_function (level, request->user_data, | |
701 _("%d: Stat %s\n"), id, | |
702 message + 8); | |
703 break; | |
704 case SSH_FXP_SETSTAT: | |
705 memcpy (&num, message + 4, 4); | |
706 num = ntohl (num); | |
707 pos = message + 12 + num - 1; | |
708 oldchar = *pos; | |
709 *pos = '\0'; | |
710 memcpy (&stattype, message + 8 + num, 4); | |
711 stattype = ntohl (stattype); | |
712 memcpy (&attr, message + 12 + num, 4); | |
713 attr = ntohl (attr); | |
714 switch (stattype) | |
715 { | |
716 case SSH_FILEXFER_ATTR_PERMISSIONS: | |
717 request->logging_function (level, request->user_data, | |
718 _("%d: Chmod %s %o\n"), id, | |
719 message + 8, attr); | |
720 break; | |
721 case SSH_FILEXFER_ATTR_ACMODTIME: | |
722 request->logging_function (level, request->user_data, | |
723 _("%d: Utime %s %d\n"), id, | |
724 message + 8, attr); | |
725 } | |
726 *pos = oldchar; | |
727 break; | |
728 case SSH_FXP_STATUS: | |
729 if (params->dont_log_status) | |
730 break; | |
731 memcpy (&num, message + 4, 4); | |
732 num = ntohl (num); | |
733 switch (num) | |
734 { | |
735 case SSH_FX_OK: | |
736 descr = _("OK"); | |
737 break; | |
738 case SSH_FX_EOF: | |
739 descr = _("EOF"); | |
740 break; | |
741 case SSH_FX_NO_SUCH_FILE: | |
742 descr = _("No such file or directory"); | |
743 break; | |
744 case SSH_FX_PERMISSION_DENIED: | |
745 descr = _("Permission denied"); | |
746 break; | |
747 case SSH_FX_FAILURE: | |
748 descr = _("Failure"); | |
749 break; | |
750 case SSH_FX_BAD_MESSAGE: | |
751 descr = _("Bad message"); | |
752 break; | |
753 case SSH_FX_NO_CONNECTION: | |
754 descr = _("No connection"); | |
755 break; | |
756 case SSH_FX_CONNECTION_LOST: | |
757 descr = _("Connection lost"); | |
758 break; | |
759 case SSH_FX_OP_UNSUPPORTED: | |
760 descr = _("Operation unsupported"); | |
761 break; | |
762 default: | |
763 descr = _("Unknown message returned from server"); | |
764 break; | |
765 } | |
766 request->logging_function (level, request->user_data, | |
767 "%d: %s\n", id, descr); | |
768 break; | |
769 case SSH_FXP_HANDLE: | |
770 request->logging_function (level, request->user_data, | |
771 "%d: File handle\n", id); | |
772 break; | |
773 case SSH_FXP_DATA: | |
774 break; | |
775 case SSH_FXP_NAME: | |
776 memcpy (&num, message + 4, 4); | |
777 num = ntohl (num); | |
778 request->logging_function (level, request->user_data, | |
779 "%d: Filenames (%d entries)\n", id, | |
780 num); | |
781 break; | |
782 default: | |
783 request->logging_function (level, request->user_data, | |
784 "Command: %x\n", type); | |
785 } | |
786 } | |
787 | |
788 | |
789 static int | |
790 sshv2_end_transfer (gftp_request * request) | |
791 { | |
792 sshv2_params * params; | |
793 sshv2_message message; | |
794 gint32 len; | |
795 | |
796 g_return_val_if_fail (request != NULL, -2); | |
797 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
798 | |
799 params = request->protocol_data; | |
800 if (params->message.buffer != NULL) | |
801 { | |
802 sshv2_message_free (¶ms->message); | |
803 params->count = 0; | |
804 } | |
805 | |
806 if (params->handle_len > 0) | |
807 { | |
808 len = htonl (params->id++); | |
809 memcpy (params->handle, &len, 4); | |
810 | |
811 if (sshv2_send_command (request, SSH_FXP_CLOSE, params->handle, | |
812 params->handle_len) < 0) | |
813 return (-2); | |
814 | |
815 memset (&message, 0, sizeof (message)); | |
816 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_STATUS) | |
817 { | |
818 request->logging_function (gftp_logging_error, request->user_data, | |
819 _("Received wrong response from server, disconnecting\n")); | |
820 sshv2_message_free (&message); | |
821 gftp_disconnect (request); | |
822 return (-2); | |
823 } | |
824 sshv2_message_free (&message); | |
825 params->handle_len = 0; | |
826 } | |
827 | |
828 if (params->read_buffer != NULL) | |
829 { | |
830 g_free (params->read_buffer); | |
831 params->read_buffer = NULL; | |
832 } | |
833 | |
834 return (0); | |
835 } | |
836 | |
837 | |
838 static int | |
839 sshv2_list_files (gftp_request * request) | |
840 { | |
841 sshv2_params * params; | |
842 sshv2_message message; | |
843 char *tempstr; | |
844 gint32 len; | |
845 | |
846 g_return_val_if_fail (request != NULL, -2); | |
847 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
848 g_return_val_if_fail (request->sockfd != NULL, -2); | |
849 | |
850 params = request->protocol_data; | |
851 | |
852 request->logging_function (gftp_logging_misc, request->user_data, | |
853 _("Retrieving directory listing...\n")); | |
854 | |
855 tempstr = g_malloc (strlen (request->directory) + 9); | |
856 | |
857 len = htonl (params->id++); | |
858 memcpy (tempstr, &len, 4); | |
859 | |
860 len = htonl (strlen (request->directory)); | |
861 memcpy (tempstr + 4, &len, 4); | |
862 strcpy (tempstr + 8, request->directory); | |
863 if (sshv2_send_command (request, SSH_FXP_OPENDIR, tempstr, | |
864 strlen (request->directory) + 8) < 0) | |
865 { | |
866 g_free (tempstr); | |
867 return (-2); | |
868 } | |
869 g_free (tempstr); | |
870 | |
871 memset (&message, 0, sizeof (message)); | |
872 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE) | |
873 { | |
874 request->logging_function (gftp_logging_error, request->user_data, | |
875 _("Received wrong response from server, disconnecting\n")); | |
876 sshv2_message_free (&message); | |
877 gftp_disconnect (request); | |
878 return (-2); | |
879 } | |
880 | |
881 if (message.length - 4 > SSH_MAX_HANDLE_SIZE) | |
882 { | |
883 request->logging_function (gftp_logging_error, request->user_data, | |
884 _("Error: Message size %d too big from server\n"), | |
885 message.length - 4); | |
886 sshv2_message_free (&message); | |
887 gftp_disconnect (request); | |
888 return (-1); | |
889 | |
890 } | |
891 | |
892 memset (params->handle, 0, 4); | |
893 memcpy (params->handle + 4, message.buffer + 4, message.length - 5); | |
894 params->handle_len = message.length - 1; | |
895 sshv2_message_free (&message); | |
896 params->count = 0; | |
897 return (0); | |
898 } | |
899 | |
900 | |
901 static int | |
902 sshv2_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd) | |
903 { | |
904 gint32 len, attrs, longnamelen; | |
905 int ret, i, count, retsize; | |
906 sshv2_params *params; | |
907 char *longname; | |
908 | |
909 g_return_val_if_fail (request != NULL, -2); | |
910 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
911 g_return_val_if_fail (fle != NULL, -2); | |
912 | |
913 params = request->protocol_data; | |
914 | |
915 if (request->last_dir_entry) | |
916 { | |
917 g_free (request->last_dir_entry); | |
918 request->last_dir_entry = NULL; | |
919 request->last_dir_entry_len = 0; | |
920 } | |
921 retsize = 0; | |
922 | |
923 if (params->count > 0) | |
924 ret = SSH_FXP_NAME; | |
925 else | |
926 { | |
927 if (!request->cached) | |
928 { | |
929 if (params->message.buffer != NULL) | |
930 sshv2_message_free (¶ms->message); | |
931 | |
932 len = htonl (params->id++); | |
933 memcpy (params->handle, &len, 4); | |
934 | |
935 if (sshv2_send_command (request, SSH_FXP_READDIR, params->handle, | |
936 params->handle_len) < 0) | |
937 return (-2); | |
938 } | |
939 | |
940 if ((ret = sshv2_read_response (request, ¶ms->message, fd)) < 0) | |
941 return (-2); | |
942 | |
943 if (!request->cached) | |
944 { | |
945 request->last_dir_entry = g_malloc (params->message.length + 4); | |
946 len = htonl (params->message.length); | |
947 memcpy (request->last_dir_entry, &len, 4); | |
948 request->last_dir_entry[4] = params->message.command; | |
949 memcpy (request->last_dir_entry + 5, params->message.buffer, | |
950 params->message.length - 1); | |
951 request->last_dir_entry_len = params->message.length + 4; | |
952 } | |
953 | |
954 if (ret == SSH_FXP_NAME) | |
955 { | |
956 params->message.pos = params->message.buffer + 4; | |
957 if ((params->count = sshv2_buffer_get_int32 (request, | |
958 ¶ms->message, -1)) < 0) | |
959 return (-2); | |
960 } | |
961 } | |
962 | |
963 if (ret == SSH_FXP_NAME) | |
964 { | |
965 if ((len = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0 || | |
966 params->message.pos + len > params->message.end) | |
967 return (-2); | |
968 | |
969 params->message.pos += len; | |
970 | |
971 if ((longnamelen = sshv2_buffer_get_int32 (request, | |
972 ¶ms->message, -1)) < 0 || | |
973 params->message.pos + longnamelen > params->message.end) | |
974 return (-2); | |
975 | |
976 longname = params->message.pos; | |
977 params->message.pos += longnamelen; | |
978 | |
979 if ((attrs = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
980 return (-2); | |
981 | |
982 if (attrs & SSH_FILEXFER_ATTR_SIZE) | |
983 { | |
984 params->message.pos += 8; | |
985 if (params->message.pos > params->message.end) | |
986 { | |
987 request->logging_function (gftp_logging_error, request->user_data, | |
988 _("Received wrong response from server, disconnecting\n")); | |
989 sshv2_message_free (¶ms->message); | |
990 gftp_disconnect (request); | |
991 return (-2); | |
992 } | |
993 } | |
994 | |
995 if (attrs & SSH_FILEXFER_ATTR_UIDGID) | |
996 { | |
997 params->message.pos += 8; | |
998 if (params->message.pos > params->message.end) | |
999 { | |
1000 request->logging_function (gftp_logging_error, request->user_data, | |
1001 _("Received wrong response from server, disconnecting\n")); | |
1002 sshv2_message_free (¶ms->message); | |
1003 gftp_disconnect (request); | |
1004 return (-2); | |
1005 } | |
1006 } | |
1007 | |
1008 if (attrs & SSH_FILEXFER_ATTR_PERMISSIONS) | |
1009 { | |
1010 params->message.pos += 4; | |
1011 if (params->message.pos > params->message.end) | |
1012 { | |
1013 request->logging_function (gftp_logging_error, request->user_data, | |
1014 _("Received wrong response from server, disconnecting\n")); | |
1015 sshv2_message_free (¶ms->message); | |
1016 gftp_disconnect (request); | |
1017 return (-2); | |
1018 } | |
1019 } | |
1020 | |
1021 if (attrs & SSH_FILEXFER_ATTR_ACMODTIME) | |
1022 { | |
1023 params->message.pos += 8; | |
1024 if (params->message.pos > params->message.end) | |
1025 { | |
1026 request->logging_function (gftp_logging_error, request->user_data, | |
1027 _("Received wrong response from server, disconnecting\n")); | |
1028 sshv2_message_free (¶ms->message); | |
1029 gftp_disconnect (request); | |
1030 return (-2); | |
1031 } | |
1032 } | |
1033 | |
1034 if (attrs & SSH_FILEXFER_ATTR_EXTENDED) | |
1035 { | |
1036 if ((count = sshv2_buffer_get_int32 (request, | |
1037 ¶ms->message, -1)) < 0) | |
1038 return (-2); | |
1039 | |
1040 for (i=0; i<count; i++) | |
1041 { | |
1042 if ((len = sshv2_buffer_get_int32 (request, | |
1043 ¶ms->message, -1)) < 0 || | |
1044 params->message.pos + len + 4 > params->message.end) | |
1045 return (-2); | |
1046 | |
1047 params->message.pos += len + 4; | |
1048 | |
1049 if ((len = sshv2_buffer_get_int32 (request, | |
1050 ¶ms->message, -1)) < 0 || | |
1051 params->message.pos + len + 4 > params->message.end) | |
1052 return (-2); | |
1053 | |
1054 params->message.pos += len + 4; | |
1055 } | |
1056 } | |
1057 | |
1058 longname[longnamelen] = '\0'; | |
1059 | |
1060 /* The commercial SSH2 puts a / and * after some entries */ | |
1061 if (longname[longnamelen - 1] == '*') | |
1062 longname[--longnamelen] = '\0'; | |
1063 if (longname[longnamelen - 1] == '/') | |
1064 longname[--longnamelen] = '\0'; | |
1065 | |
1066 if (gftp_parse_ls (longname, fle) != 0) | |
1067 { | |
1068 gftp_file_destroy (fle); | |
1069 return (-2); | |
1070 } | |
1071 retsize = strlen (longname); | |
1072 | |
1073 params->count--; | |
1074 } | |
1075 else if (ret == SSH_FXP_STATUS) | |
1076 { | |
1077 sshv2_message_free (¶ms->message); | |
1078 return (0); | |
1079 } | |
1080 else | |
1081 { | |
1082 request->logging_function (gftp_logging_error, request->user_data, | |
1083 _("Received wrong response from server, disconnecting\n")); | |
1084 sshv2_message_free (¶ms->message); | |
1085 gftp_disconnect (request); | |
1086 return (-2); | |
1087 } | |
1088 | |
1089 return (retsize); | |
1090 } | |
1091 | |
1092 | |
1093 static int | |
1094 sshv2_chdir (gftp_request * request, const char *directory) | |
1095 { | |
1096 sshv2_message message; | |
1097 sshv2_params * params; | |
1098 char *tempstr, *dir; | |
1099 gint32 num; | |
1100 size_t len; | |
1101 | |
1102 g_return_val_if_fail (request != NULL, -2); | |
1103 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1104 | |
1105 params = request->protocol_data; | |
1106 if (request->directory != directory) | |
1107 { | |
1108 if (*directory == '/') | |
1109 { | |
1110 len = strlen (directory) + 8; | |
1111 tempstr = g_malloc (len + 1); | |
1112 strcpy (tempstr + 8, directory); | |
1113 } | |
1114 else | |
1115 { | |
1116 len = strlen (directory) + strlen (request->directory) + 9; | |
1117 tempstr = g_malloc (len + 1); | |
1118 strcpy (tempstr + 8, request->directory); | |
1119 strcat (tempstr + 8, "/"); | |
1120 strcat (tempstr + 8, directory); | |
1121 } | |
1122 | |
1123 num = htonl (params->id++); | |
1124 memcpy (tempstr, &num, 4); | |
1125 | |
1126 num = htonl (len - 8); | |
1127 memcpy (tempstr + 4, &num, 4); | |
1128 if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len) < 0) | |
1129 { | |
1130 g_free (tempstr); | |
1131 return (-2); | |
1132 } | |
1133 g_free (tempstr); | |
1134 | |
1135 memset (&message, 0, sizeof (message)); | |
1136 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_NAME) | |
1137 { | |
1138 request->logging_function (gftp_logging_error, request->user_data, | |
1139 _("Received wrong response from server, disconnecting\n")); | |
1140 sshv2_message_free (&message); | |
1141 gftp_disconnect (request); | |
1142 return (-2); | |
1143 } | |
1144 | |
1145 message.pos += 4; | |
1146 if (sshv2_buffer_get_int32 (request, &message, 1) != 1) | |
1147 return (-2); | |
1148 | |
1149 if ((dir = sshv2_buffer_get_string (request, &message)) == NULL) | |
1150 return (-2); | |
1151 | |
1152 if (request->directory) | |
1153 g_free (request->directory); | |
1154 request->directory = dir; | |
1155 sshv2_message_free (&message); | |
1156 } | |
1157 | |
1158 return (0); | |
1159 } | |
1160 | |
1161 | |
1162 static int | |
1163 sshv2_getcwd (gftp_request * request) | |
1164 { | |
1165 sshv2_message message; | |
1166 sshv2_params * params; | |
1167 char *tempstr, *dir; | |
1168 gint32 num; | |
1169 size_t len; | |
1170 | |
1171 g_return_val_if_fail (request != NULL, -2); | |
1172 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1173 | |
1174 if (request->directory == NULL || *request->directory == '\0') | |
1175 dir = "."; | |
1176 else | |
1177 dir = request->directory; | |
1178 | |
1179 params = request->protocol_data; | |
1180 len = strlen (dir); | |
1181 tempstr = g_malloc (len + 9); | |
1182 strcpy (tempstr + 8, dir); | |
1183 | |
1184 num = htonl (params->id++); | |
1185 memcpy (tempstr, &num, 4); | |
1186 | |
1187 num = htonl (len); | |
1188 memcpy (tempstr + 4, &num, 4); | |
1189 if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len + 8) < 0) | |
1190 { | |
1191 g_free (tempstr); | |
1192 return (-2); | |
1193 } | |
1194 | |
1195 g_free (tempstr); | |
1196 if (request->directory) | |
1197 { | |
1198 g_free (request->directory); | |
1199 request->directory = NULL; | |
1200 } | |
1201 | |
1202 memset (&message, 0, sizeof (message)); | |
1203 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_NAME) | |
1204 { | |
1205 request->logging_function (gftp_logging_error, request->user_data, | |
1206 _("Received wrong response from server, disconnecting\n")); | |
1207 sshv2_message_free (&message); | |
1208 gftp_disconnect (request); | |
1209 return (-2); | |
1210 } | |
1211 | |
1212 message.pos += 4; | |
1213 if (sshv2_buffer_get_int32 (request, &message, 1) < 0) | |
1214 return (-2); | |
1215 | |
1216 if ((request->directory = sshv2_buffer_get_string (request, &message)) == NULL) | |
1217 return (-2); | |
1218 sshv2_message_free (&message); | |
1219 return (0); | |
1220 } | |
1221 | |
1222 | |
1223 static int | |
1224 sshv2_rmdir (gftp_request * request, const char *directory) | |
1225 { | |
1226 sshv2_params * params; | |
1227 sshv2_message message; | |
1228 char *tempstr; | |
1229 gint32 num; | |
1230 size_t len; | |
1231 | |
1232 g_return_val_if_fail (request != NULL, -2); | |
1233 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1234 g_return_val_if_fail (directory != NULL, -2); | |
1235 | |
1236 params = request->protocol_data; | |
1237 | |
1238 if (*directory == '/') | |
1239 { | |
1240 len = strlen (directory) + 8; | |
1241 tempstr = g_malloc (len + 1); | |
1242 strcpy (tempstr + 8, directory); | |
1243 } | |
1244 else | |
1245 { | |
1246 len = strlen (directory) + strlen (request->directory) + 9; | |
1247 tempstr = g_malloc (len + 1); | |
1248 strcpy (tempstr + 8, request->directory); | |
1249 strcat (tempstr + 8, "/"); | |
1250 strcat (tempstr + 8, directory); | |
1251 } | |
1252 | |
1253 num = htonl (params->id++); | |
1254 memcpy (tempstr, &num, 4); | |
1255 | |
1256 num = htonl (len - 8); | |
1257 memcpy (tempstr + 4, &num, 4); | |
1258 | |
1259 if (sshv2_send_command (request, SSH_FXP_RMDIR, tempstr, len) < 0) | |
1260 { | |
1261 g_free (tempstr); | |
1262 return (-2); | |
1263 } | |
1264 g_free (tempstr); | |
1265 | |
1266 memset (&message, 0, sizeof (message)); | |
1267 if (sshv2_read_response (request, &message, NULL) < 0) | |
1268 return (-2); | |
1269 | |
1270 message.pos += 4; | |
1271 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1272 return (-2); | |
1273 | |
1274 sshv2_message_free (&message); | |
1275 | |
1276 return (0); | |
1277 } | |
1278 | |
1279 | |
1280 static int | |
1281 sshv2_rmfile (gftp_request * request, const char *file) | |
1282 { | |
1283 sshv2_params * params; | |
1284 sshv2_message message; | |
1285 char *tempstr; | |
1286 gint32 num; | |
1287 size_t len; | |
1288 | |
1289 g_return_val_if_fail (request != NULL, -2); | |
1290 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1291 g_return_val_if_fail (file != NULL, -2); | |
1292 | |
1293 params = request->protocol_data; | |
1294 | |
1295 if (*file == '/') | |
1296 { | |
1297 len = strlen (file) + 8; | |
1298 tempstr = g_malloc (len + 1); | |
1299 strcpy (tempstr + 8, file); | |
1300 } | |
1301 else | |
1302 { | |
1303 len = strlen (file) + strlen (request->directory) + 9; | |
1304 tempstr = g_malloc (len + 1); | |
1305 strcpy (tempstr + 8, request->directory); | |
1306 strcat (tempstr + 8, "/"); | |
1307 strcat (tempstr + 8, file); | |
1308 } | |
1309 | |
1310 num = htonl (params->id++); | |
1311 memcpy (tempstr, &num, 4); | |
1312 | |
1313 num = htonl (len - 8); | |
1314 memcpy (tempstr + 4, &num, 4); | |
1315 | |
1316 if (sshv2_send_command (request, SSH_FXP_REMOVE, tempstr, len) < 0) | |
1317 { | |
1318 g_free (tempstr); | |
1319 return (-2); | |
1320 } | |
1321 g_free (tempstr); | |
1322 | |
1323 memset (&message, 0, sizeof (message)); | |
1324 if (sshv2_read_response (request, &message, NULL) < 0) | |
1325 return (-2); | |
1326 | |
1327 message.pos += 4; | |
1328 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1329 return (-2); | |
1330 | |
1331 sshv2_message_free (&message); | |
1332 | |
1333 return (0); | |
1334 } | |
1335 | |
1336 | |
1337 static int | |
1338 sshv2_chmod (gftp_request * request, const char *file, int mode) | |
1339 { | |
1340 char *tempstr, buf[10]; | |
1341 sshv2_params * params; | |
1342 sshv2_message message; | |
1343 gint32 num; | |
1344 size_t len; | |
1345 | |
1346 g_return_val_if_fail (request != NULL, -2); | |
1347 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1348 g_return_val_if_fail (file != NULL, -2); | |
1349 | |
1350 params = request->protocol_data; | |
1351 | |
1352 if (*file == '/') | |
1353 { | |
1354 len = strlen (file) + 16; | |
1355 tempstr = g_malloc (len + 1); | |
1356 strcpy (tempstr + 8, file); | |
1357 } | |
1358 else | |
1359 { | |
1360 len = strlen (file) + strlen (request->directory) + 17; | |
1361 tempstr = g_malloc (len + 1); | |
1362 strcpy (tempstr + 8, request->directory); | |
1363 strcat (tempstr + 8, "/"); | |
1364 strcat (tempstr + 8, file); | |
1365 } | |
1366 | |
1367 num = htonl (params->id++); | |
1368 memcpy (tempstr, &num, 4); | |
1369 | |
1370 num = htonl (len - 16); | |
1371 memcpy (tempstr + 4, &num, 4); | |
1372 | |
1373 num = htonl (SSH_FILEXFER_ATTR_PERMISSIONS); | |
1374 memcpy (tempstr + len - 8, &num, 4); | |
1375 | |
1376 g_snprintf (buf, sizeof (buf), "%d", mode); | |
1377 num = htonl (strtol (buf, NULL, 8)); | |
1378 memcpy (tempstr + len - 4, &num, 4); | |
1379 | |
1380 if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0) | |
1381 { | |
1382 g_free (tempstr); | |
1383 return (-2); | |
1384 } | |
1385 g_free (tempstr); | |
1386 | |
1387 memset (&message, 0, sizeof (message)); | |
1388 if (sshv2_read_response (request, &message, NULL) < 0) | |
1389 return (-2); | |
1390 | |
1391 message.pos += 4; | |
1392 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1393 return (-2); | |
1394 | |
1395 sshv2_message_free (&message); | |
1396 | |
1397 return (0); | |
1398 } | |
1399 | |
1400 | |
1401 static int | |
1402 sshv2_mkdir (gftp_request * request, const char *newdir) | |
1403 { | |
1404 sshv2_params * params; | |
1405 sshv2_message message; | |
1406 char *tempstr; | |
1407 gint32 num; | |
1408 size_t len; | |
1409 | |
1410 g_return_val_if_fail (request != NULL, -2); | |
1411 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1412 g_return_val_if_fail (newdir != NULL, -2); | |
1413 | |
1414 params = request->protocol_data; | |
1415 | |
1416 if (*newdir == '/') | |
1417 { | |
1418 len = strlen (newdir) + 12; | |
1419 tempstr = g_malloc (len + 1); | |
1420 strcpy (tempstr + 8, newdir); | |
1421 } | |
1422 else | |
1423 { | |
1424 len = strlen (newdir) + strlen (request->directory) + 13; | |
1425 tempstr = g_malloc (len + 1); | |
1426 strcpy (tempstr + 8, request->directory); | |
1427 strcat (tempstr + 8, "/"); | |
1428 strcat (tempstr + 8, newdir); | |
1429 } | |
1430 | |
1431 num = htonl (params->id++); | |
1432 memcpy (tempstr, &num, 4); | |
1433 | |
1434 num = htonl (len - 12); | |
1435 memcpy (tempstr + 4, &num, 4); | |
1436 memset (tempstr + len - 4, 0, 4); /* attributes */ | |
1437 | |
1438 if (sshv2_send_command (request, SSH_FXP_MKDIR, tempstr, len) < 0) | |
1439 { | |
1440 g_free (tempstr); | |
1441 return (-2); | |
1442 } | |
1443 g_free (tempstr); | |
1444 | |
1445 memset (&message, 0, sizeof (message)); | |
1446 if (sshv2_read_response (request, &message, NULL) < 0) | |
1447 return (-2); | |
1448 | |
1449 message.pos += 4; | |
1450 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1451 return (-2); | |
1452 | |
1453 sshv2_message_free (&message); | |
1454 | |
1455 return (0); | |
1456 } | |
1457 | |
1458 | |
1459 static int | |
1460 sshv2_rename (gftp_request * request, const char *oldname, const char *newname) | |
1461 { | |
1462 char *tempstr, *oldstr, *newstr; | |
1463 sshv2_params * params; | |
1464 sshv2_message message; | |
1465 gint32 num; | |
1466 size_t oldlen, newlen; | |
1467 | |
1468 g_return_val_if_fail (request != NULL, -2); | |
1469 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1470 g_return_val_if_fail (oldname != NULL, -2); | |
1471 g_return_val_if_fail (newname != NULL, -2); | |
1472 | |
1473 params = request->protocol_data; | |
1474 | |
1475 if (*oldname == '/') | |
1476 { | |
1477 oldlen = strlen (oldname); | |
1478 oldstr = g_strconcat (oldname, NULL); | |
1479 } | |
1480 else | |
1481 { | |
1482 oldlen = strlen (request->directory) + strlen (oldname) + 1; | |
1483 oldstr = g_strconcat (request->directory, "/", oldname, NULL); | |
1484 } | |
1485 | |
1486 if (*newname == '/') | |
1487 { | |
1488 newlen = strlen (newname); | |
1489 newstr = g_strconcat (newname, NULL); | |
1490 } | |
1491 else | |
1492 { | |
1493 newlen = strlen (request->directory) + strlen (newname) + 1; | |
1494 newstr = g_strconcat (request->directory, "/", newname, NULL); | |
1495 } | |
1496 | |
1497 tempstr = g_malloc (oldlen + newlen + 13); | |
1498 num = htonl (params->id++); | |
1499 memcpy (tempstr, &num, 4); | |
1500 | |
1501 num = htonl (oldlen); | |
1502 memcpy (tempstr + 4, &num, 4); | |
1503 strcpy (tempstr + 8, oldstr); | |
1504 | |
1505 num = htonl (newlen); | |
1506 memcpy (tempstr + 8 + oldlen, &num, 4); | |
1507 strcpy (tempstr + 12 + oldlen, newstr); | |
1508 | |
1509 if (sshv2_send_command (request, SSH_FXP_RENAME, tempstr, oldlen + newlen + 12) < 0) | |
1510 { | |
1511 g_free (tempstr); | |
1512 return (-2); | |
1513 } | |
1514 g_free (tempstr); | |
1515 | |
1516 memset (&message, 0, sizeof (message)); | |
1517 if (sshv2_read_response (request, &message, NULL) < 0) | |
1518 return (-2); | |
1519 | |
1520 message.pos += 4; | |
1521 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1522 return (-2); | |
1523 | |
1524 sshv2_message_free (&message); | |
1525 | |
1526 return (0); | |
1527 } | |
1528 | |
1529 | |
1530 static int | |
1531 sshv2_set_file_time (gftp_request * request, const char *file, time_t datetime) | |
1532 { | |
1533 sshv2_params * params; | |
1534 sshv2_message message; | |
1535 char *tempstr; | |
1536 gint32 num; | |
1537 size_t len; | |
1538 | |
1539 g_return_val_if_fail (request != NULL, -2); | |
1540 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1541 g_return_val_if_fail (file != NULL, -2); | |
1542 | |
1543 params = request->protocol_data; | |
1544 | |
1545 if (*file == '/') | |
1546 { | |
1547 len = strlen (file) + 20; | |
1548 tempstr = g_malloc (len + 1); | |
1549 strcpy (tempstr + 8, file); | |
1550 } | |
1551 else | |
1552 { | |
1553 len = strlen (file) + strlen (request->directory) + 21; | |
1554 tempstr = g_malloc (len + 1); | |
1555 strcpy (tempstr + 8, request->directory); | |
1556 strcat (tempstr + 8, "/"); | |
1557 strcat (tempstr + 8, file); | |
1558 } | |
1559 | |
1560 num = htonl (params->id++); | |
1561 memcpy (tempstr, &num, 4); | |
1562 | |
1563 num = htonl (len - 20); | |
1564 memcpy (tempstr + 4, &num, 4); | |
1565 | |
1566 num = htonl (SSH_FILEXFER_ATTR_ACMODTIME); | |
1567 memcpy (tempstr + len - 12, &num, 4); | |
1568 | |
1569 num = htonl (datetime); | |
1570 memcpy (tempstr + len - 8, &num, 4); | |
1571 | |
1572 num = htonl (datetime); | |
1573 memcpy (tempstr + len - 4, &num, 4); | |
1574 | |
1575 if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0) | |
1576 { | |
1577 g_free (tempstr); | |
1578 return (-2); | |
1579 } | |
1580 g_free (tempstr); | |
1581 | |
1582 memset (&message, 0, sizeof (message)); | |
1583 if (sshv2_read_response (request, &message, NULL) < 0) | |
1584 return (-2); | |
1585 | |
1586 message.pos += 4; | |
1587 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0) | |
1588 return (-2); | |
1589 | |
1590 sshv2_message_free (&message); | |
1591 | |
1592 return (0); | |
1593 } | |
1594 | |
1595 | |
1596 static off_t | |
1597 sshv2_get_file_size (gftp_request * request, const char *file) | |
1598 { | |
1599 gint32 len, highnum, lownum, attrs, num; | |
1600 sshv2_params * params; | |
1601 char *tempstr; | |
1602 #ifdef G_HAVE_GINT64 | |
1603 gint64 ret; | |
1604 #endif | |
1605 | |
1606 g_return_val_if_fail (request != NULL, -2); | |
1607 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1608 g_return_val_if_fail (file != NULL, -2); | |
1609 | |
1610 params = request->protocol_data; | |
1611 | |
1612 if (*file == '/') | |
1613 { | |
1614 len = strlen (file); | |
1615 tempstr = g_malloc (len + 9); | |
1616 strcpy (tempstr + 8, file); | |
1617 } | |
1618 else | |
1619 { | |
1620 len = strlen (file) + strlen (request->directory) + 1; | |
1621 tempstr = g_malloc (len + 9); | |
1622 strcpy (tempstr + 8, request->directory); | |
1623 strcat (tempstr + 8, "/"); | |
1624 strcat (tempstr + 8, file); | |
1625 } | |
1626 | |
1627 num = htonl (params->id++); | |
1628 memcpy (tempstr, &num, 4); | |
1629 | |
1630 num = htonl (len); | |
1631 memcpy (tempstr + 4, &num, 4); | |
1632 | |
1633 if (sshv2_send_command (request, SSH_FXP_STAT, tempstr, len + 8) < 0) | |
1634 { | |
1635 g_free (tempstr); | |
1636 return (-2); | |
1637 } | |
1638 g_free (tempstr); | |
1639 | |
1640 memset (¶ms->message, 0, sizeof (params->message)); | |
1641 if (sshv2_read_response (request, ¶ms->message, NULL) != SSH_FXP_ATTRS) | |
1642 { | |
1643 request->logging_function (gftp_logging_error, request->user_data, | |
1644 _("Received wrong response from server, disconnecting\n")); | |
1645 sshv2_message_free (¶ms->message); | |
1646 gftp_disconnect (request); | |
1647 return (-2); | |
1648 } | |
1649 | |
1650 if (params->message.length < 5) | |
1651 return (-2); | |
1652 params->message.pos += 4; | |
1653 | |
1654 if ((attrs = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
1655 return (-2); | |
1656 | |
1657 if (attrs & SSH_FILEXFER_ATTR_SIZE) | |
1658 { | |
1659 if ((highnum = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
1660 return (-2); | |
1661 | |
1662 if ((lownum = sshv2_buffer_get_int32 (request, ¶ms->message, -1)) < 0) | |
1663 return (-2); | |
1664 | |
1665 sshv2_message_free (¶ms->message); | |
1666 | |
1667 #if G_HAVE_GINT64 | |
1668 ret = (gint64) lownum | ((gint64) highnum >> 32); | |
1669 return (ret); | |
1670 #else | |
1671 return (lownum); | |
1672 #endif | |
1673 } | |
1674 | |
1675 sshv2_message_free (¶ms->message); | |
1676 | |
1677 return (0); | |
1678 | |
1679 } | |
1680 | |
1681 | |
1682 static long | |
1683 sshv2_get_file (gftp_request * request, const char *file, FILE * fd, | |
1684 off_t startsize) | |
1685 { | |
1686 sshv2_params * params; | |
1687 sshv2_message message; | |
1688 char *tempstr; | |
1689 size_t stlen; | |
1690 gint32 num; | |
1691 | |
1692 g_return_val_if_fail (request != NULL, -2); | |
1693 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1694 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1695 /* fd ignored for this protocol */ | |
1696 | |
1697 params = request->protocol_data; | |
1698 params->offset = startsize; | |
1699 | |
1700 if (*file == '/') | |
1701 { | |
1702 stlen = strlen (file); | |
1703 tempstr = g_malloc (stlen + 16); | |
1704 strcpy (tempstr + 8, file); | |
1705 } | |
1706 else | |
1707 { | |
1708 stlen = strlen (file) + strlen (request->directory) + 1; | |
1709 tempstr = g_malloc (stlen + 16); | |
1710 strcpy (tempstr + 8, request->directory); | |
1711 strcat (tempstr + 8, "/"); | |
1712 strcat (tempstr + 8, file); | |
1713 } | |
1714 | |
1715 num = htonl (params->id++); | |
1716 memcpy (tempstr, &num, 4); | |
1717 | |
1718 num = htonl (stlen); | |
1719 memcpy (tempstr + 4, &num, 4); | |
1720 | |
1721 num = htonl (SSH_FXF_READ); | |
1722 memcpy (tempstr + 8 + stlen, &num, 4); | |
1723 | |
1724 memset (tempstr + 12 + stlen, 0, 4); | |
1725 | |
1726 if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0) | |
1727 { | |
1728 g_free (tempstr); | |
1729 return (-2); | |
1730 } | |
1731 | |
1732 g_free (tempstr); | |
1733 memset (&message, 0, sizeof (message)); | |
1734 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE) | |
1735 { | |
1736 request->logging_function (gftp_logging_error, request->user_data, | |
1737 _("Received wrong response from server, disconnecting\n")); | |
1738 sshv2_message_free (&message); | |
1739 gftp_disconnect (request); | |
1740 return (-2); | |
1741 } | |
1742 | |
1743 if (message.length - 4 > SSH_MAX_HANDLE_SIZE) | |
1744 { | |
1745 request->logging_function (gftp_logging_error, request->user_data, | |
1746 _("Error: Message size %d too big from server\n"), | |
1747 message.length - 4); | |
1748 sshv2_message_free (&message); | |
1749 gftp_disconnect (request); | |
1750 return (-1); | |
1751 | |
1752 } | |
1753 | |
1754 memset (params->handle, 0, 4); | |
1755 memcpy (params->handle + 4, message.buffer+ 4, message.length - 5); | |
1756 params->handle_len = message.length - 1; | |
1757 sshv2_message_free (&message); | |
1758 | |
1759 return (sshv2_get_file_size (request, file)); | |
1760 } | |
1761 | |
1762 | |
1763 static int | |
1764 sshv2_put_file (gftp_request * request, const char *file, FILE * fd, | |
1765 off_t startsize, off_t totalsize) | |
1766 { | |
1767 sshv2_params * params; | |
1768 sshv2_message message; | |
1769 char *tempstr; | |
1770 size_t stlen; | |
1771 gint32 num; | |
1772 | |
1773 g_return_val_if_fail (request != NULL, -2); | |
1774 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1775 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1776 /* fd ignored for this protocol */ | |
1777 | |
1778 params = request->protocol_data; | |
1779 params->offset = 0; | |
1780 | |
1781 if (*file == '/') | |
1782 { | |
1783 stlen = strlen (file); | |
1784 tempstr = g_malloc (stlen + 16); | |
1785 strcpy (tempstr + 8, file); | |
1786 } | |
1787 else | |
1788 { | |
1789 stlen = strlen (file) + strlen (request->directory) + 1; | |
1790 tempstr = g_malloc (stlen + 16); | |
1791 strcpy (tempstr + 8, request->directory); | |
1792 strcat (tempstr + 8, "/"); | |
1793 strcat (tempstr + 8, file); | |
1794 } | |
1795 | |
1796 num = htonl (params->id++); | |
1797 memcpy (tempstr, &num, 4); | |
1798 | |
1799 num = htonl (stlen); | |
1800 memcpy (tempstr + 4, &num, 4); | |
1801 | |
1802 if (startsize > 0) | |
1803 num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_APPEND); | |
1804 else | |
1805 num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC); | |
1806 memcpy (tempstr + 8 + stlen, &num, 4); | |
1807 | |
1808 memset (tempstr + 12 + stlen, 0, 4); | |
1809 | |
1810 if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0) | |
1811 { | |
1812 g_free (tempstr); | |
1813 return (-2); | |
1814 } | |
1815 | |
1816 g_free (tempstr); | |
1817 memset (&message, 0, sizeof (message)); | |
1818 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE) | |
1819 { | |
1820 request->logging_function (gftp_logging_error, request->user_data, | |
1821 _("Received wrong response from server, disconnecting\n")); | |
1822 sshv2_message_free (&message); | |
1823 gftp_disconnect (request); | |
1824 return (-2); | |
1825 } | |
1826 | |
1827 if (message.length - 4 > SSH_MAX_HANDLE_SIZE) | |
1828 { | |
1829 request->logging_function (gftp_logging_error, request->user_data, | |
1830 _("Error: Message size %d too big from server\n"), | |
1831 message.length - 4); | |
1832 sshv2_message_free (&message); | |
1833 gftp_disconnect (request); | |
1834 return (-1); | |
1835 | |
1836 } | |
1837 | |
1838 memset (params->handle, 0, 4); | |
1839 memcpy (params->handle + 4, message.buffer+ 4, message.length - 5); | |
1840 params->handle_len = message.length - 1; | |
1841 sshv2_message_free (&message); | |
1842 | |
1843 return (0); | |
1844 } | |
1845 | |
1846 | |
1847 static size_t | |
1848 sshv2_get_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1849 { | |
1850 sshv2_params * params; | |
1851 sshv2_message message; | |
1852 gint32 num; | |
1853 | |
1854 #ifdef G_HAVE_GINT64 | |
1855 gint64 offset; | |
1856 #else | |
1857 gint32 offset; | |
1858 #endif | |
1859 | |
1860 g_return_val_if_fail (request != NULL, -2); | |
1861 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1862 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1863 g_return_val_if_fail (buf != NULL, -2); | |
1864 | |
1865 params = request->protocol_data; | |
1866 | |
1867 if (params->read_buffer == NULL) | |
1868 { | |
1869 params->read_buffer = g_malloc (params->handle_len + 12); | |
1870 num = htonl (params->handle_len); | |
1871 memcpy (params->read_buffer, params->handle, params->handle_len); | |
1872 } | |
1873 | |
1874 num = htonl (params->id++); | |
1875 memcpy (params->read_buffer, &num, 4); | |
1876 | |
1877 #ifdef G_HAVE_GINT64 | |
1878 offset = hton64 (params->offset); | |
1879 memcpy (params->read_buffer + params->handle_len, &offset, 8); | |
1880 #else | |
1881 memset (params->read_buffer + params->handle_len, 0, 4); | |
1882 offset = htonl (params->offset); | |
1883 memcpy (params->read_buffer + params->handle_len + 4, &offset, 4); | |
1884 #endif | |
1885 | |
1886 num = htonl (size); | |
1887 memcpy (params->read_buffer + params->handle_len + 8, &num, 4); | |
1888 | |
1889 if (sshv2_send_command (request, SSH_FXP_READ, params->read_buffer, params->handle_len + 12) < 0) | |
1890 return (-2); | |
1891 | |
1892 memset (&message, 0, sizeof (message)); | |
1893 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_DATA) | |
1894 { | |
1895 message.pos += 4; | |
1896 if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0) | |
1897 return (-2); | |
1898 sshv2_message_free (&message); | |
1899 if (num != SSH_FX_EOF) | |
1900 { | |
1901 request->logging_function (gftp_logging_error, request->user_data, | |
1902 _("Received wrong response from server, disconnecting\n")); | |
1903 gftp_disconnect (request); | |
1904 return (-2); | |
1905 } | |
1906 return (0); | |
1907 } | |
1908 | |
1909 memcpy (&num, message.buffer + 4, 4); | |
1910 num = ntohl (num); | |
1911 if (num > size) | |
1912 { | |
1913 request->logging_function (gftp_logging_error, request->user_data, | |
1914 _("Error: Message size %d too big from server\n"), | |
1915 num); | |
1916 sshv2_message_free (&message); | |
1917 gftp_disconnect (request); | |
1918 return (-1); | |
1919 | |
1920 } | |
1921 | |
1922 memcpy (buf, message.buffer + 8, num); | |
1923 sshv2_message_free (&message); | |
1924 params->offset += num; | |
1925 return (num); | |
1926 } | |
1927 | |
1928 | |
1929 static size_t | |
1930 sshv2_put_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1931 { | |
1932 sshv2_params * params; | |
1933 sshv2_message message; | |
1934 char tempstr[32768]; | |
1935 gint32 num; | |
1936 int ret; | |
1937 | |
1938 #ifdef G_HAVE_GINT64 | |
1939 gint64 offset; | |
1940 #else | |
1941 gint32 offset; | |
1942 #endif | |
1943 | |
1944 g_return_val_if_fail (request != NULL, -2); | |
1945 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2); | |
1946 g_return_val_if_fail (request->sockfd != NULL, -2); | |
1947 g_return_val_if_fail (buf != NULL, -2); | |
1948 g_return_val_if_fail (size <= 32500, -2); | |
1949 | |
1950 params = request->protocol_data; | |
1951 | |
1952 num = htonl (params->handle_len); | |
1953 memcpy (tempstr, params->handle, params->handle_len); | |
1954 | |
1955 num = htonl (params->id++); | |
1956 memcpy (tempstr, &num, 4); | |
1957 | |
1958 #ifdef G_HAVE_GINT64 | |
1959 offset = hton64 (params->offset); | |
1960 memcpy (tempstr + params->handle_len, &offset, 8); | |
1961 #else | |
1962 memset (tempstr + params->handle_len, 0, 4); | |
1963 offset = htonl (params->offset); | |
1964 memcpy (tempstr + params->handle_len + 4, &offset, 4); | |
1965 #endif | |
1966 | |
1967 num = htonl (size); | |
1968 memcpy (tempstr + params->handle_len + 8, &num, 4); | |
1969 memcpy (tempstr + params->handle_len + 12, buf, size); | |
1970 | |
1971 if (sshv2_send_command (request, SSH_FXP_WRITE, tempstr, params->handle_len + size + 12) < 0) | |
1972 { | |
1973 g_free (tempstr); | |
1974 return (-2); | |
1975 } | |
1976 | |
1977 memset (&message, 0, sizeof (message)); | |
1978 params->dont_log_status = 1; | |
1979 ret = sshv2_read_response (request, &message, NULL); | |
1980 params->dont_log_status = 0; | |
1981 if (ret != SSH_FXP_STATUS) | |
1982 { | |
1983 request->logging_function (gftp_logging_error, request->user_data, | |
1984 _("Received wrong response from server, disconnecting\n")); | |
1985 sshv2_message_free (&message); | |
1986 gftp_disconnect (request); | |
1987 return (-2); | |
1988 } | |
1989 | |
1990 message.pos += 4; | |
1991 if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0) | |
1992 return (-2); | |
1993 sshv2_message_free (&message); | |
1994 | |
1995 if (num == SSH_FX_EOF) | |
1996 return (0); | |
1997 else if (num != SSH_FX_OK) | |
1998 return (-1); | |
1999 | |
2000 params->offset += size; | |
2001 return (size); | |
2002 } | |
2003 |