+ if (dir == NULL || attrname == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (dir->attributes == NULL)
+ if ((sysfs_read_dir_attributes(dir) != 0)
+ || (dir->attributes == NULL))
+ return NULL;
+
+ attr = (struct sysfs_attribute *)dlist_find_custom
+ (dir->attributes, attrname, dir_attribute_name_equal);
+ if (attr != NULL) {
+ /*
+ * don't read here since we would have read the attribute in
+ * in the routine that called this routine
+ */
+ return attr;
+ } else {
+ memset(new_path, 0, SYSFS_PATH_MAX);
+ strcpy(new_path, dir->path);
+ strcat(new_path, "/");
+ strcat(new_path, attrname);
+ if ((sysfs_path_is_file(new_path)) == 0) {
+ if ((add_attribute(dir, new_path)) == 0) {
+ attr = (struct sysfs_attribute *)dlist_find_custom
+ (dir->attributes, attrname, dir_attribute_name_equal);
+ }
+ return attr;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * sysfs_get_directory_link: retrieves link from one directory list
+ * @dir: directory to retrieve link from
+ * @linkname: name of link to look for
+ * returns reference to sysfs_link if found and NULL if not found
+ */
+struct sysfs_link *sysfs_get_directory_link
+ (struct sysfs_directory *dir, unsigned char *linkname)
+{
+ if (dir == NULL || linkname == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (dir->links == NULL)
+ if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL))
+ return NULL;
+
+ return (struct sysfs_link *)dlist_find_custom(dir->links,
+ linkname, dir_link_name_equal);
+}
+
+/**
+ * sysfs_get_subdirectory: retrieves subdirectory by name.
+ * @dir: directory to search for subdirectory.
+ * @subname: subdirectory name to get.
+ * returns reference to subdirectory or NULL if not found
+ */
+struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir,
+ unsigned char *subname)
+{
+ struct sysfs_directory *sub = NULL, *cursub = NULL;
+
+ if (dir == NULL || subname == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (dir->subdirs == NULL)
+ if (sysfs_read_dir_subdirs(dir) != 0)
+ return NULL;
+
+ sub = (struct sysfs_directory *)dlist_find_custom(dir->subdirs,
+ subname, dir_subdir_name_equal);
+ if (sub != NULL)
+ return sub;
+
+ if (dir->subdirs != NULL) {
+ dlist_for_each_data(dir->subdirs, cursub,
+ struct sysfs_directory) {
+ if (cursub->subdirs == NULL) {
+ if (sysfs_read_dir_subdirs(cursub) != 0)
+ continue;
+ if (cursub->subdirs == NULL)
+ continue;
+ }
+ sub = sysfs_get_subdirectory(cursub, subname);
+ if (sub != NULL)
+ return sub;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * sysfs_get_subdirectory_link: looks through all subdirs for specific link.
+ * @dir: directory and subdirectories to search for link.
+ * @linkname: link name to get.
+ * returns reference to link or NULL if not found
+ */
+struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
+ unsigned char *linkname)
+{
+ struct sysfs_directory *cursub = NULL;
+ struct sysfs_link *ln = NULL;
+
+ if (dir == NULL || linkname == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ln = sysfs_get_directory_link(dir, linkname);
+ if (ln != NULL)
+ return ln;
+
+ if (dir->subdirs == NULL)
+ if (sysfs_read_dir_subdirs(dir) != 0)
+ return NULL;
+
+ if (dir->subdirs != NULL) {
+ dlist_for_each_data(dir->subdirs, cursub,
+ struct sysfs_directory) {
+ ln = sysfs_get_subdirectory_link(cursub, linkname);
+ if (ln != NULL)
+ return ln;
+ }
+ }
+ return NULL;