src/platform/3ds/3ds-vfs.c (view raw)
1/* Copyright (c) 2013-2014 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 "3ds-vfs.h"
7
8#ifdef USE_VFS_3DS
9#include "util/memory.h"
10#include "util/string.h"
11
12struct VFile3DS {
13 struct VFile d;
14
15 Handle handle;
16 u64 offset;
17};
18
19struct VDirEntry3DS {
20 struct VDirEntry d;
21 FS_DirectoryEntry ent;
22 char utf8Name[256];
23};
24
25struct VDir3DS {
26 struct VDir d;
27
28 char* path;
29 Handle handle;
30 struct VDirEntry3DS vde;
31};
32
33static bool _vf3dClose(struct VFile* vf);
34static off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence);
35static ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size);
36static ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size);
37static void* _vf3dMap(struct VFile* vf, size_t size, int flags);
38static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size);
39static void _vf3dTruncate(struct VFile* vf, size_t size);
40static ssize_t _vf3dSize(struct VFile* vf);
41static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size);
42
43static bool _vd3dClose(struct VDir* vd);
44static void _vd3dRewind(struct VDir* vd);
45static struct VDirEntry* _vd3dListNext(struct VDir* vd);
46static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode);
47static struct VDir* _vd3dOpenDir(struct VDir* vd, const char* path);
48static bool _vd3dDeleteFile(struct VDir* vd, const char* path);
49
50static const char* _vd3deName(struct VDirEntry* vde);
51static enum VFSType _vd3deType(struct VDirEntry* vde);
52
53struct VFile* VFileOpen3DS(FS_Archive* archive, const char* path, int flags) {
54 struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS));
55 if (!vf3d) {
56 return 0;
57 }
58
59 // TODO: Use UTF-16
60 FS_Path newPath = fsMakePath(PATH_ASCII, path);
61 Result res = FSUSER_OpenFile(&vf3d->handle, *archive, newPath, flags, 0);
62 if (res & 0xFFFC03FF) {
63 free(vf3d);
64 return 0;
65 }
66
67 vf3d->offset = 0;
68
69 vf3d->d.close = _vf3dClose;
70 vf3d->d.seek = _vf3dSeek;
71 vf3d->d.read = _vf3dRead;
72 vf3d->d.readline = VFileReadline;
73 vf3d->d.write = _vf3dWrite;
74 vf3d->d.map = _vf3dMap;
75 vf3d->d.unmap = _vf3dUnmap;
76 vf3d->d.truncate = _vf3dTruncate;
77 vf3d->d.size = _vf3dSize;
78 vf3d->d.sync = _vf3dSync;
79
80 return &vf3d->d;
81}
82
83bool _vf3dClose(struct VFile* vf) {
84 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
85
86 FSFILE_Close(vf3d->handle);
87 svcCloseHandle(vf3d->handle);
88 return true;
89}
90
91off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence) {
92 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
93 u64 size;
94 switch (whence) {
95 case SEEK_SET:
96 vf3d->offset = offset;
97 break;
98 case SEEK_END:
99 FSFILE_GetSize(vf3d->handle, &size);
100 vf3d->offset = size;
101 // Fall through
102 case SEEK_CUR:
103 vf3d->offset += offset;
104 break;
105 }
106 return vf3d->offset;
107}
108
109ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size) {
110 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
111 u32 sizeRead;
112 Result res = FSFILE_Read(vf3d->handle, &sizeRead, vf3d->offset, buffer, size);
113 if (res) {
114 return -1;
115 }
116 vf3d->offset += sizeRead;
117 return sizeRead;
118}
119
120ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size) {
121 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
122 u32 sizeWritten;
123 Result res = FSFILE_Write(vf3d->handle, &sizeWritten, vf3d->offset, buffer, size, FS_WRITE_FLUSH);
124 if (res) {
125 return -1;
126 }
127 vf3d->offset += sizeWritten;
128 return sizeWritten;
129}
130
131static void* _vf3dMap(struct VFile* vf, size_t size, int flags) {
132 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
133 UNUSED(flags);
134 void* buffer = anonymousMemoryMap(size);
135 if (buffer) {
136 u32 sizeRead;
137 FSFILE_Read(vf3d->handle, &sizeRead, 0, buffer, size);
138 }
139 return buffer;
140}
141
142static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size) {
143 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
144 u32 sizeWritten;
145 FSFILE_Write(vf3d->handle, &sizeWritten, 0, memory, size, FS_WRITE_FLUSH);
146 mappedMemoryFree(memory, size);
147}
148
149static void _vf3dTruncate(struct VFile* vf, size_t size) {
150 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
151 FSFILE_SetSize(vf3d->handle, size);
152}
153
154ssize_t _vf3dSize(struct VFile* vf) {
155 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
156 u64 size;
157 FSFILE_GetSize(vf3d->handle, &size);
158 return size;
159}
160
161static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) {
162 struct VFile3DS* vf3d = (struct VFile3DS*) vf;
163 if (buffer) {
164 u32 sizeWritten;
165 Result res = FSFILE_Write(vf3d->handle, &sizeWritten, 0, buffer, size, FS_WRITE_FLUSH);
166 if (res) {
167 return false;
168 }
169 }
170 FSFILE_Flush(vf3d->handle);
171 return true;
172}
173
174struct VDir* VDirOpen(const char* path) {
175 struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS));
176 if (!vd3d) {
177 return 0;
178 }
179
180 // TODO: Use UTF-16
181 FS_Path newPath = fsMakePath(PATH_ASCII, path);
182 Result res = FSUSER_OpenDirectory(&vd3d->handle, sdmcArchive, newPath);
183 if (res & 0xFFFC03FF) {
184 free(vd3d);
185 return 0;
186 }
187
188 vd3d->path = strdup(path);
189
190 vd3d->d.close = _vd3dClose;
191 vd3d->d.rewind = _vd3dRewind;
192 vd3d->d.listNext = _vd3dListNext;
193 vd3d->d.openFile = _vd3dOpenFile;
194 vd3d->d.openDir = _vd3dOpenDir;
195 vd3d->d.deleteFile = _vd3dDeleteFile;
196
197 vd3d->vde.d.name = _vd3deName;
198 vd3d->vde.d.type = _vd3deType;
199
200 return &vd3d->d;
201}
202
203static bool _vd3dClose(struct VDir* vd) {
204 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
205 FSDIR_Close(vd3d->handle);
206 free(vd3d->path);
207 free(vd3d);
208 return true;
209}
210
211static void _vd3dRewind(struct VDir* vd) {
212 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
213 FSDIR_Close(vd3d->handle);
214 // TODO: Use UTF-16
215 FS_Path newPath = fsMakePath(PATH_ASCII, vd3d->path);
216 FSUSER_OpenDirectory(&vd3d->handle, sdmcArchive, newPath);
217}
218
219static struct VDirEntry* _vd3dListNext(struct VDir* vd) {
220 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
221 u32 n = 0;
222 memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent));
223 memset(vd3d->vde.utf8Name, 0, sizeof(vd3d->vde.utf8Name));
224 FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent);
225 if (!n) {
226 return 0;
227 }
228 return &vd3d->vde.d;
229}
230
231static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) {
232 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
233 if (!path) {
234 return 0;
235 }
236 const char* dir = vd3d->path;
237 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
238 sprintf(combined, "%s/%s", dir, path);
239
240 struct VFile* file = VFileOpen(combined, mode);
241 free(combined);
242 return file;
243}
244
245static struct VDir* _vd3dOpenDir(struct VDir* vd, const char* path) {
246 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
247 if (!path) {
248 return 0;
249 }
250 const char* dir = vd3d->path;
251 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
252 sprintf(combined, "%s/%s", dir, path);
253
254 struct VDir* vd2 = VDirOpen(combined);
255 if (!vd2) {
256 vd2 = VDirOpenArchive(combined);
257 }
258 free(combined);
259 return vd2;
260}
261
262static bool _vd3dDeleteFile(struct VDir* vd, const char* path) {
263 struct VDir3DS* vd3d = (struct VDir3DS*) vd;
264 if (!path) {
265 return 0;
266 }
267 const char* dir = vd3d->path;
268 char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
269 sprintf(combined, "%s/%s", dir, path);
270
271 // TODO: Use UTF-16
272 FS_Path newPath = fsMakePath(PATH_ASCII, combined);
273 bool ret = !FSUSER_DeleteFile(sdmcArchive, newPath);
274 free(combined);
275 return ret;
276}
277
278static const char* _vd3deName(struct VDirEntry* vde) {
279 struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
280 if (!vd3de->utf8Name[0]) {
281 utf16_to_utf8(vd3de->utf8Name, vd3de->ent.name, sizeof(vd3de->utf8Name));
282 }
283 return vd3de->utf8Name;
284}
285
286static enum VFSType _vd3deType(struct VDirEntry* vde) {
287 struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
288 if (vd3de->ent.attributes & FS_ATTRIBUTE_DIRECTORY) {
289 return VFS_DIRECTORY;
290 }
291 return VFS_FILE;
292}
293#endif