diff options
| -rw-r--r-- | fs/sysfs/symlink.c | 88 | 
1 files changed, 42 insertions, 46 deletions
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3eac20c63c41..5f66c4466151 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -19,39 +19,6 @@  #include "sysfs.h" -static int object_depth(struct sysfs_dirent *sd) -{ -	int depth = 0; - -	for (; sd->s_parent; sd = sd->s_parent) -		depth++; - -	return depth; -} - -static int object_path_length(struct sysfs_dirent * sd) -{ -	int length = 1; - -	for (; sd->s_parent; sd = sd->s_parent) -		length += strlen(sd->s_name) + 1; - -	return length; -} - -static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) -{ -	--length; -	for (; sd->s_parent; sd = sd->s_parent) { -		int cur = strlen(sd->s_name); - -		/* back up enough to print this bus id with '/' */ -		length -= cur; -		strncpy(buffer + length, sd->s_name, cur); -		*(buffer + --length) = '/'; -	} -} -  /**   *	sysfs_create_link - create symlink between two objects.   *	@kobj:	object whose directory we're creating the link in. @@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char  	return error;  } -  /**   *	sysfs_remove_link - remove symlink in object's directory.   *	@kobj:	object we're acting for. @@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)  	sysfs_hash_and_remove(kobj->sd, name);  } -static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, -				 struct sysfs_dirent * target_sd, char *path) +static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, +				 struct sysfs_dirent *target_sd, char *path)  { -	char * s; -	int depth, size; +	struct sysfs_dirent *base, *sd; +	char *s = path; +	int len = 0; + +	/* go up to the root, stop at the base */ +	base = parent_sd; +	while (base->s_parent) { +		sd = target_sd->s_parent; +		while (sd->s_parent && base != sd) +			sd = sd->s_parent; + +		if (base == sd) +			break; + +		strcpy(s, "../"); +		s += 3; +		base = base->s_parent; +	} + +	/* determine end of target string for reverse fillup */ +	sd = target_sd; +	while (sd->s_parent && sd != base) { +		len += strlen(sd->s_name) + 1; +		sd = sd->s_parent; +	} -	depth = object_depth(parent_sd); -	size = object_path_length(target_sd) + depth * 3 - 1; -	if (size > PATH_MAX) +	/* check limits */ +	if (len < 2) +		return -EINVAL; +	len--; +	if ((s - path) + len > PATH_MAX)  		return -ENAMETOOLONG; -	pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); +	/* reverse fillup of target string from target to base */ +	sd = target_sd; +	while (sd->s_parent && sd != base) { +		int slen = strlen(sd->s_name); -	for (s = path; depth--; s += 3) -		strcpy(s,"../"); +		len -= slen; +		strncpy(s + len, sd->s_name, slen); +		if (len) +			s[--len] = '/'; -	fill_object_path(target_sd, path, size); -	pr_debug("%s: path = '%s'\n", __FUNCTION__, path); +		sd = sd->s_parent; +	}  	return 0;  }  | 

