all repos — mgba @ 60577e83948647d36a2e6a8b4ec8f8556df3f72f

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 <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}