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