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