📄 namei.c
字号:
{ do { symname++; } while (*symname == '/'); pc->componentType = 1; pc->lengthComponentIdent = 0; pc->componentFileVersionNum = 0; pc += sizeof(struct pathComponent); elen += sizeof(struct pathComponent); } err = -ENAMETOOLONG; while (*symname) { if (elen + sizeof(struct pathComponent) > eoffset) goto out_no_entry; pc = (struct pathComponent *)(ea + elen); compstart = (char *)symname; do { symname++; } while (*symname && *symname != '/'); pc->componentType = 5; pc->lengthComponentIdent = 0; pc->componentFileVersionNum = 0; if (compstart[0] == '.') { if ((symname-compstart) == 1) pc->componentType = 4; else if ((symname-compstart) == 2 && compstart[1] == '.') pc->componentType = 3; } if (pc->componentType == 5) { if ( !(namelen = udf_put_filename(inode->i_sb, compstart, name, symname-compstart))) goto out_no_entry; if (elen + sizeof(struct pathComponent) + namelen > eoffset) goto out_no_entry; else pc->lengthComponentIdent = namelen; memcpy(pc->componentIdent, name, namelen); } elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; if (*symname) { do { symname++; } while (*symname == '/'); } } udf_release_data(bh); inode->i_size = elen; if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) UDF_I_LENALLOC(inode) = inode->i_size; mark_inode_dirty(inode); if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) goto out_no_entry; cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); if (UDF_SB_LVIDBH(inode->i_sb)) { struct logicalVolHeaderDesc *lvhd; uint64_t uniqueID; lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse); uniqueID = le64_to_cpu(lvhd->uniqueID); *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; lvhd->uniqueID = cpu_to_le64(uniqueID); mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1); } udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) { mark_inode_dirty(dir);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,14) dir->i_version = ++event;#else dir->i_version = ++global_event;#endif } if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); udf_release_data(fibh.sbh); d_instantiate(dentry, inode); err = 0;out: return err;out_no_entry: inode->i_nlink--; mark_inode_dirty(inode); iput(inode); goto out;}int udf_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry){ struct inode *inode = old_dentry->d_inode; struct udf_fileident_bh fibh; int err; struct fileIdentDesc cfi, *fi; if (S_ISDIR(inode->i_mode)) return -EPERM;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,6) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM;#endif if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1) return -EMLINK; if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) return err; cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); if (UDF_SB_LVIDBH(inode->i_sb)) { struct logicalVolHeaderDesc *lvhd; uint64_t uniqueID; lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse); uniqueID = le64_to_cpu(lvhd->uniqueID); *(uint32_t *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; lvhd->uniqueID = cpu_to_le64(uniqueID); mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1); } udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) { mark_inode_dirty(dir);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,14) dir->i_version = ++event;#else dir->i_version = ++global_event;#endif } if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); udf_release_data(fibh.sbh); inode->i_nlink ++; inode->i_ctime = CURRENT_TIME; UDF_I_UCTIME(inode) = CURRENT_UTIME; mark_inode_dirty(inode); inode->i_count ++; d_instantiate(dentry, inode); return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,6)/* * rename uses retrying to avoid race-conditions: at least they should be * minimal. * it tries to allocate all the blocks, then sanity-checks, and if the sanity- * checks fail, it tries to restart itself again. Very practical - no changes * are done until we know everything works ok.. and then all the changes can be * done in one fell swoop when we have claimed all the buffers needed. * * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */static int do_udf_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ struct inode * old_inode, * new_inode; struct udf_fileident_bh ofibh, nfibh; struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi; struct buffer_head *dir_bh = NULL; int retval = -ENOENT; if (old_dentry->d_name.len > UDF_NAME_LEN) goto end_rename; old_inode = old_dentry->d_inode; if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi))) { if (ofibh.sbh != ofibh.ebh) udf_release_data(ofibh.ebh); udf_release_data(ofibh.sbh); } if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) != old_inode->i_ino) { goto end_rename; } new_inode = new_dentry->d_inode; nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi); if (nfi) { if (!new_inode) { if (nfibh.sbh != nfibh.ebh) udf_release_data(nfibh.ebh); udf_release_data(nfibh.sbh); nfi = NULL; } else { DQUOT_INIT(new_inode); } } retval = 0; if (new_inode == old_inode) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { uint32_t offset = udf_ext0_offset(old_inode); retval = -EINVAL; if (is_subdir(new_dentry, old_dentry)) goto end_rename; if (new_inode) { /* Prune any children before testing for busy */ if (new_dentry->d_count > 1) shrink_dcache_parent(new_dentry); retval = -EBUSY; if (new_dentry->d_count > 1) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) goto end_rename; } if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) { dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) - (UDF_I_EFE(old_inode) ? sizeof(struct extendedFileEntry) : sizeof(struct fileEntry)), old_inode->i_sb->s_blocksize, &offset); } else { dir_bh = udf_bread(old_inode, 0, 0, &retval); if (!dir_bh) goto end_rename; dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset); } if (!dir_fi) goto end_rename; if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) != old_dir->i_ino) { goto end_rename; } retval = -EMLINK; if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1) goto end_rename; } if (!nfi) { nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval); if (!nfi) goto end_rename; } new_dir->i_version = ++event; /* * Like most other Unix systems, set the ctime for inodes on a * rename. */ old_inode->i_ctime = CURRENT_TIME; UDF_I_UCTIME(old_inode) = CURRENT_UTIME; mark_inode_dirty(old_inode); /* * ok, that's it */ ncfi.fileVersionNum = ocfi.fileVersionNum; ncfi.fileCharacteristics = ocfi.fileCharacteristics; memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad)); udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL); /* The old fid may have moved - find it again */ ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi); udf_delete_entry(old_inode, ofi, &ofibh, &ocfi); old_dir->i_version = ++event; if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; UDF_I_UCTIME(new_inode) = CURRENT_UTIME; mark_inode_dirty(new_inode); } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME; mark_inode_dirty(old_dir); if (dir_fi) { dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir)); udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) + cpu_to_le16(dir_fi->lengthOfImpUse) + 3) & ~3); if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) { mark_inode_dirty(old_inode); old_inode->i_version = ++event; } else mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink --; mark_inode_dirty(old_dir); if (new_inode) { new_inode->i_nlink --; mark_inode_dirty(new_inode); } else { new_dir->i_nlink ++; mark_inode_dirty(new_dir); } } /* Update the dcache */ d_move(old_dentry, new_dentry); if (ofi) { if (ofibh.sbh != ofibh.ebh) udf_release_data(ofibh.ebh); udf_release_data(ofibh.sbh); } retval = 0;end_rename: udf_release_data(dir_bh); if (nfi) { if (nfibh.sbh != nfibh.ebh) udf_release_data(nfibh.ebh); udf_release_data(nfibh.sbh); } return retval;}/* Ok, rename also locks out other renames, as they can change the parent of * a directory, and we don't want any races. Other races are checked for by * "do_rename()", which restarts if there are inconsistencies. * * Note that there is no race between different filesystems: it's only within * the same device that races occur: many renames can happen at once, as long * as they are on different partitions. * * In the udf file system, we use a lock flag stored in the memory * super-block. This way, we really lock other renames only if they occur * on the same file system */int udf_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ int result; while (UDF_SB_RENAME_LOCK(old_dir->i_sb)) sleep_on(&UDF_SB_RENAME_WAIT(old_dir->i_sb)); UDF_SB_RENAME_LOCK(old_dir->i_sb) = 1; result = do_udf_rename(old_dir, old_dentry, new_dir, new_dentry); UDF_SB_RENAME_LOCK(old_dir->i_sb) = 0; wake_up(&UDF_SB_RENAME_WAIT(old_dir->i_sb)); return result;}#else/* Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */int udf_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry){ struct inode * old_inode, * new_inode; struct udf_fileident_bh ofibh, nfibh; struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi; struct buffer_head *dir_bh = NULL; int retval = -ENOENT; old_inode = old_dentry->d_inode; if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi))) { if (ofibh.sbh != ofibh.ebh) udf_release_data(ofibh.ebh); udf_release_data(ofibh.sbh); } if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) != old_inode->i_ino) { goto end_rename; } new_inode = new_dentry->d_inode; nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi); if (nfi) { if (!new_inode) { if (nfibh.sbh != nfibh.ebh) udf_release_data(nfibh.ebh); udf_release_data(nfibh.sbh); nfi = NULL; } else { DQUOT_INIT(new_inode); } } if (S_ISDIR(old_inode->i_mode)) { uint32_t offset = udf_ext0_offset(old_inode); if (new_inode) { retval = -ENOTEMPTY; if (!empty_dir(new_inode)) goto end_rename; } retval = -EIO; dir_bh = udf_bread(old_inode, 0, 0, &retval); if (!dir_bh) goto end_rename; dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset); if (!dir_fi) goto end_rename; if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) != old_dir->i_ino) { goto end_rename; } retval = -EMLINK; if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1) goto end_rename; } if (!nfi) { nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval); if (!nfi) goto end_rename; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,14) new_dir->i_version = ++event;#else new_dir->i_version = ++global_event;#endif /* * ok, that's it */ ncfi.fileVersionNum = ocfi.fileVersionNum; ncfi.fileCharacteristics = ocfi.fileCharacteristics; memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad)); udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL); /* The old fid may have moved - find it again */ ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi); udf_delete_entry(old_inode, ofi, &ofibh, &ocfi);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,14) old_dir->i_version = ++event;#else old_dir->i_version = ++global_event;#endif if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; UDF_I_UCTIME(new_inode) = CURRENT_UTIME; mark_inode_dirty(new_inode); } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME; mark_inode_dirty(old_dir); if (dir_bh) { dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir)); udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) + cpu_to_le16(dir_fi->lengthOfImpUse) + 3) & ~3); if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) { mark_inode_dirty(old_inode);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,14) old_inode->i_version = ++event;#else old_inode->i_version = ++global_event;#endif } else mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink --; mark_inode_dirty(old_dir); if (new_inode) { new_inode->i_nlink --; mark_inode_dirty(new_inode); } else { new_dir->i_nlink ++; mark_inode_dirty(new_dir); } } if (ofi) { if (ofibh.sbh != ofibh.ebh) udf_release_data(ofibh.ebh); udf_release_data(ofibh.sbh); } retval = 0;end_rename: udf_release_data(dir_bh); if (nfi) { if (nfibh.sbh != nfibh.ebh) udf_release_data(nfibh.ebh); udf_release_data(nfibh.sbh); } return retval;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -