PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
pfs_fio.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9#
10# PFS I/O manager related routines
11*/
12
13#include <stdio.h>
14#ifdef _IOP
15#include <sysclib.h>
16#else
17#include <string.h>
18#endif
19#include <errno.h>
20#include <iomanX.h>
21#include <thsemap.h>
22#include <hdd-ioctl.h>
23
24#include "libpfs.h"
25#include "pfs.h"
26#include "pfs_fio.h"
27#include "pfs_fioctl.h"
28
30// Globals
31
32static const u8 openFlagArray[] = { 0, 4, 2, 6, 0, 0, 0, 0 };
33int pfsFioSema = 0;
34pfs_file_slot_t *pfsFileSlots;
35
36extern pfs_config_t pfsConfig;
37extern pfs_cache_t *pfsCacheBuf;
38extern u32 pfsCacheNumBuffers;
39extern pfs_mount_t *pfsMountBuf;
40
41#ifdef PFS_STAT_RETURN_INODE_LBA
42extern u32 pfsBlockSize;
43#endif
44
46// Function declarations
47
48static int openFile(pfs_mount_t *pfsMount, pfs_file_slot_t *freeSlot, const char *filename, int openFlags, int mode);
49static int fileTransferRemainder(pfs_file_slot_t *fileSlot, void *buf, int size, int operation);
50static int fileTransfer(pfs_file_slot_t *fileSlot, u8 *buf, int size, int operation);
51static void fioStatFiller(pfs_cache_t *clink, iox_stat_t *stat);
52static s64 _seek(pfs_file_slot_t *fileSlot, s64 offset, int whence, int mode);
53static int _remove(pfs_mount_t *pfsMount, const char *path, int mode);
54static int mountDevice(pfs_block_device_t *blockDev, int fd, int unit, int flag);
55static void _sync(void);
56
58// Function definitions
59
60int pfsFioCheckForLastError(pfs_mount_t *pfsMount, int rv)
61{
62 return pfsMount->lastError ? pfsMount->lastError : (u32)rv;
63}
64
65int pfsFioCheckFileSlot(pfs_file_slot_t *fileSlot)
66{
67 WaitSema(pfsFioSema);
68
69 if(fileSlot->clink==NULL)
70 {
71 SignalSema(pfsFioSema);
72 return -EBADF;
73 }
74
75 return 0;
76}
77
78void pfsFioCloseFileSlot(pfs_file_slot_t *fileSlot)
79{
80 pfs_mount_t *pfsMount=fileSlot->clink->pfsMount;
81
82 if(fileSlot->fd->mode & FIO_O_WRONLY)
83 {
84 if(fileSlot->unaligned.dirty!=0)
85 {
86 pfsMount->blockDev->transfer(pfsMount->fd, fileSlot->unaligned.buffer,
87 fileSlot->unaligned.sub, fileSlot->unaligned.sector, 1, PFS_IO_MODE_WRITE);
88 }
89 pfsInodeSetTime(fileSlot->clink); // set time :P
90 fileSlot->clink->u.inode->attr|=PFS_FIO_ATTR_CLOSED;
91 if(pfsMount->flags & PFS_FIO_ATTR_WRITEABLE)
92 pfsCacheFlushAllDirty(pfsMount);
93 }
94 pfsCacheFree(fileSlot->block_pos.inode);
95 pfsCacheFree(fileSlot->clink);
96 memset(fileSlot, 0, sizeof(pfs_file_slot_t));
97}
98
99pfs_mount_t *pfsFioGetMountedUnit(int unit)
100{
101 pfs_mount_t *pfsMount;
102
103 WaitSema(pfsFioSema);
104 if((pfsMount=pfsGetMountedUnit(unit))==NULL)
105 SignalSema(pfsFioSema);
106 return pfsMount;
107}
108
109static int mountDevice(pfs_block_device_t *blockDev, int fd, int unit, int flag)
110{
111 s32 i;
112 int rv;
113
114 if((u32)unit >= pfsConfig.maxMount)
115 return -EMFILE;
116
117 if(pfsMountBuf[unit].flags & PFS_MOUNT_BUSY)
118 return -EBUSY;
119
120 for(i = 0; (u32)i < pfsConfig.maxMount; i++)
121 if((pfsMountBuf[i].flags & PFS_MOUNT_BUSY) &&
122 (blockDev == pfsMountBuf[i].blockDev) &&
123 (fd == pfsMountBuf[i].fd)) // Cant mount the same partition more than once
124 return -EBUSY;
125
126 pfsMountBuf[unit].blockDev = blockDev;
127 pfsMountBuf[unit].fd = fd;
128 pfsMountBuf[unit].flags = flag;
129
130 rv = pfsMountSuperBlock(&pfsMountBuf[unit]);
131 if(rv < 0)
132 return rv;
133
134 pfsMountBuf[unit].flags |= PFS_MOUNT_BUSY;
135
136 return 0;
137}
138
139static int openFile(pfs_mount_t *pfsMount, pfs_file_slot_t *freeSlot, const char *filename, int openFlags, int mode)
140{
141 char file[256];
142 int result, result2, result3, result4;
143 pfs_cache_t *parentInode, *fileInode, *cached;
144
145
146 result = 0; //no error
147#ifdef PFS_SUPPORT_BHDD
148 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
149 if (openFlags & FIO_O_CREAT)
150 return -EACCES;
151#endif
152 // Get the inode for the directory which contains the file (dir) in filename
153 // After this call, 'file' will contain the name of the file we're operating on.
154 if ((parentInode=pfsInodeGetParent(pfsMount, NULL, filename, file, &result))==0)
155 {
156 return result;
157 }
158
159 // Get the inode for the actual file/directory contained in the parent dir
160 fileInode=pfsInodeGetFileInDir(parentInode, file, &result);
161
162 // If file already exists..
163 if (fileInode)
164 {
165 u32 flags;
166 u32 count;
167
168 // Setup flags
169 flags=openFlagArray[openFlags & FIO_O_RDWR];
170 if (openFlags & FIO_O_TRUNC) flags |= 2;
171 if (openFlags & PFS_FDIRO) flags |= 4;
172 if ((mode & 0x10000) ||
173 ((openFlags & (FIO_O_CREAT|FIO_O_EXCL)) == (FIO_O_CREAT|FIO_O_EXCL))){
174 result=-EEXIST;
175 }
176 else
177 {
178 count = 0;
179
180 // Resolve actual file from a symlink
181 while ((fileInode->u.inode->mode & FIO_S_IFMT) == FIO_S_IFLNK)
182 {
183 if (count++>=4)
184 {
185 result=-ELOOP;
186 goto label;
187 }
188
189 parentInode=pfsInodeGetParent(pfsMount, parentInode, (char*)&fileInode->u.inode->data[1],
190 file, &result);
191 pfsCacheFree(fileInode);
192 if ((parentInode==0) ||
193 ((fileInode=pfsInodeGetFileInDir(parentInode, file, &result))==0))
194 goto label;
195 }
196
197 // Make sure that if a file is being opened, then inode does not point
198 // to a directory, and vice versa.
199 if ((openFlags & PFS_FDIRO) == 0)
200 {
201 if ((fileInode->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR)
202 result=-EISDIR;
203 }else{
204 if ((fileInode->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
205 result=-ENOTDIR;
206 }
207
208 // Truncate file if required
209 if ((result==0) &&
210 ((result=pfsCheckAccess(fileInode, flags & 0xFFFF))==0) &&
211 (openFlags & FIO_O_TRUNC))
212 {
213 cached=pfsCacheGetData(fileInode->pfsMount, fileInode->sub, fileInode->block+1, PFS_CACHE_FLAG_NOLOAD | PFS_CACHE_FLAG_NOTHING, &result2);
214 if (cached)
215 {
216 memset(cached->u.aentry, 0, sizeof(pfs_inode_t)); //1024
217 cached->u.aentry->aLen=sizeof(pfs_inode_t);
218 cached->flags |= PFS_CACHE_FLAG_DIRTY;
219 pfsCacheFree(cached);
220 }
221 if (result2 == 0)
222 {
223 fileInode->u.inode->size = 0;
224 fileInode->u.inode->attr &= ~PFS_FIO_ATTR_CLOSED; //~0x80==0xFF7F
225 fileInode->flags |= PFS_CACHE_FLAG_DIRTY;
226 pfsFreeZones(fileInode);
227 }
228 }
229 }
230
231 // Otherwise, if file doesnt already exist..
232 }else{
233 if ((openFlags & FIO_O_CREAT) && (result==-ENOENT) &&
234 ((result=pfsCheckAccess(parentInode, 2))==0) &&
235 (fileInode=pfsInodeCreate(parentInode, mode, PFS_UID,
236 PFS_GID, &result)))
237 {
238 if ((mode & FIO_S_IFMT) == FIO_S_IFLNK)
239 {
240 strcpy((char*)&fileInode->u.inode->data[1], (char*)freeSlot);
241 freeSlot=NULL;
242 }
243
244 // If new file is a directory, the fill self and parent entries
245 if ((mode & FIO_S_IFMT) == FIO_S_IFDIR)
246 {
247 cached=pfsCacheGetData(fileInode->pfsMount, fileInode->u.inode->data[1].subpart,
248 fileInode->u.inode->data[1].number << fileInode->pfsMount->inode_scale,
249 PFS_CACHE_FLAG_NOLOAD | PFS_CACHE_FLAG_NOTHING, &result3);
250 if (cached)
251 {
252 pfsFillSelfAndParentDentries(cached,
253 &fileInode->u.inode->inode_block,
254 &parentInode->u.inode->inode_block);
255 cached->flags |= PFS_CACHE_FLAG_DIRTY;
256 pfsCacheFree(cached);
257 }
258 result=result3;
259 // Otherwise if its just a regular file, just zero its attribute entry
260 }else{
261 cached=pfsCacheGetData(fileInode->pfsMount, fileInode->sub, fileInode->block+1,
262 PFS_CACHE_FLAG_NOLOAD | PFS_CACHE_FLAG_NOTHING, &result4);
263 if (cached)
264 {
265 memset(cached->u.aentry, 0, sizeof(pfs_inode_t));
266 cached->u.aentry->aLen=sizeof(pfs_inode_t);
267 cached->flags |= PFS_CACHE_FLAG_DIRTY;
268 pfsCacheFree(cached);
269 }
270 result=result4;
271 }
272
273 // Link new file with parent directory
274 if ((result==0) && (cached=pfsDirAddEntry(parentInode, file, &fileInode->u.inode->inode_block,
275 mode, &result)))
276 {
277 pfsInodeSetTimeParent(parentInode, cached);
278 pfsCacheFree(cached);
279 }
280 }
281 }
282label:
283 pfsCacheFree(parentInode);
284 if ((result==0) && freeSlot && fileInode)
285 {
286 freeSlot->clink=fileInode;
287 if (openFlags & FIO_O_APPEND)
288 freeSlot->position = fileInode->u.inode->size;
289 else
290 freeSlot->position = 0;
291
292 result=pfsBlockInitPos(freeSlot->clink, &freeSlot->block_pos, freeSlot->position);
293 if (result==0)
294 {
295 if ((openFlags & FIO_O_WRONLY) &&
296 (fileInode->u.inode->attr & PFS_FIO_ATTR_CLOSED)){
297 fileInode->u.inode->attr &= ~PFS_FIO_ATTR_CLOSED;
298 fileInode->flags |= PFS_CACHE_FLAG_DIRTY;
299 if (pfsMount->flags & PFS_FIO_ATTR_WRITEABLE)
300 pfsCacheFlushAllDirty(pfsMount);
301 }
302 if ((result=pfsFioCheckForLastError(pfsMount, result))==0)
303 return 0;
304 }
305 freeSlot->clink=NULL;
306 }
307
308 if(fileInode) pfsCacheFree(fileInode);
309
310 return pfsFioCheckForLastError(pfsMount, result);
311}
312
313static int fileTransferRemainder(pfs_file_slot_t *fileSlot, void *buf, int size, int operation)
314{
315 u32 sector, pos;
316 s32 i;
317 int result;
318 pfs_blockpos_t *blockpos = &fileSlot->block_pos;
319 pfs_mount_t *pfsMount = fileSlot->clink->pfsMount;
320 pfs_unaligned_io_t *unaligned = &fileSlot->unaligned;
321 pfs_unaligned_io_t *unaligned2 = NULL;
322 pfs_blockinfo_t *bi = pfsBlockGetCurrent(blockpos);
323
324 sector = ((bi->number+blockpos->block_offset) << pfsMount->sector_scale) +
325 (blockpos->byte_offset >> 9);
326 pos = blockpos->byte_offset & 0x1FF;
327
328 if(operation == 0)
329 { //If READ, copy latest data from the buffer of any FD that was opened for writing.
330 for(i = 0; (u32)i < pfsConfig.maxOpen; i++)
331 {
332 if((pfsFileSlots[i].clink != NULL)
333 && (pfsFileSlots[i].clink->pfsMount == pfsMount)
334 && (pfsFileSlots[i].unaligned.dirty)
335 && (pfsFileSlots[i].unaligned.sub == bi->subpart)
336 && (pfsFileSlots[i].unaligned.sector == sector))
337 {
338 unaligned2 = &pfsFileSlots[i].unaligned;
339 if(unaligned != unaligned2)
340 memcpy(unaligned->buffer, unaligned2->buffer, sizeof(unaligned->buffer));
341 else
342 unaligned2 = NULL; //Nothing to update.
343 break;
344 }
345 }
346 }
347
348 if(unaligned2 == NULL)
349 { //If the latest version is likely in disk.
350 if((unaligned->sector != sector) || (unaligned->sub!=bi->subpart))
351 {
352 if (unaligned->dirty)
353 {
354 result=pfsMount->blockDev->transfer(pfsMount->fd, unaligned->buffer, unaligned->sub, unaligned->sector, 1, PFS_IO_MODE_WRITE);
355 if(result)
356 return result;
357 unaligned->dirty=0;
358 }
359
360 unaligned->sub=bi->subpart;
361 unaligned->sector=sector;
362
363 if(pos || (fileSlot->position != fileSlot->clink->u.inode->size))
364 {
365 result = pfsMount->blockDev->transfer(pfsMount->fd, unaligned->buffer, unaligned->sub, unaligned->sector, 1, PFS_IO_MODE_READ);
366 if(result)
367 return result | 0x10000;
368 }
369 }
370 }
371
372 if (operation==0)
373 memcpy(buf, &unaligned->buffer[pos], size=min(size, (int)sizeof(unaligned->buffer)-(int)pos));
374 else
375 memcpy(&unaligned->buffer[pos], buf, size=min(size, (int)sizeof(unaligned->buffer)-(int)pos));
376
377 if (operation == 1)
378 {
379 if (pfsMount->flags & PFS_FIO_ATTR_WRITEABLE)
380 {
381 if ((result=pfsMount->blockDev->transfer(pfsMount->fd, unaligned->buffer, unaligned->sub,
382 unaligned->sector, operation, operation)))
383 return result;
384
385 //In late modules, sync data with all other FDs that were opened for reading.
386 for(i = 0; (u32)i < pfsConfig.maxOpen; i++)
387 {
388 if((pfsFileSlots[i].clink != NULL)
389 && (pfsFileSlots[i].clink->pfsMount == pfsMount)
390 && (pfsFileSlots[i].unaligned.sub == fileSlot->unaligned.sub)
391 && (pfsFileSlots[i].unaligned.sector == fileSlot->unaligned.sector))
392 {
393 if(!pfsFileSlots[i].unaligned.dirty)
394 memcpy(pfsFileSlots[i].unaligned.buffer, unaligned->buffer, sizeof(pfsFileSlots[i].unaligned.buffer));
395 }
396 }
397 }
398 else
399 unaligned->dirty=operation;
400 }
401 return size;
402}
403
404// Does actual read/write of data from file
405static int fileTransfer(pfs_file_slot_t *fileSlot, u8 *buf, int size, int operation)
406{
407 int result=0;
408 pfs_blockpos_t *blockpos=&fileSlot->block_pos;
409 pfs_mount_t *pfsMount=fileSlot->clink->pfsMount;
410 u64 bytes_remain;
411 int total = size;
412
413 // If we're writing and there is less free space in the last allocated block segment
414 // than can hold the data being written, then try and expand the block segment
415 if ((operation==1) &&
416 (fileSlot->clink->u.inode->number_data - 1 == blockpos->block_segment))
417 {
418 bytes_remain = (pfsBlockGetCurrent(blockpos)->count - blockpos->block_offset) * pfsMount->zsize - blockpos->byte_offset;
419
420 if (bytes_remain < (u32)size)
421 {
422 pfsBlockExpandSegment(fileSlot->clink, blockpos,
423 ((size-bytes_remain+pfsMount->zsize-1) & (~(pfsMount->zsize-1))) / pfsMount->zsize);
424 }
425 }
426
427 while (size)
428 {
429 pfs_blockinfo_t *bi;
430 u32 sectors;
431
432 // Get block info for current file position
433 bi=pfsBlockGetCurrent(blockpos);
434
435 // Get amount of remaining data in current block
436 bytes_remain=(bi->count - blockpos->block_offset) * pfsMount->zsize - blockpos->byte_offset;
437
438 // If there is no space/data left in the current block segment, then we need to move onto the next
439 if (bytes_remain==0)
440 {
441 // If we're at the end of allocated block segments, then allocate a new block segment
442 if (blockpos->block_segment == fileSlot->clink->u.inode->number_data-1){
443 if (operation==0){
444 PFS_PRINTF(PFS_DRV_NAME" Panic: This is a bug!\n");
445 return 0;
446 }
447
448 result = pfsBlockAllocNewSegment(fileSlot->clink, blockpos,
449 (size - 1 + pfsMount->zsize) / pfsMount->zsize);
450 if(result<0)
451 break;
452
453 // Otherwise, move to the next block segment
454 }else
455 if ((result=pfsBlockSeekNextSegment(fileSlot->clink, blockpos)))
456 {
457 return result;
458 }
459
460 bi=pfsBlockGetCurrent(blockpos);
461 bytes_remain=(bi->count - blockpos->block_offset) * pfsMount->zsize - blockpos->byte_offset;
462 }
463
464 if (bytes_remain==0)
465 {
466 PFS_PRINTF(PFS_DRV_NAME" Panic: There is no zone.\n");
467 return 0;
468 }
469
470 if(fileSlot->unaligned.dirty)
471 { //If there is going to be a partial transfer, write the dirty data to disk first.
472 u32 sector = ((bi->number + fileSlot->block_pos.block_offset) << pfsMount->sector_scale) + (fileSlot->block_pos.byte_offset / 512);
473 if((fileSlot->unaligned.sector == sector) &&
474 (fileSlot->unaligned.sub == bi->subpart)
475 && (size < 512))
476 {
477 if((result = pfsMount->blockDev->transfer(pfsMount->fd, fileSlot->unaligned.buffer, fileSlot->unaligned.sub, fileSlot->unaligned.sector, 1, PFS_IO_MODE_WRITE)) != 0)
478 return result;
479
480 fileSlot->unaligned.dirty = 0;
481 }
482 }
483
484 // If we are transferring size not a multiple of 512, under 512, or to
485 // an unaligned buffer we need to use a special function rather than
486 // just doing a ATA sector transfer.
487 if ((blockpos->byte_offset & 0x1FF) || (size < 512) || ((uiptr)buf & 3))
488 {
489 if ((result=fileTransferRemainder(fileSlot, buf, size, operation)) < 0)
490 break;
491 }
492 else
493 {
494 sectors = (u32)(bytes_remain / 512);
495 if ((u32)(size / 512) < sectors) sectors = size / 512; //sectors=min(size/512, sectors)
496
497 // Do the ATA sector transfer
498 result=pfsMount->blockDev->transfer(pfsMount->fd, buf, bi->subpart,
499 ((bi->number + blockpos->block_offset) << pfsMount->sector_scale)+(blockpos->byte_offset / 512),
500 sectors, operation);
501 if (result < 0)
502 {
503 result |= 0x10000; // TODO: EIO define
504 break;
505 }
506 result = sectors * 512;
507 }
508
509 size -= result;
510 fileSlot->position += result;
511 buf += result;
512
513 // If file has grown, need to mark inode as dirty
514 if(fileSlot->clink->u.inode->size < fileSlot->position)
515 {
516 fileSlot->clink->u.inode->size = fileSlot->position;
517 fileSlot->clink->flags |= PFS_CACHE_FLAG_DIRTY;
518 }
519
520 blockpos->block_offset+=pfsBlockSyncPos(blockpos, result);
521 }
522 return result < 0 ? result : total;
523}
524
525int pfsFioInit(iomanX_iop_device_t *f)
526{
527 iop_sema_t sema;
528
529 (void)f;
530
531 sema.attr = 1;
532 sema.option = 0;
533 sema.initial = 1;
534 sema.max = 1;
535
536 pfsFioSema = CreateSema(&sema);
537
538 return 0;
539}
540
541int pfsFioDeinit(iomanX_iop_device_t *f)
542{
543 (void)f;
544
545 pfsFioDevctlCloseAll();
546
547 DeleteSema(pfsFioSema);
548
549 return 0;
550}
551
552int pfsFioFormat(iomanX_iop_file_t *f, const char *dev, const char *blockdev, void *args, int arglen)
553{
554 int *arg = (int *)args;
555 int fragment = 0;
556 int fd;
557 pfs_block_device_t *blockDev;
558 int rv;
559
560 (void)f;
561 (void)dev;
562
563 // Has a fragment bit pattern been specified ?
564 if((arglen == (3 * sizeof(int))) && (arg[1] == 0x2D66)) //arg[1] == "-f"
565 fragment = arg[2];
566
567 if((blockDev = pfsGetBlockDeviceTable(blockdev)) == 0)
568 return -ENXIO;
569
570#ifdef PFS_SUPPORT_BHDD
571 if (strcmp(blockDev->devName, "bhdd") == 0)
572 return -EACCES;
573#endif
574
575 WaitSema(pfsFioSema);
576
577 fd = iomanX_open(blockdev, FIO_O_RDWR);
578
579 if(fd < 0)
580 rv = fd;
581 else {
582 rv = pfsFormat(blockDev, fd, arg[0], fragment);
583 iomanX_close(fd);
584 }
585
586 SignalSema(pfsFioSema);
587
588 return rv;
589}
590
591int pfsFioOpen(iomanX_iop_file_t *f, const char *name, int flags, int mode)
592{
593 int rv = 0;
594 s32 i;
595 pfs_file_slot_t *freeSlot;
596 pfs_mount_t *pfsMount;
597
598 (void)flags;
599
600 if(!name)
601 return -ENOENT;
602
603 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
604 {
605 return -ENODEV;
606 }
607
608 // Find free file slot
609 for(i = 0; (u32)i < pfsConfig.maxOpen; i++)
610 {
611 if(!pfsFileSlots[i].fd) {
612 freeSlot = &pfsFileSlots[i];
613 goto pfsOpen_slotFound;
614 }
615 }
616
617 PFS_PRINTF(PFS_DRV_NAME" Error: There are no free file slots!\n");
618 freeSlot = NULL;
619
620pfsOpen_slotFound:
621
622 if(!freeSlot) {
623 rv = -EMFILE;
624 goto pfsOpen_end;
625 }
626
627 // Do actual open
628 if((rv = openFile(pfsMount, freeSlot, name, f->mode, (mode & 0xfff) | FIO_S_IFREG)))
629 goto pfsOpen_end;
630
631 freeSlot->fd = f;
632 f->privdata = freeSlot;
633
634pfsOpen_end:
635
636 SignalSema(pfsFioSema);
637
638 return rv;
639}
640
641int pfsFioClose(iomanX_iop_file_t *f)
642{
643 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
644 int rv;
645
646 rv = pfsFioCheckFileSlot(fileSlot);
647 if(rv)
648 return rv;
649
650 pfsFioCloseFileSlot(fileSlot);
651
652 SignalSema(pfsFioSema);
653
654 return 0;
655}
656
657int pfsFioRead(iomanX_iop_file_t *f, void *buf, int size)
658{
660 int result = pfsFioCheckFileSlot(fileSlot);
661
662 if (result)
663 {
664 return result;
665 }
666
667 // Check bounds, adjust size if necessary
668 if(fileSlot->clink->u.inode->size < (fileSlot->position + size))
669 size = (int)(fileSlot->clink->u.inode->size - fileSlot->position);
670
671 result = size ? fileTransfer(fileSlot, buf, size, 0) : 0;
672 result = pfsFioCheckForLastError(fileSlot->clink->pfsMount, result);
673
674 SignalSema(pfsFioSema);
675 return result;
676}
677
678int pfsFioWrite(iomanX_iop_file_t *f, void *buf, int size)
679{
680 pfs_mount_t *pfsMount;
682 int result = pfsFioCheckFileSlot(fileSlot);
683
684 if(result)
685 return result;
686
687 pfsMount = fileSlot->clink->pfsMount;
688
689 if(fileSlot->position + (unsigned int)size < fileSlot->position)
690 result = -EINVAL;
691 else
692 {
693#ifdef PFS_SUPPORT_BHDD
694 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
695 return -EBADF;
696 else
697#endif
698 {
699 result = fileTransfer(fileSlot, buf, size, 1);
700 }
701 }
702
703 if (pfsMount->flags & PFS_FIO_ATTR_WRITEABLE)
704 pfsCacheFlushAllDirty(pfsMount);
705
706 result = pfsFioCheckForLastError(pfsMount, result);
707 SignalSema(pfsFioSema);
708 return result;
709}
710
711static s64 _seek(pfs_file_slot_t *fileSlot, s64 offset, int whence, int mode)
712{
713 int rv;
714 s64 startPos, newPos;
715
716 if (mode & FIO_O_DIROPEN)
717 {
718 return -EISDIR;
719 }
720
721 switch (whence)
722 {
723 case FIO_SEEK_SET:
724 startPos = 0;
725 break;
726 case FIO_SEEK_CUR:
727 startPos= fileSlot->position;
728 break;
729 case FIO_SEEK_END:
730 startPos = fileSlot->clink->u.inode->size;
731 break;
732 default:
733 return -EINVAL;
734 }
735 newPos = startPos + offset;
736
737 if (((offset < 0) && (startPos < newPos)) ||
738 ((offset > 0) && (startPos > newPos)) ||
739 (fileSlot->clink->u.inode->size < (u64)newPos))
740 {
741 return -EINVAL;
742 }
743
744 pfsCacheFree(fileSlot->block_pos.inode);
745 rv=pfsBlockInitPos(fileSlot->clink, &fileSlot->block_pos, newPos);
746 if (rv==0)
747 fileSlot->position = newPos;
748 else {
749 fileSlot->position = 0;
750 pfsBlockInitPos(fileSlot->clink, &fileSlot->block_pos, 0);
751 }
752
753 if (rv)
754 {
755 return rv;
756 }
757
758 return newPos;
759}
760
761int pfsFioLseek(iomanX_iop_file_t *f, int pos, int whence)
762{
764 int result = pfsFioCheckFileSlot(fileSlot);
765
766 if (result)
767 return result;
768
769 result = (u32)_seek(fileSlot, (s64)pos, whence, f->mode);
770
771 SignalSema(pfsFioSema);
772 return result;
773}
774
775s64 pfsFioLseek64(iomanX_iop_file_t *f, s64 offset, int whence)
776{
777 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
778 u64 rv;
779
780 rv=pfsFioCheckFileSlot(fileSlot);
781 if(!rv)
782 {
783 rv=_seek(fileSlot, offset, whence, f->mode);
784 SignalSema(pfsFioSema);
785 }
786 return rv;
787}
788
789static int _remove(pfs_mount_t *pfsMount, const char *path, int mode)
790{
791 char szPath[256];
792 int rv=0;
793 pfs_cache_t *parent;
794 pfs_cache_t *file;
795
796#ifdef PFS_SUPPORT_BHDD
797 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
798 return -EACCES;
799#endif
800
801 if((parent=pfsInodeGetParent(pfsMount, NULL, path, szPath, &rv))==NULL)
802 return rv;
803
804 if((file=pfsInodeGetFileInDir(parent, szPath, &rv))!=NULL)
805 {
806 if(mode!=0)
807 {// remove dir
808 if((file->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
809 rv=-ENOTDIR;
810 else if(pfsCheckDirForFiles(file)==0)
811 rv=-ENOTEMPTY;
812 else if(((u16)file->u.inode->inode_block.number==pfsMount->root_dir.number) &&
813 ((u16)file->u.inode->inode_block.subpart==pfsMount->root_dir.subpart))
814 rv=-EBUSY;
815 else if(((u16)file->u.inode->inode_block.number==pfsMount->current_dir.number) &&
816 ((u16)file->u.inode->inode_block.subpart==pfsMount->current_dir.subpart))
817 rv=-EBUSY;
818 }
819 else// just a file
820 if((file->u.inode->mode & FIO_S_IFMT)==FIO_S_IFDIR)
821 rv=-EISDIR;
822
823 if(rv==0)
824 {
825 if(file->u.inode->uid!=0)
826 rv=pfsCheckAccess(file, 2);
827 if(file->nused>=2)
828 rv=-EBUSY;
829 if(rv==0)
830 return pfsInodeRemove(parent, file, szPath);
831 }
832 pfsCacheFree(file);
833 }
834 pfsCacheFree(parent);
835 return pfsFioCheckForLastError(pfsMount, rv);
836}
837
838int pfsFioRemove(iomanX_iop_file_t *f, const char *name)
839{
840 pfs_mount_t *pfsMount;
841 int rv;
842
843 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
844 return -ENODEV;
845
846 rv = _remove(pfsMount, name, 0);
847
848 SignalSema(pfsFioSema);
849
850 return rv;
851}
852
853int pfsFioMkdir(iomanX_iop_file_t *f, const char *path, int mode)
854{
855 pfs_mount_t *pfsMount;
856 int rv;
857
858 mode = (mode & 0xfff) | 0x10000 | FIO_S_IFDIR; // TODO: change to some constant/macro
859
860 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
861 return -ENODEV;
862
863 rv = openFile(pfsMount, NULL, path, FIO_O_CREAT | FIO_O_WRONLY, mode);
864
865 SignalSema(pfsFioSema);
866
867 return rv;
868}
869
870int pfsFioRmdir(iomanX_iop_file_t *f, const char *path)
871{
872 pfs_mount_t *pfsMount;
873 const char *temp;
874 int rv;
875
876 temp = path + strlen(path);
877 if(*temp == '.')
878 return -EINVAL;
879
880 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
881 return -ENODEV;
882
883 rv = _remove(pfsMount, path, 0x01); // TODO: constant for 0x01 ?
884
885 SignalSema(pfsFioSema);
886
887 return rv;
888}
889
890int pfsFioDopen(iomanX_iop_file_t *f, const char *name)
891{
892 return pfsFioOpen(f, name, 0, 0);
893}
894
895int pfsFioDread(iomanX_iop_file_t *f, iox_dirent_t *dirent)
896{
897 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
898 pfs_mount_t *pfsMount;
899 pfs_cache_t *clink;
901 int result;
902 int rv;
903
904 rv = pfsFioCheckFileSlot(fileSlot);
905 if(rv < 0)
906 return rv;
907
908 pfsMount = fileSlot->clink->pfsMount;
909
910 if((fileSlot->clink->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
911 {
912 rv = -ENOTDIR;
913 }
914 else
915 {
916 if((rv = pfsGetNextDentry(fileSlot->clink, &fileSlot->block_pos, (u32 *)&fileSlot->position,
917 dirent->name, &bi)) > 0)
918 {
919
920 clink = pfsInodeGetData(pfsMount, bi.subpart, bi.number, &result);
921 if(clink != NULL)
922 {
923 fioStatFiller(clink, &dirent->stat);
924 pfsCacheFree(clink);
925 }
926
927 if(result)
928 rv = result;
929 }
930 }
931
932 rv = pfsFioCheckForLastError(pfsMount, rv);
933 SignalSema(pfsFioSema);
934
935 return rv;
936}
937
938static void fioStatFiller(pfs_cache_t *clink, iox_stat_t *stat)
939{
940 stat->mode = clink->u.inode->mode;
941 stat->attr = clink->u.inode->attr;
942 stat->size = (u32)clink->u.inode->size;
943 stat->hisize = (u32)(clink->u.inode->size >> 32);
944 memcpy(&stat->ctime, &clink->u.inode->ctime, sizeof(pfs_datetime_t));
945 memcpy(&stat->atime, &clink->u.inode->atime, sizeof(pfs_datetime_t));
946 memcpy(&stat->mtime, &clink->u.inode->mtime, sizeof(pfs_datetime_t));
947 stat->private_0 = clink->u.inode->uid;
948 stat->private_1 = clink->u.inode->gid;
949 stat->private_2 = clink->u.inode->number_blocks;
950 stat->private_3 = clink->u.inode->number_data;
951#ifndef PFS_STAT_RETURN_INODE_LBA
952 stat->private_4 = 0;
953 stat->private_5 = 0;
954#else
955 stat->private_4 = clink->sub;
956 stat->private_5 = clink->block << pfsBlockSize;
957#endif
958}
959
960int pfsFioGetstat(iomanX_iop_file_t *f, const char *name, iox_stat_t *stat)
961{
962 pfs_mount_t *pfsMount;
963 pfs_cache_t *clink;
964 int rv=0;
965
966 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
967 return -ENODEV;
968
969 clink=pfsInodeGetFile(pfsMount, NULL, name, &rv);
970 if(clink!=NULL)
971 {
972 fioStatFiller(clink, stat);
973 pfsCacheFree(clink);
974 }
975
976 SignalSema(pfsFioSema);
977 return pfsFioCheckForLastError(pfsMount, rv);
978}
979
980int pfsFioChstat(iomanX_iop_file_t *f, const char *name, iox_stat_t *stat, unsigned int statmask)
981{
982 pfs_mount_t *pfsMount;
983 pfs_cache_t *clink;
984 int rv = 0;
985
986 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
987 return -ENODEV;
988#ifdef PFS_SUPPORT_BHDD
989 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
990 {
991 SignalSema(pfsFioSema);
992 return -EBADF;
993 }
994#endif
995 clink = pfsInodeGetFile(pfsMount, NULL, name, &rv);
996 if(clink != NULL) {
997
998 rv = pfsCheckAccess(clink, 0x02);
999 if(rv == 0) {
1000
1001 clink->flags |= PFS_CACHE_FLAG_DIRTY;
1002
1003 if((statmask & FIO_CST_MODE) && ((clink->u.inode->mode & FIO_S_IFMT) != FIO_S_IFLNK))
1004 clink->u.inode->mode = (clink->u.inode->mode & FIO_S_IFMT) | (stat->mode & 0xfff);
1005 if(statmask & FIO_CST_ATTR)
1006 clink->u.inode->attr = (clink->u.inode->attr & 0xA0) | (stat->attr & 0xFF5F);
1007 if(statmask & FIO_CST_SIZE)
1008 rv = -EACCES;
1009 if(statmask & FIO_CST_CT)
1010 memcpy(&clink->u.inode->ctime, stat->ctime, sizeof(pfs_datetime_t));
1011 if(statmask & FIO_CST_AT)
1012 memcpy(&clink->u.inode->atime, stat->atime, sizeof(pfs_datetime_t));
1013 if(statmask & FIO_CST_MT)
1014 memcpy(&clink->u.inode->mtime, stat->mtime, sizeof(pfs_datetime_t));
1015/* //By PFS v2.2, changing UID and GID was no longer allowed.
1016 if(statmask & FIO_CST_PRVT) {
1017 clink->u.inode->uid = stat->private_0;
1018 clink->u.inode->gid = stat->private_1;
1019 } */
1020
1021 if(pfsMount->flags & PFS_FIO_ATTR_WRITEABLE)
1022 pfsCacheFlushAllDirty(pfsMount);
1023 }
1024
1025 pfsCacheFree(clink);
1026
1027 }
1028
1029 SignalSema(pfsFioSema);
1030 return pfsFioCheckForLastError(pfsMount, rv);
1031}
1032
1033int pfsFioRename(iomanX_iop_file_t *ff, const char *old, const char *new)
1034{
1035 char path1[256], path2[256];
1036 int result=0;
1037 pfs_mount_t *pfsMount;
1038 int f, sameParent;
1039 pfs_cache_t *parentOld=NULL, *parentNew=NULL;
1040 pfs_cache_t *removeOld=NULL, *removeNew=NULL;
1041 pfs_cache_t *iFileOld=NULL, *iFileNew=NULL;
1042 pfs_cache_t *newParent=NULL,*addNew=NULL;
1043
1044 pfsMount=pfsFioGetMountedUnit(ff->unit);
1045 if (pfsMount==0) return -ENODEV;
1046#ifdef PFS_SUPPORT_BHDD
1047 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
1048 {
1049 SignalSema(pfsFioSema);
1050 return -EACCES;
1051 }
1052#endif
1053 parentOld=pfsInodeGetParent(pfsMount, NULL, old, path1, &result);
1054 if (parentOld){
1055 u32 nused=parentOld->nused;
1056
1057 if (nused != 1){
1058 result=-EBUSY;
1059 goto exit;
1060 }
1061
1062 if ((iFileOld=pfsInodeGetFileInDir(parentOld, path1, &result))==NULL) goto exit;
1063
1064 if ((parentNew=pfsInodeGetParent(pfsMount, NULL, new, path2, &result))==NULL) goto exit;
1065
1066 f=(iFileOld->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR;
1067
1068 sameParent = parentOld == parentNew;
1069
1070 if ((parentNew->nused != nused) && ((!sameParent) || (parentNew->nused!=2))){
1071 result=-EBUSY;
1072 goto exit;
1073 }
1074
1075 iFileNew=pfsInodeGetFileInDir(parentNew, path2, &result);
1076 if (iFileNew){
1077 if (f){
1078 if ((iFileNew->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
1079 result=-ENOTDIR;
1080 else
1081 if (pfsCheckDirForFiles(iFileNew)){
1082 if (iFileNew->nused >= 2)
1083 result=-EBUSY;
1084 else{
1085 if (iFileOld==iFileNew)
1086 goto exit;
1087 }
1088 }else
1089 result=-ENOTEMPTY;
1090 }else
1091 if ((iFileNew->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR)
1092 result=-EISDIR;
1093 else
1094 if (iFileNew->nused >= 2)
1095 result=-EBUSY;
1096 else{
1097 if (iFileOld==iFileNew)
1098 goto exit;
1099 }
1100 }else
1101 if (result==-ENOENT)
1102 result=0;
1103
1104 if (result) goto exit;
1105
1106 if (f && (!sameParent)){
1107 pfs_cache_t *parent;
1108
1109 parent=pfsCacheUsedAdd(parentNew);
1110 do{
1111 pfs_cache_t *tmp;
1112
1113 if (parent==iFileOld){
1114 result=-EINVAL;
1115 break;
1116 }
1117 tmp=pfsInodeGetFileInDir(parent, "..", &result);
1118 pfsCacheFree(parent);
1119 if (tmp==parent)break;
1120 parent=tmp;
1121 }while(parent);
1122 pfsCacheFree(parent);
1123 }
1124
1125 if (result==0){
1126 if (strcmp(path1, ".") && strcmp(path1, "..") &&
1127 strcmp(path2, ".") && strcmp(path2, "..")){
1128 result=pfsCheckAccess(parentOld, 3);
1129 if (result==0)
1130 result=pfsCheckAccess(parentNew, 3);
1131 }else
1132 result=-EINVAL;
1133
1134 if (result==0){
1135 if (iFileNew && ((removeNew=pfsDirRemoveEntry(parentNew, path2))==NULL))
1136 result=-ENOENT;
1137 else{
1138 removeOld=pfsDirRemoveEntry(parentOld, path1);
1139 if (removeOld==0)
1140 result=-ENOENT;
1141 else{
1142 addNew=pfsDirAddEntry(parentNew, path2, &iFileOld->u.inode->inode_block, iFileOld->u.inode->mode, &result);
1143 if (addNew && f && (!sameParent))
1144 newParent=pfsSetDentryParent(iFileOld, &parentNew->u.inode->inode_block, &result);
1145 }
1146 }
1147 }
1148 }
1149
1150 if (result){
1151 if (removeNew) removeNew->pfsMount=NULL;
1152 if (removeOld) removeOld->pfsMount=NULL;
1153 if (addNew) addNew->pfsMount=NULL;
1154 if (iFileNew) iFileNew->pfsMount=NULL;
1155 parentOld->pfsMount=NULL;
1156 parentNew->pfsMount=NULL;
1157 }else{
1158 if (sameParent){
1159 if (removeOld!=addNew)
1160 removeOld->flags |= PFS_CACHE_FLAG_DIRTY;
1161 }else
1162 {
1163 pfsInodeSetTimeParent(parentOld, removeOld);
1164 }
1165 pfsInodeSetTimeParent(parentNew, addNew);
1166
1167 if (newParent != NULL){
1168 pfsInodeSetTimeParent(iFileOld, newParent);
1169 pfsCacheFree(newParent);
1170 }
1171
1172 if (iFileNew != NULL){
1173 iFileNew->flags &= ~PFS_CACHE_FLAG_DIRTY;
1174 pfsBitmapFreeInodeBlocks(iFileNew);
1175 }
1176
1177 //if (pfsMount->flags & PFS_FIO_ATTR_WRITEABLE) No check for this in late versions of PFS.
1178 pfsCacheFlushAllDirty(pfsMount);
1179 }
1180 if (removeOld) pfsCacheFree(removeOld);
1181 if (addNew) pfsCacheFree(addNew);
1182 if (removeNew) pfsCacheFree(removeNew);
1183exit:
1184 if (iFileNew) pfsCacheFree(iFileNew);
1185 pfsCacheFree(iFileOld);
1186 pfsCacheFree(parentOld);
1187 pfsCacheFree(parentNew);
1188 }
1189 SignalSema(pfsFioSema);
1190 return pfsFioCheckForLastError(pfsMount, result);
1191}
1192
1193int pfsFioChdir(iomanX_iop_file_t *f, const char *name)
1194{
1195 pfs_mount_t *pfsMount;
1196 pfs_cache_t *clink;
1197 int result = 0;
1198
1199 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
1200 return -ENODEV;
1201
1202 clink = pfsInodeGetFile(pfsMount, 0, name, &result);
1203 if(clink != NULL) {
1204 if((clink->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
1205 result = -ENOTDIR;
1206 else {
1207
1208 result = pfsCheckAccess(clink, 0x01);
1209
1210 if(result == 0)
1211 memcpy(&pfsMount->current_dir, &clink->u.inode->inode_block, sizeof(pfs_blockinfo_t));
1212 }
1213
1214 pfsCacheFree(clink);
1215 }
1216
1217 SignalSema(pfsFioSema);
1218 return pfsFioCheckForLastError(pfsMount, result);
1219}
1220
1221static void _sync(void)
1222{
1223 s32 i, j;
1224
1225 for(i=0;(u32)i<pfsConfig.maxOpen;i++)
1226 {
1227 pfs_unaligned_io_t *unaligned=&pfsFileSlots[i].unaligned;
1228 if(unaligned->dirty) {
1229 pfs_mount_t *pfsMount=pfsFileSlots[i].clink->pfsMount;
1230 pfsMount->blockDev->transfer(pfsMount->fd, unaligned->buffer,
1231 unaligned->sub, unaligned->sector, 1, PFS_IO_MODE_WRITE);
1232
1233 //In late modules, sync data with all other FDs that were opened for reading.
1234 for(j = 0; (u32)j < pfsConfig.maxOpen; j++)
1235 {
1236 if((pfsFileSlots[j].clink != NULL)
1237 && (pfsFileSlots[i].clink->pfsMount == pfsFileSlots[j].clink->pfsMount)
1238 && (pfsFileSlots[i].unaligned.sub == pfsFileSlots[j].unaligned.sub)
1239 && (pfsFileSlots[i].unaligned.sector == pfsFileSlots[j].unaligned.sector))
1240 {
1241 if(!pfsFileSlots[j].unaligned.dirty)
1242 memcpy(pfsFileSlots[j].unaligned.buffer, pfsFileSlots[i].unaligned.buffer, sizeof(pfsFileSlots[j].unaligned.buffer));
1243 }
1244 }
1245
1246 unaligned->dirty=0;
1247 }
1248 }
1249}
1250
1251int pfsFioSync(iomanX_iop_file_t *f, const char *dev, int flag)
1252{
1253 pfs_mount_t *pfsMount;
1254
1255 (void)dev;
1256 (void)flag;
1257
1258 if(!(pfsMount = pfsFioGetMountedUnit(f->unit)))
1259 return -ENODEV;
1260#ifdef PFS_SUPPORT_BHDD
1261 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
1262 {
1263 SignalSema(pfsFioSema);
1264 return -ENODEV;
1265 }
1266#endif
1267 _sync();
1268 pfsCacheFlushAllDirty(pfsMount);
1269
1270 SignalSema(pfsFioSema);
1271 return pfsFioCheckForLastError(pfsMount, 0);
1272}
1273
1274int pfsFioMount(iomanX_iop_file_t *f, const char *fsname, const char *devname, int flag, void *arg, int arglen)
1275{
1276 int rv;
1277 int fd;
1278 pfs_block_device_t *blockDev;
1279
1280 (void)fsname;
1281 (void)arg;
1282 (void)arglen;
1283
1284 if(!(blockDev = pfsGetBlockDeviceTable(devname)))
1285 return -ENXIO;
1286
1287 WaitSema(pfsFioSema);
1288
1289 fd = iomanX_open(devname, (flag & FIO_MT_RDONLY) ? FIO_O_RDONLY : FIO_O_RDWR); // ps2hdd.irx fd
1290 if(fd < 0)
1291 rv = fd;
1292 else {
1293 if((rv=mountDevice(blockDev, fd, f->unit, flag)) < 0)
1294 iomanX_close(fd);
1295 }
1296 SignalSema(pfsFioSema);
1297 return rv;
1298}
1299
1300int pfsFioUmount(iomanX_iop_file_t *f, const char *fsname)
1301{
1302 s32 i;
1303 int rv=0;
1304 int busy_flag=0;
1305 pfs_mount_t *pfsMount;
1306
1307 (void)fsname;
1308
1309 if((pfsMount = pfsFioGetMountedUnit(f->unit))==NULL)
1310 return -ENODEV;
1311
1312 for(i = 0; (u32)i < pfsConfig.maxOpen; i++)
1313 {
1314 if((pfsFileSlots[i].clink!=NULL) && (pfsFileSlots[i].clink->pfsMount==pfsMount))
1315 {
1316 busy_flag=1;
1317 break;
1318 }
1319 }
1320 if(busy_flag==0)
1321 {
1322 pfsCacheClose(pfsMount);
1323 iomanX_close(pfsMount->fd);
1324 pfsClearMount(pfsMount);
1325 }
1326 else
1327 rv=-EBUSY; // Mount device busy
1328
1329 SignalSema(pfsFioSema);
1330 return rv;
1331}
1332
1333int pfsFioSymlink(iomanX_iop_file_t *f, const char *old, const char *new)
1334{
1335 int rv;
1336 pfs_mount_t *pfsMount;
1337 int mode = 0x10000 | FIO_S_IFLNK | 0x1FF;
1338
1339 if(old==NULL || new==NULL)
1340 return -ENOENT;
1341
1342 if(!(pfsMount=pfsFioGetMountedUnit(f->unit)))
1343 return -ENODEV;
1344
1345 rv = openFile(pfsMount, (pfs_file_slot_t *)old, (const char *)new, FIO_O_CREAT|FIO_O_WRONLY, mode);
1346 SignalSema(pfsFioSema);
1347 return rv;
1348}
1349
1350int pfsFioReadlink(iomanX_iop_file_t *f, const char *path, char *buf, unsigned int buflen)
1351{
1352 int rv=0;
1353 pfs_mount_t *pfsMount;
1354 pfs_cache_t *clink;
1355
1356 if((int)buflen < 0)
1357 return -EINVAL;
1358 if(!(pfsMount=pfsFioGetMountedUnit(f->unit)))
1359 return -ENODEV;
1360
1361 if((clink=pfsInodeGetFile(pfsMount, NULL, path, &rv))!=NULL)
1362 {
1363 if(!FIO_S_ISLNK(clink->u.inode->mode))
1364 rv=-EINVAL;
1365 else
1366 {
1367 rv=strlen((char *)&clink->u.inode->data[1]);
1368 if(buflen < (unsigned int)rv)
1369 rv=(int)buflen;
1370 memcpy(buf, &clink->u.inode->data[1], rv);
1371 }
1372 pfsCacheFree(clink);
1373 }
1374 SignalSema(pfsFioSema);
1375
1376 return pfsFioCheckForLastError(pfsMount, rv);
1377}
#define ENOENT
Definition errno.h:23
#define EEXIST
Definition errno.h:53
#define ENXIO
Definition errno.h:31
#define EINVAL
Definition errno.h:63
#define ELOOP
Definition errno.h:193
#define EMFILE
Definition errno.h:67
#define EBUSY
Definition errno.h:51
#define ENOTDIR
Definition errno.h:59
#define ENOTEMPTY
Definition errno.h:189
#define ENODEV
Definition errno.h:57
#define EACCES
Definition errno.h:45
#define EBADF
Definition errno.h:37
#define EISDIR
Definition errno.h:61
void * privdata
Definition iomanX.h:78
#define FIO_S_IFMT
Definition iox_stat.h:39
#define FIO_S_IFLNK
Definition iox_stat.h:41
#define FIO_S_IFDIR
Definition iox_stat.h:45
#define FIO_S_IFREG
Definition iox_stat.h:43
u32 count
start sector of fragmented bd/file