xref: /netbsd-src/usr.sbin/fstyp/ntfs.c (revision 638ed4d6a7cb780c509d5b1726f4c2c6ecff7721)
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