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 #include <err.h> 33 #ifdef WITH_ICONV 34 #include <iconv.h> 35 #endif 36 #include <stdint.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 #include "fstyp.h" 42 43 #define NTFS_A_VOLUMENAME 0x60 44 #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946)) 45 #define NTFS_VOLUMEINO 3 46 47 struct ntfs_attr { 48 uint32_t a_type; 49 uint32_t reclen; 50 uint8_t a_flag; 51 uint8_t a_namelen; 52 uint8_t a_nameoff; 53 uint8_t reserved1; 54 uint8_t a_compression; 55 uint8_t reserved2; 56 uint16_t a_index; 57 uint16_t a_datalen; 58 uint16_t reserved3; 59 uint16_t a_dataoff; 60 uint16_t a_indexed; 61 } __packed; 62 63 struct ntfs_filerec { 64 uint32_t fr_hdrmagic; 65 uint16_t fr_hdrfoff; 66 uint16_t fr_hdrfnum; 67 uint8_t reserved[8]; 68 uint16_t fr_seqnum; 69 uint16_t fr_nlink; 70 uint16_t fr_attroff; 71 uint16_t fr_flags; 72 uint32_t fr_size; 73 uint32_t fr_allocated; 74 uint64_t fr_mainrec; 75 uint16_t fr_attrnum; 76 } __packed; 77 78 struct ntfs_bootfile { 79 uint8_t reserved1[3]; 80 uint8_t bf_sysid[8]; 81 uint16_t bf_bps; 82 uint8_t bf_spc; 83 uint8_t reserved2[7]; 84 uint8_t bf_media; 85 uint8_t reserved3[2]; 86 uint16_t bf_spt; 87 uint16_t bf_heads; 88 uint8_t reserver4[12]; 89 uint64_t bf_spv; 90 uint64_t bf_mftcn; 91 uint64_t bf_mftmirrcn; 92 int8_t bf_mftrecsz; 93 uint32_t bf_ibsz; 94 uint32_t bf_volsn; 95 } __packed; 96 97 #ifdef WITH_ICONV 98 static void 99 convert_label(const void *label /* LE */, size_t labellen, char *label_out, 100 size_t label_sz) 101 { 102 char *label_out_orig; 103 iconv_t cd; 104 size_t rc; 105 106 /* dstname="" means convert to the current locale. */ 107 cd = iconv_open("", NTFS_ENC); 108 if (cd == (iconv_t)-1) { 109 warn("ntfs: Could not open iconv"); 110 return; 111 } 112 113 label_out_orig = label_out; 114 115 rc = iconv(cd, __DECONST(char **, &label), &labellen, &label_out, 116 &label_sz); 117 if (rc == (size_t)-1) { 118 warn("ntfs: iconv()"); 119 *label_out_orig = '\0'; 120 } else { 121 /* NUL-terminate result (iconv advances label_out). */ 122 if (label_sz == 0) 123 label_out--; 124 *label_out = '\0'; 125 } 126 127 iconv_close(cd); 128 } 129 #endif 130 131 int 132 fstyp_ntfs(FILE *fp, char *label, size_t size) 133 { 134 struct ntfs_bootfile *bf; 135 char *filerecp; 136 #ifdef WITH_ICONV 137 struct ntfs_filerec *fr; 138 struct ntfs_attr *atr; 139 off_t voloff; 140 int8_t mftrecsz; 141 size_t recsize; 142 #endif /* WITH_ICONV */ 143 144 filerecp = NULL; 145 146 bf = (struct ntfs_bootfile *)read_buf(fp, 0, 512); 147 if (bf == NULL || strncmp(bf->bf_sysid, "NTFS ", 8) != 0) 148 goto fail; 149 #ifdef WITH_ICONV 150 if (!show_label) 151 goto ok; 152 153 mftrecsz = bf->bf_mftrecsz; 154 recsize = (mftrecsz > 0) ? 155 (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz); 156 157 voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps + 158 recsize * NTFS_VOLUMEINO; 159 160 filerecp = read_buf(fp, voloff, recsize); 161 if (filerecp == NULL) 162 goto fail; 163 fr = (struct ntfs_filerec *)filerecp; 164 165 if (fr->fr_hdrmagic != NTFS_FILEMAGIC) 166 goto fail; 167 168 for (size_t ioff = fr->fr_attroff; 169 ioff + sizeof(struct ntfs_attr) < recsize; 170 ioff += atr->reclen) { 171 atr = (struct ntfs_attr *)(filerecp + ioff); 172 if ((int)atr->a_type == -1) 173 goto ok; 174 if (atr->a_type == NTFS_A_VOLUMENAME) { 175 if ((size_t)atr->a_dataoff + atr->a_datalen > recsize) { 176 warnx("ntfs: Volume name attribute overflow"); 177 goto fail; 178 } 179 convert_label(filerecp + ioff + atr->a_dataoff, 180 atr->a_datalen, label, size); 181 goto ok; 182 } 183 if (atr->reclen == 0) { 184 warnx("ntfs: Invalid attribute record length"); 185 goto fail; 186 } 187 } 188 warnx("ntfs: Volume name not found"); 189 goto fail; 190 191 ok: 192 #else 193 if (show_label) { 194 warnx("label not available without iconv support"); 195 memset(label, 0, size); 196 } 197 #endif /* WITH_ICONV */ 198 free(bf); 199 free(filerecp); 200 201 return (0); 202 203 fail: 204 free(bf); 205 free(filerecp); 206 207 return (1); 208 } 209