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 <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <retro_common.h>
28
29 #include <boolean.h>
30 #include <retro_dirent.h>
31
32 #if defined(_WIN32)
33 # ifdef _MSC_VER
34 # define setmode _setmode
35 # endif
36 #include <sys/stat.h>
37 # ifdef _XBOX
38 # include <xtl.h>
39 # define INVALID_FILE_ATTRIBUTES -1
40 # else
41 # include <io.h>
42 # include <fcntl.h>
43 # include <direct.h>
44 # include <windows.h>
45 # endif
46 #elif defined(VITA)
47 # include <psp2/io/fcntl.h>
48 # include <psp2/io/dirent.h>
49 #include <psp2/io/stat.h>
50 #else
51 # if defined(PSP)
52 # include <pspiofilemgr.h>
53 # endif
54 # include <sys/types.h>
55 # include <sys/stat.h>
56 # include <dirent.h>
57 # include <unistd.h>
58 #endif
59
60 #ifdef __CELLOS_LV2__
61 #include <cell/cell_fs.h>
62 #endif
63
64 #if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
65 #include <unistd.h> /* stat() is defined here */
66 #endif
67
68 struct RDIR
69 {
70 #if defined(_WIN32)
71 WIN32_FIND_DATA entry;
72 HANDLE directory;
73 bool next;
74 char path[PATH_MAX_LENGTH];
75 #elif defined(VITA) || defined(PSP)
76 SceUID directory;
77 SceIoDirent entry;
78 #elif defined(__CELLOS_LV2__)
79 CellFsErrno error;
80 int directory;
81 CellFsDirent entry;
82 #else
83 DIR *directory;
84 const struct dirent *entry;
85 #endif
86 };
87
retro_opendir(const char * name)88 struct RDIR *retro_opendir(const char *name)
89 {
90 #if defined(_WIN32)
91 char path_buf[1024];
92 #endif
93 struct RDIR *rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
94
95 if (!rdir)
96 return NULL;
97
98 #if defined(_WIN32)
99 path_buf[0] = '\0';
100 snprintf(path_buf, sizeof(path_buf), "%s\\*", name);
101 rdir->directory = FindFirstFile(path_buf, &rdir->entry);
102 #elif defined(VITA) || defined(PSP)
103 rdir->directory = sceIoDopen(name);
104 #elif defined(_3DS)
105 rdir->directory = (name && *name)? opendir(name) : NULL;
106 rdir->entry = NULL;
107 #elif defined(__CELLOS_LV2__)
108 rdir->error = cellFsOpendir(name, &rdir->directory);
109 #else
110 rdir->directory = opendir(name);
111 rdir->entry = NULL;
112 #endif
113
114 return rdir;
115 }
116
retro_dirent_error(struct RDIR * rdir)117 bool retro_dirent_error(struct RDIR *rdir)
118 {
119 #if defined(_WIN32)
120 return (rdir->directory == INVALID_HANDLE_VALUE);
121 #elif defined(VITA) || defined(PSP)
122 return (rdir->directory < 0);
123 #elif defined(__CELLOS_LV2__)
124 return (rdir->error != CELL_FS_SUCCEEDED);
125 #else
126 return !(rdir->directory);
127 #endif
128 }
129
retro_readdir(struct RDIR * rdir)130 int retro_readdir(struct RDIR *rdir)
131 {
132 #if defined(_WIN32)
133 if(rdir->next)
134 return (FindNextFile(rdir->directory, &rdir->entry) != 0);
135
136 rdir->next = true;
137 return (rdir->directory != INVALID_HANDLE_VALUE);
138 #elif defined(VITA) || defined(PSP)
139 return (sceIoDread(rdir->directory, &rdir->entry) > 0);
140 #elif defined(__CELLOS_LV2__)
141 uint64_t nread;
142 rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
143 return (nread != 0);
144 #else
145 return ((rdir->entry = readdir(rdir->directory)) != NULL);
146 #endif
147 }
148
retro_dirent_get_name(struct RDIR * rdir)149 const char *retro_dirent_get_name(struct RDIR *rdir)
150 {
151 #if defined(_WIN32)
152 return rdir->entry.cFileName;
153 #elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
154 return rdir->entry.d_name;
155 #else
156 return rdir->entry->d_name;
157 #endif
158 }
159
160 /**
161 *
162 * retro_dirent_is_dir:
163 * @rdir : pointer to the directory entry.
164 * @path : path to the directory entry.
165 *
166 * Is the directory listing entry a directory?
167 *
168 * Returns: true if directory listing entry is
169 * a directory, false if not.
170 */
retro_dirent_is_dir(struct RDIR * rdir,const char * path)171 bool retro_dirent_is_dir(struct RDIR *rdir, const char *path)
172 {
173 #if defined(_WIN32)
174 const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
175 return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
176 #elif defined(PSP) || defined(VITA)
177 const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
178 #if defined(PSP)
179 return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
180 #elif defined(VITA)
181 return SCE_S_ISDIR(entry->d_stat.st_mode);
182 #endif
183 #elif defined(__CELLOS_LV2__)
184 CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
185 return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
186 #else
187 struct stat buf;
188 #if defined(DT_DIR)
189 const struct dirent *entry = (const struct dirent*)rdir->entry;
190 if (entry->d_type == DT_DIR)
191 return true;
192 /* This can happen on certain file systems. */
193 if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
194 return false;
195 #endif
196 /* dirent struct doesn't have d_type, do it the slow way ... */
197 if (stat(path, &buf) < 0)
198 return false;
199 return S_ISDIR(buf.st_mode);
200 #endif
201 }
202
retro_dirent_include_hidden(struct RDIR * rdir,bool include_hidden)203 void retro_dirent_include_hidden(struct RDIR *rdir, bool include_hidden)
204 {
205 #ifdef _WIN32
206 if (include_hidden)
207 rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
208 else
209 rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
210 #endif
211 }
212
retro_closedir(struct RDIR * rdir)213 void retro_closedir(struct RDIR *rdir)
214 {
215 if (!rdir)
216 return;
217
218 #if defined(_WIN32)
219 if (rdir->directory != INVALID_HANDLE_VALUE)
220 FindClose(rdir->directory);
221 #elif defined(VITA) || defined(PSP)
222 sceIoDclose(rdir->directory);
223 #elif defined(__CELLOS_LV2__)
224 rdir->error = cellFsClosedir(rdir->directory);
225 #else
226 if (rdir->directory)
227 closedir(rdir->directory);
228 #endif
229
230 free(rdir);
231 }
232