comparison lib/local.c @ 1:8b1883341c6f

Initial revision
author masneyb
date Mon, 05 Aug 2002 19:46:57 +0000
parents
children 5551ab2301fe
comparison
equal deleted inserted replaced
0:674ed97069fd 1:8b1883341c6f
1 /*****************************************************************************/
2 /* local.c - functions that will use the local system */
3 /* Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org> */
4 /* */
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation; either version 2 of the License, or */
8 /* (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
14 /* */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program; if not, write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
18 /*****************************************************************************/
19
20 #include "gftp.h"
21
22 static void local_destroy ( gftp_request * request );
23 static void local_remove_key ( gpointer key,
24 gpointer value,
25 gpointer user_data );
26 static int local_connect ( gftp_request * request );
27 static void local_disconnect ( gftp_request * request );
28 static long local_get_file ( gftp_request * request,
29 const char *filename,
30 FILE * fd,
31 off_t startsize );
32 static int local_put_file ( gftp_request * request,
33 const char *filename,
34 FILE * fd,
35 off_t startsize,
36 off_t totalsize );
37 static int local_end_transfer ( gftp_request * request );
38 static int local_get_next_file ( gftp_request * request,
39 gftp_file * fle,
40 FILE * fd );
41 static int local_list_files ( gftp_request * request );
42 static off_t local_get_file_size ( gftp_request * request,
43 const char *filename );
44 static int local_chdir ( gftp_request * request,
45 const char *directory );
46 static int local_rmdir ( gftp_request * request,
47 const char *directory );
48 static int local_rmfile ( gftp_request * request,
49 const char *file );
50 static int local_mkdir ( gftp_request * request,
51 const char *directory );
52 static int local_rename ( gftp_request * request,
53 const char *oldname,
54 const char *newname );
55 static int local_chmod ( gftp_request * request,
56 const char *file,
57 int mode );
58 static int local_set_file_time ( gftp_request * request,
59 const char *file,
60 time_t datetime );
61 static char *make_text_mode ( gftp_file * fle,
62 mode_t mode );
63 static gint hash_compare ( gconstpointer path1,
64 gconstpointer path2 );
65 static guint hash_function ( gconstpointer key );
66
67 typedef struct local_protocol_data_tag
68 {
69 DIR *dir;
70 GHashTable *userhash, *grouphash;
71 } local_protocol_data;
72
73
74 void
75 local_init (gftp_request * request)
76 {
77 local_protocol_data *lpd;
78
79 g_return_if_fail (request != NULL);
80
81 request->protonum = GFTP_LOCAL_NUM;
82 request->init = local_init;
83 request->destroy = local_destroy;
84 request->connect = local_connect;
85 request->disconnect = local_disconnect;
86 request->get_file = local_get_file;
87 request->put_file = local_put_file;
88 request->transfer_file = NULL;
89 request->get_next_file_chunk = NULL;
90 request->put_next_file_chunk = NULL;
91 request->end_transfer = local_end_transfer;
92 request->list_files = local_list_files;
93 request->get_next_file = local_get_next_file;
94 request->set_data_type = NULL;
95 request->get_file_size = local_get_file_size;
96 request->chdir = local_chdir;
97 request->rmdir = local_rmdir;
98 request->rmfile = local_rmfile;
99 request->mkdir = local_mkdir;
100 request->rename = local_rename;
101 request->chmod = local_chmod;
102 request->set_file_time = local_set_file_time;
103 request->site = NULL;
104 request->parse_url = NULL;
105 request->url_prefix = "file";
106 request->protocol_name = "Local";
107 request->need_hostport = 0;
108 request->need_userpass = 0;
109 request->use_cache = 0;
110 request->use_threads = 0;
111 request->always_connected = 1;
112 gftp_set_config_options (request);
113
114 lpd = g_malloc0 (sizeof (*lpd));
115 request->protocol_data = lpd;
116 lpd->userhash = g_hash_table_new (hash_function, hash_compare);
117 lpd->grouphash = g_hash_table_new (hash_function, hash_compare);
118 }
119
120
121 static void
122 local_destroy (gftp_request * request)
123 {
124 local_protocol_data * lpd;
125
126 g_return_if_fail (request != NULL);
127 g_return_if_fail (request->protonum == GFTP_LOCAL_NUM);
128
129 lpd = request->protocol_data;
130 g_hash_table_foreach (lpd->userhash, local_remove_key, NULL);
131 g_hash_table_destroy (lpd->userhash);
132 g_hash_table_foreach (lpd->grouphash, local_remove_key, NULL);
133 g_hash_table_destroy (lpd->grouphash);
134 lpd->userhash = lpd->grouphash = NULL;
135 }
136
137
138 static void
139 local_remove_key (gpointer key, gpointer value, gpointer user_data)
140 {
141 g_free (value);
142 }
143
144
145 static int
146 local_connect (gftp_request * request)
147 {
148 char tempstr[PATH_MAX];
149
150 g_return_val_if_fail (request != NULL, -2);
151 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
152
153 request->sockfd = (void *) 1;
154
155 if (request->directory)
156 {
157 if (chdir (request->directory) != 0)
158 {
159 request->logging_function (gftp_logging_error, request->user_data,
160 _("Could not change local directory to %s: %s\n"),
161 request->directory, g_strerror (errno));
162 }
163 g_free (request->directory);
164 request->directory = NULL;
165 }
166
167 if (getcwd (tempstr, sizeof (tempstr)) != NULL)
168 {
169 tempstr[sizeof (tempstr) - 1] = '\0';
170 request->directory = g_malloc (strlen (tempstr) + 1);
171 strcpy (request->directory, tempstr);
172 }
173 else
174 request->logging_function (gftp_logging_error, request->user_data,
175 _("Could not get current working directory: %s\n"),
176 g_strerror (errno));
177
178 return (0);
179 }
180
181
182 static void
183 local_disconnect (gftp_request * request)
184 {
185 g_return_if_fail (request != NULL);
186 g_return_if_fail (request->protonum == GFTP_LOCAL_NUM);
187
188 if (request->datafd != NULL)
189 {
190 if (fclose (request->datafd) < 0)
191 request->logging_function (gftp_logging_error, request->user_data,
192 _("Error closing file descriptor: %s\n"),
193 g_strerror (errno));
194 request->datafd = NULL;
195 }
196 request->sockfd = NULL;
197 }
198
199
200 static long
201 local_get_file (gftp_request * request, const char *filename, FILE * fd,
202 off_t startsize)
203 {
204 size_t size;
205
206 g_return_val_if_fail (request != NULL, -2);
207 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
208 g_return_val_if_fail (filename != NULL, -2);
209
210 if (fd == NULL)
211 {
212 if ((request->datafd = fopen (filename, "rb")) == NULL)
213 {
214 request->logging_function (gftp_logging_error, request->user_data,
215 _("Error: Cannot open local file %s: %s\n"),
216 filename, g_strerror (errno));
217 return (-2);
218 }
219 }
220 else
221 request->datafd = fd;
222
223 if (lseek (fileno (request->datafd), 0, SEEK_END) == -1)
224 {
225 request->logging_function (gftp_logging_error, request->user_data,
226 _("Error: Cannot seek on file %s: %s\n"),
227 filename, g_strerror (errno));
228 fclose (request->datafd);
229 request->datafd = NULL;
230 }
231
232 if ((size = ftell (request->datafd)) == -1)
233 {
234 request->logging_function (gftp_logging_error, request->user_data,
235 _("Error: Cannot seek on file %s: %s\n"),
236 filename, g_strerror (errno));
237 fclose (request->datafd);
238 request->datafd = NULL;
239 }
240
241 if (lseek (fileno (request->datafd), startsize, SEEK_SET) == -1)
242 {
243 request->logging_function (gftp_logging_error, request->user_data,
244 _("Error: Cannot seek on file %s: %s\n"),
245 filename, g_strerror (errno));
246 fclose (request->datafd);
247 request->datafd = NULL;
248 }
249
250 return (size);
251 }
252
253
254 static int
255 local_put_file (gftp_request * request, const char *filename, FILE * fd,
256 off_t startsize, off_t totalsize)
257 {
258 int sock;
259
260 g_return_val_if_fail (request != NULL, -2);
261 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
262 g_return_val_if_fail (filename != NULL, -2);
263
264 if (fd == NULL)
265 {
266 if ((sock = open (filename,
267 startsize > 0 ? O_WRONLY | O_APPEND | O_CREAT: O_WRONLY | O_CREAT,
268 S_IRUSR | S_IWUSR)) < 0)
269 {
270 request->logging_function (gftp_logging_error, request->user_data,
271 _("Error: Cannot open local file %s: %s\n"),
272 filename, g_strerror (errno));
273 return (-2);
274 }
275
276 if ((request->datafd = fdopen (sock, "ab")) == NULL)
277 {
278 request->logging_function (gftp_logging_error, request->user_data,
279 _("Cannot fdopen() socket for %s: %s\n"),
280 filename, g_strerror (errno));
281 close (sock);
282 return (-2);
283 }
284 }
285 else
286 request->datafd = fd;
287
288 if (ftruncate (fileno (request->datafd), startsize) == -1)
289 {
290 request->logging_function (gftp_logging_error, request->user_data,
291 _("Error: Cannot truncate local file %s: %s\n"),
292 filename, g_strerror (errno));
293 fclose (request->datafd);
294 request->datafd = NULL;
295 return (-2);
296 }
297
298 if (fseek (request->datafd, startsize, SEEK_SET) == -1)
299 {
300 request->logging_function (gftp_logging_error, request->user_data,
301 _("Error: Cannot seek on file %s: %s\n"),
302 filename, g_strerror (errno));
303 fclose (request->datafd);
304 request->datafd = NULL;
305 return (-2);
306 }
307 return (0);
308 }
309
310
311 static int
312 local_end_transfer (gftp_request * request)
313 {
314 local_protocol_data * lpd;
315
316 lpd = request->protocol_data;
317 if (lpd->dir)
318 {
319 closedir (lpd->dir);
320 lpd->dir = NULL;
321 }
322
323 if (request->datafd != NULL)
324 {
325 if (fclose (request->datafd) < 0)
326 request->logging_function (gftp_logging_error, request->user_data,
327 _("Error closing file descriptor: %s\n"),
328 g_strerror (errno));
329
330 request->datafd = NULL;
331 }
332
333 return (0);
334 }
335
336
337 static int
338 local_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd)
339 {
340 local_protocol_data * lpd;
341 struct dirent *dirp;
342 char *user, *group;
343 struct passwd *pw;
344 struct group *gr;
345 struct stat st;
346
347 /* the struct passwd and struct group are not thread safe. But,
348 we're ok here because I have threading turned off for the local
349 protocol (see use_threads in local_init above) */
350 g_return_val_if_fail (request != NULL, -2);
351 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
352 g_return_val_if_fail (fle != NULL, -2);
353
354 lpd = request->protocol_data;
355 memset (fle, 0, sizeof (*fle));
356
357 if ((dirp = readdir (lpd->dir)) == NULL)
358 {
359 closedir (lpd->dir);
360 lpd->dir = NULL;
361 return (-2);
362 }
363
364 fle->file = g_malloc (strlen (dirp->d_name) + 1);
365 strcpy (fle->file, dirp->d_name);
366 if (lstat (fle->file, &st) != 0)
367 {
368 closedir (lpd->dir);
369 lpd->dir = NULL;
370 return (-2);
371 }
372
373 if ((user = g_hash_table_lookup (lpd->userhash,
374 GUINT_TO_POINTER(st.st_uid))) != NULL)
375 {
376 fle->user = g_malloc (strlen (user) + 1);
377 strcpy (fle->user, user);
378 }
379 else
380 {
381 if ((pw = getpwuid (st.st_uid)) == NULL)
382 fle->user = g_strdup_printf ("%u", st.st_uid);
383 else
384 {
385 fle->user = g_malloc (strlen (pw->pw_name) + 1);
386 strcpy (fle->user, pw->pw_name);
387 }
388
389 user = g_malloc (strlen (fle->user) + 1);
390 strcpy (user, fle->user);
391 g_hash_table_insert (lpd->userhash, GUINT_TO_POINTER (st.st_uid), user);
392 }
393
394 if ((group = g_hash_table_lookup (lpd->grouphash,
395 GUINT_TO_POINTER(st.st_gid))) != NULL)
396 {
397 fle->group = g_malloc (strlen (group) + 1);
398 strcpy (fle->group, group);
399 }
400 else
401 {
402 if ((gr = getgrgid (st.st_gid)) == NULL)
403 fle->group = g_strdup_printf ("%u", st.st_gid);
404 else
405 {
406 fle->group = g_malloc (strlen (gr->gr_name) + 1);
407 strcpy (fle->group, gr->gr_name);
408 }
409
410 group = g_malloc (strlen (fle->group) + 1);
411 strcpy (group, fle->group);
412 g_hash_table_insert (lpd->grouphash, GUINT_TO_POINTER (st.st_gid), group);
413 }
414
415 fle->size = st.st_size;
416 fle->datetime = st.st_mtime;
417 fle->attribs = make_text_mode (fle, st.st_mode);
418
419 if (*fle->attribs == 'd')
420 fle->isdir = 1;
421 if (*fle->attribs == 'l')
422 fle->islink = 1;
423 if (strchr (fle->attribs, 'x') != NULL && !fle->isdir && !fle->islink)
424 fle->isexe = 1;
425 if (*fle->attribs == 'b')
426 fle->isblock = 1;
427 if (*fle->attribs == 'c')
428 fle->ischar = 1;
429 if (*fle->attribs == 's')
430 fle->issocket = 1;
431 if (*fle->attribs == 'p')
432 fle->isfifo = 1;
433 return (1);
434 }
435
436
437 static int
438 local_list_files (gftp_request * request)
439 {
440 local_protocol_data *lpd;
441 char *tempstr;
442
443 g_return_val_if_fail (request != NULL, -2);
444 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
445 lpd = request->protocol_data;
446
447 tempstr = g_strconcat (request->directory, "/", NULL);
448
449 if ((lpd->dir = opendir (tempstr)) == NULL)
450 {
451 request->logging_function (gftp_logging_error, request->user_data,
452 _("Could not get local directory listing %s: %s\n"),
453 tempstr, g_strerror (errno));
454 g_free (tempstr);
455 return (-1);
456 }
457
458 g_free (tempstr);
459 return (0);
460 }
461
462
463 static off_t
464 local_get_file_size (gftp_request * request, const char *filename)
465 {
466 struct stat st;
467
468 if (stat (filename, &st) == -1)
469 return (-1);
470 return (st.st_size);
471 }
472
473
474 static int
475 local_chdir (gftp_request * request, const char *directory)
476 {
477 char tempstr[255];
478
479 g_return_val_if_fail (request != NULL, -2);
480 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
481 g_return_val_if_fail (directory != NULL, -2);
482
483 if (chdir (directory) == 0)
484 {
485 request->logging_function (gftp_logging_error, request->user_data,
486 _("Successfully changed local directory to %s\n"),
487 directory);
488 if (request->directory != directory)
489 {
490 if (getcwd (tempstr, sizeof (tempstr)) == NULL)
491 {
492 request->logging_function (gftp_logging_error, request->user_data,
493 _("Could not get current working directory: %s\n"),
494 g_strerror (errno));
495 return (-1);
496 }
497 if (request->directory)
498 g_free (request->directory);
499 request->directory = g_malloc (strlen (tempstr) + 1);
500 strcpy (request->directory, tempstr);
501 }
502 return (0);
503 }
504 request->logging_function (gftp_logging_error, request->user_data,
505 _("Could not change local directory to %s: %s\n"),
506 directory, g_strerror (errno));
507 return (-1);
508 }
509
510
511 static int
512 local_rmdir (gftp_request * request, const char *directory)
513 {
514 g_return_val_if_fail (request != NULL, -2);
515 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
516 g_return_val_if_fail (directory != NULL, -2);
517
518 if (rmdir (directory) == 0)
519 {
520 request->logging_function (gftp_logging_error, request->user_data,
521 _("Successfully removed %s\n"), directory);
522 return (0);
523 }
524 else
525 {
526 request->logging_function (gftp_logging_error, request->user_data,
527 _("Error: Could not remove directory %s: %s\n"),
528 directory, g_strerror (errno));
529 return (-1);
530 }
531 }
532
533
534 static int
535 local_rmfile (gftp_request * request, const char *file)
536 {
537 g_return_val_if_fail (request != NULL, -2);
538 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
539 g_return_val_if_fail (file != NULL, -2);
540
541 if (unlink (file) == 0)
542 {
543 request->logging_function (gftp_logging_error, request->user_data,
544 _("Successfully removed %s\n"), file);
545 return (0);
546 }
547 else
548 {
549 request->logging_function (gftp_logging_error, request->user_data,
550 _("Error: Could not remove file %s: %s\n"),
551 file, g_strerror (errno));
552 return (-1);
553 }
554 }
555
556
557 static int
558 local_mkdir (gftp_request * request, const char *directory)
559 {
560 g_return_val_if_fail (request != NULL, -2);
561 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
562 g_return_val_if_fail (directory != NULL, -2);
563
564 if (mkdir (directory, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
565 {
566 request->logging_function (gftp_logging_error, request->user_data,
567 _("Successfully made directory %s\n"),
568 directory);
569 return (0);
570 }
571 else
572 {
573 request->logging_function (gftp_logging_error, request->user_data,
574 _("Error: Could not make directory %s: %s\n"),
575 directory, g_strerror (errno));
576 return (-1);
577 }
578 }
579
580
581 static int
582 local_rename (gftp_request * request, const char *oldname,
583 const char *newname)
584 {
585 g_return_val_if_fail (request != NULL, -2);
586 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
587 g_return_val_if_fail (oldname != NULL, -2);
588 g_return_val_if_fail (newname != NULL, -2);
589
590 if (rename (oldname, newname) == 0)
591 {
592 request->logging_function (gftp_logging_error, request->user_data,
593 _("Successfully renamed %s to %s\n"),
594 oldname, newname);
595 return (0);
596 }
597 else
598 {
599 request->logging_function (gftp_logging_error, request->user_data,
600 _("Error: Could not rename %s to %s: %s\n"),
601 oldname, newname, g_strerror (errno));
602 return (-1);
603 }
604 }
605
606
607 static int
608 local_chmod (gftp_request * request, const char *file, int mode)
609 {
610 char buf[10];
611 int newmode;
612
613 g_return_val_if_fail (request != NULL, -2);
614 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
615 g_return_val_if_fail (file != NULL, -2);
616
617 g_snprintf (buf, sizeof (buf), "%d", mode);
618 newmode = strtol (buf, NULL, 8);
619
620 if (chmod (file, newmode) == 0)
621 {
622 request->logging_function (gftp_logging_error, request->user_data,
623 _("Successfully changed mode of %s to %d\n"),
624 file, mode);
625 return (0);
626 }
627 else
628 {
629 request->logging_function (gftp_logging_error, request->user_data,
630 _("Error: Could not change mode of %s to %d: %s\n"),
631 file, mode, g_strerror (errno));
632 return (-1);
633 }
634 }
635
636
637 static int
638 local_set_file_time (gftp_request * request, const char *file,
639 time_t datetime)
640 {
641 struct utimbuf time_buf;
642
643 g_return_val_if_fail (request != NULL, -2);
644 g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
645 g_return_val_if_fail (file != NULL, -2);
646
647 time_buf.modtime = time_buf.actime = datetime;
648 return (utime (file, &time_buf));
649 }
650
651
652 static char *
653 make_text_mode (gftp_file * fle, mode_t mode)
654 {
655 char *str;
656
657 str = g_malloc0 (11);
658
659 str[0] = '?';
660 if (S_ISREG (mode))
661 str[0] = '-';
662
663 if (S_ISLNK (mode))
664 {
665 fle->islink = 1;
666 str[0] = 'l';
667 }
668
669 if (S_ISBLK (mode))
670 {
671 fle->isblock = 1;
672 str[0] = 'b';
673 }
674
675 if (S_ISCHR (mode))
676 {
677 fle->ischar = 1;
678 str[0] = 'c';
679 }
680
681 if (S_ISFIFO (mode))
682 {
683 fle->isfifo = 1;
684 str[0] = 'p';
685 }
686
687 if (S_ISSOCK (mode))
688 {
689 fle->issocket = 1;
690 str[0] = 's';
691 }
692
693 if (S_ISDIR (mode))
694 {
695 fle->isdir = 1;
696 str[0] = 'd';
697 }
698
699 str[1] = mode & S_IRUSR ? 'r' : '-';
700 str[2] = mode & S_IWUSR ? 'w' : '-';
701
702 if ((mode & S_ISUID) && (mode & S_IXUSR))
703 str[3] = 's';
704 else if (mode & S_ISUID)
705 str[3] = 'S';
706 else if (mode & S_IXUSR)
707 str[3] = 'x';
708 else
709 str[3] = '-';
710
711 str[4] = mode & S_IRGRP ? 'r' : '-';
712 str[5] = mode & S_IWGRP ? 'w' : '-';
713
714 if ((mode & S_ISGID) && (mode & S_IXGRP))
715 str[6] = 's';
716 else if (mode & S_ISGID)
717 str[6] = 'S';
718 else if (mode & S_IXGRP)
719 str[6] = 'x';
720 else
721 str[6] = '-';
722
723 str[7] = mode & S_IROTH ? 'r' : '-';
724 str[8] = mode & S_IWOTH ? 'w' : '-';
725
726 if ((mode & S_ISVTX) && (mode & S_IXOTH))
727 str[9] = 't';
728 else if (mode & S_ISVTX)
729 str[9] = 'T';
730 else if (mode & S_IXOTH)
731 str[9] = 'x';
732 else
733 str[9] = '-';
734 return (str);
735 }
736
737
738 static gint
739 hash_compare (gconstpointer path1, gconstpointer path2)
740 {
741 return (GPOINTER_TO_UINT (path1) == GPOINTER_TO_UINT (path2));
742 }
743
744
745 static guint
746 hash_function (gconstpointer key)
747 {
748 return (GPOINTER_TO_UINT (key));
749 }
750