mirror of
https://github.com/MidnightCommander/mc
synced 2025-01-03 18:14:25 +03:00
Ticket #1828: Improved symlink handling in ftpfs
Originally from: http://mail.gnome.org/archives/mc-devel/2005-April/msg00035.html The routines `vfs_s_find_entry_linear()' and `vfs_s_find_entry_tree()' call `canonicalize_pathname()' on entry. This routine eats `..' path components in certain cases. In case of ftpfs this is not desired - the path should be kept as is since the code in direntry.c doesn't have enough knowledge of the directory structure on the remote end. Assume that there is a path like this on the remote server /path1/path2/path3 The `path2' component is a symlink to some directory and `path3' is a symlink stored in `path2' which is relative to `path2' i.e. path2 path3 -> ../some/other/path Now, the code in direntry.c will determine that `path3' is a symlink and will try to resolve (vfs_s_resolve_symlink) it by passing the following path /path1/path2/../some/other/path to `vfs_s_find_entry_linear' . As I've said above this routine calls `canonicalize_pathname' on entry which will modify the path like this: /path1/some/other/path Now this is clearly wrong since `path2' is a symlink and it should be resolved first. In the case of ftpfs the code in direntry.c doesn't have enough knowledge about physycal directory layout on the remote filesystem so it shouldn't try to canonicalize the path. The path should be left as is and passed to the remote end for processing. Fix issue: Changed function canonicalize_pathname (as fact, renamed to custom_canonicalize_pathname) In this function added ability to partial canonicalize of pathname. And some functions from vfs/direntry.c calls custom_canonicalize_pathname without removal of '..' stuff. Signed-off-by: Slava Zanko <slavazanko@gmail.com>
This commit is contained in:
parent
00b94eec5d
commit
4f36622725
11
src/util.h
11
src/util.h
@ -146,6 +146,17 @@ extern struct sigaction startup_handler;
|
||||
char *tilde_expand (const char *);
|
||||
|
||||
/* Pathname canonicalization */
|
||||
typedef enum {
|
||||
CANON_PATH_JOINSLASHES = 1L<<0, /* Multiple `/'s are collapsed to a single `/'. */
|
||||
CANON_PATH_REMSLASHDOTS = 1L<<1, /* Leading `./'s, `/'s and trailing `/.'s are removed. */
|
||||
CANON_PATH_REMDOUBLEDOTS = 1L<<3, /* Non-leading `../'s and trailing `..'s are handled by removing */
|
||||
CANON_PATH_GUARDUNC = 1L<<4, /* Detect and preserve UNC paths: //server/... */
|
||||
CANON_PATH_ALL = CANON_PATH_JOINSLASHES
|
||||
| CANON_PATH_REMSLASHDOTS
|
||||
| CANON_PATH_REMDOUBLEDOTS
|
||||
| CANON_PATH_GUARDUNC
|
||||
} CANON_PATH_FLAGS;
|
||||
void custom_canonicalize_pathname (char *, CANON_PATH_FLAGS);
|
||||
void canonicalize_pathname (char *);
|
||||
|
||||
/* Misc Unix functions */
|
||||
|
@ -457,14 +457,14 @@ close_error_pipe (int error, const char *text)
|
||||
* Well formed UNC paths are modified only in the local part.
|
||||
*/
|
||||
void
|
||||
canonicalize_pathname (char *path)
|
||||
custom_canonicalize_pathname (char *path, CANON_PATH_FLAGS flags)
|
||||
{
|
||||
char *p, *s;
|
||||
int len;
|
||||
char *lpath = path; /* path without leading UNC part */
|
||||
|
||||
/* Detect and preserve UNC paths: //server/... */
|
||||
if (path[0] == PATH_SEP && path[1] == PATH_SEP) {
|
||||
if ( ( flags & CANON_PATH_GUARDUNC ) && path[0] == PATH_SEP && path[1] == PATH_SEP) {
|
||||
p = path + 2;
|
||||
while (p[0] && p[0] != '/')
|
||||
p++;
|
||||
@ -475,6 +475,7 @@ canonicalize_pathname (char *path)
|
||||
if (!lpath[0] || !lpath[1])
|
||||
return;
|
||||
|
||||
if ( flags & CANON_PATH_JOINSLASHES ) {
|
||||
/* Collapse multiple slashes */
|
||||
p = lpath;
|
||||
while (*p) {
|
||||
@ -485,7 +486,9 @@ canonicalize_pathname (char *path)
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & CANON_PATH_JOINSLASHES ) {
|
||||
/* Collapse "/./" -> "/" */
|
||||
p = lpath;
|
||||
while (*p) {
|
||||
@ -494,7 +497,9 @@ canonicalize_pathname (char *path)
|
||||
else
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & CANON_PATH_REMSLASHDOTS ) {
|
||||
/* Remove trailing slashes */
|
||||
p = lpath + strlen (lpath) - 1;
|
||||
while (p > lpath && *p == PATH_SEP)
|
||||
@ -526,7 +531,9 @@ canonicalize_pathname (char *path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & CANON_PATH_REMDOUBLEDOTS ) {
|
||||
/* Collapse "/.." with the previous part of path */
|
||||
p = lpath;
|
||||
while (p[0] && p[1] && p[2]) {
|
||||
@ -579,6 +586,13 @@ canonicalize_pathname (char *path)
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
canonicalize_pathname (char *path)
|
||||
{
|
||||
custom_canonicalize_pathname (path, CANON_PATH_ALL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GET_PROCESS_STATS
|
||||
|
@ -263,7 +263,8 @@ vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
|
||||
char * const pathref = g_strdup (a_path);
|
||||
char *path = pathref;
|
||||
|
||||
canonicalize_pathname (path);
|
||||
/* canonicalize as well, but don't remove '../' from path */
|
||||
custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_RMDBLDT));
|
||||
|
||||
while (root) {
|
||||
while (*path == PATH_SEP) /* Strip leading '/' */
|
||||
@ -336,7 +337,8 @@ vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
|
||||
if (root->super->root != root)
|
||||
vfs_die ("We have to use _real_ root. Always. Sorry.");
|
||||
|
||||
canonicalize_pathname (path);
|
||||
/* canonicalize as well, but don't remove '../' from path */
|
||||
custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_RMDBLDT));
|
||||
|
||||
if (!(flags & FL_DIR)) {
|
||||
char *dirname, *name, *save;
|
||||
|
Loading…
Reference in New Issue
Block a user