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