src/util/vfs/vfs-dirent.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba-util/vfs.h>
7
8#include <mgba-util/string.h>
9
10#include <dirent.h>
11#include <errno.h>
12#include <sys/stat.h>
13
14static bool _vdClose(struct VDir* vd);
15static void _vdRewind(struct VDir* vd);
16static struct VDirEntry* _vdListNext(struct VDir* vd);
17static struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode);
18static struct VDir* _vdOpenDir(struct VDir* vd, const char* path);
19static bool _vdDeleteFile(struct VDir* vd, const char* path);
20
21static const char* _vdeName(struct VDirEntry* vde);
22static enum VFSType _vdeType(struct VDirEntry* vde);
23
24struct VDirDE;
25struct VDirEntryDE {
26 struct VDirEntry d;
27 struct VDirDE* p;
28 struct dirent* ent;
29};
30
31struct VDirDE {
32 struct VDir d;
33 DIR* de;
34 struct VDirEntryDE vde;
35 char* path;
36};
37
38struct VDir* VDirOpen(const char* path) {
39#ifdef __wii__
40 if (!path || !path[0]) {
41 return VDeviceList();
42 }
43#endif
44 DIR* de = opendir(path);
45 if (!de) {
46 return 0;
47 }
48
49 struct VDirDE* vd = malloc(sizeof(struct VDirDE));
50 if (!vd) {
51 closedir(de);
52 return 0;
53 }
54
55 vd->d.close = _vdClose;
56 vd->d.rewind = _vdRewind;
57 vd->d.listNext = _vdListNext;
58 vd->d.openFile = _vdOpenFile;
59 vd->d.openDir = _vdOpenDir;
60 vd->d.deleteFile = _vdDeleteFile;
61 vd->path = strdup(path);
62 vd->de = de;
63
64 vd->vde.d.name = _vdeName;
65 vd->vde.d.type = _vdeType;
66 vd->vde.p = vd;
67
68 return &vd->d;
69}
70
71bool _vdClose(struct VDir* vd) {
72 struct VDirDE* vdde = (struct VDirDE*) vd;
73 if (closedir(vdde->de) < 0) {
74 return false;
75 }
76 free(vdde->path);
77 free(vdde);
78 return true;
79}
80
81void _vdRewind(struct VDir* vd) {
82 struct VDirDE* vdde = (struct VDirDE*) vd;
83 rewinddir(vdde->de);
84}
85
86struct VDirEntry* _vdListNext(struct VDir* vd) {
87 struct VDirDE* vdde = (struct VDirDE*) vd;
88 vdde->vde.ent = readdir(vdde->de);
89 if (vdde->vde.ent) {
90 return &vdde->vde.d;
91 }
92
93 return 0;
94}
95
96struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode) {
97 struct VDirDE* vdde = (struct VDirDE*) vd;
98 if (!path) {
99 return 0;
100 }
101 const char* dir = vdde->path;
102 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
103 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
104
105 struct VFile* file = VFileOpen(combined, mode);
106 free(combined);
107 return file;
108}
109
110struct VDir* _vdOpenDir(struct VDir* vd, const char* path) {
111 struct VDirDE* vdde = (struct VDirDE*) vd;
112 if (!path) {
113 return 0;
114 }
115 const char* dir = vdde->path;
116 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
117 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
118
119 struct VDir* vd2 = VDirOpen(combined);
120 if (!vd2) {
121 vd2 = VDirOpenArchive(combined);
122 }
123 free(combined);
124 return vd2;
125}
126
127bool _vdDeleteFile(struct VDir* vd, const char* path) {
128 struct VDirDE* vdde = (struct VDirDE*) vd;
129 if (!path) {
130 return false;
131 }
132 const char* dir = vdde->path;
133 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
134 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
135
136 bool ret = !unlink(combined);
137 free(combined);
138 return ret;
139}
140
141const char* _vdeName(struct VDirEntry* vde) {
142 struct VDirEntryDE* vdede = (struct VDirEntryDE*) vde;
143 if (vdede->ent) {
144 return vdede->ent->d_name;
145 }
146 return 0;
147}
148
149static enum VFSType _vdeType(struct VDirEntry* vde) {
150 struct VDirEntryDE* vdede = (struct VDirEntryDE*) vde;
151#if !defined(WIN32) && !defined(__HAIKU__)
152 if (vdede->ent->d_type == DT_DIR) {
153 return VFS_DIRECTORY;
154 }
155 return VFS_FILE;
156#else
157 const char* dir = vdede->p->path;
158 char* combined = malloc(sizeof(char) * (strlen(vdede->ent->d_name) + strlen(dir) + 2));
159 sprintf(combined, "%s%s%s", dir, PATH_SEP, vdede->ent->d_name);
160 struct stat sb;
161 stat(combined, &sb);
162 free(combined);
163
164 if (S_ISDIR(sb.st_mode)) {
165 return VFS_DIRECTORY;
166 }
167 return VFS_FILE;
168#endif
169}
170
171bool VDirCreate(const char* path) {
172 return mkdir(path, 0777) == 0 || errno == EEXIST;
173}