void TocManager::readDir(const char *path, TocNode **node, int level) { if (level <= 2) { // we don't scan deeper than that iox_dirent_t dirent; int fd = fio.dopen(path); if (fd >= 0) { while (fio.dread(fd, &dirent) > 0) if (dirent.name[0] != '.') { // skip '.' and '..' *node = new TocNode; (*node)->sub = (*node)->next = NULL; (*node)->nameLen = strlen(dirent.name); memcpy((*node)->name, dirent.name, (*node)->nameLen + 1); if (dirent.stat.mode & FIO_S_IFDIR) { // directory (*node)->isDir = true; char nextPath[256]; sprintf(nextPath, "%s%s/", path, dirent.name); readDir(nextPath, &((*node)->sub), level + 1); } else (*node)->isDir = false; node = &((*node)->next); } fio.dclose(fd); } else printf("Can't open path: %s\n", path); } }
bool Ps2ReadFile::open(const char *name) { assert(_fd < 0); _fd = fio.open(name, O_RDONLY); if (_fd >= 0) { _fileSize = fio.seek(_fd, 0, SEEK_END); fio.seek(_fd, 0, SEEK_SET); return true; } else return false; }
void Ps2File::cacheReadAhead() { if (_cacheOpRunning) { // there's already some cache read running if (fio.poll(_fd)) // did it finish? cacheReadSync(); // yes. } if ((!_cacheOpRunning) && ((_readBytesBlock >= CACHE_READ_THRESHOLD) || _stream) && fio.fioAvail()) { // the engine seems to do sequential reads and there are no other I/Os going on. read ahead. uint32 cachePosEnd = _cachePos + _bytesInCache; if (_cachePos > _filePos) return; // there was a seek in the meantime, don't cache. if (cachePosEnd - _filePos >= CACHE_FILL_MIN) return; // cache is full enough. if (cachePosEnd == _fileSize) return; // can't read beyond EOF. assert(cachePosEnd < _fileSize); if (_cachePos + _bytesInCache <= _filePos) { _cacheOfs = _bytesInCache = 0; _cachePos = cachePosEnd = _filePos & ~READ_ALIGN_MASK; assert(_filePos == _physFilePos); } else { uint32 cacheDiff = _filePos - _cachePos; assert(_bytesInCache >= cacheDiff); cacheDiff &= ~READ_ALIGN_MASK; _bytesInCache -= cacheDiff; _cachePos += cacheDiff; _cacheOfs = (_cacheOfs + cacheDiff) % CACHE_SIZE; } if (_physFilePos != cachePosEnd) { sioprintf("unexpected _physFilePos %d cache %d %d\n", _physFilePos, _cacheOfs, _bytesInCache); // assert(!(cachePosEnd & READ_ALIGN_MASK)); // romeo _physFilePos = fio.seek(_fd, cachePosEnd, SEEK_SET); if (_physFilePos != cachePosEnd) { sioprintf("cache seek error: seek to %d instead of %d, fs = %d\n", _physFilePos, cachePosEnd, _fileSize); return; } } uint32 cacheDest = (_cacheOfs + _bytesInCache) % CACHE_SIZE; uint32 cacheRead = CACHE_SIZE - _bytesInCache; if (cacheDest + cacheRead > CACHE_SIZE) cacheRead = CACHE_SIZE - cacheDest; if (cacheRead > MAX_READ_STEP) cacheRead = MAX_READ_STEP; assert((!(cacheRead & READ_ALIGN_MASK)) && cacheRead); _cacheOpRunning = true; fio.read(_fd, _cacheBuf + cacheDest, cacheRead); } }
Ps2WriteFile::~Ps2WriteFile(void) { if ((_fd >= 0) && (_bytesInCache)) { fio.write(_fd, _cacheBuf, _bytesInCache); int wrRes = fio.sync(_fd); if (wrRes != (int)_bytesInCache) // too late to return an error printf("Cache flush on fclose(): Unable to write %d cached bytes to mc, only %d bytes written\n", _bytesInCache, wrRes); } if (_fd >= 0) fio.close(_fd); free(_cacheBuf); }
uint32 Ps2ReadFile::read(void *dest, uint32 len) { WaitSema(_sema); uint8 *destBuf = (uint8*)dest; if ((_filePos < _cachePos) || (_filePos + len > _cachePos + _bytesInCache)) cacheReadSync(); // we have to read from CD, sync cache. while (len && (_filePos != _fileSize)) { if ((_filePos >= _cachePos) && (_filePos < _cachePos + _bytesInCache)) { // read from cache uint32 staPos = (_cacheOfs + (_filePos - _cachePos)) % CACHE_SIZE; uint32 cpyLen = _bytesInCache - (_filePos - _cachePos); if (cpyLen > len) cpyLen = len; if (staPos + cpyLen > CACHE_SIZE) cpyLen = CACHE_SIZE - staPos; assert(cpyLen); memcpy(destBuf, _cacheBuf + staPos, cpyLen); _filePos += cpyLen; destBuf += cpyLen; _readBytesBlock += len; len -= cpyLen; } else { // cache miss assert(!_cacheOpRunning); if (_physFilePos != _filePos) { if ((_filePos < _physFilePos) || (_filePos > _physFilePos + (CACHE_SIZE / 2))) _readBytesBlock = 0; // reset cache hit count _physFilePos = _filePos & ~READ_ALIGN_MASK; if (fio.seek(_fd, _physFilePos, SEEK_SET) != (int)_physFilePos) break; // read beyond EOF } int doRead = len + (_filePos - _physFilePos); doRead = (doRead + READ_ALIGN_MASK) & ~READ_ALIGN_MASK; if (doRead > MAX_READ_STEP) doRead = MAX_READ_STEP; if (doRead < 2048) doRead = 2048; fio.read(_fd, _cacheBuf, doRead); _cachePos = _physFilePos; _cacheOfs = 0; _bytesInCache = fio.sync(_fd); _physFilePos += _bytesInCache; if (!_bytesInCache) break; // EOF } } cacheReadAhead(); SignalSema(_sema); return destBuf - (uint8*)dest; }
bool Ps2SaveFileManager::mcCheck(const char *path) { // Common::FSNode dir(Common::String(path), 1); // FIXED in gcc 3.4.x const Common::String str(path); Common::FSNode dir(str); // int res; printf("mcCheck\n"); if (!dir.exists()) { printf("! exist -> create : "); #ifdef __USE_LIBMC__ printf("%s\n", path+4); // WaitSema(_sema); mcSync(0, NULL, NULL); mcMkDir(0 /*port*/, 0 /*slot*/, path+4); mcSync(0, NULL, &res); printf("sync : %d\n", res); // SignalSema(_sema); #else printf("%s\n", path); fio.mkdir(path); #endif } // TODO: res; return true; }
bool Ps2SaveFileManager::removeSavefile(const Common::String &filename) { Common::FSNode savePath(ConfMan.get("savepath")); // TODO: is this fast? Common::FSNode file; if (!savePath.exists() || !savePath.isDirectory()) return false; if (_getDev(savePath) == MC_DEV) { // if (strncmp(savePath.getPath().c_str(), "mc0:", 4) == 0) { char path[32], temp[32]; strcpy(temp, filename.c_str()); // mcSplit(temp, game, ext); char *game = strdup(strtok(temp, ".")); char *ext = strdup(strtok(NULL, "*")); sprintf(path, "mc0:ScummVM/%s", game); // per game path mcCheck(path); sprintf(path, "mc0:ScummVM/%s/%s.sav", game, ext); file = Common::FSNode(path); free(game); free(ext); } else { file = savePath.getChild(filename); } if (!file.exists() || file.isDirectory()) return false; fio.remove(file.getPath().c_str()); return true; }
Ps2ReadFile::~Ps2ReadFile(void) { if (_cacheOpRunning) cacheReadSync(); free(_cacheBuf); if (_fd >= 0) fio.close(_fd); DeleteSema(_sema); }
void Ps2File::cacheReadSync() { if (_cacheOpRunning) { int res = fio.sync(_fd); assert(res >= 0); _bytesInCache += res; _physFilePos += res; _cacheOpRunning = false; } }
Ps2File::~Ps2File() { uint32 w; if (_fd >= 0) { if (_mode != O_RDONLY) { fio.seek(_fd, 0, SEEK_SET); fio.write(_fd, _cacheBuf, _filePos); w = fio.sync(_fd); dbg_printf("flushed wbuf: %x of %x\n", w, _filePos); } fio.close(_fd); uint32 r = fio.sync(_fd); dbg_printf("close [%d] - sync'd = %d\n", _fd, r); } free(_cacheBuf); #ifdef __PS2_FILE_SEMA__ DeleteSema(_sema); #endif }
uint32 Ps2WriteFile::write(const void *src, uint32 len) { uint32 size = len; uint8 *srcBuf = (uint8*)src; while (size) { uint32 doCpy = (len > CACHE_SIZE - _bytesInCache) ? (CACHE_SIZE - _bytesInCache) : len; if (doCpy) { memcpy(_cacheBuf + _bytesInCache, srcBuf, doCpy); _bytesInCache += doCpy; srcBuf += doCpy; size -= doCpy; } if (_bytesInCache == CACHE_SIZE) { fio.write(_fd, _cacheBuf, _bytesInCache); if (fio.sync(_fd) != (int)_bytesInCache) { printf("Unable to flush %d cached bytes to memory card!\n", _bytesInCache); return 0; } _filePos += _bytesInCache; _bytesInCache = 0; } } return len; }
bool Ps2File::open(const char *name, int mode) { #if 1 _fd = fio.open(name, mode); dbg_printf("open %s [%d]\n", name, _fd); if (_fd >= 0) { _mode = mode; _filePos = 0; if (_mode == O_RDONLY) { _fileSize = fio.seek(_fd, 0, SEEK_END); fio.seek(_fd, 0, SEEK_SET); } else _fileSize = 0; dbg_printf(" _mode = %x\n", _mode); dbg_printf(" _fileSize = %d\n", _fileSize); // dbg_printf(" _filePos = %d\n", _filePos); return true; } return false; #else uint32 r; // hack: FIO does not reports size for RW (?) _fd = fio.open(name, O_RDONLY); if (_fd >= 0) { _fileSize = fio.seek(_fd, 0, SEEK_END); fio.seek(_fd, 0, SEEK_SET); /* rewind ! */ if (_fileSize && mode != O_RDONLY) { fio.read(_fd, _cacheBuf, _fileSize); r = fio.sync(_fd); dbg_printf(" sz=%d, read=%d\n", _fileSize, r); assert(r == _fileSize); } fio.close(_fd); } else _fileSize = 0; /* new file */ _fd = fio.open(name, mode); dbg_printf("open %s [%d]\n", name, _fd); if (_fd >= 0) { _mode = mode; _filePos = 0; if (_fileSize) { /* existing data */ if (mode == O_RDONLY) { /* DANGER: for w* modes it will truncate your fine files */ fio.seek(_fd, 0, SEEK_SET); } else if (_mode & O_APPEND) { fio.seek(_fd, 0, _fileSize); _filePos = _fileSize; } #if 0 /* file already trunc'd when opened as w* -> moved up */ if (mode != O_RDONLY) { fio.read(_fd, _cacheBuf, _fileSize); r = fio.sync(_fd); dbg_printf(" sz=%d, read=%d\n", _fileSize, r); assert(r == _fileSize); // _fileSize = fio.seek(_fd, 0, SEEK_END); } #endif } dbg_printf(" _mode = %x\n", _mode); dbg_printf(" _fileSize = %d\n", _fileSize); dbg_printf(" _filePos = %d\n", _filePos); return true; } else return false; #endif }
uint32 Ps2File::read(void *dest, uint32 len) { // uint32 r=0, d=0, ds=0, sz=0; #ifdef __PS2_FILE_SEMA__ WaitSema(_sema); #endif #ifdef __PS2_FILE_DEBUG__ dbg_printf("read (1) : _filePos = %d\n", _filePos); dbg_printf("read (1) : _cachePos = %d\n", _cachePos); #endif if (len == 0) { #ifdef __PS2_FILE_SEMA__ SignalSema(_sema); #endif return 0; } if (_filePos >= _fileSize) { _eof = true; #ifdef __PS2_FILE_SEMA__ SignalSema(_sema); #endif return 0; } if ((_filePos+len) > _fileSize) { len = _fileSize-_filePos; _eof = true; } uint8 *destBuf = (uint8 *)dest; if ((_filePos < _cachePos) || (_filePos + len > _cachePos + _bytesInCache)) cacheReadSync(); // we have to read from CD, sync cache. while (len && (_filePos != _fileSize)) { if ((_filePos >= _cachePos) && (_filePos < _cachePos + _bytesInCache)) { // read from cache uint32 staPos = (_cacheOfs + (_filePos - _cachePos)) % CACHE_SIZE; uint32 cpyLen = _bytesInCache - (_filePos - _cachePos); if (cpyLen > len) cpyLen = len; if (staPos + cpyLen > CACHE_SIZE) cpyLen = CACHE_SIZE - staPos; assert(cpyLen); memcpy(destBuf, _cacheBuf + staPos, cpyLen); _filePos += cpyLen; destBuf += cpyLen; _readBytesBlock += len; len -= cpyLen; } else { // cache miss assert(!_cacheOpRunning); if (_physFilePos != _filePos) { if ((_filePos < _physFilePos) || (_filePos > _physFilePos + (CACHE_SIZE / 2))) _readBytesBlock = 0; // reset cache hit count _physFilePos = _filePos & ~READ_ALIGN_MASK; if (fio.seek(_fd, _physFilePos, SEEK_SET) != (int)_physFilePos) break; // read beyond EOF } int doRead = len + (_filePos - _physFilePos); doRead = (doRead + READ_ALIGN_MASK) & ~READ_ALIGN_MASK; if (doRead > MAX_READ_STEP) doRead = MAX_READ_STEP; if (doRead < 2048) doRead = 2048; fio.read(_fd, _cacheBuf, doRead); _cachePos = _physFilePos; _cacheOfs = 0; _bytesInCache = fio.sync(_fd); _physFilePos += _bytesInCache; if (!_bytesInCache) break; // EOF } } #ifndef ENABLE_PROFILING // doesn't play nice with -pg cacheReadAhead(); #endif #ifdef __PS2_FILE_SEMA__ SignalSema(_sema); #endif return destBuf - (uint8 *)dest; }
bool Ps2FilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const { //TODO: honor the hidden flag // dbg_printf("getChildren\n"); if (!_isDirectory) return false; if (_isRoot) { if (g_systemPs2->cdPresent()) list.push_back(new Ps2FilesystemNode("cdfs:")); if (g_systemPs2->hddPresent()) list.push_back(new Ps2FilesystemNode("pfs0:")); if (g_systemPs2->usbMassPresent()) list.push_back(new Ps2FilesystemNode("mass:")); if (g_systemPs2->netPresent()) list.push_back(new Ps2FilesystemNode("host:")); if (g_systemPs2->mcPresent()) list.push_back(new Ps2FilesystemNode("mc0:")); return true; } else { int fd; if (_path == "pfs0:") fd = fio.dopen("pfs0:/"); else fd = fio.dopen(_path.c_str()); // dbg_printf("dopen = %d\n", fd); if (fd >= 0) { iox_dirent_t dirent; Ps2FilesystemNode dirEntry; int dreadRes; while ((dreadRes = fio.dread(fd, &dirent)) > 0) { if (dirent.name[0] == '.') continue; // ignore '.' and '..' if ( (mode == Common::FSNode::kListAll) || ((mode == Common::FSNode::kListDirectoriesOnly) && (dirent.stat.mode & FIO_S_IFDIR)) || ((mode == Common::FSNode::kListFilesOnly) && !(dirent.stat.mode & FIO_S_IFDIR)) ) { dirEntry._isHere = true; dirEntry._isDirectory = (bool)(dirent.stat.mode & FIO_S_IFDIR); dirEntry._isRoot = false; dirEntry._path = _path; dirEntry._path += dirent.name; if (dirEntry._isDirectory && dirEntry._path.lastChar() != '/') dirEntry._path += '/'; dirEntry._displayName = dirent.name; dirEntry._verified = true; list.push_back(new Ps2FilesystemNode(&dirEntry)); } } fio.dclose(fd); return true; } } return false; }
void Ps2FilesystemNode::doverify(void) { PS2Device medium; int fd; if (_verified) return; _verified = true; dbg_printf(" verify: %s -> ", _path.c_str()); #if 0 if (_path.empty()) { dbg_printf("PlayStation 2 Root !\n"); _verified = true; return; } if (_path.lastChar() == ':') { dbg_printf("Dev: %s\n", _path.c_str()); _verified = true; return; } #endif if (_path[3] != ':' && _path[4] != ':') { dbg_printf("relative path !\n"); _isHere = false; _isDirectory = false; return; } medium = _getDev(_path); if (medium == ERR_DEV) { _isHere = false; _isDirectory = false; return; } switch (medium) { #if 0 case HD_DEV: /*stat*/ case USB_DEV: iox_stat_t stat; fileXioGetStat(_path.c_str(), &stat); fileXioWaitAsync(FXIO_WAIT, &fd); if (!fd) { dbg_printf(" yes [stat]\n"); return true; } break; #endif case CD_DEV: /*no stat*/ case HD_DEV: case USB_DEV: case HOST_DEV: case MC_DEV: #if 1 fd = fio.open(_path.c_str(), O_RDONLY); dbg_printf("_path = %s -- fio.open -> %d\n", _path.c_str(), fd); if (fd >=0) { fio.close(fd); dbg_printf(" yes [open]\n"); _isHere = true; if (medium==MC_DEV && _path.lastChar()=='/') _isDirectory = true; else _isDirectory = false; return; } fd = fio.dopen(_path.c_str()); if (fd >=0) { fio.dclose(fd); dbg_printf(" yes [dopen]\n"); _isHere = true; _isDirectory = true; return; } #else fileXioOpen(_path.c_str(), O_RDONLY, DEFAULT_MODE); fileXioWaitAsync(FXIO_WAIT, &fd); if (fd>=0) { fileXioClose(fd); fileXioWaitAsync(FXIO_WAIT, &fd); return true; } fileXioDopen(_path.c_str()); fileXioWaitAsync(FXIO_WAIT, &fd); if (fd>=0) { fileXioDclose(fd); fileXioWaitAsync(FXIO_WAIT, &fd); return true; } #endif break; case ERR_DEV: _isHere = false; _isDirectory = false; break; } _isHere = false; _isDirectory = false; dbg_printf(" no\n"); return; }
bool Ps2WriteFile::open(const char *name) { _fd = fio.open(name, O_WRONLY | O_CREAT | O_TRUNC); return (_fd >= 0); }