diff options
author | njl <njl@FreeBSD.org> | 2005-04-16 01:49:50 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2005-04-16 01:49:50 +0000 |
commit | 9de8e0daf94d3598eba43ca102b8629938c52342 (patch) | |
tree | 5bc43493562b53a95d88c7bedf8826ce135a6042 /sys/fs | |
parent | 1dcaba98da1080966fee63c904aec67d3b386ace (diff) | |
download | FreeBSD-src-9de8e0daf94d3598eba43ca102b8629938c52342.zip FreeBSD-src-9de8e0daf94d3598eba43ca102b8629938c52342.tar.gz |
Fix mbnambuf support for multi-byte characters. If a substring is larger
than WIN_CHARS bytes, we shift the suffix (previous substrings) upwards
by the amount this substring exceeds its WIN_CHARS slot. Profiling shows
this change is indistinguishable from the previous code at 95% confidence.
This bug would result in attempts to access or create files or directories
with multi-byte characters returning an error but no data loss.
Reported and tested by: avatar
MFC after: 3 days
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/msdosfs/msdosfs_conv.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c index 1dff0d8..8010457 100644 --- a/sys/fs/msdosfs/msdosfs_conv.c +++ b/sys/fs/msdosfs/msdosfs_conv.c @@ -103,7 +103,7 @@ static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount static char *nambuf_ptr; static size_t nambuf_len; -static int nambuf_max_id; +static int nambuf_last_id; /* * Convert the unix version of time to dos's idea of time to be used in @@ -1205,33 +1205,43 @@ mbnambuf_init(void) nambuf_ptr[MAXNAMLEN] = '\0'; } nambuf_len = 0; - nambuf_max_id = -1; + nambuf_last_id = -1; } /* - * Fill out our concatenation buffer with the given substring, at the - * offset specified by its id. For the last substring (i.e., the one with - * the maximum id), use it to calculate the length of the entire string. - * Since this function is usually called with ids in descending order, this - * reduces the number of times we need to call strlen() since we know that - * all previous substrings are exactly WIN_CHARS in length. + * Fill out our concatenation buffer with the given substring, at the offset + * specified by its id. Since this function must be called with ids in + * descending order, we take advantage of the fact that ASCII substrings are + * exactly WIN_CHARS in length. For non-ASCII substrings, we shift all + * previous (i.e. higher id) substrings upwards to make room for this one. + * This only penalizes portions of substrings that contain more than + * WIN_CHARS bytes when they are first encountered. */ void mbnambuf_write(char *name, int id) { size_t count; + char *slot; - count = WIN_CHARS; - if (id > nambuf_max_id) { - count = strlen(name); - nambuf_len = id * WIN_CHARS + count; - if (nambuf_len > MAXNAMLEN) { - printf("msdosfs: file name %zu too long\n", nambuf_len); - return; - } - nambuf_max_id = id; + KASSERT(nambuf_len == 0 || id == nambuf_last_id - 1, + ("non-decreasing id, id %d last id %d", id, nambuf_last_id)); + + /* Store this substring in a WIN_CHAR-aligned slot. */ + slot = nambuf_ptr + (id * WIN_CHARS); + count = strlen(name); + if (nambuf_len + count > MAXNAMLEN) { + printf("msdosfs: file name %zu too long\n", nambuf_len + count); + return; } - memcpy(nambuf_ptr + (id * WIN_CHARS), name, count); + + /* Shift suffix upwards by the amount length exceeds WIN_CHARS. */ + if (count > WIN_CHARS && nambuf_len != 0) + bcopy(slot + WIN_CHARS, slot + count, nambuf_len); + + /* Copy in the substring to its slot and update length so far. */ + bcopy(name, slot, count); + nambuf_len += count; + nambuf_last_id = id; } /* @@ -1249,7 +1259,7 @@ mbnambuf_flush(struct dirent *dp) mbnambuf_init(); return (NULL); } - memcpy(dp->d_name, nambuf_ptr, nambuf_len); + bcopy(nambuf_ptr, dp->d_name, nambuf_len); dp->d_name[nambuf_len] = '\0'; dp->d_namlen = nambuf_len; |