|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/fs/fatfs/fatfs_vnops.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /* 2 * Copyright (c) 2005-2008, Kohsuke Ohtani 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 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/prex.h> 31 32 #include <sys/vnode.h> 33 #include <sys/file.h> 34 #include <sys/mount.h> 35 #include <sys/dirent.h> 36 #include <sys/buf.h> 37 38 #include <ctype.h> 39 #include <unistd.h> 40 #include <errno.h> 41 #include <string.h> 42 #include <stdlib.h> 43 #include <fcntl.h> 44 45 #include "fatfs.h" 46 47 /* 48 * Time bits: 15-11 hours (0-23), 10-5 min, 4-0 sec /2 49 * Date bits: 15-9 year - 1980, 8-5 month, 4-0 day 50 */ 51 #define TEMP_DATE 0x3021 52 #define TEMP_TIME 0 53 54 #define fatfs_open ((vnop_open_t)vop_nullop) 55 #define fatfs_close ((vnop_close_t)vop_nullop) 56 static int fatfs_read (vnode_t, file_t, void *, size_t, size_t *); 57 static int fatfs_write (vnode_t, file_t, void *, size_t, size_t *); 58 #define fatfs_seek ((vnop_seek_t)vop_nullop) 59 #define fatfs_ioctl ((vnop_ioctl_t)vop_einval) 60 #define fatfs_fsync ((vnop_fsync_t)vop_nullop) 61 static int fatfs_readdir(vnode_t, file_t, struct dirent *); 62 static int fatfs_lookup (vnode_t, char *, vnode_t); 63 static int fatfs_create (vnode_t, char *, mode_t); 64 static int fatfs_remove (vnode_t, vnode_t, char *); 65 static int fatfs_rename (vnode_t, vnode_t, char *, vnode_t, vnode_t, char *); 66 static int fatfs_mkdir (vnode_t, char *, mode_t); 67 static int fatfs_rmdir (vnode_t, vnode_t, char *); 68 static int fatfs_getattr(vnode_t, struct vattr *); 69 static int fatfs_setattr(vnode_t, struct vattr *); 70 static int fatfs_inactive(vnode_t); 71 static int fatfs_truncate(vnode_t, off_t); 72 73 /* 74 * vnode operations 75 */ 76 struct vnops fatfs_vnops = { 77 fatfs_open, /* open */ 78 fatfs_close, /* close */ 79 fatfs_read, /* read */ 80 fatfs_write, /* write */ 81 fatfs_seek, /* seek */ 82 fatfs_ioctl, /* ioctl */ 83 fatfs_fsync, /* fsync */ 84 fatfs_readdir, /* readdir */ 85 fatfs_lookup, /* lookup */ 86 fatfs_create, /* create */ 87 fatfs_remove, /* remove */ 88 fatfs_rename, /* remame */ 89 fatfs_mkdir, /* mkdir */ 90 fatfs_rmdir, /* rmdir */ 91 fatfs_getattr, /* getattr */ 92 fatfs_setattr, /* setattr */ 93 fatfs_inactive, /* inactive */ 94 fatfs_truncate, /* truncate */ 95 }; 96 97 /* 98 * Read one cluster to buffer. 99 */ 100 static int 101 fat_read_cluster(struct fatfsmount *fmp, u_long cluster) 102 { 103 u_long sec; 104 size_t size; 105 106 sec = cl_to_sec(fmp, cluster); 107 size = fmp->sec_per_cl * SEC_SIZE; 108 return device_read(fmp->dev, fmp->io_buf, &size, sec); 109 } 110 111 /* 112 * Write one cluster from buffer. 113 */ 114 static int 115 fat_write_cluster(struct fatfsmount *fmp, u_long cluster) 116 { 117 u_long sec; 118 size_t size; 119 120 sec = cl_to_sec(fmp, cluster); 121 size = fmp->sec_per_cl * SEC_SIZE; 122 return device_write(fmp->dev, fmp->io_buf, &size, sec); 123 } 124 125 /* 126 * Lookup vnode for the specified file/directory. 127 * The vnode data will be set properly. 128 */ 129 static int 130 fatfs_lookup(vnode_t dvp, char *name, vnode_t vp) 131 { 132 struct fatfsmount *fmp; 133 struct fat_dirent *de; 134 struct fatfs_node *np; 135 int error; 136 137 if (*name == '\0') 138 return ENOENT; 139 140 fmp = vp->v_mount->m_data; 141 mutex_lock(&fmp->lock); 142 143 DPRINTF(("fatfs_lookup: name=%s\n", name)); 144 145 np = vp->v_data; 146 error = fatfs_lookup_node(dvp, name, np); 147 if (error) { 148 DPRINTF(("fatfs_lookup: failed!! name=%s\n", name)); 149 mutex_unlock(&fmp->lock); 150 return error; 151 } 152 de = &np->dirent; 153 vp->v_type = IS_DIR(de) ? VDIR : VREG; 154 fat_attr_to_mode(de->attr, &vp->v_mode); 155 vp->v_mode = ALLPERMS; 156 vp->v_size = de->size; 157 vp->v_blkno = de->cluster; 158 159 DPRINTF(("fatfs_lookup: cl=%d\n", de->cluster)); 160 mutex_unlock(&fmp->lock); 161 return 0; 162 } 163 164 static int 165 fatfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) 166 { 167 struct fatfsmount *fmp; 168 int nr_read, nr_copy, buf_pos, error; 169 u_long cl, file_pos; 170 171 DPRINTF(("fatfs_read: vp=%x\n", vp)); 172 173 *result = 0; 174 fmp = vp->v_mount->m_data; 175 176 if (vp->v_type == VDIR) 177 return EISDIR; 178 if (vp->v_type != VREG) 179 return EINVAL; 180 181 /* Check if current file position is already end of file. */ 182 file_pos = fp->f_offset; 183 if (file_pos >= vp->v_size) 184 return 0; 185 186 mutex_lock(&fmp->lock); 187 188 /* Get the actual read size. */ 189 if (vp->v_size - file_pos < size) 190 size = vp->v_size - file_pos; 191 192 /* Seek to the cluster for the file offset */ 193 error = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl); 194 if (error) 195 goto out; 196 197 /* Read and copy data */ 198 nr_read = 0; 199 buf_pos = file_pos % fmp->cluster_size; 200 do { 201 if (fat_read_cluster(fmp, cl)) { 202 error = EIO; 203 goto out; 204 } 205 206 nr_copy = fmp->cluster_size; 207 if (buf_pos > 0) 208 nr_copy -= buf_pos; 209 if (buf_pos + size < fmp->cluster_size) 210 nr_copy = size; 211 memcpy(buf, fmp->io_buf + buf_pos, nr_copy); 212 213 file_pos += nr_copy; 214 nr_read += nr_copy; 215 size -= nr_copy; 216 if (size <= 0) 217 break; 218 219 error = fat_next_cluster(fmp, cl, &cl); 220 if (error) 221 goto out; 222 223 buf = (void *)((u_long)buf + nr_copy); 224 buf_pos = 0; 225 } while (!IS_EOFCL(fmp, cl)); 226 227 fp->f_offset = file_pos; 228 *result = nr_read; 229 error = 0; 230 out: 231 mutex_unlock(&fmp->lock); 232 return error; 233 } 234 235 static int 236 fatfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) 237 { 238 struct fatfsmount *fmp; 239 struct fatfs_node *np; 240 struct fat_dirent *de; 241 int nr_copy, nr_write, buf_pos, i, cl_size, error; 242 u_long file_pos, end_pos; 243 u_long cl; 244 245 DPRINTF(("fatfs_write: vp=%x\n", vp)); 246 247 *result = 0; 248 fmp = vp->v_mount->m_data; 249 250 if (vp->v_type == VDIR) 251 return EISDIR; 252 if (vp->v_type != VREG) 253 return EINVAL; 254 255 mutex_lock(&fmp->lock); 256 257 /* Check if file position exceeds the end of file. */ 258 end_pos = vp->v_size; 259 file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset; 260 if (file_pos + size > end_pos) { 261 /* Expand the file size before writing to it */ 262 end_pos = file_pos + size; 263 error = fat_expand_file(fmp, vp->v_blkno, end_pos); 264 if (error) { 265 error = EIO; 266 goto out; 267 } 268 269 /* Update directory entry */ 270 np = vp->v_data; 271 de = &np->dirent; 272 de->size = end_pos; 273 error = fatfs_put_node(fmp, np); 274 if (error) 275 goto out; 276 vp->v_size = end_pos; 277 } 278 279 /* Seek to the cluster for the file offset */ 280 error = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl); 281 if (error) 282 goto out; 283 284 buf_pos = file_pos % fmp->cluster_size; 285 cl_size = size / fmp->cluster_size + 1; 286 nr_write = 0; 287 i = 0; 288 do { 289 /* First and last cluster must be read before write */ 290 if (i == 0 || i == cl_size) { 291 if (fat_read_cluster(fmp, cl)) { 292 error = EIO; 293 goto out; 294 } 295 } 296 nr_copy = fmp->cluster_size; 297 if (buf_pos > 0) 298 nr_copy -= buf_pos; 299 if (buf_pos + size < fmp->cluster_size) 300 nr_copy = size; 301 memcpy(fmp->io_buf + buf_pos, buf, nr_copy); 302 303 if (fat_write_cluster(fmp, cl)) { 304 error = EIO; 305 goto out; 306 } 307 file_pos += nr_copy; 308 nr_write += nr_copy; 309 size -= nr_copy; 310 if (size <= 0) 311 break; 312 313 error = fat_next_cluster(fmp, cl, &cl); 314 if (error) 315 goto out; 316 317 buf = (void *)((u_long)buf + nr_copy); 318 buf_pos = 0; 319 i++; 320 } while (!IS_EOFCL(fmp, cl)); 321 322 fp->f_offset = file_pos; 323 324 /* 325 * XXX: Todo! 326 * de.time = ? 327 * de.date = ? 328 * if (dirent_set(fp, &de)) 329 * return EIO; 330 */ 331 *result = nr_write; 332 error = 0; 333 out: 334 mutex_unlock(&fmp->lock); 335 return error; 336 } 337 338 static int 339 fatfs_readdir(vnode_t vp, file_t fp, struct dirent *dir) 340 { 341 struct fatfsmount *fmp; 342 struct fatfs_node np; 343 struct fat_dirent *de; 344 int error; 345 346 fmp = vp->v_mount->m_data; 347 mutex_lock(&fmp->lock); 348 349 error = fatfs_get_node(vp, fp->f_offset, &np); 350 if (error) 351 goto out; 352 de = &np.dirent; 353 fat_restore_name((char *)&de->name, dir->d_name); 354 355 if (de->attr & FA_SUBDIR) 356 dir->d_type = DT_DIR; 357 else if (de->attr & FA_DEVICE) 358 dir->d_type = DT_BLK; 359 else 360 dir->d_type = DT_REG; 361 362 dir->d_fileno = fp->f_offset; 363 dir->d_namlen = strlen(dir->d_name); 364 365 fp->f_offset++; 366 error = 0; 367 out: 368 mutex_unlock(&fmp->lock); 369 return error; 370 } 371 372 /* 373 * Create empty file. 374 */ 375 static int 376 fatfs_create(vnode_t dvp, char *name, mode_t mode) 377 { 378 struct fatfsmount *fmp; 379 struct fatfs_node np; 380 struct fat_dirent *de; 381 u_long cl; 382 int error; 383 384 DPRINTF(("fatfs_create: %s\n", name)); 385 386 if (!S_ISREG(mode)) 387 return EINVAL; 388 389 if (!fat_valid_name(name)) 390 return EINVAL; 391 392 fmp = dvp->v_mount->m_data; 393 mutex_lock(&fmp->lock); 394 395 /* Allocate free cluster for new file. */ 396 error = fat_alloc_cluster(fmp, 0, &cl); 397 if (error) 398 goto out; 399 400 de = &np.dirent; 401 memset(de, 0, sizeof(struct fat_dirent)); 402 fat_convert_name(name, (char *)de->name); 403 de->cluster = cl; 404 de->time = TEMP_TIME; 405 de->date = TEMP_DATE; 406 fat_mode_to_attr(mode, &de->attr); 407 error = fatfs_add_node(dvp, &np); 408 if (error) 409 goto out; 410 error = fat_set_cluster(fmp, cl, fmp->fat_eof); 411 out: 412 mutex_unlock(&fmp->lock); 413 return error; 414 } 415 416 static int 417 fatfs_remove(vnode_t dvp, vnode_t vp, char *name) 418 { 419 struct fatfsmount *fmp; 420 struct fatfs_node np; 421 struct fat_dirent *de; 422 int error; 423 424 if (*name == '\0') 425 return ENOENT; 426 427 fmp = dvp->v_mount->m_data; 428 mutex_lock(&fmp->lock); 429 430 error = fatfs_lookup_node(dvp, name, &np); 431 if (error) 432 goto out; 433 de = &np.dirent; 434 if (IS_DIR(de)) { 435 error = EISDIR; 436 goto out; 437 } 438 if (!IS_FILE(de)) { 439 error = EPERM; 440 goto out; 441 } 442 443 /* Remove clusters */ 444 error = fat_free_clusters(fmp, de->cluster); 445 if (error) 446 goto out; 447 448 /* remove directory */ 449 de->name[0] = 0xe5; 450 error = fatfs_put_node(fmp, &np); 451 out: 452 mutex_unlock(&fmp->lock); 453 return error; 454 } 455 456 static int 457 fatfs_rename(vnode_t dvp1, vnode_t vp1, char *name1, 458 vnode_t dvp2, vnode_t vp2, char *name2) 459 { 460 struct fatfsmount *fmp; 461 struct fatfs_node np1; 462 struct fat_dirent *de1, *de2; 463 int error; 464 465 fmp = dvp1->v_mount->m_data; 466 mutex_lock(&fmp->lock); 467 468 error = fatfs_lookup_node(dvp1, name1, &np1); 469 if (error) 470 goto out; 471 de1 = &np1.dirent; 472 473 if (IS_FILE(de1)) { 474 /* Remove destination file, first */ 475 error = fatfs_remove(dvp2, vp1, name2); 476 if (error == EIO) 477 goto out; 478 479 /* Change file name of directory entry */ 480 fat_convert_name(name2, (char *)de1->name); 481 482 /* Same directory ? */ 483 if (dvp1 == dvp2) { 484 /* Change the name of existing file */ 485 error = fatfs_put_node(fmp, &np1); 486 if (error) 487 goto out; 488 } else { 489 /* Create new directory entry */ 490 error = fatfs_add_node(dvp2, &np1); 491 if (error) 492 goto out; 493 494 /* Remove souce file */ 495 error = fatfs_remove(dvp1, vp2, name1); 496 if (error) 497 goto out; 498 } 499 } else { 500 501 /* remove destination directory */ 502 error = fatfs_rmdir(dvp2, NULL, name2); 503 if (error == EIO) 504 goto out; 505 506 /* Change file name of directory entry */ 507 fat_convert_name(name2, (char *)de1->name); 508 509 /* Same directory ? */ 510 if (dvp1 == dvp2) { 511 /* Change the name of existing directory */ 512 error = fatfs_put_node(fmp, &np1); 513 if (error) 514 goto out; 515 } else { 516 /* Create new directory entry */ 517 error = fatfs_add_node(dvp2, &np1); 518 if (error) 519 goto out; 520 521 /* Update "." and ".." for renamed directory */ 522 if (fat_read_cluster(fmp, de1->cluster)) { 523 error = EIO; 524 goto out; 525 } 526 527 de2 = (struct fat_dirent *)fmp->io_buf; 528 de2->cluster = de1->cluster; 529 de2->time = TEMP_TIME; 530 de2->date = TEMP_DATE; 531 de2++; 532 de2->cluster = dvp2->v_blkno; 533 de2->time = TEMP_TIME; 534 de2->date = TEMP_DATE; 535 536 if (fat_write_cluster(fmp, de1->cluster)) { 537 error = EIO; 538 goto out; 539 } 540 541 /* Remove souce directory */ 542 error = fatfs_rmdir(dvp1, NULL, name1); 543 if (error) 544 goto out; 545 } 546 } 547 out: 548 mutex_unlock(&fmp->lock); 549 return error; 550 } 551 552 static int 553 fatfs_mkdir(vnode_t dvp, char *name, mode_t mode) 554 { 555 struct fatfsmount *fmp; 556 struct fatfs_node np; 557 struct fat_dirent *de; 558 u_long cl; 559 int error; 560 561 if (!S_ISDIR(mode)) 562 return EINVAL; 563 564 if (!fat_valid_name(name)) 565 return ENOTDIR; 566 567 fmp = dvp->v_mount->m_data; 568 mutex_lock(&fmp->lock); 569 570 /* Allocate free cluster for directory data */ 571 error = fat_alloc_cluster(fmp, 0, &cl); 572 if (error) 573 goto out; 574 575 memset(&np, 0, sizeof(struct fatfs_node)); 576 de = &np.dirent; 577 fat_convert_name(name, (char *)&de->name); 578 de->cluster = cl; 579 de->time = TEMP_TIME; 580 de->date = TEMP_DATE; 581 fat_mode_to_attr(mode, &de->attr); 582 error = fatfs_add_node(dvp, &np); 583 if (error) 584 goto out; 585 586 /* Initialize "." and ".." for new directory */ 587 memset(fmp->io_buf, 0, fmp->cluster_size); 588 589 de = (struct fat_dirent *)fmp->io_buf; 590 memcpy(de->name, ". ", 11); 591 de->attr = FA_SUBDIR; 592 de->cluster = cl; 593 de->time = TEMP_TIME; 594 de->date = TEMP_DATE; 595 de++; 596 memcpy(de->name, ".. ", 11); 597 de->attr = FA_SUBDIR; 598 de->cluster = dvp->v_blkno; 599 de->time = TEMP_TIME; 600 de->date = TEMP_DATE; 601 602 if (fat_write_cluster(fmp, cl)) { 603 error = EIO; 604 goto out; 605 } 606 /* Add eof */ 607 error = fat_set_cluster(fmp, cl, fmp->fat_eof); 608 out: 609 mutex_unlock(&fmp->lock); 610 return error; 611 } 612 613 /* 614 * remove can be done only with empty directory 615 */ 616 static int 617 fatfs_rmdir(vnode_t dvp, vnode_t vp, char *name) 618 { 619 struct fatfsmount *fmp; 620 struct fatfs_node np; 621 struct fat_dirent *de; 622 int error; 623 624 if (*name == '\0') 625 return ENOENT; 626 627 fmp = dvp->v_mount->m_data; 628 mutex_lock(&fmp->lock); 629 630 error = fatfs_lookup_node(dvp, name, &np); 631 if (error) 632 goto out; 633 634 de = &np.dirent; 635 if (!IS_DIR(de)) { 636 error = ENOTDIR; 637 goto out; 638 } 639 640 /* Remove clusters */ 641 error = fat_free_clusters(fmp, de->cluster); 642 if (error) 643 goto out; 644 645 /* remove directory */ 646 de->name[0] = 0xe5; 647 648 error = fatfs_put_node(fmp, &np); 649 out: 650 mutex_unlock(&fmp->lock); 651 return error; 652 } 653 654 static int 655 fatfs_getattr(vnode_t vp, struct vattr *vap) 656 { 657 /* XXX */ 658 return 0; 659 } 660 661 static int 662 fatfs_setattr(vnode_t vp, struct vattr *vap) 663 { 664 /* XXX */ 665 return 0; 666 } 667 668 669 static int 670 fatfs_inactive(vnode_t vp) 671 { 672 673 free(vp->v_data); 674 return 0; 675 } 676 677 static int 678 fatfs_truncate(vnode_t vp, off_t length) 679 { 680 struct fatfsmount *fmp; 681 struct fatfs_node *np; 682 struct fat_dirent *de; 683 int error; 684 685 fmp = vp->v_mount->m_data; 686 mutex_lock(&fmp->lock); 687 688 np = vp->v_data; 689 de = &np->dirent; 690 691 if (length == 0) { 692 /* Remove clusters */ 693 error = fat_free_clusters(fmp, de->cluster); 694 if (error) 695 goto out; 696 } else if (length > vp->v_size) { 697 error = fat_expand_file(fmp, vp->v_blkno, length); 698 if (error) { 699 error = EIO; 700 goto out; 701 } 702 } 703 704 /* Update directory entry */ 705 de->size = length; 706 error = fatfs_put_node(fmp, np); 707 if (error) 708 goto out; 709 vp->v_size = length; 710 out: 711 mutex_unlock(&fmp->lock); 712 return error; 713 } 714 715 int 716 fatfs_init(void) 717 { 718 return 0; 719 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |