summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ftpfs/ChangeLog9
-rw-r--r--ftpfs/dir.c14
-rw-r--r--ftpfs/ftpfs.c26
-rw-r--r--libftpconn/ChangeLog10
-rw-r--r--libftpconn/unix.c118
5 files changed, 145 insertions, 32 deletions
diff --git a/ftpfs/ChangeLog b/ftpfs/ChangeLog
index 185ec775..e99034d8 100644
--- a/ftpfs/ChangeLog
+++ b/ftpfs/ChangeLog
@@ -1,3 +1,12 @@
+2002-04-13 Moritz Schulte <moritz@chaosdorf.de>
+
+ * ftpfs.c: Include <sys/stat.h>
+ (main): Stat the underlying node and initialize the root node's
+ stat information.
+
+ * dir.c (ftpfs_refresh_node): If refreshing the root node, simply
+ use the old stat information.
+
2002-03-11 Roland McGrath <roland@frob.com>
* ftpfs.c (parse_startup_opt): If given one argument with no :,
diff --git a/ftpfs/dir.c b/ftpfs/dir.c
index 9e550ce8..6ae5facc 100644
--- a/ftpfs/dir.c
+++ b/ftpfs/dir.c
@@ -483,8 +483,9 @@ ftpfs_refresh_node (struct node *node)
if (!err && entry->noent)
err = ENOENT;
}
- else
+ else if (*(entry->name))
{
+ /* The root node is treated seperately below. */
struct ftp_conn *conn;
err = ftpfs_get_ftp_conn (dir->fs, &conn);
@@ -518,6 +519,17 @@ ftpfs_refresh_node (struct node *node)
entry->name_timestamp = timestamp;
}
}
+ else
+ {
+ /* Refresh the root node with the old stat
+ information. */
+ struct refresh_entry_state res;
+ res.entry = entry;
+ res.timestamp = timestamp;
+ err = update_old_entry (entry->name,
+ &netfs_root_node->nn_stat,
+ NULL, &res);
+ }
}
if ((entry->stat.st_mtime < node->nn_stat.st_mtime
diff --git a/ftpfs/ftpfs.c b/ftpfs/ftpfs.c
index 4efb5ffb..86fea34c 100644
--- a/ftpfs/ftpfs.c
+++ b/ftpfs/ftpfs.c
@@ -24,6 +24,7 @@
#include <error.h>
#include <argz.h>
#include <netdb.h>
+#include <sys/stat.h>
#include <version.h>
@@ -365,7 +366,8 @@ int
main (int argc, char **argv)
{
error_t err;
- mach_port_t bootstrap;
+ mach_port_t bootstrap, underlying_node;
+ struct stat underlying_stat;
const struct argp_child argp_children[] =
{ {&common_argp}, {&netfs_std_startup_argp}, {0} };
struct argp argp =
@@ -395,7 +397,27 @@ main (int argc, char **argv)
netfs_root_node = ftpfs->root;
- netfs_startup (bootstrap, 0);
+ underlying_node = netfs_startup (bootstrap, 0);
+ err = io_stat (underlying_node, &underlying_stat);
+ if (err)
+ error (1, err, "cannot stat underling node");
+
+ /* Initialize stat information of the root node. */
+ netfs_root_node->nn_stat = underlying_stat;
+ netfs_root_node->nn_stat.st_mode =
+ S_IFDIR | (underlying_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+
+ /* If the underlying node isn't a directory, propagate read permission to
+ execute permission since we need that for lookups. */
+ if (! S_ISDIR (underlying_stat.st_mode))
+ {
+ if (underlying_stat.st_mode & S_IRUSR)
+ netfs_root_node->nn_stat.st_mode |= S_IXUSR;
+ if (underlying_stat.st_mode & S_IRGRP)
+ netfs_root_node->nn_stat.st_mode |= S_IXGRP;
+ if (underlying_stat.st_mode & S_IROTH)
+ netfs_root_node->nn_stat.st_mode |= S_IXOTH;
+ }
for (;;)
netfs_server_loop ();
diff --git a/libftpconn/ChangeLog b/libftpconn/ChangeLog
index b23fce62..c53eb6ba 100644
--- a/libftpconn/ChangeLog
+++ b/libftpconn/ChangeLog
@@ -1,3 +1,13 @@
+2002-04-13 Moritz Schulte <moritz@chaosdorf.de>
+
+ * unix.c: Include <libgen.h>.
+ (struct get_stats_state): New member: searched_name.
+ (ftp_conn_unix_start_get_stats): Return EINVAL if trying to list
+ the root node without listing it's content; set searched_name to
+ the dirname.
+ (ftp_conn_unix_cont_get_stats): If searching for the list info of
+ one entry, skip all other entries.
+
2001-12-22 Roland McGrath <roland@frob.com>
* ftpconn.h (ftp_conn_validate_syshooks): Don't make this extern
diff --git a/libftpconn/unix.c b/libftpconn/unix.c
index e3277721..7a5136f8 100644
--- a/libftpconn/unix.c
+++ b/libftpconn/unix.c
@@ -27,6 +27,7 @@
#include <grp.h>
#include <sys/time.h>
#include <netinet/in.h>
+#include <libgen.h> /* For dirname(). */
#ifdef HAVE_HURD_HURD_TYPES_H
#include <hurd/hurd_types.h>
#endif
@@ -145,6 +146,9 @@ struct get_stats_state
int name_partial; /* True if NAME isn't complete. */
int contents; /* Are we looking for directory contents? */
+ char *searched_name; /* If we are not, then we are only
+ looking for this name. */
+
int added_slash; /* Did we prefix the name with `./'? */
struct stat stat; /* Last read stat info. */
@@ -155,8 +159,6 @@ struct get_stats_state
char buf[7000];
};
-
-
/* Start an operation to get a list of file-stat structures for NAME (this is
often similar to ftp_conn_start_dir, but with OS-specific flags), and
return a file-descriptor for reading on, and a state structure in STATE
@@ -168,51 +170,102 @@ ftp_conn_unix_start_get_stats (struct ftp_conn *conn,
const char *name, int contents,
int *fd, void **state)
{
- error_t err;
+ error_t err = 0;
size_t req_len;
- char *req;
- struct get_stats_state *s = malloc (sizeof (struct get_stats_state));
- const char *flags = contents ? "-A" : "-Ad";
+ char *req = NULL;
+ struct get_stats_state *s = NULL;
+ const char *flags = "-A";
const char *slash = strchr (name, '/');
+ char *searched_name = NULL;
+ s = (struct get_stats_state *) malloc (sizeof (struct get_stats_state));
if (! s)
- return ENOMEM;
+ {
+ err = ENOMEM;
+ goto out;
+ }
+ if (! contents)
+ {
+ if (! strcmp (name, "/"))
+ {
+ /* Listing only the directory itself and not the directory
+ content seems to be not supported by all FTP servers. If
+ the directory in question is not the root directory, we
+ can simply lookup `..', but that doesn't work if we are
+ already on the root directory. */
+ err = EINVAL;
+ }
+ else
+ {
+ searched_name = strdup (basename ((char *) name));
+ if (! searched_name)
+ err = ENOMEM;
+ }
+ if (err)
+ goto out;
+ }
if (strcspn (name, "*? \t\n{}$`\\\"'") < strlen (name))
/* NAME contains some metacharacters, which makes the behavior of various
ftp servers unpredictable, so punt. */
{
- free (s);
- return EINVAL;
+ err = EINVAL;
+ goto out;
}
/* We pack the ls options and the name into the list argument, in REQ,
which will do the right thing on most unix ftp servers. */
- /* Space needed for REQ. */
- req_len = strlen (flags) + 1 + strlen (name) + 1;
-
- /* If NAME doesn't contain a slash, we prepend `./' to it so that we can
- tell from the results whether it's a directory or not. */
- if (! slash)
- req_len += 2;
-
- req = malloc (req_len);
- if (! req)
- return ENOMEM;
-
- snprintf (req, req_len, "%s %s%s", flags, slash ? "" : "./", name);
+ req_len = strlen (flags) + 2; /* space character + null character. */
+ if (! contents)
+ {
+ /* If we are looking for a directory rather than its content,
+ lookup the parent directory and search for the entry, rather
+ than looking it up directly, as not all ftp servers support
+ the -d option to ls. To make sure we get a directory, append
+ '/', except for the root directory. */
+ char *dirn = dirname ((char *) name);
+ int is_root = ! strcmp (dirn, "/");
+ req_len += strlen (dirn) + (is_root ? 0 : 1);
+ req = malloc (req_len);
+ if (! req)
+ err = ENOMEM;
+ else
+ sprintf (req, "%s %s%s", flags, dirn, (is_root ? "" : "/"));
+ }
+ else
+ {
+ /* If NAME doesn't contain a slash, we prepend `./' to it so that we can
+ tell from the results whether it's a directory or not. */
+ req_len += strlen (name) + (slash ? 0 : 2);
+ req = malloc (req_len);
+ if (! req)
+ err = ENOMEM;
+ else
+ sprintf (req, "%s %s%s", flags, slash ? "" : "./", name);
+ }
+
+ if (err)
+ goto out;
/* Make the actual request. */
err = ftp_conn_start_dir (conn, req, fd);
- free (req);
+ out:
+ if (req)
+ free (req);
if (err)
- free (s);
+ {
+ if (s)
+ free (s);
+ if (searched_name)
+ free (searched_name);
+ }
else
{
s->contents = contents;
+ s->searched_name = searched_name;
s->added_slash = !slash;
s->name = 0;
s->name_len = s->name_alloced = 0;
@@ -616,11 +669,16 @@ ftp_conn_unix_cont_get_stats (struct ftp_conn *conn, int fd, void *state,
/* Pass only directory-relative names to the callback function. */
name = basename (name);
- /* Call the callback function to process the current entry; it is
- responsible for freeing S->name and SYMLINK_TARGET. */
- err = (*add_stat) (name, &s->stat, symlink_target, hook);
- if (err)
- goto finished;
+ if (s->contents || ! strcmp (s->name, s->searched_name))
+ {
+ /* We are only interested in searched_name. */
+
+ /* Call the callback function to process the current entry; it is
+ responsible for freeing S->name and SYMLINK_TARGET. */
+ err = (*add_stat) (name, &s->stat, symlink_target, hook);
+ if (err)
+ goto finished;
+ }
s->name_len = 0;
s->name_partial = 0;
@@ -658,6 +716,8 @@ finished:
return. */
if (s->name)
free (s->name);
+ if (s->searched_name)
+ free (s->searched_name);
free (s);
close (fd);