1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #if defined(__PLAYSTATION2__)
24
25 // Disable symbol overrides so that we can use "FILE"
26 #define FORBIDDEN_SYMBOL_EXCEPTION_FILE
27 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
28 #define FORBIDDEN_SYMBOL_EXCEPTION_abort
29 #define FORBIDDEN_SYMBOL_EXCEPTION_exit
30
31 #include "backends/fs/ps2/ps2-fs.h"
32
33 #include <kernel.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include "backends/platform/ps2/asyncfio.h"
37 #include "backends/platform/ps2/fileio.h"
38 #include "backends/platform/ps2/systemps2.h"
39 #include "backends/platform/ps2/ps2debug.h"
40
41 #include <fileXio_rpc.h>
42
43 #include "backends/platform/ps2/ps2temp.h"
44
45 #define DEFAULT_MODE (FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IROTH | FIO_S_IWOTH)
46
47 extern AsyncFio fio;
48 extern OSystem_PS2 *g_systemPs2;
49
_lastPathComponent(const Common::String & str)50 const char *_lastPathComponent(const Common::String &str) {
51 if (str.empty())
52 return "";
53
54 const char *start = str.c_str();
55 const char *cur = start + str.size() - 2;
56
57 while (cur >= start && *cur != '/' && *cur != ':') {
58 --cur;
59 }
60
61 cur++;
62
63 // dbg_printf("lastPathComponent path=%s token=%s\n", start, cur);
64
65 return cur;
66 }
67
Ps2FilesystemNode()68 Ps2FilesystemNode::Ps2FilesystemNode() {
69 dbg_printf("NEW FSNODE()\n");
70
71 _isHere = true;
72 _isDirectory = true;
73 _isRoot = true;
74 _verified = false;
75 _displayName = Common::String("PlayStation 2");
76 _path = "";
77 }
78
Ps2FilesystemNode(const Common::String & path)79 Ps2FilesystemNode::Ps2FilesystemNode(const Common::String &path) {
80 dbg_printf("NEW FSNODE(%s)\n", path.c_str());
81
82 _path = path;
83
84 if (path.empty()) {
85 _isHere = true;
86 _isDirectory = true; /* root is always a dir */
87 _isRoot = true;
88 _displayName = Common::String("PlayStation 2");
89 _verified = true;
90 } else if (path.lastChar() == ':') {
91 _isHere = true;
92 _isDirectory = true; /* devs are always a dir */
93 _isRoot = false;
94 _displayName = getDeviceDescription();
95 _verified = true;
96 } else {
97 _verified = false;
98 doverify();
99 if (!_isHere)
100 return;
101
102 _displayName = _lastPathComponent(_path);
103
104 if (_isDirectory && _path.lastChar() != '/')
105 _path+= '/';
106
107 _isRoot = false;
108 }
109 }
110
Ps2FilesystemNode(const Common::String & path,bool verify)111 Ps2FilesystemNode::Ps2FilesystemNode(const Common::String &path, bool verify) {
112 dbg_printf("NEW FSNODE(%s, %d)\n", path.c_str(), verify);
113
114 _path = path;
115
116 if (path.empty()) {
117 _isHere = true;
118 _isDirectory = true; /* root is always a dir */
119 _isRoot = true;
120 _displayName = Common::String("PlayStation 2");
121 _verified = true;
122 } else if (path.lastChar() == ':') {
123 _isHere = true;
124 _isDirectory = true; /* devs are always a dir */
125 _isRoot = false;
126 _displayName = getDeviceDescription();
127 _verified = true;
128 } else {
129 _verified = false;
130 if (verify) {
131 doverify();
132
133 if (!_isHere)
134 return;
135
136 } else {
137 _verified = false;
138 _isDirectory = false;
139 _isHere = false; // true
140 }
141
142 _displayName = _lastPathComponent(_path);
143
144 if (_isDirectory && _path.lastChar() != '/')
145 _path+= '/';
146
147 _isRoot = false;
148 }
149 }
150
Ps2FilesystemNode(const Ps2FilesystemNode * node)151 Ps2FilesystemNode::Ps2FilesystemNode(const Ps2FilesystemNode *node) {
152 _displayName = node->_displayName;
153 _isDirectory = node->_isDirectory;
154 _path = node->_path;
155 _isRoot = node->_isRoot;
156 _isHere = node->_isHere;
157 _verified = node->_verified;
158 }
159
doverify(void)160 void Ps2FilesystemNode::doverify(void) {
161 PS2Device medium;
162 int fd;
163
164 if (_verified)
165 return;
166
167 _verified = true;
168
169 dbg_printf(" verify: %s -> ", _path.c_str());
170
171 #if 0
172 if (_path.empty()) {
173 dbg_printf("PlayStation 2 Root !\n");
174 _verified = true;
175 return;
176 }
177
178 if (_path.lastChar() == ':') {
179 dbg_printf("Dev: %s\n", _path.c_str());
180 _verified = true;
181 return;
182 }
183 #endif
184
185 if (_path[3] != ':' && _path[4] != ':') {
186 dbg_printf("relative path !\n");
187 _isHere = false;
188 _isDirectory = false;
189 return;
190 }
191
192 medium = _getDev(_path);
193 if (medium == ERR_DEV) {
194 _isHere = false;
195 _isDirectory = false;
196 return;
197 }
198
199 switch (medium) {
200 #if 0
201 case HD_DEV: /*stat*/
202 case USB_DEV:
203 iox_stat_t stat;
204
205 fileXioGetStat(_path.c_str(), &stat);
206 fileXioWaitAsync(FXIO_WAIT, &fd);
207
208 if (!fd) {
209 dbg_printf(" yes [stat]\n");
210 return true;
211 }
212 break;
213 #endif
214
215 case CD_DEV: /*no stat*/
216 case HD_DEV:
217 case USB_DEV:
218 case HOST_DEV:
219 case MC_DEV:
220 #if 1
221 fd = fio.open(_path.c_str(), O_RDONLY);
222
223 dbg_printf("_path = %s -- fio.open -> %d\n", _path.c_str(), fd);
224
225 if (fd >=0) {
226 fio.close(fd);
227 dbg_printf(" yes [open]\n");
228 _isHere = true;
229 if (medium==MC_DEV && _path.lastChar()=='/')
230 _isDirectory = true;
231 else
232 _isDirectory = false;
233 return;
234 }
235
236 fd = fio.dopen(_path.c_str());
237 if (fd >=0) {
238 fio.dclose(fd);
239 dbg_printf(" yes [dopen]\n");
240 _isHere = true;
241 _isDirectory = true;
242 return;
243 }
244
245 #else
246 fileXioOpen(_path.c_str(), O_RDONLY, DEFAULT_MODE);
247 fileXioWaitAsync(FXIO_WAIT, &fd);
248 if (fd>=0) {
249 fileXioClose(fd);
250 fileXioWaitAsync(FXIO_WAIT, &fd);
251 return true;
252 }
253
254 fileXioDopen(_path.c_str());
255 fileXioWaitAsync(FXIO_WAIT, &fd);
256 if (fd>=0) {
257 fileXioDclose(fd);
258 fileXioWaitAsync(FXIO_WAIT, &fd);
259 return true;
260 }
261 #endif
262 break;
263 case ERR_DEV:
264 _isHere = false;
265 _isDirectory = false;
266 break;
267 }
268
269 _isHere = false;
270 _isDirectory = false;
271
272 dbg_printf(" no\n");
273 return;
274 }
275
getChild(const Common::String & n) const276 AbstractFSNode *Ps2FilesystemNode::getChild(const Common::String &n) const {
277
278 dbg_printf("getChild : %s\n", n.c_str());
279
280 if (!_isDirectory)
281 return NULL;
282
283 if (_isRoot) {
284 if (n.lastChar() == ':')
285 return new Ps2FilesystemNode(n);
286 else
287 return NULL;
288 }
289
290 return new Ps2FilesystemNode(_path+n, 1);
291
292 /*
293 int fd;
294
295 if (_path == "pfs0:")
296 fd = fio.dopen("pfs0:/");
297 else
298 fd = fio.dopen(_path.c_str());
299
300 if (fd >= 0) {
301 iox_dirent_t dirent;
302
303 while (fio.dread(fd, &dirent) > 0) {
304 if (strcmp(n.c_str(), dirent.name) == 0) {
305 Ps2FilesystemNode *dirEntry = new Ps2FilesystemNode();
306
307 dirEntry->_isHere = true;
308 dirEntry->_isDirectory = (bool)(dirent.stat.mode & FIO_S_IFDIR);
309 dirEntry->_isRoot = false;
310
311 dirEntry->_path = _path;
312 dirEntry->_path += dirent.name;
313 if (dirEntry->_isDirectory && dirEntry->_path.lastChar() != '/')
314 dirEntry->_path += '/';
315 dirEntry->_displayName = dirent.name;
316
317 dirEntry->_verified = true;
318
319 fio.dclose(fd);
320 return dirEntry;
321 }
322 }
323 fio.dclose(fd);
324 }
325
326 return NULL;
327 */
328 }
329
getChildren(AbstractFSList & list,ListMode mode,bool hidden) const330 bool Ps2FilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const {
331 //TODO: honor the hidden flag
332
333 // dbg_printf("getChildren\n");
334
335 if (!_isDirectory)
336 return false;
337
338 if (_isRoot) {
339 if (g_systemPs2->cdPresent())
340 list.push_back(new Ps2FilesystemNode("cdfs:"));
341
342 if (g_systemPs2->hddPresent())
343 list.push_back(new Ps2FilesystemNode("pfs0:"));
344
345 if (g_systemPs2->usbMassPresent())
346 list.push_back(new Ps2FilesystemNode("mass:"));
347
348 if (g_systemPs2->netPresent())
349 list.push_back(new Ps2FilesystemNode("host:"));
350
351 if (g_systemPs2->mcPresent())
352 list.push_back(new Ps2FilesystemNode("mc0:"));
353
354 return true;
355 } else {
356 int fd;
357
358 if (_path == "pfs0:")
359 fd = fio.dopen("pfs0:/");
360 else
361 fd = fio.dopen(_path.c_str());
362
363 // dbg_printf("dopen = %d\n", fd);
364
365 if (fd >= 0) {
366 iox_dirent_t dirent;
367 Ps2FilesystemNode dirEntry;
368 int dreadRes;
369 while ((dreadRes = fio.dread(fd, &dirent)) > 0) {
370
371 if (dirent.name[0] == '.')
372 continue; // ignore '.' and '..'
373
374 if ( (mode == Common::FSNode::kListAll) ||
375
376 ((mode == Common::FSNode::kListDirectoriesOnly) &&
377 (dirent.stat.mode & FIO_S_IFDIR)) ||
378
379 ((mode == Common::FSNode::kListFilesOnly) &&
380 !(dirent.stat.mode & FIO_S_IFDIR)) ) {
381
382 dirEntry._isHere = true;
383 dirEntry._isDirectory = (bool)(dirent.stat.mode & FIO_S_IFDIR);
384 dirEntry._isRoot = false;
385
386 dirEntry._path = _path;
387 dirEntry._path += dirent.name;
388 if (dirEntry._isDirectory && dirEntry._path.lastChar() != '/')
389 dirEntry._path += '/';
390 dirEntry._displayName = dirent.name;
391
392 dirEntry._verified = true;
393
394 list.push_back(new Ps2FilesystemNode(&dirEntry));
395 }
396 }
397 fio.dclose(fd);
398 return true;
399 }
400 }
401 return false;
402 }
403
getParent() const404 AbstractFSNode *Ps2FilesystemNode::getParent() const {
405 // dbg_printf("Ps2FilesystemNode::getParent : path = %s\n", _path.c_str());
406
407 if (_isRoot)
408 return new Ps2FilesystemNode(this); // FIXME : 0 ???
409
410 if (_path.lastChar() == ':') // devs
411 return new Ps2FilesystemNode(); // N: default is root
412
413 const char *start = _path.c_str();
414 const char *end = _lastPathComponent(_path);
415
416 Common::String str(start, end - start);
417 // dbg_printf(" parent = %s\n", str.c_str());
418
419 return new Ps2FilesystemNode(str, true);
420 }
421
getDeviceDescription() const422 const char *Ps2FilesystemNode::getDeviceDescription() const {
423 if (strncmp(_path.c_str(), "cdfs", 4) == 0)
424 return "DVD Drive";
425 else if (strncmp(_path.c_str(), "pfs0", 4) == 0)
426 return "Harddisk";
427 else if (strncmp(_path.c_str(), "mass", 4) == 0)
428 return "USB Mass Storage";
429 else if (strncmp(_path.c_str(), "host", 4) == 0)
430 return "Host";
431 else if (strncmp(_path.c_str(), "mc0", 3) == 0)
432 return "Memory Card";
433 else
434 return "WTF ???";
435 }
436
createReadStream()437 Common::SeekableReadStream *Ps2FilesystemNode::createReadStream() {
438 Common::SeekableReadStream *ss = PS2FileStream::makeFromPath(getPath(), false);
439 return ss;
440 }
441
createWriteStream()442 Common::WriteStream *Ps2FilesystemNode::createWriteStream() {
443 return PS2FileStream::makeFromPath(getPath(), true);
444 }
445
createDirectory()446 bool Ps2FilesystemNode::createDirectory() {
447 warning("Ps2FilesystemNode::createDirectory(): Not supported");
448 return _isHere && _isDirectory;
449 }
450
451 #endif
452