+ /* Change the item to a node */
+ if( p_parent->i_children == -1 )
+ {
+ playlist_LockItemToNode( p_playlist,p_parent );
+ }
+
+ /* get the first directory entry */
+ i_dir_content = scandir( psz_name, &pp_dir_content, Filter, alphasort );
+ if( i_dir_content == -1 )
+ {
+ msg_Warn( p_playlist, "Failed to read directory" );
+ return VLC_EGENERIC;
+ }
+ else if( i_dir_content <= 0 )
+ {
+ /* directory is empty */
+ return VLC_SUCCESS;
+ }
+
+ /* While we still have entries in the directory */
+ for( i = 0; i < i_dir_content; i++ )
+ {
+ struct dirent *p_dir_content = pp_dir_content[i];
+ int i_size_entry = strlen( psz_name ) +
+ strlen( p_dir_content->d_name ) + 2;
+ char *psz_uri = (char *)malloc( sizeof(char) * i_size_entry );
+
+ sprintf( psz_uri, "%s/%s", psz_name, p_dir_content->d_name );
+
+ /* if it starts with '.' then forget it */
+ if( p_dir_content->d_name[0] != '.' )
+ {
+#if defined( S_ISDIR )
+ struct stat stat_data;
+
+ if( !stat( psz_uri, &stat_data )
+ && S_ISDIR(stat_data.st_mode) && i_mode != MODE_COLLAPSE )
+#elif defined( DT_DIR )
+ if( ( p_dir_content->d_type & DT_DIR ) && i_mode != MODE_COLLAPSE )
+#else
+ if( 0 )
+#endif
+ {
+#if defined( S_ISLNK )
+/*
+ * FIXME: there is a ToCToU race condition here; but it is rather tricky
+ * impossible to fix while keeping some kind of portable code, and maybe even
+ * in a non-portable way.
+ */
+ if( lstat( psz_uri, &stat_data )
+ || S_ISLNK(stat_data.st_mode) )
+ {
+ msg_Dbg( p_playlist, "Skipping directory symlink %s",
+ psz_uri );
+ free( psz_uri );
+ continue;
+ }
+#endif
+ if( i_mode == MODE_NONE )
+ {
+ msg_Dbg( p_playlist, "Skipping subdirectory %s", psz_uri );
+ free( psz_uri );
+ continue;
+ }
+ else if( i_mode == MODE_EXPAND )
+ {
+ char *psz_newname, *psz_tmp;
+ msg_Dbg(p_playlist, "Reading subdirectory %s", psz_uri );
+
+ psz_tmp = FromLocale( p_dir_content->d_name );
+ psz_newname = vlc_fix_readdir_charset(
+ p_playlist, psz_tmp );
+ LocaleFree( psz_tmp );
+
+ p_node = playlist_NodeCreate( p_playlist,
+ p_parent->pp_parents[0]->i_view,
+ psz_newname, p_parent );
+
+ playlist_CopyParents( p_parent, p_node );
+
+ p_node->input.i_type = ITEM_TYPE_DIRECTORY;
+
+ if( ReadDir( p_playlist, psz_uri , MODE_EXPAND,
+ p_node ) != VLC_SUCCESS )
+ {
+ return VLC_EGENERIC;
+ }
+
+ /* an strdup() just because of Mac OS X */
+ free( psz_newname );
+ }
+ }
+ else
+ {
+ playlist_item_t *p_item;
+ char *psz_tmp1, *psz_tmp2, *psz_loc;
+
+ if( i_extensions > 0 )
+ {
+ char *psz_dot = strrchr( p_dir_content->d_name, '.' );
+ if( psz_dot++ && *psz_dot )
+ {
+ int a;
+ for( a = 0; a < i_extensions; a++ )
+ {
+ if( !strcmp( psz_dot, ppsz_extensions[a] ) )
+ break;
+ }
+ if( a < i_extensions )
+ {
+ msg_Dbg( p_playlist, "Ignoring file %s", psz_uri );
+ free( psz_uri );
+ continue;
+ }
+ }
+ }
+
+ psz_loc = FromLocale( psz_uri );
+ psz_tmp1 = vlc_fix_readdir_charset( VLC_OBJECT(p_playlist),
+ psz_loc );
+ LocaleFree( psz_loc );
+
+ psz_loc = FromLocale( p_dir_content->d_name );
+ psz_tmp2 = vlc_fix_readdir_charset( VLC_OBJECT(p_playlist),
+ psz_loc );
+ LocaleFree( psz_loc );
+
+ p_item = playlist_ItemNewWithType( VLC_OBJECT(p_playlist),
+ psz_tmp1, psz_tmp2, ITEM_TYPE_VFILE );
+ playlist_NodeAddItem( p_playlist,p_item,
+ p_parent->pp_parents[0]->i_view,
+ p_parent,
+ PLAYLIST_APPEND | PLAYLIST_PREPARSE,
+ PLAYLIST_END );
+
+ playlist_CopyParents( p_parent, p_item );
+ }
+ }
+ free( psz_uri );
+ }
+
+ for( i = 0; i < i_extensions; i++ )
+ {
+ if( ppsz_extensions[i] )
+ free( ppsz_extensions[i] );
+ }
+ if( ppsz_extensions ) free( ppsz_extensions );
+ if( psz_ignore ) free( psz_ignore );
+
+ for( i = 0; i < i_dir_content; i++ )
+ if( pp_dir_content[i] ) free( pp_dir_content[i] );
+ if( pp_dir_content ) free( pp_dir_content );
+ return VLC_SUCCESS;