1 /*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * The Mach Operating System project at Carnegie-Mellon University. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)ufs.c 8.1 (Berkeley) 06/11/93 11 * 12 * 13 * Copyright (c) 1990, 1991 Carnegie Mellon University 14 * All Rights Reserved. 15 * 16 * Author: David Golub 17 * 18 * Permission to use, copy, modify and distribute this software and its 19 * documentation is hereby granted, provided that both the copyright 20 * notice and this permission notice appear in all copies of the 21 * software, derivative works or modified versions, and any portions 22 * thereof, and that both notices appear in supporting documentation. 23 * 24 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 25 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 26 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27 * 28 * Carnegie Mellon requests users of this software to return to 29 * 30 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31 * School of Computer Science 32 * Carnegie Mellon University 33 * Pittsburgh PA 15213-3890 34 * 35 * any improvements or extensions that they make and grant Carnegie the 36 * rights to redistribute these changes. 37 */ 38 39 /* 40 * Stand-alone file reading package. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/time.h> 45 #include <ufs/ffs/fs.h> 46 #include <ufs/ufs/dinode.h> 47 #include <ufs/ufs/dir.h> 48 #include <stand/stand.h> 49 50 /* 51 * In-core open file. 52 */ 53 struct file { 54 off_t f_seekp; /* seek pointer */ 55 struct fs *f_fs; /* pointer to super-block */ 56 struct dinode f_di; /* copy of on-disk inode */ 57 int f_nindir[NIADDR]; 58 /* number of blocks mapped by 59 indirect block at level i */ 60 char *f_blk[NIADDR]; /* buffer for indirect block at 61 level i */ 62 u_long f_blksize[NIADDR]; 63 /* size of buffer */ 64 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 65 char *f_buf; /* buffer for data block */ 66 u_int f_buf_size; /* size of data block */ 67 daddr_t f_buf_blkno; /* block number of data block */ 68 }; 69 70 /* 71 * Read a new inode into a file structure. 72 */ 73 static int 74 read_inode(inumber, f) 75 ino_t inumber; 76 struct open_file *f; 77 { 78 register struct file *fp = (struct file *)f->f_fsdata; 79 register struct fs *fs = fp->f_fs; 80 char *buf; 81 u_int rsize; 82 int rc; 83 84 /* 85 * Read inode and save it. 86 */ 87 buf = alloc(fs->fs_bsize); 88 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 89 fsbtodb(fs, itod(fs, inumber)), fs->fs_bsize, buf, &rsize); 90 if (rc) 91 goto out; 92 if (rsize != fs->fs_bsize) { 93 rc = EIO; 94 goto out; 95 } 96 97 { 98 register struct dinode *dp; 99 100 dp = (struct dinode *)buf; 101 fp->f_di = dp[itoo(fs, inumber)]; 102 } 103 104 /* 105 * Clear out the old buffers 106 */ 107 { 108 register int level; 109 110 for (level = 0; level < NIADDR; level++) 111 fp->f_blkno[level] = -1; 112 fp->f_buf_blkno = -1; 113 } 114 out: 115 free(buf, fs->fs_bsize); 116 return (0); 117 } 118 119 /* 120 * Given an offset in a file, find the disk block number that 121 * contains that block. 122 */ 123 static int 124 block_map(f, file_block, disk_block_p) 125 struct open_file *f; 126 daddr_t file_block; 127 daddr_t *disk_block_p; /* out */ 128 { 129 register struct file *fp = (struct file *)f->f_fsdata; 130 register struct fs *fs = fp->f_fs; 131 int level; 132 int idx; 133 daddr_t ind_block_num; 134 daddr_t *ind_p; 135 int rc; 136 137 /* 138 * Index structure of an inode: 139 * 140 * di_db[0..NDADDR-1] hold block numbers for blocks 141 * 0..NDADDR-1 142 * 143 * di_ib[0] index block 0 is the single indirect block 144 * holds block numbers for blocks 145 * NDADDR .. NDADDR + NINDIR(fs)-1 146 * 147 * di_ib[1] index block 1 is the double indirect block 148 * holds block numbers for INDEX blocks for blocks 149 * NDADDR + NINDIR(fs) .. 150 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 151 * 152 * di_ib[2] index block 2 is the triple indirect block 153 * holds block numbers for double-indirect 154 * blocks for blocks 155 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 156 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 157 * + NINDIR(fs)**3 - 1 158 */ 159 160 if (file_block < NDADDR) { 161 /* Direct block. */ 162 *disk_block_p = fp->f_di.di_db[file_block]; 163 return (0); 164 } 165 166 file_block -= NDADDR; 167 168 /* 169 * nindir[0] = NINDIR 170 * nindir[1] = NINDIR**2 171 * nindir[2] = NINDIR**3 172 * etc 173 */ 174 for (level = 0; level < NIADDR; level++) { 175 if (file_block < fp->f_nindir[level]) 176 break; 177 file_block -= fp->f_nindir[level]; 178 } 179 if (level == NIADDR) { 180 /* Block number too high */ 181 return (EFBIG); 182 } 183 184 ind_block_num = fp->f_di.di_ib[level]; 185 186 for (; level >= 0; level--) { 187 if (ind_block_num == 0) { 188 *disk_block_p = 0; /* missing */ 189 return (0); 190 } 191 192 if (fp->f_blkno[level] != ind_block_num) { 193 if (fp->f_blk[level] == (char *)0) 194 fp->f_blk[level] = 195 alloc(fs->fs_bsize); 196 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 197 fsbtodb(fp->f_fs, ind_block_num), 198 fs->fs_bsize, 199 fp->f_blk[level], 200 &fp->f_blksize[level]); 201 if (rc) 202 return (rc); 203 if (fp->f_blksize[level] != fs->fs_bsize) 204 return (EIO); 205 fp->f_blkno[level] = ind_block_num; 206 } 207 208 ind_p = (daddr_t *)fp->f_blk[level]; 209 210 if (level > 0) { 211 idx = file_block / fp->f_nindir[level - 1]; 212 file_block %= fp->f_nindir[level - 1]; 213 } else 214 idx = file_block; 215 216 ind_block_num = ind_p[idx]; 217 } 218 219 *disk_block_p = ind_block_num; 220 221 return (0); 222 } 223 224 /* 225 * Read a portion of a file into an internal buffer. Return 226 * the location in the buffer and the amount in the buffer. 227 */ 228 static int 229 buf_read_file(f, buf_p, size_p) 230 struct open_file *f; 231 char **buf_p; /* out */ 232 u_int *size_p; /* out */ 233 { 234 register struct file *fp = (struct file *)f->f_fsdata; 235 register struct fs *fs = fp->f_fs; 236 long off; 237 register daddr_t file_block; 238 daddr_t disk_block; 239 long block_size; 240 int rc; 241 242 off = blkoff(fs, fp->f_seekp); 243 file_block = lblkno(fs, fp->f_seekp); 244 block_size = dblksize(fs, &fp->f_di, file_block); 245 246 if (file_block != fp->f_buf_blkno) { 247 rc = block_map(f, file_block, &disk_block); 248 if (rc) 249 return (rc); 250 251 if (fp->f_buf == (char *)0) 252 fp->f_buf = alloc(fs->fs_bsize); 253 254 if (disk_block == 0) { 255 bzero(fp->f_buf, block_size); 256 fp->f_buf_size = block_size; 257 } else { 258 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 259 fsbtodb(fs, disk_block), 260 block_size, fp->f_buf, &fp->f_buf_size); 261 if (rc) 262 return (rc); 263 } 264 265 fp->f_buf_blkno = file_block; 266 } 267 268 /* 269 * Return address of byte in buffer corresponding to 270 * offset, and size of remainder of buffer after that 271 * byte. 272 */ 273 *buf_p = fp->f_buf + off; 274 *size_p = block_size - off; 275 276 /* 277 * But truncate buffer at end of file. 278 */ 279 if (*size_p > fp->f_di.di_size - fp->f_seekp) 280 *size_p = fp->f_di.di_size - fp->f_seekp; 281 282 return (0); 283 } 284 285 /* 286 * Search a directory for a name and return its 287 * i_number. 288 */ 289 static int 290 search_directory(name, f, inumber_p) 291 char *name; 292 struct open_file *f; 293 ino_t *inumber_p; /* out */ 294 { 295 register struct file *fp = (struct file *)f->f_fsdata; 296 register struct direct *dp; 297 struct direct *edp; 298 char *buf; 299 u_int buf_size; 300 int namlen, length; 301 int rc; 302 303 length = strlen(name); 304 305 fp->f_seekp = 0; 306 while (fp->f_seekp < fp->f_di.di_size) { 307 rc = buf_read_file(f, &buf, &buf_size); 308 if (rc) 309 return (rc); 310 311 dp = (struct direct *)buf; 312 edp = (struct direct *)(buf + buf_size); 313 while (dp < edp) { 314 if (dp->d_ino == (ino_t)0) 315 goto next; 316 #if BYTE_ORDER == LITTLE_ENDIAN 317 if (fp->f_fs->fs_maxsymlinklen <= 0) 318 namlen = dp->d_type; 319 else 320 #endif 321 namlen = dp->d_namlen; 322 if (namlen == length && 323 !strcmp(name, dp->d_name)) { 324 /* found entry */ 325 *inumber_p = dp->d_ino; 326 return (0); 327 } 328 next: 329 dp = (struct direct *)((char *)dp + dp->d_reclen); 330 } 331 fp->f_seekp += buf_size; 332 } 333 return (ENOENT); 334 } 335 336 /* 337 * Open a file. 338 */ 339 int 340 ufs_open(path, f) 341 char *path; 342 struct open_file *f; 343 { 344 register char *cp, *ncp; 345 register int c; 346 ino_t inumber, parent_inumber; 347 int nlinks = 0; 348 struct file *fp; 349 struct fs *fs; 350 int rc; 351 u_int buf_size; 352 #if 0 353 char namebuf[MAXPATHLEN+1]; 354 #endif 355 356 /* allocate file system specific data structure */ 357 fp = alloc(sizeof(struct file)); 358 bzero(fp, sizeof(struct file)); 359 f->f_fsdata = (void *)fp; 360 361 /* allocate space and read super block */ 362 fs = alloc(SBSIZE); 363 fp->f_fs = fs; 364 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 365 SBLOCK, SBSIZE, (char *)fs, &buf_size); 366 if (rc) 367 goto out; 368 369 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || 370 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { 371 rc = EINVAL; 372 goto out; 373 } 374 375 /* 376 * Calculate indirect block levels. 377 */ 378 { 379 register int mult; 380 register int level; 381 382 mult = 1; 383 for (level = 0; level < NIADDR; level++) { 384 mult *= NINDIR(fs); 385 fp->f_nindir[level] = mult; 386 } 387 } 388 389 inumber = ROOTINO; 390 if ((rc = read_inode(inumber, f)) != 0) 391 goto out; 392 393 cp = path; 394 while (*cp) { 395 396 /* 397 * Remove extra separators 398 */ 399 while (*cp == '/') 400 cp++; 401 if (*cp == '\0') 402 break; 403 404 /* 405 * Check that current node is a directory. 406 */ 407 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 408 rc = ENOTDIR; 409 goto out; 410 } 411 412 /* 413 * Get next component of path name. 414 */ 415 { 416 register int len = 0; 417 418 ncp = cp; 419 while ((c = *cp) != '\0' && c != '/') { 420 if (++len > MAXNAMLEN) { 421 rc = ENOENT; 422 goto out; 423 } 424 cp++; 425 } 426 *cp = '\0'; 427 } 428 429 /* 430 * Look up component in current directory. 431 * Save directory inumber in case we find a 432 * symbolic link. 433 */ 434 parent_inumber = inumber; 435 rc = search_directory(ncp, f, &inumber); 436 *cp = c; 437 if (rc) 438 goto out; 439 440 /* 441 * Open next component. 442 */ 443 if ((rc = read_inode(inumber, f)) != 0) 444 goto out; 445 446 #if 0 447 /* 448 * Check for symbolic link. 449 */ 450 if ((fp->i_mode & IFMT) == IFLNK) { 451 int link_len = fp->f_di.di_size; 452 int len; 453 454 len = strlen(cp) + 1; 455 456 if (fp->f_di.di_size >= MAXPATHLEN - 1 || 457 ++nlinks > MAXSYMLINKS) { 458 rc = ENOENT; 459 goto out; 460 } 461 462 strcpy(&namebuf[link_len], cp); 463 464 if ((fp->i_flags & IC_FASTLINK) != 0) { 465 bcopy(fp->i_symlink, namebuf, (unsigned) link_len); 466 } else { 467 /* 468 * Read file for symbolic link 469 */ 470 char *buf; 471 u_int buf_size; 472 daddr_t disk_block; 473 register struct fs *fs = fp->f_fs; 474 475 (void) block_map(f, (daddr_t)0, &disk_block); 476 rc = device_read(&fp->f_dev, 477 fsbtodb(fs, disk_block), 478 blksize(fs, fp, 0), 479 &buf, &buf_size); 480 if (rc) 481 goto out; 482 483 bcopy((char *)buf, namebuf, (unsigned)link_len); 484 free(buf, buf_size); 485 } 486 487 /* 488 * If relative pathname, restart at parent directory. 489 * If absolute pathname, restart at root. 490 */ 491 cp = namebuf; 492 if (*cp != '/') 493 inumber = parent_inumber; 494 else 495 inumber = (ino_t)ROOTINO; 496 497 if ((rc = read_inode(inumber, fp)) != 0) 498 goto out; 499 } 500 #endif 501 } 502 503 /* 504 * Found terminal component. 505 */ 506 rc = 0; 507 out: 508 if (rc) 509 free(fp, sizeof(struct file)); 510 return (rc); 511 } 512 513 int 514 ufs_close(f) 515 struct open_file *f; 516 { 517 register struct file *fp = (struct file *)f->f_fsdata; 518 int level; 519 520 f->f_fsdata = (void *)0; 521 if (fp == (struct file *)0) 522 return (0); 523 524 for (level = 0; level < NIADDR; level++) { 525 if (fp->f_blk[level]) 526 free(fp->f_blk[level], fp->f_fs->fs_bsize); 527 } 528 if (fp->f_buf) 529 free(fp->f_buf, fp->f_fs->fs_bsize); 530 free(fp->f_fs, SBSIZE); 531 free(fp, sizeof(struct file)); 532 return (0); 533 } 534 535 /* 536 * Copy a portion of a file into kernel memory. 537 * Cross block boundaries when necessary. 538 */ 539 int 540 ufs_read(f, start, size, resid) 541 struct open_file *f; 542 char *start; 543 u_int size; 544 u_int *resid; /* out */ 545 { 546 register struct file *fp = (struct file *)f->f_fsdata; 547 register u_int csize; 548 char *buf; 549 u_int buf_size; 550 int rc = 0; 551 552 while (size != 0) { 553 if (fp->f_seekp >= fp->f_di.di_size) 554 break; 555 556 rc = buf_read_file(f, &buf, &buf_size); 557 if (rc) 558 break; 559 560 csize = size; 561 if (csize > buf_size) 562 csize = buf_size; 563 564 bcopy(buf, start, csize); 565 566 fp->f_seekp += csize; 567 start += csize; 568 size -= csize; 569 } 570 if (resid) 571 *resid = size; 572 return (rc); 573 } 574 575 /* 576 * Not implemented. 577 */ 578 int 579 ufs_write(f, start, size, resid) 580 struct open_file *f; 581 char *start; 582 u_int size; 583 u_int *resid; /* out */ 584 { 585 586 return (EROFS); 587 } 588 589 off_t 590 ufs_seek(f, offset, where) 591 struct open_file *f; 592 off_t offset; 593 int where; 594 { 595 register struct file *fp = (struct file *)f->f_fsdata; 596 597 switch (where) { 598 case SEEK_SET: 599 fp->f_seekp = offset; 600 break; 601 case SEEK_CUR: 602 fp->f_seekp += offset; 603 break; 604 case SEEK_END: 605 fp->f_seekp = fp->f_di.di_size - offset; 606 break; 607 default: 608 return (-1); 609 } 610 return (fp->f_seekp); 611 } 612 613 int 614 ufs_stat(f, sb) 615 struct open_file *f; 616 struct stat *sb; 617 { 618 register struct file *fp = (struct file *)f->f_fsdata; 619 620 /* only important stuff */ 621 sb->st_mode = fp->f_di.di_mode; 622 sb->st_uid = fp->f_di.di_uid; 623 sb->st_gid = fp->f_di.di_gid; 624 sb->st_size = fp->f_di.di_size; 625 return (0); 626 } 627