📄 link.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/fs/link.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
25400 /* This file handles the LINK and UNLINK system calls. It also deals with
25401 * deallocating the storage used by a file when the last UNLINK is done to a
25402 * file and the blocks must be returned to the free block pool.
25403 *
25404 * The entry points into this file are
25405 * do_link: perform the LINK system call
25406 * do_unlink: perform the UNLINK and RMDIR system calls
25407 * do_rename: perform the RENAME system call
25408 * truncate: release all the blocks associated with an inode
25409 */
25410
25411 #include "fs.h"
25412 #include <sys/stat.h>
25413 #include <string.h>
25414 #include <minix/callnr.h>
25415 #include "buf.h"
25416 #include "file.h"
25417 #include "fproc.h"
25418 #include "inode.h"
25419 #include "param.h"
25420 #include "super.h"
25421
25422 #define SAME 1000
25423
25424 FORWARD _PROTOTYPE( int remove_dir, (struct inode *rldirp, struct inode *rip,
25425 char dir_name[NAME_MAX]) );
25426
25427 FORWARD _PROTOTYPE( int unlink_file, (struct inode *dirp, struct inode *rip,
25428 char file_name[NAME_MAX]) );
25429
25430
25431 /*===========================================================================*
25432 * do_link *
25433 *===========================================================================*/
25434 PUBLIC int do_link()
25435 {
25436 /* Perform the link(name1, name2) system call. */
25437
25438 register struct inode *ip, *rip;
25439 register int r;
25440 char string[NAME_MAX];
25441 struct inode *new_ip;
25442
25443 /* See if 'name' (file to be linked) exists. */
25444 if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
25445 if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
25446
25447 /* Check to see if the file has maximum number of links already. */
25448 r = OK;
25449 if ( (rip->i_nlinks & BYTE) >= LINK_MAX) r = EMLINK;
25450
25451 /* Only super_user may link to directories. */
25452 if (r == OK)
25453 if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
25454
25455 /* If error with 'name', return the inode. */
25456 if (r != OK) {
25457 put_inode(rip);
25458 return(r);
25459 }
25460
25461 /* Does the final directory of 'name2' exist? */
25462 if (fetch_name(name2, name2_length, M1) != OK) {
25463 put_inode(rip);
25464 return(err_code);
25465 }
25466 if ( (ip = last_dir(user_path, string)) == NIL_INODE) r = err_code;
25467
25468 /* If 'name2' exists in full (even if no space) set 'r' to error. */
25469 if (r == OK) {
25470 if ( (new_ip = advance(ip, string)) == NIL_INODE) {
25471 r = err_code;
25472 if (r == ENOENT) r = OK;
25473 } else {
25474 put_inode(new_ip);
25475 r = EEXIST;
25476 }
25477 }
25478
25479 /* Check for links across devices. */
25480 if (r == OK)
25481 if (rip->i_dev != ip->i_dev) r = EXDEV;
25482
25483 /* Try to link. */
25484 if (r == OK)
25485 r = search_dir(ip, string, &rip->i_num, ENTER);
25486
25487 /* If success, register the linking. */
25488 if (r == OK) {
25489 rip->i_nlinks++;
25490 rip->i_update |= CTIME;
25491 rip->i_dirt = DIRTY;
25492 }
25493
25494 /* Done. Release both inodes. */
25495 put_inode(rip);
25496 put_inode(ip);
25497 return(r);
25498 }
25501 /*===========================================================================*
25502 * do_unlink *
25503 *===========================================================================*/
25504 PUBLIC int do_unlink()
25505 {
25506 /* Perform the unlink(name) or rmdir(name) system call. The code for these two
25507 * is almost the same. They differ only in some condition testing. Unlink()
25508 * may be used by the superuser to do dangerous things; rmdir() may not.
25509 */
25510
25511 register struct inode *rip;
25512 struct inode *rldirp;
25513 int r;
25514 char string[NAME_MAX];
25515
25516 /* Get the last directory in the path. */
25517 if (fetch_name(name, name_length, M3) != OK) return(err_code);
25518 if ( (rldirp = last_dir(user_path, string)) == NIL_INODE)
25519 return(err_code);
25520
25521 /* The last directory exists. Does the file also exist? */
25522 r = OK;
25523 if ( (rip = advance(rldirp, string)) == NIL_INODE) r = err_code;
25524
25525 /* If error, return inode. */
25526 if (r != OK) {
25527 put_inode(rldirp);
25528 return(r);
25529 }
25530
25531 /* Do not remove a mount point. */
25532 if (rip->i_num == ROOT_INODE) {
25533 put_inode(rldirp);
25534 put_inode(rip);
25535 return(EBUSY);
25536 }
25537
25538 /* Now test if the call is allowed, separately for unlink() and rmdir(). */
25539 if (fs_call == UNLINK) {
25540 /* Only the su may unlink directories, but the su can unlink any dir.*/
25541 if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
25542
25543 /* Don't unlink a file if it is the root of a mounted file system. */
25544 if (rip->i_num == ROOT_INODE) r = EBUSY;
25545
25546 /* Actually try to unlink the file; fails if parent is mode 0 etc. */
25547 if (r == OK) r = unlink_file(rldirp, rip, string);
25548
25549 } else {
25550 r = remove_dir(rldirp, rip, string); /* call is RMDIR */
25551 }
25552
25553 /* If unlink was possible, it has been done, otherwise it has not. */
25554 put_inode(rip);
25555 put_inode(rldirp);
25556 return(r);
25557 }
25560 /*===========================================================================*
25561 * do_rename *
25562 *===========================================================================*/
25563 PUBLIC int do_rename()
25564 {
25565 /* Perform the rename(name1, name2) system call. */
25566
25567 struct inode *old_dirp, *old_ip; /* ptrs to old dir, file inodes */
25568 struct inode *new_dirp, *new_ip; /* ptrs to new dir, file inodes */
25569 struct inode *new_superdirp, *next_new_superdirp;
25570 int r = OK; /* error flag; initially no error */
25571 int odir, ndir; /* TRUE iff {old|new} file is dir */
25572 int same_pdir; /* TRUE iff parent dirs are the same */
25573 char old_name[NAME_MAX], new_name[NAME_MAX];
25574 ino_t numb;
25575 int r1;
25576
25577 /* See if 'name1' (existing file) exists. Get dir and file inodes. */
25578 if (fetch_name(name1, name1_length, M1) != OK) return(err_code);
25579 if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);
25580
25581 if ( (old_ip = advance(old_dirp, old_name)) == NIL_INODE) r = err_code;
25582
25583 /* See if 'name2' (new name) exists. Get dir and file inodes. */
25584 if (fetch_name(name2, name2_length, M1) != OK) r = err_code;
25585 if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
25586 new_ip = advance(new_dirp, new_name); /* not required to exist */
25587
25588 if (old_ip != NIL_INODE)
25589 odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */
25590
25591 /* If it is ok, check for a variety of possible errors. */
25592 if (r == OK) {
25593 same_pdir = (old_dirp == new_dirp);
25594
25595 /* The old inode must not be a superdirectory of the new last dir. */
25596 if (odir && !same_pdir) {
25597 dup_inode(new_superdirp = new_dirp);
25598 while (TRUE) { /* may hang in a file system loop */
25599 if (new_superdirp == old_ip) {
25600 r = EINVAL;
25601 break;
25602 }
25603 next_new_superdirp = advance(new_superdirp, dot2);
25604 put_inode(new_superdirp);
25605 if (next_new_superdirp == new_superdirp)
25606 break; /* back at system root directory */
25607 new_superdirp = next_new_superdirp;
25608 if (new_superdirp == NIL_INODE) {
25609 /* Missing ".." entry. Assume the worst. */
25610 r = EINVAL;
25611 break;
25612 }
25613 }
25614 put_inode(new_superdirp);
25615 }
25616
25617 /* The old or new name must not be . or .. */
25618 if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 ||
25619 strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL;
25620
25621 /* Both parent directories must be on the same device. */
25622 if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -