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