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