1*638ed4d6Schristos /* $NetBSD: ntfs.c,v 1.3 2021/12/02 14:26:12 christos Exp $ */
2b985414bSchristos
3b985414bSchristos /*-
4b985414bSchristos * Copyright (c) 2017 The NetBSD Foundation, Inc.
5b985414bSchristos * Copyright (c) 2016 The DragonFly Project
6b985414bSchristos * Copyright (c) 2005 Takanori Watanabe
7b985414bSchristos * Copyright (c) 2014 The FreeBSD Foundation
8b985414bSchristos * All rights reserved.
9b985414bSchristos *
10b985414bSchristos * This code is derived from software contributed to The NetBSD Foundation
11b985414bSchristos * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>.
12b985414bSchristos *
13b985414bSchristos * This software was developed by Edward Tomasz Napierala under sponsorship
14b985414bSchristos * from the FreeBSD Foundation.
15b985414bSchristos *
16b985414bSchristos * Redistribution and use in source and binary forms, with or without
17b985414bSchristos * modification, are permitted provided that the following conditions
18b985414bSchristos * are met:
19b985414bSchristos * 1. Redistributions of source code must retain the above copyright
20b985414bSchristos * notice, this list of conditions and the following disclaimer.
21b985414bSchristos * 2. Redistributions in binary form must reproduce the above copyright
22b985414bSchristos * notice, this list of conditions and the following disclaimer in the
23b985414bSchristos * documentation and/or other materials provided with the distribution.
24b985414bSchristos *
25b985414bSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26b985414bSchristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27b985414bSchristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28b985414bSchristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29b985414bSchristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30b985414bSchristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31b985414bSchristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32b985414bSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33b985414bSchristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34b985414bSchristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35b985414bSchristos * SUCH DAMAGE.
36b985414bSchristos */
37b985414bSchristos #include <sys/cdefs.h>
38*638ed4d6Schristos __RCSID("$NetBSD: ntfs.c,v 1.3 2021/12/02 14:26:12 christos Exp $");
39b985414bSchristos
40bdaaf639Stkusumi #include <err.h>
41bdaaf639Stkusumi #include <iconv.h>
42*638ed4d6Schristos #include <langinfo.h>
43b985414bSchristos #include <stdint.h>
44b985414bSchristos #include <stdio.h>
45b985414bSchristos #include <stdlib.h>
46b985414bSchristos #include <string.h>
47b985414bSchristos
48b985414bSchristos #include "fstyp.h"
49b985414bSchristos
50b985414bSchristos #define NTFS_A_VOLUMENAME 0x60
51b985414bSchristos #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946))
52b985414bSchristos #define NTFS_VOLUMEINO 3
53b985414bSchristos
54b985414bSchristos struct ntfs_attr {
55b985414bSchristos uint32_t a_type;
56b985414bSchristos uint32_t reclen;
57b985414bSchristos uint8_t a_flag;
58b985414bSchristos uint8_t a_namelen;
59b985414bSchristos uint8_t a_nameoff;
60b985414bSchristos uint8_t reserved1;
61b985414bSchristos uint8_t a_compression;
62b985414bSchristos uint8_t reserved2;
63b985414bSchristos uint16_t a_index;
64b985414bSchristos uint16_t a_datalen;
65b985414bSchristos uint16_t reserved3;
66b985414bSchristos uint16_t a_dataoff;
67b985414bSchristos uint16_t a_indexed;
68b985414bSchristos } __packed;
69b985414bSchristos
70b985414bSchristos struct ntfs_filerec {
71b985414bSchristos uint32_t fr_hdrmagic;
72b985414bSchristos uint16_t fr_hdrfoff;
73b985414bSchristos uint16_t fr_hdrfnum;
74b985414bSchristos uint8_t reserved[8];
75b985414bSchristos uint16_t fr_seqnum;
76b985414bSchristos uint16_t fr_nlink;
77b985414bSchristos uint16_t fr_attroff;
78b985414bSchristos uint16_t fr_flags;
79b985414bSchristos uint32_t fr_size;
80b985414bSchristos uint32_t fr_allocated;
81b985414bSchristos uint64_t fr_mainrec;
82b985414bSchristos uint16_t fr_attrnum;
83b985414bSchristos } __packed;
84b985414bSchristos
85b985414bSchristos struct ntfs_bootfile {
86b985414bSchristos uint8_t reserved1[3];
87b985414bSchristos uint8_t bf_sysid[8];
88b985414bSchristos uint16_t bf_bps;
89b985414bSchristos uint8_t bf_spc;
90b985414bSchristos uint8_t reserved2[7];
91b985414bSchristos uint8_t bf_media;
92b985414bSchristos uint8_t reserved3[2];
93b985414bSchristos uint16_t bf_spt;
94b985414bSchristos uint16_t bf_heads;
95b985414bSchristos uint8_t reserver4[12];
96b985414bSchristos uint64_t bf_spv;
97b985414bSchristos uint64_t bf_mftcn;
98b985414bSchristos uint64_t bf_mftmirrcn;
99b985414bSchristos int8_t bf_mftrecsz;
100b985414bSchristos uint32_t bf_ibsz;
101b985414bSchristos uint32_t bf_volsn;
102b985414bSchristos } __packed;
103b985414bSchristos
104bdaaf639Stkusumi static void
convert_label(const void * label,size_t labellen,char * label_out,size_t label_sz)105bdaaf639Stkusumi convert_label(const void *label /* LE */, size_t labellen, char *label_out,
106bdaaf639Stkusumi size_t label_sz)
107bdaaf639Stkusumi {
108bdaaf639Stkusumi char *label_out_orig;
109bdaaf639Stkusumi iconv_t cd;
110bdaaf639Stkusumi size_t rc;
111bdaaf639Stkusumi
112*638ed4d6Schristos cd = iconv_open(nl_langinfo(CODESET), NTFS_ENC);
113bdaaf639Stkusumi if (cd == (iconv_t)-1) {
114bdaaf639Stkusumi warn("ntfs: Could not open iconv");
115bdaaf639Stkusumi return;
116bdaaf639Stkusumi }
117bdaaf639Stkusumi
118bdaaf639Stkusumi label_out_orig = label_out;
119bdaaf639Stkusumi
120bdaaf639Stkusumi rc = iconv(cd, __UNCONST(&label), &labellen, &label_out,
121bdaaf639Stkusumi &label_sz);
122bdaaf639Stkusumi if (rc == (size_t)-1) {
123bdaaf639Stkusumi warn("ntfs: iconv()");
124bdaaf639Stkusumi *label_out_orig = '\0';
125bdaaf639Stkusumi } else {
126bdaaf639Stkusumi /* NUL-terminate result (iconv advances label_out). */
127bdaaf639Stkusumi if (label_sz == 0)
128bdaaf639Stkusumi label_out--;
129bdaaf639Stkusumi *label_out = '\0';
130bdaaf639Stkusumi }
131bdaaf639Stkusumi
132bdaaf639Stkusumi iconv_close(cd);
133bdaaf639Stkusumi }
134bdaaf639Stkusumi
135b985414bSchristos int
fstyp_ntfs(FILE * fp,char * label,size_t size)136b985414bSchristos fstyp_ntfs(FILE *fp, char *label, size_t size)
137b985414bSchristos {
138b985414bSchristos struct ntfs_bootfile *bf;
139b985414bSchristos struct ntfs_filerec *fr;
140b985414bSchristos struct ntfs_attr *atr;
141b985414bSchristos off_t voloff;
142b985414bSchristos char *filerecp, *ap;
143b985414bSchristos int8_t mftrecsz;
144bdaaf639Stkusumi size_t recsize;
145b985414bSchristos
146b985414bSchristos filerecp = NULL;
147b985414bSchristos
148b985414bSchristos bf = read_buf(fp, 0, 512);
149b985414bSchristos if (bf == NULL || strncmp((char*)bf->bf_sysid, "NTFS ", 8) != 0)
150b985414bSchristos goto fail;
151bdaaf639Stkusumi if (!show_label)
152bdaaf639Stkusumi goto ok;
153b985414bSchristos
154b985414bSchristos mftrecsz = bf->bf_mftrecsz;
155b985414bSchristos recsize = mftrecsz > 0 ? (size_t)(mftrecsz * bf->bf_bps * bf->bf_spc)
156b985414bSchristos : (size_t)(1 << -mftrecsz);
157b985414bSchristos
158bdaaf639Stkusumi voloff = (off_t)((off_t)bf->bf_mftcn * bf->bf_spc * bf->bf_bps +
159bdaaf639Stkusumi (off_t)recsize * NTFS_VOLUMEINO);
160b985414bSchristos
161b985414bSchristos filerecp = read_buf(fp, voloff, recsize);
162b985414bSchristos if (filerecp == NULL)
163b985414bSchristos goto fail;
164b985414bSchristos fr = (struct ntfs_filerec *)filerecp;
165b985414bSchristos
166b985414bSchristos if (fr->fr_hdrmagic != NTFS_FILEMAGIC)
167b985414bSchristos goto fail;
168b985414bSchristos
169b985414bSchristos for (ap = filerecp + fr->fr_attroff;
170b985414bSchristos atr = (struct ntfs_attr *)ap, (int)atr->a_type != -1;
171b985414bSchristos ap += atr->reclen) {
172bdaaf639Stkusumi if (atr->a_type != NTFS_A_VOLUMENAME)
173bdaaf639Stkusumi continue;
174bdaaf639Stkusumi
175bdaaf639Stkusumi convert_label(ap + atr->a_dataoff,
176bdaaf639Stkusumi atr->a_datalen, label, size);
177b985414bSchristos break;
178b985414bSchristos }
179b985414bSchristos
180bdaaf639Stkusumi ok:
181b985414bSchristos free(bf);
182b985414bSchristos free(filerecp);
183b985414bSchristos
184b985414bSchristos return 0;
185b985414bSchristos
186b985414bSchristos fail:
187b985414bSchristos free(bf);
188b985414bSchristos free(filerecp);
189b985414bSchristos
190b985414bSchristos return 1;
191b985414bSchristos }
192