X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fdirectory.c;h=7f295473019dc97a876f31f166c0265ffe2a413e;hb=9914cd554d1f24bc0149e2ca05b41d227c6e11bf;hp=a0fe15cc088f1732131811a07dcdf115f23c144e;hpb=ba70ee5a40afbb85110ca43cb20eda92dfa81d9a;p=vlc diff --git a/modules/access/directory.c b/modules/access/directory.c index a0fe15cc08..7f29547301 100644 --- a/modules/access/directory.c +++ b/modules/access/directory.c @@ -34,22 +34,18 @@ #include "fs.h" #include -#ifdef HAVE_SYS_TYPES_H -# include -#endif +#include #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include +# include #elif defined( WIN32 ) && !defined( UNDER_CE ) # include #endif -#ifdef HAVE_DIRENT_H -# include -#endif #ifdef __sun__ static inline int dirfd (DIR *dir) { @@ -57,7 +53,7 @@ static inline int dirfd (DIR *dir) } #endif -#include +#include #include #include @@ -74,22 +70,41 @@ struct directory_t directory_t *parent; DIR *handle; char *uri; -#ifndef WIN32 - struct stat st; + char **filev; + int filec, i; +#ifdef HAVE_OPENAT + dev_t device; + ino_t inode; +#else + char *path; #endif - char path[1]; }; struct access_sys_t { directory_t *current; - DIR *handle; char *ignored_exts; - int mode; + char mode; + bool header; int i_item_count; - char *psz_xspf_extension; + char *xspf_ext; }; +/* Select non-hidden files only */ +static int visible (const char *name) +{ + return name[0] != '.'; +} + +static int collate (const char **a, const char **b) +{ +#ifdef HAVE_STRCOLL + return strcoll (*a, *b); +#else + return strcmp (*a, *b); +#endif +} + /***************************************************************************** * Open: open the directory *****************************************************************************/ @@ -97,25 +112,10 @@ int DirOpen( vlc_object_t *p_this ) { access_t *p_access = (access_t*)p_this; - 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 + if( !p_access->psz_filepath ) return VLC_EGENERIC; -#endif - } + DIR *handle = vlc_opendir (p_access->psz_filepath); if (handle == NULL) return VLC_EGENERIC; @@ -125,22 +125,58 @@ int DirOpen( vlc_object_t *p_this ) int DirInit (access_t *p_access, DIR *handle) { access_sys_t *p_sys = malloc (sizeof (*p_sys)); - if (!p_sys) + if (unlikely(p_sys == NULL)) + goto error; + + char *uri; + if (!strcmp (p_access->psz_access, "fd")) { - closedir( handle ); - return VLC_ENOMEM; + if (asprintf (&uri, "fd://%s", p_access->psz_location) == -1) + uri = NULL; } + else + uri = make_URI (p_access->psz_filepath, "file"); + if (unlikely(uri == NULL)) + goto error; + + /* "Open" the base directory */ + directory_t *root = malloc (sizeof (*root)); + if (unlikely(root == NULL)) + { + free (uri); + goto error; + } + root->parent = NULL; + root->handle = handle; + root->uri = uri; + root->filec = vlc_loaddir (handle, &root->filev, visible, collate); + if (root->filec < 0) + root->filev = NULL; + root->i = 0; +#ifdef HAVE_OPENAT + struct stat st; + if (fstat (dirfd (handle), &st)) + { + free (root); + free (uri); + goto error; + } + root->device = st.st_dev; + root->inode = st.st_ino; +#else + root->path = strdup (p_access->psz_filepath); +#endif 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->current = root; + p_sys->ignored_exts = var_InheritString (p_access, "ignore-filetypes"); + p_sys->header = true; p_sys->i_item_count = 0; - p_sys->psz_xspf_extension = strdup( "" ); + p_sys->xspf_ext = strdup (""); /* Handle mode */ - char *psz = var_CreateGetString( p_access, "recursive" ); - if( *psz == '\0' || !strcasecmp( psz, "none" ) ) + char *psz = var_InheritString (p_access, "recursive"); + if (psz == NULL || !strcasecmp (psz, "none")) p_sys->mode = MODE_NONE; else if( !strcasecmp( psz, "collapse" ) ) p_sys->mode = MODE_COLLAPSE; @@ -157,6 +193,11 @@ int DirInit (access_t *p_access, DIR *handle) p_access->psz_demux = strdup ("xspf-open"); return VLC_SUCCESS; + +error: + closedir (handle); + free (p_sys); + return VLC_EGENERIC; } /***************************************************************************** @@ -174,32 +215,33 @@ void DirClose( vlc_object_t * p_this ) p_sys->current = current->parent; closedir (current->handle); free (current->uri); + while (current->i < current->filec) + free (current->filev[current->i++]); + free (current->filev); +#ifndef HAVE_OPENAT + free (current->path); +#endif 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->xspf_ext); free (p_sys->ignored_exts); free (p_sys); } +#ifdef HAVE_OPENAT /* Detect directories that recurse into themselves. */ -static bool has_inode_loop (const directory_t *dir) +static bool has_inode_loop (const directory_t *dir, dev_t dev, ino_t inode) { -#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)) + while (dir != NULL) + { + if ((dir->device == dev) && (dir->inode == inode)) return true; -#else -# undef fstat -# define fstat( fd, st ) (0) - VLC_UNUSED( dir ); -#endif + dir = dir->parent; + } return false; } +#endif block_t *DirBlock (access_t *p_access) { @@ -209,7 +251,7 @@ block_t *DirBlock (access_t *p_access) if (p_access->info.b_eof) return NULL; - if (current == NULL) + if (p_sys->header) { /* Startup: send the XSPF header */ static const char header[] = "\n" @@ -219,56 +261,36 @@ block_t *DirBlock (access_t *p_access) 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 = make_URI (current->path); - if ((current->uri == NULL) - || fstat (dirfd (current->handle), ¤t->st)) - { - free (current->uri); - free (current); - block_Release (block); - goto fatal; - } - - p_sys->handle = NULL; - p_sys->current = current; + p_sys->header = false; return block; } - char *entry = utf8_readdir (current->handle); - if (entry == NULL) + if (current->i >= current->filec) { /* End of directory, go back to parent */ closedir (current->handle); p_sys->current = current->parent; free (current->uri); + free (current->filev); +#ifndef HAVE_OPENAT + free (current->path); +#endif 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 ) + int len = asprintf (&footer, " \n" + " \n" + "%s" + " \n" + "\n", p_sys->xspf_ext ? p_sys->xspf_ext : ""); + if (unlikely(len == -1)) goto fatal; - block_t *block = block_Alloc ( len ); - if (!block) - goto fatal; - memcpy (block->p_buffer, footer, len); - free( footer ); + block_t *block = block_heap_Alloc (footer, footer, len); + if (unlikely(block == NULL)) + free (footer); p_access->info.b_eof = true; return block; } @@ -276,87 +298,101 @@ block_t *DirBlock (access_t *p_access) { /* 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 ); + char *old_xspf_ext = p_sys->xspf_ext; + if (old_xspf_ext != NULL + && asprintf (&p_sys->xspf_ext, "%s \n", + old_xspf_ext ? old_xspf_ext : "") == -1) + p_sys->xspf_ext = NULL; + free (old_xspf_ext); } return NULL; } - /* Skip current, parent and hidden directories */ - if (entry[0] == '.') - { - free (entry); - return NULL; - } + char *entry = current->filev[current->i++]; + /* Handle recursion */ if (p_sys->mode != MODE_COLLAPSE) { - directory_t *sub = malloc (sizeof (*sub) + strlen (current->path) + 1 - + strlen (entry)); - if (sub == NULL) + DIR *handle; +#ifdef HAVE_OPENAT + int fd = vlc_openat (dirfd (current->handle), entry, O_RDONLY); + if (fd == -1) + goto skip; /* File cannot be opened... forget it */ + + struct stat st; + if (fstat (fd, &st)) { - free (entry); - return NULL; + close (fd); + goto skip; /* cannot stat?! */ } - sprintf (sub->path, "%s/%s", current->path, entry); - - DIR *handle = utf8_opendir (sub->path); - if (handle != NULL) + if (!S_ISDIR (st.st_mode)) + { + close (fd); + goto notdir; + } + if (p_sys->mode == MODE_NONE + || has_inode_loop (current, st.st_dev, st.st_ino) + || (handle = fdopendir (fd)) == NULL) + { + close (fd); + goto skip; + } +#else + char *path; + if (asprintf (&path, "%s/%s", current->path, entry) == -1) + goto skip; + if ((handle = vlc_opendir (path)) == NULL) + goto notdir; + if (p_sys->mode == MODE_NONE) + goto skip; +#endif + directory_t *sub = malloc (sizeof (*sub)); + if (unlikely(sub == NULL)) + { + closedir (handle); +#ifndef HAVE_OPENAT + free (path); +#endif + goto skip; + } + sub->parent = current; + sub->handle = handle; + sub->filec = vlc_loaddir (handle, &sub->filev, visible, collate); + if (sub->filec < 0) + sub->filev = NULL; + sub->i = 0; +#ifdef HAVE_OPENAT + sub->device = st.st_dev; + sub->inode = st.st_ino; +#else + sub->path = path; +#endif + p_sys->current = sub; + + char *encoded = encode_URI_component (entry); + if (encoded == NULL + || (asprintf (&sub->uri, "%s/%s", current->uri, encoded) == -1)) + sub->uri = NULL; + free (encoded); + if (unlikely(sub->uri == 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)) - { - free (entry); - closedir (handle); - free (sub->uri); - 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) - { - free (entry); - goto fatal; - } - - char *title = convert_xml_special_chars (entry); free (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; + goto fatal; } - else - free (sub); + + /* Add node to XSPF extension */ + char *old_xspf_ext = p_sys->xspf_ext; + char *title = convert_xml_special_chars (entry); + if (old_xspf_ext != NULL && title != NULL + && asprintf (&p_sys->xspf_ext, "%s \n", + old_xspf_ext, title) == -1) + p_sys->xspf_ext = NULL; + free (old_xspf_ext); + free (title); + goto skip; } +notdir: /* Skip files with ignored extensions */ if (p_sys->ignored_exts != NULL) { @@ -400,30 +436,28 @@ block_t *DirBlock (access_t *p_access) 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) + char *old_xspf_ext = p_sys->xspf_ext; + if (old_xspf_ext != NULL + && asprintf (&p_sys->xspf_ext, "%s \n", + old_xspf_ext, p_sys->i_item_count - 1) == -1) + p_sys->xspf_ext = NULL; + free (old_xspf_ext); + + block_t *block = block_heap_Alloc (entry, entry, len); + if (unlikely(block == NULL)) { free (entry); goto fatal; } - memcpy (block->p_buffer, entry, len); - free (entry); return block; fatal: p_access->info.b_eof = true; return NULL; + +skip: + free (entry); + return NULL; } /*****************************************************************************