18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * namei.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * PURPOSE 58c2ecf20Sopenharmony_ci * Inode name handling routines for the OSTA-UDF(tm) filesystem. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * COPYRIGHT 88c2ecf20Sopenharmony_ci * This file is distributed under the terms of the GNU General Public 98c2ecf20Sopenharmony_ci * License (GPL). Copies of the GPL can be obtained from: 108c2ecf20Sopenharmony_ci * ftp://prep.ai.mit.edu/pub/gnu/GPL 118c2ecf20Sopenharmony_ci * Each contributing author retains all rights to their own work. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * (C) 1998-2004 Ben Fennema 148c2ecf20Sopenharmony_ci * (C) 1999-2000 Stelias Computing Inc 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * HISTORY 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * 12/12/98 blf Created. Split out the lookup code from dir.c 198c2ecf20Sopenharmony_ci * 04/19/99 blf link, mknod, symlink support 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "udfdecl.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "udf_i.h" 258c2ecf20Sopenharmony_ci#include "udf_sb.h" 268c2ecf20Sopenharmony_ci#include <linux/string.h> 278c2ecf20Sopenharmony_ci#include <linux/errno.h> 288c2ecf20Sopenharmony_ci#include <linux/mm.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/sched.h> 318c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 328c2ecf20Sopenharmony_ci#include <linux/exportfs.h> 338c2ecf20Sopenharmony_ci#include <linux/iversion.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline int udf_match(int len1, const unsigned char *name1, int len2, 368c2ecf20Sopenharmony_ci const unsigned char *name2) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci if (len1 != len2) 398c2ecf20Sopenharmony_ci return 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return !memcmp(name1, name2, len1); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciint udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, 458c2ecf20Sopenharmony_ci struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh, 468c2ecf20Sopenharmony_ci uint8_t *impuse, uint8_t *fileident) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(struct tag); 498c2ecf20Sopenharmony_ci uint16_t crc; 508c2ecf20Sopenharmony_ci int offset; 518c2ecf20Sopenharmony_ci uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse); 528c2ecf20Sopenharmony_ci uint8_t lfi = cfi->lengthFileIdent; 538c2ecf20Sopenharmony_ci int padlen = fibh->eoffset - fibh->soffset - liu - lfi - 548c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc); 558c2ecf20Sopenharmony_ci int adinicb = 0; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 588c2ecf20Sopenharmony_ci adinicb = 1; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci offset = fibh->soffset + sizeof(struct fileIdentDesc); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (impuse) { 638c2ecf20Sopenharmony_ci if (adinicb || (offset + liu < 0)) { 648c2ecf20Sopenharmony_ci memcpy((uint8_t *)sfi->impUse, impuse, liu); 658c2ecf20Sopenharmony_ci } else if (offset >= 0) { 668c2ecf20Sopenharmony_ci memcpy(fibh->ebh->b_data + offset, impuse, liu); 678c2ecf20Sopenharmony_ci } else { 688c2ecf20Sopenharmony_ci memcpy((uint8_t *)sfi->impUse, impuse, -offset); 698c2ecf20Sopenharmony_ci memcpy(fibh->ebh->b_data, impuse - offset, 708c2ecf20Sopenharmony_ci liu + offset); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci offset += liu; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (fileident) { 778c2ecf20Sopenharmony_ci if (adinicb || (offset + lfi < 0)) { 788c2ecf20Sopenharmony_ci memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi); 798c2ecf20Sopenharmony_ci } else if (offset >= 0) { 808c2ecf20Sopenharmony_ci memcpy(fibh->ebh->b_data + offset, fileident, lfi); 818c2ecf20Sopenharmony_ci } else { 828c2ecf20Sopenharmony_ci memcpy((uint8_t *)sfi->fileIdent + liu, fileident, 838c2ecf20Sopenharmony_ci -offset); 848c2ecf20Sopenharmony_ci memcpy(fibh->ebh->b_data, fileident - offset, 858c2ecf20Sopenharmony_ci lfi + offset); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci offset += lfi; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (adinicb || (offset + padlen < 0)) { 928c2ecf20Sopenharmony_ci memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen); 938c2ecf20Sopenharmony_ci } else if (offset >= 0) { 948c2ecf20Sopenharmony_ci memset(fibh->ebh->b_data + offset, 0x00, padlen); 958c2ecf20Sopenharmony_ci } else { 968c2ecf20Sopenharmony_ci memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset); 978c2ecf20Sopenharmony_ci memset(fibh->ebh->b_data, 0x00, padlen + offset); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(struct tag), 1018c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc) - sizeof(struct tag)); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (fibh->sbh == fibh->ebh) { 1048c2ecf20Sopenharmony_ci crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, 1058c2ecf20Sopenharmony_ci crclen + sizeof(struct tag) - 1068c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc)); 1078c2ecf20Sopenharmony_ci } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) { 1088c2ecf20Sopenharmony_ci crc = crc_itu_t(crc, fibh->ebh->b_data + 1098c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc) + 1108c2ecf20Sopenharmony_ci fibh->soffset, 1118c2ecf20Sopenharmony_ci crclen + sizeof(struct tag) - 1128c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc)); 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, 1158c2ecf20Sopenharmony_ci -fibh->soffset - sizeof(struct fileIdentDesc)); 1168c2ecf20Sopenharmony_ci crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci cfi->descTag.descCRC = cpu_to_le16(crc); 1208c2ecf20Sopenharmony_ci cfi->descTag.descCRCLength = cpu_to_le16(crclen); 1218c2ecf20Sopenharmony_ci cfi->descTag.tagChecksum = udf_tag_checksum(&cfi->descTag); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) { 1248c2ecf20Sopenharmony_ci memcpy((uint8_t *)sfi, (uint8_t *)cfi, 1258c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc)); 1268c2ecf20Sopenharmony_ci } else { 1278c2ecf20Sopenharmony_ci memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset); 1288c2ecf20Sopenharmony_ci memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset, 1298c2ecf20Sopenharmony_ci sizeof(struct fileIdentDesc) + fibh->soffset); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (adinicb) { 1338c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 1348c2ecf20Sopenharmony_ci } else { 1358c2ecf20Sopenharmony_ci if (fibh->sbh != fibh->ebh) 1368c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(fibh->ebh, inode); 1378c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(fibh->sbh, inode); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci inode_inc_iversion(inode); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * udf_find_entry - find entry in given directory. 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * @dir: directory inode to search in 1488c2ecf20Sopenharmony_ci * @child: qstr of the name 1498c2ecf20Sopenharmony_ci * @fibh: buffer head / inode with file identifier descriptor we found 1508c2ecf20Sopenharmony_ci * @cfi: found file identifier descriptor with given name 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * This function searches in the directory @dir for a file name @child. When 1538c2ecf20Sopenharmony_ci * found, @fibh points to the buffer head(s) (bh is NULL for in ICB 1548c2ecf20Sopenharmony_ci * directories) containing the file identifier descriptor (FID). In that case 1558c2ecf20Sopenharmony_ci * the function returns pointer to the FID in the buffer or inode - but note 1568c2ecf20Sopenharmony_ci * that FID may be split among two buffers (blocks) so accessing it via that 1578c2ecf20Sopenharmony_ci * pointer isn't easily possible. This pointer can be used only as an iterator 1588c2ecf20Sopenharmony_ci * for other directory manipulation functions. For inspection of the FID @cfi 1598c2ecf20Sopenharmony_ci * can be used - the found FID is copied there. 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * Returns pointer to FID, NULL when nothing found, or error code. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic struct fileIdentDesc *udf_find_entry(struct inode *dir, 1648c2ecf20Sopenharmony_ci const struct qstr *child, 1658c2ecf20Sopenharmony_ci struct udf_fileident_bh *fibh, 1668c2ecf20Sopenharmony_ci struct fileIdentDesc *cfi) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct fileIdentDesc *fi = NULL; 1698c2ecf20Sopenharmony_ci loff_t f_pos; 1708c2ecf20Sopenharmony_ci udf_pblk_t block; 1718c2ecf20Sopenharmony_ci int flen; 1728c2ecf20Sopenharmony_ci unsigned char *fname = NULL, *copy_name = NULL; 1738c2ecf20Sopenharmony_ci unsigned char *nameptr; 1748c2ecf20Sopenharmony_ci uint8_t lfi; 1758c2ecf20Sopenharmony_ci uint16_t liu; 1768c2ecf20Sopenharmony_ci loff_t size; 1778c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 1788c2ecf20Sopenharmony_ci uint32_t elen; 1798c2ecf20Sopenharmony_ci sector_t offset; 1808c2ecf20Sopenharmony_ci struct extent_position epos = {}; 1818c2ecf20Sopenharmony_ci struct udf_inode_info *dinfo = UDF_I(dir); 1828c2ecf20Sopenharmony_ci int isdotdot = child->len == 2 && 1838c2ecf20Sopenharmony_ci child->name[0] == '.' && child->name[1] == '.'; 1848c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci size = udf_ext0_offset(dir) + dir->i_size; 1878c2ecf20Sopenharmony_ci f_pos = udf_ext0_offset(dir); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh = NULL; 1908c2ecf20Sopenharmony_ci fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1); 1918c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 1928c2ecf20Sopenharmony_ci if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos, 1938c2ecf20Sopenharmony_ci &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { 1948c2ecf20Sopenharmony_ci fi = ERR_PTR(-EIO); 1958c2ecf20Sopenharmony_ci goto out_err; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci block = udf_get_lb_pblock(sb, &eloc, offset); 1998c2ecf20Sopenharmony_ci if ((++offset << sb->s_blocksize_bits) < elen) { 2008c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 2018c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct short_ad); 2028c2ecf20Sopenharmony_ci else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 2038c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct long_ad); 2048c2ecf20Sopenharmony_ci } else 2058c2ecf20Sopenharmony_ci offset = 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh = udf_tread(sb, block); 2088c2ecf20Sopenharmony_ci if (!fibh->sbh) { 2098c2ecf20Sopenharmony_ci fi = ERR_PTR(-EIO); 2108c2ecf20Sopenharmony_ci goto out_err; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); 2158c2ecf20Sopenharmony_ci if (!fname) { 2168c2ecf20Sopenharmony_ci fi = ERR_PTR(-ENOMEM); 2178c2ecf20Sopenharmony_ci goto out_err; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci while (f_pos < size) { 2218c2ecf20Sopenharmony_ci fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, 2228c2ecf20Sopenharmony_ci &elen, &offset); 2238c2ecf20Sopenharmony_ci if (!fi) { 2248c2ecf20Sopenharmony_ci fi = ERR_PTR(-EIO); 2258c2ecf20Sopenharmony_ci goto out_err; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci liu = le16_to_cpu(cfi->lengthOfImpUse); 2298c2ecf20Sopenharmony_ci lfi = cfi->lengthFileIdent; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (fibh->sbh == fibh->ebh) { 2328c2ecf20Sopenharmony_ci nameptr = fi->fileIdent + liu; 2338c2ecf20Sopenharmony_ci } else { 2348c2ecf20Sopenharmony_ci int poffset; /* Unpaded ending offset */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci poffset = fibh->soffset + sizeof(struct fileIdentDesc) + 2378c2ecf20Sopenharmony_ci liu + lfi; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (poffset >= lfi) 2408c2ecf20Sopenharmony_ci nameptr = (uint8_t *)(fibh->ebh->b_data + 2418c2ecf20Sopenharmony_ci poffset - lfi); 2428c2ecf20Sopenharmony_ci else { 2438c2ecf20Sopenharmony_ci if (!copy_name) { 2448c2ecf20Sopenharmony_ci copy_name = kmalloc(UDF_NAME_LEN_CS0, 2458c2ecf20Sopenharmony_ci GFP_NOFS); 2468c2ecf20Sopenharmony_ci if (!copy_name) { 2478c2ecf20Sopenharmony_ci fi = ERR_PTR(-ENOMEM); 2488c2ecf20Sopenharmony_ci goto out_err; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci nameptr = copy_name; 2528c2ecf20Sopenharmony_ci memcpy(nameptr, fi->fileIdent + liu, 2538c2ecf20Sopenharmony_ci lfi - poffset); 2548c2ecf20Sopenharmony_ci memcpy(nameptr + lfi - poffset, 2558c2ecf20Sopenharmony_ci fibh->ebh->b_data, poffset); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { 2608c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) 2618c2ecf20Sopenharmony_ci continue; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) { 2658c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) 2668c2ecf20Sopenharmony_ci continue; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) && 2708c2ecf20Sopenharmony_ci isdotdot) 2718c2ecf20Sopenharmony_ci goto out_ok; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!lfi) 2748c2ecf20Sopenharmony_ci continue; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); 2778c2ecf20Sopenharmony_ci if (flen < 0) { 2788c2ecf20Sopenharmony_ci fi = ERR_PTR(flen); 2798c2ecf20Sopenharmony_ci goto out_err; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (udf_match(flen, fname, child->len, child->name)) 2838c2ecf20Sopenharmony_ci goto out_ok; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci fi = NULL; 2878c2ecf20Sopenharmony_ciout_err: 2888c2ecf20Sopenharmony_ci if (fibh->sbh != fibh->ebh) 2898c2ecf20Sopenharmony_ci brelse(fibh->ebh); 2908c2ecf20Sopenharmony_ci brelse(fibh->sbh); 2918c2ecf20Sopenharmony_ciout_ok: 2928c2ecf20Sopenharmony_ci brelse(epos.bh); 2938c2ecf20Sopenharmony_ci kfree(fname); 2948c2ecf20Sopenharmony_ci kfree(copy_name); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return fi; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, 3008c2ecf20Sopenharmony_ci unsigned int flags) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct inode *inode = NULL; 3038c2ecf20Sopenharmony_ci struct fileIdentDesc cfi; 3048c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 3058c2ecf20Sopenharmony_ci struct fileIdentDesc *fi; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (dentry->d_name.len > UDF_NAME_LEN) 3088c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); 3118c2ecf20Sopenharmony_ci if (IS_ERR(fi)) 3128c2ecf20Sopenharmony_ci return ERR_CAST(fi); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (fi) { 3158c2ecf20Sopenharmony_ci struct kernel_lb_addr loc; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 3188c2ecf20Sopenharmony_ci brelse(fibh.ebh); 3198c2ecf20Sopenharmony_ci brelse(fibh.sbh); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci loc = lelb_to_cpu(cfi.icb.extLocation); 3228c2ecf20Sopenharmony_ci inode = udf_iget(dir->i_sb, &loc); 3238c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 3248c2ecf20Sopenharmony_ci return ERR_CAST(inode); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic struct fileIdentDesc *udf_add_entry(struct inode *dir, 3318c2ecf20Sopenharmony_ci struct dentry *dentry, 3328c2ecf20Sopenharmony_ci struct udf_fileident_bh *fibh, 3338c2ecf20Sopenharmony_ci struct fileIdentDesc *cfi, int *err) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 3368c2ecf20Sopenharmony_ci struct fileIdentDesc *fi = NULL; 3378c2ecf20Sopenharmony_ci unsigned char *name = NULL; 3388c2ecf20Sopenharmony_ci int namelen; 3398c2ecf20Sopenharmony_ci loff_t f_pos; 3408c2ecf20Sopenharmony_ci loff_t size = udf_ext0_offset(dir) + dir->i_size; 3418c2ecf20Sopenharmony_ci int nfidlen; 3428c2ecf20Sopenharmony_ci udf_pblk_t block; 3438c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 3448c2ecf20Sopenharmony_ci uint32_t elen = 0; 3458c2ecf20Sopenharmony_ci sector_t offset; 3468c2ecf20Sopenharmony_ci struct extent_position epos = {}; 3478c2ecf20Sopenharmony_ci struct udf_inode_info *dinfo; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh = NULL; 3508c2ecf20Sopenharmony_ci name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS); 3518c2ecf20Sopenharmony_ci if (!name) { 3528c2ecf20Sopenharmony_ci *err = -ENOMEM; 3538c2ecf20Sopenharmony_ci goto out_err; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (dentry) { 3578c2ecf20Sopenharmony_ci if (!dentry->d_name.len) { 3588c2ecf20Sopenharmony_ci *err = -EINVAL; 3598c2ecf20Sopenharmony_ci goto out_err; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci namelen = udf_put_filename(sb, dentry->d_name.name, 3628c2ecf20Sopenharmony_ci dentry->d_name.len, 3638c2ecf20Sopenharmony_ci name, UDF_NAME_LEN_CS0); 3648c2ecf20Sopenharmony_ci if (!namelen) { 3658c2ecf20Sopenharmony_ci *err = -ENAMETOOLONG; 3668c2ecf20Sopenharmony_ci goto out_err; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } else { 3698c2ecf20Sopenharmony_ci namelen = 0; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci nfidlen = ALIGN(sizeof(struct fileIdentDesc) + namelen, UDF_NAME_PAD); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci f_pos = udf_ext0_offset(dir); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); 3778c2ecf20Sopenharmony_ci dinfo = UDF_I(dir); 3788c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 3798c2ecf20Sopenharmony_ci if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, 3808c2ecf20Sopenharmony_ci &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { 3818c2ecf20Sopenharmony_ci block = udf_get_lb_pblock(dir->i_sb, 3828c2ecf20Sopenharmony_ci &dinfo->i_location, 0); 3838c2ecf20Sopenharmony_ci fibh->soffset = fibh->eoffset = sb->s_blocksize; 3848c2ecf20Sopenharmony_ci goto add; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci block = udf_get_lb_pblock(dir->i_sb, &eloc, offset); 3878c2ecf20Sopenharmony_ci if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { 3888c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 3898c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct short_ad); 3908c2ecf20Sopenharmony_ci else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 3918c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct long_ad); 3928c2ecf20Sopenharmony_ci } else 3938c2ecf20Sopenharmony_ci offset = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 3968c2ecf20Sopenharmony_ci if (!fibh->sbh) { 3978c2ecf20Sopenharmony_ci *err = -EIO; 3988c2ecf20Sopenharmony_ci goto out_err; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci block = dinfo->i_location.logicalBlockNum; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci while (f_pos < size) { 4058c2ecf20Sopenharmony_ci fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, 4068c2ecf20Sopenharmony_ci &elen, &offset); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (!fi) { 4098c2ecf20Sopenharmony_ci *err = -EIO; 4108c2ecf20Sopenharmony_ci goto out_err; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { 4148c2ecf20Sopenharmony_ci if (udf_dir_entry_len(cfi) == nfidlen) { 4158c2ecf20Sopenharmony_ci cfi->descTag.tagSerialNum = cpu_to_le16(1); 4168c2ecf20Sopenharmony_ci cfi->fileVersionNum = cpu_to_le16(1); 4178c2ecf20Sopenharmony_ci cfi->fileCharacteristics = 0; 4188c2ecf20Sopenharmony_ci cfi->lengthFileIdent = namelen; 4198c2ecf20Sopenharmony_ci cfi->lengthOfImpUse = cpu_to_le16(0); 4208c2ecf20Sopenharmony_ci if (!udf_write_fi(dir, cfi, fi, fibh, NULL, 4218c2ecf20Sopenharmony_ci name)) 4228c2ecf20Sopenharmony_ci goto out_ok; 4238c2ecf20Sopenharmony_ci else { 4248c2ecf20Sopenharmony_ci *err = -EIO; 4258c2ecf20Sopenharmony_ci goto out_err; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciadd: 4328c2ecf20Sopenharmony_ci f_pos += nfidlen; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB && 4358c2ecf20Sopenharmony_ci sb->s_blocksize - fibh->eoffset < nfidlen) { 4368c2ecf20Sopenharmony_ci brelse(epos.bh); 4378c2ecf20Sopenharmony_ci epos.bh = NULL; 4388c2ecf20Sopenharmony_ci fibh->soffset -= udf_ext0_offset(dir); 4398c2ecf20Sopenharmony_ci fibh->eoffset -= udf_ext0_offset(dir); 4408c2ecf20Sopenharmony_ci f_pos -= udf_ext0_offset(dir); 4418c2ecf20Sopenharmony_ci if (fibh->sbh != fibh->ebh) 4428c2ecf20Sopenharmony_ci brelse(fibh->ebh); 4438c2ecf20Sopenharmony_ci brelse(fibh->sbh); 4448c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh = 4458c2ecf20Sopenharmony_ci udf_expand_dir_adinicb(dir, &block, err); 4468c2ecf20Sopenharmony_ci if (!fibh->sbh) 4478c2ecf20Sopenharmony_ci goto out_err; 4488c2ecf20Sopenharmony_ci epos.block = dinfo->i_location; 4498c2ecf20Sopenharmony_ci epos.offset = udf_file_entry_alloc_offset(dir); 4508c2ecf20Sopenharmony_ci /* Load extent udf_expand_dir_adinicb() has created */ 4518c2ecf20Sopenharmony_ci udf_current_aext(dir, &epos, &eloc, &elen, 1); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* Entry fits into current block? */ 4558c2ecf20Sopenharmony_ci if (sb->s_blocksize - fibh->eoffset >= nfidlen) { 4568c2ecf20Sopenharmony_ci fibh->soffset = fibh->eoffset; 4578c2ecf20Sopenharmony_ci fibh->eoffset += nfidlen; 4588c2ecf20Sopenharmony_ci if (fibh->sbh != fibh->ebh) { 4598c2ecf20Sopenharmony_ci brelse(fibh->sbh); 4608c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 4648c2ecf20Sopenharmony_ci block = dinfo->i_location.logicalBlockNum; 4658c2ecf20Sopenharmony_ci fi = (struct fileIdentDesc *) 4668c2ecf20Sopenharmony_ci (dinfo->i_data + fibh->soffset - 4678c2ecf20Sopenharmony_ci udf_ext0_offset(dir) + 4688c2ecf20Sopenharmony_ci dinfo->i_lenEAttr); 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci block = eloc.logicalBlockNum + 4718c2ecf20Sopenharmony_ci ((elen - 1) >> 4728c2ecf20Sopenharmony_ci dir->i_sb->s_blocksize_bits); 4738c2ecf20Sopenharmony_ci fi = (struct fileIdentDesc *) 4748c2ecf20Sopenharmony_ci (fibh->sbh->b_data + fibh->soffset); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } else { 4778c2ecf20Sopenharmony_ci /* Round up last extent in the file */ 4788c2ecf20Sopenharmony_ci elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1); 4798c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 4808c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct short_ad); 4818c2ecf20Sopenharmony_ci else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 4828c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct long_ad); 4838c2ecf20Sopenharmony_ci udf_write_aext(dir, &epos, &eloc, elen, 1); 4848c2ecf20Sopenharmony_ci dinfo->i_lenExtents = (dinfo->i_lenExtents + sb->s_blocksize 4858c2ecf20Sopenharmony_ci - 1) & ~(sb->s_blocksize - 1); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci fibh->soffset = fibh->eoffset - sb->s_blocksize; 4888c2ecf20Sopenharmony_ci fibh->eoffset += nfidlen - sb->s_blocksize; 4898c2ecf20Sopenharmony_ci if (fibh->sbh != fibh->ebh) { 4908c2ecf20Sopenharmony_ci brelse(fibh->sbh); 4918c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci block = eloc.logicalBlockNum + ((elen - 1) >> 4958c2ecf20Sopenharmony_ci dir->i_sb->s_blocksize_bits); 4968c2ecf20Sopenharmony_ci fibh->ebh = udf_bread(dir, 4978c2ecf20Sopenharmony_ci f_pos >> dir->i_sb->s_blocksize_bits, 1, err); 4988c2ecf20Sopenharmony_ci if (!fibh->ebh) 4998c2ecf20Sopenharmony_ci goto out_err; 5008c2ecf20Sopenharmony_ci /* Extents could have been merged, invalidate our position */ 5018c2ecf20Sopenharmony_ci brelse(epos.bh); 5028c2ecf20Sopenharmony_ci epos.bh = NULL; 5038c2ecf20Sopenharmony_ci epos.block = dinfo->i_location; 5048c2ecf20Sopenharmony_ci epos.offset = udf_file_entry_alloc_offset(dir); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (!fibh->soffset) { 5078c2ecf20Sopenharmony_ci /* Find the freshly allocated block */ 5088c2ecf20Sopenharmony_ci while (udf_next_aext(dir, &epos, &eloc, &elen, 1) == 5098c2ecf20Sopenharmony_ci (EXT_RECORDED_ALLOCATED >> 30)) 5108c2ecf20Sopenharmony_ci ; 5118c2ecf20Sopenharmony_ci block = eloc.logicalBlockNum + ((elen - 1) >> 5128c2ecf20Sopenharmony_ci dir->i_sb->s_blocksize_bits); 5138c2ecf20Sopenharmony_ci brelse(fibh->sbh); 5148c2ecf20Sopenharmony_ci fibh->sbh = fibh->ebh; 5158c2ecf20Sopenharmony_ci fi = (struct fileIdentDesc *)(fibh->sbh->b_data); 5168c2ecf20Sopenharmony_ci } else { 5178c2ecf20Sopenharmony_ci fi = (struct fileIdentDesc *) 5188c2ecf20Sopenharmony_ci (fibh->sbh->b_data + sb->s_blocksize + 5198c2ecf20Sopenharmony_ci fibh->soffset); 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci memset(cfi, 0, sizeof(struct fileIdentDesc)); 5248c2ecf20Sopenharmony_ci if (UDF_SB(sb)->s_udfrev >= 0x0200) 5258c2ecf20Sopenharmony_ci udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block, 5268c2ecf20Sopenharmony_ci sizeof(struct tag)); 5278c2ecf20Sopenharmony_ci else 5288c2ecf20Sopenharmony_ci udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block, 5298c2ecf20Sopenharmony_ci sizeof(struct tag)); 5308c2ecf20Sopenharmony_ci cfi->fileVersionNum = cpu_to_le16(1); 5318c2ecf20Sopenharmony_ci cfi->lengthFileIdent = namelen; 5328c2ecf20Sopenharmony_ci cfi->lengthOfImpUse = cpu_to_le16(0); 5338c2ecf20Sopenharmony_ci if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { 5348c2ecf20Sopenharmony_ci dir->i_size += nfidlen; 5358c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 5368c2ecf20Sopenharmony_ci dinfo->i_lenAlloc += nfidlen; 5378c2ecf20Sopenharmony_ci else { 5388c2ecf20Sopenharmony_ci /* Find the last extent and truncate it to proper size */ 5398c2ecf20Sopenharmony_ci while (udf_next_aext(dir, &epos, &eloc, &elen, 1) == 5408c2ecf20Sopenharmony_ci (EXT_RECORDED_ALLOCATED >> 30)) 5418c2ecf20Sopenharmony_ci ; 5428c2ecf20Sopenharmony_ci elen -= dinfo->i_lenExtents - dir->i_size; 5438c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 5448c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct short_ad); 5458c2ecf20Sopenharmony_ci else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 5468c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct long_ad); 5478c2ecf20Sopenharmony_ci udf_write_aext(dir, &epos, &eloc, elen, 1); 5488c2ecf20Sopenharmony_ci dinfo->i_lenExtents = dir->i_size; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 5528c2ecf20Sopenharmony_ci goto out_ok; 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci *err = -EIO; 5558c2ecf20Sopenharmony_ci goto out_err; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ciout_err: 5598c2ecf20Sopenharmony_ci fi = NULL; 5608c2ecf20Sopenharmony_ci if (fibh->sbh != fibh->ebh) 5618c2ecf20Sopenharmony_ci brelse(fibh->ebh); 5628c2ecf20Sopenharmony_ci brelse(fibh->sbh); 5638c2ecf20Sopenharmony_ciout_ok: 5648c2ecf20Sopenharmony_ci brelse(epos.bh); 5658c2ecf20Sopenharmony_ci kfree(name); 5668c2ecf20Sopenharmony_ci return fi; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, 5708c2ecf20Sopenharmony_ci struct udf_fileident_bh *fibh, 5718c2ecf20Sopenharmony_ci struct fileIdentDesc *cfi) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) 5768c2ecf20Sopenharmony_ci memset(&(cfi->icb), 0x00, sizeof(struct long_ad)); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int udf_add_nondir(struct dentry *dentry, struct inode *inode) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 5848c2ecf20Sopenharmony_ci struct inode *dir = d_inode(dentry->d_parent); 5858c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 5868c2ecf20Sopenharmony_ci struct fileIdentDesc cfi, *fi; 5878c2ecf20Sopenharmony_ci int err; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); 5908c2ecf20Sopenharmony_ci if (unlikely(!fi)) { 5918c2ecf20Sopenharmony_ci inode_dec_link_count(inode); 5928c2ecf20Sopenharmony_ci discard_new_inode(inode); 5938c2ecf20Sopenharmony_ci return err; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); 5968c2ecf20Sopenharmony_ci cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location); 5978c2ecf20Sopenharmony_ci *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = 5988c2ecf20Sopenharmony_ci cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL); 5998c2ecf20Sopenharmony_ci udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); 6008c2ecf20Sopenharmony_ci dir->i_ctime = dir->i_mtime = current_time(dir); 6018c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 6028c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 6038c2ecf20Sopenharmony_ci brelse(fibh.ebh); 6048c2ecf20Sopenharmony_ci brelse(fibh.sbh); 6058c2ecf20Sopenharmony_ci d_instantiate_new(dentry, inode); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode, 6118c2ecf20Sopenharmony_ci bool excl) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct inode *inode = udf_new_inode(dir, mode); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 6168c2ecf20Sopenharmony_ci return PTR_ERR(inode); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 6198c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_adinicb_aops; 6208c2ecf20Sopenharmony_ci else 6218c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_aops; 6228c2ecf20Sopenharmony_ci inode->i_op = &udf_file_inode_operations; 6238c2ecf20Sopenharmony_ci inode->i_fop = &udf_file_operations; 6248c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return udf_add_nondir(dentry, inode); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct inode *inode = udf_new_inode(dir, mode); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 6348c2ecf20Sopenharmony_ci return PTR_ERR(inode); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 6378c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_adinicb_aops; 6388c2ecf20Sopenharmony_ci else 6398c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_aops; 6408c2ecf20Sopenharmony_ci inode->i_op = &udf_file_inode_operations; 6418c2ecf20Sopenharmony_ci inode->i_fop = &udf_file_operations; 6428c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 6438c2ecf20Sopenharmony_ci d_tmpfile(dentry, inode); 6448c2ecf20Sopenharmony_ci unlock_new_inode(inode); 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, 6498c2ecf20Sopenharmony_ci dev_t rdev) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct inode *inode; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (!old_valid_dev(rdev)) 6548c2ecf20Sopenharmony_ci return -EINVAL; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci inode = udf_new_inode(dir, mode); 6578c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 6588c2ecf20Sopenharmony_ci return PTR_ERR(inode); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci init_special_inode(inode, mode, rdev); 6618c2ecf20Sopenharmony_ci return udf_add_nondir(dentry, inode); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct inode *inode; 6678c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 6688c2ecf20Sopenharmony_ci struct fileIdentDesc cfi, *fi; 6698c2ecf20Sopenharmony_ci int err; 6708c2ecf20Sopenharmony_ci struct udf_inode_info *dinfo = UDF_I(dir); 6718c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci inode = udf_new_inode(dir, S_IFDIR | mode); 6748c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 6758c2ecf20Sopenharmony_ci return PTR_ERR(inode); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 6788c2ecf20Sopenharmony_ci inode->i_op = &udf_dir_inode_operations; 6798c2ecf20Sopenharmony_ci inode->i_fop = &udf_dir_operations; 6808c2ecf20Sopenharmony_ci fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err); 6818c2ecf20Sopenharmony_ci if (!fi) { 6828c2ecf20Sopenharmony_ci inode_dec_link_count(inode); 6838c2ecf20Sopenharmony_ci discard_new_inode(inode); 6848c2ecf20Sopenharmony_ci goto out; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci set_nlink(inode, 2); 6878c2ecf20Sopenharmony_ci cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); 6888c2ecf20Sopenharmony_ci cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location); 6898c2ecf20Sopenharmony_ci *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = 6908c2ecf20Sopenharmony_ci cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL); 6918c2ecf20Sopenharmony_ci cfi.fileCharacteristics = 6928c2ecf20Sopenharmony_ci FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT; 6938c2ecf20Sopenharmony_ci udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL); 6948c2ecf20Sopenharmony_ci brelse(fibh.sbh); 6958c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); 6988c2ecf20Sopenharmony_ci if (!fi) { 6998c2ecf20Sopenharmony_ci clear_nlink(inode); 7008c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 7018c2ecf20Sopenharmony_ci discard_new_inode(inode); 7028c2ecf20Sopenharmony_ci goto out; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); 7058c2ecf20Sopenharmony_ci cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location); 7068c2ecf20Sopenharmony_ci *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = 7078c2ecf20Sopenharmony_ci cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL); 7088c2ecf20Sopenharmony_ci cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY; 7098c2ecf20Sopenharmony_ci udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); 7108c2ecf20Sopenharmony_ci inc_nlink(dir); 7118c2ecf20Sopenharmony_ci dir->i_ctime = dir->i_mtime = current_time(dir); 7128c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 7138c2ecf20Sopenharmony_ci d_instantiate_new(dentry, inode); 7148c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 7158c2ecf20Sopenharmony_ci brelse(fibh.ebh); 7168c2ecf20Sopenharmony_ci brelse(fibh.sbh); 7178c2ecf20Sopenharmony_ci err = 0; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ciout: 7208c2ecf20Sopenharmony_ci return err; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int empty_dir(struct inode *dir) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct fileIdentDesc *fi, cfi; 7268c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 7278c2ecf20Sopenharmony_ci loff_t f_pos; 7288c2ecf20Sopenharmony_ci loff_t size = udf_ext0_offset(dir) + dir->i_size; 7298c2ecf20Sopenharmony_ci udf_pblk_t block; 7308c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 7318c2ecf20Sopenharmony_ci uint32_t elen; 7328c2ecf20Sopenharmony_ci sector_t offset; 7338c2ecf20Sopenharmony_ci struct extent_position epos = {}; 7348c2ecf20Sopenharmony_ci struct udf_inode_info *dinfo = UDF_I(dir); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci f_pos = udf_ext0_offset(dir); 7378c2ecf20Sopenharmony_ci fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 7408c2ecf20Sopenharmony_ci fibh.sbh = fibh.ebh = NULL; 7418c2ecf20Sopenharmony_ci else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, 7428c2ecf20Sopenharmony_ci &epos, &eloc, &elen, &offset) == 7438c2ecf20Sopenharmony_ci (EXT_RECORDED_ALLOCATED >> 30)) { 7448c2ecf20Sopenharmony_ci block = udf_get_lb_pblock(dir->i_sb, &eloc, offset); 7458c2ecf20Sopenharmony_ci if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { 7468c2ecf20Sopenharmony_ci if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 7478c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct short_ad); 7488c2ecf20Sopenharmony_ci else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 7498c2ecf20Sopenharmony_ci epos.offset -= sizeof(struct long_ad); 7508c2ecf20Sopenharmony_ci } else 7518c2ecf20Sopenharmony_ci offset = 0; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block); 7548c2ecf20Sopenharmony_ci if (!fibh.sbh) { 7558c2ecf20Sopenharmony_ci brelse(epos.bh); 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci } else { 7598c2ecf20Sopenharmony_ci brelse(epos.bh); 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci while (f_pos < size) { 7648c2ecf20Sopenharmony_ci fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc, 7658c2ecf20Sopenharmony_ci &elen, &offset); 7668c2ecf20Sopenharmony_ci if (!fi) { 7678c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 7688c2ecf20Sopenharmony_ci brelse(fibh.ebh); 7698c2ecf20Sopenharmony_ci brelse(fibh.sbh); 7708c2ecf20Sopenharmony_ci brelse(epos.bh); 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (cfi.lengthFileIdent && 7758c2ecf20Sopenharmony_ci (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) { 7768c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 7778c2ecf20Sopenharmony_ci brelse(fibh.ebh); 7788c2ecf20Sopenharmony_ci brelse(fibh.sbh); 7798c2ecf20Sopenharmony_ci brelse(epos.bh); 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 7858c2ecf20Sopenharmony_ci brelse(fibh.ebh); 7868c2ecf20Sopenharmony_ci brelse(fibh.sbh); 7878c2ecf20Sopenharmony_ci brelse(epos.bh); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return 1; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic int udf_rmdir(struct inode *dir, struct dentry *dentry) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci int retval; 7958c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 7968c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 7978c2ecf20Sopenharmony_ci struct fileIdentDesc *fi, cfi; 7988c2ecf20Sopenharmony_ci struct kernel_lb_addr tloc; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci retval = -ENOENT; 8018c2ecf20Sopenharmony_ci fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); 8028c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(fi)) { 8038c2ecf20Sopenharmony_ci if (fi) 8048c2ecf20Sopenharmony_ci retval = PTR_ERR(fi); 8058c2ecf20Sopenharmony_ci goto out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci retval = -EIO; 8098c2ecf20Sopenharmony_ci tloc = lelb_to_cpu(cfi.icb.extLocation); 8108c2ecf20Sopenharmony_ci if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino) 8118c2ecf20Sopenharmony_ci goto end_rmdir; 8128c2ecf20Sopenharmony_ci retval = -ENOTEMPTY; 8138c2ecf20Sopenharmony_ci if (!empty_dir(inode)) 8148c2ecf20Sopenharmony_ci goto end_rmdir; 8158c2ecf20Sopenharmony_ci retval = udf_delete_entry(dir, fi, &fibh, &cfi); 8168c2ecf20Sopenharmony_ci if (retval) 8178c2ecf20Sopenharmony_ci goto end_rmdir; 8188c2ecf20Sopenharmony_ci if (inode->i_nlink != 2) 8198c2ecf20Sopenharmony_ci udf_warn(inode->i_sb, "empty directory has nlink != 2 (%u)\n", 8208c2ecf20Sopenharmony_ci inode->i_nlink); 8218c2ecf20Sopenharmony_ci clear_nlink(inode); 8228c2ecf20Sopenharmony_ci inode->i_size = 0; 8238c2ecf20Sopenharmony_ci inode_dec_link_count(dir); 8248c2ecf20Sopenharmony_ci inode->i_ctime = dir->i_ctime = dir->i_mtime = 8258c2ecf20Sopenharmony_ci current_time(inode); 8268c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ciend_rmdir: 8298c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 8308c2ecf20Sopenharmony_ci brelse(fibh.ebh); 8318c2ecf20Sopenharmony_ci brelse(fibh.sbh); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ciout: 8348c2ecf20Sopenharmony_ci return retval; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int udf_unlink(struct inode *dir, struct dentry *dentry) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci int retval; 8408c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 8418c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 8428c2ecf20Sopenharmony_ci struct fileIdentDesc *fi; 8438c2ecf20Sopenharmony_ci struct fileIdentDesc cfi; 8448c2ecf20Sopenharmony_ci struct kernel_lb_addr tloc; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci retval = -ENOENT; 8478c2ecf20Sopenharmony_ci fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(fi)) { 8508c2ecf20Sopenharmony_ci if (fi) 8518c2ecf20Sopenharmony_ci retval = PTR_ERR(fi); 8528c2ecf20Sopenharmony_ci goto out; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci retval = -EIO; 8568c2ecf20Sopenharmony_ci tloc = lelb_to_cpu(cfi.icb.extLocation); 8578c2ecf20Sopenharmony_ci if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino) 8588c2ecf20Sopenharmony_ci goto end_unlink; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (!inode->i_nlink) { 8618c2ecf20Sopenharmony_ci udf_debug("Deleting nonexistent file (%lu), %u\n", 8628c2ecf20Sopenharmony_ci inode->i_ino, inode->i_nlink); 8638c2ecf20Sopenharmony_ci set_nlink(inode, 1); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci retval = udf_delete_entry(dir, fi, &fibh, &cfi); 8668c2ecf20Sopenharmony_ci if (retval) 8678c2ecf20Sopenharmony_ci goto end_unlink; 8688c2ecf20Sopenharmony_ci dir->i_ctime = dir->i_mtime = current_time(dir); 8698c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 8708c2ecf20Sopenharmony_ci inode_dec_link_count(inode); 8718c2ecf20Sopenharmony_ci inode->i_ctime = dir->i_ctime; 8728c2ecf20Sopenharmony_ci retval = 0; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ciend_unlink: 8758c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 8768c2ecf20Sopenharmony_ci brelse(fibh.ebh); 8778c2ecf20Sopenharmony_ci brelse(fibh.sbh); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ciout: 8808c2ecf20Sopenharmony_ci return retval; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int udf_symlink(struct inode *dir, struct dentry *dentry, 8848c2ecf20Sopenharmony_ci const char *symname) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct inode *inode = udf_new_inode(dir, S_IFLNK | 0777); 8878c2ecf20Sopenharmony_ci struct pathComponent *pc; 8888c2ecf20Sopenharmony_ci const char *compstart; 8898c2ecf20Sopenharmony_ci struct extent_position epos = {}; 8908c2ecf20Sopenharmony_ci int eoffset, elen = 0; 8918c2ecf20Sopenharmony_ci uint8_t *ea; 8928c2ecf20Sopenharmony_ci int err; 8938c2ecf20Sopenharmony_ci udf_pblk_t block; 8948c2ecf20Sopenharmony_ci unsigned char *name = NULL; 8958c2ecf20Sopenharmony_ci int namelen; 8968c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 8978c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 9008c2ecf20Sopenharmony_ci return PTR_ERR(inode); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 9038c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 9048c2ecf20Sopenharmony_ci name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS); 9058c2ecf20Sopenharmony_ci if (!name) { 9068c2ecf20Sopenharmony_ci err = -ENOMEM; 9078c2ecf20Sopenharmony_ci goto out_no_entry; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_symlink_aops; 9118c2ecf20Sopenharmony_ci inode->i_op = &udf_symlink_inode_operations; 9128c2ecf20Sopenharmony_ci inode_nohighmem(inode); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 9158c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 9168c2ecf20Sopenharmony_ci uint32_t bsize; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci block = udf_new_block(sb, inode, 9198c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum, 9208c2ecf20Sopenharmony_ci iinfo->i_location.logicalBlockNum, &err); 9218c2ecf20Sopenharmony_ci if (!block) 9228c2ecf20Sopenharmony_ci goto out_no_entry; 9238c2ecf20Sopenharmony_ci epos.block = iinfo->i_location; 9248c2ecf20Sopenharmony_ci epos.offset = udf_file_entry_alloc_offset(inode); 9258c2ecf20Sopenharmony_ci epos.bh = NULL; 9268c2ecf20Sopenharmony_ci eloc.logicalBlockNum = block; 9278c2ecf20Sopenharmony_ci eloc.partitionReferenceNum = 9288c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum; 9298c2ecf20Sopenharmony_ci bsize = sb->s_blocksize; 9308c2ecf20Sopenharmony_ci iinfo->i_lenExtents = bsize; 9318c2ecf20Sopenharmony_ci udf_add_aext(inode, &epos, &eloc, bsize, 0); 9328c2ecf20Sopenharmony_ci brelse(epos.bh); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci block = udf_get_pblock(sb, block, 9358c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum, 9368c2ecf20Sopenharmony_ci 0); 9378c2ecf20Sopenharmony_ci epos.bh = udf_tgetblk(sb, block); 9388c2ecf20Sopenharmony_ci if (unlikely(!epos.bh)) { 9398c2ecf20Sopenharmony_ci err = -ENOMEM; 9408c2ecf20Sopenharmony_ci goto out_no_entry; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci lock_buffer(epos.bh); 9438c2ecf20Sopenharmony_ci memset(epos.bh->b_data, 0x00, bsize); 9448c2ecf20Sopenharmony_ci set_buffer_uptodate(epos.bh); 9458c2ecf20Sopenharmony_ci unlock_buffer(epos.bh); 9468c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(epos.bh, inode); 9478c2ecf20Sopenharmony_ci ea = epos.bh->b_data + udf_ext0_offset(inode); 9488c2ecf20Sopenharmony_ci } else 9498c2ecf20Sopenharmony_ci ea = iinfo->i_data + iinfo->i_lenEAttr; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci eoffset = sb->s_blocksize - udf_ext0_offset(inode); 9528c2ecf20Sopenharmony_ci pc = (struct pathComponent *)ea; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (*symname == '/') { 9558c2ecf20Sopenharmony_ci do { 9568c2ecf20Sopenharmony_ci symname++; 9578c2ecf20Sopenharmony_ci } while (*symname == '/'); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci pc->componentType = 1; 9608c2ecf20Sopenharmony_ci pc->lengthComponentIdent = 0; 9618c2ecf20Sopenharmony_ci pc->componentFileVersionNum = 0; 9628c2ecf20Sopenharmony_ci elen += sizeof(struct pathComponent); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci while (*symname) { 9688c2ecf20Sopenharmony_ci if (elen + sizeof(struct pathComponent) > eoffset) 9698c2ecf20Sopenharmony_ci goto out_no_entry; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci pc = (struct pathComponent *)(ea + elen); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci compstart = symname; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci do { 9768c2ecf20Sopenharmony_ci symname++; 9778c2ecf20Sopenharmony_ci } while (*symname && *symname != '/'); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci pc->componentType = 5; 9808c2ecf20Sopenharmony_ci pc->lengthComponentIdent = 0; 9818c2ecf20Sopenharmony_ci pc->componentFileVersionNum = 0; 9828c2ecf20Sopenharmony_ci if (compstart[0] == '.') { 9838c2ecf20Sopenharmony_ci if ((symname - compstart) == 1) 9848c2ecf20Sopenharmony_ci pc->componentType = 4; 9858c2ecf20Sopenharmony_ci else if ((symname - compstart) == 2 && 9868c2ecf20Sopenharmony_ci compstart[1] == '.') 9878c2ecf20Sopenharmony_ci pc->componentType = 3; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (pc->componentType == 5) { 9918c2ecf20Sopenharmony_ci namelen = udf_put_filename(sb, compstart, 9928c2ecf20Sopenharmony_ci symname - compstart, 9938c2ecf20Sopenharmony_ci name, UDF_NAME_LEN_CS0); 9948c2ecf20Sopenharmony_ci if (!namelen) 9958c2ecf20Sopenharmony_ci goto out_no_entry; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (elen + sizeof(struct pathComponent) + namelen > 9988c2ecf20Sopenharmony_ci eoffset) 9998c2ecf20Sopenharmony_ci goto out_no_entry; 10008c2ecf20Sopenharmony_ci else 10018c2ecf20Sopenharmony_ci pc->lengthComponentIdent = namelen; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci memcpy(pc->componentIdent, name, namelen); 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (*symname) { 10098c2ecf20Sopenharmony_ci do { 10108c2ecf20Sopenharmony_ci symname++; 10118c2ecf20Sopenharmony_ci } while (*symname == '/'); 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci brelse(epos.bh); 10168c2ecf20Sopenharmony_ci inode->i_size = elen; 10178c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 10188c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = inode->i_size; 10198c2ecf20Sopenharmony_ci else 10208c2ecf20Sopenharmony_ci udf_truncate_tail_extent(inode); 10218c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 10228c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci err = udf_add_nondir(dentry, inode); 10258c2ecf20Sopenharmony_ciout: 10268c2ecf20Sopenharmony_ci kfree(name); 10278c2ecf20Sopenharmony_ci return err; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ciout_no_entry: 10308c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 10318c2ecf20Sopenharmony_ci inode_dec_link_count(inode); 10328c2ecf20Sopenharmony_ci discard_new_inode(inode); 10338c2ecf20Sopenharmony_ci goto out; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic int udf_link(struct dentry *old_dentry, struct inode *dir, 10378c2ecf20Sopenharmony_ci struct dentry *dentry) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct inode *inode = d_inode(old_dentry); 10408c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 10418c2ecf20Sopenharmony_ci struct fileIdentDesc cfi, *fi; 10428c2ecf20Sopenharmony_ci int err; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); 10458c2ecf20Sopenharmony_ci if (!fi) { 10468c2ecf20Sopenharmony_ci return err; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); 10498c2ecf20Sopenharmony_ci cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location); 10508c2ecf20Sopenharmony_ci if (UDF_SB(inode->i_sb)->s_lvid_bh) { 10518c2ecf20Sopenharmony_ci *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = 10528c2ecf20Sopenharmony_ci cpu_to_le32(lvid_get_unique_id(inode->i_sb)); 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); 10558c2ecf20Sopenharmony_ci if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 10568c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 10598c2ecf20Sopenharmony_ci brelse(fibh.ebh); 10608c2ecf20Sopenharmony_ci brelse(fibh.sbh); 10618c2ecf20Sopenharmony_ci inc_nlink(inode); 10628c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 10638c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 10648c2ecf20Sopenharmony_ci dir->i_ctime = dir->i_mtime = current_time(dir); 10658c2ecf20Sopenharmony_ci mark_inode_dirty(dir); 10668c2ecf20Sopenharmony_ci ihold(inode); 10678c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci return 0; 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci/* Anybody can rename anything with this: the permission checks are left to the 10738c2ecf20Sopenharmony_ci * higher-level routines. 10748c2ecf20Sopenharmony_ci */ 10758c2ecf20Sopenharmony_cistatic int udf_rename(struct inode *old_dir, struct dentry *old_dentry, 10768c2ecf20Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 10778c2ecf20Sopenharmony_ci unsigned int flags) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci struct inode *old_inode = d_inode(old_dentry); 10808c2ecf20Sopenharmony_ci struct inode *new_inode = d_inode(new_dentry); 10818c2ecf20Sopenharmony_ci struct udf_fileident_bh ofibh, nfibh; 10828c2ecf20Sopenharmony_ci struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL; 10838c2ecf20Sopenharmony_ci struct fileIdentDesc ocfi, ncfi; 10848c2ecf20Sopenharmony_ci struct buffer_head *dir_bh = NULL; 10858c2ecf20Sopenharmony_ci int retval = -ENOENT; 10868c2ecf20Sopenharmony_ci struct kernel_lb_addr tloc; 10878c2ecf20Sopenharmony_ci struct udf_inode_info *old_iinfo = UDF_I(old_inode); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (flags & ~RENAME_NOREPLACE) 10908c2ecf20Sopenharmony_ci return -EINVAL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi); 10938c2ecf20Sopenharmony_ci if (!ofi || IS_ERR(ofi)) { 10948c2ecf20Sopenharmony_ci if (IS_ERR(ofi)) 10958c2ecf20Sopenharmony_ci retval = PTR_ERR(ofi); 10968c2ecf20Sopenharmony_ci goto end_rename; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (ofibh.sbh != ofibh.ebh) 11008c2ecf20Sopenharmony_ci brelse(ofibh.ebh); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci brelse(ofibh.sbh); 11038c2ecf20Sopenharmony_ci tloc = lelb_to_cpu(ocfi.icb.extLocation); 11048c2ecf20Sopenharmony_ci if (udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) != old_inode->i_ino) 11058c2ecf20Sopenharmony_ci goto end_rename; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi); 11088c2ecf20Sopenharmony_ci if (IS_ERR(nfi)) { 11098c2ecf20Sopenharmony_ci retval = PTR_ERR(nfi); 11108c2ecf20Sopenharmony_ci goto end_rename; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci if (nfi && !new_inode) { 11138c2ecf20Sopenharmony_ci if (nfibh.sbh != nfibh.ebh) 11148c2ecf20Sopenharmony_ci brelse(nfibh.ebh); 11158c2ecf20Sopenharmony_ci brelse(nfibh.sbh); 11168c2ecf20Sopenharmony_ci nfi = NULL; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci if (S_ISDIR(old_inode->i_mode)) { 11198c2ecf20Sopenharmony_ci int offset = udf_ext0_offset(old_inode); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (new_inode) { 11228c2ecf20Sopenharmony_ci retval = -ENOTEMPTY; 11238c2ecf20Sopenharmony_ci if (!empty_dir(new_inode)) 11248c2ecf20Sopenharmony_ci goto end_rename; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci retval = -EIO; 11278c2ecf20Sopenharmony_ci if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 11288c2ecf20Sopenharmony_ci dir_fi = udf_get_fileident( 11298c2ecf20Sopenharmony_ci old_iinfo->i_data - 11308c2ecf20Sopenharmony_ci (old_iinfo->i_efe ? 11318c2ecf20Sopenharmony_ci sizeof(struct extendedFileEntry) : 11328c2ecf20Sopenharmony_ci sizeof(struct fileEntry)), 11338c2ecf20Sopenharmony_ci old_inode->i_sb->s_blocksize, &offset); 11348c2ecf20Sopenharmony_ci } else { 11358c2ecf20Sopenharmony_ci dir_bh = udf_bread(old_inode, 0, 0, &retval); 11368c2ecf20Sopenharmony_ci if (!dir_bh) 11378c2ecf20Sopenharmony_ci goto end_rename; 11388c2ecf20Sopenharmony_ci dir_fi = udf_get_fileident(dir_bh->b_data, 11398c2ecf20Sopenharmony_ci old_inode->i_sb->s_blocksize, &offset); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci if (!dir_fi) 11428c2ecf20Sopenharmony_ci goto end_rename; 11438c2ecf20Sopenharmony_ci tloc = lelb_to_cpu(dir_fi->icb.extLocation); 11448c2ecf20Sopenharmony_ci if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) != 11458c2ecf20Sopenharmony_ci old_dir->i_ino) 11468c2ecf20Sopenharmony_ci goto end_rename; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci if (!nfi) { 11498c2ecf20Sopenharmony_ci nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, 11508c2ecf20Sopenharmony_ci &retval); 11518c2ecf20Sopenharmony_ci if (!nfi) 11528c2ecf20Sopenharmony_ci goto end_rename; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * Like most other Unix systems, set the ctime for inodes on a 11578c2ecf20Sopenharmony_ci * rename. 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci old_inode->i_ctime = current_time(old_inode); 11608c2ecf20Sopenharmony_ci mark_inode_dirty(old_inode); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * ok, that's it 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ci ncfi.fileVersionNum = ocfi.fileVersionNum; 11668c2ecf20Sopenharmony_ci ncfi.fileCharacteristics = ocfi.fileCharacteristics; 11678c2ecf20Sopenharmony_ci memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(ocfi.icb)); 11688c2ecf20Sopenharmony_ci udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* The old fid may have moved - find it again */ 11718c2ecf20Sopenharmony_ci ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi); 11728c2ecf20Sopenharmony_ci udf_delete_entry(old_dir, ofi, &ofibh, &ocfi); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (new_inode) { 11758c2ecf20Sopenharmony_ci new_inode->i_ctime = current_time(new_inode); 11768c2ecf20Sopenharmony_ci inode_dec_link_count(new_inode); 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); 11798c2ecf20Sopenharmony_ci new_dir->i_ctime = new_dir->i_mtime = current_time(new_dir); 11808c2ecf20Sopenharmony_ci mark_inode_dirty(old_dir); 11818c2ecf20Sopenharmony_ci mark_inode_dirty(new_dir); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (dir_fi) { 11848c2ecf20Sopenharmony_ci dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location); 11858c2ecf20Sopenharmony_ci udf_update_tag((char *)dir_fi, udf_dir_entry_len(dir_fi)); 11868c2ecf20Sopenharmony_ci if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 11878c2ecf20Sopenharmony_ci mark_inode_dirty(old_inode); 11888c2ecf20Sopenharmony_ci else 11898c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(dir_bh, old_inode); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci inode_dec_link_count(old_dir); 11928c2ecf20Sopenharmony_ci if (new_inode) 11938c2ecf20Sopenharmony_ci inode_dec_link_count(new_inode); 11948c2ecf20Sopenharmony_ci else { 11958c2ecf20Sopenharmony_ci inc_nlink(new_dir); 11968c2ecf20Sopenharmony_ci mark_inode_dirty(new_dir); 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (ofi) { 12018c2ecf20Sopenharmony_ci if (ofibh.sbh != ofibh.ebh) 12028c2ecf20Sopenharmony_ci brelse(ofibh.ebh); 12038c2ecf20Sopenharmony_ci brelse(ofibh.sbh); 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci retval = 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ciend_rename: 12098c2ecf20Sopenharmony_ci brelse(dir_bh); 12108c2ecf20Sopenharmony_ci if (nfi) { 12118c2ecf20Sopenharmony_ci if (nfibh.sbh != nfibh.ebh) 12128c2ecf20Sopenharmony_ci brelse(nfibh.ebh); 12138c2ecf20Sopenharmony_ci brelse(nfibh.sbh); 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci return retval; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic struct dentry *udf_get_parent(struct dentry *child) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct kernel_lb_addr tloc; 12228c2ecf20Sopenharmony_ci struct inode *inode = NULL; 12238c2ecf20Sopenharmony_ci struct qstr dotdot = QSTR_INIT("..", 2); 12248c2ecf20Sopenharmony_ci struct fileIdentDesc cfi; 12258c2ecf20Sopenharmony_ci struct udf_fileident_bh fibh; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (!udf_find_entry(d_inode(child), &dotdot, &fibh, &cfi)) 12288c2ecf20Sopenharmony_ci return ERR_PTR(-EACCES); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (fibh.sbh != fibh.ebh) 12318c2ecf20Sopenharmony_ci brelse(fibh.ebh); 12328c2ecf20Sopenharmony_ci brelse(fibh.sbh); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci tloc = lelb_to_cpu(cfi.icb.extLocation); 12358c2ecf20Sopenharmony_ci inode = udf_iget(child->d_sb, &tloc); 12368c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 12378c2ecf20Sopenharmony_ci return ERR_CAST(inode); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci return d_obtain_alias(inode); 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block, 12448c2ecf20Sopenharmony_ci u16 partref, __u32 generation) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct inode *inode; 12478c2ecf20Sopenharmony_ci struct kernel_lb_addr loc; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (block == 0) 12508c2ecf20Sopenharmony_ci return ERR_PTR(-ESTALE); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci loc.logicalBlockNum = block; 12538c2ecf20Sopenharmony_ci loc.partitionReferenceNum = partref; 12548c2ecf20Sopenharmony_ci inode = udf_iget(sb, &loc); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 12578c2ecf20Sopenharmony_ci return ERR_CAST(inode); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (generation && inode->i_generation != generation) { 12608c2ecf20Sopenharmony_ci iput(inode); 12618c2ecf20Sopenharmony_ci return ERR_PTR(-ESTALE); 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci return d_obtain_alias(inode); 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cistatic struct dentry *udf_fh_to_dentry(struct super_block *sb, 12678c2ecf20Sopenharmony_ci struct fid *fid, int fh_len, int fh_type) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci if (fh_len < 3 || 12708c2ecf20Sopenharmony_ci (fh_type != FILEID_UDF_WITH_PARENT && 12718c2ecf20Sopenharmony_ci fh_type != FILEID_UDF_WITHOUT_PARENT)) 12728c2ecf20Sopenharmony_ci return NULL; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref, 12758c2ecf20Sopenharmony_ci fid->udf.generation); 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic struct dentry *udf_fh_to_parent(struct super_block *sb, 12798c2ecf20Sopenharmony_ci struct fid *fid, int fh_len, int fh_type) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci if (fh_len < 5 || fh_type != FILEID_UDF_WITH_PARENT) 12828c2ecf20Sopenharmony_ci return NULL; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return udf_nfs_get_inode(sb, fid->udf.parent_block, 12858c2ecf20Sopenharmony_ci fid->udf.parent_partref, 12868c2ecf20Sopenharmony_ci fid->udf.parent_generation); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_cistatic int udf_encode_fh(struct inode *inode, __u32 *fh, int *lenp, 12898c2ecf20Sopenharmony_ci struct inode *parent) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci int len = *lenp; 12928c2ecf20Sopenharmony_ci struct kernel_lb_addr location = UDF_I(inode)->i_location; 12938c2ecf20Sopenharmony_ci struct fid *fid = (struct fid *)fh; 12948c2ecf20Sopenharmony_ci int type = FILEID_UDF_WITHOUT_PARENT; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (parent && (len < 5)) { 12978c2ecf20Sopenharmony_ci *lenp = 5; 12988c2ecf20Sopenharmony_ci return FILEID_INVALID; 12998c2ecf20Sopenharmony_ci } else if (len < 3) { 13008c2ecf20Sopenharmony_ci *lenp = 3; 13018c2ecf20Sopenharmony_ci return FILEID_INVALID; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci *lenp = 3; 13058c2ecf20Sopenharmony_ci fid->udf.block = location.logicalBlockNum; 13068c2ecf20Sopenharmony_ci fid->udf.partref = location.partitionReferenceNum; 13078c2ecf20Sopenharmony_ci fid->udf.parent_partref = 0; 13088c2ecf20Sopenharmony_ci fid->udf.generation = inode->i_generation; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (parent) { 13118c2ecf20Sopenharmony_ci location = UDF_I(parent)->i_location; 13128c2ecf20Sopenharmony_ci fid->udf.parent_block = location.logicalBlockNum; 13138c2ecf20Sopenharmony_ci fid->udf.parent_partref = location.partitionReferenceNum; 13148c2ecf20Sopenharmony_ci fid->udf.parent_generation = inode->i_generation; 13158c2ecf20Sopenharmony_ci *lenp = 5; 13168c2ecf20Sopenharmony_ci type = FILEID_UDF_WITH_PARENT; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci return type; 13208c2ecf20Sopenharmony_ci} 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ciconst struct export_operations udf_export_ops = { 13238c2ecf20Sopenharmony_ci .encode_fh = udf_encode_fh, 13248c2ecf20Sopenharmony_ci .fh_to_dentry = udf_fh_to_dentry, 13258c2ecf20Sopenharmony_ci .fh_to_parent = udf_fh_to_parent, 13268c2ecf20Sopenharmony_ci .get_parent = udf_get_parent, 13278c2ecf20Sopenharmony_ci}; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ciconst struct inode_operations udf_dir_inode_operations = { 13308c2ecf20Sopenharmony_ci .lookup = udf_lookup, 13318c2ecf20Sopenharmony_ci .create = udf_create, 13328c2ecf20Sopenharmony_ci .link = udf_link, 13338c2ecf20Sopenharmony_ci .unlink = udf_unlink, 13348c2ecf20Sopenharmony_ci .symlink = udf_symlink, 13358c2ecf20Sopenharmony_ci .mkdir = udf_mkdir, 13368c2ecf20Sopenharmony_ci .rmdir = udf_rmdir, 13378c2ecf20Sopenharmony_ci .mknod = udf_mknod, 13388c2ecf20Sopenharmony_ci .rename = udf_rename, 13398c2ecf20Sopenharmony_ci .tmpfile = udf_tmpfile, 13408c2ecf20Sopenharmony_ci}; 1341