PS2SDK
PS2 Homebrew Libraries
ps2sdkapi.c
Go to the documentation of this file.
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # (C)2001, Gustavo Scotti (gustavo@scotti.com)
7 # (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
8 # (c) 2023 Francisco Javier Trujillo Mata <fjtrujy@gmail.com>
9 # Licenced under Academic Free License version 2.0
10 # Review ps2sdk README & LICENSE files for further details.
11 */
12 
18 #include <ps2sdkapi.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #define NEWLIB_PORT_AWARE
24 #include <fileio.h>
25 #include "iox_stat.h"
26 
27 typedef struct _fio_file_info_
28 {
29  // cppcheck-suppress unusedStructMember
30  int fd;
31  // cppcheck-suppress unusedStructMember
32  char filename[];
34 
35 #ifdef F___fioOpsInitialize
36 _libcglue_fdman_path_ops_t __fio_fdman_path_ops;
37 _libcglue_fdman_fd_ops_t __fio_fdman_ops_file;
38 _libcglue_fdman_fd_ops_t __fio_fdman_ops_dir;
39 
40 extern void __fioOpsInitializeImpl(void);
41 
42 __attribute__((constructor))
43 static void __fioOpsInitialize(void)
44 {
45  __fioOpsInitializeImpl();
46 }
47 #else
48 extern _libcglue_fdman_path_ops_t __fio_fdman_path_ops;
49 extern _libcglue_fdman_fd_ops_t __fio_fdman_ops_file;
50 extern _libcglue_fdman_fd_ops_t __fio_fdman_ops_dir;
51 #endif
52 
53 #ifdef F___fioOpenHelper
54 #define IOP_O_RDONLY 0x0001
55 #define IOP_O_WRONLY 0x0002
56 #define IOP_O_RDWR 0x0003
57 #define IOP_O_DIROPEN 0x0008 // Internal use for dopen
58 #define IOP_O_NBLOCK 0x0010
59 #define IOP_O_APPEND 0x0100
60 #define IOP_O_CREAT 0x0200
61 #define IOP_O_TRUNC 0x0400
62 #define IOP_O_EXCL 0x0800
63 #define IOP_O_NOWAIT 0x8000
64 
65 int __fioOpenHelper(_libcglue_fdman_fd_info_t *info, const char *buf, int flags, mode_t mode)
66 {
67  int iop_flags = 0;
68  int is_dir = 0;
69  int iop_fd;
70 
71  // newlib flags differ from iop flags
72  if ((flags & 3) == O_RDONLY) iop_flags |= IOP_O_RDONLY;
73  if ((flags & 3) == O_WRONLY) iop_flags |= IOP_O_WRONLY;
74  if ((flags & 3) == O_RDWR ) iop_flags |= IOP_O_RDWR;
75  if (flags & O_NONBLOCK) iop_flags |= IOP_O_NBLOCK;
76  if (flags & O_APPEND) iop_flags |= IOP_O_APPEND;
77  if (flags & O_CREAT) iop_flags |= IOP_O_CREAT;
78  if (flags & O_TRUNC) iop_flags |= IOP_O_TRUNC;
79  if (flags & O_EXCL) iop_flags |= IOP_O_EXCL;
80  //if (flags & O_???) iop_flags |= IOP_O_NOWAIT;
81  if (flags & O_DIRECTORY) {
82  iop_flags |= IOP_O_DIROPEN;
83  is_dir = 1;
84  }
85 
86  iop_fd = is_dir ? fioDopen(buf) : fioOpen(buf, iop_flags);
87  if (iop_fd >= 0) {
88  _fio_file_info_t *userdata;
89  int buf_len;
90 
91  buf_len = strlen(buf);
92  userdata = malloc(sizeof(_fio_file_info_t) + buf_len + 1);
93  if (userdata == NULL)
94  {
95  return -ENOMEM;
96  }
97  userdata->fd = iop_fd;
98  memcpy(userdata->filename, buf, buf_len);
99  userdata->filename[buf_len] = '\x00';
100  info->userdata = (void *)userdata;
101  info->ops = is_dir ? &__fio_fdman_ops_dir : &__fio_fdman_ops_file;
102  return 0;
103  }
104  return iop_fd;
105 }
106 #else
107 int __fioOpenHelper(_libcglue_fdman_fd_info_t *info, const char *buf, int flags, mode_t mode);
108 #endif
109 
110 #ifdef F___fioGetFdHelper
111 int __fioGetFdHelper(void *userdata)
112 {
113  _fio_file_info_t *finfo;
114 
115  if (userdata == NULL)
116  {
117  return -EINVAL;
118  }
119 
120  finfo = (_fio_file_info_t *)userdata;
121  return finfo->fd;
122 }
123 #else
124 int __fioGetFdHelper(void *userdata);
125 #endif
126 
127 #ifdef F___fioGetFilenameHelper
128 char *__fioGetFilenameHelper(void *userdata)
129 {
130  _fio_file_info_t *finfo;
131 
132  if (userdata == NULL)
133  {
134  return NULL;
135  }
136 
137  finfo = (_fio_file_info_t *)userdata;
138  return finfo->filename;
139 }
140 #else
141 char *__fioGetFilenameHelper(void *userdata);
142 #endif
143 
144 #ifdef F___fioCloseHelper
145 int __fioCloseHelper(void *userdata)
146 {
147  int rv;
148  int fd;
149 
150  fd = __fioGetFdHelper(userdata);
151  if (fd < 0)
152  {
153  return fd;
154  }
155 
156  rv = fioClose(fd);
157  free(userdata);
158  return rv;
159 }
160 #else
161 int __fioCloseHelper(void *userdata);
162 #endif
163 
164 #ifdef F___fioDcloseHelper
165 int __fioDcloseHelper(void *userdata)
166 {
167  int rv;
168  int fd;
169 
170  fd = __fioGetFdHelper(userdata);
171  if (fd < 0)
172  {
173  return fd;
174  }
175 
176  rv = fioDclose(fd);
177  free(userdata);
178  return rv;
179 }
180 #else
181 int __fioDcloseHelper(void *userdata);
182 #endif
183 
184 #ifdef F___fioReadHelper
185 int __fioReadHelper(void *userdata, void *buf, int nbytes)
186 {
187  int rv;
188  int fd;
189 
190  fd = __fioGetFdHelper(userdata);
191  if (fd < 0)
192  {
193  return fd;
194  }
195 
196  rv = fioRead(fd, buf, nbytes);
197  return rv;
198 }
199 #else
200 int __fioReadHelper(void *userdata, void *buf, int nbytes);
201 #endif
202 
203 #ifdef F___fioLseekHelper
204 int __fioLseekHelper(void *userdata, int offset, int whence)
205 {
206  int rv;
207  int fd;
208 
209  fd = __fioGetFdHelper(userdata);
210  if (fd < 0)
211  {
212  return fd;
213  }
214 
215  rv = fioLseek(fd, offset, whence);
216  return rv;
217 }
218 #else
219 int __fioLseekHelper(void *userdata, int offset, int whence);
220 #endif
221 
222 #ifdef F___fioWriteHelper
223 int __fioWriteHelper(void *userdata, const void *buf, int nbytes)
224 {
225  int rv;
226  int fd;
227 
228  fd = __fioGetFdHelper(userdata);
229  if (fd < 0)
230  {
231  return fd;
232  }
233 
234  rv = fioWrite(fd, buf, nbytes);
235  return rv;
236 }
237 #else
238 int __fioWriteHelper(void *userdata, const void *buf, int nbytes);
239 #endif
240 
241 #ifdef F___fioIoctlHelper
242 int __fioIoctlHelper(void *userdata, int request, void *data)
243 {
244  int rv;
245  int fd;
246 
247  fd = __fioGetFdHelper(userdata);
248  if (fd < 0)
249  {
250  return fd;
251  }
252 
253  rv = fioIoctl(fd, request, data);
254  return rv;
255 }
256 #else
257 int __fioIoctlHelper(void *userdata, int request, void *data);
258 #endif
259 
260 #ifdef F___fioDreadHelper
261 int __fioDreadHelper(void *userdata, struct dirent *dir)
262 {
263  int rv;
264  int fd;
265  io_dirent_t iodir;
266 
267  // Took from io_dirent_t
268  #define __MAXNAMLEN 256
269 
270  fd = __fioGetFdHelper(userdata);
271  if (fd < 0)
272  {
273  return fd;
274  }
275 
276  rv = fioDread(fd, &iodir);
277  if (rv < 0) {
278  errno = ENOENT;
279  return -1;
280  }
281 
282  dir->d_fileno = rv; // TODO: This number should be in theory a unique number per file
283  snprintf(dir->d_name, sizeof(dir->d_name), "%.*s", (int)(sizeof(iodir.name) - 1), iodir.name);
284  dir->d_reclen = 0;
285  switch (iodir.stat.mode & FIO_SO_IFMT) {
286  case FIO_SO_IFLNK: dir->d_type = DT_LNK; break;
287  case FIO_SO_IFDIR: dir->d_type = DT_DIR; break;
288  case FIO_SO_IFREG: dir->d_type = DT_REG; break;
289  default: dir->d_type = DT_UNKNOWN; break;
290  }
291 
292 
293  return rv;
294 }
295 #else
296 int __fioDreadHelper(void *userdata, struct dirent *dir);
297 #endif
298 
299 #ifdef F___fioLseekDirHelper
300 int __fioLseekDirHelper(void *userdata, int offset, int whence)
301 {
302  int i;
303  int fd;
304  char *filename;
305  _fio_file_info_t *finfo;
306  int uid;
307  struct dirent dir;
308 
309  fd = __fioGetFdHelper(userdata);
310  if (fd < 0)
311  {
312  return fd;
313  }
314 
315  filename = __fioGetFilenameHelper(userdata);
316 
317  if (filename == NULL)
318  {
319  return -EINVAL;
320  }
321 
322  if (userdata == NULL)
323  {
324  return -EINVAL;
325  }
326 
327  finfo = (_fio_file_info_t *)userdata;
328 
329  if (whence != SEEK_SET)
330  {
331  return -EINVAL;
332  }
333 
334  fioDclose(fd);
335  uid = fioDopen(filename);
336  finfo->fd = uid;
337  for (i = 0; i < offset; i++) {
338  __fioDreadHelper(userdata, &dir);
339  }
340 
341  return offset;
342 }
343 #else
344 int __fioLseekDirHelper(void *userdata, int offset, int whence);
345 #endif
346 
347 #ifdef F___libcglue_init_stdio
348 int __libcglue_init_stdio(_libcglue_fdman_fd_info_t *info, int fd)
349 {
350  _fio_file_info_t *userdata;
351  int fnlen;
352  const char *tty0_str = "tty0:";
353 
354  fnlen = strlen(tty0_str) + 1;
355 
356  userdata = malloc(sizeof(_fio_file_info_t) + fnlen);
357  if (userdata == NULL)
358  {
359  return -ENOMEM;
360  }
361  userdata->fd = fd;
362  memcpy(userdata->filename, tty0_str, fnlen - 1);
363  userdata->filename[fnlen - 1] = '\x00';
364  info->userdata = (void *)userdata;
365  info->ops = &__fio_fdman_ops_file;
366  return 0;
367 }
368 #endif
369 
371 #ifdef F___fioMkdirHelper
372 int __fioMkdirHelper(const char *path, int mode)
373 {
374  // Old fio mkdir has no mode argument
375  (void)mode;
376 
377  return fioMkdir(path);
378 }
379 #else
380 int __fioMkdirHelper(const char *path, int mode);
381 #endif
382 
383 #ifdef F___fioGetstatHelper
384 static time_t io_to_posix_time(const unsigned char *ps2time)
385 {
386  struct tm tim;
387  tim.tm_sec = ps2time[1];
388  tim.tm_min = ps2time[2];
389  tim.tm_hour = ps2time[3];
390  tim.tm_mday = ps2time[4];
391  tim.tm_mon = ps2time[5] - 1;
392  tim.tm_year = ((u16)ps2time[6] | ((u16)ps2time[7] << 8)) - 1900;
393  return mktime(&tim);
394 }
395 
396 static mode_t io_to_posix_mode(unsigned int ps2mode)
397 {
398  mode_t posixmode = 0;
399  if (ps2mode & FIO_SO_IFREG) posixmode |= S_IFREG;
400  if (ps2mode & FIO_SO_IFDIR) posixmode |= S_IFDIR;
401  if (ps2mode & FIO_SO_IROTH) posixmode |= S_IRUSR|S_IRGRP|S_IROTH;
402  if (ps2mode & FIO_SO_IWOTH) posixmode |= S_IWUSR|S_IWGRP|S_IWOTH;
403  if (ps2mode & FIO_SO_IXOTH) posixmode |= S_IXUSR|S_IXGRP|S_IXOTH;
404  return posixmode;
405 }
406 
407 static void __fill_stat(struct stat *stat, const io_stat_t *fiostat)
408 {
409  stat->st_dev = 0;
410  stat->st_ino = 0;
411  stat->st_mode = io_to_posix_mode(fiostat->mode);
412  stat->st_nlink = 0;
413  stat->st_uid = 0;
414  stat->st_gid = 0;
415  stat->st_rdev = 0;
416  stat->st_size = ((off_t)fiostat->hisize << 32) | (off_t)fiostat->size;
417  stat->st_atime = io_to_posix_time(fiostat->atime);
418  stat->st_mtime = io_to_posix_time(fiostat->mtime);
419  stat->st_ctime = io_to_posix_time(fiostat->ctime);
420  stat->st_blksize = 16*1024;
421  stat->st_blocks = stat->st_size / 512;
422 }
423 
424 int __fioGetstatHelper(const char *path, struct stat *buf)
425 {
426  io_stat_t fiostat;
427 
428  if (strncmp(path, "tty", 3) == 0 && path[3] >= '0' && path[3] <= '9' && path[4] == ':')
429  {
430  memset(buf, 0, sizeof(struct stat));
431  buf->st_mode = S_IFCHR;
432  return 0;
433  }
434 
435  if (fioGetstat(path, &fiostat) < 0) {
436  errno = ENOENT;
437  return -1;
438  }
439 
440  __fill_stat(buf, &fiostat);
441 
442  return 0;
443 }
444 #else
445 int __fioGetstatHelper(const char *path, struct stat *buf);
446 #endif
447 
448 #ifdef F___fioOpsInitializeImpl
449 int __attribute__((weak)) _open(const char *buf, int flags, ...);
450 int __attribute__((weak)) _unlink(const char *path);
451 int __attribute__((weak)) mkdir(const char *path, mode_t mode);
452 int __attribute__((weak)) rmdir(const char *path);
453 int __attribute__((weak)) _stat(const char *path, struct stat *buf);
454 int __attribute__((weak)) _fstat(int fd, struct stat *buf);
455 int __attribute__((weak)) _close(int fd);
456 int __attribute__((weak)) _read(int fd, void *buf, size_t nbytes);
457 off_t __attribute__((weak)) _lseek(int fd, off_t offset, int whence);
458 int __attribute__((weak)) _write(int fd, const void *buf, size_t nbytes);
459 int __attribute__((weak)) _ioctl(int fd, int request, void *data);
460 int __attribute__((weak)) _ps2sdk_ioctl(int fd, int request, void *data);
461 int __attribute__((weak)) getdents(int fd, void *dd_buf, int count);
462 
463 void __fioOpsInitializeImpl(void)
464 {
465  memset(&__fio_fdman_path_ops, 0, sizeof(__fio_fdman_path_ops));
466  // cppcheck-suppress knownConditionTrueFalse
467  if (&_open) __fio_fdman_path_ops.open = __fioOpenHelper;
468  // cppcheck-suppress knownConditionTrueFalse
469  if (&_unlink) __fio_fdman_path_ops.remove = fioRemove;
470  // cppcheck-suppress knownConditionTrueFalse
471  if (&mkdir) __fio_fdman_path_ops.mkdir = __fioMkdirHelper;
472  // cppcheck-suppress knownConditionTrueFalse
473  if (&rmdir) __fio_fdman_path_ops.rmdir = fioRmdir;
474  // cppcheck-suppress knownConditionTrueFalse
475  if ((&_stat) || (&_fstat)) __fio_fdman_path_ops.stat = __fioGetstatHelper;
476 
477  memset(&__fio_fdman_ops_file, 0, sizeof(__fio_fdman_ops_file));
478  __fio_fdman_ops_file.getfd = __fioGetFdHelper;
479  __fio_fdman_ops_file.getfilename = __fioGetFilenameHelper;
480  // cppcheck-suppress knownConditionTrueFalse
481  if (&_close) __fio_fdman_ops_file.close = __fioCloseHelper;
482  // cppcheck-suppress knownConditionTrueFalse
483  if (&_read) __fio_fdman_ops_file.read = __fioReadHelper;
484  // cppcheck-suppress knownConditionTrueFalse
485  if (&_lseek) __fio_fdman_ops_file.lseek = __fioLseekHelper;
486  // cppcheck-suppress knownConditionTrueFalse
487  if (&_write) __fio_fdman_ops_file.write = __fioWriteHelper;
488  // cppcheck-suppress knownConditionTrueFalse
489  if ((&_ioctl) || (&_ps2sdk_ioctl)) __fio_fdman_ops_file.ioctl = __fioIoctlHelper;
490 
491  memset(&__fio_fdman_ops_dir, 0, sizeof(__fio_fdman_ops_dir));
492  __fio_fdman_ops_dir.getfd = __fioGetFdHelper;
493  __fio_fdman_ops_dir.getfilename = __fioGetFilenameHelper;
494  // cppcheck-suppress knownConditionTrueFalse
495  if (&_close) __fio_fdman_ops_dir.close = __fioDcloseHelper;
496  // cppcheck-suppress knownConditionTrueFalse
497  if (&_lseek) __fio_fdman_ops_dir.lseek = __fioLseekDirHelper;
498  // cppcheck-suppress knownConditionTrueFalse
499  if (&getdents) __fio_fdman_ops_dir.dread = __fioDreadHelper;
500 }
501 #endif
502 
503 extern _libcglue_fdman_path_ops_t * _ps2sdk_get_default_fdman_path_ops(void);
504 #ifdef F__ps2sdk_get_default_fdman_path_ops
505 _libcglue_fdman_path_ops_t * __attribute__((weak)) _ps2sdk_get_default_fdman_path_ops(void)
506 {
507  return &__fio_fdman_path_ops;
508 }
509 #endif
510 
511 #ifdef F__libcglue_fdman_path_ops
512 _libcglue_fdman_path_ops_t *_libcglue_fdman_path_ops = NULL;
513 
514 __attribute__((constructor))
515 static void __libcglue_fdman_path_ops_initialize(void)
516 {
517  _libcglue_fdman_path_ops = _ps2sdk_get_default_fdman_path_ops();
518 }
519 #endif
520 
521 #ifdef F__libcglue_fdman_socket_ops
522 _libcglue_fdman_socket_ops_t *_libcglue_fdman_socket_ops = NULL;
523 #endif
524 
525 #ifdef F__libcglue_fdman_inet_ops
526 _libcglue_fdman_inet_ops_t *_libcglue_fdman_inet_ops = NULL;
527 #endif
FIO_SO_IFREG
#define FIO_SO_IFREG
Definition: iox_stat.h:126
FIO_SO_IXOTH
#define FIO_SO_IXOTH
Definition: iox_stat.h:135
request
Definition: thread.c:17
ENOMEM
#define ENOMEM
Definition: errno.h:43
s_info
Definition: xprintf.c:78
_fio_file_info_
Definition: ps2sdkapi.c:27
ENOENT
#define ENOENT
Definition: errno.h:23
fileio.h
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
__attribute__
typedef __attribute__
Definition: tlbfunc.c:60
FIO_SO_IFMT
#define FIO_SO_IFMT
Definition: iox_stat.h:122
_libcglue_fdman_socket_ops_
Definition: ps2sdkapi.h:123
_libcglue_fdman_path_ops_
Definition: ps2sdkapi.h:97
stdio.h
io_stat_t
Definition: io_common.h:47
FIO_SO_IFDIR
#define FIO_SO_IFDIR
Definition: iox_stat.h:128
FIO_SO_IFLNK
#define FIO_SO_IFLNK
Definition: iox_stat.h:124
_libcglue_fdman_inet_ops_
Definition: ps2sdkapi.h:145
io_dirent_t
Definition: io_common.h:58
__fioMkdirHelper
int __fioMkdirHelper(const char *path, int mode)
_libcglue_fdman_fd_ops_
Definition: ps2sdkapi.h:52
EINVAL
#define EINVAL
Definition: errno.h:63
FIO_SO_IWOTH
#define FIO_SO_IWOTH
Definition: iox_stat.h:133
stdlib.h
_libcglue_fdman_fd_info_
Definition: ps2sdkapi.h:82
iox_stat.h
errno.h
FIO_SO_IROTH
#define FIO_SO_IROTH
Definition: iox_stat.h:131