2 * Shared code between the fish.c and the ftp.c file systems
4 * Actually, this code is not being used by fish.c any more :-).
6 * Namespace pollution: X_hint_reread, X_flushdir.
8 static int store_file (struct direntry
*fe
);
9 static int retrieve_file (struct direntry
*fe
);
10 static int remove_temp_file (char *file_name
);
11 static struct dir
*retrieve_dir (struct connection
*bucket
,
13 int resolve_symlinks
);
14 static void my_forget (char *path
);
16 static int linear_start (struct direntry
*fe
, int from
);
17 static int linear_read (struct direntry
*fe
, void *buf
, int len
);
18 static void linear_close (struct direntry
*fe
);
21 select_on_two (int fd1
, int fd2
)
24 struct timeval timeout
;
26 int maxfd
= (fd1
> fd2
? fd1
: fd2
) + 1;
33 v
= select (maxfd
, &set
, 0, 0, &timeout
);
36 if (FD_ISSET (fd1
, &set
))
38 if (FD_ISSET (fd2
, &set
))
44 get_line (int sock
, char *buf
, int buf_len
, char term
)
49 for (i
= 0; i
< buf_len
; i
++, buf
++) {
50 if (read(sock
, buf
, sizeof(char)) <= 0)
53 fwrite (buf
, 1, 1, logfile
);
62 while ((status
= read(sock
, &c
, sizeof(c
))) > 0){
64 fwrite (&c
, 1, 1, logfile
);
74 direntry_destructor (void *data
)
76 struct direntry
*fe
= data
;
85 if (fe
->local_filename
) {
86 if (fe
->local_is_temp
) {
87 if (!fe
->local_stat
.st_mtime
)
88 unlink(fe
->local_filename
);
92 if (stat (fe
->local_filename
, &sb
) >=0 &&
93 fe
->local_stat
.st_mtime
== sb
.st_mtime
)
94 unlink (fe
->local_filename
); /* Delete only if it hasn't changed */
97 g_free(fe
->local_filename
);
98 fe
->local_filename
= NULL
;
100 if (fe
->remote_filename
)
101 g_free(fe
->remote_filename
);
108 dir_destructor(void *data
)
110 struct dir
*fd
= data
;
115 g_free(fd
->remote_path
);
116 linklist_destroy(fd
->file_list
, direntry_destructor
);
121 get_line_interruptible (char *buffer
, int size
, int fd
)
126 for (i
= 0; i
< size
-1; i
++) {
127 n
= read (fd
, buffer
+i
, 1);
128 if (n
== -1 && errno
== EINTR
){
136 if (buffer
[i
] == '\n'){
146 free_bucket (void *data
)
148 struct connection
*bucket
= data
;
150 g_free(qhost(bucket
));
151 g_free(quser(bucket
));
153 g_free(qcdir(bucket
));
155 g_free(qhome(bucket
));
157 g_free(qupdir(bucket
));
158 if (bucket
->password
)
159 wipe_password (bucket
->password
);
160 linklist_destroy(qdcache(bucket
), dir_destructor
);
166 connection_destructor(void *data
)
168 connection_close (data
);
173 flush_all_directory(struct connection
*bucket
)
175 linklist_delete_all(qdcache(bucket
), dir_destructor
);
178 static void X_fill_names (vfs
*me
, void (*func
)(char *))
180 struct linklist
*lptr
;
182 struct connection
*bucket
;
184 if (!connections_list
)
186 lptr
= connections_list
;
188 if ((bucket
= lptr
->data
) != 0){
190 path_name
= g_strconcat ( X_myname
, quser (bucket
),
192 qcdir(bucket
), NULL
);
197 } while (lptr
!= connections_list
);
201 * makes BUCKET point to the connection bucket descriptor for PATH
202 * returns a malloced string with the pathname relative to BUCKET.
204 * path must _not_ contain initial /bla/#ftp:
207 s_get_path (struct connection
**bucket
, char *path
, char *name
)
209 char *user
, *host
, *remote_path
, *pass
;
213 if (strncmp (path
, name
, strlen (name
)))
214 return NULL
; /* Normal: consider cd /bla/#ftp */
216 if (!(path
= strstr (path
, name
)))
219 path
+= strlen (name
);
221 if (!(remote_path
= my_get_host_and_username (path
, &host
, &user
, &port
, &pass
)))
224 if ((*bucket
= open_link (host
, user
, port
, pass
)) == NULL
) {
225 g_free (remote_path
);
234 wipe_password (pass
);
239 /* NOTE: Usage of tildes is deprecated, consider:
240 * cd /#ftp:pavel@hobit
242 * And now: what do I want to do? Do I want to go to /home/pavel or to
243 * /#ftp:hobit/home/pavel? I think first has better sense...
246 int f
= !strcmp( remote_path
, "/~" );
247 if (f
|| !strncmp( remote_path
, "/~/", 3 )) {
249 s
= concat_dir_and_file( qhome (*bucket
), remote_path
+3-f
);
250 g_free (remote_path
);
260 force_expiration
= 1;
265 s_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
268 case MCCTL_REMOVELOCALCOPY
:
269 return remove_temp_file (path
);
271 case MCCTL_FORGET_ABOUT
:
278 static struct direntry
*
279 _get_file_entry(struct connection
*bucket
, char *file_name
,
283 struct direntry
*ent
;
284 struct linklist
*file_list
, *lptr
;
288 p
= strrchr(file_name
, '/');
291 dcache
= retrieve_dir(bucket
, *file_name
? file_name
: "/", op
& DO_RESOLVE_SYMLINK
);
294 file_list
= dcache
->file_list
;
298 for (lptr
= file_list
->next
; lptr
!= file_list
; lptr
= lptr
->next
) {
300 if (strcmp(p
, ent
->name
) == 0) {
301 if (S_ISLNK(ent
->s
.st_mode
) && (op
& DO_RESOLVE_SYMLINK
)) {
302 if (ent
->l_stat
== NULL
) ERRNOR (ENOENT
, NULL
);
303 if (S_ISLNK(ent
->l_stat
->st_mode
)) ERRNOR (ELOOP
, NULL
);
305 if (ent
&& (op
& DO_OPEN
)) {
308 fmode
= S_ISLNK(ent
->s
.st_mode
)
309 ? ent
->l_stat
->st_mode
311 if (S_ISDIR(fmode
)) ERRNOR (EISDIR
, NULL
);
312 if (!S_ISREG(fmode
)) ERRNOR (EPERM
, NULL
);
313 if ((flags
& O_EXCL
) && (flags
& O_CREAT
)) ERRNOR (EEXIST
, NULL
);
314 if (ent
->remote_filename
== NULL
)
315 if (!(ent
->remote_filename
= g_strdup(file_name
))) ERRNOR (ENOMEM
, NULL
);
316 if (ent
->local_filename
== NULL
||
317 !ent
->local_stat
.st_mtime
||
318 stat (ent
->local_filename
, &sb
) < 0 ||
319 sb
.st_mtime
!= ent
->local_stat
.st_mtime
) {
322 if (ent
->local_filename
){
323 g_free (ent
->local_filename
);
324 ent
->local_filename
= NULL
;
326 if (flags
& O_TRUNC
) {
327 ent
->local_filename
= tempnam (NULL
, X
"fs");
328 if (ent
->local_filename
== NULL
) ERRNOR (ENOMEM
, NULL
);
329 handle
= open(ent
->local_filename
, O_CREAT
| O_TRUNC
| O_RDWR
| O_EXCL
, 0600);
330 if (handle
< 0) ERRNOR (EIO
, NULL
);
332 if (stat (ent
->local_filename
, &ent
->local_stat
) < 0)
333 ent
->local_stat
.st_mtime
= 0;
336 if (IS_LINEAR(flags
)) {
337 ent
->local_is_temp
= 0;
338 ent
->local_filename
= NULL
;
339 ent
->linear_state
= LS_LINEAR_CLOSED
;
342 if (!retrieve_file(ent
))
346 else if (flags
& O_TRUNC
) {
347 truncate(ent
->local_filename
, 0);
353 if ((op
& DO_OPEN
) && (flags
& O_CREAT
)) {
356 ent
= g_new (struct direntry
, 1);
357 ent
->freshly_created
= 0;
358 if (ent
== NULL
) ERRNOR (ENOMEM
, NULL
);
360 ent
->linkname
= NULL
;
362 ent
->bucket
= bucket
;
363 ent
->name
= g_strdup(p
);
364 ent
->remote_filename
= g_strdup(file_name
);
365 ent
->local_filename
= tempnam (NULL
, X
"fs");
366 if (!ent
->name
&& !ent
->remote_filename
&& !ent
->local_filename
) {
367 direntry_destructor(ent
);
368 ERRNOR (ENOMEM
, NULL
);
370 handle
= creat(ent
->local_filename
, 0700);
375 fstat(handle
, &ent
->s
);
378 /* This is very wrong - like this a zero length file will be always created
379 and usually preclude uploading anything more desirable */
380 #if defined(UPLOAD_ZERO_LENGTH_FILE)
381 if (!store_file(ent
)) goto error
;
384 if (!linklist_insert(file_list
, ent
)) {
388 ent
->freshly_created
= 1;
391 else ERRNOR (ENOENT
, NULL
);
393 direntry_destructor(ent
);
398 /* this just free's the local temp file. I don't know if the
399 remote file can be used after this without crashing - paul
400 psheer@obsidian.co.za psheer@icon.co.za */
402 remove_temp_file (char *file_name
)
405 struct connection
*bucket
;
406 struct direntry
*ent
;
407 struct linklist
*file_list
, *lptr
;
410 if (!(file_name
= get_path (&bucket
, file_name
)))
412 p
= strrchr (file_name
, '/');
415 dcache
= retrieve_dir (bucket
, *file_name
? file_name
: "/", 0);
418 file_list
= dcache
->file_list
;
422 for (lptr
= file_list
->next
; lptr
!= file_list
; lptr
= lptr
->next
) {
424 if (strcmp (p
, ent
->name
) == 0) {
425 if (ent
->local_filename
) {
426 unlink (ent
->local_filename
);
427 g_free (ent
->local_filename
);
428 ent
->local_filename
= NULL
;
436 static struct direntry
*
437 get_file_entry(char *path
, int op
, int flags
)
439 struct connection
*bucket
;
443 if (!(remote_path
= get_path (&bucket
, path
)))
445 fe
= _get_file_entry(bucket
, remote_path
, op
,
449 if (op
& DO_FREE_RESOURCE
)
450 vfs_add_noncurrent_stamps (&vfs_X_ops
, (vfsid
) bucket
, NULL
);
456 #define OPT_IGNORE_ERROR 2
458 static int normal_flush
= 1;
460 void X_hint_reread(int reread
)
472 unsigned int has_changed
:1;
477 static void *s_open (vfs
*me
, char *file
, int flags
, int mode
)
482 fp
= g_new (struct filp
, 1);
483 if (fp
== NULL
) ERRNOR (ENOMEM
, NULL
);
484 fe
= get_file_entry(file
, DO_OPEN
| DO_RESOLVE_SYMLINK
, flags
);
489 fe
->linear_state
= IS_LINEAR(flags
);
490 if (!fe
->linear_state
) {
491 fp
->local_handle
= open(fe
->local_filename
, flags
, mode
);
492 if (fp
->local_handle
< 0) {
494 ERRNOR (errno
, NULL
);
496 } else fp
->local_handle
= -1;
497 #ifdef UPLOAD_ZERO_LENGTH_FILE
498 fp
->has_changed
= fe
->freshly_created
;
508 static int s_read (void *data
, char *buffer
, int count
)
514 if (fp
->fe
->linear_state
== LS_LINEAR_CLOSED
) {
515 print_vfs_message ("Starting linear transfer...");
516 if (!linear_start (fp
->fe
, 0))
520 if (fp
->fe
->linear_state
== LS_LINEAR_CLOSED
)
521 vfs_die ("linear_start() did not set linear_state!");
523 if (fp
->fe
->linear_state
== LS_LINEAR_OPEN
)
524 return linear_read (fp
->fe
, buffer
, count
);
526 n
= read (fp
->local_handle
, buffer
, count
);
532 static int s_write (void *data
, char *buf
, int nbyte
)
534 struct filp
*fp
= data
;
537 if (fp
->fe
->linear_state
)
538 vfs_die ("You may not write to linear file");
539 n
= write (fp
->local_handle
, buf
, nbyte
);
546 static int s_close (void *data
)
548 struct filp
*fp
= data
;
551 if (fp
->has_changed
) {
552 if (!store_file(fp
->fe
))
555 flush_all_directory(fp
->fe
->bucket
);
557 if (fp
->fe
->linear_state
== LS_LINEAR_OPEN
)
558 linear_close(fp
->fe
);
559 if (fp
->local_handle
>= 0)
560 close(fp
->local_handle
);
561 qlock(fp
->fe
->bucket
)--;
562 direntry_destructor(fp
->fe
);
567 static int s_errno (vfs
*me
)
574 * On some operating systems (Slowaris 2 for example)
575 * the d_name member is just a char long (nice trick that break everything),
576 * so we need to set up some space for the filename.
580 #ifdef NEED_EXTRA_DIRENT_BUFFER
581 char extra_buffer
[MC_MAXPATHLEN
];
583 struct linklist
*pos
;
587 /* Possible FIXME: what happens if one directory is opened twice ? */
589 static void *s_opendir (vfs
*me
, char *dirname
)
591 struct connection
*bucket
;
593 struct my_dirent
*dirp
;
595 if (!(remote_path
= get_path (&bucket
, dirname
)))
597 dirp
= g_new (struct my_dirent
, 1);
602 dirp
->dcache
= retrieve_dir(bucket
, remote_path
, 1);
603 if (dirp
->dcache
== NULL
)
605 dirp
->pos
= dirp
->dcache
->file_list
->next
;
607 dirp
->dcache
->count
++;
610 vfs_add_noncurrent_stamps (&vfs_X_ops
, (vfsid
) bucket
, NULL
);
616 static void *s_readdir (void *data
)
619 struct my_dirent
*dirp
= data
;
621 if (dirp
->pos
== dirp
->dcache
->file_list
)
623 fe
= dirp
->pos
->data
;
624 strcpy (&(dirp
->dent
.d_name
[0]), fe
->name
);
625 #ifndef DIRENT_LENGTH_COMPUTED
626 dirp
->d_namlen
= strlen (dirp
->d_name
);
628 dirp
->pos
= dirp
->pos
->next
;
629 return (void *) &dirp
->dent
;
632 static int s_telldir (void *data
)
634 struct my_dirent
*dirp
= data
;
635 struct linklist
*pos
;
638 pos
= dirp
->dcache
->file_list
->next
;
639 while( pos
!=dirp
->dcache
->file_list
) {
640 if (pos
== dirp
->pos
)
648 static void s_seekdir (void *data
, int pos
)
650 struct my_dirent
*dirp
= data
;
653 dirp
->pos
= dirp
->dcache
->file_list
->next
;
654 for (i
=0; i
<pos
; i
++)
658 static int s_closedir (void *info
)
660 struct my_dirent
*dirp
= info
;
661 dir_destructor(dirp
->dcache
);
666 static int s_lstat (vfs
*me
, char *path
, struct stat
*buf
)
670 fe
= get_file_entry(path
, DO_FREE_RESOURCE
, 0);
679 static int s_stat (vfs
*me
, char *path
, struct stat
*buf
)
683 fe
= get_file_entry(path
, DO_RESOLVE_SYMLINK
| DO_FREE_RESOURCE
, 0);
685 if (!S_ISLNK(fe
->s
.st_mode
))
695 static int s_fstat (void *data
, struct stat
*buf
)
697 struct filp
*fp
= data
;
699 if (!S_ISLNK(fp
->fe
->s
.st_mode
))
702 *buf
= *fp
->fe
->l_stat
;
706 static int s_readlink (vfs
*me
, char *path
, char *buf
, int size
)
710 fe
= get_file_entry(path
, DO_FREE_RESOURCE
, 0);
713 if (!S_ISLNK(fe
->s
.st_mode
)) ERRNOR (EINVAL
, -1);
714 if (fe
->linkname
== NULL
) ERRNOR (EACCES
, -1);
715 if (strlen(fe
->linkname
) >= size
) ERRNOR (ERANGE
, -1);
716 strncpy(buf
, fe
->linkname
, size
);
717 return strlen(fe
->linkname
);
720 static int s_chdir (vfs
*me
, char *path
)
723 struct connection
*bucket
;
725 if (!(remote_path
= get_path(&bucket
, path
)))
728 g_free(qcdir(bucket
));
729 qcdir(bucket
) = remote_path
;
730 bucket
->cwd_defered
= 1;
732 vfs_add_noncurrent_stamps (&vfs_X_ops
, (vfsid
) bucket
, NULL
);
736 static int s_lseek (void *data
, off_t offset
, int whence
)
738 struct filp
*fp
= data
;
740 if (fp
->fe
->linear_state
== LS_LINEAR_OPEN
)
741 vfs_die ("You promissed not to seek!");
742 if (fp
->fe
->linear_state
== LS_LINEAR_CLOSED
) {
743 print_vfs_message ("Preparing reget...");
744 if (whence
!= SEEK_SET
)
745 vfs_die ("You may not do such seek on linear file");
746 if (!linear_start (fp
->fe
, offset
))
750 return lseek(fp
->local_handle
, offset
, whence
);
753 static vfsid
s_getid (vfs
*me
, char *p
, struct vfs_stamping
**parent
)
755 struct connection
*bucket
;
758 *parent
= NULL
; /* We are not enclosed in any other fs */
760 if (!(remote_path
= get_path (&bucket
, p
)))
764 return (vfsid
) bucket
;
768 static int s_nothingisopen (vfsid id
)
770 return qlock((struct connection
*)id
) == 0;
773 static void s_free (vfsid id
)
775 struct connection
*bucket
= (struct connection
*) id
;
777 connection_destructor(bucket
);
778 linklist_delete(connections_list
, bucket
);
781 static char *s_getlocalcopy (vfs
*me
, char *path
)
783 struct filp
*fp
= (struct filp
*) s_open (me
, path
, O_RDONLY
, 0);
788 if (fp
->fe
->local_filename
== NULL
) {
789 s_close ((void *) fp
);
792 p
= g_strdup (fp
->fe
->local_filename
);
793 qlock(fp
->fe
->bucket
)++;
795 s_close ((void *) fp
);
799 static void s_ungetlocalcopy (vfs
*me
, char *path
, char *local
, int has_changed
)
801 struct filp
*fp
= (struct filp
*) s_open (me
, path
, O_WRONLY
, 0);
805 if (!strcmp (fp
->fe
->local_filename
, local
)) {
806 fp
->has_changed
= has_changed
;
807 qlock(fp
->fe
->bucket
)--;
808 direntry_destructor(fp
->fe
);
809 s_close ((void *) fp
);
811 /* Should not happen */
812 s_close ((void *) fp
);
813 mc_def_ungetlocalcopy (me
, path
, local
, has_changed
);
820 linklist_destroy(connections_list
, connection_destructor
);
821 connections_list
= NULL
;
827 static int retrieve_file(struct direntry
*fe
)
829 /* If you want reget, you'll have to open file with O_LINEAR */
833 int stat_size
= fe
->s
.st_size
;
835 if (fe
->local_filename
)
837 if (!(fe
->local_filename
= tempnam (NULL
, X
))) ERRNOR (ENOMEM
, 0);
838 fe
->local_is_temp
= 1;
840 local_handle
= open(fe
->local_filename
, O_RDWR
| O_CREAT
| O_TRUNC
| O_EXCL
, 0600);
841 if (local_handle
== -1) {
846 if (!linear_start (fe
, 0))
849 /* Clear the interrupt status */
850 enable_interrupt_key ();
853 if ((n
= linear_read(fe
, buffer
, sizeof(buffer
))) < 0)
859 vfs_print_stats (X
, "Getting file", fe
->remote_filename
, total
, stat_size
);
861 while (write(local_handle
, buffer
, n
) < 0) {
862 if (errno
== EINTR
) {
863 if (got_interrupt()) {
875 disable_interrupt_key();
878 if (stat (fe
->local_filename
, &fe
->local_stat
) < 0)
879 fe
->local_stat
.st_mtime
= 0;
886 disable_interrupt_key();
888 unlink(fe
->local_filename
);
890 g_free(fe
->local_filename
);
891 fe
->local_filename
= NULL
;