#include <vlc_access.h>
#include <sys/types.h>
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-
+#include <sys/stat.h>
+#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
# include <fcntl.h>
# include <io.h>
#endif
-#ifdef __sun__
-static inline int dirfd (DIR *dir)
-{
- return dir->dd_fd;
-}
-#endif
-
#include <vlc_fs.h>
#include <vlc_url.h>
#include <vlc_strings.h>
+#include <vlc_charset.h>
enum
{
directory_t *parent;
DIR *handle;
char *uri;
-#ifndef WIN32
- struct stat st;
-#endif
-#ifndef HAVE_OPENAT
+ char **filev;
+ int filec, i;
+#ifdef HAVE_OPENAT
+ dev_t device;
+ ino_t inode;
+#else
char *path;
#endif
};
char mode;
bool header;
int i_item_count;
- char *psz_xspf_extension;
+ char *xspf_ext;
+ int (*compar)(const char **a, const char **b);
};
+/* 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
+}
+
+static int version (const char **a, const char **b)
+{
+ return strverscmp (*a, *b);
+}
+
/*****************************************************************************
* Open: open the directory
*****************************************************************************/
uri = NULL;
}
else
- uri = make_URI (p_access->psz_filepath, "file");
+ uri = vlc_path2uri (p_access->psz_filepath, "file");
if (unlikely(uri == NULL))
goto error;
free (uri);
goto error;
}
+
+ char *psz_sort = var_InheritString (p_access, "directory-sort");
+ if (!psz_sort)
+ p_sys->compar = collate;
+ else if (!strcasecmp (psz_sort, "version"))
+ p_sys->compar = version;
+ else if (!strcasecmp (psz_sort, "none"))
+ p_sys->compar = NULL;
+ else
+ p_sys->compar = collate;
+ free(psz_sort);
+
root->parent = NULL;
root->handle = handle;
root->uri = uri;
-#ifndef HAVE_OPENAT
- root->path = strdup (p_access->psz_filepath);
-#endif
- if (fstat (dirfd (handle), &root->st))
+ root->filec = vlc_loaddir (handle, &root->filev, visible, p_sys->compar);
+ 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 = 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_InheritString (p_access, "recursive");
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);
}
- 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)
{
return block;
}
- char *entry = vlc_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
if (p_sys->current == NULL)
{ /* End of XSPF playlist */
char *footer;
- int len = asprintf( &footer, " </trackList>\n" \
- " <extension application=\"http://www.videolan.org/vlc/playlist/0\">\n" \
- "%s" \
- " </extension>\n" \
- "</playlist>\n", p_sys->psz_xspf_extension );
+ int len = asprintf (&footer, " </trackList>\n"
+ " <extension application=\"http://www.videolan.org/"
+ "vlc/playlist/0\">\n"
+ "%s"
+ " </extension>\n"
+ "</playlist>\n", p_sys->xspf_ext ? p_sys->xspf_ext : "");
if (unlikely(len == -1))
goto fatal;
- block_t *block = block_heap_Alloc (footer, footer, len);
+ block_t *block = block_heap_Alloc (footer, len);
if (unlikely(block == NULL))
free (footer);
p_access->info.b_eof = true;
{
/* 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 </vlc:node>\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 </vlc:node>\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));
- if (sub == NULL)
+ DIR *handle;
+#ifdef HAVE_OPENAT
+ int fd = vlc_openat (dirfd (current->handle), entry,
+ O_RDONLY | O_DIRECTORY);
+ if (fd == -1)
{
- free (entry);
- return NULL;
+ if (errno == ENOTDIR)
+ goto notdir;
+ goto skip; /* File cannot be opened... forget it */
}
- DIR *handle;
-#ifdef HAVE_OPENAT
- int fd = vlc_openat (dirfd (current->handle), entry, O_RDONLY);
- if (fd != -1)
+ struct stat st;
+ if (fstat (fd, &st)
+ || p_sys->mode == MODE_NONE
+ || has_inode_loop (current, st.st_dev, st.st_ino)
+ || (handle = fdopendir (fd)) == NULL)
{
- handle = fdopendir (fd);
- if (handle == NULL)
- close (fd);
+ close (fd);
+ goto skip;
}
- else
- handle = NULL;
#else
- if (asprintf (&sub->path, "%s/%s", current->path, entry) != -1)
- handle = vlc_opendir (sub->path);
- else
- handle = NULL;
+ 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
- if (handle != NULL)
+ 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, p_sys->compar);
+ 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"
- " <vlc:node title=\"%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;
+ EnsureUTF8 (entry);
+ char *title = convert_xml_special_chars (entry);
+ if (old_xspf_ext != NULL
+ && asprintf (&p_sys->xspf_ext, "%s <vlc:node title=\"%s\">\n",
+ old_xspf_ext, title ? 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)
{
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 <vlc:item tid=\"%i\" />\n",
- old_xspf_extension, p_sys->i_item_count-1 );
- if (len2 == -1)
- goto fatal;
- free( old_xspf_extension );
-
- block_t *block = block_heap_Alloc (entry, entry, len);
+ char *old_xspf_ext = p_sys->xspf_ext;
+ if (old_xspf_ext != NULL
+ && asprintf (&p_sys->xspf_ext, "%s <vlc:item tid=\"%i\" />\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, len);
if (unlikely(block == NULL))
{
free (entry);
fatal:
p_access->info.b_eof = true;
return NULL;
+
+skip:
+ free (entry);
+ return NULL;
}
/*****************************************************************************