X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fdirectory.c;h=05b6ec1615e65737d233c2f837db8e8bc32de479;hb=b694b642baea32dfa21ec9d771ef7295ac398d6d;hp=e01fed287b0b644fe7867cdcfb69f003deb4d3bd;hpb=f556b69004ce0978944d0f1ce024f04b9130b53a;p=vlc diff --git a/modules/access/directory.c b/modules/access/directory.c index e01fed287b..05b6ec1615 100644 --- a/modules/access/directory.c +++ b/modules/access/directory.c @@ -1,7 +1,7 @@ /***************************************************************************** * directory.c: expands a directory (directory: access plug-in) ***************************************************************************** - * Copyright (C) 2002-2007 the VideoLAN team + * Copyright (C) 2002-2008 the VideoLAN team * $Id$ * * Authors: Derk-Jan Hartman @@ -26,33 +26,25 @@ * Preamble *****************************************************************************/ -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include -#include -#include -#include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif -#ifdef HAVE_ERRNO_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif #ifdef HAVE_UNISTD_H # include #elif defined( WIN32 ) && !defined( UNDER_CE ) # include -#elif defined( UNDER_CE ) -# define strcoll strcmp #endif #ifdef HAVE_DIRENT_H @@ -60,6 +52,8 @@ #endif #include +#include +#include /***************************************************************************** * Module descriptor @@ -67,8 +61,6 @@ static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); -static int DemuxOpen ( vlc_object_t * ); - #define RECURSIVE_TEXT N_("Subdirectory behavior") #define RECURSIVE_LONGTEXT N_( \ "Select whether subdirectories must be expanded.\n" \ @@ -76,9 +68,9 @@ static int DemuxOpen ( vlc_object_t * ); "collapse: subdirectories appear but are expanded on first play.\n" \ "expand: all subdirectories are expanded.\n" ) -static const char *psz_recursive_list[] = { "none", "collapse", "expand" }; -static const char *psz_recursive_list_text[] = { N_("none"), N_("collapse"), - N_("expand") }; +static const char *const psz_recursive_list[] = { "none", "collapse", "expand" }; +static const char *const psz_recursive_list_text[] = { + N_("none"), N_("collapse"), N_("expand") }; #define IGNORE_TEXT N_("Ignored extensions") #define IGNORE_LONGTEXT N_( \ @@ -87,28 +79,22 @@ static const char *psz_recursive_list_text[] = { N_("none"), N_("collapse"), "This is useful if you add directories that contain playlist files " \ "for instance. Use a comma-separated list of extensions." ) -vlc_module_begin(); - set_category( CAT_INPUT ); - set_shortname( _("Directory" ) ); - set_subcategory( SUBCAT_INPUT_ACCESS ); - set_description( _("Standard filesystem directory input") ); - set_capability( "access2", 55 ); - add_shortcut( "directory" ); - add_shortcut( "dir" ); - add_shortcut( "file" ); +vlc_module_begin () + set_category( CAT_INPUT ) + set_shortname( N_("Directory" ) ) + set_subcategory( SUBCAT_INPUT_ACCESS ) + set_description( N_("Standard filesystem directory input") ) + set_capability( "access", 55 ) + add_shortcut( "directory" ) + add_shortcut( "dir" ) + add_shortcut( "file" ) add_string( "recursive", "expand" , NULL, RECURSIVE_TEXT, - RECURSIVE_LONGTEXT, VLC_FALSE ); - change_string_list( psz_recursive_list, psz_recursive_list_text, 0 ); - add_string( "ignore-filetypes", "m3u,db,nfo,jpg,gif,sfv,txt,sub,idx,srt,cue", - NULL, IGNORE_TEXT, IGNORE_LONGTEXT, VLC_FALSE ); - set_callbacks( Open, Close ); - - add_submodule(); - set_description( "Directory EOF"); - set_capability( "demux2", 0 ); - add_shortcut( "directory" ); - set_callbacks( DemuxOpen, NULL ); -vlc_module_end(); + RECURSIVE_LONGTEXT, false ) + change_string_list( psz_recursive_list, psz_recursive_list_text, 0 ) + add_string( "ignore-filetypes", "m3u,db,nfo,ini,jpg,jpeg,ljpg,gif,png,pgm,pgmyuv,pbm,pam,tga,bmp,pnm,xpm,xcf,pcx,tif,tiff,lbm,sfv,txt,sub,idx,srt,cue,ssa", + NULL, IGNORE_TEXT, IGNORE_LONGTEXT, false ) + set_callbacks( Open, Close ) +vlc_module_end () /***************************************************************************** @@ -122,21 +108,30 @@ enum MODE_NONE }; -typedef struct stat_list_t stat_list_t; - -static int Read( access_t *, uint8_t *, int ); -static int ReadNull( access_t *, uint8_t *, int ); -static int Control( access_t *, int, va_list ); - -static int Demux( demux_t *p_demux ); -static int DemuxControl( demux_t *p_demux, int i_query, va_list args ); - +typedef struct directory_t directory_t; +struct directory_t +{ + directory_t *parent; + DIR *handle; + char *uri; +#ifndef WIN32 + struct stat st; +#endif + char path[1]; +}; -static int ReadDir( playlist_t *, const char *psz_name, int i_mode, - playlist_item_t *, playlist_item_t *, input_item_t *, - DIR *handle, stat_list_t *stats ); +struct access_sys_t +{ + directory_t *current; + DIR *handle; + char *ignored_exts; + int mode; + int i_item_count; + char *psz_xspf_extension; +}; -static DIR *OpenDir (vlc_object_t *obj, const char *psz_name); +static block_t *Block( access_t * ); +static int Control( access_t *, int, va_list ); /***************************************************************************** * Open: open the directory @@ -144,20 +139,60 @@ static DIR *OpenDir (vlc_object_t *obj, const char *psz_name); static int Open( vlc_object_t *p_this ) { access_t *p_access = (access_t*)p_this; + access_sys_t *p_sys; + + if( !p_access->psz_path ) + return VLC_EGENERIC; + + DIR *handle; + if (strcmp (p_access->psz_path, "-")) + handle = utf8_opendir (p_access->psz_path); + else + { +#if 0 /* This won't work yet, it generates paths like "-/music.ogg". + * We'd need to use openat() here and in the file access... */ + int fd = dup (0); + handle = fdopendir (fd); + if (handle == NULL) + close (fd); +#else + return VLC_EGENERIC; +#endif + } - DIR *handle = OpenDir (p_this, p_access->psz_path); if (handle == NULL) return VLC_EGENERIC; - p_access->p_sys = (access_sys_t *)handle; + p_sys = malloc (sizeof (*p_sys)); + if (!p_sys) + { + closedir( handle ); + return VLC_ENOMEM; + } + + p_access->p_sys = p_sys; + p_sys->current = NULL; + p_sys->handle = handle; + p_sys->ignored_exts = var_CreateGetString (p_access, "ignore-filetypes"); + p_sys->i_item_count = 0; + p_sys->psz_xspf_extension = strdup( "" ); + + /* Handle mode */ + char *psz = var_CreateGetString( p_access, "recursive" ); + if( *psz == '\0' || !strcasecmp( psz, "none" ) ) + p_sys->mode = MODE_NONE; + else if( !strcasecmp( psz, "collapse" ) ) + p_sys->mode = MODE_COLLAPSE; + else + p_sys->mode = MODE_EXPAND; + free( psz ); - p_access->pf_read = Read; - p_access->pf_block = NULL; + p_access->pf_read = NULL; + p_access->pf_block = Block; p_access->pf_seek = NULL; p_access->pf_control= Control; - - /* Force a demux */ - p_access->psz_demux = strdup( "directory" ); + free (p_access->psz_demux); + p_access->psz_demux = strdup ("xspf-open"); return VLC_SUCCESS; } @@ -168,120 +203,294 @@ static int Open( vlc_object_t *p_this ) static void Close( vlc_object_t * p_this ) { access_t *p_access = (access_t*)p_this; - DIR *handle = (DIR *)p_access->p_sys; - closedir (handle); + access_sys_t *p_sys = p_access->p_sys; + + while (p_sys->current) + { + directory_t *current = p_sys->current; + + p_sys->current = current->parent; + closedir (current->handle); + free (current->uri); + free (current); + } + if (p_sys->handle != NULL) + closedir (p_sys->handle); /* corner case,:Block() not called ever */ + free (p_sys->psz_xspf_extension); + free (p_sys->ignored_exts); + free (p_sys); } -/***************************************************************************** - * ReadNull: read the directory - *****************************************************************************/ -static int ReadNull( access_t *p_access, uint8_t *p_buffer, int i_len) +/** + * URI-encodes a file path. The only reserved characters is slash. + */ +static char *encode_path (const char *path) +{ + static const char sep[]= "%2F"; + char *enc = encode_URI_component (path), *ptr = enc; + + if (enc == NULL) + return NULL; + + /* Replace '%2F' with '/'. TODO: extend encode_URI*() */ + /* (On Windows, both ':' and '\\' will be encoded) */ + while ((ptr = strstr (ptr, sep)) != NULL) + { + *ptr++ = '/'; + memmove (ptr, ptr + 2, strlen (ptr) - 1); + } + return enc; +} + +/* Detect directories that recurse into themselves. */ +static bool has_inode_loop (const directory_t *dir) { - /* Return fake data */ - memset( p_buffer, 0, i_len ); - return i_len; +#ifndef WIN32 + dev_t dev = dir->st.st_dev; + ino_t inode = dir->st.st_ino; + + while ((dir = dir->parent) != NULL) + if ((dir->st.st_dev == dev) && (dir->st.st_ino == inode)) + return true; +#else +# define fstat( fd, st ) (0) +#endif + return false; } -/***************************************************************************** - * Read: read the directory - *****************************************************************************/ -static int Read( access_t *p_access, uint8_t *p_buffer, int i_len) +static block_t *Block (access_t *p_access) { - char *psz; - int i_mode, i_activity; - char *psz_name = strdup (p_access->psz_path); + access_sys_t *p_sys = p_access->p_sys; + directory_t *current = p_sys->current; - if( psz_name == NULL ) - return VLC_ENOMEM; + if (p_access->info.b_eof) + return NULL; - playlist_t *p_playlist = pl_Yield( p_access ); - playlist_item_t *p_item_in_category; - input_item_t *p_current_input = input_GetItem( - (input_thread_t*)p_access->p_parent); - playlist_item_t *p_current = playlist_ItemGetByInput( p_playlist, - p_current_input, - VLC_FALSE ); + if (current == NULL) + { /* Startup: send the XSPF header */ + static const char header[] = + "\n" + "\n" + " \n"; + block_t *block = block_Alloc (sizeof (header) - 1); + if (!block) + goto fatal; + memcpy (block->p_buffer, header, sizeof (header) - 1); + + /* "Open" the base directory */ + current = malloc (sizeof (*current) + strlen (p_access->psz_path)); + if (current == NULL) + { + block_Release (block); + goto fatal; + } + current->parent = NULL; + current->handle = p_sys->handle; + strcpy (current->path, p_access->psz_path); + current->uri = encode_path (current->path); + if ((current->uri == NULL) + || fstat (dirfd (current->handle), ¤t->st)) + { + free (current->uri); + free (current); + block_Release (block); + goto fatal; + } - if( p_current == NULL ) - { - msg_Err( p_access, "unable to find item in playlist" ); - vlc_object_release( p_playlist ); - return VLC_ENOOBJ; + p_sys->handle = NULL; + p_sys->current = current; + return block; } - /* Remove the ending '/' char */ - if (psz_name[0]) - { - char *ptr = psz_name + strlen (psz_name); - switch (*--ptr) + char *entry = utf8_readdir (current->handle); + if (entry == NULL) + { /* End of directory, go back to parent */ + closedir (current->handle); + p_sys->current = current->parent; + free (current); + + if (p_sys->current == NULL) + { /* End of XSPF playlist */ + char *footer; + int len = asprintf( &footer, " \n" \ + " \n" \ + "%s" \ + " \n" \ + "\n", p_sys->psz_xspf_extension ); + if( len < 0 ) + goto fatal; + + block_t *block = block_Alloc ( len ); + if (!block) + goto fatal; + memcpy (block->p_buffer, footer, len); + free( footer ); + p_access->info.b_eof = true; + return block; + } + else { - case '/': - case '\\': - *ptr = '\0'; + /* This was the end of a "subnode" */ + /* Write the ID to the extension */ + char *old_xspf_extension = p_sys->psz_xspf_extension; + if (old_xspf_extension == NULL) + goto fatal; + + int len2 = asprintf( &p_sys->psz_xspf_extension, "%s \n", old_xspf_extension ); + if (len2 == -1) + goto fatal; + free( old_xspf_extension ); } + return NULL; } - /* Handle mode */ - psz = var_CreateGetString( p_access, "recursive" ); - if( *psz == '\0' || !strncmp( psz, "none" , 4 ) ) - i_mode = MODE_NONE; - else if( !strncmp( psz, "collapse", 8 ) ) - i_mode = MODE_COLLAPSE; - else - i_mode = MODE_EXPAND; - free( psz ); - - p_current->p_input->i_type = ITEM_TYPE_DIRECTORY; - p_item_in_category = playlist_ItemToNode( p_playlist, p_current, - VLC_FALSE ); - - i_activity = var_GetInteger( p_playlist, "activity" ); - var_SetInteger( p_playlist, "activity", i_activity + - DIRECTORY_ACTIVITY ); + /* Skip current, parent and hidden directories */ + if (entry[0] == '.') + return NULL; + /* Handle recursion */ + if (p_sys->mode != MODE_COLLAPSE) + { + directory_t *sub = malloc (sizeof (*sub) + strlen (current->path) + 1 + + strlen (entry)); + if (sub == NULL) + return NULL; + sprintf (sub->path, "%s/%s", current->path, entry); + + DIR *handle = utf8_opendir (sub->path); + if (handle != NULL) + { + sub->parent = current; + sub->handle = handle; + + char *encoded = encode_URI_component (entry); + if ((encoded == NULL) + || (asprintf (&sub->uri, "%s/%s", current->uri, encoded) == -1)) + sub->uri = NULL; + free (encoded); + + if ((p_sys->mode == MODE_NONE) + || fstat (dirfd (handle), &sub->st) + || has_inode_loop (sub) + || (sub->uri == NULL)) + { + closedir (handle); + free (sub); + return NULL; + } + p_sys->current = sub; + + /* Add node to xspf extension */ + char *old_xspf_extension = p_sys->psz_xspf_extension; + if (old_xspf_extension == NULL) + goto fatal; + + char *title = convert_xml_special_chars (entry); + if (title == NULL + || asprintf (&p_sys->psz_xspf_extension, "%s" + " \n", old_xspf_extension, + title) == -1) + { + free (title); + goto fatal; + } + free (title); + free (old_xspf_extension); + return NULL; + } + else + free (sub); + } - ReadDir( p_playlist, psz_name, i_mode, p_current, p_item_in_category, - p_current_input, (DIR *)p_access->p_sys, NULL ); + /* Skip files with ignored extensions */ + if (p_sys->ignored_exts != NULL) + { + const char *ext = strrchr (entry, '.'); + if (ext != NULL) + { + size_t extlen = strlen (++ext); + for (const char *type = p_sys->ignored_exts, *end; + type[0]; type = end + 1) + { + end = strchr (type, ','); + if (end == NULL) + end = type + strlen (type); - i_activity = var_GetInteger( p_playlist, "activity" ); - var_SetInteger( p_playlist, "activity", i_activity - - DIRECTORY_ACTIVITY ); + if (type + extlen == end + && !strncasecmp (ext, type, extlen)) + return NULL; - playlist_Signal( p_playlist ); + if (*end == '\0') + break; + } + } + } - if( psz_name ) free( psz_name ); - vlc_object_release( p_playlist ); + char *encoded = encode_URI_component (entry); + free (entry); + if (encoded == NULL) + goto fatal; + int len = asprintf (&entry, + " file://%s/%s\n" \ + " \n" \ + " %d\n" \ + " \n" \ + " \n", + current->uri, encoded, p_sys->i_item_count++); + free (encoded); + if (len == -1) + goto fatal; + + /* Write the ID to the extension */ + char *old_xspf_extension = p_sys->psz_xspf_extension; + if (old_xspf_extension == NULL) + goto fatal; + + int len2 = asprintf( &p_sys->psz_xspf_extension, "%s \n", + old_xspf_extension, p_sys->i_item_count-1 ); + if (len2 == -1) + goto fatal; + free( old_xspf_extension ); + + /* TODO: new block allocator for malloc()ated data */ + block_t *block = block_Alloc (len); + if (!block) + { + free (entry); + goto fatal; + } + memcpy (block->p_buffer, entry, len); + free (entry); + return block; - /* Return fake data forever */ - p_access->pf_read = ReadNull; - return ReadNull( p_access, p_buffer, i_len ); +fatal: + p_access->info.b_eof = true; + return NULL; } /***************************************************************************** - * DemuxOpen: + * Control: *****************************************************************************/ static int Control( access_t *p_access, int i_query, va_list args ) { - vlc_bool_t *pb_bool; - int *pi_int; - int64_t *pi_64; + bool *pb_bool; + int64_t *pi_64; switch( i_query ) { /* */ case ACCESS_CAN_SEEK: case ACCESS_CAN_FASTSEEK: + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = false; + break; + case ACCESS_CAN_PAUSE: case ACCESS_CAN_CONTROL_PACE: - pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* ); - *pb_bool = VLC_FALSE; /* FIXME */ + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = true; break; /* */ - case ACCESS_GET_MTU: - pi_int = (int*)va_arg( args, int * ); - *pi_int = 0; - break; - case ACCESS_GET_PTS_DELAY: pi_64 = (int64_t*)va_arg( args, int64_t * ); *pi_64 = DEFAULT_PTS_DELAY * 1000; @@ -293,6 +502,8 @@ static int Control( access_t *p_access, int i_query, va_list args ) case ACCESS_SET_TITLE: case ACCESS_SET_SEEKPOINT: case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: + case ACCESS_GET_META: return VLC_EGENERIC; default: @@ -301,252 +512,3 @@ static int Control( access_t *p_access, int i_query, va_list args ) } return VLC_SUCCESS; } - -/***************************************************************************** - * DemuxOpen: - *****************************************************************************/ -static int DemuxOpen ( vlc_object_t *p_this ) -{ - demux_t *p_demux = (demux_t*)p_this; - - if( strcmp( p_demux->psz_demux, "directory" ) ) - return VLC_EGENERIC; - - p_demux->pf_demux = Demux; - p_demux->pf_control = DemuxControl; - return VLC_SUCCESS; -} - -/***************************************************************************** - * Demux: EOF - *****************************************************************************/ -static int Demux( demux_t *p_demux ) -{ - return 0; -} - -/***************************************************************************** - * DemuxControl: - *****************************************************************************/ -static int DemuxControl( demux_t *p_demux, int i_query, va_list args ) -{ - return demux2_vaControlHelper( p_demux->s, 0, 0, 0, 1, i_query, args ); -} - - -static int Sort (const char **a, const char **b) -{ - return strcoll (*a, *b); -} - -struct stat_list_t -{ - stat_list_t *parent; - struct stat st; -}; - - -/***************************************************************************** - * ReadDir: read a directory and add its content to the list - *****************************************************************************/ -static int ReadDir( playlist_t *p_playlist, const char *psz_name, - int i_mode, playlist_item_t *p_parent, - playlist_item_t *p_parent_category, - input_item_t *p_current_input, - DIR *handle, stat_list_t *stparent ) -{ - char **pp_dir_content = NULL; - int i_dir_content, i, i_return = VLC_SUCCESS; - playlist_item_t *p_node; - - char **ppsz_extensions = NULL; - int i_extensions = 0; - char *psz_ignore; - - struct stat_list_t stself; - int fd = dirfd (handle); - - if ((fd == -1) || fstat (fd, &stself.st)) - { - msg_Err (p_playlist, "cannot stat `%s': %s", psz_name, - strerror (errno)); - return VLC_EGENERIC; - } - - for (stat_list_t *stats = stparent; stats != NULL; stats = stats->parent) - { -#ifndef WIN32 - if ((stself.st.st_ino == stats->st.st_ino) - && (stself.st.st_dev == stats->st.st_dev)) - { - msg_Warn (p_playlist, - "ignoring infinitely recursive directory `%s'", - psz_name); - return VLC_SUCCESS; - } -#else - /* Windows has st_dev (driver letter - 'A'), but it zeroes st_ino, - * so that the test above will always incorrectly succeed. */ -#endif - } - - stself.parent = stparent; - - /* Get the first directory entry */ - i_dir_content = utf8_loaddir (handle, &pp_dir_content, NULL, Sort); - if( i_dir_content == -1 ) - { - msg_Err (p_playlist, "cannot read `%s': %s", psz_name, - strerror (errno)); - return VLC_EGENERIC; - } - else if( i_dir_content <= 0 ) - { - /* directory is empty */ - msg_Dbg( p_playlist, "%s directory is empty", psz_name ); - free( pp_dir_content ); - return VLC_SUCCESS; - } - - /* Build array with ignores */ - psz_ignore = var_CreateGetString( p_playlist, "ignore-filetypes" ); - if( psz_ignore && *psz_ignore ) - { - char *psz_parser = psz_ignore; - int a; - - for( a = 0; psz_parser[a] != '\0'; a++ ) - { - if( psz_parser[a] == ',' ) i_extensions++; - } - - ppsz_extensions = (char **)calloc (i_extensions, sizeof (char *)); - - for( a = 0; a < i_extensions; a++ ) - { - char *tmp, *ptr; - - while( psz_parser[0] != '\0' && psz_parser[0] == ' ' ) psz_parser++; - ptr = strchr( psz_parser, ','); - tmp = ( ptr == NULL ) - ? strdup( psz_parser ) - : strndup( psz_parser, ptr - psz_parser ); - - ppsz_extensions[a] = tmp; - psz_parser = ptr + 1; - } - } - if( psz_ignore ) free( psz_ignore ); - - /* While we still have entries in the directory */ - for( i = 0; i < i_dir_content; i++ ) - { - const char *entry = pp_dir_content[i]; - int i_size_entry = strlen( psz_name ) + - strlen( entry ) + 2 + 7 /* strlen("file://") */; - char psz_uri[i_size_entry]; - - sprintf( psz_uri, "%s/%s", psz_name, entry); - - /* if it starts with '.' then forget it */ - if (entry[0] != '.') - { - DIR *subdir = (i_mode != MODE_COLLAPSE) - ? OpenDir (VLC_OBJECT (p_playlist), psz_uri) : NULL; - - if (subdir != NULL) /* Recurse into subdirectory */ - { - if( i_mode == MODE_NONE ) - { - msg_Dbg( p_playlist, "skipping subdirectory `%s'", - psz_uri ); - closedir (subdir); - continue; - } - - msg_Dbg (p_playlist, "creating subdirectory %s", psz_uri); - - p_node = playlist_NodeCreate( p_playlist, entry, - p_parent_category, - PLAYLIST_NO_REBUILD ); - - /* If we had the parent in category, the it is now node. - * Else, we still don't have */ - i_return = ReadDir( p_playlist, psz_uri , MODE_EXPAND, - p_node, p_parent_category ? p_node : NULL, - p_current_input, subdir, &stself ); - closedir (subdir); - if (i_return) - break; // error :-( - } - else - { - input_item_t *p_input; - - if( i_extensions > 0 ) - { - const char *psz_dot = strrchr (entry, '.' ); - 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 ); - continue; - } - } - } - - memmove (psz_uri + 7, psz_uri, sizeof (psz_uri) - 7); - memcpy (psz_uri, "file://", 7); - p_input = input_ItemNewWithType( VLC_OBJECT(p_playlist), - psz_uri, entry, 0, NULL, - -1, ITEM_TYPE_VFILE ); - if (p_input != NULL) - { - if( p_current_input ) - input_ItemCopyOptions( p_current_input, p_input ); - playlist_BothAddInput( p_playlist, p_input, - p_parent_category, - PLAYLIST_APPEND|PLAYLIST_PREPARSE| - PLAYLIST_NO_REBUILD, - PLAYLIST_END, NULL, NULL ); - } - } - } - } - - for( i = 0; i < i_extensions; i++ ) - if( ppsz_extensions[i] ) free( ppsz_extensions[i] ); - if( ppsz_extensions ) free( ppsz_extensions ); - - 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 i_return; -} - - -static DIR *OpenDir (vlc_object_t *obj, const char *path) -{ - msg_Dbg (obj, "opening directory `%s'", path); - DIR *handle = utf8_opendir (path); - if (handle == NULL) - { - int err = errno; - if (err != ENOTDIR) - msg_Err (obj, "%s: %s", path, strerror (err)); - else - msg_Dbg (obj, "skipping non-directory `%s'", path); - errno = err; - - return NULL; - } - return handle; -}