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