1 /*****************************************************************************
2 *
3 * Copyright (c) 2008-2010, CoreCodec, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of CoreCodec, Inc. nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY CoreCodec, Inc. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL CoreCodec, Inc. BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 ****************************************************************************/
29
30 #include "file.h"
31
32 #if defined(TARGET_PS2SDK)
33
34 #include <stdio.h>
35 #include <sys/stat.h>
36 #include <kernel.h>
37 #include <fileXio_rpc.h>
38 #include <loadfile.h>
39
40 typedef struct filestream
41 {
42 stream Stream;
43 int fd;
44 tchar_t URL[MAXPATH]; // TODO: turn into a dynamic data
45 filepos_t Length;
46 int Flags;
47
48 tchar_t DirPath[MAXPATH]; // TODO: turn into a dynamic data
49 int FindDir;
50 int DevNo;
51
52 } filestream;
53
CdromPath(const char * Path,char * Tmp,size_t TmpLen)54 const char* CdromPath(const char* Path, char* Tmp, size_t TmpLen)
55 {
56 if (strnicmp(Path,"cdrom",5)==0)
57 {
58 // 8.3 upper case name
59 size_t a,b,c;
60 for (a=0,b=0,c=32;b+1<TmpLen && Path[a];++a)
61 {
62 char ch=Path[a];
63 if (ch=='/' || ch=='\\' || ch==':')
64 {
65 c=0;
66 }
67 else
68 if (ch=='.')
69 {
70 if (c>=16) continue;
71 c=16;
72 }
73 else
74 {
75 if (c==8) continue;
76 if (c==16+3) continue;
77 if (c<32)
78 ch=toupper(ch);
79 ++c;
80 }
81 Tmp[b++]=ch;
82 }
83 Tmp[b]=0;
84 Path = Tmp;
85 }
86 return Path;
87 }
88
Open(filestream * p,const tchar_t * URL,int Flags)89 static err_t Open(filestream* p, const tchar_t* URL, int Flags)
90 {
91 if (p->fd>=0)
92 fileXioClose(p->fd);
93
94 p->Length = INVALID_FILEPOS_T;
95 p->fd = -1;
96
97 if (URL && URL[0])
98 {
99 tchar_t Tmp[MAXPATH];
100 int size;
101 int mode = 0;
102
103 URL = CdromPath(URL,Tmp,TSIZEOF(Tmp));
104
105 if (Flags & SFLAG_WRONLY && !(Flags & SFLAG_RDONLY))
106 mode = O_WRONLY;
107 else if (Flags & SFLAG_RDONLY && !(Flags & SFLAG_WRONLY))
108 mode = O_RDONLY;
109 else
110 mode = O_RDWR;
111
112 if (Flags & SFLAG_CREATE)
113 mode |= O_CREAT|O_TRUNC;
114
115 p->fd = fileXioOpen(URL, mode, FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH );
116 if (p->fd<0)
117 {
118 if ((Flags & (SFLAG_REOPEN|SFLAG_SILENT))==0)
119 NodeReportError(p,NULL,ERR_ID,ERR_FILE_NOT_FOUND,URL);
120 return ERR_FILE_NOT_FOUND;
121 }
122
123 tcscpy_s(p->URL,TSIZEOF(p->URL),URL);
124
125 if ((size = fileXioLseek(p->fd, 0, SEEK_END)) >= 0)
126 {
127 fileXioLseek(p->fd, 0, SEEK_SET);
128 p->Length = size;
129 }
130 }
131 return ERR_NONE;
132 }
133
Read(filestream * p,void * Data,size_t Size,size_t * Readed)134 static err_t Read(filestream* p,void* Data,size_t Size,size_t* Readed)
135 {
136 err_t Err;
137 int n;
138
139 n = fileXioRead(p->fd, Data, (unsigned int)Size);
140 if (n<0)
141 {
142 n=0;
143 Err = ERR_READ;
144 }
145 else
146 Err = ((size_t)n != Size) ? ERR_END_OF_FILE:ERR_NONE;
147
148 if (Readed)
149 *Readed = n;
150 return Err;
151 }
152
ReadBlock(filestream * p,block * Block,size_t Ofs,size_t Size,size_t * Readed)153 static err_t ReadBlock(filestream* p,block* Block,size_t Ofs,size_t Size,size_t* Readed)
154 {
155 return Read(p,(void*)(Block->Ptr+Ofs),Size,Readed);
156 }
157
Write(filestream * p,const void * Data,size_t Size,size_t * Written)158 static err_t Write(filestream* p,const void* Data,size_t Size,size_t* Written)
159 {
160 err_t Err;
161 int n;
162
163 n = fileXioWrite(p->fd, (void*)Data, (unsigned int)Size);
164 if (n<0)
165 {
166 n=0;
167 Err = ERR_WRITE;
168 }
169 else
170 Err = (n != Size) ? ERR_WRITE:ERR_NONE;
171
172 if (Written)
173 *Written = n;
174 return Err;
175 }
176
Seek(filestream * p,filepos_t Pos,int SeekMode)177 static filepos_t Seek(filestream* p,filepos_t Pos,int SeekMode)
178 {
179 int Pos = fileXioLseek(p->fd, Pos, SeekMode);
180 if (Pos<0)
181 return INVALID_FILEPOS_T;
182 return Pos;
183 }
184
SetLength(filestream * p,dataid Id,const int * Data,size_t Size)185 static err_t SetLength(filestream* p,dataid Id,const int* Data,size_t Size)
186 {
187 #ifndef TODO
188 assert(NULL); // not supported yet
189 #endif
190 return ERR_NOT_SUPPORTED;
191 }
192
OpenDir(filestream * p,const tchar_t * URL,int UNUSED_PARAM (Flags))193 static err_t OpenDir(filestream* p,const tchar_t* URL,int UNUSED_PARAM(Flags))
194 {
195 if (p->FindDir>=0)
196 {
197 fileXioDclose(p->FindDir);
198 p->FindDir=-1;
199 }
200
201 if (!URL[0])
202 {
203 p->DevNo = 0;
204 return ERR_NONE;
205 }
206
207 p->DevNo = -1;
208 p->FindDir = fileXioDopen(URL);
209
210 if (p->FindDir<0)
211 {
212 int fd = fileXioOpen(URL,O_RDONLY,0);
213 if (fd >= 0)
214 {
215 fileXioClose(fd);
216 return ERR_NOT_DIRECTORY;
217 }
218 else
219 return ERR_FILE_NOT_FOUND;
220 }
221
222 tcscpy_s(p->DirPath,TSIZEOF(p->DirPath),URL);
223 AddPathDelimiter(p->DirPath,TSIZEOF(p->DirPath));
224 return ERR_NONE;
225 }
226
PS2ToDateTime(unsigned char time[8])227 static datetime_t PS2ToDateTime(unsigned char time[8])
228 {
229 datetime_t t;
230 datepack_t p;
231 p.Year = time[6] + (time[7]<<8);
232 p.Month = time[5];
233 p.Day = time[4];
234 p.Hour = time[3];
235 p.Minute = time[2];
236 p.Second = time[1];
237 t = TimePackToRel(&p,0);
238 if (t != INVALID_DATETIME_T)
239 {
240 t -= 9*60*60; //adjust JST to GMC
241 if (t == INVALID_DATETIME_T)
242 ++t;
243 }
244 return t;
245 }
246
EnumDir(filestream * p,const tchar_t * Exts,bool_t ExtFilter,streamdir * Item)247 static err_t EnumDir(filestream* p,const tchar_t* Exts,bool_t ExtFilter,streamdir* Item)
248 {
249 iox_dirent_t Dirent;
250
251 Item->FileName[0] = 0;
252 Item->DisplayName[0] = 0;
253
254 if (p->DevNo>=0)
255 {
256 static const tchar_t* const Devices[] =
257 {
258 "mass:",
259 //"cdrom:", //driver doesn't support directory listing
260 "hdd:",
261 //"host:", //driver doesn't support directory listing
262 "cdda:",
263 "cdfs:",
264 "smb:",
265 NULL,
266 };
267 for (;!Item->FileName[0];++p->DevNo)
268 {
269 int fd;
270 const tchar_t* URL = Devices[p->DevNo];
271 if (!URL)
272 break;
273
274 fd = fileXioDopen(URL);
275 if (fd>=0)
276 {
277 fileXioDclose(fd);
278 tcscpy_s(Item->FileName,TSIZEOF(Item->FileName), URL);
279 Item->ModifiedDate = INVALID_DATETIME_T;
280 Item->Type = FTYPE_DIR;
281 Item->Size = INVALID_FILEPOS_T;
282 }
283 }
284 }
285 else
286 {
287 if (p->FindDir<0)
288 return ERR_END_OF_FILE;
289
290 while (!Item->FileName[0])
291 {
292 if (fileXioDread(p->FindDir,&Dirent)<=0)
293 break;
294
295 if (Dirent.name[0]=='.') // skip unix/mac hidden files
296 continue;
297
298 tcscpy_s(Item->FileName,TSIZEOF(Item->FileName), Dirent.name);
299
300 Item->ModifiedDate = PS2ToDateTime(Dirent.stat.mtime);
301 if (FIO_S_ISDIR(Dirent.stat.mode))
302 {
303 Item->Type = FTYPE_DIR;
304 Item->Size = INVALID_FILEPOS_T;
305 }
306 else
307 {
308 Item->Size = Dirent.stat.size;
309 Item->Type = CheckExts(Item->FileName,Exts);
310
311 if (!Item->Type && ExtFilter)
312 Item->FileName[0] = 0; // skip
313 }
314 }
315 }
316
317 if (!Item->FileName[0])
318 {
319 if (p->FindDir>=0)
320 {
321 fileXioDclose(p->FindDir);
322 p->FindDir = -1;
323 }
324 return ERR_END_OF_FILE;
325 }
326
327 return ERR_NONE;
328 }
329
Delete(filestream * p)330 static void Delete(filestream* p)
331 {
332 if (p->fd>=0)
333 {
334 fileXioClose(p->fd);
335 p->fd = -1;
336 }
337 if (p->FindDir>=0)
338 {
339 fileXioDclose(p->FindDir);
340 p->FindDir = -1;
341 }
342 }
343
LoadIRX(anynode * AnyNode,const char * Name,size_t ParamCount,const char * Param)344 bool_t LoadIRX(anynode* AnyNode,const char* Name,size_t ParamCount,const char* Param)
345 {
346 int ret;
347 fourcc_t Data;
348 //tchar_t Path[MAXPATH];
349 size_t ParamSize=0;
350 const char* s = Param;
351 for (;ParamCount>0;--ParamCount)
352 {
353 ParamSize += strlen(s)+1;
354 s += strlen(s)+1;
355 }
356
357 /*
358 // try external file
359 if (GetResourcePath(AnyNode,0,Path,TSIZEOF(Path))==ERR_NONE)
360 {
361 tchar_t Tmp[MAXPATH];
362 tcscat_s(Path,TSIZEOF(Path),Name);
363 if (SifExecModuleFile(CdromPath(Path,Tmp,TSIZEOF(Tmp)), ParamSize, Param, &ret)>=0)
364 return ret>=0;
365 }
366 */
367
368 // try core-c resource
369 Data = NodeEnumClassStr(AnyNode,NULL,RESOURCEDATA_ID,NODE_NAME,Name);
370 if (Data)
371 {
372 size_t size = (size_t)NodeClass_Meta(NodeContext_FindClass(AnyNode,Data),RESOURCEDATA_SIZE,META_PARAM_CUSTOM);
373 void* ptr = (void*)NodeClass_Meta(NodeContext_FindClass(AnyNode,Data),RESOURCEDATA_PTR,META_PARAM_CUSTOM);
374 if (ptr && size)
375 {
376 SifExecModuleBuffer(ptr, size, ParamSize, Param, &ret);
377 return ret>=0;
378 }
379 }
380 return 0;
381 }
382
USB_Init(anynode * p)383 void USB_Init(anynode* p)
384 {
385 LoadIRX(p,"usbd.irx",0,NULL);
386 LoadIRX(p,"usbhdfsd.irx",0,NULL);
387 }
388
FileXio_Init(nodemodule * p)389 void FileXio_Init(nodemodule* p)
390 {
391 LoadIRX(p,"fastmem.irx",0,NULL);
392 LoadIRX(p,"poweroff.irx",0,NULL);
393 LoadIRX(p,"iomanx.irx",0,NULL);
394 LoadIRX(p,"filexio.irx",0,NULL);
395 #ifndef CONFIG_NODRIVERS
396 USB_Init(p);
397 #endif
398 }
399
FileXio_Done(nodemodule * p)400 void FileXio_Done(nodemodule* p)
401 {
402 }
403
META_START(File_Class,FILE_CLASS)404 META_START(File_Class,FILE_CLASS)
405 META_CLASS(SIZE,sizeof(filestream))
406 META_CLASS(PRIORITY,PRI_MINIMUM)
407 META_CLASS(DELETE,Delete)
408 META_VMT(TYPE_FUNC,stream_vmt,Open,Open)
409 META_VMT(TYPE_FUNC,stream_vmt,Read,Read)
410 META_VMT(TYPE_FUNC,stream_vmt,ReadBlock,ReadBlock)
411 META_VMT(TYPE_FUNC,stream_vmt,Write,Write)
412 META_VMT(TYPE_FUNC,stream_vmt,Seek,Seek)
413 META_VMT(TYPE_FUNC,stream_vmt,OpenDir,OpenDir)
414 META_VMT(TYPE_FUNC,stream_vmt,EnumDir,EnumDir)
415 META_CONST(TYPE_INT,filestream,fd,-1)
416 META_CONST(TYPE_INT,filestream,FindDir,-1)
417 META_DATA_RDONLY(TYPE_INT,STREAM_FLAGS,filestream,Flags)
418 META_DATA_RDONLY(TYPE_STRING,STREAM_URL,filestream,URL)
419 META_PARAM(SET,STREAM_LENGTH,SetLength)
420 META_DATA(TYPE_FILEPOS,STREAM_LENGTH,filestream,Length)
421 META_PARAM(STRING,NODE_PROTOCOL,T("file"))
422 META_END_CONTINUE(STREAM_CLASS)
423
424 META_START_CONTINUE(RESOURCEDATA_ID)
425 META_CLASS(FLAGS,CFLAG_ABSTRACT)
426 META_END(NODE_CLASS)
427
428 bool_t FileExists(nodecontext *p,const tchar_t* Path)
429 {
430 // not all file systems supports fileXioGetstat
431 tchar_t Tmp[MAXPATH];
432 int fd = fileXioOpen(CdromPath(Path,Tmp,TSIZEOF(Tmp)),O_RDONLY,0);
433 if (fd >= 0)
434 {
435 fileXioClose(fd);
436 return 1;
437 }
438 return 0;
439 }
440
FileErase(nodecontext * p,const tchar_t * Path,bool_t Force,bool_t Safe)441 bool_t FileErase(nodecontext *p,const tchar_t* Path, bool_t Force, bool_t Safe)
442 {
443 bool_t Result = fileXioRemove(Path)==0;
444 fileXioRmdir(Path); // workaround for the bug in the ROM that creates a directory right after removing the file
445 return Result;
446 }
447
FolderErase(nodecontext * p,const tchar_t * Path,bool_t Force,bool_t Safe)448 bool_t FolderErase(nodecontext *p,const tchar_t* Path, bool_t Force, bool_t Safe)
449 {
450 return fileXioRmdir(Path) == 0;
451 }
452
PathIsFolder(nodecontext * p,const tchar_t * Path)453 bool_t PathIsFolder(nodecontext *p,const tchar_t* Path)
454 {
455 // not all file systems supports fileXioGetstat
456 if (tcsnicmp(Path,T("cdrom"),5)!=0)
457 {
458 int fd = fileXioDopen(Path);
459 if (fd >= 0)
460 {
461 fileXioDclose(fd);
462 return 1;
463 }
464 }
465 return 0;
466 }
467
FileDateTime(nodecontext * p,const tchar_t * Path)468 datetime_t FileDateTime(nodecontext *p,const tchar_t* Path)
469 {
470 iox_stat_t Stat;
471 if (fileXioGetStat(Path,&Stat)==0)
472 return PS2ToDateTime(Stat.mtime);
473 return INVALID_DATETIME_T;
474 }
475
FileMove(nodecontext * p,const tchar_t * In,const tchar_t * Out)476 bool_t FileMove(nodecontext *p,const tchar_t* In,const tchar_t* Out)
477 {
478 #ifndef TODO
479 assert(NULL); // not supported yet
480 #endif
481 return 0;
482 }
483
FolderCreate(nodecontext * p,const tchar_t * Path)484 bool_t FolderCreate(nodecontext *p,const tchar_t* Path)
485 {
486 return fileXioMkdir(Path,FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH)==0;
487 }
488
FileTemp(anynode * Any)489 stream *FileTemp(anynode *Any)
490 {
491 #ifndef TODO
492 assert(NULL); // TODO: not supported yet
493 #endif
494 return NULL;
495 }
496
FileTempName(anynode * Any,tchar_t * Out,size_t OutLen)497 bool_t FileTempName(anynode *Any,tchar_t *Out, size_t OutLen)
498 {
499 #ifndef TODO
500 assert(NULL); // TODO: not supported yet
501 #endif
502 return 0;
503 }
504
GetPathFreeSpace(nodecontext * UNUSED_PARAM (p),const tchar_t * Path)505 int64_t GetPathFreeSpace(nodecontext* UNUSED_PARAM(p), const tchar_t* Path)
506 {
507 #ifndef TODO
508 assert(NULL); // TODO: not supported yet
509 #endif
510 return -1;
511 }
512
513 #endif
514