From ca764e66ea7c3361de6ed3a820a9d5e39dd3c0c9 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 16 May 2012 09:17:40 +0200 Subject: nfsclient: Fix symbolic link evaluation --- cpukit/libfs/src/nfsclient/src/nfs.c | 163 +++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 66 deletions(-) (limited to 'cpukit/libfs') diff --git a/cpukit/libfs/src/nfsclient/src/nfs.c b/cpukit/libfs/src/nfsclient/src/nfs.c index bff5d6da16..bbec6b803c 100644 --- a/cpukit/libfs/src/nfsclient/src/nfs.c +++ b/cpukit/libfs/src/nfsclient/src/nfs.c @@ -574,8 +574,8 @@ typedef struct NfsNodeRec_ { Forward Declarations *****************************************/ -static ssize_t nfs_readlink( - const rtems_filesystem_location_info_t *loc, +static ssize_t nfs_readlink_with_node( + NfsNode node, char *buf, size_t len ); @@ -1299,19 +1299,24 @@ static bool nfs_is_directory( return is_dir; } -static NfsNode nfs_search_in_directory( +static int nfs_search_in_directory( Nfs nfs, - NfsNode node, - char *part + const NfsNode dir, + char *part, + NfsNode entry ) { int rv; + entry->nfs = nfs; + /* lookup one element */ - SERP_ARGS(node).diroparg.name = part; + SERP_ATTR(entry) = SERP_ATTR(dir); + SERP_FILE(entry) = SERP_FILE(dir); + SERP_ARGS(entry).diroparg.name = part; /* remember args / directory fh */ - memcpy( &node->args, &SERP_FILE(node), sizeof(node->args)); + memcpy(&entry->args, &SERP_FILE(dir), sizeof(dir->args)); #if DEBUG & DEBUG_EVALPATH fprintf(stderr,"Looking up '%s'\n",part); @@ -1320,92 +1325,100 @@ static NfsNode nfs_search_in_directory( rv = nfscall( nfs->server, NFSPROC_LOOKUP, - (xdrproc_t) xdr_diropargs, &SERP_FILE(node), - (xdrproc_t) xdr_serporid, &node->serporid + (xdrproc_t) xdr_diropargs, &SERP_FILE(entry), + (xdrproc_t) xdr_serporid, &entry->serporid ); - if (rv == 0 && node->serporid.status == NFS_OK) { + if (rv == 0 && entry->serporid.status == NFS_OK) { int force_update = 1; - rv = updateAttr(node, force_update); - if (rv != 0) { - node = NULL; - } + rv = updateAttr(entry, force_update); } else { - node = NULL; + rv = -1; } - return node; + return rv; } -static void nfs_follow_link(rtems_filesystem_eval_path_context_t *ctx) +static void nfs_eval_follow_link( + rtems_filesystem_eval_path_context_t *ctx, + NfsNode link +) { const size_t len = NFS_MAXPATHLEN + 1; - char *link = malloc(len); + char *buf = malloc(len); - if (link != NULL) { - rtems_filesystem_location_info_t *currentloc = - rtems_filesystem_eval_path_get_currentloc(ctx); - ssize_t rv = nfs_readlink(currentloc, link, len); + if (buf != NULL) { + ssize_t rv = nfs_readlink_with_node(link, buf, len); if (rv >= 0) { - rtems_filesystem_eval_path_recursive(ctx, link, (size_t) rv); + rtems_filesystem_eval_path_recursive(ctx, buf, (size_t) rv); } else { rtems_filesystem_eval_path_error(ctx, 0); } - free(link); + free(buf); } else { rtems_filesystem_eval_path_error(ctx, ENOMEM); } } -static bool nfs_update_currentloc( +static void nfs_eval_set_handlers( rtems_filesystem_eval_path_context_t *ctx, - Nfs nfs, - NfsNode node + ftype type ) { - bool ok = true; - rtems_filesystem_location_info_t *pathloc = + rtems_filesystem_location_info_t *currentloc = rtems_filesystem_eval_path_get_currentloc(ctx); - pathloc->node_access = node; - - switch (SERP_ATTR(node).type) { - case NFDIR: pathloc->handlers = &nfs_dir_file_handlers; break; - case NFREG: pathloc->handlers = &nfs_file_file_handlers; break; - case NFLNK: pathloc->handlers = &nfs_link_file_handlers; break; - default: pathloc->handlers = &rtems_filesystem_handlers_default; break; + switch (type) { + case NFDIR: + currentloc->handlers = &nfs_dir_file_handlers; + break; + case NFREG: + currentloc->handlers = &nfs_file_file_handlers; + break; + case NFLNK: + currentloc->handlers = &nfs_link_file_handlers; + break; + default: + currentloc->handlers = &rtems_filesystem_handlers_default; + break; } +} - /* remember the name of this directory entry */ +static int nfs_move_node(NfsNode dst, const NfsNode src) +{ + int rv = 0; - if (node->args.name) { - if (node->str) { + if (dst->str != NULL) { #if DEBUG & DEBUG_COUNT_NODES - rtems_interrupt_level flags; - rtems_interrupt_disable(flags); - nfs->stringsInUse--; - rtems_interrupt_enable(flags); + rtems_interrupt_level flags; + rtems_interrupt_disable(flags); + dst->nfs->stringsInUse--; + rtems_interrupt_enable(flags); #endif - free(node->str); - } - node->args.name = node->str = strdup(node->args.name); - if (node->str != NULL) { + free(dst->str); + } + + *dst = *src; + dst->str = NULL; + + if (src->args.name != NULL) { + dst->str = dst->args.name = strdup(src->args.name); + if (dst->str != NULL) { #if DEBUG & DEBUG_COUNT_NODES rtems_interrupt_level flags; rtems_interrupt_disable(flags); - nfs->stringsInUse++; + dst->nfs->stringsInUse++; rtems_interrupt_enable(flags); #endif } else { - rtems_filesystem_eval_path_error(ctx, ENOMEM); - ok = false; + rv = -1; } } - return ok; + return rv; } static rtems_filesystem_eval_path_generic_status nfs_eval_part( @@ -1419,20 +1432,28 @@ static rtems_filesystem_eval_path_generic_status nfs_eval_part( rtems_filesystem_eval_path_get_currentloc(ctx); Nfs nfs = currentloc->mt_entry->fs_info; NfsNode dir = currentloc->node_access; - NfsNode entry = nfs_search_in_directory(nfs, dir, part); + NfsNodeRec entry; + int rv = nfs_search_in_directory(nfs, dir, part, &entry); - if (entry != NULL) { - rtems_filesystem_eval_path_clear_token(ctx); + if (rv == 0) { + bool terminal = !rtems_filesystem_eval_path_has_path(ctx); + int eval_flags = rtems_filesystem_eval_path_get_flags(ctx); + bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0; + ftype type = SERP_ATTR(&entry).type; - if (nfs_update_currentloc(ctx, nfs, entry)) { - int eval_flags = rtems_filesystem_eval_path_get_flags(ctx); - bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0; - bool terminal = !rtems_filesystem_eval_path_has_path( ctx ); + rtems_filesystem_eval_path_clear_token(ctx); - if (SERP_ATTR(entry).type == NFLNK && (follow_sym_link || !terminal)) { - nfs_follow_link(ctx); - } else if (!terminal) { - status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE; + if (type == NFLNK && (follow_sym_link || !terminal)) { + nfs_eval_follow_link(ctx, &entry); + } else { + rv = nfs_move_node(dir, &entry); + if (rv == 0) { + nfs_eval_set_handlers(ctx, type); + if (!terminal) { + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE; + } + } else { + rtems_filesystem_eval_path_error(ctx, ENOMEM); } } } else { @@ -2015,13 +2036,12 @@ char *dupname; return rv; } -static ssize_t nfs_readlink( - const rtems_filesystem_location_info_t *loc, +static ssize_t nfs_readlink_with_node( + NfsNode node, char *buf, size_t len ) { - NfsNode node = loc->node_access; Nfs nfs = node->nfs; readlinkres_strbuf rr; @@ -2034,7 +2054,7 @@ static ssize_t nfs_readlink( (xdrproc_t)xdr_readlinkres_strbuf, &rr) || (NFS_OK != (errno = rr.status)) ) { #if DEBUG & DEBUG_SYSCALLS - perror("nfs_readlink"); + perror("nfs_readlink_with_node"); #endif return -1; } @@ -2042,6 +2062,17 @@ static ssize_t nfs_readlink( return (ssize_t) strlen(rr.strbuf.buf); } +static ssize_t nfs_readlink( + const rtems_filesystem_location_info_t *loc, + char *buf, + size_t len +) +{ + NfsNode node = loc->node_access; + + return nfs_readlink_with_node(node, buf, len); +} + static int nfs_rename( const rtems_filesystem_location_info_t *oldparentloc, const rtems_filesystem_location_info_t *oldloc, -- cgit v1.2.3