comparison lib/local.c @ 48:e5f6054590b5

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