src/platform/psp2/sce-vfs.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/platform/psp2/sce-vfs.h>
7
8#include <psp2/io/dirent.h>
9
10#include <mgba-util/vfs.h>
11#include <mgba-util/memory.h>
12
13#ifndef SCE_CST_SIZE
14#define SCE_CST_SIZE 0x0004
15#endif
16
17struct VFileSce {
18 struct VFile d;
19
20 SceUID fd;
21};
22
23struct VDirEntrySce {
24 struct VDirEntry d;
25 SceIoDirent ent;
26};
27
28struct VDirSce {
29 struct VDir d;
30 struct VDirEntrySce de;
31 SceUID fd;
32 char* path;
33};
34
35static bool _vfsceClose(struct VFile* vf);
36static off_t _vfsceSeek(struct VFile* vf, off_t offset, int whence);
37static ssize_t _vfsceRead(struct VFile* vf, void* buffer, size_t size);
38static ssize_t _vfsceWrite(struct VFile* vf, const void* buffer, size_t size);
39static void* _vfsceMap(struct VFile* vf, size_t size, int flags);
40static void _vfsceUnmap(struct VFile* vf, void* memory, size_t size);
41static void _vfsceTruncate(struct VFile* vf, size_t size);
42static ssize_t _vfsceSize(struct VFile* vf);
43static bool _vfsceSync(struct VFile* vf, const void* memory, size_t size);
44
45static bool _vdsceClose(struct VDir* vd);
46static void _vdsceRewind(struct VDir* vd);
47static struct VDirEntry* _vdsceListNext(struct VDir* vd);
48static struct VFile* _vdsceOpenFile(struct VDir* vd, const char* path, int mode);
49static struct VDir* _vdsceOpenDir(struct VDir* vd, const char* path);
50static bool _vdsceDeleteFile(struct VDir* vd, const char* path);
51
52static const char* _vdesceName(struct VDirEntry* vde);
53static enum VFSType _vdesceType(struct VDirEntry* vde);
54
55static bool _vdlsceClose(struct VDir* vd);
56static void _vdlsceRewind(struct VDir* vd);
57static struct VDirEntry* _vdlsceListNext(struct VDir* vd);
58static struct VFile* _vdlsceOpenFile(struct VDir* vd, const char* path, int mode);
59static struct VDir* _vdlsceOpenDir(struct VDir* vd, const char* path);
60static bool _vdlsceDeleteFile(struct VDir* vd, const char* path);
61
62static const char* _vdlesceName(struct VDirEntry* vde);
63static enum VFSType _vdlesceType(struct VDirEntry* vde);
64
65struct VFile* VFileOpenSce(const char* path, int flags, SceMode mode) {
66 struct VFileSce* vfsce = malloc(sizeof(struct VFileSce));
67 if (!vfsce) {
68 return 0;
69 }
70
71 vfsce->fd = sceIoOpen(path, flags, mode);
72 if (vfsce->fd < 0) {
73 free(vfsce);
74 return 0;
75 }
76
77 vfsce->d.close = _vfsceClose;
78 vfsce->d.seek = _vfsceSeek;
79 vfsce->d.read = _vfsceRead;
80 vfsce->d.readline = VFileReadline;
81 vfsce->d.write = _vfsceWrite;
82 vfsce->d.map = _vfsceMap;
83 vfsce->d.unmap = _vfsceUnmap;
84 vfsce->d.truncate = _vfsceTruncate;
85 vfsce->d.size = _vfsceSize;
86 vfsce->d.sync = _vfsceSync;
87
88 return &vfsce->d;
89}
90
91bool _vfsceClose(struct VFile* vf) {
92 struct VFileSce* vfsce = (struct VFileSce*) vf;
93 sceIoSyncByFd(vfsce->fd);
94 return sceIoClose(vfsce->fd) >= 0;
95}
96
97off_t _vfsceSeek(struct VFile* vf, off_t offset, int whence) {
98 struct VFileSce* vfsce = (struct VFileSce*) vf;
99 return sceIoLseek(vfsce->fd, offset, whence);
100}
101
102ssize_t _vfsceRead(struct VFile* vf, void* buffer, size_t size) {
103 struct VFileSce* vfsce = (struct VFileSce*) vf;
104 return sceIoRead(vfsce->fd, buffer, size);
105}
106
107ssize_t _vfsceWrite(struct VFile* vf, const void* buffer, size_t size) {
108 struct VFileSce* vfsce = (struct VFileSce*) vf;
109 return sceIoWrite(vfsce->fd, buffer, size);
110}
111
112static void* _vfsceMap(struct VFile* vf, size_t size, int flags) {
113 struct VFileSce* vfsce = (struct VFileSce*) vf;
114 UNUSED(flags);
115 void* buffer = anonymousMemoryMap(size);
116 if (buffer) {
117 SceOff cur = sceIoLseek(vfsce->fd, 0, SEEK_CUR);
118 sceIoLseek(vfsce->fd, 0, SEEK_SET);
119 sceIoRead(vfsce->fd, buffer, size);
120 sceIoLseek(vfsce->fd, cur, SEEK_SET);
121 }
122 return buffer;
123}
124
125static void _vfsceUnmap(struct VFile* vf, void* memory, size_t size) {
126 struct VFileSce* vfsce = (struct VFileSce*) vf;
127 SceOff cur = sceIoLseek(vfsce->fd, 0, SEEK_CUR);
128 sceIoLseek(vfsce->fd, 0, SEEK_SET);
129 sceIoWrite(vfsce->fd, memory, size);
130 sceIoLseek(vfsce->fd, cur, SEEK_SET);
131 sceIoSyncByFd(vfsce->fd);
132 mappedMemoryFree(memory, size);
133}
134
135static void _vfsceTruncate(struct VFile* vf, size_t size) {
136 struct VFileSce* vfsce = (struct VFileSce*) vf;
137 SceIoStat stat = { .st_size = size };
138 sceIoChstatByFd(vfsce->fd, &stat, SCE_CST_SIZE);
139}
140
141ssize_t _vfsceSize(struct VFile* vf) {
142 struct VFileSce* vfsce = (struct VFileSce*) vf;
143 SceOff cur = sceIoLseek(vfsce->fd, 0, SEEK_CUR);
144 SceOff end = sceIoLseek(vfsce->fd, 0, SEEK_END);
145 sceIoLseek(vfsce->fd, cur, SEEK_SET);
146 return end;
147}
148
149bool _vfsceSync(struct VFile* vf, const void* buffer, size_t size) {
150 struct VFileSce* vfsce = (struct VFileSce*) vf;
151 if (buffer && size) {
152 SceOff cur = sceIoLseek(vfsce->fd, 0, SEEK_CUR);
153 sceIoLseek(vfsce->fd, 0, SEEK_SET);
154 sceIoWrite(vfsce->fd, buffer, size);
155 sceIoLseek(vfsce->fd, cur, SEEK_SET);
156 }
157 return sceIoSyncByFd(vfsce->fd) >= 0;
158}
159
160struct VDir* VDirOpen(const char* path) {
161 if (!path || !path[0]) {
162 return VDeviceList();
163 }
164
165 SceUID dir = sceIoDopen(path);
166 if (dir < 0) {
167 return 0;
168 }
169
170 struct VDirSce* vd = malloc(sizeof(struct VDirSce));
171 vd->fd = dir;
172 vd->d.close = _vdsceClose;
173 vd->d.rewind = _vdsceRewind;
174 vd->d.listNext = _vdsceListNext;
175 vd->d.openFile = _vdsceOpenFile;
176 vd->d.openDir = _vdsceOpenDir;
177 vd->d.deleteFile = _vdsceDeleteFile;
178 vd->path = strdup(path);
179
180 vd->de.d.name = _vdesceName;
181 vd->de.d.type = _vdesceType;
182
183 return &vd->d;
184}
185
186bool _vdsceClose(struct VDir* vd) {
187 struct VDirSce* vdsce = (struct VDirSce*) vd;
188 if (sceIoDclose(vdsce->fd) < 0) {
189 return false;
190 }
191 free(vdsce->path);
192 free(vdsce);
193 return true;
194}
195
196void _vdsceRewind(struct VDir* vd) {
197 struct VDirSce* vdsce = (struct VDirSce*) vd;
198 sceIoDclose(vdsce->fd);
199 vdsce->fd = sceIoDopen(vdsce->path);
200}
201
202struct VDirEntry* _vdsceListNext(struct VDir* vd) {
203 struct VDirSce* vdsce = (struct VDirSce*) vd;
204 if (sceIoDread(vdsce->fd, &vdsce->de.ent) <= 0) {
205 return 0;
206 }
207 return &vdsce->de.d;
208}
209
210struct VFile* _vdsceOpenFile(struct VDir* vd, const char* path, int mode) {
211 struct VDirSce* vdsce = (struct VDirSce*) vd;
212 if (!path) {
213 return 0;
214 }
215 const char* dir = vdsce->path;
216 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + strlen(PATH_SEP) + 1));
217 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
218
219 struct VFile* file = VFileOpen(combined, mode);
220 free(combined);
221 return file;
222}
223
224struct VDir* _vdsceOpenDir(struct VDir* vd, const char* path) {
225 struct VDirSce* vdsce = (struct VDirSce*) vd;
226 if (!path) {
227 return 0;
228 }
229 const char* dir = vdsce->path;
230 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + strlen(PATH_SEP) + 1));
231 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
232
233 struct VDir* vd2 = VDirOpen(combined);
234 if (!vd2) {
235 vd2 = VDirOpenArchive(combined);
236 }
237 free(combined);
238 return vd2;
239}
240
241bool _vdsceDeleteFile(struct VDir* vd, const char* path) {
242 struct VDirSce* vdsce = (struct VDirSce*) vd;
243 if (!path) {
244 return 0;
245 }
246 const char* dir = vdsce->path;
247 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + strlen(PATH_SEP) + 1));
248 sprintf(combined, "%s%s%s", dir, PATH_SEP, path);
249
250 bool ret = sceIoRemove(combined) >= 0;
251 free(combined);
252 return ret;
253}
254
255static const char* _vdesceName(struct VDirEntry* vde) {
256 struct VDirEntrySce* vdesce = (struct VDirEntrySce*) vde;
257 return vdesce->ent.d_name;
258}
259
260static enum VFSType _vdesceType(struct VDirEntry* vde) {
261 struct VDirEntrySce* vdesce = (struct VDirEntrySce*) vde;
262 if (SCE_S_ISDIR(vdesce->ent.d_stat.st_mode)) {
263 return VFS_DIRECTORY;
264 }
265 return VFS_FILE;
266}
267
268struct VDirEntrySceDevList {
269 struct VDirEntry d;
270 ssize_t index;
271 const char* name;
272};
273
274struct VDirSceDevList {
275 struct VDir d;
276 struct VDirEntrySceDevList vde;
277};
278
279static const char* _devs[] = {
280 "ux0:",
281 "ur0:",
282 "uma0:"
283};
284
285struct VDir* VDeviceList() {
286 struct VDirSceDevList* vd = malloc(sizeof(struct VDirSceDevList));
287 if (!vd) {
288 return 0;
289 }
290
291 vd->d.close = _vdlsceClose;
292 vd->d.rewind = _vdlsceRewind;
293 vd->d.listNext = _vdlsceListNext;
294 vd->d.openFile = _vdlsceOpenFile;
295 vd->d.openDir = _vdlsceOpenDir;
296 vd->d.deleteFile = _vdlsceDeleteFile;
297
298 vd->vde.d.name = _vdlesceName;
299 vd->vde.d.type = _vdlesceType;
300 vd->vde.index = -1;
301 vd->vde.name = 0;
302
303 return &vd->d;
304}
305
306static bool _vdlsceClose(struct VDir* vd) {
307 struct VDirSceDevList* vdl = (struct VDirSceDevList*) vd;
308 free(vdl);
309 return true;
310}
311
312static void _vdlsceRewind(struct VDir* vd) {
313 struct VDirSceDevList* vdl = (struct VDirSceDevList*) vd;
314 vdl->vde.name = NULL;
315 vdl->vde.index = -1;
316}
317
318static struct VDirEntry* _vdlsceListNext(struct VDir* vd) {
319 struct VDirSceDevList* vdl = (struct VDirSceDevList*) vd;
320 while (vdl->vde.index < 3) {
321 ++vdl->vde.index;
322 vdl->vde.name = _devs[vdl->vde.index];
323 SceUID dir = sceIoDopen(vdl->vde.name);
324 if (dir < 0) {
325 continue;
326 }
327 sceIoDclose(dir);
328 return &vdl->vde.d;
329 }
330 return 0;
331}
332
333static struct VFile* _vdlsceOpenFile(struct VDir* vd, const char* path, int mode) {
334 UNUSED(vd);
335 UNUSED(path);
336 UNUSED(mode);
337 return NULL;
338}
339
340static struct VDir* _vdlsceOpenDir(struct VDir* vd, const char* path) {
341 UNUSED(vd);
342 return VDirOpen(path);
343}
344
345static bool _vdlsceDeleteFile(struct VDir* vd, const char* path) {
346 UNUSED(vd);
347 UNUSED(path);
348 return false;
349}
350
351static const char* _vdlesceName(struct VDirEntry* vde) {
352 struct VDirEntrySceDevList* vdle = (struct VDirEntrySceDevList*) vde;
353 return vdle->name;
354}
355
356static enum VFSType _vdlesceType(struct VDirEntry* vde) {
357 UNUSED(vde);
358 return VFS_DIRECTORY;
359}