all repos — mgba @ 120e1006d04ed62e011b2342842ac6c54f0673c3

mGBA Game Boy Advance Emulator

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}