Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1297994 > unrolled thread
| Started by | Andrew Gabbasov <andrew_gabbasov@mentor.com> |
|---|---|
| First post | 2015-12-24 17:30 +0100 |
| Last post | 2015-12-24 17:30 +0100 |
| Articles | 5 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v2 0/7] udf: rework name conversions to fix multi-bytes characters support Andrew Gabbasov <andrew_gabbasov@mentor.com> - 2015-12-24 17:30 +0100
[PATCH v2 5/7] udf: Adjust UDF_NAME_LEN to better reflect actual restrictions Andrew Gabbasov <andrew_gabbasov@mentor.com> - 2015-12-24 17:30 +0100
[PATCH v2 1/7] udf: Prevent buffer overrun with multi-byte characters Andrew Gabbasov <andrew_gabbasov@mentor.com> - 2015-12-24 17:30 +0100
[PATCH v2 3/7] udf: Parameterize output length in udf_put_filename Andrew Gabbasov <andrew_gabbasov@mentor.com> - 2015-12-24 17:30 +0100
[PATCH v2 7/7] udf: Merge linux specific translation into CS0 conversion function Andrew Gabbasov <andrew_gabbasov@mentor.com> - 2015-12-24 17:30 +0100
| From | Andrew Gabbasov <andrew_gabbasov@mentor.com> |
|---|---|
| Date | 2015-12-24 17:30 +0100 |
| Subject | [PATCH v2 0/7] udf: rework name conversions to fix multi-bytes characters support |
| Message-ID | <qJgW5-Ay-7@gated-at.bofh.it> |
V2: The single patch was split into several commits for separate logical steps. Also, some minor fixes were done in the code of the patches. V1: Current implementation has several issues in unicode.c, mostly related to handling multi-bytes characters in file names: - loop ending conditions in udf_CS0toUTF8 and udf_CS0toNLS functions do not properly catch the end of output buffer in case of multi-bytes characters, allowing out-of-bounds writing and memory corruption; - udf_UTF8toCS0 and udf_NLStoCS0 do not check the right boundary of output buffer at all, also allowing out-of-bounds writing and memory corruption; - udf_translate_to_linux does not take into account multi-bytes characters at all (although it is called after converting to UTF8 or NLS): maximal length of extension is counted as 5 bytes, that may be incorrect with multi-bytes characters; when inserting CRC and extension for long names (near the end of the buffer), they are inserted at fixed place at the end, that can break into the middle of the multi-bytes character; - when being converted from CS0 to UTF8 (or NLS), the name can be truncated (even if the sizes in bytes of input and output buffers are the same), but the following translating function does not know about it and does not insert CRC, as it is assumed by the specs. Because of the last item above, it looks like all the checks and conversions (re-coding and possible CRC insertions) should be done simultaneously in the single function. This means that the listed issues can not be fixed independently and separately. So, the whole conversion and translation support should be reworked. The proposed implementation below fixes the listed issues, and also has some additional features: - it gets rid of "struct ustr", since it actually just makes an unneeded extra copying of the buffer and does not have any other significant advantage; - it unifies UTF8 and NLS conversions support, since there is no much sense to separate these cases; - UDF_NAME_LEN constant adjusted to better reflect actual restrictions. Andrew Gabbasov (7): udf: Prevent buffer overrun with multi-byte characters udf: Check output buffer length when converting name to CS0 udf: Parameterize output length in udf_put_filename udf: Join functions for UTF8 and NLS conversions udf: Adjust UDF_NAME_LEN to better reflect actual restrictions udf: Remove struct ustr as non-needed intermediate storage udf: Merge linux specific translation into CS0 conversion function fs/udf/namei.c | 16 +- fs/udf/super.c | 38 ++-- fs/udf/udfdecl.h | 21 +- fs/udf/unicode.c | 611 ++++++++++++++++++++++--------------------------------- 4 files changed, 274 insertions(+), 412 deletions(-) -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Andrew Gabbasov <andrew_gabbasov@mentor.com> |
|---|---|
| Date | 2015-12-24 17:30 +0100 |
| Subject | [PATCH v2 5/7] udf: Adjust UDF_NAME_LEN to better reflect actual restrictions |
| Message-ID | <qJgW5-Ay-15@gated-at.bofh.it> |
| In reply to | #1297994 |
Actual name length restriction is 254 bytes, this is used in 'ustr'
structure, and this is what fits into UDF File Ident structures.
And in most cases the constant is used as UDF_NAME_LEN-2.
So, it's better to just modify the constant to make it closer
to reality.
Also, in some cases it's useful to have a separate constant for
the maximum length of file name field in CS0 encoding in UDF File
Ident structures.
Also, remove the unused UDF_PATH_LEN constant.
Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
---
fs/udf/namei.c | 10 +++++-----
fs/udf/super.c | 2 +-
fs/udf/udfdecl.h | 6 +++---
fs/udf/unicode.c | 6 +++---
4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 6192070..8527368 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -291,7 +291,7 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
struct udf_fileident_bh fibh;
struct fileIdentDesc *fi;
- if (dentry->d_name.len > UDF_NAME_LEN - 2)
+ if (dentry->d_name.len > UDF_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
#ifdef UDF_RECOVERY
@@ -351,7 +351,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
struct udf_inode_info *dinfo;
fibh->sbh = fibh->ebh = NULL;
- name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS);
if (!name) {
*err = -ENOMEM;
goto out_err;
@@ -364,7 +364,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
}
namelen = udf_put_filename(sb, dentry->d_name.name,
dentry->d_name.len,
- name, UDF_NAME_LEN);
+ name, UDF_NAME_LEN_CS0);
if (!namelen) {
*err = -ENAMETOOLONG;
goto out_err;
@@ -915,7 +915,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
iinfo = UDF_I(inode);
down_write(&iinfo->i_data_sem);
- name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS);
if (!name) {
err = -ENOMEM;
goto out_no_entry;
@@ -999,7 +999,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
if (pc->componentType == 5) {
namelen = udf_put_filename(sb, compstart,
symname - compstart,
- name, UDF_NAME_LEN);
+ name, UDF_NAME_LEN_CS0);
if (!namelen)
goto out_no_entry;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 81155b9..a801721 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -2348,7 +2348,7 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
le32_to_cpu(lvidiu->numDirs)) : 0)
+ buf->f_bfree;
buf->f_ffree = buf->f_bfree;
- buf->f_namelen = UDF_NAME_LEN - 2;
+ buf->f_namelen = UDF_NAME_LEN;
buf->f_fsid.val[0] = (u32)id;
buf->f_fsid.val[1] = (u32)(id >> 32);
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 35591e3..2a70a63 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,
#define UDF_EXTENT_FLAG_MASK 0xC0000000
#define UDF_NAME_PAD 4
-#define UDF_NAME_LEN 256
-#define UDF_PATH_LEN 1023
+#define UDF_NAME_LEN 254
+#define UDF_NAME_LEN_CS0 255
static inline size_t udf_file_entry_alloc_offset(struct inode *inode)
{
@@ -109,7 +109,7 @@ struct generic_desc {
struct ustr {
uint8_t u_cmpID;
- uint8_t u_name[UDF_NAME_LEN - 2];
+ uint8_t u_name[UDF_NAME_LEN];
uint8_t u_len;
};
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 21a8cfb..7eaa865 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -33,7 +33,7 @@ static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *,
static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
{
- if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2))
+ if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN))
return 0;
memset(dest, 0, sizeof(struct ustr));
@@ -184,14 +184,14 @@ static int udf_name_from_CS0(struct ustr *utf_o,
ocu = ocu_i->u_name;
utf_o->u_len = 0;
- for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
+ for (i = 0; (i < ocu_len) && (utf_o->u_len < UDF_NAME_LEN);) {
/* Expand OSTA compressed Unicode to Unicode */
uint32_t c = ocu[i++];
if (cmp_id == 16)
c = (c << 8) | ocu[i++];
len = conv_f(c, &utf_o->u_name[utf_o->u_len],
- UDF_NAME_LEN - 2 - utf_o->u_len);
+ UDF_NAME_LEN - utf_o->u_len);
/* Valid character? */
if (len >= 0)
utf_o->u_len += len;
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andrew Gabbasov <andrew_gabbasov@mentor.com> |
|---|---|
| Date | 2015-12-24 17:30 +0100 |
| Subject | [PATCH v2 1/7] udf: Prevent buffer overrun with multi-byte characters |
| Message-ID | <qJgW6-Ay-21@gated-at.bofh.it> |
| In reply to | #1297994 |
udf_CS0toUTF8 function stops the conversion when the output buffer
length reaches UDF_NAME_LEN-2, which is correct maximum name length,
but, when checking, it leaves the space for a single byte only,
while multi-bytes output characters can take more space, causing
buffer overflow.
Similar error exists in udf_CS0toNLS function, that restricts
the output length to UDF_NAME_LEN, while actual maximum allowed
length is UDF_NAME_LEN-2.
In these cases the output can override not only the current buffer
length field, causing corruption of the name buffer itself, but also
following allocation structures, causing kernel crash.
Adjust the output length checks in both functions to prevent buffer
overruns in case of multi-bytes UTF8 or NLS characters.
Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
---
fs/udf/unicode.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index ab478e6..95a224b 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -128,11 +128,15 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
if (c < 0x80U)
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
else if (c < 0x800U) {
+ if (utf_o->u_len > (UDF_NAME_LEN - 4))
+ break;
utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0xc0 | (c >> 6));
utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0x80 | (c & 0x3f));
} else {
+ if (utf_o->u_len > (UDF_NAME_LEN - 5))
+ break;
utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0xe0 | (c >> 12));
utf_o->u_name[utf_o->u_len++] =
@@ -277,7 +281,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
c = (c << 8) | ocu[i++];
len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
- UDF_NAME_LEN - utf_o->u_len);
+ UDF_NAME_LEN - 2 - utf_o->u_len);
/* Valid character? */
if (len >= 0)
utf_o->u_len += len;
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andrew Gabbasov <andrew_gabbasov@mentor.com> |
|---|---|
| Date | 2015-12-24 17:30 +0100 |
| Subject | [PATCH v2 3/7] udf: Parameterize output length in udf_put_filename |
| Message-ID | <qJgW7-Ay-35@gated-at.bofh.it> |
| In reply to | #1297994 |
Make the desired output length a parameter rather than have it
hard-coded to UDF_NAME_LEN. Although all call sites still have
this length the same, this parameterization will make the function
more universal and also consistent with udf_get_filename.
Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
---
fs/udf/namei.c | 10 ++++++----
fs/udf/udfdecl.h | 4 ++--
fs/udf/unicode.c | 10 +++++-----
3 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index c97b5a8..6192070 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -362,8 +362,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
*err = -EINVAL;
goto out_err;
}
- namelen = udf_put_filename(sb, dentry->d_name.name, name,
- dentry->d_name.len);
+ namelen = udf_put_filename(sb, dentry->d_name.name,
+ dentry->d_name.len,
+ name, UDF_NAME_LEN);
if (!namelen) {
*err = -ENAMETOOLONG;
goto out_err;
@@ -996,8 +997,9 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
}
if (pc->componentType == 5) {
- namelen = udf_put_filename(sb, compstart, name,
- symname - compstart);
+ namelen = udf_put_filename(sb, compstart,
+ symname - compstart,
+ name, UDF_NAME_LEN);
if (!namelen)
goto out_no_entry;
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 47bb3f5..35591e3 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -213,8 +213,8 @@ udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc,
/* unicode.c */
extern int udf_get_filename(struct super_block *, uint8_t *, int, uint8_t *,
int);
-extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
- int);
+extern int udf_put_filename(struct super_block *, const uint8_t *, int,
+ uint8_t *, int);
extern int udf_build_ustr(struct ustr *, dstring *, int);
extern int udf_CS0toUTF8(struct ustr *, const struct ustr *);
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 155f912..13e8b69 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -388,22 +388,22 @@ out1:
return ret;
}
-int udf_put_filename(struct super_block *sb, const uint8_t *sname,
- uint8_t *dname, int flen)
+int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen,
+ uint8_t *dname, int dlen)
{
struct ustr unifilename;
int namelen;
- if (!udf_char_to_ustr(&unifilename, sname, flen))
+ if (!udf_char_to_ustr(&unifilename, sname, slen))
return 0;
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
- namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
+ namelen = udf_UTF8toCS0(dname, &unifilename, dlen);
if (!namelen)
return 0;
} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname,
- &unifilename, UDF_NAME_LEN);
+ &unifilename, dlen);
if (!namelen)
return 0;
} else
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andrew Gabbasov <andrew_gabbasov@mentor.com> |
|---|---|
| Date | 2015-12-24 17:30 +0100 |
| Subject | [PATCH v2 7/7] udf: Merge linux specific translation into CS0 conversion function |
| Message-ID | <qJgW7-Ay-39@gated-at.bofh.it> |
| In reply to | #1297994 |
Current implementation of udf_translate_to_linux function does not
support multi-bytes characters at all: it counts bytes while calculating
extension length, when inserting CRC inside the name it doesn't
take into account inter-character boundaries and can break into
the middle of the character.
The most efficient way to properly support multi-bytes characters is
merging of translation operations directly into conversion function.
This can help to avoid extra passes along the string or parsing
the multi-bytes character back into unicode to find out it's length.
Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
---
fs/udf/unicode.c | 260 ++++++++++++++++++++++++++++++-------------------------
1 file changed, 141 insertions(+), 119 deletions(-)
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index f1cdeac..1dc967d 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -28,9 +28,6 @@
#include "udf_sb.h"
-static int udf_translate_to_linux(uint8_t *, int, const uint8_t *, int,
- const uint8_t *, int);
-
static int udf_uni2char_utf8(wchar_t uni,
unsigned char *out,
int boundlen)
@@ -114,13 +111,32 @@ static int udf_char2uni_utf8(const unsigned char *in,
return u_len;
}
+#define ILLEGAL_CHAR_MARK '_'
+#define EXT_MARK '.'
+#define CRC_MARK '#'
+#define EXT_SIZE 5
+/* Number of chars we need to store generated CRC to make filename unique */
+#define CRC_LEN 5
+
static int udf_name_from_CS0(uint8_t *str_o, int str_max_len,
const uint8_t *ocu, int ocu_len,
- int (*conv_f)(wchar_t, unsigned char *, int))
+ int (*conv_f)(wchar_t, unsigned char *, int),
+ int translate)
{
+ uint32_t c;
uint8_t cmp_id;
int i, len;
- int str_o_len = 0;
+ int u_ch;
+ int firstDots = 0, needsCRC = 0, illChar;
+ int ext_i_len, ext_max_len;
+ int str_o_len = 0; /* Length of resulting output */
+ int ext_o_len = 0; /* Extension output length */
+ int ext_crc_len = 0; /* Extension output length if used with CRC */
+ int i_ext = -1; /* Extension position in input buffer */
+ int o_crc = 0; /* Rightmost possible output pos for CRC+ext */
+ unsigned short valueCRC;
+ uint8_t ext[EXT_SIZE * NLS_MAX_CHARSET_SIZE + 1];
+ uint8_t crc[CRC_LEN];
if (str_max_len <= 0)
return 0;
@@ -133,22 +149,134 @@ static int udf_name_from_CS0(uint8_t *str_o, int str_max_len,
cmp_id = ocu[0];
if (cmp_id != 8 && cmp_id != 16) {
memset(str_o, 0, str_max_len);
- pr_err("unknown compression code (%d) stri=%s\n", cmp_id, ocu);
+ pr_err("unknown compression code (%d)\n", cmp_id);
return -EINVAL;
}
+ u_ch = cmp_id >> 3;
+
+ ocu++;
+ ocu_len--;
+
+ if (translate) {
+ /* Look for extension */
+ for (i = (ocu_len & ~(u_ch - 1)) - u_ch, ext_i_len = 0;
+ (i >= 0) && (ext_i_len < EXT_SIZE);
+ i -= u_ch, ext_i_len++) {
+
+ c = ocu[i];
+ if (u_ch > 1)
+ c = (c << 8) | ocu[i + 1];
+
+ if (c == EXT_MARK) {
+ if (ext_i_len)
+ i_ext = i;
+ break;
+ }
+ }
+ if (i_ext >= 0) {
+ /* Convert extension */
+ ext_max_len = min_t(int, sizeof(ext), str_max_len);
+ ext[ext_o_len++] = EXT_MARK;
+ illChar = 0;
+ for (i = i_ext + u_ch; i < ocu_len;) {
+
+ c = ocu[i++];
+ if (u_ch > 1)
+ c = (c << 8) | ocu[i++];
+
+ if (c == '/' || c == 0) {
+ if (illChar)
+ continue;
+ illChar = 1;
+ needsCRC = 1;
+ c = ILLEGAL_CHAR_MARK;
+ } else {
+ illChar = 0;
+ }
+
+ len = conv_f(c, &ext[ext_o_len],
+ ext_max_len - ext_o_len);
+ /* Valid character? */
+ if (len >= 0) {
+ ext_o_len += len;
+ } else {
+ ext[ext_o_len++] = '?';
+ needsCRC = 1;
+ }
+ if ((ext_o_len + CRC_LEN) < str_max_len)
+ ext_crc_len = ext_o_len;
+ }
+ }
+ }
+
+ illChar = 0;
+ for (i = 0; i < ocu_len;) {
+
+ if (str_o_len >= str_max_len) {
+ needsCRC = 1;
+ break;
+ }
+
+ if (translate && (i == i_ext)) {
+ if (str_o_len > (str_max_len - ext_o_len))
+ needsCRC = 1;
+ break;
+ }
- for (i = 1; (i < ocu_len) && (str_o_len < str_max_len);) {
/* Expand OSTA compressed Unicode to Unicode */
- uint32_t c = ocu[i++];
- if (cmp_id == 16)
+ c = ocu[i++];
+ if (u_ch > 1)
c = (c << 8) | ocu[i++];
+ if (translate) {
+ if ((c == '.') && (firstDots >= 0))
+ firstDots++;
+ else
+ firstDots = -1;
+
+ if (c == '/' || c == 0) {
+ if (illChar)
+ continue;
+ illChar = 1;
+ needsCRC = 1;
+ c = ILLEGAL_CHAR_MARK;
+ } else {
+ illChar = 0;
+ }
+ }
+
len = conv_f(c, &str_o[str_o_len], str_max_len - str_o_len);
/* Valid character? */
- if (len >= 0)
+ if (len >= 0) {
str_o_len += len;
- else
+ } else {
str_o[str_o_len++] = '?';
+ needsCRC = 1;
+ }
+ if (str_o_len <= (str_max_len - ext_o_len - CRC_LEN))
+ o_crc = str_o_len;
+ }
+
+ if (translate) {
+ if ((firstDots == 1) || (firstDots == 2))
+ needsCRC = 1;
+ if (needsCRC) {
+ str_o_len = o_crc;
+ valueCRC = crc_itu_t(0, ocu, ocu_len);
+ crc[0] = CRC_MARK;
+ crc[1] = hex_asc_upper_hi(valueCRC >> 8);
+ crc[2] = hex_asc_upper_lo(valueCRC >> 8);
+ crc[3] = hex_asc_upper_hi(valueCRC);
+ crc[4] = hex_asc_upper_lo(valueCRC);
+ len = min_t(int, CRC_LEN, str_max_len - str_o_len);
+ memcpy(&str_o[str_o_len], crc, len);
+ str_o_len += len;
+ ext_o_len = ext_crc_len;
+ }
+ if (ext_o_len > 0) {
+ memcpy(&str_o[str_o_len], ext, ext_o_len);
+ str_o_len += ext_o_len;
+ }
}
return str_o_len;
@@ -202,13 +330,12 @@ try_again:
int udf_CS0toUTF8(uint8_t *utf_o, int o_len, const uint8_t *ocu_i, int i_len)
{
return udf_name_from_CS0(utf_o, o_len, ocu_i, i_len,
- udf_uni2char_utf8);
+ udf_uni2char_utf8, 0);
}
int udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen,
uint8_t *dname, int dlen)
{
- uint8_t *filename;
int (*conv_f)(wchar_t, unsigned char *, int);
int ret;
@@ -218,10 +345,6 @@ int udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen,
if (dlen <= 0)
return 0;
- filename = kmalloc(dlen, GFP_NOFS);
- if (!filename)
- return -ENOMEM;
-
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
conv_f = udf_uni2char_utf8;
} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
@@ -229,18 +352,10 @@ int udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen,
} else
BUG();
- ret = udf_name_from_CS0(filename, dlen, sname, slen, conv_f);
- if (ret < 0) {
- udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
- goto out2;
- }
-
- ret = udf_translate_to_linux(dname, dlen, filename, dlen, sname, slen);
+ ret = udf_name_from_CS0(dname, dlen, sname, slen, conv_f, 1);
/* Zero length filename isn't valid... */
if (ret == 0)
ret = -EINVAL;
-out2:
- kfree(filename);
return ret;
}
@@ -259,96 +374,3 @@ int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen,
return udf_name_to_CS0(dname, dlen, sname, slen, conv_f);
}
-#define ILLEGAL_CHAR_MARK '_'
-#define EXT_MARK '.'
-#define CRC_MARK '#'
-#define EXT_SIZE 5
-/* Number of chars we need to store generated CRC to make filename unique */
-#define CRC_LEN 5
-
-static int udf_translate_to_linux(uint8_t *newName, int newLen,
- const uint8_t *udfName, int udfLen,
- const uint8_t *fidName, int fidNameLen)
-{
- int index, newIndex = 0, needsCRC = 0;
- int extIndex = 0, newExtIndex = 0, hasExt = 0;
- unsigned short valueCRC;
- uint8_t curr;
-
- if (udfName[0] == '.' &&
- (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) {
- needsCRC = 1;
- newIndex = udfLen;
- memcpy(newName, udfName, udfLen);
- } else {
- for (index = 0; index < udfLen; index++) {
- curr = udfName[index];
- if (curr == '/' || curr == 0) {
- needsCRC = 1;
- curr = ILLEGAL_CHAR_MARK;
- while (index + 1 < udfLen &&
- (udfName[index + 1] == '/' ||
- udfName[index + 1] == 0))
- index++;
- }
- if (curr == EXT_MARK &&
- (udfLen - index - 1) <= EXT_SIZE) {
- if (udfLen == index + 1)
- hasExt = 0;
- else {
- hasExt = 1;
- extIndex = index;
- newExtIndex = newIndex;
- }
- }
- if (newIndex < newLen)
- newName[newIndex++] = curr;
- else
- needsCRC = 1;
- }
- }
- if (needsCRC) {
- uint8_t ext[EXT_SIZE];
- int localExtIndex = 0;
-
- if (hasExt) {
- int maxFilenameLen;
- for (index = 0;
- index < EXT_SIZE && extIndex + index + 1 < udfLen;
- index++) {
- curr = udfName[extIndex + index + 1];
-
- if (curr == '/' || curr == 0) {
- needsCRC = 1;
- curr = ILLEGAL_CHAR_MARK;
- while (extIndex + index + 2 < udfLen &&
- (index + 1 < EXT_SIZE &&
- (udfName[extIndex + index + 2] == '/' ||
- udfName[extIndex + index + 2] == 0)))
- index++;
- }
- ext[localExtIndex++] = curr;
- }
- maxFilenameLen = newLen - CRC_LEN - localExtIndex;
- if (newIndex > maxFilenameLen)
- newIndex = maxFilenameLen;
- else
- newIndex = newExtIndex;
- } else if (newIndex > newLen - CRC_LEN)
- newIndex = newLen - CRC_LEN;
- newName[newIndex++] = CRC_MARK;
- valueCRC = crc_itu_t(0, fidName, fidNameLen);
- newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8);
- newName[newIndex++] = hex_asc_upper_lo(valueCRC >> 8);
- newName[newIndex++] = hex_asc_upper_hi(valueCRC);
- newName[newIndex++] = hex_asc_upper_lo(valueCRC);
-
- if (hasExt) {
- newName[newIndex++] = EXT_MARK;
- for (index = 0; index < localExtIndex; index++)
- newName[newIndex++] = ext[index];
- }
- }
-
- return newIndex;
-}
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web