aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2019-12-23 02:41:13 +0000
committerConrad Meyer <cem@FreeBSD.org>2019-12-23 02:41:13 +0000
commitec80d2eeddab0c40000c969b62d8281dae27e0c1 (patch)
treefdf249b2e814c8d38b7cc2b721ce8dfab47e3d89 /usr.sbin
parent42e08952bb84aa86dfdcc7b80c95b58e515bdce7 (diff)
downloadsrc-ec80d2eeddab0c40000c969b62d8281dae27e0c1.tar.gz
src-ec80d2eeddab0c40000c969b62d8281dae27e0c1.zip
fstyp(8): Use iconv(3) to convert NTFS vol labels correctly
Rather than hackily extracting only the ASCII subset of UTF-16LE, go ahead and convert the label to the user's locale correctly.
Notes
Notes: svn path=/head/; revision=356032
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/fstyp/fstyp.c2
-rw-r--r--usr.sbin/fstyp/fstyp.h5
-rw-r--r--usr.sbin/fstyp/ntfs.c67
3 files changed, 50 insertions, 24 deletions
diff --git a/usr.sbin/fstyp/fstyp.c b/usr.sbin/fstyp/fstyp.c
index 395e68cf717d..b8ccbd9c0568 100644
--- a/usr.sbin/fstyp/fstyp.c
+++ b/usr.sbin/fstyp/fstyp.c
@@ -67,7 +67,7 @@ static struct {
{ "ext2fs", &fstyp_ext2fs, false, NULL },
{ "geli", &fstyp_geli, true, NULL },
{ "msdosfs", &fstyp_msdosfs, false, NULL },
- { "ntfs", &fstyp_ntfs, false, NULL },
+ { "ntfs", &fstyp_ntfs, false, NTFS_ENC },
{ "ufs", &fstyp_ufs, false, NULL },
#ifdef HAVE_ZFS
{ "zfs", &fstyp_zfs, true, NULL },
diff --git a/usr.sbin/fstyp/fstyp.h b/usr.sbin/fstyp/fstyp.h
index 3b8e80cfe71d..09c0242f6785 100644
--- a/usr.sbin/fstyp/fstyp.h
+++ b/usr.sbin/fstyp/fstyp.h
@@ -38,6 +38,11 @@
/* The spec doesn't seem to permit UTF-16 surrogates; definitely LE. */
#define EXFAT_ENC "UCS-2LE"
+/*
+ * NTFS itself is agnostic to encoding; it just stores 255 u16 wchars. In
+ * practice, UTF-16 seems expected for NTFS. (Maybe also for exFAT.)
+ */
+#define NTFS_ENC "UTF-16LE"
extern bool show_label; /* -l flag */
diff --git a/usr.sbin/fstyp/ntfs.c b/usr.sbin/fstyp/ntfs.c
index 905841045e7d..d7e29c23fe85 100644
--- a/usr.sbin/fstyp/ntfs.c
+++ b/usr.sbin/fstyp/ntfs.c
@@ -31,6 +31,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <err.h>
+#include <iconv.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -92,6 +94,38 @@ struct ntfs_bootfile {
uint32_t bf_volsn;
} __packed;
+static void
+convert_label(const void *label /* LE */, size_t labellen, char *label_out,
+ size_t label_sz)
+{
+ char *label_out_orig;
+ iconv_t cd;
+ size_t rc;
+
+ /* dstname="" means convert to the current locale. */
+ cd = iconv_open("", NTFS_ENC);
+ if (cd == (iconv_t)-1) {
+ warn("ntfs: Could not open iconv");
+ return;
+ }
+
+ label_out_orig = label_out;
+
+ rc = iconv(cd, __DECONST(char **, &label), &labellen, &label_out,
+ &label_sz);
+ if (rc == (size_t)-1) {
+ warn("ntfs: iconv()");
+ *label_out_orig = '\0';
+ } else {
+ /* NUL-terminate result (iconv advances label_out). */
+ if (label_sz == 0)
+ label_out--;
+ *label_out = '\0';
+ }
+
+ iconv_close(cd);
+}
+
int
fstyp_ntfs(FILE *fp, char *label, size_t size)
{
@@ -101,14 +135,15 @@ fstyp_ntfs(FILE *fp, char *label, size_t size)
off_t voloff;
char *filerecp, *ap;
int8_t mftrecsz;
- char vnchar;
- int recsize, j;
+ int recsize;
filerecp = NULL;
bf = (struct ntfs_bootfile *)read_buf(fp, 0, 512);
if (bf == NULL || strncmp(bf->bf_sysid, "NTFS ", 8) != 0)
goto fail;
+ if (!show_label)
+ goto ok;
mftrecsz = bf->bf_mftrecsz;
recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz);
@@ -127,29 +162,15 @@ fstyp_ntfs(FILE *fp, char *label, size_t size)
for (ap = filerecp + fr->fr_attroff;
atr = (struct ntfs_attr *)ap, (int)atr->a_type != -1;
ap += atr->reclen) {
- if (atr->a_type == NTFS_A_VOLUMENAME) {
- if(atr->a_datalen >= size *2){
- goto fail;
- }
- /*
- *UNICODE to ASCII.
- * Should we need to use iconv(9)?
- */
- for (j = 0; j < atr->a_datalen; j++) {
- vnchar = *(ap + atr->a_dataoff + j);
- if (j & 1) {
- if (vnchar) {
- goto fail;
- }
- } else {
- label[j / 2] = vnchar;
- }
- }
- label[j / 2] = 0;
- break;
- }
+ if (atr->a_type != NTFS_A_VOLUMENAME)
+ continue;
+
+ convert_label(ap + atr->a_dataoff,
+ atr->a_datalen, label, size);
+ break;
}
+ok:
free(bf);
free(filerecp);