diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 15:22:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 15:22:37 -0400 |
commit | 77d913178c248d436a15151be5214ef2bf06a465 (patch) | |
tree | 92c16e294858eab0042abc77389e4bd2f4770264 | |
parent | 53d2e6976bd4042672ed7b90dfbf4b31635b7dcf (diff) | |
parent | ab73ef46398e2c0159f3a71de834586422d2a44a (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull UDF and quota updates from Jan Kara:
"This contains a rewrite of UDF handling of filename encoding to fix
remaining overflow issues from Andrew Gabbasov and quota changes to
support new Q_[X]GETNEXTQUOTA quotactl for VFS quota formats"
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
quota: Fix possible GPF due to uninitialised pointers
ext4: Make Q_GETNEXTQUOTA work for quota in hidden inodes
quota: Forbid Q_GETQUOTA and Q_GETNEXTQUOTA for frozen filesystem
quota: Fix possible races during quota loading
ocfs2: Implement get_next_id()
quota_v2: Implement get_next_id() for V2 quota format
quota: Add support for ->get_nextdqblk() for VFS quota
udf: Merge linux specific translation into CS0 conversion function
udf: Remove struct ustr as non-needed intermediate storage
udf: Use separate buffer for copying split names
udf: Adjust UDF_NAME_LEN to better reflect actual restrictions
udf: Join functions for UTF8 and NLS conversions
udf: Parameterize output length in udf_put_filename
quota: Allow Q_GETQUOTA for frozen filesystem
quota: Fixup comments about return value of Q_[X]GETNEXTQUOTA
-rw-r--r-- | fs/ext4/super.c | 4 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_trace.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/quota_global.c | 25 | ||||
-rw-r--r-- | fs/quota/dquot.c | 54 | ||||
-rw-r--r-- | fs/quota/quota.c | 10 | ||||
-rw-r--r-- | fs/quota/quota_tree.c | 67 | ||||
-rw-r--r-- | fs/quota/quota_v2.c | 6 | ||||
-rw-r--r-- | fs/reiserfs/super.c | 1 | ||||
-rw-r--r-- | fs/udf/dir.c | 13 | ||||
-rw-r--r-- | fs/udf/namei.c | 29 | ||||
-rw-r--r-- | fs/udf/super.c | 38 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 21 | ||||
-rw-r--r-- | fs/udf/unicode.c | 630 | ||||
-rw-r--r-- | include/linux/dqblk_qtree.h | 2 | ||||
-rw-r--r-- | include/linux/quota.h | 3 | ||||
-rw-r--r-- | include/linux/quotaops.h | 3 |
16 files changed, 471 insertions, 437 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 99996e9a8f57..539297515896 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -1129,6 +1129,7 @@ static const struct dquot_operations ext4_quota_operations = { | |||
1129 | .alloc_dquot = dquot_alloc, | 1129 | .alloc_dquot = dquot_alloc, |
1130 | .destroy_dquot = dquot_destroy, | 1130 | .destroy_dquot = dquot_destroy, |
1131 | .get_projid = ext4_get_projid, | 1131 | .get_projid = ext4_get_projid, |
1132 | .get_next_id = dquot_get_next_id, | ||
1132 | }; | 1133 | }; |
1133 | 1134 | ||
1134 | static const struct quotactl_ops ext4_qctl_operations = { | 1135 | static const struct quotactl_ops ext4_qctl_operations = { |
@@ -1138,7 +1139,8 @@ static const struct quotactl_ops ext4_qctl_operations = { | |||
1138 | .get_state = dquot_get_state, | 1139 | .get_state = dquot_get_state, |
1139 | .set_info = dquot_set_dqinfo, | 1140 | .set_info = dquot_set_dqinfo, |
1140 | .get_dqblk = dquot_get_dqblk, | 1141 | .get_dqblk = dquot_get_dqblk, |
1141 | .set_dqblk = dquot_set_dqblk | 1142 | .set_dqblk = dquot_set_dqblk, |
1143 | .get_nextdqblk = dquot_get_next_dqblk, | ||
1142 | }; | 1144 | }; |
1143 | #endif | 1145 | #endif |
1144 | 1146 | ||
diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h index 6cb019b7c6a8..a52a2dbc064e 100644 --- a/fs/ocfs2/ocfs2_trace.h +++ b/fs/ocfs2/ocfs2_trace.h | |||
@@ -2035,6 +2035,8 @@ DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_release_dquot); | |||
2035 | 2035 | ||
2036 | DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_acquire_dquot); | 2036 | DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_acquire_dquot); |
2037 | 2037 | ||
2038 | DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_get_next_id); | ||
2039 | |||
2038 | DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_mark_dquot_dirty); | 2040 | DEFINE_OCFS2_UINT_INT_EVENT(ocfs2_mark_dquot_dirty); |
2039 | 2041 | ||
2040 | /* End of trace events for fs/ocfs2/quota_global.c. */ | 2042 | /* End of trace events for fs/ocfs2/quota_global.c. */ |
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index 9c9dd30bc945..91bc674203ed 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
@@ -860,6 +860,30 @@ out: | |||
860 | return status; | 860 | return status; |
861 | } | 861 | } |
862 | 862 | ||
863 | static int ocfs2_get_next_id(struct super_block *sb, struct kqid *qid) | ||
864 | { | ||
865 | int type = qid->type; | ||
866 | struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv; | ||
867 | int status = 0; | ||
868 | |||
869 | trace_ocfs2_get_next_id(from_kqid(&init_user_ns, *qid), type); | ||
870 | status = ocfs2_lock_global_qf(info, 0); | ||
871 | if (status < 0) | ||
872 | goto out; | ||
873 | status = ocfs2_qinfo_lock(info, 0); | ||
874 | if (status < 0) | ||
875 | goto out_global; | ||
876 | status = qtree_get_next_id(&info->dqi_gi, qid); | ||
877 | ocfs2_qinfo_unlock(info, 0); | ||
878 | out_global: | ||
879 | ocfs2_unlock_global_qf(info, 0); | ||
880 | out: | ||
881 | /* Avoid logging ENOENT since it just means there isn't next ID */ | ||
882 | if (status && status != -ENOENT) | ||
883 | mlog_errno(status); | ||
884 | return status; | ||
885 | } | ||
886 | |||
863 | static int ocfs2_mark_dquot_dirty(struct dquot *dquot) | 887 | static int ocfs2_mark_dquot_dirty(struct dquot *dquot) |
864 | { | 888 | { |
865 | unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) | | 889 | unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) | |
@@ -968,4 +992,5 @@ const struct dquot_operations ocfs2_quota_operations = { | |||
968 | .write_info = ocfs2_write_info, | 992 | .write_info = ocfs2_write_info, |
969 | .alloc_dquot = ocfs2_alloc_dquot, | 993 | .alloc_dquot = ocfs2_alloc_dquot, |
970 | .destroy_dquot = ocfs2_destroy_dquot, | 994 | .destroy_dquot = ocfs2_destroy_dquot, |
995 | .get_next_id = ocfs2_get_next_id, | ||
971 | }; | 996 | }; |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 04ca0cc6d065..ba827daea5a0 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -411,6 +411,8 @@ int dquot_acquire(struct dquot *dquot) | |||
411 | ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot); | 411 | ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot); |
412 | if (ret < 0) | 412 | if (ret < 0) |
413 | goto out_iolock; | 413 | goto out_iolock; |
414 | /* Make sure flags update is visible after dquot has been filled */ | ||
415 | smp_mb__before_atomic(); | ||
414 | set_bit(DQ_READ_B, &dquot->dq_flags); | 416 | set_bit(DQ_READ_B, &dquot->dq_flags); |
415 | /* Instantiate dquot if needed */ | 417 | /* Instantiate dquot if needed */ |
416 | if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { | 418 | if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { |
@@ -427,6 +429,11 @@ int dquot_acquire(struct dquot *dquot) | |||
427 | goto out_iolock; | 429 | goto out_iolock; |
428 | } | 430 | } |
429 | } | 431 | } |
432 | /* | ||
433 | * Make sure flags update is visible after on-disk struct has been | ||
434 | * allocated. Paired with smp_rmb() in dqget(). | ||
435 | */ | ||
436 | smp_mb__before_atomic(); | ||
430 | set_bit(DQ_ACTIVE_B, &dquot->dq_flags); | 437 | set_bit(DQ_ACTIVE_B, &dquot->dq_flags); |
431 | out_iolock: | 438 | out_iolock: |
432 | mutex_unlock(&dqopt->dqio_mutex); | 439 | mutex_unlock(&dqopt->dqio_mutex); |
@@ -887,6 +894,11 @@ we_slept: | |||
887 | goto out; | 894 | goto out; |
888 | } | 895 | } |
889 | } | 896 | } |
897 | /* | ||
898 | * Make sure following reads see filled structure - paired with | ||
899 | * smp_mb__before_atomic() in dquot_acquire(). | ||
900 | */ | ||
901 | smp_rmb(); | ||
890 | #ifdef CONFIG_QUOTA_DEBUG | 902 | #ifdef CONFIG_QUOTA_DEBUG |
891 | BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ | 903 | BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ |
892 | #endif | 904 | #endif |
@@ -1398,7 +1410,7 @@ static int dquot_active(const struct inode *inode) | |||
1398 | static int __dquot_initialize(struct inode *inode, int type) | 1410 | static int __dquot_initialize(struct inode *inode, int type) |
1399 | { | 1411 | { |
1400 | int cnt, init_needed = 0; | 1412 | int cnt, init_needed = 0; |
1401 | struct dquot **dquots, *got[MAXQUOTAS]; | 1413 | struct dquot **dquots, *got[MAXQUOTAS] = {}; |
1402 | struct super_block *sb = inode->i_sb; | 1414 | struct super_block *sb = inode->i_sb; |
1403 | qsize_t rsv; | 1415 | qsize_t rsv; |
1404 | int ret = 0; | 1416 | int ret = 0; |
@@ -1415,7 +1427,6 @@ static int __dquot_initialize(struct inode *inode, int type) | |||
1415 | int rc; | 1427 | int rc; |
1416 | struct dquot *dquot; | 1428 | struct dquot *dquot; |
1417 | 1429 | ||
1418 | got[cnt] = NULL; | ||
1419 | if (type != -1 && cnt != type) | 1430 | if (type != -1 && cnt != type) |
1420 | continue; | 1431 | continue; |
1421 | /* | 1432 | /* |
@@ -2031,6 +2042,21 @@ int dquot_commit_info(struct super_block *sb, int type) | |||
2031 | } | 2042 | } |
2032 | EXPORT_SYMBOL(dquot_commit_info); | 2043 | EXPORT_SYMBOL(dquot_commit_info); |
2033 | 2044 | ||
2045 | int dquot_get_next_id(struct super_block *sb, struct kqid *qid) | ||
2046 | { | ||
2047 | struct quota_info *dqopt = sb_dqopt(sb); | ||
2048 | int err; | ||
2049 | |||
2050 | if (!dqopt->ops[qid->type]->get_next_id) | ||
2051 | return -ENOSYS; | ||
2052 | mutex_lock(&dqopt->dqio_mutex); | ||
2053 | err = dqopt->ops[qid->type]->get_next_id(sb, qid); | ||
2054 | mutex_unlock(&dqopt->dqio_mutex); | ||
2055 | |||
2056 | return err; | ||
2057 | } | ||
2058 | EXPORT_SYMBOL(dquot_get_next_id); | ||
2059 | |||
2034 | /* | 2060 | /* |
2035 | * Definitions of diskquota operations. | 2061 | * Definitions of diskquota operations. |
2036 | */ | 2062 | */ |
@@ -2042,6 +2068,7 @@ const struct dquot_operations dquot_operations = { | |||
2042 | .write_info = dquot_commit_info, | 2068 | .write_info = dquot_commit_info, |
2043 | .alloc_dquot = dquot_alloc, | 2069 | .alloc_dquot = dquot_alloc, |
2044 | .destroy_dquot = dquot_destroy, | 2070 | .destroy_dquot = dquot_destroy, |
2071 | .get_next_id = dquot_get_next_id, | ||
2045 | }; | 2072 | }; |
2046 | EXPORT_SYMBOL(dquot_operations); | 2073 | EXPORT_SYMBOL(dquot_operations); |
2047 | 2074 | ||
@@ -2563,6 +2590,27 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid, | |||
2563 | } | 2590 | } |
2564 | EXPORT_SYMBOL(dquot_get_dqblk); | 2591 | EXPORT_SYMBOL(dquot_get_dqblk); |
2565 | 2592 | ||
2593 | int dquot_get_next_dqblk(struct super_block *sb, struct kqid *qid, | ||
2594 | struct qc_dqblk *di) | ||
2595 | { | ||
2596 | struct dquot *dquot; | ||
2597 | int err; | ||
2598 | |||
2599 | if (!sb->dq_op->get_next_id) | ||
2600 | return -ENOSYS; | ||
2601 | err = sb->dq_op->get_next_id(sb, qid); | ||
2602 | if (err < 0) | ||
2603 | return err; | ||
2604 | dquot = dqget(sb, *qid); | ||
2605 | if (IS_ERR(dquot)) | ||
2606 | return PTR_ERR(dquot); | ||
2607 | do_get_dqblk(dquot, di); | ||
2608 | dqput(dquot); | ||
2609 | |||
2610 | return 0; | ||
2611 | } | ||
2612 | EXPORT_SYMBOL(dquot_get_next_dqblk); | ||
2613 | |||
2566 | #define VFS_QC_MASK \ | 2614 | #define VFS_QC_MASK \ |
2567 | (QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \ | 2615 | (QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \ |
2568 | QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \ | 2616 | QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \ |
@@ -2763,6 +2811,7 @@ const struct quotactl_ops dquot_quotactl_ops = { | |||
2763 | .get_state = dquot_get_state, | 2811 | .get_state = dquot_get_state, |
2764 | .set_info = dquot_set_dqinfo, | 2812 | .set_info = dquot_set_dqinfo, |
2765 | .get_dqblk = dquot_get_dqblk, | 2813 | .get_dqblk = dquot_get_dqblk, |
2814 | .get_nextdqblk = dquot_get_next_dqblk, | ||
2766 | .set_dqblk = dquot_set_dqblk | 2815 | .set_dqblk = dquot_set_dqblk |
2767 | }; | 2816 | }; |
2768 | EXPORT_SYMBOL(dquot_quotactl_ops); | 2817 | EXPORT_SYMBOL(dquot_quotactl_ops); |
@@ -2774,6 +2823,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = { | |||
2774 | .get_state = dquot_get_state, | 2823 | .get_state = dquot_get_state, |
2775 | .set_info = dquot_set_dqinfo, | 2824 | .set_info = dquot_set_dqinfo, |
2776 | .get_dqblk = dquot_get_dqblk, | 2825 | .get_dqblk = dquot_get_dqblk, |
2826 | .get_nextdqblk = dquot_get_next_dqblk, | ||
2777 | .set_dqblk = dquot_set_dqblk | 2827 | .set_dqblk = dquot_set_dqblk |
2778 | }; | 2828 | }; |
2779 | EXPORT_SYMBOL(dquot_quotactl_sysfile_ops); | 2829 | EXPORT_SYMBOL(dquot_quotactl_sysfile_ops); |
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 0ebc90496525..0f10ee9892ce 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
@@ -224,7 +224,7 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id, | |||
224 | 224 | ||
225 | /* | 225 | /* |
226 | * Return quota for next active quota >= this id, if any exists, | 226 | * Return quota for next active quota >= this id, if any exists, |
227 | * otherwise return -ESRCH via ->get_nextdqblk | 227 | * otherwise return -ENOENT via ->get_nextdqblk |
228 | */ | 228 | */ |
229 | static int quota_getnextquota(struct super_block *sb, int type, qid_t id, | 229 | static int quota_getnextquota(struct super_block *sb, int type, qid_t id, |
230 | void __user *addr) | 230 | void __user *addr) |
@@ -655,7 +655,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id, | |||
655 | 655 | ||
656 | /* | 656 | /* |
657 | * Return quota for next active quota >= this id, if any exists, | 657 | * Return quota for next active quota >= this id, if any exists, |
658 | * otherwise return -ESRCH via ->get_nextdqblk. | 658 | * otherwise return -ENOENT via ->get_nextdqblk. |
659 | */ | 659 | */ |
660 | static int quota_getnextxquota(struct super_block *sb, int type, qid_t id, | 660 | static int quota_getnextxquota(struct super_block *sb, int type, qid_t id, |
661 | void __user *addr) | 661 | void __user *addr) |
@@ -765,10 +765,14 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | |||
765 | /* Return 1 if 'cmd' will block on frozen filesystem */ | 765 | /* Return 1 if 'cmd' will block on frozen filesystem */ |
766 | static int quotactl_cmd_write(int cmd) | 766 | static int quotactl_cmd_write(int cmd) |
767 | { | 767 | { |
768 | /* | ||
769 | * We cannot allow Q_GETQUOTA and Q_GETNEXTQUOTA without write access | ||
770 | * as dquot_acquire() may allocate space for new structure and OCFS2 | ||
771 | * needs to increment on-disk use count. | ||
772 | */ | ||
768 | switch (cmd) { | 773 | switch (cmd) { |
769 | case Q_GETFMT: | 774 | case Q_GETFMT: |
770 | case Q_GETINFO: | 775 | case Q_GETINFO: |
771 | case Q_GETNEXTQUOTA: | ||
772 | case Q_SYNC: | 776 | case Q_SYNC: |
773 | case Q_XGETQSTAT: | 777 | case Q_XGETQSTAT: |
774 | case Q_XGETQSTATV: | 778 | case Q_XGETQSTATV: |
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c index 58efb83dec1c..0738972e8d3f 100644 --- a/fs/quota/quota_tree.c +++ b/fs/quota/quota_tree.c | |||
@@ -22,10 +22,9 @@ MODULE_LICENSE("GPL"); | |||
22 | 22 | ||
23 | #define __QUOTA_QT_PARANOIA | 23 | #define __QUOTA_QT_PARANOIA |
24 | 24 | ||
25 | static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) | 25 | static int __get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) |
26 | { | 26 | { |
27 | unsigned int epb = info->dqi_usable_bs >> 2; | 27 | unsigned int epb = info->dqi_usable_bs >> 2; |
28 | qid_t id = from_kqid(&init_user_ns, qid); | ||
29 | 28 | ||
30 | depth = info->dqi_qtree_depth - depth - 1; | 29 | depth = info->dqi_qtree_depth - depth - 1; |
31 | while (depth--) | 30 | while (depth--) |
@@ -33,6 +32,13 @@ static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) | |||
33 | return id % epb; | 32 | return id % epb; |
34 | } | 33 | } |
35 | 34 | ||
35 | static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth) | ||
36 | { | ||
37 | qid_t id = from_kqid(&init_user_ns, qid); | ||
38 | |||
39 | return __get_index(info, id, depth); | ||
40 | } | ||
41 | |||
36 | /* Number of entries in one blocks */ | 42 | /* Number of entries in one blocks */ |
37 | static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) | 43 | static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) |
38 | { | 44 | { |
@@ -668,3 +674,60 @@ int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) | |||
668 | return 0; | 674 | return 0; |
669 | } | 675 | } |
670 | EXPORT_SYMBOL(qtree_release_dquot); | 676 | EXPORT_SYMBOL(qtree_release_dquot); |
677 | |||
678 | static int find_next_id(struct qtree_mem_dqinfo *info, qid_t *id, | ||
679 | unsigned int blk, int depth) | ||
680 | { | ||
681 | char *buf = getdqbuf(info->dqi_usable_bs); | ||
682 | __le32 *ref = (__le32 *)buf; | ||
683 | ssize_t ret; | ||
684 | unsigned int epb = info->dqi_usable_bs >> 2; | ||
685 | unsigned int level_inc = 1; | ||
686 | int i; | ||
687 | |||
688 | if (!buf) | ||
689 | return -ENOMEM; | ||
690 | |||
691 | for (i = depth; i < info->dqi_qtree_depth - 1; i++) | ||
692 | level_inc *= epb; | ||
693 | |||
694 | ret = read_blk(info, blk, buf); | ||
695 | if (ret < 0) { | ||
696 | quota_error(info->dqi_sb, | ||
697 | "Can't read quota tree block %u", blk); | ||
698 | goto out_buf; | ||
699 | } | ||
700 | for (i = __get_index(info, *id, depth); i < epb; i++) { | ||
701 | if (ref[i] == cpu_to_le32(0)) { | ||
702 | *id += level_inc; | ||
703 | continue; | ||
704 | } | ||
705 | if (depth == info->dqi_qtree_depth - 1) { | ||
706 | ret = 0; | ||
707 | goto out_buf; | ||
708 | } | ||
709 | ret = find_next_id(info, id, le32_to_cpu(ref[i]), depth + 1); | ||
710 | if (ret != -ENOENT) | ||
711 | break; | ||
712 | } | ||
713 | if (i == epb) { | ||
714 | ret = -ENOENT; | ||
715 | goto out_buf; | ||
716 | } | ||
717 | out_buf: | ||
718 | kfree(buf); | ||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid) | ||
723 | { | ||
724 | qid_t id = from_kqid(&init_user_ns, *qid); | ||
725 | int ret; | ||
726 | |||
727 | ret = find_next_id(info, &id, QT_TREEOFF, 0); | ||
728 | if (ret < 0) | ||
729 | return ret; | ||
730 | *qid = make_kqid(&init_user_ns, qid->type, id); | ||
731 | return 0; | ||
732 | } | ||
733 | EXPORT_SYMBOL(qtree_get_next_id); | ||
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index ed85d4f35c04..ca71bf881ad1 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c | |||
@@ -304,6 +304,11 @@ static int v2_free_file_info(struct super_block *sb, int type) | |||
304 | return 0; | 304 | return 0; |
305 | } | 305 | } |
306 | 306 | ||
307 | static int v2_get_next_id(struct super_block *sb, struct kqid *qid) | ||
308 | { | ||
309 | return qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid); | ||
310 | } | ||
311 | |||
307 | static const struct quota_format_ops v2_format_ops = { | 312 | static const struct quota_format_ops v2_format_ops = { |
308 | .check_quota_file = v2_check_quota_file, | 313 | .check_quota_file = v2_check_quota_file, |
309 | .read_file_info = v2_read_file_info, | 314 | .read_file_info = v2_read_file_info, |
@@ -312,6 +317,7 @@ static const struct quota_format_ops v2_format_ops = { | |||
312 | .read_dqblk = v2_read_dquot, | 317 | .read_dqblk = v2_read_dquot, |
313 | .commit_dqblk = v2_write_dquot, | 318 | .commit_dqblk = v2_write_dquot, |
314 | .release_dqblk = v2_release_dquot, | 319 | .release_dqblk = v2_release_dquot, |
320 | .get_next_id = v2_get_next_id, | ||
315 | }; | 321 | }; |
316 | 322 | ||
317 | static struct quota_format_type v2r0_quota_format = { | 323 | static struct quota_format_type v2r0_quota_format = { |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index c0306ec8ed7b..b8f2d1e8c645 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -802,6 +802,7 @@ static const struct dquot_operations reiserfs_quota_operations = { | |||
802 | .write_info = reiserfs_write_info, | 802 | .write_info = reiserfs_write_info, |
803 | .alloc_dquot = dquot_alloc, | 803 | .alloc_dquot = dquot_alloc, |
804 | .destroy_dquot = dquot_destroy, | 804 | .destroy_dquot = dquot_destroy, |
805 | .get_next_id = dquot_get_next_id, | ||
805 | }; | 806 | }; |
806 | 807 | ||
807 | static const struct quotactl_ops reiserfs_qctl_operations = { | 808 | static const struct quotactl_ops reiserfs_qctl_operations = { |
diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 541d9c65014d..b51b371b874a 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c | |||
@@ -45,7 +45,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx) | |||
45 | int block, iblock; | 45 | int block, iblock; |
46 | loff_t nf_pos; | 46 | loff_t nf_pos; |
47 | int flen; | 47 | int flen; |
48 | unsigned char *fname = NULL; | 48 | unsigned char *fname = NULL, *copy_name = NULL; |
49 | unsigned char *nameptr; | 49 | unsigned char *nameptr; |
50 | uint16_t liu; | 50 | uint16_t liu; |
51 | uint8_t lfi; | 51 | uint8_t lfi; |
@@ -143,7 +143,15 @@ static int udf_readdir(struct file *file, struct dir_context *ctx) | |||
143 | if (poffset >= lfi) { | 143 | if (poffset >= lfi) { |
144 | nameptr = (char *)(fibh.ebh->b_data + poffset - lfi); | 144 | nameptr = (char *)(fibh.ebh->b_data + poffset - lfi); |
145 | } else { | 145 | } else { |
146 | nameptr = fname; | 146 | if (!copy_name) { |
147 | copy_name = kmalloc(UDF_NAME_LEN, | ||
148 | GFP_NOFS); | ||
149 | if (!copy_name) { | ||
150 | ret = -ENOMEM; | ||
151 | goto out; | ||
152 | } | ||
153 | } | ||
154 | nameptr = copy_name; | ||
147 | memcpy(nameptr, fi->fileIdent + liu, | 155 | memcpy(nameptr, fi->fileIdent + liu, |
148 | lfi - poffset); | 156 | lfi - poffset); |
149 | memcpy(nameptr + lfi - poffset, | 157 | memcpy(nameptr + lfi - poffset, |
@@ -185,6 +193,7 @@ out: | |||
185 | brelse(fibh.sbh); | 193 | brelse(fibh.sbh); |
186 | brelse(epos.bh); | 194 | brelse(epos.bh); |
187 | kfree(fname); | 195 | kfree(fname); |
196 | kfree(copy_name); | ||
188 | 197 | ||
189 | return ret; | 198 | return ret; |
190 | } | 199 | } |
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 42eafb91f7ff..a2ba11eca995 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
@@ -165,7 +165,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
165 | struct fileIdentDesc *fi = NULL; | 165 | struct fileIdentDesc *fi = NULL; |
166 | loff_t f_pos; | 166 | loff_t f_pos; |
167 | int block, flen; | 167 | int block, flen; |
168 | unsigned char *fname = NULL; | 168 | unsigned char *fname = NULL, *copy_name = NULL; |
169 | unsigned char *nameptr; | 169 | unsigned char *nameptr; |
170 | uint8_t lfi; | 170 | uint8_t lfi; |
171 | uint16_t liu; | 171 | uint16_t liu; |
@@ -236,7 +236,15 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
236 | nameptr = (uint8_t *)(fibh->ebh->b_data + | 236 | nameptr = (uint8_t *)(fibh->ebh->b_data + |
237 | poffset - lfi); | 237 | poffset - lfi); |
238 | else { | 238 | else { |
239 | nameptr = fname; | 239 | if (!copy_name) { |
240 | copy_name = kmalloc(UDF_NAME_LEN, | ||
241 | GFP_NOFS); | ||
242 | if (!copy_name) { | ||
243 | fi = ERR_PTR(-ENOMEM); | ||
244 | goto out_err; | ||
245 | } | ||
246 | } | ||
247 | nameptr = copy_name; | ||
240 | memcpy(nameptr, fi->fileIdent + liu, | 248 | memcpy(nameptr, fi->fileIdent + liu, |
241 | lfi - poffset); | 249 | lfi - poffset); |
242 | memcpy(nameptr + lfi - poffset, | 250 | memcpy(nameptr + lfi - poffset, |
@@ -279,6 +287,7 @@ out_err: | |||
279 | out_ok: | 287 | out_ok: |
280 | brelse(epos.bh); | 288 | brelse(epos.bh); |
281 | kfree(fname); | 289 | kfree(fname); |
290 | kfree(copy_name); | ||
282 | 291 | ||
283 | return fi; | 292 | return fi; |
284 | } | 293 | } |
@@ -291,7 +300,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, | |||
291 | struct udf_fileident_bh fibh; | 300 | struct udf_fileident_bh fibh; |
292 | struct fileIdentDesc *fi; | 301 | struct fileIdentDesc *fi; |
293 | 302 | ||
294 | if (dentry->d_name.len > UDF_NAME_LEN - 2) | 303 | if (dentry->d_name.len > UDF_NAME_LEN) |
295 | return ERR_PTR(-ENAMETOOLONG); | 304 | return ERR_PTR(-ENAMETOOLONG); |
296 | 305 | ||
297 | #ifdef UDF_RECOVERY | 306 | #ifdef UDF_RECOVERY |
@@ -351,7 +360,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
351 | struct udf_inode_info *dinfo; | 360 | struct udf_inode_info *dinfo; |
352 | 361 | ||
353 | fibh->sbh = fibh->ebh = NULL; | 362 | fibh->sbh = fibh->ebh = NULL; |
354 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | 363 | name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS); |
355 | if (!name) { | 364 | if (!name) { |
356 | *err = -ENOMEM; | 365 | *err = -ENOMEM; |
357 | goto out_err; | 366 | goto out_err; |
@@ -362,8 +371,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
362 | *err = -EINVAL; | 371 | *err = -EINVAL; |
363 | goto out_err; | 372 | goto out_err; |
364 | } | 373 | } |
365 | namelen = udf_put_filename(sb, dentry->d_name.name, name, | 374 | namelen = udf_put_filename(sb, dentry->d_name.name, |
366 | dentry->d_name.len); | 375 | dentry->d_name.len, |
376 | name, UDF_NAME_LEN_CS0); | ||
367 | if (!namelen) { | 377 | if (!namelen) { |
368 | *err = -ENAMETOOLONG; | 378 | *err = -ENAMETOOLONG; |
369 | goto out_err; | 379 | goto out_err; |
@@ -914,7 +924,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
914 | 924 | ||
915 | iinfo = UDF_I(inode); | 925 | iinfo = UDF_I(inode); |
916 | down_write(&iinfo->i_data_sem); | 926 | down_write(&iinfo->i_data_sem); |
917 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | 927 | name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS); |
918 | if (!name) { | 928 | if (!name) { |
919 | err = -ENOMEM; | 929 | err = -ENOMEM; |
920 | goto out_no_entry; | 930 | goto out_no_entry; |
@@ -997,8 +1007,9 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
997 | } | 1007 | } |
998 | 1008 | ||
999 | if (pc->componentType == 5) { | 1009 | if (pc->componentType == 5) { |
1000 | namelen = udf_put_filename(sb, compstart, name, | 1010 | namelen = udf_put_filename(sb, compstart, |
1001 | symname - compstart); | 1011 | symname - compstart, |
1012 | name, UDF_NAME_LEN_CS0); | ||
1002 | if (!namelen) | 1013 | if (!namelen) |
1003 | goto out_no_entry; | 1014 | goto out_no_entry; |
1004 | 1015 | ||
diff --git a/fs/udf/super.c b/fs/udf/super.c index a522c15a0bfd..fa92fe839fda 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -887,18 +887,14 @@ static int udf_find_fileset(struct super_block *sb, | |||
887 | static int udf_load_pvoldesc(struct super_block *sb, sector_t block) | 887 | static int udf_load_pvoldesc(struct super_block *sb, sector_t block) |
888 | { | 888 | { |
889 | struct primaryVolDesc *pvoldesc; | 889 | struct primaryVolDesc *pvoldesc; |
890 | struct ustr *instr, *outstr; | 890 | uint8_t *outstr; |
891 | struct buffer_head *bh; | 891 | struct buffer_head *bh; |
892 | uint16_t ident; | 892 | uint16_t ident; |
893 | int ret = -ENOMEM; | 893 | int ret = -ENOMEM; |
894 | 894 | ||
895 | instr = kmalloc(sizeof(struct ustr), GFP_NOFS); | 895 | outstr = kmalloc(128, GFP_NOFS); |
896 | if (!instr) | ||
897 | return -ENOMEM; | ||
898 | |||
899 | outstr = kmalloc(sizeof(struct ustr), GFP_NOFS); | ||
900 | if (!outstr) | 896 | if (!outstr) |
901 | goto out1; | 897 | return -ENOMEM; |
902 | 898 | ||
903 | bh = udf_read_tagged(sb, block, block, &ident); | 899 | bh = udf_read_tagged(sb, block, block, &ident); |
904 | if (!bh) { | 900 | if (!bh) { |
@@ -923,31 +919,25 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) | |||
923 | #endif | 919 | #endif |
924 | } | 920 | } |
925 | 921 | ||
926 | if (!udf_build_ustr(instr, pvoldesc->volIdent, 32)) { | 922 | ret = udf_CS0toUTF8(outstr, 31, pvoldesc->volIdent, 32); |
927 | ret = udf_CS0toUTF8(outstr, instr); | 923 | if (ret < 0) |
928 | if (ret < 0) | 924 | goto out_bh; |
929 | goto out_bh; | ||
930 | 925 | ||
931 | strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name, | 926 | strncpy(UDF_SB(sb)->s_volume_ident, outstr, ret); |
932 | outstr->u_len > 31 ? 31 : outstr->u_len); | 927 | udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); |
933 | udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); | ||
934 | } | ||
935 | 928 | ||
936 | if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128)) { | 929 | ret = udf_CS0toUTF8(outstr, 127, pvoldesc->volSetIdent, 128); |
937 | ret = udf_CS0toUTF8(outstr, instr); | 930 | if (ret < 0) |
938 | if (ret < 0) | 931 | goto out_bh; |
939 | goto out_bh; | ||
940 | 932 | ||
941 | udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); | 933 | outstr[ret] = 0; |
942 | } | 934 | udf_debug("volSetIdent[] = '%s'\n", outstr); |
943 | 935 | ||
944 | ret = 0; | 936 | ret = 0; |
945 | out_bh: | 937 | out_bh: |
946 | brelse(bh); | 938 | brelse(bh); |
947 | out2: | 939 | out2: |
948 | kfree(outstr); | 940 | kfree(outstr); |
949 | out1: | ||
950 | kfree(instr); | ||
951 | return ret; | 941 | return ret; |
952 | } | 942 | } |
953 | 943 | ||
@@ -2358,7 +2348,7 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
2358 | le32_to_cpu(lvidiu->numDirs)) : 0) | 2348 | le32_to_cpu(lvidiu->numDirs)) : 0) |
2359 | + buf->f_bfree; | 2349 | + buf->f_bfree; |
2360 | buf->f_ffree = buf->f_bfree; | 2350 | buf->f_ffree = buf->f_bfree; |
2361 | buf->f_namelen = UDF_NAME_LEN - 2; | 2351 | buf->f_namelen = UDF_NAME_LEN; |
2362 | buf->f_fsid.val[0] = (u32)id; | 2352 | buf->f_fsid.val[0] = (u32)id; |
2363 | buf->f_fsid.val[1] = (u32)(id >> 32); | 2353 | buf->f_fsid.val[1] = (u32)(id >> 32); |
2364 | 2354 | ||
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index fa0044b6b81d..972b70625614 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -49,8 +49,8 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb, | |||
49 | #define UDF_EXTENT_FLAG_MASK 0xC0000000 | 49 | #define UDF_EXTENT_FLAG_MASK 0xC0000000 |
50 | 50 | ||
51 | #define UDF_NAME_PAD 4 | 51 | #define UDF_NAME_PAD 4 |
52 | #define UDF_NAME_LEN 256 | 52 | #define UDF_NAME_LEN 254 |
53 | #define UDF_PATH_LEN 1023 | 53 | #define UDF_NAME_LEN_CS0 255 |
54 | 54 | ||
55 | static inline size_t udf_file_entry_alloc_offset(struct inode *inode) | 55 | static inline size_t udf_file_entry_alloc_offset(struct inode *inode) |
56 | { | 56 | { |
@@ -106,12 +106,6 @@ struct generic_desc { | |||
106 | __le32 volDescSeqNum; | 106 | __le32 volDescSeqNum; |
107 | }; | 107 | }; |
108 | 108 | ||
109 | struct ustr { | ||
110 | uint8_t u_cmpID; | ||
111 | uint8_t u_name[UDF_NAME_LEN - 2]; | ||
112 | uint8_t u_len; | ||
113 | }; | ||
114 | |||
115 | 109 | ||
116 | /* super.c */ | 110 | /* super.c */ |
117 | 111 | ||
@@ -214,12 +208,11 @@ udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc, | |||
214 | } | 208 | } |
215 | 209 | ||
216 | /* unicode.c */ | 210 | /* unicode.c */ |
217 | extern int udf_get_filename(struct super_block *, uint8_t *, int, uint8_t *, | 211 | extern int udf_get_filename(struct super_block *, const uint8_t *, int, |
218 | int); | 212 | uint8_t *, int); |
219 | extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, | 213 | extern int udf_put_filename(struct super_block *, const uint8_t *, int, |
220 | int); | 214 | uint8_t *, int); |
221 | extern int udf_build_ustr(struct ustr *, dstring *, int); | 215 | extern int udf_CS0toUTF8(uint8_t *, int, const uint8_t *, int); |
222 | extern int udf_CS0toUTF8(struct ustr *, const struct ustr *); | ||
223 | 216 | ||
224 | /* ialloc.c */ | 217 | /* ialloc.c */ |
225 | extern void udf_free_inode(struct inode *); | 218 | extern void udf_free_inode(struct inode *); |
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index e788a05aab83..3ff42f4437f3 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c | |||
@@ -28,199 +28,72 @@ | |||
28 | 28 | ||
29 | #include "udf_sb.h" | 29 | #include "udf_sb.h" |
30 | 30 | ||
31 | static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *, | 31 | static int udf_uni2char_utf8(wchar_t uni, |
32 | int); | 32 | unsigned char *out, |
33 | 33 | int boundlen) | |
34 | static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) | ||
35 | { | ||
36 | if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2)) | ||
37 | return 0; | ||
38 | |||
39 | memset(dest, 0, sizeof(struct ustr)); | ||
40 | memcpy(dest->u_name, src, strlen); | ||
41 | dest->u_cmpID = 0x08; | ||
42 | dest->u_len = strlen; | ||
43 | |||
44 | return strlen; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * udf_build_ustr | ||
49 | */ | ||
50 | int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) | ||
51 | { | ||
52 | int usesize; | ||
53 | |||
54 | if (!dest || !ptr || !size) | ||
55 | return -1; | ||
56 | BUG_ON(size < 2); | ||
57 | |||
58 | usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name)); | ||
59 | usesize = min(usesize, size - 2); | ||
60 | dest->u_cmpID = ptr[0]; | ||
61 | dest->u_len = usesize; | ||
62 | memcpy(dest->u_name, ptr + 1, usesize); | ||
63 | memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * udf_build_ustr_exact | ||
70 | */ | ||
71 | static void udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) | ||
72 | { | ||
73 | memset(dest, 0, sizeof(struct ustr)); | ||
74 | dest->u_cmpID = ptr[0]; | ||
75 | dest->u_len = exactsize - 1; | ||
76 | memcpy(dest->u_name, ptr + 1, exactsize - 1); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * udf_CS0toUTF8 | ||
81 | * | ||
82 | * PURPOSE | ||
83 | * Convert OSTA Compressed Unicode to the UTF-8 equivalent. | ||
84 | * | ||
85 | * PRE-CONDITIONS | ||
86 | * utf Pointer to UTF-8 output buffer. | ||
87 | * ocu Pointer to OSTA Compressed Unicode input buffer | ||
88 | * of size UDF_NAME_LEN bytes. | ||
89 | * both of type "struct ustr *" | ||
90 | * | ||
91 | * POST-CONDITIONS | ||
92 | * <return> >= 0 on success. | ||
93 | * | ||
94 | * HISTORY | ||
95 | * November 12, 1997 - Andrew E. Mileski | ||
96 | * Written, tested, and released. | ||
97 | */ | ||
98 | int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) | ||
99 | { | 34 | { |
100 | const uint8_t *ocu; | 35 | int u_len = 0; |
101 | uint8_t cmp_id, ocu_len; | 36 | |
102 | int i; | 37 | if (boundlen <= 0) |
103 | 38 | return -ENAMETOOLONG; | |
104 | ocu_len = ocu_i->u_len; | 39 | |
105 | if (ocu_len == 0) { | 40 | if (uni < 0x80) { |
106 | memset(utf_o, 0, sizeof(struct ustr)); | 41 | out[u_len++] = (unsigned char)uni; |
107 | return 0; | 42 | } else if (uni < 0x800) { |
108 | } | 43 | if (boundlen < 2) |
109 | 44 | return -ENAMETOOLONG; | |
110 | cmp_id = ocu_i->u_cmpID; | 45 | out[u_len++] = (unsigned char)(0xc0 | (uni >> 6)); |
111 | if (cmp_id != 8 && cmp_id != 16) { | 46 | out[u_len++] = (unsigned char)(0x80 | (uni & 0x3f)); |
112 | memset(utf_o, 0, sizeof(struct ustr)); | 47 | } else { |
113 | pr_err("unknown compression code (%d) stri=%s\n", | 48 | if (boundlen < 3) |
114 | cmp_id, ocu_i->u_name); | 49 | return -ENAMETOOLONG; |
115 | return -EINVAL; | 50 | out[u_len++] = (unsigned char)(0xe0 | (uni >> 12)); |
116 | } | 51 | out[u_len++] = (unsigned char)(0x80 | ((uni >> 6) & 0x3f)); |
117 | 52 | out[u_len++] = (unsigned char)(0x80 | (uni & 0x3f)); | |
118 | ocu = ocu_i->u_name; | ||
119 | utf_o->u_len = 0; | ||
120 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { | ||
121 | |||
122 | /* Expand OSTA compressed Unicode to Unicode */ | ||
123 | uint32_t c = ocu[i++]; | ||
124 | if (cmp_id == 16) | ||
125 | c = (c << 8) | ocu[i++]; | ||
126 | |||
127 | /* Compress Unicode to UTF-8 */ | ||
128 | if (c < 0x80U) | ||
129 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; | ||
130 | else if (c < 0x800U) { | ||
131 | if (utf_o->u_len > (UDF_NAME_LEN - 4)) | ||
132 | break; | ||
133 | utf_o->u_name[utf_o->u_len++] = | ||
134 | (uint8_t)(0xc0 | (c >> 6)); | ||
135 | utf_o->u_name[utf_o->u_len++] = | ||
136 | (uint8_t)(0x80 | (c & 0x3f)); | ||
137 | } else { | ||
138 | if (utf_o->u_len > (UDF_NAME_LEN - 5)) | ||
139 | break; | ||
140 | utf_o->u_name[utf_o->u_len++] = | ||
141 | (uint8_t)(0xe0 | (c >> 12)); | ||
142 | utf_o->u_name[utf_o->u_len++] = | ||
143 | (uint8_t)(0x80 | | ||
144 | ((c >> 6) & 0x3f)); | ||
145 | utf_o->u_name[utf_o->u_len++] = | ||
146 | (uint8_t)(0x80 | (c & 0x3f)); | ||
147 | } | ||
148 | } | 53 | } |
149 | utf_o->u_cmpID = 8; | 54 | return u_len; |
150 | |||
151 | return utf_o->u_len; | ||
152 | } | 55 | } |
153 | 56 | ||
154 | /* | 57 | static int udf_char2uni_utf8(const unsigned char *in, |
155 | * | 58 | int boundlen, |
156 | * udf_UTF8toCS0 | 59 | wchar_t *uni) |
157 | * | ||
158 | * PURPOSE | ||
159 | * Convert UTF-8 to the OSTA Compressed Unicode equivalent. | ||
160 | * | ||
161 | * DESCRIPTION | ||
162 | * This routine is only called by udf_lookup(). | ||
163 | * | ||
164 | * PRE-CONDITIONS | ||
165 | * ocu Pointer to OSTA Compressed Unicode output | ||
166 | * buffer of size UDF_NAME_LEN bytes. | ||
167 | * utf Pointer to UTF-8 input buffer. | ||
168 | * utf_len Length of UTF-8 input buffer in bytes. | ||
169 | * | ||
170 | * POST-CONDITIONS | ||
171 | * <return> Zero on success. | ||
172 | * | ||
173 | * HISTORY | ||
174 | * November 12, 1997 - Andrew E. Mileski | ||
175 | * Written, tested, and released. | ||
176 | */ | ||
177 | static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) | ||
178 | { | 60 | { |
179 | unsigned c, i, max_val, utf_char; | 61 | unsigned int utf_char; |
180 | int utf_cnt, u_len, u_ch; | 62 | unsigned char c; |
181 | 63 | int utf_cnt, u_len; | |
182 | memset(ocu, 0, sizeof(dstring) * length); | ||
183 | ocu[0] = 8; | ||
184 | max_val = 0xffU; | ||
185 | u_ch = 1; | ||
186 | 64 | ||
187 | try_again: | 65 | utf_char = 0; |
188 | u_len = 0U; | 66 | utf_cnt = 0; |
189 | utf_char = 0U; | 67 | for (u_len = 0; u_len < boundlen;) { |
190 | utf_cnt = 0U; | 68 | c = in[u_len++]; |
191 | for (i = 0U; i < utf->u_len; i++) { | ||
192 | /* Name didn't fit? */ | ||
193 | if (u_len + 1 + u_ch >= length) | ||
194 | return 0; | ||
195 | |||
196 | c = (uint8_t)utf->u_name[i]; | ||
197 | 69 | ||
198 | /* Complete a multi-byte UTF-8 character */ | 70 | /* Complete a multi-byte UTF-8 character */ |
199 | if (utf_cnt) { | 71 | if (utf_cnt) { |
200 | utf_char = (utf_char << 6) | (c & 0x3fU); | 72 | utf_char = (utf_char << 6) | (c & 0x3f); |
201 | if (--utf_cnt) | 73 | if (--utf_cnt) |
202 | continue; | 74 | continue; |
203 | } else { | 75 | } else { |
204 | /* Check for a multi-byte UTF-8 character */ | 76 | /* Check for a multi-byte UTF-8 character */ |
205 | if (c & 0x80U) { | 77 | if (c & 0x80) { |
206 | /* Start a multi-byte UTF-8 character */ | 78 | /* Start a multi-byte UTF-8 character */ |
207 | if ((c & 0xe0U) == 0xc0U) { | 79 | if ((c & 0xe0) == 0xc0) { |
208 | utf_char = c & 0x1fU; | 80 | utf_char = c & 0x1f; |
209 | utf_cnt = 1; | 81 | utf_cnt = 1; |
210 | } else if ((c & 0xf0U) == 0xe0U) { | 82 | } else if ((c & 0xf0) == 0xe0) { |
211 | utf_char = c & 0x0fU; | 83 | utf_char = c & 0x0f; |
212 | utf_cnt = 2; | 84 | utf_cnt = 2; |
213 | } else if ((c & 0xf8U) == 0xf0U) { | 85 | } else if ((c & 0xf8) == 0xf0) { |
214 | utf_char = c & 0x07U; | 86 | utf_char = c & 0x07; |
215 | utf_cnt = 3; | 87 | utf_cnt = 3; |
216 | } else if ((c & 0xfcU) == 0xf8U) { | 88 | } else if ((c & 0xfc) == 0xf8) { |
217 | utf_char = c & 0x03U; | 89 | utf_char = c & 0x03; |
218 | utf_cnt = 4; | 90 | utf_cnt = 4; |
219 | } else if ((c & 0xfeU) == 0xfcU) { | 91 | } else if ((c & 0xfe) == 0xfc) { |
220 | utf_char = c & 0x01U; | 92 | utf_char = c & 0x01; |
221 | utf_cnt = 5; | 93 | utf_cnt = 5; |
222 | } else { | 94 | } else { |
223 | goto error_out; | 95 | utf_cnt = -1; |
96 | break; | ||
224 | } | 97 | } |
225 | continue; | 98 | continue; |
226 | } else { | 99 | } else { |
@@ -228,97 +101,216 @@ try_again: | |||
228 | utf_char = c; | 101 | utf_char = c; |
229 | } | 102 | } |
230 | } | 103 | } |
231 | 104 | *uni = utf_char; | |
232 | /* Choose no compression if necessary */ | 105 | break; |
233 | if (utf_char > max_val) { | ||
234 | if (max_val == 0xffU) { | ||
235 | max_val = 0xffffU; | ||
236 | ocu[0] = (uint8_t)0x10U; | ||
237 | u_ch = 2; | ||
238 | goto try_again; | ||
239 | } | ||
240 | goto error_out; | ||
241 | } | ||
242 | |||
243 | if (max_val == 0xffffU) | ||
244 | ocu[++u_len] = (uint8_t)(utf_char >> 8); | ||
245 | ocu[++u_len] = (uint8_t)(utf_char & 0xffU); | ||
246 | } | 106 | } |
247 | |||
248 | if (utf_cnt) { | 107 | if (utf_cnt) { |
249 | error_out: | 108 | *uni = '?'; |
250 | ocu[++u_len] = '?'; | 109 | return -EINVAL; |
251 | printk(KERN_DEBUG pr_fmt("bad UTF-8 character\n")); | ||
252 | } | 110 | } |
111 | return u_len; | ||
112 | } | ||
253 | 113 | ||
254 | ocu[length - 1] = (uint8_t)u_len + 1; | 114 | #define ILLEGAL_CHAR_MARK '_' |
115 | #define EXT_MARK '.' | ||
116 | #define CRC_MARK '#' | ||
117 | #define EXT_SIZE 5 | ||
118 | /* Number of chars we need to store generated CRC to make filename unique */ | ||
119 | #define CRC_LEN 5 | ||
120 | |||
121 | static int udf_name_conv_char(uint8_t *str_o, int str_o_max_len, | ||
122 | int *str_o_idx, | ||
123 | const uint8_t *str_i, int str_i_max_len, | ||
124 | int *str_i_idx, | ||
125 | int u_ch, int *needsCRC, | ||
126 | int (*conv_f)(wchar_t, unsigned char *, int), | ||
127 | int translate) | ||
128 | { | ||
129 | uint32_t c; | ||
130 | int illChar = 0; | ||
131 | int len, gotch = 0; | ||
132 | |||
133 | for (; (!gotch) && (*str_i_idx < str_i_max_len); *str_i_idx += u_ch) { | ||
134 | if (*str_o_idx >= str_o_max_len) { | ||
135 | *needsCRC = 1; | ||
136 | return gotch; | ||
137 | } | ||
255 | 138 | ||
256 | return u_len + 1; | 139 | /* Expand OSTA compressed Unicode to Unicode */ |
140 | c = str_i[*str_i_idx]; | ||
141 | if (u_ch > 1) | ||
142 | c = (c << 8) | str_i[*str_i_idx + 1]; | ||
143 | |||
144 | if (translate && (c == '/' || c == 0)) | ||
145 | illChar = 1; | ||
146 | else if (illChar) | ||
147 | break; | ||
148 | else | ||
149 | gotch = 1; | ||
150 | } | ||
151 | if (illChar) { | ||
152 | *needsCRC = 1; | ||
153 | c = ILLEGAL_CHAR_MARK; | ||
154 | gotch = 1; | ||
155 | } | ||
156 | if (gotch) { | ||
157 | len = conv_f(c, &str_o[*str_o_idx], str_o_max_len - *str_o_idx); | ||
158 | /* Valid character? */ | ||
159 | if (len >= 0) | ||
160 | *str_o_idx += len; | ||
161 | else if (len == -ENAMETOOLONG) { | ||
162 | *needsCRC = 1; | ||
163 | gotch = 0; | ||
164 | } else { | ||
165 | str_o[(*str_o_idx)++] = '?'; | ||
166 | *needsCRC = 1; | ||
167 | } | ||
168 | } | ||
169 | return gotch; | ||
257 | } | 170 | } |
258 | 171 | ||
259 | static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, | 172 | static int udf_name_from_CS0(uint8_t *str_o, int str_max_len, |
260 | const struct ustr *ocu_i) | 173 | const uint8_t *ocu, int ocu_len, |
174 | int (*conv_f)(wchar_t, unsigned char *, int), | ||
175 | int translate) | ||
261 | { | 176 | { |
262 | const uint8_t *ocu; | 177 | uint32_t c; |
263 | uint8_t cmp_id, ocu_len; | 178 | uint8_t cmp_id; |
264 | int i, len; | 179 | int idx, len; |
180 | int u_ch; | ||
181 | int needsCRC = 0; | ||
182 | int ext_i_len, ext_max_len; | ||
183 | int str_o_len = 0; /* Length of resulting output */ | ||
184 | int ext_o_len = 0; /* Extension output length */ | ||
185 | int ext_crc_len = 0; /* Extension output length if used with CRC */ | ||
186 | int i_ext = -1; /* Extension position in input buffer */ | ||
187 | int o_crc = 0; /* Rightmost possible output pos for CRC+ext */ | ||
188 | unsigned short valueCRC; | ||
189 | uint8_t ext[EXT_SIZE * NLS_MAX_CHARSET_SIZE + 1]; | ||
190 | uint8_t crc[CRC_LEN]; | ||
265 | 191 | ||
192 | if (str_max_len <= 0) | ||
193 | return 0; | ||
266 | 194 | ||
267 | ocu_len = ocu_i->u_len; | ||
268 | if (ocu_len == 0) { | 195 | if (ocu_len == 0) { |
269 | memset(utf_o, 0, sizeof(struct ustr)); | 196 | memset(str_o, 0, str_max_len); |
270 | return 0; | 197 | return 0; |
271 | } | 198 | } |
272 | 199 | ||
273 | cmp_id = ocu_i->u_cmpID; | 200 | cmp_id = ocu[0]; |
274 | if (cmp_id != 8 && cmp_id != 16) { | 201 | if (cmp_id != 8 && cmp_id != 16) { |
275 | memset(utf_o, 0, sizeof(struct ustr)); | 202 | memset(str_o, 0, str_max_len); |
276 | pr_err("unknown compression code (%d) stri=%s\n", | 203 | pr_err("unknown compression code (%d)\n", cmp_id); |
277 | cmp_id, ocu_i->u_name); | ||
278 | return -EINVAL; | 204 | return -EINVAL; |
279 | } | 205 | } |
206 | u_ch = cmp_id >> 3; | ||
280 | 207 | ||
281 | ocu = ocu_i->u_name; | 208 | ocu++; |
282 | utf_o->u_len = 0; | 209 | ocu_len--; |
283 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { | ||
284 | /* Expand OSTA compressed Unicode to Unicode */ | ||
285 | uint32_t c = ocu[i++]; | ||
286 | if (cmp_id == 16) | ||
287 | c = (c << 8) | ocu[i++]; | ||
288 | 210 | ||
289 | len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], | 211 | if (ocu_len % u_ch) { |
290 | UDF_NAME_LEN - 2 - utf_o->u_len); | 212 | pr_err("incorrect filename length (%d)\n", ocu_len + 1); |
291 | /* Valid character? */ | 213 | return -EINVAL; |
292 | if (len >= 0) | 214 | } |
293 | utf_o->u_len += len; | 215 | |
294 | else | 216 | if (translate) { |
295 | utf_o->u_name[utf_o->u_len++] = '?'; | 217 | /* Look for extension */ |
218 | for (idx = ocu_len - u_ch, ext_i_len = 0; | ||
219 | (idx >= 0) && (ext_i_len < EXT_SIZE); | ||
220 | idx -= u_ch, ext_i_len++) { | ||
221 | c = ocu[idx]; | ||
222 | if (u_ch > 1) | ||
223 | c = (c << 8) | ocu[idx + 1]; | ||
224 | |||
225 | if (c == EXT_MARK) { | ||
226 | if (ext_i_len) | ||
227 | i_ext = idx; | ||
228 | break; | ||
229 | } | ||
230 | } | ||
231 | if (i_ext >= 0) { | ||
232 | /* Convert extension */ | ||
233 | ext_max_len = min_t(int, sizeof(ext), str_max_len); | ||
234 | ext[ext_o_len++] = EXT_MARK; | ||
235 | idx = i_ext + u_ch; | ||
236 | while (udf_name_conv_char(ext, ext_max_len, &ext_o_len, | ||
237 | ocu, ocu_len, &idx, | ||
238 | u_ch, &needsCRC, | ||
239 | conv_f, translate)) { | ||
240 | if ((ext_o_len + CRC_LEN) < str_max_len) | ||
241 | ext_crc_len = ext_o_len; | ||
242 | } | ||
243 | } | ||
296 | } | 244 | } |
297 | utf_o->u_cmpID = 8; | ||
298 | 245 | ||
299 | return utf_o->u_len; | 246 | idx = 0; |
247 | while (1) { | ||
248 | if (translate && (idx == i_ext)) { | ||
249 | if (str_o_len > (str_max_len - ext_o_len)) | ||
250 | needsCRC = 1; | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | if (!udf_name_conv_char(str_o, str_max_len, &str_o_len, | ||
255 | ocu, ocu_len, &idx, | ||
256 | u_ch, &needsCRC, conv_f, translate)) | ||
257 | break; | ||
258 | |||
259 | if (translate && | ||
260 | (str_o_len <= (str_max_len - ext_o_len - CRC_LEN))) | ||
261 | o_crc = str_o_len; | ||
262 | } | ||
263 | |||
264 | if (translate) { | ||
265 | if (str_o_len <= 2 && str_o[0] == '.' && | ||
266 | (str_o_len == 1 || str_o[1] == '.')) | ||
267 | needsCRC = 1; | ||
268 | if (needsCRC) { | ||
269 | str_o_len = o_crc; | ||
270 | valueCRC = crc_itu_t(0, ocu, ocu_len); | ||
271 | crc[0] = CRC_MARK; | ||
272 | crc[1] = hex_asc_upper_hi(valueCRC >> 8); | ||
273 | crc[2] = hex_asc_upper_lo(valueCRC >> 8); | ||
274 | crc[3] = hex_asc_upper_hi(valueCRC); | ||
275 | crc[4] = hex_asc_upper_lo(valueCRC); | ||
276 | len = min_t(int, CRC_LEN, str_max_len - str_o_len); | ||
277 | memcpy(&str_o[str_o_len], crc, len); | ||
278 | str_o_len += len; | ||
279 | ext_o_len = ext_crc_len; | ||
280 | } | ||
281 | if (ext_o_len > 0) { | ||
282 | memcpy(&str_o[str_o_len], ext, ext_o_len); | ||
283 | str_o_len += ext_o_len; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | return str_o_len; | ||
300 | } | 288 | } |
301 | 289 | ||
302 | static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, | 290 | static int udf_name_to_CS0(uint8_t *ocu, int ocu_max_len, |
303 | int length) | 291 | const uint8_t *str_i, int str_len, |
292 | int (*conv_f)(const unsigned char *, int, wchar_t *)) | ||
304 | { | 293 | { |
305 | int len; | 294 | int i, len; |
306 | unsigned i, max_val; | 295 | unsigned int max_val; |
307 | uint16_t uni_char; | 296 | wchar_t uni_char; |
308 | int u_len, u_ch; | 297 | int u_len, u_ch; |
309 | 298 | ||
310 | memset(ocu, 0, sizeof(dstring) * length); | 299 | if (ocu_max_len <= 0) |
300 | return 0; | ||
301 | |||
302 | memset(ocu, 0, ocu_max_len); | ||
311 | ocu[0] = 8; | 303 | ocu[0] = 8; |
312 | max_val = 0xffU; | 304 | max_val = 0xff; |
313 | u_ch = 1; | 305 | u_ch = 1; |
314 | 306 | ||
315 | try_again: | 307 | try_again: |
316 | u_len = 0U; | 308 | u_len = 1; |
317 | for (i = 0U; i < uni->u_len; i++) { | 309 | for (i = 0; i < str_len; i++) { |
318 | /* Name didn't fit? */ | 310 | /* Name didn't fit? */ |
319 | if (u_len + 1 + u_ch >= length) | 311 | if (u_len + u_ch > ocu_max_len) |
320 | return 0; | 312 | return 0; |
321 | len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); | 313 | len = conv_f(&str_i[i], str_len - i, &uni_char); |
322 | if (!len) | 314 | if (!len) |
323 | continue; | 315 | continue; |
324 | /* Invalid character, deal with it */ | 316 | /* Invalid character, deal with it */ |
@@ -328,187 +320,65 @@ try_again: | |||
328 | } | 320 | } |
329 | 321 | ||
330 | if (uni_char > max_val) { | 322 | if (uni_char > max_val) { |
331 | max_val = 0xffffU; | 323 | max_val = 0xffff; |
332 | ocu[0] = (uint8_t)0x10U; | 324 | ocu[0] = 0x10; |
333 | u_ch = 2; | 325 | u_ch = 2; |
334 | goto try_again; | 326 | goto try_again; |
335 | } | 327 | } |
336 | 328 | ||
337 | if (max_val == 0xffffU) | 329 | if (max_val == 0xffff) |
338 | ocu[++u_len] = (uint8_t)(uni_char >> 8); | 330 | ocu[u_len++] = (uint8_t)(uni_char >> 8); |
339 | ocu[++u_len] = (uint8_t)(uni_char & 0xffU); | 331 | ocu[u_len++] = (uint8_t)(uni_char & 0xff); |
340 | i += len - 1; | 332 | i += len - 1; |
341 | } | 333 | } |
342 | 334 | ||
343 | ocu[length - 1] = (uint8_t)u_len + 1; | 335 | return u_len; |
344 | return u_len + 1; | ||
345 | } | 336 | } |
346 | 337 | ||
347 | int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, | 338 | int udf_CS0toUTF8(uint8_t *utf_o, int o_len, const uint8_t *ocu_i, int i_len) |
339 | { | ||
340 | return udf_name_from_CS0(utf_o, o_len, ocu_i, i_len, | ||
341 | udf_uni2char_utf8, 0); | ||
342 | } | ||
343 | |||
344 | int udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen, | ||
348 | uint8_t *dname, int dlen) | 345 | uint8_t *dname, int dlen) |
349 | { | 346 | { |
350 | struct ustr *filename, *unifilename; | 347 | int (*conv_f)(wchar_t, unsigned char *, int); |
351 | int ret; | 348 | int ret; |
352 | 349 | ||
353 | if (!slen) | 350 | if (!slen) |
354 | return -EIO; | 351 | return -EIO; |
355 | 352 | ||
356 | filename = kmalloc(sizeof(struct ustr), GFP_NOFS); | 353 | if (dlen <= 0) |
357 | if (!filename) | 354 | return 0; |
358 | return -ENOMEM; | ||
359 | |||
360 | unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS); | ||
361 | if (!unifilename) { | ||
362 | ret = -ENOMEM; | ||
363 | goto out1; | ||
364 | } | ||
365 | 355 | ||
366 | udf_build_ustr_exact(unifilename, sname, slen); | ||
367 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { | 356 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { |
368 | ret = udf_CS0toUTF8(filename, unifilename); | 357 | conv_f = udf_uni2char_utf8; |
369 | if (ret < 0) { | ||
370 | udf_debug("Failed in udf_get_filename: sname = %s\n", | ||
371 | sname); | ||
372 | goto out2; | ||
373 | } | ||
374 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { | 358 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { |
375 | ret = udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename, | 359 | conv_f = UDF_SB(sb)->s_nls_map->uni2char; |
376 | unifilename); | ||
377 | if (ret < 0) { | ||
378 | udf_debug("Failed in udf_get_filename: sname = %s\n", | ||
379 | sname); | ||
380 | goto out2; | ||
381 | } | ||
382 | } else | 360 | } else |
383 | BUG(); | 361 | BUG(); |
384 | 362 | ||
385 | ret = udf_translate_to_linux(dname, dlen, | 363 | ret = udf_name_from_CS0(dname, dlen, sname, slen, conv_f, 1); |
386 | filename->u_name, filename->u_len, | ||
387 | unifilename->u_name, unifilename->u_len); | ||
388 | /* Zero length filename isn't valid... */ | 364 | /* Zero length filename isn't valid... */ |
389 | if (ret == 0) | 365 | if (ret == 0) |
390 | ret = -EINVAL; | 366 | ret = -EINVAL; |
391 | out2: | ||
392 | kfree(unifilename); | ||
393 | out1: | ||
394 | kfree(filename); | ||
395 | return ret; | 367 | return ret; |
396 | } | 368 | } |
397 | 369 | ||
398 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, | 370 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, |
399 | uint8_t *dname, int flen) | 371 | uint8_t *dname, int dlen) |
400 | { | 372 | { |
401 | struct ustr unifilename; | 373 | int (*conv_f)(const unsigned char *, int, wchar_t *); |
402 | int namelen; | ||
403 | |||
404 | if (!udf_char_to_ustr(&unifilename, sname, flen)) | ||
405 | return 0; | ||
406 | 374 | ||
407 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { | 375 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { |
408 | namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN); | 376 | conv_f = udf_char2uni_utf8; |
409 | if (!namelen) | ||
410 | return 0; | ||
411 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { | 377 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { |
412 | namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, | 378 | conv_f = UDF_SB(sb)->s_nls_map->char2uni; |
413 | &unifilename, UDF_NAME_LEN); | ||
414 | if (!namelen) | ||
415 | return 0; | ||
416 | } else | 379 | } else |
417 | return 0; | 380 | BUG(); |
418 | 381 | ||
419 | return namelen; | 382 | return udf_name_to_CS0(dname, dlen, sname, slen, conv_f); |
420 | } | 383 | } |
421 | 384 | ||
422 | #define ILLEGAL_CHAR_MARK '_' | ||
423 | #define EXT_MARK '.' | ||
424 | #define CRC_MARK '#' | ||
425 | #define EXT_SIZE 5 | ||
426 | /* Number of chars we need to store generated CRC to make filename unique */ | ||
427 | #define CRC_LEN 5 | ||
428 | |||
429 | static int udf_translate_to_linux(uint8_t *newName, int newLen, | ||
430 | uint8_t *udfName, int udfLen, | ||
431 | uint8_t *fidName, int fidNameLen) | ||
432 | { | ||
433 | int index, newIndex = 0, needsCRC = 0; | ||
434 | int extIndex = 0, newExtIndex = 0, hasExt = 0; | ||
435 | unsigned short valueCRC; | ||
436 | uint8_t curr; | ||
437 | |||
438 | if (udfName[0] == '.' && | ||
439 | (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) { | ||
440 | needsCRC = 1; | ||
441 | newIndex = udfLen; | ||
442 | memcpy(newName, udfName, udfLen); | ||
443 | } else { | ||
444 | for (index = 0; index < udfLen; index++) { | ||
445 | curr = udfName[index]; | ||
446 | if (curr == '/' || curr == 0) { | ||
447 | needsCRC = 1; | ||
448 | curr = ILLEGAL_CHAR_MARK; | ||
449 | while (index + 1 < udfLen && | ||
450 | (udfName[index + 1] == '/' || | ||
451 | udfName[index + 1] == 0)) | ||
452 | index++; | ||
453 | } | ||
454 | if (curr == EXT_MARK && | ||
455 | (udfLen - index - 1) <= EXT_SIZE) { | ||
456 | if (udfLen == index + 1) | ||
457 | hasExt = 0; | ||
458 | else { | ||
459 | hasExt = 1; | ||
460 | extIndex = index; | ||
461 | newExtIndex = newIndex; | ||
462 | } | ||
463 | } | ||
464 | if (newIndex < newLen) | ||
465 | newName[newIndex++] = curr; | ||
466 | else | ||
467 | needsCRC = 1; | ||
468 | } | ||
469 | } | ||
470 | if (needsCRC) { | ||
471 | uint8_t ext[EXT_SIZE]; | ||
472 | int localExtIndex = 0; | ||
473 | |||
474 | if (hasExt) { | ||
475 | int maxFilenameLen; | ||
476 | for (index = 0; | ||
477 | index < EXT_SIZE && extIndex + index + 1 < udfLen; | ||
478 | index++) { | ||
479 | curr = udfName[extIndex + index + 1]; | ||
480 | |||
481 | if (curr == '/' || curr == 0) { | ||
482 | needsCRC = 1; | ||
483 | curr = ILLEGAL_CHAR_MARK; | ||
484 | while (extIndex + index + 2 < udfLen && | ||
485 | (index + 1 < EXT_SIZE && | ||
486 | (udfName[extIndex + index + 2] == '/' || | ||
487 | udfName[extIndex + index + 2] == 0))) | ||
488 | index++; | ||
489 | } | ||
490 | ext[localExtIndex++] = curr; | ||
491 | } | ||
492 | maxFilenameLen = newLen - CRC_LEN - localExtIndex; | ||
493 | if (newIndex > maxFilenameLen) | ||
494 | newIndex = maxFilenameLen; | ||
495 | else | ||
496 | newIndex = newExtIndex; | ||
497 | } else if (newIndex > newLen - CRC_LEN) | ||
498 | newIndex = newLen - CRC_LEN; | ||
499 | newName[newIndex++] = CRC_MARK; | ||
500 | valueCRC = crc_itu_t(0, fidName, fidNameLen); | ||
501 | newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8); | ||
502 | newName[newIndex++] = hex_asc_upper_lo(valueCRC >> 8); | ||
503 | newName[newIndex++] = hex_asc_upper_hi(valueCRC); | ||
504 | newName[newIndex++] = hex_asc_upper_lo(valueCRC); | ||
505 | |||
506 | if (hasExt) { | ||
507 | newName[newIndex++] = EXT_MARK; | ||
508 | for (index = 0; index < localExtIndex; index++) | ||
509 | newName[newIndex++] = ext[index]; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | return newIndex; | ||
514 | } | ||
diff --git a/include/linux/dqblk_qtree.h b/include/linux/dqblk_qtree.h index ff8b55359648..0de21e935976 100644 --- a/include/linux/dqblk_qtree.h +++ b/include/linux/dqblk_qtree.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define QTREE_DEL_REWRITE 6 | 15 | #define QTREE_DEL_REWRITE 6 |
16 | 16 | ||
17 | struct dquot; | 17 | struct dquot; |
18 | struct kqid; | ||
18 | 19 | ||
19 | /* Operations */ | 20 | /* Operations */ |
20 | struct qtree_fmt_operations { | 21 | struct qtree_fmt_operations { |
@@ -52,5 +53,6 @@ static inline int qtree_depth(struct qtree_mem_dqinfo *info) | |||
52 | entries *= epb; | 53 | entries *= epb; |
53 | return i; | 54 | return i; |
54 | } | 55 | } |
56 | int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid); | ||
55 | 57 | ||
56 | #endif /* _LINUX_DQBLK_QTREE_H */ | 58 | #endif /* _LINUX_DQBLK_QTREE_H */ |
diff --git a/include/linux/quota.h b/include/linux/quota.h index fba92f5c1a63..9dfb6bce8c9e 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h | |||
@@ -306,6 +306,7 @@ struct quota_format_ops { | |||
306 | int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ | 306 | int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ |
307 | int (*commit_dqblk)(struct dquot *dquot); /* Write structure for one user */ | 307 | int (*commit_dqblk)(struct dquot *dquot); /* Write structure for one user */ |
308 | int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */ | 308 | int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */ |
309 | int (*get_next_id)(struct super_block *sb, struct kqid *qid); /* Get next ID with existing structure in the quota file */ | ||
309 | }; | 310 | }; |
310 | 311 | ||
311 | /* Operations working with dquots */ | 312 | /* Operations working with dquots */ |
@@ -321,6 +322,8 @@ struct dquot_operations { | |||
321 | * quota code only */ | 322 | * quota code only */ |
322 | qsize_t *(*get_reserved_space) (struct inode *); | 323 | qsize_t *(*get_reserved_space) (struct inode *); |
323 | int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */ | 324 | int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */ |
325 | /* Get next ID with active quota structure */ | ||
326 | int (*get_next_id) (struct super_block *sb, struct kqid *qid); | ||
324 | }; | 327 | }; |
325 | 328 | ||
326 | struct path; | 329 | struct path; |
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 7a57c28eb5e7..f00fa86ac966 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h | |||
@@ -82,6 +82,7 @@ int dquot_commit(struct dquot *dquot); | |||
82 | int dquot_acquire(struct dquot *dquot); | 82 | int dquot_acquire(struct dquot *dquot); |
83 | int dquot_release(struct dquot *dquot); | 83 | int dquot_release(struct dquot *dquot); |
84 | int dquot_commit_info(struct super_block *sb, int type); | 84 | int dquot_commit_info(struct super_block *sb, int type); |
85 | int dquot_get_next_id(struct super_block *sb, struct kqid *qid); | ||
85 | int dquot_mark_dquot_dirty(struct dquot *dquot); | 86 | int dquot_mark_dquot_dirty(struct dquot *dquot); |
86 | 87 | ||
87 | int dquot_file_open(struct inode *inode, struct file *file); | 88 | int dquot_file_open(struct inode *inode, struct file *file); |
@@ -99,6 +100,8 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state); | |||
99 | int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii); | 100 | int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii); |
100 | int dquot_get_dqblk(struct super_block *sb, struct kqid id, | 101 | int dquot_get_dqblk(struct super_block *sb, struct kqid id, |
101 | struct qc_dqblk *di); | 102 | struct qc_dqblk *di); |
103 | int dquot_get_next_dqblk(struct super_block *sb, struct kqid *id, | ||
104 | struct qc_dqblk *di); | ||
102 | int dquot_set_dqblk(struct super_block *sb, struct kqid id, | 105 | int dquot_set_dqblk(struct super_block *sb, struct kqid id, |
103 | struct qc_dqblk *di); | 106 | struct qc_dqblk *di); |
104 | 107 | ||