diff options
-rw-r--r-- | ftpfs/ChangeLog | 9 | ||||
-rw-r--r-- | ftpfs/dir.c | 14 | ||||
-rw-r--r-- | ftpfs/ftpfs.c | 26 | ||||
-rw-r--r-- | libftpconn/ChangeLog | 10 | ||||
-rw-r--r-- | libftpconn/unix.c | 118 |
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); |