1 /* $NetBSD: ntfs.c,v 1.3 2021/12/02 14:26:12 christos 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.3 2021/12/02 14:26:12 christos Exp $"); 39 40 #include <err.h> 41 #include <iconv.h> 42 #include <langinfo.h> 43 #include <stdint.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 48 #include "fstyp.h" 49 50 #define NTFS_A_VOLUMENAME 0x60 51 #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946)) 52 #define NTFS_VOLUMEINO 3 53 54 struct ntfs_attr { 55 uint32_t a_type; 56 uint32_t reclen; 57 uint8_t a_flag; 58 uint8_t a_namelen; 59 uint8_t a_nameoff; 60 uint8_t reserved1; 61 uint8_t a_compression; 62 uint8_t reserved2; 63 uint16_t a_index; 64 uint16_t a_datalen; 65 uint16_t reserved3; 66 uint16_t a_dataoff; 67 uint16_t a_indexed; 68 } __packed; 69 70 struct ntfs_filerec { 71 uint32_t fr_hdrmagic; 72 uint16_t fr_hdrfoff; 73 uint16_t fr_hdrfnum; 74 uint8_t reserved[8]; 75 uint16_t fr_seqnum; 76 uint16_t fr_nlink; 77 uint16_t fr_attroff; 78 uint16_t fr_flags; 79 uint32_t fr_size; 80 uint32_t fr_allocated; 81 uint64_t fr_mainrec; 82 uint16_t fr_attrnum; 83 } __packed; 84 85 struct ntfs_bootfile { 86 uint8_t reserved1[3]; 87 uint8_t bf_sysid[8]; 88 uint16_t bf_bps; 89 uint8_t bf_spc; 90 uint8_t reserved2[7]; 91 uint8_t bf_media; 92 uint8_t reserved3[2]; 93 uint16_t bf_spt; 94 uint16_t bf_heads; 95 uint8_t reserver4[12]; 96 uint64_t bf_spv; 97 uint64_t bf_mftcn; 98 uint64_t bf_mftmirrcn; 99 int8_t bf_mftrecsz; 100 uint32_t bf_ibsz; 101 uint32_t bf_volsn; 102 } __packed; 103 104 static void 105 convert_label(const void *label /* LE */, size_t labellen, char *label_out, 106 size_t label_sz) 107 { 108 char *label_out_orig; 109 iconv_t cd; 110 size_t rc; 111 112 cd = iconv_open(nl_langinfo(CODESET), 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