This source file includes following definitions.
- mc_mkdir_internal
- mc_mkdir_recursive
- mc_def_getlocalcopy
- mc_def_ungetlocalcopy
- mc_open
- MC_NAMEOP
- mc_symlink
- MC_RENAMEOP
- mc_setctl
- mc_close
- mc_opendir
- mc_readdir
- mc_closedir
- MC_STATOP
- mc_ungetlocalcopy
- mc_chdir
- mc_lseek
- mc_mkstemps
- mc_tmpdir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <config.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <signal.h>
43 #include <ctype.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <dirent.h>
47 #include <pwd.h>
48 #include <grp.h>
49
50 #include "lib/global.h"
51
52 #include "lib/widget.h"
53 #include "lib/strutil.h"
54 #include "lib/util.h"
55
56 #include "vfs.h"
57 #include "utilvfs.h"
58 #include "path.h"
59 #include "gc.h"
60 #include "xdirentry.h"
61
62
63 extern GString *vfs_str_buffer;
64 extern vfs_class *current_vfs;
65 extern struct vfs_dirent *mc_readdir_result;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 static int
82 mc_mkdir_internal (const vfs_path_t *vpath, mode_t mode)
83 {
84 struct vfs_class *me;
85
86 if (vpath == NULL)
87 return (-1);
88
89 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
90 if (me == NULL)
91 return (-1);
92
93 if (me->mkdir == NULL)
94 {
95 errno = ENOTSUP;
96 return (-1);
97 }
98
99 const int result = me->mkdir (vpath, mode);
100
101 if (result == -1)
102 errno = vfs_ferrno (me);
103
104 return result;
105 }
106
107
108
109 static int
110 mc_mkdir_recursive (const vfs_path_t *vpath, mode_t mode)
111 {
112 vfs_path_t *q;
113 int result;
114
115 if (mc_mkdir_internal (vpath, mode) == 0)
116 return 0;
117 if (errno != ENOENT)
118 return (-1);
119
120
121 if (!vfs_file_is_local (vpath))
122 return (-1);
123
124 if (strcmp (vfs_path_as_str (vpath), PATH_SEP_STR) == 0)
125 {
126 errno = ENOTDIR;
127 return (-1);
128 }
129
130 q = vfs_path_append_new (vpath, "..", (char *) NULL);
131 result = mc_mkdir_recursive (q, mode);
132 vfs_path_free (q, TRUE);
133
134 if (result == 0)
135 result = mc_mkdir_internal (vpath, mode);
136
137 return result;
138 }
139
140
141
142 static vfs_path_t *
143 mc_def_getlocalcopy (const vfs_path_t *filename_vpath)
144 {
145 vfs_path_t *tmp_vpath = NULL;
146 int fdin, fdout = -1;
147 ssize_t i;
148 char buffer[BUF_1K * 8];
149 struct stat mystat;
150
151 fdin = mc_open (filename_vpath, O_RDONLY | O_LINEAR);
152 if (fdin == -1)
153 goto fail;
154
155 fdout = vfs_mkstemps (&tmp_vpath, "vfs", vfs_path_get_last_path_str (filename_vpath));
156 if (fdout == -1)
157 goto fail;
158
159 while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0)
160 {
161 if (write (fdout, buffer, i) != i)
162 goto fail;
163 }
164 if (i == -1)
165 goto fail;
166 i = mc_close (fdin);
167 fdin = -1;
168 if (i == -1)
169 goto fail;
170
171 i = close (fdout);
172 fdout = -1;
173 if (i == -1)
174 goto fail;
175
176 if (mc_stat (filename_vpath, &mystat) != -1)
177 mc_chmod (tmp_vpath, mystat.st_mode);
178
179 return tmp_vpath;
180
181 fail:
182 vfs_path_free (tmp_vpath, TRUE);
183 if (fdout != -1)
184 close (fdout);
185 if (fdin != -1)
186 mc_close (fdin);
187 return NULL;
188 }
189
190
191
192 static int
193 mc_def_ungetlocalcopy (const vfs_path_t *filename_vpath, const vfs_path_t *local_vpath,
194 gboolean has_changed)
195 {
196 int fdin = -1, fdout = -1;
197 const char *filename;
198 const char *local;
199
200 filename = vfs_path_get_last_path_str (filename_vpath);
201 local = vfs_path_get_last_path_str (local_vpath);
202
203 if (has_changed)
204 {
205 char buffer[BUF_1K * 8];
206 ssize_t i;
207
208 if (vfs_path_get_last_path_vfs (filename_vpath)->write == NULL)
209 goto failed;
210
211 fdin = open (local, O_RDONLY);
212 if (fdin == -1)
213 goto failed;
214 fdout = mc_open (filename_vpath, O_WRONLY | O_TRUNC);
215 if (fdout == -1)
216 goto failed;
217 while ((i = read (fdin, buffer, sizeof (buffer))) > 0)
218 if (mc_write (fdout, buffer, (size_t) i) != i)
219 goto failed;
220 if (i == -1)
221 goto failed;
222
223 if (close (fdin) == -1)
224 {
225 fdin = -1;
226 goto failed;
227 }
228 fdin = -1;
229 if (mc_close (fdout) == -1)
230 {
231 fdout = -1;
232 goto failed;
233 }
234 }
235 unlink (local);
236 return 0;
237
238 failed:
239 if (filename != NULL)
240 message (D_ERROR, MSG_ERROR, _ ("Changes to file lost:\n%s"), filename);
241 else
242 message (D_ERROR, MSG_ERROR, "%s", _ ("Changes to file lost"));
243
244 if (fdout != -1)
245 mc_close (fdout);
246 if (fdin != -1)
247 close (fdin);
248 unlink (local);
249 return (-1);
250 }
251
252
253
254
255
256 int
257 mc_open (const vfs_path_t *vpath, int flags, ...)
258 {
259 int result = -1;
260 mode_t mode = 0;
261 struct vfs_class *me;
262
263 if (vpath == NULL)
264 return (-1);
265
266
267 if ((flags & O_CREAT) != 0)
268 {
269 va_list ap;
270
271 va_start (ap, flags);
272
273
274
275 mode = va_arg (ap, PROMOTED_MODE_T);
276 va_end (ap);
277 }
278
279 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
280 if (me != NULL && me->open != NULL)
281 {
282 void *info;
283
284
285 info = me->open (vpath, flags, mode);
286 if (info == NULL)
287 errno = vfs_ferrno (me);
288 else
289 result = vfs_new_handle (me, info);
290 }
291 else
292 errno = ENOTSUP;
293
294 return result;
295 }
296
297
298
299 #define MC_NAMEOP(name, inarg, callarg) \
300 int mc_##name inarg \
301 { \
302 int result; \
303 struct vfs_class *me; \
304 \
305 if (vpath == NULL) \
306 return (-1); \
307 \
308 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); \
309 if (me == NULL) \
310 return (-1); \
311 \
312 result = me->name != NULL ? me->name callarg : -1; \
313 if (result == -1) \
314 errno = me->name != NULL ? vfs_ferrno (me) : ENOTSUP; \
315 return result; \
316 }
317
318 MC_NAMEOP (chmod, (const vfs_path_t *vpath, mode_t mode), (vpath, mode))
319 MC_NAMEOP (chown, (const vfs_path_t *vpath, uid_t owner, gid_t group), (vpath, owner, group))
320 MC_NAMEOP (fgetflags, (const vfs_path_t *vpath, unsigned long *flags), (vpath, flags))
321 MC_NAMEOP (fsetflags, (const vfs_path_t *vpath, unsigned long flags), (vpath, flags))
322 MC_NAMEOP (utime, (const vfs_path_t *vpath, mc_timesbuf_t *times), (vpath, times))
323 MC_NAMEOP (readlink, (const vfs_path_t *vpath, char *buf, size_t bufsiz), (vpath, buf, bufsiz))
324 MC_NAMEOP (unlink, (const vfs_path_t *vpath), (vpath))
325 MC_NAMEOP (rmdir, (const vfs_path_t *vpath), (vpath))
326 MC_NAMEOP (mknod, (const vfs_path_t *vpath, mode_t mode, dev_t dev), (vpath, mode, dev))
327
328
329
330 int
331 mc_mkdir (const vfs_path_t *vpath, mode_t mode)
332 {
333 return mc_mkdir_recursive (vpath, mode);
334 }
335
336
337
338 int
339 mc_symlink (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
340 {
341 int result = -1;
342
343 if (vpath1 != NULL && vpath2 != NULL)
344 {
345 struct vfs_class *me;
346
347 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath2));
348 if (me != NULL)
349 {
350 result = me->symlink != NULL ? me->symlink (vpath1, vpath2) : -1;
351 if (result == -1)
352 errno = me->symlink != NULL ? vfs_ferrno (me) : ENOTSUP;
353 }
354 }
355 return result;
356 }
357
358
359
360 #define MC_HANDLEOP(rettype, name, inarg, callarg) \
361 rettype mc_##name inarg \
362 { \
363 struct vfs_class *vfs; \
364 void *fsinfo = NULL; \
365 rettype result; \
366 \
367 if (handle == -1) \
368 return (-1); \
369 \
370 vfs = vfs_class_find_by_handle (handle, &fsinfo); \
371 if (vfs == NULL) \
372 return (-1); \
373 \
374 result = vfs->name != NULL ? vfs->name callarg : -1; \
375 if (result == -1) \
376 errno = vfs->name != NULL ? vfs_ferrno (vfs) : ENOTSUP; \
377 return result; \
378 }
379
380 MC_HANDLEOP (ssize_t, read, (int handle, void *buf, size_t count), (fsinfo, buf, count))
381 MC_HANDLEOP (ssize_t, write, (int handle, const void *buf, size_t count), (fsinfo, buf, count))
382 MC_HANDLEOP (int, fstat, (int handle, struct stat *buf), (fsinfo, buf))
383
384
385
386 #define MC_RENAMEOP(name) \
387 int mc_##name (const vfs_path_t *vpath1, const vfs_path_t *vpath2) \
388 { \
389 int result; \
390 struct vfs_class *me1, *me2; \
391 \
392 if (vpath1 == NULL || vpath2 == NULL) \
393 return (-1); \
394 \
395 me1 = VFS_CLASS (vfs_path_get_last_path_vfs (vpath1)); \
396 me2 = VFS_CLASS (vfs_path_get_last_path_vfs (vpath2)); \
397 \
398 if (me1 == NULL || me2 == NULL || me1 != me2) \
399 { \
400 errno = EXDEV; \
401 return (-1); \
402 } \
403 \
404 result = me1->name != NULL ? me1->name (vpath1, vpath2) : -1; \
405 if (result == -1) \
406 errno = me1->name != NULL ? vfs_ferrno (me1) : ENOTSUP; \
407 return result; \
408 }
409
410 MC_RENAMEOP (link)
411 MC_RENAMEOP (rename)
412
413
414
415 int
416 mc_ctl (int handle, int ctlop, void *arg)
417 {
418 struct vfs_class *vfs;
419 void *fsinfo = NULL;
420
421 vfs = vfs_class_find_by_handle (handle, &fsinfo);
422
423 return (vfs == NULL || vfs->ctl == NULL) ? 0 : vfs->ctl (fsinfo, ctlop, arg);
424 }
425
426
427
428 int
429 mc_setctl (const vfs_path_t *vpath, int ctlop, void *arg)
430 {
431 int result = -1;
432 struct vfs_class *me;
433
434 if (vpath == NULL)
435 vfs_die ("You don't want to pass NULL to mc_setctl.");
436
437 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
438 if (me != NULL)
439 result = me->setctl != NULL ? me->setctl (vpath, ctlop, arg) : 0;
440
441 return result;
442 }
443
444
445
446 int
447 mc_close (int handle)
448 {
449 struct vfs_class *vfs;
450 void *fsinfo = NULL;
451 int result;
452
453 if (handle == -1)
454 return (-1);
455
456 vfs = vfs_class_find_by_handle (handle, &fsinfo);
457 if (vfs == NULL || fsinfo == NULL)
458 return (-1);
459
460 if (handle < 3)
461 return close (handle);
462
463 if (vfs->close == NULL)
464 vfs_die ("VFS must support close.\n");
465 result = vfs->close (fsinfo);
466 vfs_free_handle (handle);
467 if (result == -1)
468 errno = vfs_ferrno (vfs);
469
470 return result;
471 }
472
473
474
475 DIR *
476 mc_opendir (const vfs_path_t *vpath)
477 {
478 int handle, *handlep;
479 void *info;
480 vfs_path_element_t *path_element;
481
482 if (vpath == NULL)
483 return NULL;
484
485 path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, -1);
486 if (!vfs_path_element_valid (path_element))
487 {
488 errno = ENOTSUP;
489 return NULL;
490 }
491
492 info = path_element->class->opendir ? path_element->class->opendir (vpath) : NULL;
493 if (info == NULL)
494 {
495 errno = path_element->class->opendir ? vfs_ferrno (path_element->class) : ENOTSUP;
496 return NULL;
497 }
498
499 path_element->dir.info = info;
500
501 path_element->dir.converter = (path_element->encoding != NULL)
502 ? str_crt_conv_from (path_element->encoding)
503 : str_cnv_from_term;
504 if (path_element->dir.converter == INVALID_CONV)
505 path_element->dir.converter = str_cnv_from_term;
506
507 handle = vfs_new_handle (path_element->class, vfs_path_element_clone (path_element));
508
509 handlep = g_new (int, 1);
510 *handlep = handle;
511 return (DIR *) handlep;
512 }
513
514
515
516 struct vfs_dirent *
517 mc_readdir (DIR *dirp)
518 {
519 int handle;
520 struct vfs_class *vfs;
521 void *fsinfo = NULL;
522 struct vfs_dirent *entry = NULL;
523 vfs_path_element_t *vfs_path_element;
524
525 if (dirp == NULL)
526 {
527 errno = EFAULT;
528 return NULL;
529 }
530
531 handle = *(int *) dirp;
532
533 vfs = vfs_class_find_by_handle (handle, &fsinfo);
534 if (vfs == NULL || fsinfo == NULL)
535 return NULL;
536
537 vfs_path_element = (vfs_path_element_t *) fsinfo;
538 if (vfs->readdir != NULL)
539 {
540 entry = vfs->readdir (vfs_path_element->dir.info);
541 if (entry == NULL)
542 return NULL;
543
544 g_string_set_size (vfs_str_buffer, 0);
545 str_vfs_convert_from (vfs_path_element->dir.converter, entry->d_name, vfs_str_buffer);
546 vfs_dirent_assign (mc_readdir_result, vfs_str_buffer->str, entry->d_ino, entry->d_type);
547 vfs_dirent_free (entry);
548 }
549 if (entry == NULL)
550 errno = vfs->readdir ? vfs_ferrno (vfs) : ENOTSUP;
551 return (entry != NULL) ? mc_readdir_result : NULL;
552 }
553
554
555
556 int
557 mc_closedir (DIR *dirp)
558 {
559 int handle;
560 struct vfs_class *vfs;
561 void *fsinfo = NULL;
562 int result = -1;
563
564 if (dirp == NULL)
565 return result;
566
567 handle = *(int *) dirp;
568
569 vfs = vfs_class_find_by_handle (handle, &fsinfo);
570 if (vfs != NULL && fsinfo != NULL)
571 {
572 vfs_path_element_t *vfs_path_element = (vfs_path_element_t *) fsinfo;
573
574 if (vfs_path_element->dir.converter != str_cnv_from_term)
575 {
576 str_close_conv (vfs_path_element->dir.converter);
577 vfs_path_element->dir.converter = INVALID_CONV;
578 }
579
580 result = vfs->closedir ? (*vfs->closedir) (vfs_path_element->dir.info) : -1;
581 vfs_free_handle (handle);
582 vfs_path_element_free (vfs_path_element);
583 }
584 g_free (dirp);
585 return result;
586 }
587
588
589
590 #define MC_STATOP(name) \
591 int mc_##name (const vfs_path_t *vpath, struct stat *buf) \
592 { \
593 int result = -1; \
594 struct vfs_class *me; \
595 \
596 if (vpath == NULL) \
597 return (-1); \
598 \
599 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath)); \
600 if (me != NULL) \
601 { \
602 result = me->name ? me->name (vpath, buf) : -1; \
603 if (result == -1) \
604 errno = me->name ? vfs_ferrno (me) : ENOTSUP; \
605 } \
606 \
607 return result; \
608 }
609
610 MC_STATOP (stat)
611 MC_STATOP (lstat)
612
613
614
615 vfs_path_t *
616 mc_getlocalcopy (const vfs_path_t *pathname_vpath)
617 {
618 vfs_path_t *result = NULL;
619 struct vfs_class *me;
620
621 if (pathname_vpath == NULL)
622 return NULL;
623
624 me = VFS_CLASS (vfs_path_get_last_path_vfs (pathname_vpath));
625 if (me != NULL)
626 {
627 result = me->getlocalcopy != NULL ? me->getlocalcopy (pathname_vpath)
628 : mc_def_getlocalcopy (pathname_vpath);
629 if (result == NULL)
630 errno = vfs_ferrno (me);
631 }
632 return result;
633 }
634
635
636
637 int
638 mc_ungetlocalcopy (const vfs_path_t *pathname_vpath, const vfs_path_t *local_vpath,
639 gboolean has_changed)
640 {
641 int result = -1;
642 const struct vfs_class *me;
643
644 if (pathname_vpath == NULL)
645 return (-1);
646
647 me = vfs_path_get_last_path_vfs (pathname_vpath);
648 if (me != NULL)
649 result = me->ungetlocalcopy != NULL
650 ? me->ungetlocalcopy (pathname_vpath, local_vpath, has_changed)
651 : mc_def_ungetlocalcopy (pathname_vpath, local_vpath, has_changed);
652
653 return result;
654 }
655
656
657
658
659
660
661
662
663
664
665
666 int
667 mc_chdir (const vfs_path_t *vpath)
668 {
669 struct vfs_class *old_vfs;
670 vfsid old_vfsid;
671 int result;
672 struct vfs_class *me;
673 const vfs_path_element_t *path_element;
674 vfs_path_t *cd_vpath;
675
676 if (vpath == NULL)
677 {
678 errno = 0;
679 return (-1);
680 }
681
682 if (vpath->relative)
683 cd_vpath = vfs_path_to_absolute (vpath);
684 else
685 cd_vpath = vfs_path_clone (vpath);
686
687 me = VFS_CLASS (vfs_path_get_last_path_vfs (cd_vpath));
688 if (me == NULL)
689 {
690 errno = EINVAL;
691 goto error_end;
692 }
693
694 if (me->chdir == NULL)
695 {
696 errno = ENOTSUP;
697 goto error_end;
698 }
699
700 result = me->chdir (cd_vpath);
701 if (result == -1)
702 {
703 errno = vfs_ferrno (me);
704 goto error_end;
705 }
706
707 old_vfsid = vfs_getid (vfs_get_raw_current_dir ());
708 old_vfs = current_vfs;
709
710
711 vfs_set_raw_current_dir (cd_vpath);
712 current_vfs = me;
713
714
715 vfs_stamp_create (old_vfs, old_vfsid);
716
717
718 path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
719 if (vfs_path_element_valid (path_element))
720 {
721 if (*path_element->path != '\0')
722 {
723 char *p;
724
725 p = strchr (path_element->path, 0) - 1;
726 if (IS_PATH_SEP (*p) && p > path_element->path)
727 *p = '\0';
728 }
729
730 #ifdef ENABLE_VFS_NET
731 {
732 struct vfs_s_super *super;
733
734 super = vfs_get_super_by_vpath (vpath);
735 if (super != NULL && super->path_element != NULL)
736 {
737 g_free (super->path_element->path);
738 super->path_element->path = g_strdup (path_element->path);
739 }
740 }
741 #endif
742 }
743
744 return 0;
745
746 error_end:
747 vfs_path_free (cd_vpath, TRUE);
748 return (-1);
749 }
750
751
752
753 off_t
754 mc_lseek (int fd, off_t offset, int whence)
755 {
756 struct vfs_class *vfs;
757 void *fsinfo = NULL;
758 off_t result;
759
760 if (fd == -1)
761 return (-1);
762
763 vfs = vfs_class_find_by_handle (fd, &fsinfo);
764 if (vfs == NULL)
765 return (-1);
766
767 result = vfs->lseek ? vfs->lseek (fsinfo, offset, whence) : -1;
768 if (result == -1)
769 errno = vfs->lseek ? vfs_ferrno (vfs) : ENOTSUP;
770 return result;
771 }
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 int
788 mc_mkstemps (vfs_path_t **pname_vpath, const char *prefix, const char *suffix)
789 {
790 char *p1, *p2;
791 int fd;
792
793 if (strchr (prefix, PATH_SEP) != NULL)
794 p1 = g_strdup (prefix);
795 else
796 {
797
798 p1 = g_build_filename (mc_tmpdir (), prefix, (char *) NULL);
799 }
800
801 p2 = g_strconcat (p1, "XXXXXX", suffix, (char *) NULL);
802 g_free (p1);
803
804 fd = g_mkstemp (p2);
805 if (fd >= 0)
806 *pname_vpath = vfs_path_from_str (p2);
807 else
808 {
809 *pname_vpath = NULL;
810 fd = -1;
811 }
812
813 g_free (p2);
814
815 return fd;
816 }
817
818
819
820
821
822
823
824
825
826
827 const char *
828 mc_tmpdir (void)
829 {
830 static char buffer[PATH_MAX];
831 static const char *tmpdir = NULL;
832 const char *sys_tmp;
833 gchar *template;
834
835
836 if (tmpdir != NULL)
837 {
838 struct stat st;
839
840 if (lstat (tmpdir, &st) == 0 && S_ISDIR (st.st_mode) && st.st_uid == getuid ()
841 && (st.st_mode & 0777) == 0700)
842 return tmpdir;
843 }
844
845 sys_tmp = getenv ("MC_TMPDIR");
846 if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
847 {
848 sys_tmp = getenv ("TMPDIR");
849 if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
850 sys_tmp = TMPDIR_DEFAULT;
851 }
852
853 template = g_build_filename (sys_tmp, "mc-XXXXXX", (char *) NULL);
854 g_strlcpy (buffer, template, sizeof (buffer));
855 g_free (template);
856
857 tmpdir = g_mkdtemp (buffer);
858 if (tmpdir != NULL)
859 g_setenv ("MC_TMPDIR", tmpdir, TRUE);
860 else
861 {
862 fprintf (stderr,
863 _ ("Cannot create temporary directory %s: %s.\n"
864 "Temporary files will not be created\n"),
865 buffer, unix_error_string (errno));
866 g_snprintf (buffer, sizeof (buffer), "%s", "/dev/null/");
867 fprintf (stderr, "%s\n", _ ("Press any key to continue..."));
868 getc (stdin);
869 }
870
871 return tmpdir;
872 }
873
874