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