📄 link.c
字号:
25623
25624 /* Parent dirs must be writable, searchable and on a writable device */
25625 if ((r1 = forbidden(old_dirp, W_BIT | X_BIT)) != OK ||
25626 (r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) r = r1;
25627
25628 /* Some tests apply only if the new path exists. */
25629 if (new_ip == NIL_INODE) {
25630 /* don't rename a file with a file system mounted on it. */
25631 if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;
25632 if (odir && (new_dirp->i_nlinks & BYTE) >= LINK_MAX &&
25633 !same_pdir && r == OK) r = EMLINK;
25634 } else {
25635 if (old_ip == new_ip) r = SAME; /* old=new */
25636
25637 /* has the old file or new file a file system mounted on it? */
25638 if (old_ip->i_dev != new_ip->i_dev) r = EXDEV;
25639
25640 ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* dir ? */
25641 if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
25642 if (odir == FALSE && ndir == TRUE) r = EISDIR;
25643 }
25644 }
25645
25646 /* If a process has another root directory than the system root, we might
25647 * "accidently" be moving it's working directory to a place where it's
25648 * root directory isn't a super directory of it anymore. This can make
25649 * the function chroot useless. If chroot will be used often we should
25650 * probably check for it here.
25651 */
25652
25653 /* The rename will probably work. Only two things can go wrong now:
25654 * 1. being unable to remove the new file. (when new file already exists)
25655 * 2. being unable to make the new directory entry. (new file doesn't exists)
25656 * [directory has to grow by one block and cannot because the disk
25657 * is completely full].
25658 */
25659 if (r == OK) {
25660 if (new_ip != NIL_INODE) {
25661 /* There is already an entry for 'new'. Try to remove it. */
25662 if (odir)
25663 r = remove_dir(new_dirp, new_ip, new_name);
25664 else
25665 r = unlink_file(new_dirp, new_ip, new_name);
25666 }
25667 /* if r is OK, the rename will succeed, while there is now an
25668 * unused entry in the new parent directory.
25669 */
25670 }
25671
25672 if (r == OK) {
25673 /* If the new name will be in the same parent directory as the old one,
25674 * first remove the old name to free an entry for the new name,
25675 * otherwise first try to create the new name entry to make sure
25676 * the rename will succeed.
25677 */
25678 numb = old_ip->i_num; /* inode number of old file */
25679
25680 if (same_pdir) {
25681 r = search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
25682 /* shouldn't go wrong. */
25683 if (r==OK) (void) search_dir(old_dirp, new_name, &numb, ENTER);
25684 } else {
25685 r = search_dir(new_dirp, new_name, &numb, ENTER);
25686 if (r == OK)
25687 (void) search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
25688 }
25689 }
25690 /* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked
25691 * for update in search_dir.
25692 */
25693
25694 if (r == OK && odir && !same_pdir) {
25695 /* Update the .. entry in the directory (still points to old_dirp). */
25696 numb = new_dirp->i_num;
25697 (void) unlink_file(old_ip, NIL_INODE, dot2);
25698 if (search_dir(old_ip, dot2, &numb, ENTER) == OK) {
25699 /* New link created. */
25700 new_dirp->i_nlinks++;
25701 new_dirp->i_dirt = DIRTY;
25702 }
25703 }
25704
25705 /* Release the inodes. */
25706 put_inode(old_dirp);
25707 put_inode(old_ip);
25708 put_inode(new_dirp);
25709 put_inode(new_ip);
25710 return(r == SAME ? OK : r);
25711 }
25714 /*===========================================================================*
25715 * truncate *
25716 *===========================================================================*/
25717 PUBLIC void truncate(rip)
25718 register struct inode *rip; /* pointer to inode to be truncated */
25719 {
25720 /* Remove all the zones from the inode 'rip' and mark it dirty. */
25721
25722 register block_t b;
25723 zone_t z, zone_size, z1;
25724 off_t position;
25725 int i, scale, file_type, waspipe, single, nr_indirects;
25726 struct buf *bp;
25727 dev_t dev;
25728
25729 file_type = rip->i_mode & I_TYPE; /* check to see if file is special */
25730 if (file_type == I_CHAR_SPECIAL || file_type == I_BLOCK_SPECIAL) return;
25731 dev = rip->i_dev; /* device on which inode resides */
25732 scale = rip->i_sp->s_log_zone_size;
25733 zone_size = (zone_t) BLOCK_SIZE << scale;
25734 nr_indirects = rip->i_nindirs;
25735
25736 /* Pipes can shrink, so adjust size to make sure all zones are removed. */
25737 waspipe = rip->i_pipe == I_PIPE; /* TRUE is this was a pipe */
25738 if (waspipe) rip->i_size = PIPE_SIZE;
25739
25740 /* Step through the file a zone at a time, finding and freeing the zones. */
25741 for (position = 0; position < rip->i_size; position += zone_size) {
25742 if ( (b = read_map(rip, position)) != NO_BLOCK) {
25743 z = (zone_t) b >> scale;
25744 free_zone(dev, z);
25745 }
25746 }
25747
25748 /* All the data zones have been freed. Now free the indirect zones. */
25749 rip->i_dirt = DIRTY;
25750 if (waspipe) {
25751 wipe_inode(rip); /* clear out inode for pipes */
25752 return; /* indirect slots contain file positions */
25753 }
25754 single = rip->i_ndzones;
25755 free_zone(dev, rip->i_zone[single]); /* single indirect zone */
25756 if ( (z = rip->i_zone[single+1]) != NO_ZONE) {
25757 /* Free all the single indirect zones pointed to by the double. */
25758 b = (block_t) z << scale;
25759 bp = get_block(dev, b, NORMAL); /* get double indirect zone */
25760 for (i = 0; i < nr_indirects; i++) {
25761 z1 = rd_indir(bp, i);
25762 free_zone(dev, z1);
25763 }
25764
25765 /* Now free the double indirect zone itself. */
25766 put_block(bp, INDIRECT_BLOCK);
25767 free_zone(dev, z);
25768 }
25769
25770 /* Leave zone numbers for de(1) to recover file after an unlink(2). */
25771 }
25774 /*===========================================================================*
25775 * remove_dir *
25776 *===========================================================================*/
25777 PRIVATE int remove_dir(rldirp, rip, dir_name)
25778 struct inode *rldirp; /* parent directory */
25779 struct inode *rip; /* directory to be removed */
25780 char dir_name[NAME_MAX]; /* name of directory to be removed */
25781 {
25782 /* A directory file has to be removed. Five conditions have to met:
25783 * - The file must be a directory
25784 * - The directory must be empty (except for . and ..)
25785 * - The final component of the path must not be . or ..
25786 * - The directory must not be the root of a mounted file system
25787 * - The directory must not be anybody's root/working directory
25788 */
25789
25790 int r;
25791 register struct fproc *rfp;
25792
25793 /* search_dir checks that rip is a directory too. */
25794 if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r;
25795
25796 if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
25797 if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */
25798
25799 for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
25800 if (rfp->fp_workdir == rip || rfp->fp_rootdir == rip) return(EBUSY);
25801 /* can't remove anybody's working dir */
25802
25803 /* Actually try to unlink the file; fails if parent is mode 0 etc. */
25804 if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
25805
25806 /* Unlink . and .. from the dir. The super user can link and unlink any dir,
25807 * so don't make too many assumptions about them.
25808 */
25809 (void) unlink_file(rip, NIL_INODE, dot1);
25810 (void) unlink_file(rip, NIL_INODE, dot2);
25811 return(OK);
25812 }
25815 /*===========================================================================*
25816 * unlink_file *
25817 *===========================================================================*/
25818 PRIVATE int unlink_file(dirp, rip, file_name)
25819 struct inode *dirp; /* parent directory of file */
25820 struct inode *rip; /* inode of file, may be NIL_INODE too. */
25821 char file_name[NAME_MAX]; /* name of file to be removed */
25822 {
25823 /* Unlink 'file_name'; rip must be the inode of 'file_name' or NIL_INODE. */
25824
25825 ino_t numb; /* inode number */
25826 int r;
25827
25828 /* If rip is not NIL_INODE, it is used to get faster access to the inode. */
25829 if (rip == NIL_INODE) {
25830 /* Search for file in directory and try to get its inode. */
25831 err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
25832 if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
25833 if (err_code != OK || rip == NIL_INODE) return(err_code);
25834 } else {
25835 dup_inode(rip); /* inode will be returned with put_inode */
25836 }
25837
25838 r = search_dir(dirp, file_name, (ino_t *) 0, DELETE);
25839
25840 if (r == OK) {
25841 rip->i_nlinks--; /* entry deleted from parent's dir */
25842 rip->i_update |= CTIME;
25843 rip->i_dirt = DIRTY;
25844 }
25845
25846 put_inode(rip);
25847 return(r);
25848 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -