comparison lib/fsp.c @ 661:2e718fba351e

2005-1-16 Brian Masney <masneyb@gftp.org> * lib/fsp.c lib/options.h lib/gftp.h - added support for the FSP protocol (from Radim Kolar <hsn@netmag.cz>). Note, I need to update the build system for gftp to compile properly
author masneyb
date Sun, 16 Jan 2005 15:48:24 +0000
parents
children 2d3ea4db3106
comparison
equal deleted inserted replaced
660:3bf77096052c 661:2e718fba351e
1 /*****************************************************************************/
2 /* fsp.c - functions interfacing with FSP v2 protocol library */
3 /* Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org> */
4 /* Copyright (C) 2004 Radim Kolar <hsn@netmag.cz> */
5 /* */
6 /* This program is free software; you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation; either version 2 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with this program; if not, write to the Free Software */
18 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
19 /*****************************************************************************/
20
21 #include "gftp.h"
22 /* include fsplibrary directly, because FSPLIB it not intergrated to build system yet. */
23 #define FSP_USE_SHAREMEM_AND_SEMOP 1
24 #include "fsplib.c"
25 #include "lock.c"
26
27 static const char cvsid[] = "$Id$";
28
29 typedef struct fsp_protocol_data_tag
30 {
31 FSP_SESSION *fsp;
32 FSP_DIR *dir;
33 FSP_FILE *file;
34 } fsp_protocol_data;
35
36 static void
37 fsp_destroy (gftp_request * request)
38 {
39 g_return_if_fail (request != NULL);
40 g_return_if_fail (request->protonum == GFTP_FSP_NUM);
41 }
42
43 static int
44 fsp_connect (gftp_request * request)
45 {
46 fsp_protocol_data * lpd;
47 intptr_t network_timeout;
48
49 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
50 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
51
52 if(! request->port)
53 request->port = gftp_protocol_default_port (request);
54
55 lpd = request->protocol_data;
56 lpd->fsp=fsp_open_session(request->hostname, request->port, request->password);
57
58 if(lpd->fsp == NULL)
59 return (GFTP_ERETRYABLE);
60 /* set up network timeout */
61 gftp_lookup_request_option (request, "network_timeout", &network_timeout);
62 lpd->fsp->timeout=1000*network_timeout;
63
64 if (!request->directory)
65 request->directory = g_strdup ("/");
66
67 request->datafd = lpd->fsp->fd;
68 return (0);
69 }
70
71 static void
72 fsp_disconnect (gftp_request * request)
73 {
74 fsp_protocol_data * lpd;
75
76 g_return_if_fail (request != NULL);
77 g_return_if_fail (request->protonum == GFTP_FSP_NUM);
78
79 lpd = request->protocol_data;
80 g_return_if_fail (lpd != NULL);
81
82 if(lpd->file)
83 {
84 fsp_fclose(lpd->file);
85 lpd->file=NULL;
86 }
87 fsp_close_session(lpd->fsp);
88 lpd->fsp=NULL;
89 request->datafd = -1;
90 if(lpd->dir)
91 {
92 fsp_closedir(lpd->dir);
93 lpd->dir=NULL;
94 }
95 }
96
97 static off_t
98 fsp_get_file (gftp_request * request, const char *filename, int fd,
99 off_t startsize)
100 {
101 fsp_protocol_data * lpd;
102 off_t size;
103 struct stat sb;
104
105 g_return_val_if_fail (request != NULL,GFTP_EFATAL);
106 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM,GFTP_EFATAL);
107 g_return_val_if_fail (filename != NULL, GFTP_EFATAL);
108
109 lpd = request->protocol_data;
110 g_return_val_if_fail (lpd != NULL,GFTP_EFATAL);
111 g_return_val_if_fail (lpd->fsp != NULL,GFTP_EFATAL);
112
113 /* CHECK: close prev. opened file, is this needed? */
114 if(lpd->file != NULL)
115 {
116 fsp_fclose(lpd->file);
117 lpd->file=NULL;
118 }
119
120 if(fsp_stat(lpd->fsp,filename,&sb))
121 return (GFTP_ERETRYABLE);
122 if(!S_ISREG(sb.st_mode))
123 return (GFTP_ERETRYABLE);
124 lpd->file=fsp_fopen(lpd->fsp,filename,"rb");
125
126 if (fsp_fseek (lpd->file, startsize, SEEK_SET) == -1)
127 {
128 request->logging_function (gftp_logging_error, request,
129 _("Error: Cannot seek on file %s: %s\n"),
130 filename, g_strerror (errno));
131 gftp_disconnect (request);
132 return (GFTP_ERETRYABLE);
133 }
134
135 return (sb.st_size);
136 }
137
138 static ssize_t fsp_read_function(gftp_request *request, void *buf, size_t size,int fd)
139 {
140 fsp_protocol_data * lpd;
141
142 g_return_val_if_fail (request != NULL, -1);
143 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, -1);
144 g_return_val_if_fail (buf != NULL, -1);
145
146 lpd = request->protocol_data;
147 g_return_val_if_fail (lpd != NULL, -1);
148 g_return_val_if_fail (lpd->file != NULL, -1);
149
150 return fsp_fread(buf,1,size,lpd->file);
151 }
152
153 static ssize_t fsp_write_function(gftp_request *request, const char *buf, size_t size,int fd)
154 {
155 fsp_protocol_data * lpd;
156
157 g_return_val_if_fail (request != NULL, -1);
158 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, -1);
159 g_return_val_if_fail (buf != NULL, -1);
160
161 lpd = request->protocol_data;
162 g_return_val_if_fail (lpd != NULL, -1);
163 g_return_val_if_fail (lpd->file != NULL, -1);
164
165 return fsp_fwrite(buf,1,size,lpd->file);
166 }
167
168 static int
169 fsp_put_file (gftp_request * request, const char *filename, int fd,
170 off_t startsize, off_t totalsize)
171 {
172 fsp_protocol_data * lpd;
173 off_t size;
174 struct stat sb;
175
176 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
177 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
178 g_return_val_if_fail (filename != NULL, GFTP_EFATAL);
179
180 lpd = request->protocol_data;
181 g_return_val_if_fail (lpd != NULL,GFTP_EFATAL);
182 g_return_val_if_fail (lpd->fsp != NULL,GFTP_EFATAL);
183
184 if(lpd->file != NULL)
185 {
186 fsp_fclose(lpd->file);
187 lpd->file=NULL;
188 }
189
190 if(fsp_canupload(lpd->fsp,filename))
191 {
192 request->logging_function (gftp_logging_error, request,
193 _("Error: Cannot upload file %s\n"),
194 filename );
195 return (GFTP_ERETRYABLE);
196 }
197
198
199 lpd->file=fsp_fopen(lpd->fsp,filename, "wb");
200 if(lpd->file == NULL)
201 {
202 request->logging_function (gftp_logging_error, request,
203 _("Error: Cannot write to file %s: %s\n"),
204 filename, g_strerror (errno));
205 return (GFTP_ERETRYABLE);
206 }
207
208 if (fsp_fseek (lpd->file, startsize, SEEK_SET) == -1)
209 {
210 request->logging_function (gftp_logging_error, request,
211 _("Error: Cannot seek on file %s: %s\n"),
212 filename, g_strerror (errno));
213 gftp_disconnect (request);
214 return (GFTP_ERETRYABLE);
215 }
216 return (0);
217 }
218
219 static int
220 fsp_end_transfer (gftp_request * request)
221 {
222 fsp_protocol_data * lpd;
223
224 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
225 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
226
227 lpd = request->protocol_data;
228 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
229
230 if (lpd->dir)
231 {
232 fsp_closedir (lpd->dir);
233 lpd->dir = NULL;
234 }
235 if (lpd ->file)
236 {
237 if(fsp_fclose(lpd->file))
238 {
239 lpd -> file = NULL;
240 request->logging_function (gftp_logging_error, request,
241 _("Error: Error closing file: %s\n"),
242 g_strerror (errno));
243 return GFTP_EFATAL;
244 }
245 lpd->file=NULL;
246 }
247
248 return (0);
249 }
250
251 static int
252 fsp_abort_transfer (gftp_request * request)
253 {
254 fsp_protocol_data * lpd;
255
256 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
257 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
258
259 lpd = request->protocol_data;
260 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
261
262 if (lpd->dir)
263 {
264 fsp_closedir (lpd->dir);
265 lpd->dir = NULL;
266 }
267 if (lpd ->file)
268 {
269 if(lpd->file->writing && lpd->file->pos>0)
270 {
271 /* need to cancel upload in progress */
272 lpd->file->writing=0;
273 fsp_install(lpd->fsp,"",0);
274 }
275 /* we can safely ignore file close error on abort */
276 fsp_fclose(lpd->file);
277 lpd->file=NULL;
278 }
279
280 return (0);
281 }
282
283 static int
284 fsp_stat_filename (gftp_request * request, const char *filename,
285 mode_t * mode)
286 {
287 struct stat st;
288 fsp_protocol_data * lpd;
289
290 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
291 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
292 g_return_val_if_fail (filename != NULL, GFTP_EFATAL);
293
294 lpd = request->protocol_data;
295 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
296
297 if (fsp_stat (lpd->fsp,filename, &st) != 0)
298 return (GFTP_ERETRYABLE);
299
300 *mode = st.st_mode;
301 return (0);
302 }
303
304 static int
305 fsp_get_next_file (gftp_request * request, gftp_file * fle, int fd)
306 {
307 fsp_protocol_data *lpd;
308 struct FSP_RDENTRY dirent;
309 struct FSP_RDENTRY *result;
310 char *symlink;
311
312 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
313 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
314 g_return_val_if_fail (fle != NULL, GFTP_EFATAL);
315
316 lpd = request->protocol_data;
317
318 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
319
320 memset (fle, 0, sizeof (*fle));
321
322 result=&dirent;
323
324 if ( fsp_readdir_native (lpd->dir,&dirent,&result))
325 {
326 fsp_closedir (lpd->dir);
327 lpd->dir = NULL;
328 request->logging_function (gftp_logging_error, request,
329 _("Corrupted file listing from FSP server %s\n"),
330 request->directory );
331 return (GFTP_EFATAL);
332 }
333
334 if ( result == NULL)
335 {
336 fsp_closedir (lpd->dir);
337 lpd->dir = NULL;
338 return 0;
339 }
340
341 fle->user = g_strdup (_("unknown"));
342 fle->group = g_strdup (_("unknown"));
343
344 /* turn FSP symlink into normal file */
345 symlink=strchr(dirent.name,'\n');
346 if (symlink)
347 *symlink='\0';
348 fle->file = g_strdup (dirent.name);
349 if (dirent.type==FSP_RDTYPE_DIR)
350 fle->st_mode = S_IFDIR | 0755;
351 else
352 fle->st_mode = S_IFREG | 0644;
353 fle->datetime = dirent.lastmod;
354 fle->size = dirent.size;
355 return (1);
356 }
357
358 static int
359 fsp_list_files (gftp_request * request)
360 {
361 fsp_protocol_data *lpd;
362
363 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
364 g_return_val_if_fail (request->directory != NULL, GFTP_EFATAL);
365 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
366
367 lpd = request->protocol_data;
368
369 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
370
371 if (request->directory == NULL)
372 {
373 request->directory = g_strdup("/");
374 }
375
376 if ((lpd->dir = fsp_opendir (lpd->fsp,request->directory)) == NULL)
377 {
378 request->logging_function (gftp_logging_error, request,
379 _("Could not get FSP directory listing %s: %s\n"),
380 request->directory, g_strerror (errno));
381 return (GFTP_ERETRYABLE);
382 }
383
384 return (0);
385 }
386
387
388 static off_t
389 fsp_get_file_size (gftp_request * request, const char *filename)
390 {
391 struct stat st;
392 fsp_protocol_data * lpd;
393
394 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
395 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
396 g_return_val_if_fail (filename != NULL, GFTP_EFATAL);
397
398 lpd = request->protocol_data;
399 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
400
401 if (fsp_stat (lpd->fsp,filename, &st) != 0)
402 return (GFTP_ERETRYABLE);
403
404 return (st.st_size);
405 }
406
407 static int
408 fsp_chdir (gftp_request * request, const char *directory)
409 {
410 fsp_protocol_data *lpd;
411 char *tempstr, *olddir;
412
413 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
414 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
415 g_return_val_if_fail (directory != NULL, GFTP_EFATAL);
416
417 lpd = request->protocol_data;
418
419 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
420 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
421
422 olddir=NULL;
423 /* build new directory string */
424 if (request->directory != directory)
425 {
426 olddir = request->directory;
427
428 if (*directory != '/' && request->directory != NULL)
429 {
430 tempstr = g_strconcat (request->directory, "/", directory, NULL);
431 request->directory = gftp_expand_path (request, tempstr);
432 g_free (tempstr);
433 }
434 else
435 request->directory = gftp_expand_path (request, directory);
436 }
437
438 if (fsp_getpro (lpd->fsp,request->directory,NULL) == 0)
439 {
440 request->logging_function (gftp_logging_misc, request,
441 _("Successfully changed directory to %s\n"),
442 directory);
443
444 if (olddir != NULL)
445 g_free (olddir);
446 return (0);
447 }
448 else
449 {
450 request->logging_function (gftp_logging_error, request,
451 _("Could not change directory to %s\n"),
452 directory);
453 g_free (request->directory);
454 request->directory = olddir;
455 return (GFTP_ERETRYABLE);
456 }
457 }
458
459 static int
460 fsp_removedir (gftp_request * request, const char *directory)
461 {
462 fsp_protocol_data *lpd;
463
464 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
465 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
466 g_return_val_if_fail (directory != NULL, GFTP_EFATAL);
467
468 lpd = request->protocol_data;
469
470 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
471 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
472
473 if (fsp_rmdir (lpd->fsp,directory) == 0)
474 {
475 request->logging_function (gftp_logging_misc, request,
476 _("Successfully removed %s\n"), directory);
477 return (0);
478 }
479 else
480 {
481 request->logging_function (gftp_logging_error, request,
482 _("Error: Could not remove directory %s: %s\n"),
483 directory, g_strerror (errno));
484 return (GFTP_ERETRYABLE);
485 }
486 }
487
488
489 static int
490 fsp_rmfile (gftp_request * request, const char *file)
491 {
492 fsp_protocol_data *lpd;
493
494 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
495 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
496 g_return_val_if_fail (file != NULL, GFTP_EFATAL);
497
498 lpd = request->protocol_data;
499 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
500 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
501
502 if (fsp_unlink (lpd->fsp,file) == 0)
503 {
504 request->logging_function (gftp_logging_misc, request,
505 _("Successfully removed %s\n"), file);
506 return (0);
507 }
508 else
509 {
510 request->logging_function (gftp_logging_error, request,
511 _("Error: Could not remove file %s: %s\n"),
512 file, g_strerror (errno));
513 return (GFTP_ERETRYABLE);
514 }
515 }
516
517 static int
518 fsp_makedir (gftp_request * request, const char *directory)
519 {
520 fsp_protocol_data *lpd;
521
522 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
523 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
524 g_return_val_if_fail (directory != NULL, GFTP_EFATAL);
525
526 lpd = request->protocol_data;
527 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
528 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
529
530 if (fsp_mkdir (lpd->fsp,directory) == 0)
531 {
532 request->logging_function (gftp_logging_misc, request,
533 _("Successfully made directory %s\n"),
534 directory);
535 return (0);
536 }
537 else
538 {
539 request->logging_function (gftp_logging_error, request,
540 _("Error: Could not make directory %s: %s\n"),
541 directory, g_strerror (errno));
542 return (GFTP_ERETRYABLE);
543 }
544 }
545
546 static int
547 fsp_ren (gftp_request * request, const char *oldname,
548 const char *newname)
549 {
550 char *newname1,*newname2;
551 fsp_protocol_data *lpd;
552
553 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
554 g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL);
555 g_return_val_if_fail (oldname != NULL, GFTP_EFATAL);
556 g_return_val_if_fail (newname != NULL, GFTP_EFATAL);
557
558 lpd = request->protocol_data;
559 g_return_val_if_fail (lpd != NULL, GFTP_EFATAL);
560 g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL);
561
562 newname1= g_strconcat (request->directory, "/", oldname, NULL);
563 newname2= g_strconcat (request->directory, "/", newname, NULL);
564
565 if (fsp_rename (lpd->fsp,newname1, newname2) == 0)
566 {
567 request->logging_function (gftp_logging_misc, request,
568 _("Successfully renamed %s to %s\n"),
569 oldname, newname);
570 g_free(newname1);
571 g_free(newname2);
572 return (0);
573 }
574 else
575 {
576 g_free(newname1);
577 g_free(newname2);
578
579 request->logging_function (gftp_logging_error, request,
580 _("Error: Could not rename %s to %s: %s\n"),
581 oldname, newname, g_strerror (errno));
582 return (GFTP_ERETRYABLE);
583 }
584 }
585
586 /* TODO: FSP needs to know file last modification time while starting
587 upload. It can not change last mod time of existing files on server.
588 */
589
590 void
591 fsp_register_module (void)
592 {
593 }
594
595 int
596 fsp_init (gftp_request * request)
597 {
598 fsp_protocol_data *lpd;
599
600 g_return_val_if_fail (request != NULL, GFTP_EFATAL);
601
602 request->protonum = GFTP_FSP_NUM;
603 request->init = fsp_init;
604 request->copy_param_options = NULL;
605 request->destroy = fsp_destroy;
606 request->read_function = fsp_read_function;
607 request->write_function = fsp_write_function;
608 request->connect = fsp_connect;
609 request->post_connect = NULL;
610 request->disconnect = fsp_disconnect;
611 request->get_file = fsp_get_file;
612 request->put_file = fsp_put_file;
613 request->transfer_file = NULL;
614 request->get_next_file_chunk = NULL;
615 request->put_next_file_chunk = NULL;
616 request->end_transfer = fsp_end_transfer;
617 request->abort_transfer = fsp_abort_transfer;
618 request->stat_filename = fsp_stat_filename;
619 request->list_files = fsp_list_files;
620 request->get_next_file = fsp_get_next_file;
621 request->get_next_dirlist_line = NULL;
622 request->get_file_size = fsp_get_file_size;
623 request->chdir = fsp_chdir;
624 request->rmdir = fsp_removedir;
625 request->rmfile = fsp_rmfile;
626 request->mkdir = fsp_makedir;
627 request->rename = fsp_ren;
628 request->chmod = NULL;
629 request->set_file_time = NULL;
630 request->site = NULL;
631 request->parse_url = NULL;
632 request->set_config_options = NULL;
633 request->swap_socks = NULL;
634 request->url_prefix = "fsp";
635 request->need_hostport = 1;
636 request->need_username = 0;
637 request->need_password = 0;
638 request->use_cache = 1;
639 request->always_connected = 0;
640
641 lpd = g_malloc0 (sizeof (*lpd));
642 request->protocol_data = lpd;
643
644 return (gftp_set_config_options (request));
645 }