mirror of
https://github.com/MidnightCommander/mc
synced 2025-04-02 13:12:53 +03:00
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:
parent
5582bcd323
commit
a04ee60c23
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
166
vfs/ftpfs.c
166
vfs/ftpfs.c
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user