access: dtv: simplify/regroup setup and drop delsys
[vlc.git] / modules / access / directory.c
1 /*****************************************************************************
2  * directory.c: expands a directory (directory: access_browser plug-in)
3  *****************************************************************************
4  * Copyright (C) 2002-2015 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          RĂ©mi Denis-Courmont
9  *          Julien 'Lta' BALLET <contact # lta.io>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <limits.h>
35 #include <sys/stat.h>
36
37 #include <vlc_common.h>
38 #include "fs.h"
39 #include <vlc_access.h>
40 #include <vlc_input_item.h>
41
42 #include <vlc_fs.h>
43 #include <vlc_url.h>
44
45 struct access_sys_t
46 {
47     char *base_uri;
48     DIR *dir;
49     bool special_files;
50 };
51
52 /*****************************************************************************
53  * DirInit: Init the directory access with a directory stream
54  *****************************************************************************/
55 int DirInit (access_t *access, DIR *dir)
56 {
57     access_sys_t *sys = malloc(sizeof (*sys));
58     if (unlikely(sys == NULL))
59         goto error;
60
61     if (!strcmp(access->psz_access, "fd"))
62     {
63         if (unlikely(asprintf(&sys->base_uri, "fd://%s",
64                               access->psz_location) == -1))
65             sys->base_uri = NULL;
66     }
67     else
68         sys->base_uri = vlc_path2uri(access->psz_filepath, "file");
69     if (unlikely(sys->base_uri == NULL))
70         goto error;
71
72     sys->dir = dir;
73     sys->special_files = var_InheritBool(access, "list-special-files");
74
75     access->p_sys = sys;
76     access->pf_readdir = DirRead;
77     access->pf_control = access_vaDirectoryControlHelper;
78     return VLC_SUCCESS;
79
80 error:
81     closedir(dir);
82     free(sys);
83     return VLC_ENOMEM;
84 }
85
86 /*****************************************************************************
87  * DirOpen: Open the directory access
88  *****************************************************************************/
89 int DirOpen (vlc_object_t *obj)
90 {
91     access_t *access = (access_t *)obj;
92
93     if (access->psz_filepath == NULL)
94         return VLC_EGENERIC;
95
96     DIR *dir = vlc_opendir(access->psz_filepath);
97     if (dir == NULL)
98         return VLC_EGENERIC;
99
100     return DirInit(access, dir);
101 }
102
103 /*****************************************************************************
104  * Close: close the target
105  *****************************************************************************/
106 void DirClose(vlc_object_t *obj)
107 {
108     access_t *access = (access_t *)obj;
109     access_sys_t *sys = access->p_sys;
110
111     free(sys->base_uri);
112     closedir(sys->dir);
113     free(sys);
114 }
115
116 input_item_t *DirRead(access_t *access)
117 {
118     access_sys_t *sys = access->p_sys;
119     const char *entry;
120
121     while ((entry = vlc_readdir(sys->dir)) != NULL)
122     {
123         struct stat st;
124         int type;
125
126 #ifdef HAVE_OPENAT
127         if (fstatat(dirfd(sys->dir), entry, &st, 0))
128             continue;
129 #else
130         char path[PATH_MAX];
131
132         if (snprintf(path, PATH_MAX, "%s"DIR_SEP"%s", access->psz_filepath,
133                      entry) >= PATH_MAX || vlc_stat(path, &st))
134             continue;
135 #endif
136         switch (st.st_mode & S_IFMT)
137         {
138             case S_IFBLK:
139                 if (!sys->special_files)
140                     continue;
141                 type = ITEM_TYPE_DISC;
142                 break;
143             case S_IFCHR:
144                 if (!sys->special_files)
145                     continue;
146                 type = ITEM_TYPE_CARD;
147                 break;
148             case S_IFIFO:
149                 if (!sys->special_files)
150                     continue;
151                 type = ITEM_TYPE_STREAM;
152                 break;
153             case S_IFREG:
154                 type = ITEM_TYPE_FILE;
155                 break;
156             case S_IFDIR:
157                 type = ITEM_TYPE_DIRECTORY;
158                 break;
159             /* S_IFLNK cannot occur while following symbolic links */
160             /* S_IFSOCK cannot be opened with open()/openat() */
161             default:
162                 continue; /* ignore */
163         }
164
165         /* Create an input item for the current entry */
166         char *encoded = vlc_uri_encode(entry);
167         if (unlikely(encoded == NULL))
168             continue;
169
170         char *uri;
171         if (unlikely(asprintf(&uri, "%s/%s", sys->base_uri, encoded) == -1))
172             uri = NULL;
173         free(encoded);
174         if (unlikely(uri == NULL))
175             continue;
176
177         input_item_t *item = input_item_NewExt(uri, entry, -1, type,
178                                                ITEM_NET_UNKNOWN);
179         free(uri);
180         if (likely(item != NULL))
181             return item;
182     }
183     return NULL;
184 }