diff --git a/vfs/ChangeLog b/vfs/ChangeLog index 01f0129d8..6fde9c7ea 100644 --- a/vfs/ChangeLog +++ b/vfs/ChangeLog @@ -1,3 +1,11 @@ +Mon Sep 21 11:40:30 1998 Pavel Machek + + * ftpfs.c, fish.c: added O_LINEAR mode to handle linear read of + files in sane way. copy_file_file will make temporary files for a + while (fix pending). + + * tar.c: fixed bzip/bzip2 compressed archives + Wed Sep 18 12:51:51 1998 Pavel Machek * fish.c, vfs.c: created aliases /#ssh: and /#rsh: diff --git a/vfs/Makefile.in b/vfs/Makefile.in index 557e1bdc0..2761cbee9 100644 --- a/vfs/Makefile.in +++ b/vfs/Makefile.in @@ -29,7 +29,7 @@ VFSHDRS = vfs.h mcfs.h tcputil.h tar.h container.h ftpfs.h names.h \ VFSOBJS = $(NONETFILES) @NETFILES@ EXTFS_MISC = README extfs.ini -EXTFS_CONST = a rpm hp48 mailfs patchfs +EXTFS_CONST = a rpm hp48 mailfs patchfs sfs.ini EXTFS_IN = deb.in lslR.in ucpio.in urar.in uzoo.in ftplist.in uar.in \ ulha.in uzip.in EXTFS_OUT = deb lslR ucpio urar uzoo ftplist uar ulha uzip diff --git a/vfs/README.fish b/vfs/README.fish index 31443f7c2..9b723c618 100644 --- a/vfs/README.fish +++ b/vfs/README.fish @@ -66,12 +66,12 @@ Server should reply with current directory (in form /abc/def/ghi) followed by line indicating success. #LIST /directory -ls -lLga $1 | grep '^[^cbt]' | ( while read p x u g s m d y n; do echo "P$p $u.$g +ls -lLa $1 | grep '^[^cbt]' | ( while read p x u g s m d y n; do echo "P$p $u.$g S$s d$m $d $y :$n "; done ) -ls -lLga $1 | grep '^[cb]' | ( while read p x u g a i m d y n; do echo "P$p $u.$g +ls -lLa $1 | grep '^[cb]' | ( while read p x u g a i m d y n; do echo "P$p $u.$g E$a$i dD$m $d $y :$n @@ -103,7 +103,7 @@ case). As you've probably noticed, this is pretty broken; it is for compatibility with ls listing. #RETR /some/name -ls -lg /some/name | ( read a b c d x e; echo $x ); echo '### 100'; cat /some/name; echo '### 200' +ls -l /some/name | ( read a b c d x e; echo $x ); echo '### 100'; cat /some/name; echo '### 200' Server sends line with filesize on it, followed by line with ### 100 indicating partial success, then it sends binary data (exactly diff --git a/vfs/extfs.h b/vfs/extfs.h index 2a2dae560..8f666f336 100644 --- a/vfs/extfs.h +++ b/vfs/extfs.h @@ -72,7 +72,6 @@ void extfs_fill_names (void (*func)(char *)); int extfs_prefix_to_type (char *path); char *extfs_get_prefix (int fstype); char *extfs_analysis (char *path, char **arc_name, int *fstype, int is_dir); -int extfs_which (char *path); void extfs_run (char *path); void extfs_done (void); diff --git a/vfs/extfs/sfs.ini b/vfs/extfs/sfs.ini index 61b979523..988c19ecc 100644 --- a/vfs/extfs/sfs.ini +++ b/vfs/extfs/sfs.ini @@ -2,7 +2,11 @@ # This is config for Single File fileSystem # gz/1 gzip < %1 > %3 -ugz/1 gzip -d < %1 > %3 +ugz/1 gzip -cdf < %1 > %3 +bz/1 bzip < %1 > %3 +ubz/1 bzip -d < %1 > %3 +bz2/1 bzip2 < %1 > %3 +ubz2/1 bzip2 -d < %1 > %3 tar/1 tar cf %3 %1 tgz/1 tar czf %3 %1 uhtml/1 lynx -force_html -dump %1 > %3 diff --git a/vfs/fish.c b/vfs/fish.c index 04ffb5d71..0ce4c4a9e 100644 --- a/vfs/fish.c +++ b/vfs/fish.c @@ -628,187 +628,81 @@ error_return: return 0; } -/* For _ctl routine */ -static int remotelocal_handle, remoten = 0, remotestat_size; +static int linear_start(struct direntry *fe) +{ + fe->local_stat.st_mtime = 0; + if (command(fe->bucket, WANT_STRING, + "#RETR %s\nls -l %s | ( read var1 var2 var3 var4 var5 var6; echo $var5 ); echo '### 100'; cat %s; echo '### 200'\n", + fe->remote_filename, fe->remote_filename, fe->remote_filename ) + != PRELIM) ERRNOR (EACCES, 0); + + fe->got = 0; + fe->total = atoi(reply_str); + return 1; +} static void -fish_abort (struct connection *bucket) +linear_abort (struct direntry *fe) { + char buffer[8192]; int n; print_vfs_message( "Aborting transfer..." ); do { - n = remotestat_size - remotetotal; - n = (n>8192) ? 8192:n; + n = MIN(8192, fe->total - fe->got); if (n) - if ((n = read(qsockr(remoteent->bucket), remotebuffer, n)) < 0) + if ((n = read(qsockr(fe->bucket), buffer, n)) < 0) return; } while (n); - if (get_reply (qsockr(remoteent->bucket), NULL, 0) != COMPLETE) + if (get_reply (qsockr(fe->bucket), NULL, 0) != COMPLETE) print_vfs_message( "Error reported after abort." ); else print_vfs_message( "Aborted transfer would be successfull." ); } -static int retrieve_file_start(struct direntry *fe) +static int +linear_read (struct direntry *fe, void *buf, int len) { - if (fe->local_filename == NULL) - ERRNOR (ENOMEM, 0); - if (command(fe->bucket, WANT_STRING, - "#RETR %s\nls -l %s | ( read var1 var2 var3 var4 var5 var6; echo $var5 ); echo '### 100'; cat %s; echo '### 200'\n", - fe->remote_filename, fe->remote_filename, fe->remote_filename ) - != PRELIM) ERRNOR (EPERM, 0); - - remotestat_size = atoi(reply_str); - - remotetotal = 0; - remoteent = fe; - return 1; -} - -static int retrieve_file_start2(struct direntry *fe) -{ - remotebuffer = xmalloc (8192, "retrieve_file"); - remotelocal_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600); - if (remotelocal_handle == -1) { - fish_abort(remoteent->bucket); - free(remotebuffer); - free(fe->local_filename); - fe->local_filename = NULL; - fe->local_is_temp = 1; - ERRNOR (EIO, 0); + int n = 0; + len = MIN( fe->total - fe->got, len ); + while (len && ((n = read (qsockr(fe->bucket), buf, len))<0)) { + if ((errno == EINTR) && !got_interrupt()) + continue; + break; } - return 1; + if (n>0) fe->got += n; + if (n<0) linear_abort(fe); + if ((!n) && ((get_reply (qsockr (fe->bucket), NULL, 0) != COMPLETE))) + ERRNOR (EIO, -1); + ERRNOR (errno, n); +} + +static int +linear_close (struct direntry *fe) +{ + if (fe->total != fe->got) + linear_abort(fe); } int fish_ctl (void *data, int ctlop, int arg) { int n = 0; - + struct filp *fp = data; + int v; switch (ctlop) { - case MCCTL_ISREMOTECOPY: - return isremotecopy; - - case MCCTL_REMOTECOPYCHUNK: - if (!transfer_started) - if (!retrieve_file_start2 (remoteent)){ - return MCERR_TARGETOPEN; - } else - transfer_started = 1; - - enable_interrupt_key (); - if (!remoten) { - int v = select_on_two (qsockr(remoteent->bucket), 0); + case MCCTL_IS_NOTREADY: + { + int v = select_on_two (qsockr(fp->fe->bucket), 0); - if (((v < 0) && (errno == EINTR)) || v == 0){ - disable_interrupt_key (); - return MCERR_DATA_ON_STDIN; - } - - n = remotestat_size - remotetotal; - n = (n>8192) ? 8192:n; - if (n) - if ((n = read(qsockr(remoteent->bucket), remotebuffer, n)) < 0){ - disable_interrupt_key (); - if (errno == EINTR) - return MCERR_DATA_ON_STDIN; - else - return MCERR_READ; - } - if (!n) { - if (get_reply (qsockr(remoteent->bucket), NULL, 0) != COMPLETE) - my_errno = EIO; - close(remotelocal_handle); - if (localname){ - free (localname); - localname = NULL; - } - disable_interrupt_key (); - transfer_started = 0; - return MCERR_FINISH; - } - disable_interrupt_key (); - remotetotal += n; - remoten = n; - } else - n = remoten; - if (write(remotelocal_handle, remotebuffer, remoten) < 0) - return MCERR_WRITE; - remoten = 0; - return n; - - /* We get this message if the transfer was aborted */ - case MCCTL_FINISHREMOTE: - if (localname) { - free (localname); - localname = NULL; + if (((v < 0) && (errno == EINTR)) || v == 0) + return 1; + return 0; } - if (!arg) { /* OK */ - if (stat (remoteent->local_filename, &remoteent->local_stat) < 0) - remoteent->local_stat.st_mtime = 0; - } else - remoteent->local_stat.st_mtime = 0; - transfer_started = 0; - fish_abort (remoteent->bucket); - my_errno = EINTR; + default: + return 0; } - return 0; -} - -static int retrieve_file(struct direntry *fe) -{ - if (fe->local_filename) - return 1; - fe->local_stat.st_mtime = 0; - fe->local_filename = tempnam (NULL, "fish"); - fe->local_is_temp = 1; - isremotecopy = 0; - - my_errno = ENOMEM; - if (!fe->local_filename || - !retrieve_file_start(fe)) - return 0; - - /* Clear the interrupt status */ - enable_interrupt_key (); - my_errno = 0; - - while (1) { - int res; - - res = fish_ctl(NULL, MCCTL_REMOTECOPYCHUNK, 0 ); - if ((res == MCERR_TARGETOPEN) || - (res == MCERR_WRITE) || - (res == MCERR_DATA_ON_STDIN) || - (res == MCERR_READ)) { - my_errno = EIO; - break; - } - if (res == MCERR_FINISH) - break; - - if (remotestat_size == 0) - print_vfs_message ("fish: Getting file: %ld bytes transfered", - remotetotal); - else - print_vfs_message ("fish: Getting file: %3d%% (%ld bytes transfered)", - remotetotal*100/remotestat_size, remotetotal); - } - - if (my_errno) { - disable_interrupt_key (); - fish_abort( remoteent->bucket ); - unlink(fe->local_filename); - free(fe->local_filename); - fe->local_filename = NULL; - return 0; - } - - if (stat (fe->local_filename, &fe->local_stat) < 0) - fe->local_stat.st_mtime = 0; - return 1; } static int diff --git a/vfs/fish.h b/vfs/fish.h index 0d3a437d8..9af85d0c4 100644 --- a/vfs/fish.h +++ b/vfs/fish.h @@ -11,12 +11,16 @@ struct direntry char *local_filename; int local_is_temp:1; int freshly_created:1; + int linear:1; struct stat local_stat; char *remote_filename; struct stat s; struct stat *l_stat; struct connection *bucket; + int tmp_reget; + + int got, total; /* Bytes transfered / bytes need to be transfered */ }; struct dir diff --git a/vfs/ftpfs.c b/vfs/ftpfs.c index 8a5a70fc3..8e2a03a99 100644 --- a/vfs/ftpfs.c +++ b/vfs/ftpfs.c @@ -994,7 +994,7 @@ open_data_connection (struct connection *bucket, char *cmd, char *remote, } static void -ftpfs_abort (struct connection *bucket, int dsock) +my_abort (struct connection *bucket, int dsock) { static unsigned char ipbuf[3] = { IAC, IP, IAC }; fd_set mask; @@ -1240,9 +1240,9 @@ retrieve_dir(struct connection *bucket, char *remote_path, int resolve_symlinks) disable_interrupt_key(); print_vfs_message("ftpfs: reading FTP directory interrupt by user"); #ifdef OLD_READ - ftpfs_abort(bucket, fileno(fp)); + my_abort(bucket, fileno(fp)); #else - ftpfs_abort(bucket, sock); + my_abort(bucket, sock); #endif close_this_sock(fp, sock); my_errno = EINTR; @@ -1369,212 +1369,69 @@ error_return: return 0; } -/* For _ctl routine */ -static int remotelocal_handle, remotesock, remoten, remotestat_size; - -static int retrieve_file_start(struct direntry *fe) +static int +linear_start(struct direntry *fe) { - if (fe->local_filename == NULL) ERRNOR (ENOMEM, 0); - remotesock = open_data_connection(fe->bucket, "RETR", fe->remote_filename, TYPE_BINARY); - if (remotesock == -1) { - my_errno = EACCES; - free (fe->local_filename); - fe->local_filename = NULL; - return 0; - } - remotetotal = 0; - remoteent = fe; + fe->local_stat.st_mtime = 0; + fe->data_sock = open_data_connection(fe->bucket, "RETR", fe->remote_filename, TYPE_BINARY); + if (fe->data_sock == -1) + ERRNOR (EACCES, 0); return 1; } -static int retrieve_file_start2(struct direntry *fe) +static int +linear_abort (struct direntry *fe) { - remotelocal_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC, 0600); - if (remotelocal_handle == -1) { - my_errno = EIO; - free(fe->local_filename); - fe->local_filename = NULL; - fe->local_is_temp = 1; - close(remotesock); - return 0; + my_abort(fe->bucket, fe->data_sock); + fe->data_sock = -1; +} + +static int +linear_read (struct direntry *fe, void *buf, int len) +{ + int n; + while ((n = read (fe->data_sock, buf, len))<0) { + if ((errno == EINTR) && !got_interrupt()) + continue; + break; } - remotestat_size = fe->s.st_size; - remotebuffer = xmalloc (8192, ""); - return 1; + + if (n<0) linear_abort(fe); + + if (!n) { + if ((get_reply (qsock (fe->bucket), NULL, 0) != COMPLETE)) { + my_errno = EIO; + n=-1; + } + fe->data_sock = -1; + } + ERRNOR (errno, n); +} + +static int +linear_close (struct direntry *fe) +{ + if (fe->data_sock != -1) + linear_abort(fe); } int ftpfs_ctl (void *data, int ctlop, int arg) { int n = 0; - + struct filp *fp = data; + int v; switch (ctlop) { - case MCCTL_ISREMOTECOPY: - return isremotecopy; - - case MCCTL_REMOTECOPYCHUNK: - if (!transfer_started) - if (!retrieve_file_start2 (remoteent)){ - return MCERR_TARGETOPEN; - } else - transfer_started = 1; - - enable_interrupt_key (); - if (!remoten) { - int v = select_on_two (remotesock, 0); + case MCCTL_IS_NOTREADY: + { + int v = select_on_two (fp->fe->data_sock, 0); - if (((v < 0) && (errno == EINTR)) || v == 0){ - disable_interrupt_key (); - return MCERR_DATA_ON_STDIN; - } - - if ((n = read(remotesock, remotebuffer, 8192)) < 0){ - disable_interrupt_key (); - if (errno == EINTR) - return MCERR_DATA_ON_STDIN; - else - return MCERR_READ; - } - if (n == 0) { - if (get_reply (qsock (remoteent->bucket), NULL, 0) != COMPLETE) { - my_errno = EIO; - } - close(remotelocal_handle); - close(remotesock); - if (localname){ - free (localname); - localname = NULL; - } - disable_interrupt_key (); - transfer_started = 0; - return MCERR_FINISH; - } - disable_interrupt_key (); - remotetotal += n; - remoten = n; - } else - n = remoten; - if (write(remotelocal_handle, remotebuffer, remoten) < 0) - return MCERR_WRITE; - remoten = 0; - return n; - - /* We get this message if the transfer was aborted */ - case MCCTL_FINISHREMOTE: - if (localname) { - free (localname); - localname = NULL; + if (((v < 0) && (errno == EINTR)) || v == 0) + return 1; + return 0; } - if (!arg) { /* OK */ - if (stat (remoteent->local_filename, &remoteent->local_stat) < 0) - remoteent->local_stat.st_mtime = 0; - } else - remoteent->local_stat.st_mtime = 0; - transfer_started = 0; - ftpfs_abort (remoteent->bucket, remotesock); - my_errno = EINTR; + default: return 0; } - return 0; -} - -static int retrieve_file(struct direntry *fe) -{ - int total, tmp_reget = do_reget; - char buffer[8192]; - int local_handle, sock, n; - - if (fe->local_filename) - return 1; - fe->local_stat.st_mtime = 0; - fe->local_filename = tempnam (NULL, "ftpfs"); - fe->local_is_temp = 1; - if (fe->local_filename == NULL) ERRNOR (ENOMEM, 0); - local_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600); - if (local_handle == -1) { - my_errno = EIO; - free(fe->local_filename); - fe->local_filename = NULL; - return 0; - } - sock = open_data_connection(fe->bucket, "RETR", fe->remote_filename, TYPE_BINARY); - if (sock == -1) { - my_errno = EACCES; - goto error_3; - } - - /* Clear the interrupt status */ - enable_interrupt_key (); - total = 0; - if (tmp_reget > 0) - total = tmp_reget; - else - total = 0; - - while (1) { - int stat_size = fe->s.st_size; - while ((n = read(sock, buffer, sizeof(buffer))) < 0) { - if (errno == EINTR) { - if (got_interrupt ()) { - disable_interrupt_key(); - ftpfs_abort(fe->bucket, sock); - my_errno = EINTR; - goto error_2; - } - else - continue; - } - my_errno = errno; - disable_interrupt_key(); - goto error_1; - } - if (n == 0) - break; - total += n; - if (stat_size == 0) - print_vfs_message ("ftpfs: Getting file: %ld bytes transfered", - total); - else - print_vfs_message ("ftpfs: Getting file: %3d%% (%ld bytes transfered)", - total*100/stat_size, total); - while (write(local_handle, buffer, n) < 0) { - if (errno == EINTR) { - if (got_interrupt()) { - ftpfs_abort(fe->bucket, sock); - my_errno = EINTR; - goto error_2; - } - else - continue; - } - my_errno = errno; - goto error_1; - } - } - close(local_handle); - close(sock); - if (get_reply (qsock (fe->bucket), NULL, 0) != COMPLETE) { - my_errno = EIO; - goto error_2; - } - - if (stat (fe->local_filename, &fe->local_stat) < 0) - fe->local_stat.st_mtime = 0; - - if (tmp_reget > 0) - fe->tmp_reget = 1; - - return 1; -error_1: - get_reply(qsock(fe->bucket), NULL, 0); -error_2: - close(sock); -error_3: - disable_interrupt_key (); - close(local_handle); - unlink(fe->local_filename); - free(fe->local_filename); - fe->local_filename = NULL; - return 0; } static int diff --git a/vfs/ftpfs.h b/vfs/ftpfs.h index 4ea9db7dd..58358a06e 100644 --- a/vfs/ftpfs.h +++ b/vfs/ftpfs.h @@ -8,15 +8,17 @@ struct direntry char *name; int count; char *linkname; - char *local_filename; + char *local_filename, *remote_filename; int local_is_temp:1; int freshly_created:1; + int linear:1; /* Did they promiss not to seek? */ int tmp_reget; struct stat local_stat; - char *remote_filename; struct stat s; struct stat *l_stat; struct connection *bucket; + + int data_sock; /* For linear_ operations */ }; struct dir diff --git a/vfs/local.c b/vfs/local.c index f8466d3a2..d143a1715 100644 --- a/vfs/local.c +++ b/vfs/local.c @@ -23,7 +23,7 @@ static void *local_open (char *file, int flags, int mode) int *local_info; int fd; - fd = open (file, flags, mode); + fd = open (file, NO_LINEAR(flags), mode); if (fd == -1) return 0; diff --git a/vfs/shared_ftp_fish.c b/vfs/shared_ftp_fish.c index ddde19e2b..b44d6fbe6 100644 --- a/vfs/shared_ftp_fish.c +++ b/vfs/shared_ftp_fish.c @@ -3,6 +3,7 @@ static struct dir *retrieve_dir(struct connection *bucket, char *remote_path, in static int store_file(struct direntry *fe); static int retrieve_file_start(struct direntry *fe); static int retrieve_file(struct direntry *fe); +static int remove_temp_file (char *file_name); static int select_on_two (int fd1, int fd2) @@ -188,7 +189,6 @@ void X_fill_names (void (*func)(char *)) } while (lptr != connections_list); } - /* get_path: * makes BUCKET point to the connection bucket descriptor for PATH * returns a malloced string with the pathname relative to BUCKET. @@ -244,31 +244,19 @@ s_get_path (struct connection **bucket, char *path, char *name) return remote_path; } -void X_flushdir (void) +void +X_flushdir (void) { - force_expiration = 1; + force_expiration = 1; } -/* These variables are for the _ctl routine */ -static char *localname = NULL; -static struct direntry *remoteent; -static int remotetotal = 0; -static int transfer_started = 0; -static char *remotebuffer; -static int isremotecopy = 0; -static int remove_temp_file (char *file_name); - -static int s_setctl (char *path, int ctlop, char *arg) +static int +s_setctl (char *path, int ctlop, char *arg) { switch (ctlop) { case MCCTL_REMOVELOCALCOPY: return remove_temp_file (path); - - case MCCTL_SETREMOTECOPY: if (localname) free (localname); - localname = strdup (vfs_canon (arg)); - return 1; - default: return 0; } } @@ -310,10 +298,8 @@ _get_file_entry(struct connection *bucket, char *file_name, if (S_ISDIR(fmode)) ERRNOR (EISDIR, NULL); if (!S_ISREG(fmode)) ERRNOR (EPERM, NULL); if ((flags & O_EXCL) && (flags & O_CREAT)) ERRNOR (EEXIST, NULL); - if (ent->remote_filename == NULL) { - ent->remote_filename = strdup(file_name); - if (ent->remote_filename == NULL) ERRNOR (ENOMEM, NULL); - } + if (ent->remote_filename == NULL) + if (!(ent->remote_filename = strdup(file_name))) ERRNOR (ENOMEM, NULL); if (ent->local_filename == NULL || !ent->local_stat.st_mtime || stat (ent->local_filename, &sb) < 0 || @@ -322,7 +308,7 @@ _get_file_entry(struct connection *bucket, char *file_name, if (ent->local_filename){ free (ent->local_filename); - ent->local_filename = 0; + ent->local_filename = NULL; } if (flags & O_TRUNC) { ent->local_filename = tempnam (NULL, X "fs"); @@ -334,15 +320,11 @@ _get_file_entry(struct connection *bucket, char *file_name, ent->local_stat.st_mtime = 0; } else { - if (localname != NULL) { - isremotecopy = 1; + if (IS_LINEAR(flags)) { ent->local_is_temp = 0; - ent->local_stat.st_mtime = 0; - ent->local_filename = strdup (localname); - if (!retrieve_file_start (ent)) { - isremotecopy = 0; + ent->local_filename = NULL; + if (!linear_start (ent)) return NULL; - } return ent; } if (!retrieve_file(ent)) @@ -405,7 +387,8 @@ error: /* this just free's the local temp file. I don't know if the remote file can be used after this without crashing - paul psheer@obsidian.co.za psheer@icon.co.za */ -static int remove_temp_file (char *file_name) +static int +remove_temp_file (char *file_name) { char *p, q; struct connection *bucket; @@ -439,7 +422,6 @@ static int remove_temp_file (char *file_name) return -1; } - static struct direntry * get_file_entry(char *path, int op, int flags) { @@ -449,7 +431,6 @@ get_file_entry(char *path, int op, int flags) if (!(remote_path = get_path (&bucket, path))) return NULL; - isremotecopy = 0; fe = _get_file_entry(bucket, remote_path, op, flags); free(remote_path); @@ -490,24 +471,23 @@ static void *s_open (char *file, int flags, int mode) fp = xmalloc(sizeof(struct filp), "struct filp"); if (fp == NULL) ERRNOR (ENOMEM, NULL); fe = get_file_entry(file, DO_OPEN | DO_RESOLVE_SYMLINK, flags); - if (fe == NULL) { + if (!fe) { free(fp); return NULL; } - if (!isremotecopy) { + fe->linear = IS_LINEAR(flags); + if (!fe->linear) { fp->local_handle = open(fe->local_filename, flags, mode); if (fp->local_handle < 0) { - my_errno = errno; free(fp); - return NULL; + ERRNOR (errno, NULL); } - } else - fp->local_handle = -1; + } else fp->local_handle = -1; #ifdef UPLOAD_ZERO_LENGTH_FILE fp->has_changed = fe->freshly_created; #else fp->has_changed = 0; -#endif +#endif fp->fe = fe; qlock(fe->bucket)++; fe->count++; @@ -520,9 +500,12 @@ static int s_read (void *data, char *buffer, int count) int n; fp = data; - n = read(fp->local_handle, buffer, count); + if (fp->fe->linear) + return linear_read (fp->fe, buffer, count); + + n = read (fp->local_handle, buffer, count); if (n < 0) - my_errno = errno; + my_errno = errno; return n; } @@ -532,9 +515,9 @@ static int s_write (void *data, char *buf, int nbyte) int n; fp = data; - n = write(fp->local_handle, buf, nbyte); + n = write (fp->local_handle, buf, nbyte); if (n < 0) - my_errno = errno; + my_errno = errno; fp->has_changed = 1; return n; } @@ -550,6 +533,8 @@ static int s_close (void *data) if (normal_flush) flush_all_directory(fp->fe->bucket); } + if (fp->fe->linear) + linear_close(fp->fe); if (fp->local_handle >= 0) close(fp->local_handle); qlock(fp->fe->bucket)--; @@ -801,7 +786,6 @@ static void s_ungetlocalcopy (char *path, char *local, int has_changed) } } - void X_done(void) { @@ -811,3 +795,74 @@ X_done(void) fclose (logfile); logfile = NULL; } + +static int retrieve_file(struct direntry *fe) +{ + int total, tmp_reget = 0; /* do_reget; -- I think it can not work: pavel@ucw.cz */ + char buffer[8192]; + int local_handle, n; + int stat_size = fe->s.st_size; + + if (fe->local_filename) + return 1; + if (!(fe->local_filename = tempnam (NULL, X))) ERRNOR (ENOMEM, 0); + fe->local_is_temp = 1; + + local_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600); + if (local_handle == -1) { + my_errno = EIO; + goto error_4; + } + + if (!linear_start (fe)) + goto error_3; + + /* Clear the interrupt status */ + enable_interrupt_key (); + total = (tmp_reget > 0) ? tmp_reget : 0; + + while (1) { + if ((n = linear_read(fe, buffer, sizeof(buffer))) < 0) + goto error_1; + if (!n) + break; + + total += n; + print_vfs_stats (X, "Getting file", fe->remote_filename, total, stat_size); + + while (write(local_handle, buffer, n) < 0) { + if (errno == EINTR) { + if (got_interrupt()) { + my_errno = EINTR; + goto error_2; + } + else + continue; + } + my_errno = errno; + goto error_1; + } + } + linear_close(fe); + disable_interrupt_key(); + close(local_handle); + + if (stat (fe->local_filename, &fe->local_stat) < 0) + fe->local_stat.st_mtime = 0; + + if (tmp_reget > 0) + fe->tmp_reget = 1; + + return 1; +error_1: +error_2: + linear_close(fe); +error_3: + disable_interrupt_key(); + close(local_handle); + unlink(fe->local_filename); +error_4: + free(fe->local_filename); + fe->local_filename = NULL; + return 0; +} diff --git a/vfs/tar.c b/vfs/tar.c index f86f94393..1d725349a 100644 --- a/vfs/tar.c +++ b/vfs/tar.c @@ -343,7 +343,8 @@ static INLINE int uncompress_tar_file (struct archive *current_archive, /* From time we have sfs this function is pretty trivial */ current_archive->is_gzipped = tar_uncompressed_local; - current_archive->tmpname = copy_strings( current_archive->name, "#ugz", NULL ); + current_archive->tmpname = copy_strings( current_archive->name, + decompress_extension (type), NULL ); result = mc_open (current_archive->tmpname, O_RDONLY); if (result == -1) diff --git a/vfs/vfs.c b/vfs/vfs.c index 5e510c3ac..adf2e9b6f 100644 --- a/vfs/vfs.c +++ b/vfs/vfs.c @@ -826,7 +826,7 @@ int mc_chdir (char *path) current_dir = vfs_canon (path); current_vfs = vfs_type (current_dir); b = strdup (current_dir); - result = (*current_vfs->chdir)(vfs_name (b)); + result = (*current_vfs->chdir) ? (*current_vfs->chdir)(vfs_name (b)) : -1; free (b); if (result == -1){ errno = ferrno (current_vfs); @@ -1580,6 +1580,17 @@ vfs_die (char *m) exit (1); } +void +print_vfs_stats (char *fs_name, char *action, char *file_name, int have, int need) +{ + if (need) + print_vfs_message ("%s: %s: %s %3d%% (%ld bytes transfered)", + fs_name, action, file_name, have*100/need, have); + else + print_vfs_message ("%s: %s: %s %ld bytes transfered", + fs_name, action, file_name, have); +} + #ifndef VFS_STANDALONE char * vfs_get_password (char *msg) diff --git a/vfs/vfs.h b/vfs/vfs.h index 4b98412af..e3be71351 100644 --- a/vfs/vfs.h +++ b/vfs/vfs.h @@ -360,4 +360,18 @@ extern void mc_vfs_done( void ); #define NO_LINEAR(a) (((a) == (O_RDONLY | O_LINEAR)) ? O_RDONLY : (a)) #endif +/* O_LINEAR is strange beast, be carefull. If you open file asserting + * O_RDONLY | O_LINEAR, you promise: + * + * a) to read file linearily from beggining to the end + * b) not to open another file before you close this one + * (this will likely go away in future) + * + * O_LINEAR allows filesystems not to create temporary file in some + * cases (ftp transfer). -- pavel@ucw.cz + */ + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)<(b) ? (b) : (a)) + #endif /* __VFS_H */