A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1287 lines 37 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2002 by Björn Stenberg 11 * Copyright (C) 2014 by Michael Sevakis 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; either version 2 16 * of the License, or (at your option) any later version. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ****************************************************************************/ 22#define RB_FILESYSTEM_OS 23#include "config.h" 24#include "system.h" 25#include <string.h> 26#include <errno.h> 27#include "debug.h" 28#include "file.h" 29#include "fileobj_mgr.h" 30#include "disk_cache.h" 31#include "rb_namespace.h" 32#include "string-extra.h" 33 34/* Define LOGF_ENABLE to enable logf output in this file */ 35//#define LOGF_ENABLE 36#ifdef LOGF_ENABLE 37#include "logf.h" 38#undef DEBUGF 39#define DEBUGF logf 40#endif 41 42 43/** 44 * These functions provide a roughly POSIX-compatible file I/O API. 45 */ 46 47/* structure used for open file descriptors */ 48static struct filestr_desc 49{ 50 struct filestr_base stream; /* basic stream info (first!) */ 51 file_size_t offset; /* current offset for stream */ 52 file_size_t *sizep; /* shortcut to file size in fileobj */ 53} open_streams[MAX_OPEN_FILES]; 54 55/* check and return a struct filestr_desc* from a file descriptor number */ 56static struct filestr_desc * get_filestr(int fildes) 57{ 58 struct filestr_desc *file = &open_streams[fildes]; 59 60 if ((unsigned int)fildes >= MAX_OPEN_FILES) 61 file = NULL; 62 else if (file->stream.flags & FDO_BUSY) 63 return file; 64 65 DEBUGF("fildes %d: bad file number\n", fildes); 66 errno = (file && (file->stream.flags & FD_NONEXIST)) ? ENXIO : EBADF; 67 return NULL; 68} 69 70#define GET_FILESTR(type, fildes) \ 71 ({ \ 72 file_internal_lock_##type(); \ 73 struct filestr_desc * _file = get_filestr(fildes); \ 74 if (_file) \ 75 FILESTR_LOCK(type, &_file->stream); \ 76 else \ 77 file_internal_unlock_##type(); \ 78 _file; \ 79 }) 80 81/* release the lock on the filestr_desc* */ 82#define RELEASE_FILESTR(type, file) \ 83 ({ \ 84 FILESTR_UNLOCK(type, &(file)->stream); \ 85 file_internal_unlock_##type(); \ 86 }) 87 88/* find a free file descriptor */ 89static int alloc_filestr(struct filestr_desc **filep) 90{ 91 for (int fildes = 0; fildes < MAX_OPEN_FILES; fildes++) 92 { 93 struct filestr_desc *file = &open_streams[fildes]; 94 if (!file->stream.flags) 95 { 96 *filep = file; 97 return fildes; 98 } 99 } 100 101 DEBUGF("Too many files open\n"); 102 return -1; 103} 104 105/* return the file size in sectors */ 106static inline unsigned long filesize_sectors(uint16_t sector_size, file_size_t size) 107{ 108 /* overflow proof whereas "(x + y - 1) / y" is not */ 109 unsigned long numsectors = size / sector_size; 110 111 if (size % sector_size) 112 numsectors++; 113 114 return numsectors; 115} 116 117/* flush a dirty cache buffer */ 118static int flush_cache(struct filestr_desc *file) 119{ 120 int rc; 121 struct filestr_cache *cachep = file->stream.cachep; 122 123 DEBUGF("Flushing dirty sector cache (%llu)\n", (uint64_t)cachep->sector); 124 125 if (fat_query_sectornum(&file->stream.fatstr) != cachep->sector) 126 { 127 /* get on the correct sector */ 128 rc = fat_seek(&file->stream.fatstr, cachep->sector); 129 if (rc < 0) 130 FILE_ERROR(EIO, rc * 10 - 1); 131 } 132 133 rc = fat_readwrite(&file->stream.fatstr, 1, cachep->buffer, true); 134 if (rc < 0) 135 { 136 if (rc == FAT_RC_ENOSPC) 137 FILE_ERROR(ENOSPC, RC); 138 else 139 FILE_ERROR(EIO, rc * 10 - 2); 140 } 141 142 cachep->flags = 0; 143 return 1; 144file_error: 145 DEBUGF("Failed flushing cache: %d\n", rc); 146 return rc; 147} 148 149static void discard_cache(struct filestr_desc *file) 150{ 151 struct filestr_cache *const cachep = file->stream.cachep; 152 cachep->flags = 0; 153} 154 155/* set the file pointer */ 156static off_t lseek_internal(struct filestr_desc *file, off_t offset, 157 int whence) 158{ 159 off_t rc; 160 file_size_t pos; 161 162 file_size_t size = MIN(*file->sizep, FILE_SIZE_MAX); 163 164 switch (whence) 165 { 166 case SEEK_SET: 167 if (offset < 0 || (file_size_t)offset > size) 168 FILE_ERROR(EINVAL, -1); 169 170 pos = offset; 171 break; 172 173 case SEEK_CUR: 174 if ((offset < 0 && (file_size_t)-offset > file->offset) || 175 (offset > 0 && (file_size_t)offset > size - file->offset)) 176 FILE_ERROR(EINVAL, -1); 177 178 pos = file->offset + offset; 179 break; 180 181 case SEEK_END: 182 if (offset > 0 || (file_size_t)-offset > size) 183 FILE_ERROR(EINVAL, -1); 184 185 pos = size + offset; 186 break; 187 188 default: 189 FILE_ERROR(EINVAL, -1); 190 } 191 192 file->offset = pos; 193 194 return pos; 195file_error: 196 return rc; 197} 198 199/* Handle syncing all file's streams to the truncation */ 200static void handle_truncate(struct filestr_desc * const file, file_size_t size) 201{ 202 uint16_t sector_size = fat_file_sector_size(IF_MV(file->stream.fatstr.fatfilep)); 203 unsigned long filesectors = filesize_sectors(sector_size, size); 204 205 struct filestr_base *s = NULL; 206 while ((s = fileobj_get_next_stream(&file->stream, s))) 207 { 208 /* caches with data beyond new extents are invalid */ 209 sector_t sector = s->cachep->sector; 210 if (sector != INVALID_SECNUM && sector >= filesectors) 211 filestr_discard_cache(s); 212 213 /* files outside bounds must be rewound */ 214 if (fat_query_sectornum(&s->fatstr) > filesectors) 215 fat_seek_to_stream(&s->fatstr, &file->stream.fatstr); 216 217 /* clip file offset too if needed */ 218 struct filestr_desc *f = (struct filestr_desc *)s; 219 if (f->offset > size) 220 f->offset = size; 221 } 222} 223 224/* truncate the file to the specified length */ 225static int ftruncate_internal(struct filestr_desc *file, file_size_t size, 226 bool write_now) 227{ 228 int rc = 0, rc2 = 1; 229 230 file_size_t cursize = *file->sizep; 231 file_size_t truncsize = MIN(size, cursize); 232 233 uint16_t sector_size = fat_file_sector_size(IF_MV(file->stream.fatstr.fatfilep)); 234 235 if (write_now) 236 { 237 unsigned long sector = filesize_sectors(sector_size, truncsize); 238 struct filestr_cache *const cachep = file->stream.cachep; 239 240 if (cachep->flags == (FSC_NEW|FSC_DIRTY) && 241 cachep->sector + 1 == sector) 242 { 243 /* sector created but may have never been added to the cluster 244 chain; flush it now or the subsequent may fail */ 245 rc2 = flush_cache(file); 246 if (rc2 == FAT_RC_ENOSPC) 247 { 248 /* no space left on device; further truncation needed */ 249 discard_cache(file); 250 truncsize = ALIGN_DOWN(truncsize - 1, sector_size); 251 sector--; 252 rc = rc2; 253 } 254 else if (rc2 < 0) 255 FILE_ERROR(ERRNO, rc2 * 10 - 1); 256 } 257 258 rc2 = fat_seek(&file->stream.fatstr, sector); 259 if (rc2 < 0) 260 FILE_ERROR(EIO, rc2 * 10 - 2); 261 262 rc2 = fat_truncate(&file->stream.fatstr); 263 if (rc2 < 0) 264 FILE_ERROR(EIO, rc2 * 10 - 3); 265 266 /* never needs to be done this way again since any data beyond the 267 cached size is now gone */ 268 fileobj_change_flags(&file->stream, 0, FO_TRUNC); 269 } 270 /* else just change the cached file size */ 271 272 if (truncsize < cursize) 273 { 274 *file->sizep = truncsize; 275 handle_truncate(file, truncsize); 276 } 277 278 /* if truncation was partially successful, it effectively destroyed 279 everything after the truncation point; still, indicate failure 280 after adjusting size */ 281 if (rc2 == 0) 282 FILE_ERROR(EIO, -4); 283 else if (rc2 < 0) 284 FILE_ERROR(ERRNO, rc2); 285 286file_error: 287 return rc; 288} 289 290/* flush back all outstanding writes to the file */ 291static int fsync_internal(struct filestr_desc *file) 292{ 293 /* call only when holding WRITER lock (updates directory entries) */ 294 int rc = 0; 295 296 file_size_t size = *file->sizep; 297 unsigned int foflags = fileobj_get_flags(&file->stream); 298 uint16_t sector_size = fat_file_sector_size(IF_MV(file->stream.fatstr.fatfilep)); 299 300 /* flush sector cache? */ 301 struct filestr_cache *const cachep = file->stream.cachep; 302 if (cachep->flags & FSC_DIRTY) 303 { 304 int rc2 = flush_cache(file); 305 if (rc2 == FAT_RC_ENOSPC && (cachep->flags & FSC_NEW)) 306 { 307 /* no space left on device so this must be dropped */ 308 discard_cache(file); 309 size = ALIGN_DOWN(size - 1, sector_size); 310 foflags |= FO_TRUNC; 311 rc = rc2; 312 } 313 else if (rc2 < 0) 314 FILE_ERROR(ERRNO, rc2 * 10 - 1); 315 } 316 317 /* truncate? */ 318 if (foflags & FO_TRUNC) 319 { 320 int rc2 = ftruncate_internal(file, size, rc == 0); 321 if (rc2 < 0) 322 FILE_ERROR(ERRNO, rc2 * 10 - 2); 323 } 324 325file_error:; 326 /* tie up all loose ends (try to close the file even if failing) */ 327 int rc2 = fat_closewrite(&file->stream.fatstr, size, 328 get_dir_fatent_dircache()); 329 if (rc2 >= 0) 330 fileop_onsync_internal(&file->stream); /* dir_fatent is implicit arg */ 331 332 if (rc2 < 0 && rc >= 0) 333 { 334 errno = EIO; 335 rc = rc2 * 10 - 3; 336 } 337 338 return rc; 339} 340 341/* finish with the file and free resources */ 342static int close_internal(struct filestr_desc *file) 343{ 344 /* call only when holding WRITER lock (updates directory entries) */ 345 int rc; 346 347 if ((file->stream.flags & (FD_WRITE|FD_NONEXIST)) == FD_WRITE) 348 { 349 rc = fsync_internal(file); 350 if (rc < 0) 351 FILE_ERROR(ERRNO, rc * 10 - 1); 352 } 353 354 rc = 0; 355file_error:; 356 int rc2 = close_stream_internal(&file->stream); 357 if (rc2 < 0 && rc >= 0) 358 rc = rc2 * 10 - 2; 359 return rc; 360} 361 362/* actually do the open gruntwork */ 363static int open_internal_inner2(const char *path, 364 struct filestr_desc *file, 365 unsigned int callflags, 366 int oflag) 367{ 368 int rc; 369 370 struct path_component_info compinfo; 371 372 if (oflag & O_CREAT) 373 callflags |= FF_PARENTINFO; 374 375 rc = open_stream_internal(path, callflags, &file->stream, &compinfo); 376 if (rc < 0) 377 { 378 DEBUGF("Open failed: %d\n", rc); 379 FILE_ERROR_RETURN(ERRNO, rc * 10 - 1); 380 } 381 382 bool created = false; 383 384 if (rc > 0) 385 { 386 if (oflag & O_EXCL) 387 { 388 DEBUGF("File exists\n"); 389 FILE_ERROR(EEXIST, -2); 390 } 391 392 if (compinfo.attr & ATTR_DIRECTORY) 393 { 394 if ((callflags & FD_WRITE) || !(callflags & FF_ANYTYPE)) 395 { 396 DEBUGF("File is a directory\n"); 397 FILE_ERROR(EISDIR, -3); 398 } 399 400 compinfo.filesize = MAX_DIRECTORY_SIZE; /* allow file ops */ 401 } 402 } 403 else if (oflag & O_CREAT) 404 { 405 if (compinfo.attr & ATTR_DIRECTORY) 406 { 407 DEBUGF("File is a directory\n"); 408 FILE_ERROR(EISDIR, -5); 409 } 410 411 /* not found; try to create it */ 412 413 callflags &= ~FO_TRUNC; 414 rc = create_stream_internal(&compinfo.parentinfo, compinfo.name, 415 compinfo.length, ATTR_NEW_FILE, callflags, 416 &file->stream); 417 if (rc < 0) 418 FILE_ERROR(ERRNO, rc * 10 - 6); 419 420 created = true; 421 } 422 else 423 { 424 DEBUGF("File not found\n"); 425 FILE_ERROR(ENOENT, -7); 426 } 427 428 fat_rewind(&file->stream.fatstr); 429 file->sizep = fileobj_get_sizep(&file->stream); 430 file->offset = 0; 431 432 if (!created) 433 { 434 /* size from storage applies to first stream only otherwise it's 435 already up to date */ 436 const bool first = fileobj_get_flags(&file->stream) & FO_SINGLE; 437 if (first) 438 *file->sizep = compinfo.filesize; 439 440 if (callflags & FO_TRUNC) 441 { 442 /* if the file is kind of "big" then free some space now */ 443 rc = ftruncate_internal(file, 0, *file->sizep >= O_TRUNC_THRESH); 444 if (rc < 0) 445 { 446 DEBUGF("O_TRUNC failed: %d\n", rc); 447 FILE_ERROR(ERRNO, rc * 10 - 4); 448 } 449 } 450 } 451 452 rc = 0; 453file_error: 454 if (rc < 0) 455 close_stream_internal(&file->stream); 456 457 return rc; 458} 459 460/* allocate a file descriptor, if needed, assemble stream flags and open 461 a new stream */ 462static int open_internal_inner1(const char *path, int oflag, 463 unsigned int callflags) 464{ 465 DEBUGF("%s(path=\"%s\",oflag=%X,callflags=%X)\n", __func__, 466 path, oflag, callflags); 467 468 int rc; 469 470 struct filestr_desc *file; 471 int fildes = alloc_filestr(&file); 472 if (fildes < 0) 473 FILE_ERROR(EMFILE, -1); 474 475 callflags &= ~FDO_MASK; 476 477 if (oflag & O_ACCMODE) 478 { 479 callflags |= FD_WRITE; 480 481 if ((oflag & O_ACCMODE) == O_WRONLY) 482 callflags |= FD_WRONLY; 483 484 if (oflag & O_APPEND) 485 callflags |= FD_APPEND; 486 487 if (oflag & O_TRUNC) 488 callflags |= FO_TRUNC; 489 } 490 else if (oflag & O_TRUNC) 491 { 492 /* O_TRUNC requires write mode */ 493 DEBUGF("No write mode but have O_TRUNC\n"); 494 FILE_ERROR(EINVAL, -2); 495 } 496 497 /* O_CREAT and O_APPEND are fine without write mode 498 * for the former, an empty file is created but no data may be written 499 * for the latter, no append will be allowed anyway */ 500 if (!(oflag & O_CREAT)) 501 oflag &= ~O_EXCL; /* result is undefined: we choose "ignore" */ 502 503 rc = open_internal_inner2(path, file, callflags, oflag); 504 if (rc < 0) 505 FILE_ERROR(ERRNO, rc * 10 - 3); 506 507 return fildes; 508 509file_error: 510 if (fildes >= 0) 511 close(fildes); 512 return rc; 513} 514 515static int open_internal_locked(const char *path, int oflag, 516 unsigned int callflags) 517{ 518 file_internal_lock_WRITER(); 519 int rc = open_internal_inner1(path, oflag, callflags); 520 file_internal_unlock_WRITER(); 521 return rc; 522} 523 524/* fill a cache buffer with a new sector */ 525static int readwrite_fill_cache(struct filestr_desc *file, unsigned long sector, 526 unsigned long filesectors, bool write) 527{ 528 /* sector != cachep->sector should have been checked by now */ 529 530 int rc; 531 struct filestr_cache *cachep = filestr_get_cache(&file->stream); 532 533 if (cachep->flags & FSC_DIRTY) 534 { 535 rc = flush_cache(file); 536 if (rc < 0) 537 FILE_ERROR(ERRNO, rc * 10 - 1); 538 } 539 540 if (fat_query_sectornum(&file->stream.fatstr) != sector) 541 { 542 /* get on the correct sector */ 543 rc = fat_seek(&file->stream.fatstr, sector); 544 if (rc < 0) 545 FILE_ERROR(EIO, rc * 10 - 2); 546 } 547 548 if (!write || sector < filesectors) 549 { 550 /* only reading or this sector would have been flushed if the cache 551 was previously needed for a different sector */ 552 rc = fat_readwrite(&file->stream.fatstr, 1, cachep->buffer, false); 553 if (rc < 0) 554 FILE_ERROR(rc == FAT_RC_ENOSPC ? ENOSPC : EIO, rc * 10 - 3); 555 } 556 else 557 { 558 /* create a fresh, shiny, new sector with that new sector smell */ 559 cachep->flags = FSC_NEW; 560 } 561 562 cachep->sector = sector; 563 return 1; 564file_error: 565 DEBUGF("Failed caching sector: %d\n", rc); 566 return rc; 567} 568 569/* read or write to part or all of the cache buffer */ 570static inline void readwrite_cache(struct filestr_cache *cachep, void *buf, 571 unsigned long secoffset, size_t nbyte, 572 bool write) 573{ 574 void *dst, *cbufp = cachep->buffer + secoffset; 575 576 if (write) 577 { 578 dst = cbufp; 579 cachep->flags |= FSC_DIRTY; 580 } 581 else 582 { 583 dst = buf; 584 buf = cbufp; 585 } 586 587 memcpy(dst, buf, nbyte); 588} 589 590/* read or write a partial sector using the file's cache */ 591static inline ssize_t readwrite_partial(struct filestr_desc *file, 592 struct filestr_cache *cachep, 593 unsigned long sector, 594 unsigned long secoffset, 595 void *buf, 596 size_t nbyte, 597 unsigned long filesectors, 598 unsigned int flags) 599{ 600 if (sector != cachep->sector) 601 { 602 /* wrong sector in buffer */ 603 int rc = readwrite_fill_cache(file, sector, filesectors, flags); 604 if (rc <= 0) 605 return rc; 606 } 607 608 readwrite_cache(cachep, buf, secoffset, nbyte, flags); 609 return nbyte; 610} 611 612/* read from or write to the file; back end to read() and write() */ 613static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte, 614 bool write) 615{ 616#ifndef LOGF_ENABLE /* wipes out log before you can save it */ 617 DEBUGF("readwrite(%p,%lx,%lu,%s)\n", 618 file, (long)buf, (unsigned long)nbyte, write ? "write" : "read"); 619#endif 620 621 const file_size_t size = *file->sizep; 622 file_size_t filerem; 623 624 if (write) 625 { 626 /* if opened in append mode, move pointer to end */ 627 if (file->stream.flags & FD_APPEND) 628 file->offset = MIN(size, FILE_SIZE_MAX); 629 630 filerem = FILE_SIZE_MAX - file->offset; 631 } 632 else 633 { 634 /* limit to maximum possible offset (EOF or FILE_SIZE_MAX) */ 635 filerem = MIN(size, FILE_SIZE_MAX) - file->offset; 636 } 637 638 if (nbyte > filerem) 639 { 640 nbyte = filerem; 641 if (nbyte > 0) 642 {} 643 else if (write) 644 FILE_ERROR_RETURN(EFBIG, -1); /* would get too large */ 645 else if (file->offset >= FILE_SIZE_MAX) 646 FILE_ERROR_RETURN(EOVERFLOW, -2); /* can't read here */ 647 } 648 649 if (nbyte == 0) 650 return 0; 651 652 int rc = 0; 653 654 struct filestr_cache * const cachep = file->stream.cachep; 655 void * const bufstart = buf; 656 uint16_t sector_size = fat_file_sector_size(IF_MV(file->stream.fatstr.fatfilep)); 657 658 const unsigned long filesectors = filesize_sectors(sector_size, size); 659 unsigned long sector = file->offset / sector_size; 660 unsigned long sectoroffs = file->offset % sector_size; 661 662 /* any head bytes? */ 663 if (sectoroffs) 664 { 665 size_t headbytes = MIN(nbyte, sector_size - sectoroffs); 666 rc = readwrite_partial(file, cachep, sector, sectoroffs, buf, headbytes, 667 filesectors, write); 668 if (rc <= 0) 669 { 670 if (rc < 0) 671 FILE_ERROR(ERRNO, rc * 10 - 3); 672 673 nbyte = 0; /* eof, skip the rest */ 674 } 675 else 676 { 677 buf += rc; 678 nbyte -= rc; 679 sector++; /* if nbyte goes to 0, the rest is skipped anyway */ 680 } 681 } 682 683 /* read/write whole sectors right into/from the supplied buffer */ 684 unsigned long sectorcount = nbyte / sector_size; 685 686 while (sectorcount) 687 { 688 unsigned long runlen = sectorcount; 689 690 /* if a cached sector is inside the transfer range, split the transfer 691 into two parts and use the cache for that sector to keep it coherent 692 without writeback */ 693 if (UNLIKELY(cachep->sector >= sector && 694 cachep->sector < sector + sectorcount)) 695 { 696 runlen = cachep->sector - sector; 697 } 698 699 if (runlen) 700 { 701 if (fat_query_sectornum(&file->stream.fatstr) != sector) 702 { 703 /* get on the correct sector */ 704 rc = 0; 705 706 /* If the dirty bit isn't set, we're somehow beyond the file 707 size and you can't explain _that_ */ 708 if (sector >= filesectors && cachep->flags == (FSC_NEW|FSC_DIRTY)) 709 { 710 rc = flush_cache(file); 711 if (rc < 0) 712 FILE_ERROR(ERRNO, rc * 10 - 4); 713 714 if (cachep->sector + 1 == sector) 715 rc = 1; /* if now ok, don't seek */ 716 } 717 718 if (rc == 0) 719 { 720 rc = fat_seek(&file->stream.fatstr, sector); 721 if (rc < 0) 722 FILE_ERROR(EIO, rc * 10 - 5); 723 } 724 } 725 726 rc = fat_readwrite(&file->stream.fatstr, runlen, buf, write); 727 if (rc < 0) 728 { 729 DEBUGF("I/O error %sing %ld sectors\n", 730 write ? "writ" : "read", runlen); 731 FILE_ERROR(rc == FAT_RC_ENOSPC ? ENOSPC : EIO, 732 rc * 10 - 6); 733 } 734 else 735 { 736 buf += rc * sector_size; 737 nbyte -= rc * sector_size; 738 sector += rc; 739 sectorcount -= rc; 740 741 /* if eof, skip tail bytes */ 742 if ((unsigned long)rc < runlen) 743 nbyte = 0; 744 745 if (!nbyte) 746 break; 747 } 748 } 749 750 if (UNLIKELY(sectorcount && sector == cachep->sector)) 751 { 752 /* do this one sector with the cache */ 753 readwrite_cache(cachep, buf, 0, sector_size, write); 754 buf += sector_size; 755 nbyte -= sector_size; 756 sector++; 757 sectorcount--; 758 } 759 } 760 761 /* any tail bytes? */ 762 if (nbyte) 763 { 764 /* tail bytes always start at sector offset 0 */ 765 rc = readwrite_partial(file, cachep, sector, 0, buf, nbyte, 766 filesectors, write); 767 if (rc < 0) 768 FILE_ERROR(ERRNO, rc * 10 - 7); 769 770 buf += rc; 771 } 772 773file_error:; 774#ifdef DEBUG 775 if (errno == ENOSPC) 776 DEBUGF("No space left on device\n"); 777#endif 778 779 size_t done = buf - bufstart; 780 if (done) 781 { 782 /* error or not, update the file offset and size if anything was 783 transferred */ 784 file->offset += done; 785#ifndef LOGF_ENABLE /* wipes out log before you can save it */ 786 DEBUGF("file offset: %ld\n", file->offset); 787#endif 788 /* adjust file size to length written */ 789 if (write && file->offset > size) 790 *file->sizep = file->offset; 791 792 if (rc > 0) 793 return done; 794 } 795 796 return rc; 797} 798 799 800/** Internal interface **/ 801 802/* open a file without codepage conversion during the directory search; 803 required to avoid any reentrancy when opening codepages and when scanning 804 directories internally, which could infinitely recurse and would corrupt 805 the static data */ 806int open_noiso_internal(const char *path, int oflag) 807{ 808 return open_internal_locked(path, oflag, FF_ANYTYPE | FF_NOISO); 809} 810 811void force_close_writer_internal(struct filestr_base *stream) 812{ 813 /* only we do writers so we know this is our guy */ 814 close_internal((struct filestr_desc *)stream); 815} 816 817 818/** POSIX **/ 819 820/* open a file */ 821int open(const char *path, int oflag) 822{ 823 DEBUGF("open(path=\"%s\",oflag=%X)\n", path, (unsigned)oflag); 824 return open_internal_locked(path, oflag, FF_ANYTYPE); 825} 826 827/* create a new file or rewrite an existing one */ 828int creat(const char *path) 829{ 830 DEBUGF("creat(path=\"%s\")\n", path); 831 return open_internal_locked(path, O_WRONLY|O_CREAT|O_TRUNC, FF_ANYTYPE); 832} 833 834/* close a file descriptor */ 835int close(int fildes) 836{ 837 DEBUGF("close(fd=%d)\n", fildes); 838 839 int rc; 840 841 file_internal_lock_WRITER(); 842 843 /* needs to work even if marked "nonexistant" */ 844 struct filestr_desc *file = &open_streams[fildes]; 845 if ((unsigned int)fildes >= MAX_OPEN_FILES || !file->stream.flags) 846 { 847 DEBUGF("filedes %d not open\n", fildes); 848 FILE_ERROR(EBADF, -2); 849 } 850 851 rc = close_internal(file); 852 if (rc < 0) 853 FILE_ERROR(ERRNO, rc * 10 - 3); 854 855file_error: 856 file_internal_unlock_WRITER(); 857 return rc; 858} 859 860/* truncate a file to a specified length */ 861int ftruncate(int fildes, off_t length) 862{ 863 DEBUGF("ftruncate(fd=%d,len=%ld)\n", fildes, (long)length); 864 865 struct filestr_desc * const file = GET_FILESTR(READER, fildes); 866 if (!file) 867 FILE_ERROR_RETURN(ERRNO, -1); 868 869 int rc; 870 871 if (!(file->stream.flags & FD_WRITE)) 872 { 873 DEBUGF("Descriptor is read-only mode\n"); 874 FILE_ERROR(EBADF, -2); 875 } 876 877 if (length < 0) 878 { 879 DEBUGF("Length %ld is invalid\n", (long)length); 880 FILE_ERROR(EINVAL, -3); 881 } 882 883 rc = ftruncate_internal(file, length, true); 884 if (rc < 0) 885 FILE_ERROR(ERRNO, rc * 10 - 4); 886 887file_error: 888 RELEASE_FILESTR(READER, file); 889 return rc; 890} 891 892/* synchronize changes to a file */ 893int fsync(int fildes) 894{ 895 DEBUGF("fsync(fd=%d)\n", fildes); 896 897 struct filestr_desc * const file = GET_FILESTR(WRITER, fildes); 898 if (!file) 899 FILE_ERROR_RETURN(ERRNO, -1); 900 901 int rc; 902 903 if (!(file->stream.flags & FD_WRITE)) 904 { 905 DEBUGF("Descriptor is read-only mode\n"); 906 FILE_ERROR(EINVAL, -2); 907 } 908 909 rc = fsync_internal(file); 910 if (rc < 0) 911 FILE_ERROR(ERRNO, rc * 10 - 3); 912 913file_error: 914 RELEASE_FILESTR(WRITER, file); 915 return rc; 916} 917 918/* move the read/write file offset */ 919off_t lseek(int fildes, off_t offset, int whence) 920{ 921#ifndef LOGF_ENABLE /* wipes out log before you can save it */ 922 DEBUGF("lseek(fd=%d,ofs=%ld,wh=%d)\n", fildes, (long)offset, whence); 923#endif 924 struct filestr_desc * const file = GET_FILESTR(READER, fildes); 925 if (!file) 926 FILE_ERROR_RETURN(ERRNO, -1); 927 928 off_t rc = lseek_internal(file, offset, whence); 929 if (rc < 0) 930 FILE_ERROR(ERRNO, rc * 10 - 2); 931 932file_error: 933 RELEASE_FILESTR(READER, file); 934 return rc; 935} 936 937/* read from a file */ 938ssize_t read(int fildes, void *buf, size_t nbyte) 939{ 940 struct filestr_desc * const file = GET_FILESTR(READER, fildes); 941 if (!file) 942 FILE_ERROR_RETURN(ERRNO, -1); 943 944 ssize_t rc; 945 946 if (file->stream.flags & FD_WRONLY) 947 { 948 DEBUGF("read(fd=%d,buf=%p,nb=%lu) - " 949 "descriptor is write-only mode\n", 950 fildes, buf, (unsigned long)nbyte); 951 FILE_ERROR(EBADF, -2); 952 } 953 954 rc = readwrite(file, buf, nbyte, false); 955 if (rc < 0) 956 FILE_ERROR(ERRNO, rc * 10 - 3); 957 958file_error: 959 RELEASE_FILESTR(READER, file); 960 return rc; 961} 962 963/* write on a file */ 964ssize_t write(int fildes, const void *buf, size_t nbyte) 965{ 966 struct filestr_desc * const file = GET_FILESTR(READER, fildes); 967 if (!file) 968 FILE_ERROR_RETURN(ERRNO, -1); 969 970 ssize_t rc; 971 972 if (!(file->stream.flags & FD_WRITE)) 973 { 974 DEBUGF("write(fd=%d,buf=%p,nb=%lu) - " 975 "descriptor is read-only mode\n", 976 fildes, buf, (unsigned long)nbyte); 977 FILE_ERROR(EBADF, -2); 978 } 979 980 rc = readwrite(file, (void *)buf, nbyte, true); 981 if (rc < 0) 982 FILE_ERROR(ERRNO, rc * 10 - 3); 983 984file_error: 985 RELEASE_FILESTR(READER, file); 986 return rc; 987} 988 989/* remove a file */ 990int remove(const char *path) 991{ 992 DEBUGF("remove(path=\"%s\")\n", path); 993 994 file_internal_lock_WRITER(); 995 int rc = remove_stream_internal(path, NULL, FF_FILE); 996 file_internal_unlock_WRITER(); 997 return rc; 998} 999 1000/* rename a file */ 1001int rename(const char *old, const char *new) 1002{ 1003 DEBUGF("rename(old=\"%s\",new=\"%s\")\n", old, new); 1004 1005 int rc, open1rc = -1, open2rc = -1; 1006 struct filestr_base oldstr, newstr; 1007 struct path_component_info oldinfo, newinfo; 1008 1009 file_internal_lock_WRITER(); 1010 1011 /* open 'old'; it must exist */ 1012 open1rc = open_stream_internal(old, FF_ANYTYPE | FF_PARENTINFO, &oldstr, 1013 &oldinfo); 1014 if (open1rc <= 0) 1015 { 1016 DEBUGF("Failed opening old: %d\n", open1rc); 1017 if (open1rc == 0) 1018 FILE_ERROR(ENOENT, -1); 1019 else 1020 FILE_ERROR(ERRNO, open1rc * 10 - 1); 1021 } 1022 1023 /* if 'old' is a directory then 'new' is also required to be one if 'new' 1024 is to be overwritten */ 1025 const bool are_dirs = oldinfo.attr & ATTR_DIRECTORY; 1026 1027 /* open new (may or may not exist) */ 1028 unsigned int callflags = FF_FILE; 1029 if (are_dirs) 1030 { 1031 /* if 'old' is found while parsing the new directory components then 1032 'new' contains path prefix that names 'old'; if new and old are in 1033 the same directory, this tests positive but that is checked later */ 1034 callflags = FF_DIR | FF_CHECKPREFIX; 1035 newinfo.prefixp = oldstr.infop; 1036 } 1037 1038 open2rc = open_stream_internal(new, callflags | FF_PARENTINFO, &newstr, 1039 &newinfo); 1040 if (open2rc < 0) 1041 { 1042 DEBUGF("Failed opening new file: %d\n", open2rc); 1043 FILE_ERROR(ERRNO, open2rc * 10 - 2); 1044 } 1045 1046#ifdef HAVE_MULTIVOLUME 1047 if (oldinfo.parentinfo.volume != newinfo.parentinfo.volume) 1048 { 1049 DEBUGF("Cross-device link\n"); 1050 FILE_ERROR(EXDEV, -3); 1051 } 1052#endif /* HAVE_MULTIVOLUME */ 1053 1054 /* if the parent is changing then this is a move, not a simple rename */ 1055 const bool is_move = !fat_file_is_same(&oldinfo.parentinfo.fatfile, 1056 &newinfo.parentinfo.fatfile); 1057 /* prefix found and moving? */ 1058 if (is_move && (newinfo.attr & ATTR_PREFIX)) 1059 { 1060 DEBUGF("New contains prefix that names old\n"); 1061 FILE_ERROR(EINVAL, -4); 1062 } 1063 1064 const char * const oldname = strmemdupa(oldinfo.name, oldinfo.length); 1065 const char * const newname = strmemdupa(newinfo.name, newinfo.length); 1066 bool is_overwrite = false; 1067 1068 if (open2rc > 0) 1069 { 1070 /* new name exists in parent; check if 'old' is overwriting 'new'; 1071 if it's the very same file, then it's just a rename */ 1072 is_overwrite = oldstr.bindp != newstr.bindp; 1073 1074 if (is_overwrite) 1075 { 1076 if (are_dirs) 1077 { 1078 /* the directory to be overwritten must be empty */ 1079 rc = test_dir_empty_internal(&newstr); 1080 if (rc < 0) 1081 FILE_ERROR(ERRNO, rc * 10 - 5); 1082 } 1083 } 1084 else if (!strcmp(newname, oldname)) /* case-only is ok */ 1085 { 1086 DEBUGF("No name change (success)\n"); 1087 rc = 0; 1088 FILE_ERROR(ERRNO, RC); 1089 } 1090 } 1091 else if (!are_dirs && (newinfo.attr & ATTR_DIRECTORY)) 1092 { 1093 /* even if new doesn't exist, canonical path type must match 1094 (ie. a directory path such as "/foo/bar/" when old names a file) */ 1095 DEBUGF("New path is a directory\n"); 1096 FILE_ERROR(EISDIR, -6); 1097 } 1098 1099 /* first, create the new entry so that there's never a time that the 1100 victim's data has no reference in the directory tree, that is, until 1101 everything else first succeeds */ 1102 struct file_base_info old_fileinfo = *oldstr.infop; 1103 rc = fat_rename(&newinfo.parentinfo.fatfile, &oldstr.infop->fatfile, 1104 newname); 1105 if (rc < 0) 1106 { 1107 DEBUGF("I/O error renaming file: %d\n", rc); 1108 FILE_ERROR(rc == FAT_RC_ENOSPC ? ENOSPC : EIO, rc * 10 - 7); 1109 } 1110 1111 if (is_overwrite) 1112 { 1113 /* 'new' would have been assigned its own directory entry and 1114 succeeded so at this point it is treated like a remove() call 1115 on the victim which preserves data until the last reference is 1116 closed */ 1117 rc = remove_stream_internal(NULL, &newstr, callflags); 1118 if (rc < 0) 1119 FILE_ERROR(ERRNO, rc * 10 - 8); 1120 } 1121 1122 fileop_onrename_internal(&oldstr, is_move ? &old_fileinfo : NULL, 1123 &newinfo.parentinfo, newname); 1124 1125file_error: 1126 /* for now, there is nothing to fail upon closing the old stream */ 1127 if (open1rc >= 0) 1128 close_stream_internal(&oldstr); 1129 1130 /* the 'new' stream could fail to close cleanly because it became 1131 impossible to remove its data if this was an overwrite operation */ 1132 if (open2rc >= 0) 1133 { 1134 int rc2 = close_stream_internal(&newstr); 1135 if (rc2 < 0 && rc >= 0) 1136 { 1137 DEBUGF("Success but failed closing new: %d\n", rc2); 1138 rc = rc2 * 10 - 9; 1139 } 1140 } 1141 1142 file_internal_unlock_WRITER(); 1143 return rc; 1144} 1145 1146/** Extensions **/ 1147 1148int modtime(const char *path, time_t modtime) 1149{ 1150 DEBUGF("modtime(path=\"%s\",modtime=%d)\n", path, (int) modtime); 1151 1152 int rc, open1rc = -1; 1153 struct filestr_base pathstr; 1154 struct path_component_info pathinfo; 1155 1156 file_internal_lock_WRITER(); 1157 1158 open1rc = open_stream_internal(path, FF_ANYTYPE | FF_PARENTINFO, 1159 &pathstr, &pathinfo); 1160 if (open1rc <= 0) 1161 { 1162 DEBUGF("Failed opening path: %d\n", open1rc); 1163 if (open1rc == 0) 1164 FILE_ERROR(ENOENT, -1); 1165 else 1166 FILE_ERROR(ERRNO, open1rc * 10 - 1); 1167 } 1168 1169 rc = fat_modtime(&pathinfo.parentinfo.fatfile, pathstr.fatstr.fatfilep, 1170 modtime); 1171 if (rc < 0) 1172 { 1173 DEBUGF("I/O error during modtime: %d\n", rc); 1174 FILE_ERROR(ERRNO, rc * 10 - 2); 1175 } 1176 1177file_error: 1178 if (open1rc >= 0) 1179 close_stream_internal(&pathstr); 1180 file_internal_unlock_WRITER(); 1181 return rc; 1182} 1183 1184/* get the binary size of a file (in bytes) */ 1185off_t filesize(int fildes) 1186{ 1187 struct filestr_desc * const file = GET_FILESTR(READER, fildes); 1188 if (!file) 1189 FILE_ERROR_RETURN(ERRNO, -1); 1190 1191 off_t rc; 1192 file_size_t size = *file->sizep; 1193 1194 if (size > FILE_SIZE_MAX) 1195 FILE_ERROR(EOVERFLOW, -2); 1196 1197 rc = (off_t)size; 1198file_error: 1199 RELEASE_FILESTR(READER, file); 1200 return rc; 1201} 1202 1203/* test if two file descriptors refer to the same file */ 1204int fsamefile(int fildes1, int fildes2) 1205{ 1206 struct filestr_desc * const file1 = GET_FILESTR(WRITER, fildes1); 1207 if (!file1) 1208 FILE_ERROR_RETURN(ERRNO, -1); 1209 1210 int rc = -2; 1211 1212 struct filestr_desc * const file2 = get_filestr(fildes2); 1213 if (file2) 1214 rc = file1->stream.bindp == file2->stream.bindp ? 1 : 0; 1215 1216 RELEASE_FILESTR(WRITER, file1); 1217 return rc; 1218} 1219 1220/* tell the relationship of path1 to path2 */ 1221int relate(const char *path1, const char *path2) 1222{ 1223 /* this is basically what rename() does but reduced to the relationship 1224 determination */ 1225 DEBUGF("relate(path1=\"%s\",path2=\"%s\")\n", path1, path2); 1226 1227 int rc, open1rc = -1, open2rc = -1; 1228 struct filestr_base str1, str2; 1229 struct path_component_info info1, info2; 1230 1231 file_internal_lock_WRITER(); 1232 1233 open1rc = open_stream_internal(path1, FF_ANYTYPE, &str1, &info1); 1234 if (open1rc <= 0) 1235 { 1236 DEBUGF("Failed opening path1: %d\n", open1rc); 1237 if (open1rc < 0) 1238 FILE_ERROR(ERRNO, open1rc * 10 - 1); 1239 else 1240 FILE_ERROR(ENOENT, -1); 1241 } 1242 1243 info2.prefixp = str1.infop; 1244 open2rc = open_stream_internal(path2, FF_ANYTYPE | FF_CHECKPREFIX, 1245 &str2, &info2); 1246 if (open2rc < 0) 1247 { 1248 DEBUGF("Failed opening path2: %d\n", open2rc); 1249 FILE_ERROR(ERRNO, open2rc * 10 - 2); 1250 } 1251 1252 rc = RELATE_DIFFERENT; 1253 1254 if (open2rc > 0) 1255 { 1256 if (str1.bindp == str2.bindp) 1257 rc = RELATE_SAME; 1258 else if (info2.attr & ATTR_PREFIX) 1259 rc = RELATE_PREFIX; 1260 } 1261 else /* open2rc == 0 */ 1262 { 1263 /* path1 existing and path2's final part not can only be a prefix or 1264 different */ 1265 if (info2.attr & ATTR_PREFIX) 1266 rc = RELATE_PREFIX; 1267 } 1268 1269file_error: 1270 if (open1rc >= 0) 1271 close_stream_internal(&str1); 1272 1273 if (open2rc >= 0) 1274 close_stream_internal(&str2); 1275 1276 file_internal_unlock_WRITER(); 1277 return rc; 1278} 1279 1280/* test file or directory existence */ 1281bool file_exists(const char *path) 1282{ 1283 file_internal_lock_WRITER(); 1284 bool rc = test_stream_exists_internal(path, FF_ANYTYPE) > 0; 1285 file_internal_unlock_WRITER(); 1286 return rc; 1287}