1275680Strasz/*-
2275680Strasz * Copyright (c) 2005 Takanori Watanabe
3275680Strasz * Copyright (c) 2014 The FreeBSD Foundation
4275680Strasz * All rights reserved.
5275680Strasz *
6275680Strasz * This software was developed by Edward Tomasz Napierala under sponsorship
7275680Strasz * from the FreeBSD Foundation.
8275680Strasz *
9275680Strasz * Redistribution and use in source and binary forms, with or without
10275680Strasz * modification, are permitted provided that the following conditions
11275680Strasz * are met:
12275680Strasz * 1. Redistributions of source code must retain the above copyright
13275680Strasz *    notice, this list of conditions and the following disclaimer.
14275680Strasz * 2. Redistributions in binary form must reproduce the above copyright
15275680Strasz *    notice, this list of conditions and the following disclaimer in the
16275680Strasz *    documentation and/or other materials provided with the distribution.
17275680Strasz *
18275680Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19275680Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20275680Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21275680Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22275680Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23275680Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24275680Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25275680Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26275680Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27275680Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28275680Strasz * SUCH DAMAGE.
29275680Strasz */
30275680Strasz
31275680Strasz#include <sys/cdefs.h>
32275680Strasz__FBSDID("$FreeBSD: releng/10.3/usr.sbin/fstyp/ntfs.c 277436 2015-01-20 20:42:55Z trasz $");
33275680Strasz
34275680Strasz#include <stdint.h>
35275680Strasz#include <stdio.h>
36275680Strasz#include <stdlib.h>
37275680Strasz#include <string.h>
38275680Strasz
39275680Strasz#include "fstyp.h"
40275680Strasz
41275680Strasz#define	NTFS_A_VOLUMENAME	0x60
42275680Strasz#define	NTFS_FILEMAGIC		((uint32_t)(0x454C4946))
43275680Strasz#define	NTFS_VOLUMEINO		3
44275680Strasz
45275680Straszstruct ntfs_attr {
46275680Strasz	uint32_t	a_type;
47275680Strasz	uint32_t	reclen;
48275680Strasz	uint8_t		a_flag;
49275680Strasz	uint8_t		a_namelen;
50275680Strasz	uint8_t		a_nameoff;
51275680Strasz	uint8_t		reserved1;
52275680Strasz	uint8_t		a_compression;
53275680Strasz	uint8_t		reserved2;
54275680Strasz	uint16_t	a_index;
55275680Strasz	uint16_t	a_datalen;
56275680Strasz	uint16_t	reserved3;
57275680Strasz	uint16_t	a_dataoff;
58275680Strasz	uint16_t	a_indexed;
59275680Strasz} __packed;
60275680Strasz
61275680Straszstruct ntfs_filerec {
62275680Strasz	uint32_t	fr_hdrmagic;
63275680Strasz	uint16_t	fr_hdrfoff;
64275680Strasz	uint16_t	fr_hdrfnum;
65275680Strasz	uint8_t		reserved[8];
66275680Strasz	uint16_t	fr_seqnum;
67275680Strasz	uint16_t	fr_nlink;
68275680Strasz	uint16_t	fr_attroff;
69275680Strasz	uint16_t	fr_flags;
70275680Strasz	uint32_t	fr_size;
71275680Strasz	uint32_t	fr_allocated;
72275680Strasz	uint64_t	fr_mainrec;
73275680Strasz	uint16_t	fr_attrnum;
74275680Strasz} __packed;
75275680Strasz
76275680Straszstruct ntfs_bootfile {
77275680Strasz	uint8_t		reserved1[3];
78275680Strasz	uint8_t		bf_sysid[8];
79275680Strasz	uint16_t	bf_bps;
80275680Strasz	uint8_t		bf_spc;
81275680Strasz	uint8_t		reserved2[7];
82275680Strasz	uint8_t		bf_media;
83275680Strasz	uint8_t		reserved3[2];
84275680Strasz	uint16_t	bf_spt;
85275680Strasz	uint16_t	bf_heads;
86275680Strasz	uint8_t		reserver4[12];
87275680Strasz	uint64_t	bf_spv;
88275680Strasz	uint64_t	bf_mftcn;
89275680Strasz	uint64_t	bf_mftmirrcn;
90275680Strasz	int8_t		bf_mftrecsz;
91275680Strasz	uint32_t	bf_ibsz;
92275680Strasz	uint32_t	bf_volsn;
93275680Strasz} __packed;
94275680Strasz
95275680Straszint
96275680Straszfstyp_ntfs(FILE *fp, char *label, size_t size)
97275680Strasz{
98275680Strasz	struct ntfs_bootfile *bf;
99275680Strasz	struct ntfs_filerec *fr;
100275680Strasz	struct ntfs_attr *atr;
101275680Strasz	off_t voloff;
102275680Strasz	char *filerecp, *ap;
103275680Strasz	int8_t mftrecsz;
104275680Strasz	char vnchar;
105275680Strasz	int recsize, j;
106275680Strasz
107275680Strasz	filerecp = NULL;
108275680Strasz
109275680Strasz	bf = (struct ntfs_bootfile *)read_buf(fp, 0, 512);
110275680Strasz	if (bf == NULL || strncmp(bf->bf_sysid, "NTFS    ", 8) != 0)
111277436Strasz		goto fail;
112275680Strasz
113275680Strasz	mftrecsz = bf->bf_mftrecsz;
114275680Strasz	recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz);
115275680Strasz
116275680Strasz	voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps +
117275680Strasz	    recsize * NTFS_VOLUMEINO;
118275680Strasz
119275680Strasz	filerecp = read_buf(fp, voloff, recsize);
120275680Strasz	if (filerecp == NULL)
121275680Strasz		goto fail;
122275680Strasz	fr = (struct ntfs_filerec *)filerecp;
123275680Strasz
124275680Strasz	if (fr->fr_hdrmagic != NTFS_FILEMAGIC)
125275680Strasz		goto fail;
126275680Strasz
127275680Strasz	for (ap = filerecp + fr->fr_attroff;
128275680Strasz	    atr = (struct ntfs_attr *)ap, (int)atr->a_type != -1;
129275680Strasz	    ap += atr->reclen) {
130275680Strasz		if (atr->a_type == NTFS_A_VOLUMENAME) {
131275680Strasz			if(atr->a_datalen >= size *2){
132275680Strasz				goto fail;
133275680Strasz			}
134275680Strasz			/*
135275680Strasz			 *UNICODE to ASCII.
136275680Strasz			 * Should we need to use iconv(9)?
137275680Strasz			 */
138275680Strasz			for (j = 0; j < atr->a_datalen; j++) {
139275680Strasz				vnchar = *(ap + atr->a_dataoff + j);
140275680Strasz				if (j & 1) {
141275680Strasz					if (vnchar) {
142275680Strasz						goto fail;
143275680Strasz					}
144275680Strasz				} else {
145275680Strasz					label[j / 2] = vnchar;
146275680Strasz				}
147275680Strasz			}
148275680Strasz			label[j / 2] = 0;
149275680Strasz			break;
150275680Strasz		}
151275680Strasz	}
152275680Strasz
153275680Strasz	free(bf);
154275680Strasz	free(filerecp);
155275680Strasz
156275680Strasz	return (0);
157275680Strasz
158275680Straszfail:
159275680Strasz	free(bf);
160275680Strasz	free(filerecp);
161275680Strasz
162275680Strasz	return (1);
163275680Strasz}
164