1 /* Copyright (C) 2010-2017 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (retro_dirent.c).
5 * ---------------------------------------------------------------------------------------
6 *
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 #include <retro_common.h>
27
28 #include <boolean.h>
29 #include <retro_dirent.h>
30
31 #if defined(_WIN32)
32 # ifdef _MSC_VER
33 # define setmode _setmode
34 # endif
35 #include <sys/stat.h>
36 # ifdef _XBOX
37 # include <xtl.h>
38 # define INVALID_FILE_ATTRIBUTES -1
39 # else
40 # include <io.h>
41 # include <fcntl.h>
42 # include <direct.h>
43 # include <windows.h>
44 # endif
45 #elif defined(VITA)
46 # include <psp2/io/fcntl.h>
47 # include <psp2/io/dirent.h>
48 #include <psp2/io/stat.h>
49 #else
50 # if defined(PSP)
51 # include <pspiofilemgr.h>
52 # endif
53 # include <sys/types.h>
54 # include <sys/stat.h>
55 # include <dirent.h>
56 # include <unistd.h>
57 #endif
58
59 #ifdef __CELLOS_LV2__
60 #include <cell/cell_fs.h>
61 #endif
62
63 #if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
64 #include <unistd.h> /* stat() is defined here */
65 #endif
66
67 struct RDIR
68 {
69 #if defined(_WIN32)
70 WIN32_FIND_DATA entry;
71 HANDLE directory;
72 bool next;
73 char path[PATH_MAX_LENGTH];
74 #elif defined(VITA) || defined(PSP)
75 SceUID directory;
76 SceIoDirent entry;
77 #elif defined(__CELLOS_LV2__)
78 CellFsErrno error;
79 int directory;
80 CellFsDirent entry;
81 #else
82 DIR *directory;
83 const struct dirent *entry;
84 #endif
85 };
86
retro_opendir(const char * name)87 struct RDIR *retro_opendir(const char *name)
88 {
89 #if defined(_WIN32)
90 char path_buf[1024];
91 #endif
92 struct RDIR *rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
93
94 if (!rdir)
95 return NULL;
96
97 #if defined(_WIN32)
98 path_buf[0] = '\0';
99 snprintf(path_buf, sizeof(path_buf), "%s\\*", name);
100 rdir->directory = FindFirstFile(path_buf, &rdir->entry);
101 #elif defined(VITA) || defined(PSP)
102 rdir->directory = sceIoDopen(name);
103 #elif defined(_3DS)
104 rdir->directory = (name && *name)? opendir(name) : NULL;
105 rdir->entry = NULL;
106 #elif defined(__CELLOS_LV2__)
107 rdir->error = cellFsOpendir(name, &rdir->directory);
108 #else
109 rdir->directory = opendir(name);
110 rdir->entry = NULL;
111 #endif
112
113 return rdir;
114 }
115
retro_dirent_error(struct RDIR * rdir)116 bool retro_dirent_error(struct RDIR *rdir)
117 {
118 #if defined(_WIN32)
119 return (rdir->directory == INVALID_HANDLE_VALUE);
120 #elif defined(VITA) || defined(PSP)
121 return (rdir->directory < 0);
122 #elif defined(__CELLOS_LV2__)
123 return (rdir->error != CELL_FS_SUCCEEDED);
124 #else
125 return !(rdir->directory);
126 #endif
127 }
128
retro_readdir(struct RDIR * rdir)129 int retro_readdir(struct RDIR *rdir)
130 {
131 #if defined(_WIN32)
132 if(rdir->next)
133 return (FindNextFile(rdir->directory, &rdir->entry) != 0);
134
135 rdir->next = true;
136 return (rdir->directory != INVALID_HANDLE_VALUE);
137 #elif defined(VITA) || defined(PSP)
138 return (sceIoDread(rdir->directory, &rdir->entry) > 0);
139 #elif defined(__CELLOS_LV2__)
140 uint64_t nread;
141 rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
142 return (nread != 0);
143 #else
144 return ((rdir->entry = readdir(rdir->directory)) != NULL);
145 #endif
146 }
147
retro_dirent_get_name(struct RDIR * rdir)148 const char *retro_dirent_get_name(struct RDIR *rdir)
149 {
150 #if defined(_WIN32)
151 return rdir->entry.cFileName;
152 #elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
153 return rdir->entry.d_name;
154 #else
155 return rdir->entry->d_name;
156 #endif
157 }
158
path_is_directory_internal(const char * path)159 static bool path_is_directory_internal(const char *path)
160 {
161 #if defined(VITA) || defined(PSP)
162 SceIoStat buf;
163 char *tmp = strdup(path);
164 size_t len = strlen(tmp);
165 if (tmp[len-1] == '/')
166 tmp[len-1]='\0';
167
168 if (sceIoGetstat(tmp, &buf) < 0)
169 {
170 free(tmp);
171 return false;
172 }
173 free(tmp);
174
175 return FIO_S_ISDIR(buf.st_mode);
176 #elif defined(__CELLOS_LV2__)
177 CellFsStat buf;
178 if (cellFsStat(path, &buf) < 0)
179 return false;
180 return ((buf.st_mode & S_IFMT) == S_IFDIR);
181 #elif defined(_WIN32)
182 struct _stat buf;
183 DWORD file_info = GetFileAttributes(path);
184
185 _stat(path, &buf);
186
187 if (file_info == INVALID_FILE_ATTRIBUTES)
188 return false;
189 return (file_info & FILE_ATTRIBUTE_DIRECTORY);
190 #else
191 struct stat buf;
192 if (stat(path, &buf) < 0)
193 return false;
194 return S_ISDIR(buf.st_mode);
195 #endif
196 }
197
198 /**
199 *
200 * retro_dirent_is_dir:
201 * @rdir : pointer to the directory entry.
202 * @path : path to the directory entry.
203 *
204 * Is the directory listing entry a directory?
205 *
206 * Returns: true if directory listing entry is
207 * a directory, false if not.
208 */
retro_dirent_is_dir(struct RDIR * rdir,const char * path)209 bool retro_dirent_is_dir(struct RDIR *rdir, const char *path)
210 {
211 #if defined(_WIN32)
212 const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
213 return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
214 #elif defined(PSP) || defined(VITA)
215 const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
216 #if defined(PSP)
217 return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
218 #elif defined(VITA)
219 return SCE_S_ISDIR(entry->d_stat.st_mode);
220 #endif
221 #elif defined(__CELLOS_LV2__)
222 CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
223 return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
224 #elif defined(DT_DIR)
225 const struct dirent *entry = (const struct dirent*)rdir->entry;
226 if (entry->d_type == DT_DIR)
227 return true;
228 /* This can happen on certain file systems. */
229 if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)
230 return path_is_directory_internal(path);
231 return false;
232 #else
233 /* dirent struct doesn't have d_type, do it the slow way ... */
234 return path_is_directory_internal(path);
235 #endif
236 }
237
retro_dirent_include_hidden(struct RDIR * rdir,bool include_hidden)238 void retro_dirent_include_hidden(struct RDIR *rdir, bool include_hidden)
239 {
240 #ifdef _WIN32
241 if (include_hidden)
242 rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
243 else
244 rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
245 #endif
246 }
247
retro_closedir(struct RDIR * rdir)248 void retro_closedir(struct RDIR *rdir)
249 {
250 if (!rdir)
251 return;
252
253 #if defined(_WIN32)
254 if (rdir->directory != INVALID_HANDLE_VALUE)
255 FindClose(rdir->directory);
256 #elif defined(VITA) || defined(PSP)
257 sceIoDclose(rdir->directory);
258 #elif defined(__CELLOS_LV2__)
259 rdir->error = cellFsClosedir(rdir->directory);
260 #else
261 if (rdir->directory)
262 closedir(rdir->directory);
263 #endif
264
265 free(rdir);
266 }
267