From: Charles Manning Date: Tue, 23 Nov 2010 21:04:20 +0000 (+1300) Subject: yaffs direct: Fix some more error handling and directory name handling X-Git-Tag: linux-mainline-patchset-4~60 X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=commitdiff_plain;h=2b102a7c5c9a5332e8159aa1c8c7d149596327ff yaffs direct: Fix some more error handling and directory name handling All Timothy's tests passing. Signed-off-by: Charles Manning --- diff --git a/direct/yaffsfs.c b/direct/yaffsfs.c index 2016101..29a9209 100644 --- a/direct/yaffsfs.c +++ b/direct/yaffsfs.c @@ -340,6 +340,42 @@ int yaffsfs_CheckNameLength(const char *name) return retVal; } + +static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path) +{ + YCHAR *alt_path = NULL; + int path_length; + int i; + + /* + * We don't have a definition for max path length. + * We will use 3 * max name length instead. + */ + *ret_path = NULL; + path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1); + + /* If the last character is a path divider, then we need to + * trim it back so that the name look-up works properly. + * eg. /foo/new_dir/ -> /foo/newdir + * Curveball: Need to handle multiple path dividers: + * eg. /foof/sdfse///// -> /foo/sdfse + */ + if(path_length > 0 && + yaffsfs_IsPathDivider(path[path_length-1])){ + alt_path = YMALLOC(path_length + 1); + if(!alt_path) + return -1; + strcpy(alt_path, path); + for(i = path_length-1; + i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); + i--) + alt_path[i] = (YCHAR) 0; + } + *ret_path = alt_path; + return 0; +} + + LIST_HEAD(yaffsfs_deviceList); /* @@ -1241,7 +1277,11 @@ int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory) if(!dir && notDir) yaffsfs_SetError(-ENOTDIR); - else if(!dir || !obj) + else if(!dir) + yaffsfs_SetError(-ENOENT); + else if(yaffs_strncmp(name,_Y("."),2) == 0) + yaffsfs_SetError(-EINVAL); + else if(!obj) yaffsfs_SetError(-ENOENT); else if(obj->my_dev->read_only) yaffsfs_SetError(-EINVAL); @@ -1249,6 +1289,8 @@ int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory) yaffsfs_SetError(-EISDIR); else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) yaffsfs_SetError(-ENOTDIR); + else if(isDirectory && obj == obj->my_dev->root_dir) + yaffsfs_SetError(-EBUSY); /* Can't rmdir a root */ else { result = yaffs_unlinker(dir,name); @@ -1278,22 +1320,43 @@ int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) int rename_allowed = 1; int notOldDir; int notNewDir; - - yaffsfs_Lock(); + YCHAR *alt_newpath=NULL; if(yaffsfs_CheckPath(newPath) < 0){ yaffsfs_SetError(-ENAMETOOLONG); return -1; } + if(yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0){ + yaffsfs_SetError(-ENOMEM); + return -1; + } + if(alt_newpath) + newPath = alt_newpath; + + yaffsfs_Lock(); + + olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0,¬OldDir); newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0,¬NewDir); obj = yaffsfs_FindObject(NULL,oldPath,0,0,NULL,NULL); + /* If the object being renamed is a directory and the + * path ended with a "/" then the olddir == obj. + * We pass through NULL for the old name to tell the lower layers + * to use olddir as the object. + */ + + if(olddir == obj) + oldname = NULL; + if((!olddir && notOldDir) || (!newdir && notNewDir)) { yaffsfs_SetError(-ENOTDIR); rename_allowed = 0; - } else if(!olddir || !newdir || !obj) { + } else if (olddir && oldname && yaffs_strncmp(oldname, _Y("."),2) == 0){ + yaffsfs_SetError(-EINVAL); + rename_allowed = 0; + }else if(!olddir || !newdir || !obj) { yaffsfs_SetError(-ENOENT); rename_allowed = 0; } else if(obj->my_dev->read_only){ @@ -1307,7 +1370,8 @@ int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) /* * It is a directory, check that it is not being renamed to * being its own decendent. - * Do this by tracing from the new directory back to the root, checking for obj + * Do this by tracing from the new directory back to the root, + * checking for obj */ struct yaffs_obj *xx = newdir; @@ -1326,6 +1390,9 @@ int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) yaffsfs_Unlock(); + if(alt_newpath) + YFREE(alt_newpath); + return (result == YAFFS_FAIL) ? -1 : 0; } @@ -1933,41 +2000,6 @@ int yaffs_fchmod(int fd, mode_t mode) return retVal; } - -static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path) -{ - YCHAR *alt_path = NULL; - int path_length; - int i; - - /* - * We don't have a definition for max path length. - * We will use 3 * max name length instead. - */ - *ret_path = NULL; - path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1); - - /* If the last character is a path divider, then we need to - * trim it back so that the name look-up works properly. - * eg. /foo/new_dir/ -> /foo/newdir - * Curveball: Need to handle multiple path dividers: - * eg. /foof/sdfse///// -> /foo/sdfse - */ - if(path_length > 0 && - yaffsfs_IsPathDivider(path[path_length-1])){ - alt_path = YMALLOC(path_length + 1); - if(!alt_path) - return -1; - strcpy(alt_path, path); - for(i = path_length-1; - i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); - i--) - alt_path[i] = (YCHAR) 0; - } - *ret_path = alt_path; - return 0; -} - int yaffs_mkdir(const YCHAR *path, mode_t mode) { struct yaffs_obj *parent = NULL; diff --git a/yaffs_guts.c b/yaffs_guts.c index 2348a94..1bc6d51 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -1620,6 +1620,10 @@ static int yaffs_change_obj_name(struct yaffs_obj *obj, return YAFFS_FAIL; } + +/* Note: + * If old_name is NULL then we take old_dir as the object to be renamed. + */ int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, struct yaffs_obj *new_dir, const YCHAR * new_name) { @@ -1641,7 +1645,9 @@ int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, * While look-up is case insensitive, the name isn't. * Therefore we might want to change x.txt to X.txt */ - if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0) + if (old_dir == new_dir && + old_name && new_name && + yaffs_strcmp(old_name, new_name) == 0) force = 1; #endif @@ -1650,7 +1656,13 @@ int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, /* ENAMETOOLONG */ return YAFFS_FAIL; - obj = yaffs_find_by_name(old_dir, old_name); + if(old_name) + obj = yaffs_find_by_name(old_dir, old_name); + else{ + obj = old_dir; + old_dir = obj->parent; + } + if (obj && obj->rename_allowed) {