[Nautilus-list] symlink-chasing



Hi,

file-method.c:get_stat_info() seems to leak file_info->symlink_name
anytime you have two levels of symlink; also, for circular links it
gets in an infinite loop, leaking that string each time.
I'm guessing this is the cause of:
 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=54684
 http://bugzilla.gnome.org/show_bug.cgi?id=62494

Can someone precisely define for me what file_info->symlink_name is
supposed to contain, so I can figure out the best way to handle
cycles?

If I just add "recursive == TRUE" as another termination condition to
this if statement, will it fix it?
	
			if ((options & GNOME_VFS_FILE_INFO_FOLLOW_LINKS) == 0
					/* we don't care to follow links */
				|| lstat (file_info->symlink_name, statptr) != 0
					/* we can't make out where this points to */
				|| !S_ISLNK (statptr->st_mode)) {
					/* the next level is not a link */
				break;
			}

Obviously the memleak needs fixing as well, aside from ending the
infinite loop.

Appending the function for reference.

Havoc

static GnomeVFSResult
get_stat_info (GnomeVFSFileInfo *file_info,
	       const gchar *full_name,
	       GnomeVFSFileInfoOptions options,
	       struct stat *statptr)
{
	struct stat statbuf;
	gboolean followed_symlink;
	gboolean is_symlink;
	gboolean recursive;
	char *link_file_path;

	followed_symlink = FALSE;
	
	recursive = FALSE;

	GNOME_VFS_FILE_INFO_SET_LOCAL (file_info, TRUE);

	if (statptr == NULL) {
		statptr = &statbuf;
	}

	if (lstat (full_name, statptr) != 0) {
		return gnome_vfs_result_from_errno ();
	}

	is_symlink = S_ISLNK (statptr->st_mode);

	if ((options & GNOME_VFS_FILE_INFO_FOLLOW_LINKS) && is_symlink) {
		if (stat (full_name, statptr) != 0) {
			if (errno == ELOOP) {
				recursive = TRUE;
			}

			/* It's a broken symlink, revert to the lstat. This is sub-optimal but
			 * acceptable because it's not a common case.
			 */
			if (lstat (full_name, statptr) != 0) {
				return gnome_vfs_result_from_errno ();
			}
		}
		GNOME_VFS_FILE_INFO_SET_SYMLINK (file_info, TRUE);
		followed_symlink = TRUE;
	}

	gnome_vfs_stat_to_file_info (file_info, statptr);

	if (is_symlink) {
		link_file_path = g_strdup (full_name);
		
		/* We will either successfully read the link name or return
		 * NULL if read_link fails -- flag it as a valid field either
		 * way.
		 */
		file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SYMLINK_NAME;

		while (TRUE) {			
			/* Deal with multiple-level symlinks by following them as
			 * far as we can.
			 */

			file_info->symlink_name = read_link (link_file_path);
			if (file_info->symlink_name == NULL) {
				g_free (link_file_path);
				return gnome_vfs_result_from_errno ();
			}
			
			if ((options & GNOME_VFS_FILE_INFO_FOLLOW_LINKS) == 0
					/* we don't care to follow links */
				|| lstat (file_info->symlink_name, statptr) != 0
					/* we can't make out where this points to */
				|| !S_ISLNK (statptr->st_mode)) {
					/* the next level is not a link */
				break;
			}
			g_free (link_file_path);
			link_file_path = g_strdup (file_info->symlink_name);
		}
		g_free (link_file_path);
	}

	return GNOME_VFS_OK;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]