From 8ec7abb551a23bdf47509189145885a364810006 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 4 Mar 2010 06:36:51 +0000 Subject: 010-03-04 Chris Johns * libcsupport/include/rtems/libio.h, libcsupport/src/_rename_r.c: Add a rename file op and have rename use it. * libfs/Makefile.am, libfs/src/dosfs/msdos_rename.c, libfs/src/imfs/imfs_rename.c: New files to support the rename file op. * libfs/src/imfs/imfs.h: Add rename interface. * libfs/src/imfs/imfs_init.c: Add rename handler. * libfs/src/imfs/miniimfs_init.c: Fix up ops struct. * libfs/src/dosfs/msdos.h: Add msdos_rename and remove msdos_file_link. * libfs/src/dosfs/msdos_create.c: Remove the link call. * libfs/src/dosfs/msdos_eval.c: Fix a path parsing bug. * libfs/src/dosfs/msdos_init.c: Add rename handler and clean up the struct naming. * libfs/src/rfs/rtems-rfs-link.c, libfs/src/rfs/rtems-rfs-link.h: Change the link call to allow linking of directories if told to and change the unlink to handle unlink directories that are not empty so rename can be supported. * libfs/src/rfs/rtems-rfs-rtems-dir.c: Fix the link/unlink calls. * libfs/src/rfs/rtems-rfs-rtems.c: Add a rename handler. Fix the link/unlink calls. * libfs/src/dosfs/msdos_dir.c, libfs/src/dosfs/msdos_format.c, libfs/src/dosfs/msdos_misc.c, httpd/asp.c, libfs/src/nfsclient/src/nfs.c: Work around a newlib warning when using the is*() family of calls. --- cpukit/ChangeLog | 40 +++++++++++ cpukit/httpd/asp.c | 4 +- cpukit/libcsupport/include/rtems/libio.h | 8 +++ cpukit/libcsupport/src/_rename_r.c | 104 ++++++++++++++++++++++++++++- cpukit/libfs/Makefile.am | 4 +- cpukit/libfs/src/dosfs/msdos.h | 11 ++- cpukit/libfs/src/dosfs/msdos_create.c | 85 ----------------------- cpukit/libfs/src/dosfs/msdos_dir.c | 4 +- cpukit/libfs/src/dosfs/msdos_eval.c | 4 +- cpukit/libfs/src/dosfs/msdos_format.c | 4 +- cpukit/libfs/src/dosfs/msdos_init.c | 39 +++++------ cpukit/libfs/src/dosfs/msdos_misc.c | 2 +- cpukit/libfs/src/dosfs/msdos_rename.c | 93 ++++++++++++++++++++++++++ cpukit/libfs/src/imfs/imfs.h | 7 ++ cpukit/libfs/src/imfs/imfs_init.c | 1 + cpukit/libfs/src/imfs/imfs_rename.c | 54 +++++++++++++++ cpukit/libfs/src/imfs/miniimfs_init.c | 4 +- cpukit/libfs/src/nfsclient/src/nfs.c | 2 +- cpukit/libfs/src/rfs/rtems-rfs-link.c | 59 +++++++++------- cpukit/libfs/src/rfs/rtems-rfs-link.h | 21 ++++-- cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c | 2 +- cpukit/libfs/src/rfs/rtems-rfs-rtems.c | 73 ++++++++++++++++++-- 22 files changed, 466 insertions(+), 159 deletions(-) create mode 100644 cpukit/libfs/src/dosfs/msdos_rename.c create mode 100644 cpukit/libfs/src/imfs/imfs_rename.c diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 86d023c92b..cb7f68b045 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,43 @@ +2010-03-04 Chris Johns + + * libcsupport/include/rtems/libio.h, libcsupport/src/_rename_r.c: + Add a rename file op and have rename use it. + + * libfs/Makefile.am, libfs/src/dosfs/msdos_rename.c, + libfs/src/imfs/imfs_rename.c: New files to support the rename file + op. + + * libfs/src/imfs/imfs.h: Add rename interface. + + * libfs/src/imfs/imfs_init.c: Add rename handler. + + * libfs/src/imfs/miniimfs_init.c: Fix up ops struct. + + * libfs/src/dosfs/msdos.h: Add msdos_rename and remove + msdos_file_link. + + * libfs/src/dosfs/msdos_create.c: Remove the link call. + + * libfs/src/dosfs/msdos_eval.c: Fix a path parsing bug. + + * libfs/src/dosfs/msdos_init.c: Add rename handler and clean up + the struct naming. + + * libfs/src/rfs/rtems-rfs-link.c, libfs/src/rfs/rtems-rfs-link.h: + Change the link call to allow linking of directories if told to + and change the unlink to handle unlink directories that are not + empty so rename can be supported. + + * libfs/src/rfs/rtems-rfs-rtems-dir.c: Fix the link/unlink calls. + + * libfs/src/rfs/rtems-rfs-rtems.c: Add a rename handler. Fix the + link/unlink calls. + + * libfs/src/dosfs/msdos_dir.c, libfs/src/dosfs/msdos_format.c, + libfs/src/dosfs/msdos_misc.c, httpd/asp.c, + libfs/src/nfsclient/src/nfs.c: Work around a newlib warning when + using the is*() family of calls. + 2010-03-01 Chris Johns * libfs/src/rfs/rtems-rfs-buffer.h: Add `rtems_rfs_buffer_handle_reset'. diff --git a/cpukit/httpd/asp.c b/cpukit/httpd/asp.c index b6402b78ac..26fcac3a3c 100644 --- a/cpukit/httpd/asp.c +++ b/cpukit/httpd/asp.c @@ -287,7 +287,7 @@ static char_t *strtokcmp(char_t *s1, char_t *s2) s1 = skipWhite(s1); len = gstrlen(s2); - for (len = gstrlen(s2); len > 0 && (tolower(*s1) == tolower(*s2)); len--) { + for (len = gstrlen(s2); len > 0 && (tolower((int)*s1) == tolower((int)*s2)); len--) { if (*s2 == '\0') { return s1; } @@ -312,7 +312,7 @@ static char_t *skipWhite(char_t *s) if (s == NULL) { return s; } - while (*s && gisspace(*s)) { + while (*s && gisspace((int)*s)) { s++; } return s; diff --git a/cpukit/libcsupport/include/rtems/libio.h b/cpukit/libcsupport/include/rtems/libio.h index 0ee6ee8458..5cd6dc5a24 100644 --- a/cpukit/libcsupport/include/rtems/libio.h +++ b/cpukit/libcsupport/include/rtems/libio.h @@ -251,6 +251,13 @@ typedef int (*rtems_filesystem_readlink_t)( size_t bufsize ); +typedef int (*rtems_filesystem_rename_t)( + rtems_filesystem_location_info_t *old_parent_loc, /* IN */ + rtems_filesystem_location_info_t *old_loc, /* IN */ + rtems_filesystem_location_info_t *new_parent_loc, /* IN */ + const char *name /* IN */ +); + typedef int (*rtems_filesystem_statvfs_t)( rtems_filesystem_location_info_t *loc, /* IN */ struct statvfs *buf /* OUT */ @@ -280,6 +287,7 @@ struct _rtems_filesystem_operations_table { rtems_filesystem_evaluate_link_t eval_link_h; rtems_filesystem_symlink_t symlink_h; rtems_filesystem_readlink_t readlink_h; + rtems_filesystem_rename_t rename_h; rtems_filesystem_statvfs_t statvfs_h; }; diff --git a/cpukit/libcsupport/src/_rename_r.c b/cpukit/libcsupport/src/_rename_r.c index 12eeb59e53..d12355c8d0 100644 --- a/cpukit/libcsupport/src/_rename_r.c +++ b/cpukit/libcsupport/src/_rename_r.c @@ -20,7 +20,8 @@ #include #include -#include +#include +#include int _rename_r( struct _reent *ptr __attribute__((unused)), @@ -28,6 +29,104 @@ int _rename_r( const char *new ) { + int old_parent_pathlen; + rtems_filesystem_location_info_t old_loc; + rtems_filesystem_location_info_t old_parent_loc; + rtems_filesystem_location_info_t new_parent_loc; + int i; + int result; + const char *name; + bool free_old_parentloc = false; + + /* + * Get the parent node of the old path to be renamed. Find the parent path. + */ + + old_parent_pathlen = rtems_filesystem_dirname ( old ); + + if ( old_parent_pathlen == 0 ) + rtems_filesystem_get_start_loc( old, &i, &old_parent_loc ); + else { + result = rtems_filesystem_evaluate_path( old, old_parent_pathlen, + RTEMS_LIBIO_PERMS_WRITE, + &old_parent_loc, + false ); + if ( result != 0 ) + return -1; + + free_old_parentloc = true; + } + + /* + * Start from the parent to find the node that should be under it. + */ + + old_loc = old_parent_loc; + name = old + old_parent_pathlen; + name += rtems_filesystem_prefix_separators( name, strlen( name ) ); + + result = rtems_filesystem_evaluate_relative_path( name , strlen( name ), + 0, &old_loc, false ); + if ( result != 0 ) { + if ( free_old_parentloc ) + rtems_filesystem_freenode( &old_parent_loc ); + rtems_set_errno_and_return_minus_one( result ); + } + + /* + * Get the parent of the new node we are renaming to. + */ + + rtems_filesystem_get_start_loc( new, &i, &new_parent_loc ); + + if ( !new_parent_loc.ops->evalformake_h ) { + if ( free_old_parentloc ) + rtems_filesystem_freenode( &old_parent_loc ); + rtems_filesystem_freenode( &old_loc ); + rtems_set_errno_and_return_minus_one( ENOTSUP ); + } + + result = (*new_parent_loc.ops->evalformake_h)( &new[i], &new_parent_loc, &name ); + if ( result != 0 ) { + rtems_filesystem_freenode( &new_parent_loc ); + if ( free_old_parentloc ) + rtems_filesystem_freenode( &old_parent_loc ); + rtems_filesystem_freenode( &old_loc ); + rtems_set_errno_and_return_minus_one( result ); + } + + /* + * Check to see if the caller is trying to rename across file system + * boundaries. + */ + + if ( old_parent_loc.mt_entry != new_parent_loc.mt_entry ) { + rtems_filesystem_freenode( &new_parent_loc ); + if ( free_old_parentloc ) + rtems_filesystem_freenode( &old_parent_loc ); + rtems_filesystem_freenode( &old_loc ); + rtems_set_errno_and_return_minus_one( EXDEV ); + } + + if ( !new_parent_loc.ops->rename_h ) { + rtems_filesystem_freenode( &new_parent_loc ); + if ( free_old_parentloc ) + rtems_filesystem_freenode( &old_parent_loc ); + rtems_filesystem_freenode( &old_loc ); + rtems_set_errno_and_return_minus_one( ENOTSUP ); + } + + result = (*new_parent_loc.ops->rename_h)( &old_parent_loc, &old_loc, &new_parent_loc, name ); + + rtems_filesystem_freenode( &new_parent_loc ); + if ( free_old_parentloc ) + rtems_filesystem_freenode( &old_parent_loc ); + rtems_filesystem_freenode( &old_loc ); + + return result; +} + +#if 0 struct stat sb; int s; @@ -38,5 +137,6 @@ int _rename_r( if ( s < 0 ) return s; return S_ISDIR(sb.st_mode) ? rmdir( old ) : unlink( old ); -} +#endif + #endif diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am index 56cdaa0052..02443de495 100644 --- a/cpukit/libfs/Makefile.am +++ b/cpukit/libfs/Makefile.am @@ -31,7 +31,7 @@ libimfs_a_SOURCES += src/imfs/imfs_chown.c src/imfs/imfs_config.c \ src/imfs/imfs_debug.c src/imfs/imfs_rmnod.c src/imfs/imfs_symlink.c \ src/imfs/imfs_readlink.c src/imfs/imfs_fdatasync.c src/imfs/imfs_fcntl.c \ src/imfs/ioman.c src/imfs/miniimfs_init.c src/imfs/imfs_load_tar.c \ - src/imfs/imfs.h \ + src/imfs/imfs_rename.c src/imfs/imfs.h \ src/imfs/deviceerrno.c \ src/devfs/devfs_init.c src/devfs/devfs_eval.c src/devfs/devfs_mknod.c \ src/devfs/devfs_show.c src/devfs/devfs_node_type.c \ @@ -59,7 +59,7 @@ libdosfs_a_SOURCES += src/dosfs/msdos_create.c src/dosfs/msdos_dir.c \ src/dosfs/msdos_initsupp.c src/dosfs/msdos_misc.c \ src/dosfs/msdos_mknod.c src/dosfs/msdos_node_type.c \ src/dosfs/msdos_conv.c src/dosfs/msdos.h src/dosfs/msdos_format.c \ - src/dosfs/dosfs.h + src/dosfs/dosfs.h src/dosfs/msdos_rename.c endif # RFS diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h index 260c4d7919..acbea3161e 100644 --- a/cpukit/libfs/src/dosfs/msdos.h +++ b/cpukit/libfs/src/dosfs/msdos.h @@ -259,6 +259,11 @@ int msdos_utime( time_t modtime /* IN */ ); +int msdos_rename(rtems_filesystem_location_info_t *old_parent_loc, + rtems_filesystem_location_info_t *old_loc, + rtems_filesystem_location_info_t *new_parent_loc, + const char *new_name); + int msdos_initialize_support( rtems_filesystem_mount_table_entry_t *temp_mt_entry, const rtems_filesystem_operations_table *op_table, @@ -323,12 +328,6 @@ msdos_dir_chmod( int msdos_file_rmnod(rtems_filesystem_location_info_t *parent_pathloc, /* IN */ rtems_filesystem_location_info_t *pathloc /* IN */); -int msdos_file_link( - rtems_filesystem_location_info_t *to_loc, - rtems_filesystem_location_info_t *pa_loc, - const char *token -); - int msdos_dir_open( rtems_libio_t *iop, /* IN */ const char *pathname, /* IN */ diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c index a9d8dbaac3..bab4a63fa8 100644 --- a/cpukit/libfs/src/dosfs/msdos_create.c +++ b/cpukit/libfs/src/dosfs/msdos_create.c @@ -267,88 +267,3 @@ err: msdos_set_first_char4file_name(parent_loc->mt_entry, &dir_pos, 0xE5); return rc; } - -/* msdos_file_link -- - * Replacement for a file "link" operation. - * MSDOS FAT FS does not support links, but this call is needed to - * allow "rename" operations. The current NEWLIB rename performs a link - * from the old to the new name and then deletes the old filename. - * - * This pseudo-"link" operation will create a new directory entry, - * copy the file size and cluster information from the "old" - * to the "new" directory entry and then clear the file size and cluster - * info from the "old" filename, leaving this file as - * a valid, but empty entry. - * - * When this "link" call is part of a "rename" sequence, the "old" - * entry will be deleted in a subsequent "rmnod" call - * - * This function has been implemented by Thomas Doerfler, - * - * - * PARAMETERS: - * to_loc - node description for "existing" node - * par_loc - node description for "new" node - * token - name of new node - * - * RETURNS: - * RC_OK on success, or -1 if error occured (errno set appropriately) - */ -int -msdos_file_link(rtems_filesystem_location_info_t *to_loc, - rtems_filesystem_location_info_t *par_loc, - const char *name -) -{ - int rc = RC_OK; - rtems_status_code sc = RTEMS_SUCCESSFUL; - msdos_fs_info_t *fs_info = to_loc->mt_entry->fs_info; - fat_file_fd_t *to_fat_fd = to_loc->node_access; - const char *token; - int len; - - /* - * check spelling and format new node name - */ - if (MSDOS_NAME != msdos_get_token(name, strlen(name), &token, &len)) { - rtems_set_errno_and_return_minus_one(ENAMETOOLONG); - } - /* - * verify, that the existing node can be linked to - * check that nodes are in same FS/volume? - */ - if (to_loc->mt_entry->fs_info != par_loc->mt_entry->fs_info) { - rtems_set_errno_and_return_minus_one(EXDEV); - } - /* - * lock volume - */ - sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, - MSDOS_VOLUME_SEMAPHORE_TIMEOUT); - if (sc != RTEMS_SUCCESSFUL) - rtems_set_errno_and_return_minus_one(EIO); - - - /* - * create new directory entry as "hard link", - * copying relevant info from existing file - */ - rc = msdos_creat_node(par_loc,MSDOS_HARD_LINK,name,len,S_IFREG, - to_loc->node_access); - /* - * set file size and first cluster number of old entry to 0 - */ - if (rc == RC_OK) { - to_fat_fd->fat_file_size = 0; - to_fat_fd->cln = FAT_EOF; - rc = msdos_set_first_cluster_num(to_loc->mt_entry, to_fat_fd); - if (rc == RC_OK) { - rc = msdos_set_file_size(par_loc->mt_entry, to_fat_fd); - } - } - /* - * FIXME: check error/abort handling - */ - rtems_semaphore_release(fs_info->vol_sema); - return rc; -} diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c index 6fa3ddecf1..1bb5c73024 100644 --- a/cpukit/libfs/src/dosfs/msdos_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_dir.c @@ -146,7 +146,7 @@ msdos_format_dirent_with_dot(char *dst,const char *src) src_tmp = src; len = i; while (i-- > 0) { - *dst++ = tolower(*src_tmp++); + *dst++ = tolower((int)(*src_tmp++)); } /* * find last non-blank character of extension @@ -165,7 +165,7 @@ msdos_format_dirent_with_dot(char *dst,const char *src) len += i + 1; /* extension + dot */ src_tmp = src + MSDOS_SHORT_BASE_LEN; while (i-- > 0) { - *dst++ = tolower(*src_tmp++); + *dst++ = tolower((int)(*src_tmp++)); len++; } } diff --git a/cpukit/libfs/src/dosfs/msdos_eval.c b/cpukit/libfs/src/dosfs/msdos_eval.c index a97c245ed0..b216af4d18 100644 --- a/cpukit/libfs/src/dosfs/msdos_eval.c +++ b/cpukit/libfs/src/dosfs/msdos_eval.c @@ -108,7 +108,7 @@ msdos_eval_path( while ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN)) { type = msdos_get_token(&pathname[i], pathnamelen, &token, &token_len); - pathnamelen += token_len; + pathnamelen -= token_len; i += token_len; fat_fd = pathloc->node_access; @@ -152,7 +152,7 @@ msdos_eval_path( rtems_semaphore_release(fs_info->vol_sema); return (*pathloc->ops->evalpath_h)(&(pathname[i-token_len]), - pathnamelen - token_len, + pathnamelen + token_len, flags, pathloc); } } diff --git a/cpukit/libfs/src/dosfs/msdos_format.c b/cpukit/libfs/src/dosfs/msdos_format.c index d424c54aa6..d2ec19b267 100644 --- a/cpukit/libfs/src/dosfs/msdos_format.c +++ b/cpukit/libfs/src/dosfs/msdos_format.c @@ -648,7 +648,7 @@ static int msdos_format_determine_fmt_params for (cnt = 0; cnt < (sizeof(fmt_params->OEMName)-1); cnt++) { - if (isprint(*from)) { + if (isprint((int)*from)) { *to++ = *from++; } else { @@ -679,7 +679,7 @@ static int msdos_format_determine_fmt_params for (cnt = 0; cnt < (sizeof(fmt_params->VolLabel)-1); cnt++) { - if (isprint(*from)) { + if (isprint((int)*from)) { *to++ = *from++; } else { diff --git a/cpukit/libfs/src/dosfs/msdos_init.c b/cpukit/libfs/src/dosfs/msdos_init.c index 89a3dac274..1e17bf9545 100644 --- a/cpukit/libfs/src/dosfs/msdos_init.c +++ b/cpukit/libfs/src/dosfs/msdos_init.c @@ -19,27 +19,24 @@ #include "msdos.h" const rtems_filesystem_operations_table msdos_ops = { - msdos_eval_path, - msdos_eval4make, -#if 0 - NULL, /* msdos_link */ -#else - msdos_file_link, /* msdos_link (pseudo-functionality) */ -#endif - msdos_file_rmnod, - msdos_node_type, - msdos_mknod, - NULL, /* msdos_chown */ - msdos_free_node_info, - NULL, - msdos_initialize, - NULL, - msdos_shut_down, /* msdos_shut_down */ - NULL, /* msdos_utime */ - NULL, - NULL, - NULL, - NULL + .evalpath_h = msdos_eval_path, + .evalformake_h = msdos_eval4make, + .link_h = NULL, + .unlink_h = msdos_file_rmnod, + .node_type_h = msdos_node_type, + .mknod_h = msdos_mknod, + .chown_h = NULL, + .freenod_h = msdos_free_node_info, + .mount_h = NULL, + .fsmount_me_h = msdos_initialize, + .unmount_h = NULL, + .fsunmount_me_h = msdos_shut_down, + .utime_h = NULL, + .eval_link_h = NULL, + .symlink_h = NULL, + .readlink_h = NULL, + .rename_h = msdos_rename, + .statvfs_h = NULL }; /* msdos_initialize -- diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c index 003d2f57f4..4ab8e22b32 100644 --- a/cpukit/libfs/src/dosfs/msdos_misc.c +++ b/cpukit/libfs/src/dosfs/msdos_misc.c @@ -65,7 +65,7 @@ msdos_is_valid_name_char(const char ch) if (strchr(" +,;=[]", ch) != NULL) return MSDOS_NAME_LONG; - if ((ch == '.') || isalnum(ch) || + if ((ch == '.') || isalnum((int)ch) || (strchr("$%'-_@~`!(){}^#&", ch) != NULL)) return MSDOS_NAME_SHORT; diff --git a/cpukit/libfs/src/dosfs/msdos_rename.c b/cpukit/libfs/src/dosfs/msdos_rename.c new file mode 100644 index 0000000000..1ad625a251 --- /dev/null +++ b/cpukit/libfs/src/dosfs/msdos_rename.c @@ -0,0 +1,93 @@ +/* + * Routine to rename a MSDOS filesystem node + * + * Copyright (C) 2010 Chris Johns + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * @(#) $Id$ + * + */ +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "fat.h" +#include "fat_fat_operations.h" +#include "fat_file.h" + +#include "msdos.h" + +/* msdos_rename -- + * Rename the node by removing the exitsing directory entry and creating a + * new one. + * + * PARAMETERS: + * old_parent_loc - node description for the "old parent" node + * old_loc - node description for the "old" node + * new_parent_loc - node description for the "parent" node + * name - name of new node + * + * RETURNS: + * RC_OK on success, or -1 if error occured (errno set appropriately) + */ +int +msdos_rename(rtems_filesystem_location_info_t *old_parent_loc, + rtems_filesystem_location_info_t *old_loc, + rtems_filesystem_location_info_t *new_parent_loc, + const char *new_name) +{ + int rc = RC_OK; + rtems_status_code sc = RTEMS_SUCCESSFUL; + msdos_fs_info_t *fs_info = new_parent_loc->mt_entry->fs_info; + fat_file_fd_t *old_fat_fd = old_loc->node_access; + const char *token; + int len; + + /* + * check spelling and format new node name + */ + if (MSDOS_NAME != msdos_get_token(new_name, strlen(new_name), &token, &len)) { + rtems_set_errno_and_return_minus_one(ENAMETOOLONG); + } + /* + * lock volume + */ + sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, + MSDOS_VOLUME_SEMAPHORE_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + + /* + * create new directory entry as "hard link", copying relevant info from + * existing file + */ + rc = msdos_creat_node(new_parent_loc, + MSDOS_HARD_LINK,new_name,len,S_IFREG, + old_fat_fd); + if (rc != RC_OK) + { + rtems_semaphore_release(fs_info->vol_sema); + return rc; + } + + /* + * mark file removed + */ + rc = msdos_set_first_char4file_name(old_loc->mt_entry, + &old_fat_fd->dir_pos, + MSDOS_THIS_DIR_ENTRY_EMPTY); + + rtems_semaphore_release(fs_info->vol_sema); + return rc; +} diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h index d198c5d884..ae682c06fd 100644 --- a/cpukit/libfs/src/imfs/imfs.h +++ b/cpukit/libfs/src/imfs/imfs.h @@ -529,6 +529,13 @@ extern int IMFS_readlink( size_t bufsize ); +extern int IMFS_rename( + rtems_filesystem_location_info_t *old_loc, /* IN */ + rtems_filesystem_location_info_t *old_parent_loc, /* IN */ + rtems_filesystem_location_info_t *new_parent_loc, /* IN */ + const char *new_name /* IN */ +); + extern int IMFS_fdatasync( rtems_libio_t *iop ); diff --git a/cpukit/libfs/src/imfs/imfs_init.c b/cpukit/libfs/src/imfs/imfs_init.c index d1b2d44fcf..9dae7cc690 100644 --- a/cpukit/libfs/src/imfs/imfs_init.c +++ b/cpukit/libfs/src/imfs/imfs_init.c @@ -50,6 +50,7 @@ const rtems_filesystem_operations_table IMFS_ops = { IMFS_evaluate_link, IMFS_symlink, IMFS_readlink, + IMFS_rename, NULL }; diff --git a/cpukit/libfs/src/imfs/imfs_rename.c b/cpukit/libfs/src/imfs/imfs_rename.c new file mode 100644 index 0000000000..f45aa5b694 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_rename.c @@ -0,0 +1,54 @@ +/* + * IMFS_rename + * + * The following rouine creates a new link node under parent with the + * name given in name and removes the old. + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "imfs.h" +#include +#include + +int IMFS_rename( + rtems_filesystem_location_info_t *old_parent_loc, /* IN */ + rtems_filesystem_location_info_t *old_loc, /* IN */ + rtems_filesystem_location_info_t *new_parent_loc, /* IN */ + const char *new_name /* IN */ +) +{ + IMFS_jnode_t *the_jnode; + IMFS_jnode_t *new_parent; + + the_jnode = old_loc->node_access; + + strncpy( the_jnode->name, new_name, IMFS_NAME_MAX ); + + if ( the_jnode->Parent != NULL ) + rtems_chain_extract( (rtems_chain_node *) the_jnode ); + + new_parent = new_parent_loc->node_access; + the_jnode->Parent = new_parent; + + rtems_chain_append( &new_parent->info.directory.Entries, &the_jnode->Node ); + + /* + * Update the time. + */ + IMFS_update_ctime( the_jnode ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/miniimfs_init.c b/cpukit/libfs/src/imfs/miniimfs_init.c index 15ca663429..2244dfde7d 100644 --- a/cpukit/libfs/src/imfs/miniimfs_init.c +++ b/cpukit/libfs/src/imfs/miniimfs_init.c @@ -49,7 +49,9 @@ const rtems_filesystem_operations_table miniIMFS_ops = { NULL, /* XXX IMFS_utime, */ NULL, /* XXX IMFS_evaluate_link, */ NULL, /* XXX IMFS_symlink, */ - NULL /* XXX IMFS_readlink */ + NULL, /* XXX IMFS_readlink */ + NULL, /* XXX IMFS_rename */ + NULL /* XXX IMFS_statvfs */ }; /* diff --git a/cpukit/libfs/src/nfsclient/src/nfs.c b/cpukit/libfs/src/nfsclient/src/nfs.c index 7014055448..53bfa770fb 100644 --- a/cpukit/libfs/src/nfsclient/src/nfs.c +++ b/cpukit/libfs/src/nfsclient/src/nfs.c @@ -3262,7 +3262,7 @@ char *dev = 0; host++; } - if (isdigit(*host)) { + if (isdigit((int)*host)) { /* avoid using gethostbyname */ sprintf(dev,"%s:%s",uidhost,path); } else { diff --git a/cpukit/libfs/src/rfs/rtems-rfs-link.c b/cpukit/libfs/src/rfs/rtems-rfs-link.c index bfbcae66e7..5346eabae3 100644 --- a/cpukit/libfs/src/rfs/rtems-rfs-link.c +++ b/cpukit/libfs/src/rfs/rtems-rfs-link.c @@ -24,13 +24,15 @@ #include #include #include +#include int rtems_rfs_link (rtems_rfs_file_system* fs, const char* name, int length, rtems_rfs_ino parent, - rtems_rfs_ino target) + rtems_rfs_ino target, + bool link_dir) { rtems_rfs_inode_handle parent_inode; rtems_rfs_inode_handle target_inode; @@ -50,7 +52,11 @@ rtems_rfs_link (rtems_rfs_file_system* fs, if (rc) return rc; - if (S_ISDIR (rtems_rfs_inode_get_mode (&target_inode))) + /* + * If the target inode is a directory and we cannot link directories + * return a not supported error code. + */ + if (!link_dir && S_ISDIR (rtems_rfs_inode_get_mode (&target_inode))) { rtems_rfs_inode_close (fs, &target_inode); return ENOTSUP; @@ -99,11 +105,12 @@ rtems_rfs_unlink (rtems_rfs_file_system* fs, rtems_rfs_ino parent, rtems_rfs_ino target, uint32_t doff, - bool dir) + rtems_rfs_unlink_dir dir_mode) { rtems_rfs_inode_handle parent_inode; rtems_rfs_inode_handle target_inode; uint16_t links; + bool dir; int rc; if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK)) @@ -112,29 +119,35 @@ rtems_rfs_unlink (rtems_rfs_file_system* fs, rc = rtems_rfs_inode_open (fs, target, &target_inode, true); if (rc) return rc; - + + /* + * If a directory process the unlink mode. + */ + + dir = RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&target_inode)); if (dir) { - rc = rtems_rfs_dir_empty (fs, &target_inode); - if (rc > 0) - { - if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK)) - printf ("rtems-rfs: dir-empty: %d: %s\n", rc, strerror (rc)); - rtems_rfs_inode_close (fs, &target_inode); - return rc; - } - } - else - { - /* - * Directories not allowed and the target is a directory. - */ - if (RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&target_inode))) + switch (dir_mode) { - if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK)) - printf ("rtems-rfs: link is a directory\n"); - rtems_rfs_inode_close (fs, &target_inode); - return EISDIR; + case rtems_rfs_unlink_dir_denied: + if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK)) + printf ("rtems-rfs: link is a directory\n"); + rtems_rfs_inode_close (fs, &target_inode); + return EISDIR; + + case rtems_rfs_unlink_dir_if_empty: + rc = rtems_rfs_dir_empty (fs, &target_inode); + if (rc > 0) + { + if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK)) + printf ("rtems-rfs: dir-empty: %d: %s\n", rc, strerror (rc)); + rtems_rfs_inode_close (fs, &target_inode); + return rc; + } + break; + + default: + break; } } diff --git a/cpukit/libfs/src/rfs/rtems-rfs-link.h b/cpukit/libfs/src/rfs/rtems-rfs-link.h index d80db0195c..359360f0fd 100644 --- a/cpukit/libfs/src/rfs/rtems-rfs-link.h +++ b/cpukit/libfs/src/rfs/rtems-rfs-link.h @@ -26,20 +26,33 @@ #include /** - * Create a link. + * Directory unlink modes. + */ +typedef enum rtems_rfs_unlink_dir_e +{ + rtems_rfs_unlink_dir_denied, /**< Not allowed to unlink a directory. */ + rtems_rfs_unlink_dir_if_empty, /**< Unlink if the directory is empty. */ + rtems_rfs_unlink_dir_allowed /**< Unlinking of directories is allowed. */ +} rtems_rfs_unlink_dir; + +/** + * Create a link. Do not link directories unless renaming or you will create + * loops in the file system. * * @param fs The file system. * @param name The name of the link. * @param length The length of the name. * @param parent The inode number of the parent directory. * @param target The inode of the target. + * @param link_dir If true directories can be linked. Useful when renaming. * @return int The error number (errno). No error if 0. */ int rtems_rfs_link (rtems_rfs_file_system* fs, const char* name, int length, rtems_rfs_ino parent, - rtems_rfs_ino target); + rtems_rfs_ino target, + bool link_dir); /** * Unlink the node from the parent directory. A directory offset for the target @@ -50,14 +63,14 @@ int rtems_rfs_link (rtems_rfs_file_system* fs, * @param parent The inode number of the parent directory. * @param target The inode of the target. * @param doff Parent directory entry offset for the target entry. - * @param dir If true unlinking of directory nodes is allowed. + * @param dir_mode Directory unlink mode. * @return int The error number (errno). No error if 0. */ int rtems_rfs_unlink (rtems_rfs_file_system* fs, rtems_rfs_ino parent, rtems_rfs_ino target, uint32_t doff, - bool dir); + rtems_rfs_unlink_dir dir_mode); /** * Symbolic link is an inode that has a path attached. diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c index f22e3d6913..1de55a0e5b 100644 --- a/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c +++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c @@ -205,7 +205,7 @@ rtems_rfs_rtems_dir_rmnod (rtems_filesystem_location_info_t* parent_pathloc, rtems_rfs_rtems_lock (fs); - rc = rtems_rfs_unlink (fs, parent, ino, doff, true); + rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_if_empty); if (rc) { rtems_rfs_rtems_unlock (fs); diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems.c index 97e803a615..081f97646d 100644 --- a/cpukit/libfs/src/rfs/rtems-rfs-rtems.c +++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems.c @@ -478,7 +478,7 @@ rtems_rfs_rtems_link (rtems_filesystem_location_info_t* to_loc, rtems_rfs_rtems_lock (fs); - rc = rtems_rfs_link (fs, name, strlen (name), parent, target); + rc = rtems_rfs_link (fs, name, strlen (name), parent, target, false); if (rc) { rtems_rfs_rtems_unlock (fs); @@ -514,7 +514,7 @@ rtems_rfs_rtems_unlink (rtems_filesystem_location_info_t* parent_loc, printf("rtems-rfs-rtems: unlink: parent:%ld doff:%lu ino:%ld\n", parent, doff, ino); - rc = rtems_rfs_unlink (fs, parent, ino, doff, false); + rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_denied); if (rc) { rtems_rfs_rtems_unlock (fs); @@ -1043,6 +1043,7 @@ rtems_rfs_rtems_mknod (const char *name, * * @param parent_pathloc * @param pathloc + * @return int */ int rtems_rfs_rtems_rmnod (rtems_filesystem_location_info_t* parent_pathloc, @@ -1060,7 +1061,7 @@ rtems_rfs_rtems_rmnod (rtems_filesystem_location_info_t* parent_pathloc, rtems_rfs_rtems_lock (fs); - rc = rtems_rfs_unlink (fs, parent, ino, doff, false); + rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_denied); if (rc) { rtems_rfs_rtems_unlock (fs); @@ -1076,6 +1077,7 @@ rtems_rfs_rtems_rmnod (rtems_filesystem_location_info_t* parent_pathloc, * everything related to this device. * * @param iop + * @return int */ int rtems_rfs_rtems_fdatasync (rtems_libio_t* iop) @@ -1089,6 +1091,68 @@ rtems_rfs_rtems_fdatasync (rtems_libio_t* iop) return 0; } +/** + * Rename the node. + * + * @param old_parent_loc The old name's parent location. + * @param old_loc The old name's location. + * @param new_parent_loc The new name's parent location. + * @param new_name The new name. + * @return int + */ +int +rtems_rfs_rtems_rename(rtems_filesystem_location_info_t* old_parent_loc, + rtems_filesystem_location_info_t* old_loc, + rtems_filesystem_location_info_t* new_parent_loc, + const char* new_name) +{ + rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (old_loc); + rtems_rfs_ino old_parent; + rtems_rfs_ino new_parent; + rtems_rfs_ino ino; + uint32_t doff; + int rc; + + old_parent = rtems_rfs_rtems_get_pathloc_ino (old_parent_loc); + new_parent = rtems_rfs_rtems_get_pathloc_ino (new_parent_loc); + + ino = rtems_rfs_rtems_get_pathloc_ino (old_loc); + doff = rtems_rfs_rtems_get_pathloc_doff (old_loc); + + if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RENAME)) + printf ("rtems-rfs: rename: ino:%ld doff:%lu, new parent:%ld new name:%s\n", + ino, doff, new_parent, new_name); + + rtems_rfs_rtems_lock (fs); + + /* + * Link to the inode before unlinking so the inode is not erased when + * unlinked. + */ + rc = rtems_rfs_link (fs, new_name, strlen (new_name), new_parent, ino, true); + if (rc) + { + rtems_rfs_rtems_unlock (fs); + return rtems_rfs_rtems_error ("rename: linking", rc); + } + + /* + * Unlink all inodes even directories with the dir option as false because a + * directory may not be empty. + */ + rc = rtems_rfs_unlink (fs, old_parent, ino, doff, + rtems_rfs_unlink_dir_allowed); + if (rc) + { + rtems_rfs_rtems_unlock (fs); + return rtems_rfs_rtems_error ("rename: unlinking", rc); + } + + rtems_rfs_rtems_unlock (fs); + + return 0; +} + /** * Return the file system stat data. * @@ -1150,7 +1214,7 @@ int rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t *mt_entry); int rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t *mt_entry); /** - * RFS file system operations table + * RFS file system operations table. */ const rtems_filesystem_operations_table rtems_rfs_ops = { @@ -1170,6 +1234,7 @@ const rtems_filesystem_operations_table rtems_rfs_ops = .eval_link_h = NULL, /* never called cause we lie in the node type */ .symlink_h = rtems_rfs_rtems_symlink, .readlink_h = rtems_rfs_rtems_readlink, + .rename_h = rtems_rfs_rtems_rename, .statvfs_h = rtems_rfs_rtems_statvfs }; -- cgit v1.2.3