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 <sys/stat.h>
12
13static bool _vdClose(struct VDir* vd);
14static void _vdRewind(struct VDir* vd);
15static struct VDirEntry* _vdListNext(struct VDir* vd);
16static struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode);
17static struct VDir* _vdOpenDir(struct VDir* vd, const char* path);
18static bool _vdDeleteFile(struct VDir* vd, const char* path);
19
20static const char* _vdeName(struct VDirEntry* vde);
21static enum VFSType _vdeType(struct VDirEntry* vde);
22
23struct VDirDE;
24struct VDirEntryDE {
25 struct VDirEntry d;
26 struct VDirDE* p;
27 struct dirent* ent;
28};
29
30struct VDirDE {
31 struct VDir d;
32 DIR* de;
33 struct VDirEntryDE vde;
34 char* path;
35};
36
37struct VDir* VDirOpen(const char* path) {
38#ifdef __wii__
39 if (!path || !path[0]) {
40 return VDeviceList();
41 }
42#endif
43 DIR* de = opendir(path);
44 if (!de) {
45 return 0;
46 }
47
48 struct VDirDE* vd = malloc(sizeof(struct VDirDE));
49 if (!vd) {
50 closedir(de);
51 return 0;
52 }
53
54 vd->d.close = _vdClose;
55 vd->d.rewind = _vdRewind;
56 vd->d.listNext = _vdListNext;
57 vd->d.openFile = _vdOpenFile;
58 vd->d.openDir = _vdOpenDir;
59 vd->d.deleteFile = _vdDeleteFile;
60 vd->path = strdup(path);
61 vd->de = de;
62
63 vd->vde.d.name = _vdeName;
64 vd->vde.d.type = _vdeType;
65 vd->vde.p = vd;
66
67 return &vd->d;
68}
69
70bool _vdClose(struct VDir* vd) {
71 struct VDirDE* vdde = (struct VDirDE*) vd;
72 if (closedir(vdde->de) < 0) {
73 return false;
74 }
75 free(vdde->path);
76 free(vdde);
77 return true;
78}
79
80void _vdRewind(struct VDir* vd) {
81 struct VDirDE* vdde = (struct VDirDE*) vd;
82 rewinddir(vdde->de);
83}
84
85struct VDirEntry* _vdListNext(struct VDir* vd) {
86 struct VDirDE* vdde = (struct VDirDE*) vd;
87 vdde->vde.ent = readdir(vdde->de);
88 if (vdde->vde.ent) {
89 return &vdde->vde.d;
90 }
91
92 return 0;
93}
94
95struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode) {
96 struct VDirDE* vdde = (struct VDirDE*) vd;
97 if (!path) {
98 return 0;
99 }
100 const char* dir = vdde->path;
101 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
102 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
103
104 struct VFile* file = VFileOpen(combined, mode);
105 free(combined);
106 return file;
107}
108
109struct VDir* _vdOpenDir(struct VDir* vd, const char* path) {
110 struct VDirDE* vdde = (struct VDirDE*) vd;
111 if (!path) {
112 return 0;
113 }
114 const char* dir = vdde->path;
115 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
116 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
117
118 struct VDir* vd2 = VDirOpen(combined);
119 if (!vd2) {
120 vd2 = VDirOpenArchive(combined);
121 }
122 free(combined);
123 return vd2;
124}
125
126bool _vdDeleteFile(struct VDir* vd, const char* path) {
127 struct VDirDE* vdde = (struct VDirDE*) vd;
128 if (!path) {
129 return false;
130 }
131 const char* dir = vdde->path;
132 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
133 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
134
135 bool ret = !unlink(combined);
136 free(combined);
137 return ret;
138}
139
140const char* _vdeName(struct VDirEntry* vde) {
141 struct VDirEntryDE* vdede = (struct VDirEntryDE*) vde;
142 if (vdede->ent) {
143 return vdede->ent->d_name;
144 }
145 return 0;
146}
147
148static enum VFSType _vdeType(struct VDirEntry* vde) {
149 struct VDirEntryDE* vdede = (struct VDirEntryDE*) vde;
150#if !defined(WIN32) && !defined(__HAIKU__)
151 if (vdede->ent->d_type == DT_DIR) {
152 return VFS_DIRECTORY;
153 }
154 return VFS_FILE;
155#else
156 const char* dir = vdede->p->path;
157 char* combined = malloc(sizeof(char) * (strlen(vdede->ent->d_name) + strlen(dir) + 2));
158 sprintf(combined, "%s%s%s", dir, PATH_SEP, vdede->ent->d_name);
159 struct stat sb;
160 stat(combined, &sb);
161 free(combined);
162
163 if (S_ISDIR(sb.st_mode)) {
164 return VFS_DIRECTORY;
165 }
166 return VFS_FILE;
167#endif
168}