diff options
Diffstat (limited to 'fs/udf')
-rw-r--r-- | fs/udf/dir.c | 2 | ||||
-rw-r--r-- | fs/udf/file.c | 2 | ||||
-rw-r--r-- | fs/udf/namei.c | 95 | ||||
-rw-r--r-- | fs/udf/super.c | 26 | ||||
-rw-r--r-- | fs/udf/symlink.c | 3 | ||||
-rw-r--r-- | fs/udf/unicode.c | 49 |
6 files changed, 119 insertions, 58 deletions
diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 541a12b5792d..541d9c65014d 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -168,7 +168,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx) } flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); - if (!flen) + if (flen < 0) continue; tloc = lelb_to_cpu(cfi.icb.extLocation); diff --git a/fs/udf/file.c b/fs/udf/file.c index 7a95b8fed302..bddf3d071dae 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -152,8 +152,6 @@ out: mutex_unlock(&inode->i_mutex); if (retval > 0) { - ssize_t err; - mark_inode_dirty(inode); err = generic_write_sync(file, iocb->ki_pos - retval, retval); if (err < 0) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 5c03f0dfb98b..c97b5a8d1e24 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -138,6 +138,25 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, return 0; } +/** + * udf_find_entry - find entry in given directory. + * + * @dir: directory inode to search in + * @child: qstr of the name + * @fibh: buffer head / inode with file identifier descriptor we found + * @cfi: found file identifier descriptor with given name + * + * This function searches in the directory @dir for a file name @child. When + * found, @fibh points to the buffer head(s) (bh is NULL for in ICB + * directories) containing the file identifier descriptor (FID). In that case + * the function returns pointer to the FID in the buffer or inode - but note + * that FID may be split among two buffers (blocks) so accessing it via that + * pointer isn't easily possible. This pointer can be used only as an iterator + * for other directory manipulation functions. For inspection of the FID @cfi + * can be used - the found FID is copied there. + * + * Returns pointer to FID, NULL when nothing found, or error code. + */ static struct fileIdentDesc *udf_find_entry(struct inode *dir, const struct qstr *child, struct udf_fileident_bh *fibh, @@ -167,8 +186,11 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1); if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos, - &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) + &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { + fi = ERR_PTR(-EIO); goto out_err; + } + block = udf_get_lb_pblock(sb, &eloc, offset); if ((++offset << sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -179,19 +201,25 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, offset = 0; fibh->sbh = fibh->ebh = udf_tread(sb, block); - if (!fibh->sbh) + if (!fibh->sbh) { + fi = ERR_PTR(-EIO); goto out_err; + } } fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); - if (!fname) + if (!fname) { + fi = ERR_PTR(-ENOMEM); goto out_err; + } while (f_pos < size) { fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset); - if (!fi) + if (!fi) { + fi = ERR_PTR(-EIO); goto out_err; + } liu = le16_to_cpu(cfi->lengthOfImpUse); lfi = cfi->lengthFileIdent; @@ -234,12 +262,17 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, continue; flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); - if (flen && udf_match(flen, fname, child->len, child->name)) + if (flen < 0) { + fi = ERR_PTR(flen); + goto out_err; + } + + if (udf_match(flen, fname, child->len, child->name)) goto out_ok; } -out_err: fi = NULL; +out_err: if (fibh->sbh != fibh->ebh) brelse(fibh->ebh); brelse(fibh->sbh); @@ -256,6 +289,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; struct fileIdentDesc cfi; struct udf_fileident_bh fibh; + struct fileIdentDesc *fi; if (dentry->d_name.len > UDF_NAME_LEN - 2) return ERR_PTR(-ENAMETOOLONG); @@ -275,7 +309,11 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, } else #endif /* UDF_RECOVERY */ - if (udf_find_entry(dir, &dentry->d_name, &fibh, &cfi)) { + fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); + if (IS_ERR(fi)) + return ERR_CAST(fi); + + if (fi) { struct kernel_lb_addr loc; if (fibh.sbh != fibh.ebh) @@ -774,8 +812,11 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry) retval = -ENOENT; fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); - if (!fi) + if (IS_ERR_OR_NULL(fi)) { + if (fi) + retval = PTR_ERR(fi); goto out; + } retval = -EIO; tloc = lelb_to_cpu(cfi.icb.extLocation); @@ -817,8 +858,12 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry) retval = -ENOENT; fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); - if (!fi) + + if (IS_ERR_OR_NULL(fi)) { + if (fi) + retval = PTR_ERR(fi); goto out; + } retval = -EIO; tloc = lelb_to_cpu(cfi.icb.extLocation); @@ -1049,24 +1094,30 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, struct udf_inode_info *old_iinfo = UDF_I(old_inode); ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi); - if (ofi) { - if (ofibh.sbh != ofibh.ebh) - brelse(ofibh.ebh); - brelse(ofibh.sbh); + if (IS_ERR(ofi)) { + retval = PTR_ERR(ofi); + goto end_rename; } + + if (ofibh.sbh != ofibh.ebh) + brelse(ofibh.ebh); + + brelse(ofibh.sbh); tloc = lelb_to_cpu(ocfi.icb.extLocation); if (!ofi || udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) != old_inode->i_ino) goto end_rename; nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi); - if (nfi) { - if (!new_inode) { - if (nfibh.sbh != nfibh.ebh) - brelse(nfibh.ebh); - brelse(nfibh.sbh); - nfi = NULL; - } + if (IS_ERR(nfi)) { + retval = PTR_ERR(nfi); + goto end_rename; + } + if (nfi && !new_inode) { + if (nfibh.sbh != nfibh.ebh) + brelse(nfibh.ebh); + brelse(nfibh.sbh); + nfi = NULL; } if (S_ISDIR(old_inode->i_mode)) { int offset = udf_ext0_offset(old_inode); @@ -1221,7 +1272,7 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block, static struct dentry *udf_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { - if ((fh_len != 3 && fh_len != 5) || + if (fh_len < 3 || (fh_type != FILEID_UDF_WITH_PARENT && fh_type != FILEID_UDF_WITHOUT_PARENT)) return NULL; @@ -1233,7 +1284,7 @@ static struct dentry *udf_fh_to_dentry(struct super_block *sb, static struct dentry *udf_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { - if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT) + if (fh_len < 5 || fh_type != FILEID_UDF_WITH_PARENT) return NULL; return udf_nfs_get_inode(sb, fid->udf.parent_block, diff --git a/fs/udf/super.c b/fs/udf/super.c index 6299f341967b..b96f190bc567 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -927,17 +927,23 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) #endif } - if (!udf_build_ustr(instr, pvoldesc->volIdent, 32)) - if (udf_CS0toUTF8(outstr, instr)) { - strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name, - outstr->u_len > 31 ? 31 : outstr->u_len); - udf_debug("volIdent[] = '%s'\n", - UDF_SB(sb)->s_volume_ident); - } + if (!udf_build_ustr(instr, pvoldesc->volIdent, 32)) { + ret = udf_CS0toUTF8(outstr, instr); + if (ret < 0) + goto out_bh; + + strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name, + outstr->u_len > 31 ? 31 : outstr->u_len); + udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); + } - if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128)) - if (udf_CS0toUTF8(outstr, instr)) - udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); + if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128)) { + ret = udf_CS0toUTF8(outstr, instr); + if (ret < 0) + goto out_bh; + + udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); + } ret = 0; out_bh: diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 8dfbc4025e2f..862535b3ba58 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -82,6 +82,9 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from, comp_len = udf_get_filename(sb, pc->componentIdent, pc->lengthComponentIdent, p, tolen); + if (comp_len < 0) + return comp_len; + p += comp_len; tolen -= comp_len; if (tolen == 0) diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index b84fee372734..ab478e62baae 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -68,21 +68,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) /* * udf_build_ustr_exact */ -static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) +static void udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) { - if ((!dest) || (!ptr) || (!exactsize)) - return -1; - memset(dest, 0, sizeof(struct ustr)); dest->u_cmpID = ptr[0]; dest->u_len = exactsize - 1; memcpy(dest->u_name, ptr + 1, exactsize - 1); - - return 0; } /* - * udf_ocu_to_utf8 + * udf_CS0toUTF8 * * PURPOSE * Convert OSTA Compressed Unicode to the UTF-8 equivalent. @@ -94,7 +89,7 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) * both of type "struct ustr *" * * POST-CONDITIONS - * <return> Zero on success. + * <return> >= 0 on success. * * HISTORY * November 12, 1997 - Andrew E. Mileski @@ -117,7 +112,7 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) memset(utf_o, 0, sizeof(struct ustr)); pr_err("unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); - return 0; + return -EINVAL; } ocu = ocu_i->u_name; @@ -154,7 +149,7 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) /* * - * udf_utf8_to_ocu + * udf_UTF8toCS0 * * PURPOSE * Convert UTF-8 to the OSTA Compressed Unicode equivalent. @@ -270,7 +265,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, memset(utf_o, 0, sizeof(struct ustr)); pr_err("unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); - return 0; + return -EINVAL; } ocu = ocu_i->u_name; @@ -338,43 +333,51 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, uint8_t *dname, int dlen) { struct ustr *filename, *unifilename; - int len = 0; + int ret; + + if (!slen) + return -EIO; filename = kmalloc(sizeof(struct ustr), GFP_NOFS); if (!filename) - return 0; + return -ENOMEM; unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS); - if (!unifilename) + if (!unifilename) { + ret = -ENOMEM; goto out1; + } - if (udf_build_ustr_exact(unifilename, sname, slen)) - goto out2; - + udf_build_ustr_exact(unifilename, sname, slen); if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { - if (!udf_CS0toUTF8(filename, unifilename)) { + ret = udf_CS0toUTF8(filename, unifilename); + if (ret < 0) { udf_debug("Failed in udf_get_filename: sname = %s\n", sname); goto out2; } } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { - if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename, - unifilename)) { + ret = udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename, + unifilename); + if (ret < 0) { udf_debug("Failed in udf_get_filename: sname = %s\n", sname); goto out2; } } else - goto out2; + BUG(); - len = udf_translate_to_linux(dname, dlen, + ret = udf_translate_to_linux(dname, dlen, filename->u_name, filename->u_len, unifilename->u_name, unifilename->u_len); + /* Zero length filename isn't valid... */ + if (ret == 0) + ret = -EINVAL; out2: kfree(unifilename); out1: kfree(filename); - return len; + return ret; } int udf_put_filename(struct super_block *sb, const uint8_t *sname, |