Tue Sep 15 20:51:42 1998 Norbert Warmuth <k3190@fh-sw.de>

* setup.c: save and restore new global variable/option
ftp_use_unix_list_options


Tue Sep 15 20:31:32 1998  Norbert Warmuth  <k3190@fh-sw.de>

* ftpfs.c (ftp_use_unix_list_options): New global variable/option.
If true we try to use 'LIST -la <path>'. When it fails we use the
two commands 'CWD <path>' and 'LIST' instead.

(resolve_symlink): rewritten. Don't get a second directory listing
with `LIST -lLa'. Instead use the cache to get the file stat of
symbolic links. If the directory the symlink points to isn't
already in the cache the directory listing will be fetched and
stored in the directory cache (without resolving symlinks
recursively).
The new method to resolve symlinks is faster if symlinks
the same directory or the directory the symlink points to
is already in the cache.
This function was small and nice until I discovered that it was
broken for symlinks to symlinks. Now it looks ugly and perhaps I
will revert it to use "LIST -lLa" again. With a fast connection it
doesn't matter which methode we use but with a slow connection I
wouldn't hesitate to burn more cpu cycles on the client side.

(retrieve_dir): Added parameter to tell whether to resolve
symlinks (don't resolve symlinks in directory listings retrieved
while resolving symlinks).
When we don't get a directory listing with 'LIST -la <path>' then
try to get it with `CWD <path>; LIST'.


Tue Sep 15 20:27:29 1998  Norbert Warmuth  <k3190@fh-sw.de

* ftpfs.c (login_server): s/ftpfs_get_host/my_get_host/

(retrieve_file_start2): Don't create target file O_EXCL, in
copy_file_file we check existance of the target file and know
that we want to truncate it (this change was already done a
while back but it was reverted with the vfs-split).


Tue Sep 15 20:15:42 1998  Norbert Warmuth  <k3190@fh-sw.de>

* ftpfs.h (struct connection): added boolean which indicates that
the ftp server doesn't unterstand Unix ls options

* ftpfs.h (struct dir): added enum to store symlink status of the
in memory directory cache (directory has no symbolic links;
symbolic links but not yet resolved; symbolic links which are resolved)


Tue Sep 15 20:02:08 1998  Norbert Warmuth  <k3190@fh-sw.de>

* shared_ftp_fish.c, fish.c: updated references to retrieve_dir to
honour the additional boolean parameter
This commit is contained in:
Norbert Warmuth 1998-09-15 19:41:22 +00:00
parent 5582bcd323
commit a04ee60c23
7 changed files with 169 additions and 78 deletions

View File

@ -1,3 +1,8 @@
Tue Sep 15 20:51:42 1998 Norbert Warmuth <k3190@fh-sw.de>
* setup.c: save and restore new global variable/option
ftp_use_unix_list_options
Tue Sep 15 01:02:34 1998 Paul Sheer <psheer@obsidian.co.za>
* gtkedit: Directory added. This directory contains all the editor

View File

@ -63,6 +63,7 @@
extern int use_netrc;
extern int ftpfs_retry_seconds;
extern int ftpfs_use_passive_connections;
extern int ftpfs_use_unix_list_options;
#endif
/* "$Id$" */
@ -225,6 +226,7 @@ static struct {
{ "ftpfs_retry_seconds", &ftpfs_retry_seconds },
{ "ftpfs_always_use_proxy", &ftpfs_always_use_proxy },
{ "ftpfs_use_passive_connections", &ftpfs_use_passive_connections },
{ "ftpfs_use_unix_list_options", &ftpfs_use_passive_connections },
#endif
#endif
#ifdef USE_INTERNAL_EDIT

View File

@ -1,3 +1,53 @@
Tue Sep 15 20:31:32 1998 Norbert Warmuth <k3190@fh-sw.de>
* ftpfs.c (ftp_use_unix_list_options): New global variable/option.
If true we try to use 'LIST -la <path>'. When it fails we use the
two commands 'CWD <path>' and 'LIST' instead.
(resolve_symlink): rewritten. Don't get a second directory listing
with `LIST -lLa'. Instead use the cache to get the file stat of
symbolic links. If the directory the symlink points to isn't
already in the cache the directory listing will be fetched and
stored in the directory cache (without resolving symlinks
recursively).
The new method to resolve symlinks is faster if symlinks
the same directory or the directory the symlink points to
is already in the cache.
This function was small and nice until I discovered that it was
broken for symlinks to symlinks. Now it looks ugly and perhaps I
will revert it to use "LIST -lLa" again. With a fast connection it
doesn't matter which methode we use but with a slow connection I
wouldn't hesitate to burn more cpu cycles on the client side.
(retrieve_dir): Added parameter to tell whether to resolve
symlinks (don't resolve symlinks in directory listings retrieved
while resolving symlinks).
When we don't get a directory listing with 'LIST -la <path>' then
try to get it with `CWD <path>; LIST'.
Tue Sep 15 20:27:29 1998 Norbert Warmuth <k3190@fh-sw.de
* ftpfs.c (login_server): s/ftpfs_get_host/my_get_host/
(retrieve_file_start2): Don't create target file O_EXCL, in
copy_file_file we check existance of the target file and know
that we want to truncate it (this change was already done a
while back but it was reverted with the vfs-split).
Tue Sep 15 20:15:42 1998 Norbert Warmuth <k3190@fh-sw.de>
* ftpfs.h (struct connection): added boolean which indicates that
the ftp server doesn't unterstand Unix ls options
* ftpfs.h (struct dir): added enum to store symlink status of the
in memory directory cache (directory has no symbolic links;
symbolic links but not yet resolved; symbolic links which are resolved)
Tue Sep 15 20:02:08 1998 Norbert Warmuth <k3190@fh-sw.de>
* shared_ftp_fish.c, fish.c: updated references to retrieve_dir to
honour the additional boolean parameter
Tue Sep 15 00:42:15 1998 Yimur Bakeyev <mc@bat.ru>
* vfs.h: add vfs_split() declaration, to make sfs.c happy.

View File

@ -381,9 +381,14 @@ static char *fish_get_current_directory(struct connection *bucket)
/*
* This is the 'new' code
*/
/*
* Last parameter (resolve_symlinks) is currently not used. Due to
* the code sharing (file shared_ftp_fish.c) the fish and ftp interface
* have to be the same (Norbert).
*/
static struct dir *
retrieve_dir(struct connection *bucket, char *remote_path)
retrieve_dir(struct connection *bucket, char *remote_path, int resolve_symlinks)
{
int sock, has_symlinks;
struct linklist *file_list, *p;

View File

@ -99,6 +99,13 @@ int ftpfs_retry_seconds = 30;
/* Method to use to connect to ftp sites */
int ftpfs_use_passive_connections = 1;
/* Method used to get directory listings:
1: try 'LIST -la <path>', if it fails
fall back to CWD <path>; LIST
0: always use CWD <path>; LIST
*/
int ftpfs_use_unix_list_options = 1;
/* Use the ~/.netrc */
int use_netrc = 1;
@ -136,6 +143,8 @@ static char reply_str [80];
static char *ftpfs_get_current_directory(struct connection *bucket);
static int __ftpfs_chdir (struct connection *bucket ,char *remote_path);
static struct direntry *_get_file_entry(struct connection *bucket,
char *file_name, int op, int flags);
static void free_bucket (void *data);
static void connection_destructor(void *data);
static void flush_all_directory(struct connection *bucket);
@ -326,7 +335,7 @@ login_server (struct connection *bucket, char *netrcpass)
#if defined(HSC_PROXY)
char *p, *host;
int port;
p = ftpfs_get_host_and_username(ftpfs_proxy_host, &host, &proxyname,
p = my_get_host_and_username(ftpfs_proxy_host, &host, &proxyname,
&port, &proxypass);
if (p)
free (p);
@ -699,6 +708,7 @@ open_command_connection (char *host, char *user, int port, char *netrcpass)
bucket->password = 0;
bucket->use_passive_connection = ftpfs_use_passive_connections | source_route;
bucket->use_source_route = source_route;
bucket->strict_rfc959_list_cmd = !ftpfs_use_unix_list_options;
bucket->isbinary = TYPE_UNKNOWN;
/* We do not want to use the passive if we are using proxies */
@ -1034,77 +1044,65 @@ ftpfs_abort (struct connection *bucket, int dsock)
static void
resolve_symlink(struct connection *bucket, struct dir *dir)
{
char buffer[2048] = "", *filename;
int sock;
FILE *fp;
struct stat s;
struct linklist *flist;
struct direntry *fe;
struct direntry *fe, *fel;
char tmp[MC_MAXPATHLEN];
print_vfs_message("Resolving symlink...");
if (strchr (dir->remote_path, ' ')) {
if (__ftpfs_chdir(bucket, dir->remote_path) != COMPLETE) {
print_vfs_message("ftpfs: CWD failed.");
return;
dir->symlink_status = FTPFS_RESOLVED_SYMLINKS;
for (flist = dir->file_list->next; flist != dir->file_list; flist = flist->next) {
/* flist->data->l_stat is alread initialized with 0 */
fel = flist->data;
if (S_ISLNK(fel->s.st_mode)) {
if (fel->linkname[0] == '/') {
if (strlen (fel->linkname) >= MC_MAXPATHLEN)
continue;
strcpy (tmp, fel->linkname);
} else {
if ((strlen (dir->remote_path) + strlen (fel->linkname)) >= MC_MAXPATHLEN)
continue;
strcpy (tmp, dir->remote_path);
if (tmp[1] != '\0')
strcat (tmp, "/");
strcat (tmp + 1, fel->linkname);
}
for ( ;; ) {
fe = _get_file_entry(bucket, tmp, 0, 0);
if (fe) {
if (S_ISLNK (fe->s.st_mode) && fe->l_stat == 0) {
/* Symlink points to link which isn't resolved, yet. */
if (fe->linkname[0] == '/') {
if (strlen (fe->linkname) >= MC_MAXPATHLEN)
break;
strcpy (tmp, fe->linkname);
} else {
/* at this point tmp looks always like this
/directory/filename, i.e. no need to check
strrchr's return value */
*(strrchr (tmp, '/') + 1) = '\0'; /* dirname */
if ((strlen (tmp) + strlen (fe->linkname)) >= MC_MAXPATHLEN)
break;
strcat (tmp, fe->linkname);
}
continue;
} else {
fel->l_stat = xmalloc(sizeof(struct stat),
"resolve_symlink: struct stat");
if ( S_ISLNK (fe->s.st_mode))
*fel->l_stat = *fe->l_stat;
else
*fel->l_stat = fe->s;
(*fel->l_stat).st_ino = bucket->__inode_counter++;
}
}
break;
}
}
sock = open_data_connection (bucket, "LIST -lLa", ".", TYPE_ASCII);
}
else
sock = open_data_connection (bucket, "LIST -lLa",
dir->remote_path, TYPE_ASCII);
if (sock == -1) {
print_vfs_message("ftpfs: couldn't resolve symlink");
return;
}
fp = fdopen(sock, "r");
if (fp == NULL) {
close(sock);
print_vfs_message("ftpfs: couldn't resolve symlink");
return;
}
enable_interrupt_key();
flist = dir->file_list->next;
while (1) {
do {
if (flist == dir->file_list)
goto done;
fe = flist->data;
flist = flist->next;
} while (!S_ISLNK(fe->s.st_mode));
while (1) {
if (fgets (buffer, sizeof (buffer), fp) == NULL)
goto done;
if (logfile){
fputs (buffer, logfile);
fflush (logfile);
}
if (parse_ls_lga (buffer, &s, &filename, NULL)) {
int r = strcmp(fe->name, filename);
free(filename);
if (r == 0) {
fe->l_stat = xmalloc(sizeof(struct stat),
"resolve_symlink: struct stat");
if (fe->l_stat == NULL)
goto done;
*fe->l_stat = s;
(*fe->l_stat).st_ino = bucket->__inode_counter++;
break;
}
if (r < 0)
break;
}
}
}
done:
while (fgets(buffer, sizeof(buffer), fp) != NULL);
disable_interrupt_key();
fclose(fp);
get_reply(qsock(bucket), NULL, 0);
}
#define X "ftp"
#define X_myname "/#ftp:"
#define X_vfs_ops ftpfs_vfs_ops
@ -1115,7 +1113,7 @@ done:
#include "shared_ftp_fish.c"
static struct dir *
retrieve_dir(struct connection *bucket, char *remote_path)
retrieve_dir(struct connection *bucket, char *remote_path, int resolve_symlinks)
{
#ifdef OLD_READ
FILE *fp;
@ -1128,6 +1126,7 @@ retrieve_dir(struct connection *bucket, char *remote_path)
int got_intr = 0;
int has_spaces = (strchr (remote_path, ' ') != NULL);
canonicalize_pathname (remote_path);
for (p = qdcache(bucket)->next;p != qdcache(bucket);
p = p->next) {
dcache = p->data;
@ -1135,9 +1134,11 @@ retrieve_dir(struct connection *bucket, char *remote_path)
struct timeval tim;
gettimeofday(&tim, NULL);
if ((tim.tv_sec < dcache->timestamp.tv_sec) && !force_expiration)
if ((tim.tv_sec < dcache->timestamp.tv_sec) && !force_expiration) {
if (resolve_symlinks && dcache->symlink_status == FTPFS_UNRESOLVED_SYMLINKS)
resolve_symlink(bucket, dcache);
return dcache;
else {
} else {
force_expiration = 0;
p->next->prev = p->prev;
p->prev->next = p->next;
@ -1149,8 +1150,11 @@ retrieve_dir(struct connection *bucket, char *remote_path)
}
has_symlinks = 0;
print_vfs_message("ftpfs: Reading FTP directory...");
if (has_spaces)
if (bucket->strict_rfc959_list_cmd)
print_vfs_message("ftpfs: Reading FTP directory... (don't use UNIX ls options)");
else
print_vfs_message("ftpfs: Reading FTP directory...");
if (has_spaces || bucket->strict_rfc959_list_cmd)
if (__ftpfs_chdir(bucket, remote_path) != COMPLETE) {
my_errno = ENOENT;
print_vfs_message("ftpfs: CWD failed.");
@ -1176,8 +1180,11 @@ retrieve_dir(struct connection *bucket, char *remote_path)
dcache->file_list = file_list;
dcache->remote_path = strdup(remote_path);
dcache->count = 1;
dcache->symlink_status = FTPFS_NO_SYMLINKS;
if (has_spaces)
if (bucket->strict_rfc959_list_cmd == 1)
sock = open_data_connection (bucket, "LIST", 0, TYPE_ASCII);
else if (has_spaces)
sock = open_data_connection (bucket, "LIST -la", ".", TYPE_ASCII);
else {
char *path = copy_strings (remote_path, PATH_SEP_STR, ".", (char *) 0);
@ -1266,6 +1273,15 @@ retrieve_dir(struct connection *bucket, char *remote_path)
goto error_3;
}
if (file_list->next == file_list) {
if (bucket->__inode_counter == 0 && !bucket->strict_rfc959_list_cmd) {
/* It's our first attempt to get a directory listing from this
server (UNIX style LIST command) */
bucket->strict_rfc959_list_cmd = 1;
free(dcache->remote_path);
free(dcache);
linklist_destroy(file_list, direntry_destructor);
return retrieve_dir (bucket, remote_path, resolve_symlinks);
}
my_errno = EACCES;
goto error_3;
}
@ -1273,8 +1289,12 @@ retrieve_dir(struct connection *bucket, char *remote_path)
my_errno = ENOMEM;
goto error_3;
}
if (has_symlinks)
resolve_symlink(bucket, dcache);
if (has_symlinks) {
if (resolve_symlinks)
resolve_symlink(bucket, dcache);
else
dcache->symlink_status = FTPFS_UNRESOLVED_SYMLINKS;
}
print_vfs_message("ftpfs: got listing");
return dcache;
error_1:
@ -1396,7 +1416,7 @@ static int retrieve_file_start(struct direntry *fe)
static int retrieve_file_start2(struct direntry *fe)
{
remotelocal_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
remotelocal_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
if (remotelocal_handle == -1) {
my_errno = EIO;
free(fe->local_filename);

View File

@ -25,8 +25,14 @@ struct dir
struct timeval timestamp;
char *remote_path;
struct linklist *file_list;
int symlink_status;
};
/* valid values for dir->symlink_status */
#define FTPFS_NO_SYMLINKS 0
#define FTPFS_UNRESOLVED_SYMLINKS 1
#define FTPFS_RESOLVED_SYMLINKS 2
struct connection {
char *host;
char *user;
@ -47,6 +53,9 @@ struct connection {
int isbinary;
int cwd_defered; /* current_directory was changed but CWD command hasn't
been sent yet */
int strict_rfc959_list_cmd; /* ftp server doesn't understand
"LIST -la <path>"; use "CWD <path>"/
"LIST" instead */
};
#define qhost(b) (b)->host

View File

@ -1,5 +1,5 @@
static struct dir *retrieve_dir(struct connection *bucket, char *remote_path);
static struct dir *retrieve_dir(struct connection *bucket, char *remote_path, int resolve_symlinks);
static int store_file(struct direntry *fe);
static int retrieve_file_start(struct direntry *fe);
static int retrieve_file(struct direntry *fe);
@ -285,7 +285,7 @@ _get_file_entry(struct connection *bucket, char *file_name,
p = strrchr(file_name, '/');
q = *p;
*p = '\0';
dcache = retrieve_dir(bucket, *file_name ? file_name : "/");
dcache = retrieve_dir(bucket, *file_name ? file_name : "/", op & DO_RESOLVE_SYMLINK);
if (dcache == NULL)
return NULL;
file_list = dcache->file_list;
@ -449,7 +449,7 @@ static int remove_temp_file (char *file_name)
p = strrchr (file_name, '/');
q = *p;
*p = '\0';
dcache = retrieve_dir (bucket, *file_name ? file_name : "/");
dcache = retrieve_dir (bucket, *file_name ? file_name : "/", 0);
if (dcache == NULL)
return -1;
file_list = dcache->file_list;
@ -627,7 +627,7 @@ static void *s_opendir (char *dirname)
my_errno = ENOMEM;
goto error_return;
}
dirp->dcache = retrieve_dir(bucket, remote_path);
dirp->dcache = retrieve_dir(bucket, remote_path, 1);
if (dirp->dcache == NULL)
goto error_return;
dirp->pos = dirp->dcache->file_list->next;