1149492Stakawata/*-
2149492Stakawata * Copyright (c) 2005 Takanori Watanabe
3149492Stakawata * All rights reserved.
4149492Stakawata *
5149492Stakawata * Redistribution and use in source and binary forms, with or without
6149492Stakawata * modification, are permitted provided that the following conditions
7149492Stakawata * are met:
8149492Stakawata * 1. Redistributions of source code must retain the above copyright
9149492Stakawata *    notice, this list of conditions and the following disclaimer.
10149492Stakawata * 2. Redistributions in binary form must reproduce the above copyright
11149492Stakawata *    notice, this list of conditions and the following disclaimer in the
12149492Stakawata *    documentation and/or other materials provided with the distribution.
13149492Stakawata *
14149492Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15149492Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16149492Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17149492Stakawata * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18149492Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19149492Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20149492Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21149492Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22149492Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23149492Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24149492Stakawata * SUCH DAMAGE.
25149492Stakawata */
26149492Stakawata
27149492Stakawata#include <sys/cdefs.h>
28149492Stakawata__FBSDID("$FreeBSD$");
29149492Stakawata
30149492Stakawata#include <sys/param.h>
31149492Stakawata#include <sys/systm.h>
32149492Stakawata#include <sys/kernel.h>
33149492Stakawata#include <sys/malloc.h>
34149492Stakawata
35149492Stakawata#include <geom/geom.h>
36149492Stakawata#include <geom/label/g_label.h>
37149492Stakawata
38247662Sattilio#define	NTFS_A_VOLUMENAME	0x60
39247662Sattilio#define	NTFS_FILEMAGIC		((uint32_t)(0x454C4946))
40247662Sattilio#define	NTFS_VOLUMEINO		3
41247662Sattilio
42149492Stakawata#define G_LABEL_NTFS_DIR	"ntfs"
43149492Stakawata
44247662Sattiliostruct ntfs_attr {
45247662Sattilio	uint32_t	a_type;
46247662Sattilio	uint32_t	reclen;
47247662Sattilio	uint8_t		a_flag;
48247662Sattilio	uint8_t		a_namelen;
49247662Sattilio	uint8_t		a_nameoff;
50247662Sattilio	uint8_t		reserved1;
51247662Sattilio	uint8_t		a_compression;
52247662Sattilio	uint8_t		reserved2;
53247662Sattilio	uint16_t	a_index;
54247662Sattilio	uint16_t	a_datalen;
55247662Sattilio	uint16_t	reserved3;
56247662Sattilio	uint16_t	a_dataoff;
57247662Sattilio	uint16_t	a_indexed;
58247837Sdumbbell} __packed;
59149492Stakawata
60247662Sattiliostruct ntfs_filerec {
61247662Sattilio	uint32_t	fr_hdrmagic;
62247662Sattilio	uint16_t	fr_hdrfoff;
63247662Sattilio	uint16_t	fr_hdrfnum;
64247662Sattilio	uint8_t		reserved[8];
65247662Sattilio	uint16_t	fr_seqnum;
66247662Sattilio	uint16_t	fr_nlink;
67247662Sattilio	uint16_t	fr_attroff;
68247662Sattilio	uint16_t	fr_flags;
69247662Sattilio	uint32_t	fr_size;
70247662Sattilio	uint32_t	fr_allocated;
71247662Sattilio	uint64_t	fr_mainrec;
72247662Sattilio	uint16_t	fr_attrnum;
73247837Sdumbbell} __packed;
74247662Sattilio
75247662Sattiliostruct ntfs_bootfile {
76247662Sattilio	uint8_t		reserved1[3];
77247662Sattilio	uint8_t		bf_sysid[8];
78247662Sattilio	uint16_t	bf_bps;
79247662Sattilio	uint8_t		bf_spc;
80247662Sattilio	uint8_t		reserved2[7];
81247662Sattilio	uint8_t		bf_media;
82247662Sattilio	uint8_t		reserved3[2];
83247662Sattilio	uint16_t	bf_spt;
84247662Sattilio	uint16_t	bf_heads;
85247662Sattilio	uint8_t		reserver4[12];
86247662Sattilio	uint64_t	bf_spv;
87247662Sattilio	uint64_t	bf_mftcn;
88247662Sattilio	uint64_t	bf_mftmirrcn;
89250264Sstas	int8_t		bf_mftrecsz;
90247662Sattilio	uint32_t	bf_ibsz;
91247662Sattilio	uint32_t	bf_volsn;
92247837Sdumbbell} __packed;
93247662Sattilio
94149492Stakawatastatic void
95149492Stakawatag_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
96149492Stakawata{
97149492Stakawata	struct g_provider *pp;
98247662Sattilio	struct ntfs_bootfile *bf;
99247662Sattilio	struct ntfs_filerec *fr;
100247662Sattilio	struct ntfs_attr *atr;
101154513Spjd	off_t voloff;
102154513Spjd	char *filerecp, *ap;
103250264Sstas	int8_t mftrecsz;
104250264Sstas	char vnchar;
105154513Spjd	int recsize, j;
106154513Spjd
107149492Stakawata	g_topology_assert_not();
108154513Spjd
109154513Spjd	label[0] = '\0';
110149492Stakawata	pp = cp->provider;
111154513Spjd	filerecp = NULL;
112154513Spjd
113247662Sattilio	bf = (struct ntfs_bootfile *)g_read_data(cp, 0, pp->sectorsize, NULL);
114154513Spjd	if (bf == NULL || strncmp(bf->bf_sysid, "NTFS    ", 8) != 0)
115154513Spjd		goto done;
116149492Stakawata
117250264Sstas	mftrecsz = bf->bf_mftrecsz;
118149492Stakawata	recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz);
119248058Sdumbbell	if (recsize == 0 || recsize % pp->sectorsize != 0)
120149538Spjd		goto done;
121154513Spjd
122149492Stakawata	voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps +
123154513Spjd	    recsize * NTFS_VOLUMEINO;
124154513Spjd	if (voloff % pp->sectorsize != 0)
125149492Stakawata		goto done;
126149492Stakawata
127152922Spjd	filerecp = g_read_data(cp, voloff, recsize, NULL);
128152913Ssobomax	if (filerecp == NULL)
129152913Ssobomax		goto done;
130247662Sattilio	fr = (struct ntfs_filerec *)filerecp;
131151684Stakawata
132247662Sattilio	if (fr->fr_hdrmagic != NTFS_FILEMAGIC)
133151684Stakawata		goto done;
134151684Stakawata
135154513Spjd	for (ap = filerecp + fr->fr_attroff;
136247662Sattilio	    atr = (struct ntfs_attr *)ap, atr->a_type != -1;
137247662Sattilio	    ap += atr->reclen) {
138247662Sattilio		if (atr->a_type == NTFS_A_VOLUMENAME) {
139247662Sattilio			if(atr->a_datalen >= size *2){
140149492Stakawata				label[0] = 0;
141149492Stakawata				goto done;
142149492Stakawata			}
143149492Stakawata			/*
144149492Stakawata			 *UNICODE to ASCII.
145149492Stakawata			 * Should we need to use iconv(9)?
146149492Stakawata			 */
147247662Sattilio			for (j = 0; j < atr->a_datalen; j++) {
148247662Sattilio				vnchar = *(ap + atr->a_dataoff + j);
149154513Spjd				if (j & 1) {
150149492Stakawata					if (vnchar) {
151149492Stakawata						label[0] = 0;
152149492Stakawata						goto done;
153149492Stakawata					}
154149492Stakawata				} else {
155149492Stakawata					label[j / 2] = vnchar;
156149492Stakawata				}
157149492Stakawata			}
158149492Stakawata			label[j / 2] = 0;
159149492Stakawata			break;
160149492Stakawata		}
161149492Stakawata	}
162149492Stakawatadone:
163149492Stakawata	if (bf != NULL)
164149492Stakawata		g_free(bf);
165149492Stakawata	if (filerecp != NULL)
166149492Stakawata		g_free(filerecp);
167149492Stakawata}
168149492Stakawata
169199875Straszstruct g_label_desc g_label_ntfs = {
170149492Stakawata	.ld_taste = g_label_ntfs_taste,
171199875Strasz	.ld_dir = G_LABEL_NTFS_DIR,
172199875Strasz	.ld_enabled = 1
173149492Stakawata};
174199875Strasz
175199875StraszG_LABEL_INIT(ntfs, g_label_ntfs, "Create device nodes for NTFS volumes");
176