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.2 (Berkeley) 11/30/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_int 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, ino_to_fsba(fs, inumber)), fs->fs_bsize, 90 buf, &rsize); 91 if (rc) 92 goto out; 93 if (rsize != fs->fs_bsize) { 94 rc = EIO; 95 goto out; 96 } 97 98 { 99 register struct dinode *dp; 100 101 dp = (struct dinode *)buf; 102 fp->f_di = dp[ino_to_fsbo(fs, inumber)]; 103 } 104 105 /* 106 * Clear out the old buffers 107 */ 108 { 109 register int level; 110 111 for (level = 0; level < NIADDR; level++) 112 fp->f_blkno[level] = -1; 113 fp->f_buf_blkno = -1; 114 } 115 out: 116 free(buf, fs->fs_bsize); 117 return (0); 118 } 119 120 /* 121 * Given an offset in a file, find the disk block number that 122 * contains that block. 123 */ 124 static int 125 block_map(f, file_block, disk_block_p) 126 struct open_file *f; 127 daddr_t file_block; 128 daddr_t *disk_block_p; /* out */ 129 { 130 register struct file *fp = (struct file *)f->f_fsdata; 131 register struct fs *fs = fp->f_fs; 132 int level; 133 int idx; 134 daddr_t ind_block_num; 135 daddr_t *ind_p; 136 int rc; 137 138 /* 139 * Index structure of an inode: 140 * 141 * di_db[0..NDADDR-1] hold block numbers for blocks 142 * 0..NDADDR-1 143 * 144 * di_ib[0] index block 0 is the single indirect block 145 * holds block numbers for blocks 146 * NDADDR .. NDADDR + NINDIR(fs)-1 147 * 148 * di_ib[1] index block 1 is the double indirect block 149 * holds block numbers for INDEX blocks for blocks 150 * NDADDR + NINDIR(fs) .. 151 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 152 * 153 * di_ib[2] index block 2 is the triple indirect block 154 * holds block numbers for double-indirect 155 * blocks for blocks 156 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 157 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 158 * + NINDIR(fs)**3 - 1 159 */ 160 161 if (file_block < NDADDR) { 162 /* Direct block. */ 163 *disk_block_p = fp->f_di.di_db[file_block]; 164 return (0); 165 } 166 167 file_block -= NDADDR; 168 169 /* 170 * nindir[0] = NINDIR 171 * nindir[1] = NINDIR**2 172 * nindir[2] = NINDIR**3 173 * etc 174 */ 175 for (level = 0; level < NIADDR; level++) { 176 if (file_block < fp->f_nindir[level]) 177 break; 178 file_block -= fp->f_nindir[level]; 179 } 180 if (level == NIADDR) { 181 /* Block number too high */ 182 return (EFBIG); 183 } 184 185 ind_block_num = fp->f_di.di_ib[level]; 186 187 for (; level >= 0; level--) { 188 if (ind_block_num == 0) { 189 *disk_block_p = 0; /* missing */ 190 return (0); 191 } 192 193 if (fp->f_blkno[level] != ind_block_num) { 194 if (fp->f_blk[level] == (char *)0) 195 fp->f_blk[level] = 196 alloc(fs->fs_bsize); 197 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 198 fsbtodb(fp->f_fs, ind_block_num), 199 fs->fs_bsize, 200 fp->f_blk[level], 201 &fp->f_blksize[level]); 202 if (rc) 203 return (rc); 204 if (fp->f_blksize[level] != fs->fs_bsize) 205 return (EIO); 206 fp->f_blkno[level] = ind_block_num; 207 } 208 209 ind_p = (daddr_t *)fp->f_blk[level]; 210 211 if (level > 0) { 212 idx = file_block / fp->f_nindir[level - 1]; 213 file_block %= fp->f_nindir[level - 1]; 214 } else 215 idx = file_block; 216 217 ind_block_num = ind_p[idx]; 218 } 219 220 *disk_block_p = ind_block_num; 221 222 return (0); 223 } 224 225 /* 226 * Read a portion of a file into an internal buffer. Return 227 * the location in the buffer and the amount in the buffer. 228 */ 229 static int 230 buf_read_file(f, buf_p, size_p) 231 struct open_file *f; 232 char **buf_p; /* out */ 233 u_int *size_p; /* out */ 234 { 235 register struct file *fp = (struct file *)f->f_fsdata; 236 register struct fs *fs = fp->f_fs; 237 long off; 238 register daddr_t file_block; 239 daddr_t disk_block; 240 long block_size; 241 int rc; 242 243 off = blkoff(fs, fp->f_seekp); 244 file_block = lblkno(fs, fp->f_seekp); 245 block_size = dblksize(fs, &fp->f_di, file_block); 246 247 if (file_block != fp->f_buf_blkno) { 248 rc = block_map(f, file_block, &disk_block); 249 if (rc) 250 return (rc); 251 252 if (fp->f_buf == (char *)0) 253 fp->f_buf = alloc(fs->fs_bsize); 254 255 if (disk_block == 0) { 256 bzero(fp->f_buf, block_size); 257 fp->f_buf_size = block_size; 258 } else { 259 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 260 fsbtodb(fs, disk_block), 261 block_size, fp->f_buf, &fp->f_buf_size); 262 if (rc) 263 return (rc); 264 } 265 266 fp->f_buf_blkno = file_block; 267 } 268 269 /* 270 * Return address of byte in buffer corresponding to 271 * offset, and size of remainder of buffer after that 272 * byte. 273 */ 274 *buf_p = fp->f_buf + off; 275 *size_p = block_size - off; 276 277 /* 278 * But truncate buffer at end of file. 279 */ 280 if (*size_p > fp->f_di.di_size - fp->f_seekp) 281 *size_p = fp->f_di.di_size - fp->f_seekp; 282 283 return (0); 284 } 285 286 /* 287 * Search a directory for a name and return its 288 * i_number. 289 */ 290 static int 291 search_directory(name, f, inumber_p) 292 char *name; 293 struct open_file *f; 294 ino_t *inumber_p; /* out */ 295 { 296 register struct file *fp = (struct file *)f->f_fsdata; 297 register struct direct *dp; 298 struct direct *edp; 299 char *buf; 300 u_int buf_size; 301 int namlen, length; 302 int rc; 303 304 length = strlen(name); 305 306 fp->f_seekp = 0; 307 while (fp->f_seekp < fp->f_di.di_size) { 308 rc = buf_read_file(f, &buf, &buf_size); 309 if (rc) 310 return (rc); 311 312 dp = (struct direct *)buf; 313 edp = (struct direct *)(buf + buf_size); 314 while (dp < edp) { 315 if (dp->d_ino == (ino_t)0) 316 goto next; 317 #if BYTE_ORDER == LITTLE_ENDIAN 318 if (fp->f_fs->fs_maxsymlinklen <= 0) 319 namlen = dp->d_type; 320 else 321 #endif 322 namlen = dp->d_namlen; 323 if (namlen == length && 324 !strcmp(name, dp->d_name)) { 325 /* found entry */ 326 *inumber_p = dp->d_ino; 327 return (0); 328 } 329 next: 330 dp = (struct direct *)((char *)dp + dp->d_reclen); 331 } 332 fp->f_seekp += buf_size; 333 } 334 return (ENOENT); 335 } 336 337 /* 338 * Open a file. 339 */ 340 int 341 ufs_open(path, f) 342 char *path; 343 struct open_file *f; 344 { 345 register char *cp, *ncp; 346 register int c; 347 ino_t inumber, parent_inumber; 348 int nlinks = 0; 349 struct file *fp; 350 struct fs *fs; 351 int rc; 352 u_int buf_size; 353 #if 0 354 char namebuf[MAXPATHLEN+1]; 355 #endif 356 357 /* allocate file system specific data structure */ 358 fp = alloc(sizeof(struct file)); 359 bzero(fp, sizeof(struct file)); 360 f->f_fsdata = (void *)fp; 361 362 /* allocate space and read super block */ 363 fs = alloc(SBSIZE); 364 fp->f_fs = fs; 365 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 366 SBLOCK, SBSIZE, (char *)fs, &buf_size); 367 if (rc) 368 goto out; 369 370 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || 371 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { 372 rc = EINVAL; 373 goto out; 374 } 375 376 /* 377 * Calculate indirect block levels. 378 */ 379 { 380 register int mult; 381 register int level; 382 383 mult = 1; 384 for (level = 0; level < NIADDR; level++) { 385 mult *= NINDIR(fs); 386 fp->f_nindir[level] = mult; 387 } 388 } 389 390 inumber = ROOTINO; 391 if ((rc = read_inode(inumber, f)) != 0) 392 goto out; 393 394 cp = path; 395 while (*cp) { 396 397 /* 398 * Remove extra separators 399 */ 400 while (*cp == '/') 401 cp++; 402 if (*cp == '\0') 403 break; 404 405 /* 406 * Check that current node is a directory. 407 */ 408 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 409 rc = ENOTDIR; 410 goto out; 411 } 412 413 /* 414 * Get next component of path name. 415 */ 416 { 417 register int len = 0; 418 419 ncp = cp; 420 while ((c = *cp) != '\0' && c != '/') { 421 if (++len > MAXNAMLEN) { 422 rc = ENOENT; 423 goto out; 424 } 425 cp++; 426 } 427 *cp = '\0'; 428 } 429 430 /* 431 * Look up component in current directory. 432 * Save directory inumber in case we find a 433 * symbolic link. 434 */ 435 parent_inumber = inumber; 436 rc = search_directory(ncp, f, &inumber); 437 *cp = c; 438 if (rc) 439 goto out; 440 441 /* 442 * Open next component. 443 */ 444 if ((rc = read_inode(inumber, f)) != 0) 445 goto out; 446 447 #if 0 448 /* 449 * Check for symbolic link. 450 */ 451 if ((fp->i_mode & IFMT) == IFLNK) { 452 int link_len = fp->f_di.di_size; 453 int len; 454 455 len = strlen(cp) + 1; 456 457 if (fp->f_di.di_size >= MAXPATHLEN - 1 || 458 ++nlinks > MAXSYMLINKS) { 459 rc = ENOENT; 460 goto out; 461 } 462 463 strcpy(&namebuf[link_len], cp); 464 465 if ((fp->i_flags & IC_FASTLINK) != 0) { 466 bcopy(fp->i_symlink, namebuf, (unsigned) link_len); 467 } else { 468 /* 469 * Read file for symbolic link 470 */ 471 char *buf; 472 u_int buf_size; 473 daddr_t disk_block; 474 register struct fs *fs = fp->f_fs; 475 476 (void) block_map(f, (daddr_t)0, &disk_block); 477 rc = device_read(&fp->f_dev, 478 fsbtodb(fs, disk_block), 479 blksize(fs, fp, 0), 480 &buf, &buf_size); 481 if (rc) 482 goto out; 483 484 bcopy((char *)buf, namebuf, (unsigned)link_len); 485 free(buf, buf_size); 486 } 487 488 /* 489 * If relative pathname, restart at parent directory. 490 * If absolute pathname, restart at root. 491 */ 492 cp = namebuf; 493 if (*cp != '/') 494 inumber = parent_inumber; 495 else 496 inumber = (ino_t)ROOTINO; 497 498 if ((rc = read_inode(inumber, fp)) != 0) 499 goto out; 500 } 501 #endif 502 } 503 504 /* 505 * Found terminal component. 506 */ 507 rc = 0; 508 out: 509 if (rc) 510 free(fp, sizeof(struct file)); 511 return (rc); 512 } 513 514 int 515 ufs_close(f) 516 struct open_file *f; 517 { 518 register struct file *fp = (struct file *)f->f_fsdata; 519 int level; 520 521 f->f_fsdata = (void *)0; 522 if (fp == (struct file *)0) 523 return (0); 524 525 for (level = 0; level < NIADDR; level++) { 526 if (fp->f_blk[level]) 527 free(fp->f_blk[level], fp->f_fs->fs_bsize); 528 } 529 if (fp->f_buf) 530 free(fp->f_buf, fp->f_fs->fs_bsize); 531 free(fp->f_fs, SBSIZE); 532 free(fp, sizeof(struct file)); 533 return (0); 534 } 535 536 /* 537 * Copy a portion of a file into kernel memory. 538 * Cross block boundaries when necessary. 539 */ 540 int 541 ufs_read(f, start, size, resid) 542 struct open_file *f; 543 char *start; 544 u_int size; 545 u_int *resid; /* out */ 546 { 547 register struct file *fp = (struct file *)f->f_fsdata; 548 register u_int csize; 549 char *buf; 550 u_int buf_size; 551 int rc = 0; 552 553 while (size != 0) { 554 if (fp->f_seekp >= fp->f_di.di_size) 555 break; 556 557 rc = buf_read_file(f, &buf, &buf_size); 558 if (rc) 559 break; 560 561 csize = size; 562 if (csize > buf_size) 563 csize = buf_size; 564 565 bcopy(buf, start, csize); 566 567 fp->f_seekp += csize; 568 start += csize; 569 size -= csize; 570 } 571 if (resid) 572 *resid = size; 573 return (rc); 574 } 575 576 /* 577 * Not implemented. 578 */ 579 int 580 ufs_write(f, start, size, resid) 581 struct open_file *f; 582 char *start; 583 u_int size; 584 u_int *resid; /* out */ 585 { 586 587 return (EROFS); 588 } 589 590 off_t 591 ufs_seek(f, offset, where) 592 struct open_file *f; 593 off_t offset; 594 int where; 595 { 596 register struct file *fp = (struct file *)f->f_fsdata; 597 598 switch (where) { 599 case SEEK_SET: 600 fp->f_seekp = offset; 601 break; 602 case SEEK_CUR: 603 fp->f_seekp += offset; 604 break; 605 case SEEK_END: 606 fp->f_seekp = fp->f_di.di_size - offset; 607 break; 608 default: 609 return (-1); 610 } 611 return (fp->f_seekp); 612 } 613 614 int 615 ufs_stat(f, sb) 616 struct open_file *f; 617 struct stat *sb; 618 { 619 register struct file *fp = (struct file *)f->f_fsdata; 620 621 /* only important stuff */ 622 sb->st_mode = fp->f_di.di_mode; 623 sb->st_uid = fp->f_di.di_uid; 624 sb->st_gid = fp->f_di.di_gid; 625 sb->st_size = fp->f_di.di_size; 626 return (0); 627 } 628