summaryrefslogtreecommitdiffstats
path: root/dosfstools/src/lfn.c
diff options
context:
space:
mode:
Diffstat (limited to 'dosfstools/src/lfn.c')
-rw-r--r--dosfstools/src/lfn.c62
1 files changed, 44 insertions, 18 deletions
diff --git a/dosfstools/src/lfn.c b/dosfstools/src/lfn.c
index 736491cb0..2601172ee 100644
--- a/dosfstools/src/lfn.c
+++ b/dosfstools/src/lfn.c
@@ -1,6 +1,7 @@
/* lfn.c - Functions for handling VFAT long filenames
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,11 +16,12 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- On Debian systems, the complete text of the GNU General Public License
+ The complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-3 file.
*/
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
@@ -27,19 +29,19 @@
#include "common.h"
#include "io.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
#include "lfn.h"
#include "file.h"
typedef struct {
- __u8 id; /* sequence number for slot */
- __u8 name0_4[10]; /* first 5 characters in name */
- __u8 attr; /* attribute byte */
- __u8 reserved; /* always 0 */
- __u8 alias_checksum; /* checksum for 8.3 alias */
- __u8 name5_10[12]; /* 6 more characters in name */
- __u16 start; /* starting cluster number, 0 in long slots */
- __u8 name11_12[4]; /* last 2 characters in name */
+ uint8_t id; /* sequence number for slot */
+ uint8_t name0_4[10]; /* first 5 characters in name */
+ uint8_t attr; /* attribute byte */
+ uint8_t reserved; /* always 0 */
+ uint8_t alias_checksum; /* checksum for 8.3 alias */
+ uint8_t name5_10[12]; /* 6 more characters in name */
+ uint16_t start; /* starting cluster number, 0 in long slots */
+ uint8_t name11_12[4]; /* last 2 characters in name */
} LFN_ENT;
#define LFN_ID_START 0x40
@@ -85,6 +87,22 @@ static unsigned char fat_uni2esc[64] = {
(cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2), \
lfn_parts*CHARS_PER_LFN, 0 ))
+#define BYTES_TO_WCHAR(cl,ch) ((wchar_t)((unsigned)(cl) + ((unsigned)(ch) << 8)))
+static size_t mbslen(wchar_t x)
+{
+ wchar_t wstr[] = { x, 0 };
+ return wcstombs(NULL, wstr, 0);
+}
+
+static size_t wctombs(char *dest, wchar_t x)
+{
+ wchar_t wstr[] = { x, 0 };
+ size_t size = wcstombs(NULL, wstr, 0);
+ if (size != (size_t) - 1)
+ size = wcstombs(dest, wstr, size + 1);
+ return size;
+}
+
/* This function converts an unicode string to a normal ASCII string, assuming
* ISO-8859-1 charset. Characters not in 8859-1 are converted to the same
* escape notation as used by the kernel, i.e. the uuencode-like ":xxx" */
@@ -93,10 +111,13 @@ static char *cnv_unicode(const unsigned char *uni, int maxlen, int use_q)
const unsigned char *up;
unsigned char *out, *cp;
int len, val;
+ size_t x;
for (len = 0, up = uni; (up - uni) / 2 < maxlen && (up[0] || up[1]);
up += 2) {
- if (UNICODE_CONVERTABLE(up[0], up[1]))
+ if ((x = mbslen(BYTES_TO_WCHAR(up[0], up[1]))) != (size_t) - 1)
+ len += x;
+ else if (UNICODE_CONVERTABLE(up[0], up[1]))
++len;
else
len += 4;
@@ -104,7 +125,10 @@ static char *cnv_unicode(const unsigned char *uni, int maxlen, int use_q)
cp = out = use_q ? qalloc(&mem_queue, len + 1) : alloc(len + 1);
for (up = uni; (up - uni) / 2 < maxlen && (up[0] || up[1]); up += 2) {
- if (UNICODE_CONVERTABLE(up[0], up[1]))
+ if ((x =
+ wctombs((char *)cp, BYTES_TO_WCHAR(up[0], up[1]))) != (size_t) - 1)
+ cp += x;
+ else if (UNICODE_CONVERTABLE(up[0], up[1]))
*cp++ = up[0];
else {
/* here the same escape notation is used as in the Linux kernel */
@@ -150,7 +174,7 @@ static void clear_lfn_slots(int start, int end)
void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name)
{
int i;
- __u8 sum;
+ uint8_t sum;
for (sum = 0, i = 0; i < 11; i++)
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + short_name[i];
@@ -366,7 +390,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
sizeof(lfn->reserved), &lfn->reserved);
}
}
- if (lfn->start != CT_LE_W(0)) {
+ if (lfn->start != htole16(0)) {
printf("Start cluster field in VFAT long filename slot is not 0 "
"(but 0x%04x).\n", lfn->start);
if (interactive)
@@ -374,7 +398,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
else
printf("Auto-setting to 0.\n");
if (!interactive || get_key("12", "?") == '1') {
- lfn->start = CT_LE_W(0);
+ lfn->start = htole16(0);
fs_write(dir_offset + offsetof(LFN_ENT, start),
sizeof(lfn->start), &lfn->start);
}
@@ -386,7 +410,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
{
char *lfn;
- __u8 sum;
+ uint8_t sum;
int i;
*lfn_offset = 0;
@@ -430,7 +454,7 @@ char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
return NULL;
case '3':
for (i = 0; i < lfn_parts; ++i) {
- __u8 id = (lfn_parts - i) | (i == 0 ? LFN_ID_START : 0);
+ uint8_t id = (lfn_parts - i) | (i == 0 ? LFN_ID_START : 0);
fs_write(lfn_offsets[i] + offsetof(LFN_ENT, id),
sizeof(id), &id);
}
@@ -440,8 +464,10 @@ char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
}
}
- for (sum = 0, i = 0; i < 11; i++)
+ for (sum = 0, i = 0; i < 8; i++)
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->name[i];
+ for (i = 0; i < 3; i++)
+ sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->ext[i];
if (sum != lfn_checksum) {
/* checksum doesn't match, long name doesn't apply to this alias */
/* Causes: 1) alias renamed */