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