📄 inode.c
字号:
udf_release_data(bh); return err;}/* * udf_iget * * PURPOSE * Get an inode. * * DESCRIPTION * This routine replaces iget() and read_inode(). * * HISTORY * October 3, 1997 - Andrew E. Mileski * Written, tested, and released. * * 12/19/98 dgb Added semaphore and changed to be a wrapper of iget */struct inode *udf_iget(struct super_block *sb, lb_addr ino){ struct inode *inode; unsigned long block; block = udf_get_lb_pblock(sb, ino, 0); /* Get the inode */ inode = iget(sb, block); /* calls udf_read_inode() ! */ if (!inode) { printk(KERN_ERR "udf: iget() failed\n"); return NULL; } else if (is_bad_inode(inode)) { iput(inode); return NULL; } else if (UDF_I_LOCATION(inode).logicalBlockNum == 0xFFFFFFFF && UDF_I_LOCATION(inode).partitionReferenceNum == 0xFFFF) { memcpy(&UDF_I_LOCATION(inode), &ino, sizeof(lb_addr)); __udf_read_inode(inode); if (is_bad_inode(inode)) { iput(inode); return NULL; } } if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) ) { udf_debug("block=%d, partition=%d out of range\n", ino.logicalBlockNum, ino.partitionReferenceNum); make_bad_inode(inode); iput(inode); return NULL; } return inode;}int8_t udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset, lb_addr eloc, uint32_t elen, struct buffer_head **bh, int inc){ int adsize; short_ad *sad = NULL; long_ad *lad = NULL; struct allocExtDesc *aed; int8_t etype; uint8_t *ptr; if (!*bh) ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); else ptr = (*bh)->b_data + *extoffset; if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(short_ad); else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) adsize = sizeof(long_ad); else return -1; if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize) { char *sptr, *dptr; struct buffer_head *nbh; int err, loffset; lb_addr obloc = *bloc; if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL, obloc.partitionReferenceNum, obloc.logicalBlockNum, &err))) { return -1; } if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) { return -1; } lock_buffer(nbh); memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize); set_buffer_uptodate(nbh); unlock_buffer(nbh); mark_buffer_dirty_inode(nbh, inode); aed = (struct allocExtDesc *)(nbh->b_data); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum); if (*extoffset + adsize > inode->i_sb->s_blocksize) { loffset = *extoffset; aed->lengthAllocDescs = cpu_to_le32(adsize); sptr = ptr - adsize; dptr = nbh->b_data + sizeof(struct allocExtDesc); memcpy(dptr, sptr, adsize); *extoffset = sizeof(struct allocExtDesc) + adsize; } else { loffset = *extoffset + adsize; aed->lengthAllocDescs = cpu_to_le32(0); sptr = ptr; *extoffset = sizeof(struct allocExtDesc); if (*bh) { aed = (struct allocExtDesc *)(*bh)->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); } else { UDF_I_LENALLOC(inode) += adsize; mark_inode_dirty(inode); } } if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, bloc->logicalBlockNum, sizeof(tag)); else udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, bloc->logicalBlockNum, sizeof(tag)); switch (UDF_I_ALLOCTYPE(inode)) { case ICBTAG_FLAG_AD_SHORT: { sad = (short_ad *)sptr; sad->extLength = cpu_to_le32( EXT_NEXT_EXTENT_ALLOCDECS | inode->i_sb->s_blocksize); sad->extPosition = cpu_to_le32(bloc->logicalBlockNum); break; } case ICBTAG_FLAG_AD_LONG: { lad = (long_ad *)sptr; lad->extLength = cpu_to_le32( EXT_NEXT_EXTENT_ALLOCDECS | inode->i_sb->s_blocksize); lad->extLocation = cpu_to_lelb(*bloc); memset(lad->impUse, 0x00, sizeof(lad->impUse)); break; } } if (*bh) { if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) udf_update_tag((*bh)->b_data, loffset); else udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); mark_buffer_dirty_inode(*bh, inode); udf_release_data(*bh); } else mark_inode_dirty(inode); *bh = nbh; } etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc); if (!*bh) { UDF_I_LENALLOC(inode) += adsize; mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)(*bh)->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize)); else udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); mark_buffer_dirty_inode(*bh, inode); } return etype;}int8_t udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset, lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc){ int adsize; uint8_t *ptr; if (!bh) ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); else { ptr = bh->b_data + *extoffset; atomic_inc(&bh->b_count); } switch (UDF_I_ALLOCTYPE(inode)) { case ICBTAG_FLAG_AD_SHORT: { short_ad *sad = (short_ad *)ptr; sad->extLength = cpu_to_le32(elen); sad->extPosition = cpu_to_le32(eloc.logicalBlockNum); adsize = sizeof(short_ad); break; } case ICBTAG_FLAG_AD_LONG: { long_ad *lad = (long_ad *)ptr; lad->extLength = cpu_to_le32(elen); lad->extLocation = cpu_to_lelb(eloc); memset(lad->impUse, 0x00, sizeof(lad->impUse)); adsize = sizeof(long_ad); break; } default: return -1; } if (bh) { if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) { struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data; udf_update_tag((bh)->b_data, le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc)); } mark_buffer_dirty_inode(bh, inode); udf_release_data(bh); } else mark_inode_dirty(inode); if (inc) *extoffset += adsize; return (elen >> 30);}int8_t udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset, lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc){ int8_t etype; while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { *bloc = *eloc; *extoffset = sizeof(struct allocExtDesc); udf_release_data(*bh); if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) { udf_debug("reading block %d failed!\n", udf_get_lb_pblock(inode->i_sb, *bloc, 0)); return -1; } } return etype;}int8_t udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset, lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc){ int alen; int8_t etype; uint8_t *ptr; if (!*bh) { if (!(*extoffset)) *extoffset = udf_file_entry_alloc_offset(inode); ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode); } else { if (!(*extoffset)) *extoffset = sizeof(struct allocExtDesc); ptr = (*bh)->b_data + *extoffset; alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); } switch (UDF_I_ALLOCTYPE(inode)) { case ICBTAG_FLAG_AD_SHORT: { short_ad *sad; if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc))) return -1; etype = le32_to_cpu(sad->extLength) >> 30; eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK; break; } case ICBTAG_FLAG_AD_LONG: { long_ad *lad; if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc))) return -1; etype = le32_to_cpu(lad->extLength) >> 30; *eloc = lelb_to_cpu(lad->extLocation); *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; break; } default: { udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode)); return -1; } } return etype;}int8_t udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset, lb_addr neloc, uint32_t nelen, struct buffer_head *bh){ lb_addr oeloc; uint32_t oelen; int8_t etype; if (bh) atomic_inc(&bh->b_count); while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1) { udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); neloc = oeloc; nelen = (etype << 30) | oelen; } udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1); udf_release_data(bh); return (nelen >> 30);}int8_t udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset, lb_addr eloc, uint32_t elen, struct buffer_head *nbh){ struct buffer_head *obh; lb_addr obloc; int oextoffset, adsize; int8_t etype; struct allocExtDesc *aed; if (nbh) { atomic_inc(&nbh->b_count); atomic_inc(&nbh->b_count); } if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(short_ad); else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) adsize = sizeof(long_ad); else adsize = 0; obh = nbh; obloc = nbloc; oextoffset = nextoffset; if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1) return -1; while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) { udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1); if (obh != nbh) { obloc = nbloc; udf_release_data(obh); atomic_inc(&nbh->b_count); obh = nbh; oextoffset = nextoffset - adsize; } } memset(&eloc, 0x00, sizeof(lb_addr)); elen = 0; if (nbh != obh) { udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1); udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); if (!obh) { UDF_I_LENALLOC(inode) -= (adsize * 2); mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)(obh)->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize)); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) udf_update_tag((obh)->b_data, oextoffset - (2*adsize)); else udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); mark_buffer_dirty_inode(obh, inode); } } else { udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); if (!obh) { UDF_I_LENALLOC(inode) -= adsize; mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)(obh)->b_data; aed->lengthAllocDescs = cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) udf_update_tag((obh)->b_data, oextoffset - adsize); else udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); mark_buffer_dirty_inode(obh, inode); } } udf_release_data(nbh); udf_release_data(obh); return (elen >> 30);}int8_t inode_bmap(struct inode *inode, int block, lb_addr *bloc, uint32_t *extoffset, lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh){ uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits; int8_t etype; if (block < 0) { printk(KERN_ERR "udf: inode_bmap: block < 0\n"); return -1; } if (!inode) { printk(KERN_ERR "udf: inode_bmap: NULL inode\n"); return -1; } *extoffset = 0; *elen = 0; *bloc = UDF_I_LOCATION(inode); do { if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1) { *offset = bcount - lbcount; UDF_I_LENEXTENTS(inode) = lbcount; return -1; } lbcount += *elen; } while (lbcount <= bcount); *offset = bcount + *elen - lbcount; return etype;}long udf_block_map(struct inode *inode, long block){ lb_addr eloc, bloc; uint32_t offset, extoffset, elen; struct buffer_head *bh = NULL; int ret; lock_kernel(); if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits); else ret = 0; unlock_kernel(); udf_release_data(bh); if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) return udf_fixed_to_variable(ret); else return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -