dosfs.c (279931) | dosfs.c (298230) |
---|---|
1/* 2 * Copyright (c) 1996, 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 12 unchanged lines hidden (view full) --- 21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> | 1/* 2 * Copyright (c) 1996, 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 12 unchanged lines hidden (view full) --- 21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> |
29__FBSDID("$FreeBSD: head/lib/libstand/dosfs.c 279931 2015-03-12 17:10:04Z jhb $"); | 29__FBSDID("$FreeBSD: head/lib/libstand/dosfs.c 298230 2016-04-18 23:09:22Z allanjude $"); |
30 31/* 32 * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, 33 * also supports VFAT. 34 */ 35 36#include <sys/types.h> 37#include <string.h> --- 88 unchanged lines hidden (view full) --- 126 127/* Does cluster number reference a valid data cluster? */ 128#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) 129 130/* Get start cluster from directory entry */ 131#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ 132 ((u_int)cv2((de)->dex.h_clus) << 16) | \ 133 cv2((de)->clus)) | 30 31/* 32 * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, 33 * also supports VFAT. 34 */ 35 36#include <sys/types.h> 37#include <string.h> --- 88 unchanged lines hidden (view full) --- 126 127/* Does cluster number reference a valid data cluster? */ 128#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) 129 130/* Get start cluster from directory entry */ 131#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ 132 ((u_int)cv2((de)->dex.h_clus) << 16) | \ 133 cv2((de)->clus)) |
134 | 134 135/* 136 * fat cache metadata 137 */ 138struct fatcache { 139 int unit; /* disk unit number */ 140 int size; /* buffer (and fat) size in sectors */ 141 u_char *buf; 142}; 143 144static struct fatcache fat; 145 |
135static int dosunmount(DOS_FS *); 136static int parsebs(DOS_FS *, DOS_BS *); 137static int namede(DOS_FS *, const char *, DOS_DE **); 138static int lookup(DOS_FS *, u_int, const char *, DOS_DE **); 139static void cp_xdnm(u_char *, DOS_XDE *); 140static void cp_sfn(u_char *, DOS_DE *); 141static off_t fsize(DOS_FS *, DOS_DE *); 142static int fatcnt(DOS_FS *, u_int); 143static int fatget(DOS_FS *, u_int *); 144static int fatend(u_int, u_int); 145static int ioread(DOS_FS *, u_int, void *, u_int); | 146static int dosunmount(DOS_FS *); 147static int parsebs(DOS_FS *, DOS_BS *); 148static int namede(DOS_FS *, const char *, DOS_DE **); 149static int lookup(DOS_FS *, u_int, const char *, DOS_DE **); 150static void cp_xdnm(u_char *, DOS_XDE *); 151static void cp_sfn(u_char *, DOS_DE *); 152static off_t fsize(DOS_FS *, DOS_DE *); 153static int fatcnt(DOS_FS *, u_int); 154static int fatget(DOS_FS *, u_int *); 155static int fatend(u_int, u_int); 156static int ioread(DOS_FS *, u_int, void *, u_int); |
146static int iobuf(DOS_FS *, u_int); 147static int ioget(struct open_file *, u_int, void *, u_int); | 157static int ioget(struct open_file *, daddr_t, size_t, void *, u_int); |
148 | 158 |
159static void 160dos_read_fat(DOS_FS *fs, struct open_file *fd) 161{ 162 struct devdesc *dd = fd->f_devdata; 163 164 if (fat.buf != NULL) { /* can we reuse old buffer? */ 165 if (fat.size != fs->spf) { 166 free(fat.buf); /* no, free old buffer */ 167 fat.buf = NULL; 168 } 169 } 170 171 if (fat.buf == NULL) 172 fat.buf = malloc(secbyt(fs->spf)); 173 174 if (fat.buf != NULL) { 175 if (ioget(fd, fs->lsnfat, 0, fat.buf, secbyt(fs->spf)) == 0) { 176 fat.size = fs->spf; 177 fat.unit = dd->d_unit; 178 return; 179 } 180 } 181 if (fat.buf != NULL) /* got IO error */ 182 free(fat.buf); 183 fat.buf = NULL; 184 fat.unit = -1; /* impossible unit */ 185 fat.size = 0; 186} 187 |
|
149/* 150 * Mount DOS filesystem 151 */ 152static int 153dos_mount(DOS_FS *fs, struct open_file *fd) 154{ 155 int err; | 188/* 189 * Mount DOS filesystem 190 */ 191static int 192dos_mount(DOS_FS *fs, struct open_file *fd) 193{ 194 int err; |
195 struct devdesc *dd = fd->f_devdata; 196 u_char *buf; |
|
156 157 bzero(fs, sizeof(DOS_FS)); 158 fs->fd = fd; | 197 198 bzero(fs, sizeof(DOS_FS)); 199 fs->fd = fd; |
159 if ((err = !(fs->buf = malloc(SECSIZ)) ? errno : 0) || 160 (err = ioget(fs->fd, 0, fs->buf, 1)) || 161 (err = parsebs(fs, (DOS_BS *)fs->buf))) { | 200 201 if ((err = !(buf = malloc(secbyt(1))) ? errno : 0) || 202 (err = ioget(fs->fd, 0, 0, buf, secbyt(1))) || 203 (err = parsebs(fs, (DOS_BS *)buf))) { 204 if (buf != NULL) 205 free(buf); |
162 (void)dosunmount(fs); 163 return(err); 164 } | 206 (void)dosunmount(fs); 207 return(err); 208 } |
209 free(buf); 210 211 if (fat.buf == NULL || fat.unit != dd->d_unit) 212 dos_read_fat(fs, fd); 213 |
|
165 fs->root = dot[0]; 166 fs->root.name[0] = ' '; 167 if (fs->fatsz == 32) { 168 fs->root.clus[0] = fs->rdcl & 0xff; 169 fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; 170 fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; 171 fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; 172 } --- 16 unchanged lines hidden (view full) --- 189} 190 191/* 192 * Common code shared by dos_mount() and dos_unmount() 193 */ 194static int 195dosunmount(DOS_FS *fs) 196{ | 214 fs->root = dot[0]; 215 fs->root.name[0] = ' '; 216 if (fs->fatsz == 32) { 217 fs->root.clus[0] = fs->rdcl & 0xff; 218 fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; 219 fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; 220 fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; 221 } --- 16 unchanged lines hidden (view full) --- 238} 239 240/* 241 * Common code shared by dos_mount() and dos_unmount() 242 */ 243static int 244dosunmount(DOS_FS *fs) 245{ |
197 if (fs->buf) 198 free(fs->buf); | |
199 free(fs); 200 return(0); 201} 202 203/* 204 * Open DOS file 205 */ 206static int --- 40 unchanged lines hidden (view full) --- 247static int 248dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) 249{ 250 off_t size; 251 u_int nb, off, clus, c, cnt, n; 252 DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 253 int err = 0; 254 | 246 free(fs); 247 return(0); 248} 249 250/* 251 * Open DOS file 252 */ 253static int --- 40 unchanged lines hidden (view full) --- 294static int 295dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) 296{ 297 off_t size; 298 u_int nb, off, clus, c, cnt, n; 299 DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; 300 int err = 0; 301 |
302 /* 303 * as ioget() can be called *a lot*, use twiddle here. 304 * also 4 seems to be good value not to slow loading down too much: 305 * with 270MB file (~540k ioget() calls, twiddle can easily waste 4-5sec. 306 */ 307 twiddle(4); |
|
255 nb = (u_int)nbyte; 256 if ((size = fsize(f->fs, &f->de)) == -1) 257 return EINVAL; 258 if (nb > (n = size - f->offset)) | 308 nb = (u_int)nbyte; 309 if ((size = fsize(f->fs, &f->de)) == -1) 310 return EINVAL; 311 if (nb > (n = size - f->offset)) |
259 nb = n; | 312 nb = n; |
260 off = f->offset; 261 if ((clus = stclus(f->fs->fatsz, &f->de))) | 313 off = f->offset; 314 if ((clus = stclus(f->fs->fatsz, &f->de))) |
262 off &= f->fs->bsize - 1; | 315 off &= f->fs->bsize - 1; |
263 c = f->c; 264 cnt = nb; 265 while (cnt) { | 316 c = f->c; 317 cnt = nb; 318 while (cnt) { |
266 n = 0; 267 if (!c) { 268 if ((c = clus)) 269 n = bytblk(f->fs, f->offset); 270 } else if (!off) 271 n++; 272 while (n--) { 273 if ((err = fatget(f->fs, &c))) | 319 n = 0; 320 if (!c) { 321 if ((c = clus)) 322 n = bytblk(f->fs, f->offset); 323 } else if (!off) 324 n++; 325 while (n--) { 326 if ((err = fatget(f->fs, &c))) |
274 goto out; | 327 goto out; |
275 if (!okclus(f->fs, c)) { | 328 if (!okclus(f->fs, c)) { |
276 err = EINVAL; 277 goto out; 278 } | 329 err = EINVAL; 330 goto out; 331 } |
279 } 280 if (!clus || (n = f->fs->bsize - off) > cnt) 281 n = cnt; 282 if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : 283 secbyt(f->fs->lsndir)) + off, 284 buf, n))) | 332 } 333 if (!clus || (n = f->fs->bsize - off) > cnt) 334 n = cnt; 335 if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : 336 secbyt(f->fs->lsndir)) + off, buf, n))) |
285 goto out; | 337 goto out; |
286 f->offset += n; 287 f->c = c; 288 off = 0; 289 buf = (char *)buf + n; 290 cnt -= n; | 338 f->offset += n; 339 f->c = c; 340 off = 0; 341 buf = (char *)buf + n; 342 cnt -= n; |
291 } 292 out: 293 if (resid) 294 *resid = nbyte - nb + cnt; 295 return(err); 296} 297 298/* --- 60 unchanged lines hidden (view full) --- 359 sb->st_uid = 0; 360 sb->st_gid = 0; 361 if ((sb->st_size = fsize(f->fs, &f->de)) == -1) 362 return EINVAL; 363 return (0); 364} 365 366static int | 343 } 344 out: 345 if (resid) 346 *resid = nbyte - nb + cnt; 347 return(err); 348} 349 350/* --- 60 unchanged lines hidden (view full) --- 411 sb->st_uid = 0; 412 sb->st_gid = 0; 413 if ((sb->st_size = fsize(f->fs, &f->de)) == -1) 414 return EINVAL; 415 return (0); 416} 417 418static int |
419dos_checksum(char *name, char *ext) 420{ 421 int x, i; 422 char buf[11]; 423 424 bcopy(name, buf, 8); 425 bcopy(ext, buf+8, 3); 426 x = 0; 427 for (i = 0; i < 11; i++) { 428 x = ((x & 1) << 7) | (x >> 1); 429 x += buf[i]; 430 x &= 0xff; 431 } 432 return (x); 433} 434 435static int |
|
367dos_readdir(struct open_file *fd, struct dirent *d) 368{ 369 /* DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; */ 370 u_char fn[261]; 371 DOS_DIR dd; 372 size_t res; 373 u_int chk, i, x, xdn; 374 int err; --- 37 unchanged lines hidden (view full) --- 412 } 413 cp_xdnm(fn, &dd.xde); 414 } else { 415 /* skip only volume label entries */ 416 continue; 417 } 418 } else { 419 if (xdn == 1) { | 436dos_readdir(struct open_file *fd, struct dirent *d) 437{ 438 /* DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; */ 439 u_char fn[261]; 440 DOS_DIR dd; 441 size_t res; 442 u_int chk, i, x, xdn; 443 int err; --- 37 unchanged lines hidden (view full) --- 481 } 482 cp_xdnm(fn, &dd.xde); 483 } else { 484 /* skip only volume label entries */ 485 continue; 486 } 487 } else { 488 if (xdn == 1) { |
420 x = 0; 421 for (i = 0; i < 11; i++) { 422 x = ((x & 1) << 7) | (x >> 1); 423 x += dd.de.name[i]; 424 x &= 0xff; 425 } | 489 x = dos_checksum(dd.de.name, dd.de.ext); |
426 if (x == chk) 427 break; 428 } else { 429 cp_sfn(fn, &dd.de); 430 break; 431 } 432 x = 0; 433 } --- 116 unchanged lines hidden (view full) --- 550 for (;;) { 551 if (!clus && !lsec) 552 lsec = fs->lsndir; 553 else if (okclus(fs, clus)) 554 lsec = blklsn(fs, clus); 555 else 556 return EINVAL; 557 for (sec = 0; sec < nsec; sec++) { | 490 if (x == chk) 491 break; 492 } else { 493 cp_sfn(fn, &dd.de); 494 break; 495 } 496 x = 0; 497 } --- 116 unchanged lines hidden (view full) --- 614 for (;;) { 615 if (!clus && !lsec) 616 lsec = fs->lsndir; 617 else if (okclus(fs, clus)) 618 lsec = blklsn(fs, clus); 619 else 620 return EINVAL; 621 for (sec = 0; sec < nsec; sec++) { |
558 if ((err = ioget(fs->fd, lsec + sec, dir, 1))) | 622 if ((err = ioget(fs->fd, lsec + sec, 0, dir, secbyt(1)))) |
559 return err; 560 for (ent = 0; ent < DEPSEC; ent++) { 561 if (!*dir[ent].de.name) 562 return ENOENT; 563 if (*dir[ent].de.name != 0xe5) { 564 if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { 565 x = dir[ent].xde.seq; 566 if (x & 0x40 || (x + 1 == xdn && --- 5 unchanged lines hidden (view full) --- 572 if (x >= 1 && x <= 20) { 573 cp_xdnm(lfn, &dir[ent].xde); 574 xdn = x; 575 continue; 576 } 577 } 578 } else if (!(dir[ent].de.attr & FA_LABEL)) { 579 if ((ok = xdn == 1)) { | 623 return err; 624 for (ent = 0; ent < DEPSEC; ent++) { 625 if (!*dir[ent].de.name) 626 return ENOENT; 627 if (*dir[ent].de.name != 0xe5) { 628 if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { 629 x = dir[ent].xde.seq; 630 if (x & 0x40 || (x + 1 == xdn && --- 5 unchanged lines hidden (view full) --- 636 if (x >= 1 && x <= 20) { 637 cp_xdnm(lfn, &dir[ent].xde); 638 xdn = x; 639 continue; 640 } 641 } 642 } else if (!(dir[ent].de.attr & FA_LABEL)) { 643 if ((ok = xdn == 1)) { |
580 for (x = 0, i = 0; i < 11; i++) 581 x = ((((x & 1) << 7) | (x >> 1)) + 582 dir[ent].de.name[i]) & 0xff; | 644 x = dos_checksum(dir[ent].de.name, dir[ent].de.ext); |
583 ok = chk == x && 584 !strcasecmp(name, (const char *)lfn); 585 } 586 if (!ok) { 587 cp_sfn(sfn, &dir[ent].de); 588 ok = !strcasecmp(name, (const char *)sfn); 589 } 590 if (ok) { --- 103 unchanged lines hidden (view full) --- 694 695 for (n = 0; okclus(fs, c); n++) 696 if (fatget(fs, &c)) 697 return -1; 698 return fatend(fs->fatsz, c) ? n : -1; 699} 700 701/* | 645 ok = chk == x && 646 !strcasecmp(name, (const char *)lfn); 647 } 648 if (!ok) { 649 cp_sfn(sfn, &dir[ent].de); 650 ok = !strcasecmp(name, (const char *)sfn); 651 } 652 if (ok) { --- 103 unchanged lines hidden (view full) --- 756 757 for (n = 0; okclus(fs, c); n++) 758 if (fatget(fs, &c)) 759 return -1; 760 return fatend(fs->fatsz, c) ? n : -1; 761} 762 763/* |
702 * Get next cluster in cluster chain | 764 * Get next cluster in cluster chain. Use in core fat cache unless another 765 * device replaced it. |
703 */ 704static int 705fatget(DOS_FS *fs, u_int *c) 706{ 707 u_char buf[4]; | 766 */ 767static int 768fatget(DOS_FS *fs, u_int *c) 769{ 770 u_char buf[4]; |
708 u_int x; 709 int err; | 771 u_char *s; 772 u_int x, offset, off, n, nbyte, lsec; 773 struct devdesc *dd = fs->fd->f_devdata; 774 int err = 0; |
710 | 775 |
711 err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, 712 fs->fatsz != 32 ? 2 : 4); 713 if (err) 714 return err; | 776 if (fat.unit != dd->d_unit) { 777 /* fat cache was changed to another device, dont use it */ 778 err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, 779 fs->fatsz != 32 ? 2 : 4); 780 if (err) 781 return err; 782 } else { 783 offset = fatoff(fs->fatsz, *c); 784 nbyte = fs->fatsz != 32 ? 2 : 4; 785 786 s = buf; 787 if ((off = offset & (SECSIZ - 1))) { 788 offset -= off; 789 lsec = bytsec(offset); 790 offset += SECSIZ; 791 if ((n = SECSIZ - off) > nbyte) 792 n = nbyte; 793 memcpy(s, fat.buf + secbyt(lsec) + off, n); 794 s += n; 795 nbyte -= n; 796 } 797 n = nbyte & (SECSIZ - 1); 798 if (nbyte -= n) { 799 memcpy(s, fat.buf + secbyt(bytsec(offset)), nbyte); 800 offset += nbyte; 801 s += nbyte; 802 } 803 if (n) 804 memcpy(s, fat.buf + secbyt(bytsec(offset)), n); 805 } 806 |
715 x = fs->fatsz != 32 ? cv2(buf) : cv4(buf); 716 *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x; | 807 x = fs->fatsz != 32 ? cv2(buf) : cv4(buf); 808 *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x; |
717 return 0; | 809 return (0); |
718} 719 720/* 721 * Is cluster an end-of-chain marker? 722 */ 723static int 724fatend(u_int sz, u_int c) 725{ --- 8 unchanged lines hidden (view full) --- 734{ 735 char *s; 736 u_int off, n; 737 int err; 738 739 s = buf; 740 if ((off = offset & (SECSIZ - 1))) { 741 offset -= off; | 810} 811 812/* 813 * Is cluster an end-of-chain marker? 814 */ 815static int 816fatend(u_int sz, u_int c) 817{ --- 8 unchanged lines hidden (view full) --- 826{ 827 char *s; 828 u_int off, n; 829 int err; 830 831 s = buf; 832 if ((off = offset & (SECSIZ - 1))) { 833 offset -= off; |
742 if ((err = iobuf(fs, bytsec(offset)))) 743 return err; 744 offset += SECSIZ; | |
745 if ((n = SECSIZ - off) > nbyte) 746 n = nbyte; | 834 if ((n = SECSIZ - off) > nbyte) 835 n = nbyte; |
747 memcpy(s, fs->buf + off, n); | 836 if ((err = ioget(fs->fd, bytsec(offset), off, s, n))) 837 return err; 838 offset += SECSIZ; |
748 s += n; 749 nbyte -= n; 750 } 751 n = nbyte & (SECSIZ - 1); 752 if (nbyte -= n) { | 839 s += n; 840 nbyte -= n; 841 } 842 n = nbyte & (SECSIZ - 1); 843 if (nbyte -= n) { |
753 if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte)))) | 844 if ((err = ioget(fs->fd, bytsec(offset), 0, s, nbyte))) |
754 return err; 755 offset += nbyte; 756 s += nbyte; 757 } 758 if (n) { | 845 return err; 846 offset += nbyte; 847 s += nbyte; 848 } 849 if (n) { |
759 if ((err = iobuf(fs, bytsec(offset)))) | 850 if ((err = ioget(fs->fd, bytsec(offset), 0, s, n))) |
760 return err; | 851 return err; |
761 memcpy(s, fs->buf, n); | |
762 } 763 return 0; 764} 765 766/* | 852 } 853 return 0; 854} 855 856/* |
767 * Buffered sector-based I/O primitive 768 */ 769static int 770iobuf(DOS_FS *fs, u_int lsec) 771{ 772 int err; 773 774 if (fs->bufsec != lsec) { 775 if ((err = ioget(fs->fd, lsec, fs->buf, 1))) 776 return err; 777 fs->bufsec = lsec; 778 } 779 return 0; 780} 781 782/* | |
783 * Sector-based I/O primitive 784 */ 785static int | 857 * Sector-based I/O primitive 858 */ 859static int |
786ioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec) | 860ioget(struct open_file *fd, daddr_t lsec, size_t offset, void *buf, u_int size) |
787{ | 861{ |
788 int err; 789 790 twiddle(1); 791 if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, 792 secbyt(nsec), buf, NULL))) 793 return(err); 794 return(0); | 862 return ((fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, offset, 863 size, buf, NULL)); |
795} | 864} |