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