• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/busybox/util-linux/volume_id/
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 *	This library is free software; you can redistribute it and/or
7 *	modify it under the terms of the GNU Lesser General Public
8 *	License as published by the Free Software Foundation; either
9 *	version 2.1 of the License, or (at your option) any later version.
10 *
11 *	This library is distributed in the hope that it will be useful,
12 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 *	Lesser General Public License for more details.
15 *
16 *	You should have received a copy of the GNU Lesser General Public
17 *	License along with this library; if not, write to the Free Software
18 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "volume_id_internal.h"
22
23struct ntfs_super_block {
24	uint8_t		jump[3];
25	uint8_t		oem_id[8];
26	uint16_t	bytes_per_sector;
27	uint8_t		sectors_per_cluster;
28	uint16_t	reserved_sectors;
29	uint8_t		fats;
30	uint16_t	root_entries;
31	uint16_t	sectors;
32	uint8_t		media_type;
33	uint16_t	sectors_per_fat;
34	uint16_t	sectors_per_track;
35	uint16_t	heads;
36	uint32_t	hidden_sectors;
37	uint32_t	large_sectors;
38	uint16_t	unused[2];
39	uint64_t	number_of_sectors;
40	uint64_t	mft_cluster_location;
41	uint64_t	mft_mirror_cluster_location;
42	int8_t		cluster_per_mft_record;
43	uint8_t		reserved1[3];
44	int8_t		cluster_per_index_record;
45	uint8_t		reserved2[3];
46	uint8_t		volume_serial[8];
47	uint16_t	checksum;
48} PACKED;
49
50struct master_file_table_record {
51	uint8_t		magic[4];
52	uint16_t	usa_ofs;
53	uint16_t	usa_count;
54	uint64_t	lsn;
55	uint16_t	sequence_number;
56	uint16_t	link_count;
57	uint16_t	attrs_offset;
58	uint16_t	flags;
59	uint32_t	bytes_in_use;
60	uint32_t	bytes_allocated;
61} PACKED;
62
63struct file_attribute {
64	uint32_t	type;
65	uint32_t	len;
66	uint8_t		non_resident;
67	uint8_t		name_len;
68	uint16_t	name_offset;
69	uint16_t	flags;
70	uint16_t	instance;
71	uint32_t	value_len;
72	uint16_t	value_offset;
73} PACKED;
74
75struct volume_info {
76	uint64_t	reserved;
77	uint8_t		major_ver;
78	uint8_t		minor_ver;
79} PACKED;
80
81#define MFT_RECORD_VOLUME			3
82#define MFT_RECORD_ATTR_VOLUME_NAME		0x60
83#define MFT_RECORD_ATTR_VOLUME_INFO		0x70
84#define MFT_RECORD_ATTR_OBJECT_ID		0x40
85#define MFT_RECORD_ATTR_END			0xffffffffu
86
87int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/)
88{
89#define off ((uint64_t)0)
90	unsigned sector_size;
91	unsigned cluster_size;
92	uint64_t mft_cluster;
93	uint64_t mft_off;
94	unsigned mft_record_size;
95	unsigned attr_type;
96	unsigned attr_off;
97	unsigned attr_len;
98	unsigned val_off;
99	unsigned val_len;
100	struct master_file_table_record *mftr;
101	struct ntfs_super_block *ns;
102	const uint8_t *buf;
103	const uint8_t *val;
104
105	dbg("probing at offset 0x%llx", (unsigned long long) off);
106
107	ns = volume_id_get_buffer(id, off, 0x200);
108	if (ns == NULL)
109		return -1;
110
111	if (memcmp(ns->oem_id, "NTFS", 4) != 0)
112		return -1;
113
114	volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS);
115
116	sector_size = le16_to_cpu(ns->bytes_per_sector);
117	cluster_size = ns->sectors_per_cluster * sector_size;
118	mft_cluster = le64_to_cpu(ns->mft_cluster_location);
119	mft_off = mft_cluster * cluster_size;
120
121	if (ns->cluster_per_mft_record < 0)
122		/* size = -log2(mft_record_size); normally 1024 Bytes */
123		mft_record_size = 1 << -ns->cluster_per_mft_record;
124	else
125		mft_record_size = ns->cluster_per_mft_record * cluster_size;
126
127	dbg("sectorsize  0x%x", sector_size);
128	dbg("clustersize 0x%x", cluster_size);
129	dbg("mftcluster  %llu", (unsigned long long) mft_cluster);
130	dbg("mftoffset  0x%llx", (unsigned long long) mft_off);
131	dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
132	dbg("mft record size  %i", mft_record_size);
133
134	buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
135			 mft_record_size);
136	if (buf == NULL)
137		goto found;
138
139	mftr = (struct master_file_table_record*) buf;
140
141	dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
142	if (memcmp(mftr->magic, "FILE", 4) != 0)
143		goto found;
144
145	attr_off = le16_to_cpu(mftr->attrs_offset);
146	dbg("file $Volume's attributes are at offset %i", attr_off);
147
148	while (1) {
149		struct file_attribute *attr;
150
151		attr = (struct file_attribute*) &buf[attr_off];
152		attr_type = le32_to_cpu(attr->type);
153		attr_len = le32_to_cpu(attr->len);
154		val_off = le16_to_cpu(attr->value_offset);
155		val_len = le32_to_cpu(attr->value_len);
156		attr_off += attr_len;
157
158		if (attr_len == 0)
159			break;
160
161		if (attr_off >= mft_record_size)
162			break;
163
164		if (attr_type == MFT_RECORD_ATTR_END)
165			break;
166
167		dbg("found attribute type 0x%x, len %i, at offset %i",
168		    attr_type, attr_len, attr_off);
169
170//		if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
171//			struct volume_info *info;
172//			dbg("found info, len %i", val_len);
173//			info = (struct volume_info*) (((uint8_t *) attr) + val_off);
174//			snprintf(id->type_version, sizeof(id->type_version)-1,
175//				 "%u.%u", info->major_ver, info->minor_ver);
176//		}
177
178		if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
179			dbg("found label, len %i", val_len);
180			if (val_len > VOLUME_ID_LABEL_SIZE)
181				val_len = VOLUME_ID_LABEL_SIZE;
182
183			val = ((uint8_t *) attr) + val_off;
184//			volume_id_set_label_raw(id, val, val_len);
185			volume_id_set_label_unicode16(id, val, LE, val_len);
186		}
187	}
188
189 found:
190//	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
191//	id->type = "ntfs";
192
193	return 0;
194}
195