summaryrefslogtreecommitdiffstats
path: root/sys/fs/msdosfs/msdosfs_conv.c
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2005-04-16 01:49:50 +0000
committernjl <njl@FreeBSD.org>2005-04-16 01:49:50 +0000
commit9de8e0daf94d3598eba43ca102b8629938c52342 (patch)
tree5bc43493562b53a95d88c7bedf8826ce135a6042 /sys/fs/msdosfs/msdosfs_conv.c
parent1dcaba98da1080966fee63c904aec67d3b386ace (diff)
downloadFreeBSD-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/msdosfs/msdosfs_conv.c')
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c48
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;
OpenPOWER on IntegriCloud