1*9f7be3f1Stkusumi /* $NetBSD: ntfs.c,v 1.2 2019/12/28 08:22:30 tkusumi Exp $ */ 259a9e119Schristos 359a9e119Schristos /*- 459a9e119Schristos * Copyright (c) 2017 The NetBSD Foundation, Inc. 559a9e119Schristos * Copyright (c) 2016 The DragonFly Project 659a9e119Schristos * Copyright (c) 2005 Takanori Watanabe 759a9e119Schristos * Copyright (c) 2014 The FreeBSD Foundation 859a9e119Schristos * All rights reserved. 959a9e119Schristos * 1059a9e119Schristos * This code is derived from software contributed to The NetBSD Foundation 1159a9e119Schristos * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>. 1259a9e119Schristos * 1359a9e119Schristos * This software was developed by Edward Tomasz Napierala under sponsorship 1459a9e119Schristos * from the FreeBSD Foundation. 1559a9e119Schristos * 1659a9e119Schristos * Redistribution and use in source and binary forms, with or without 1759a9e119Schristos * modification, are permitted provided that the following conditions 1859a9e119Schristos * are met: 1959a9e119Schristos * 1. Redistributions of source code must retain the above copyright 2059a9e119Schristos * notice, this list of conditions and the following disclaimer. 2159a9e119Schristos * 2. Redistributions in binary form must reproduce the above copyright 2259a9e119Schristos * notice, this list of conditions and the following disclaimer in the 2359a9e119Schristos * documentation and/or other materials provided with the distribution. 2459a9e119Schristos * 2559a9e119Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2659a9e119Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2759a9e119Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2859a9e119Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2959a9e119Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3059a9e119Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3159a9e119Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3259a9e119Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3359a9e119Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3459a9e119Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3559a9e119Schristos * SUCH DAMAGE. 3659a9e119Schristos */ 3759a9e119Schristos #include <sys/cdefs.h> 38*9f7be3f1Stkusumi __RCSID("$NetBSD: ntfs.c,v 1.2 2019/12/28 08:22:30 tkusumi Exp $"); 3959a9e119Schristos 40*9f7be3f1Stkusumi #include <err.h> 41*9f7be3f1Stkusumi #include <iconv.h> 4259a9e119Schristos #include <stdint.h> 4359a9e119Schristos #include <stdio.h> 4459a9e119Schristos #include <stdlib.h> 4559a9e119Schristos #include <string.h> 4659a9e119Schristos 4759a9e119Schristos #include "fstyp.h" 4859a9e119Schristos 4959a9e119Schristos #define NTFS_A_VOLUMENAME 0x60 5059a9e119Schristos #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946)) 5159a9e119Schristos #define NTFS_VOLUMEINO 3 5259a9e119Schristos 5359a9e119Schristos struct ntfs_attr { 5459a9e119Schristos uint32_t a_type; 5559a9e119Schristos uint32_t reclen; 5659a9e119Schristos uint8_t a_flag; 5759a9e119Schristos uint8_t a_namelen; 5859a9e119Schristos uint8_t a_nameoff; 5959a9e119Schristos uint8_t reserved1; 6059a9e119Schristos uint8_t a_compression; 6159a9e119Schristos uint8_t reserved2; 6259a9e119Schristos uint16_t a_index; 6359a9e119Schristos uint16_t a_datalen; 6459a9e119Schristos uint16_t reserved3; 6559a9e119Schristos uint16_t a_dataoff; 6659a9e119Schristos uint16_t a_indexed; 6759a9e119Schristos } __packed; 6859a9e119Schristos 6959a9e119Schristos struct ntfs_filerec { 7059a9e119Schristos uint32_t fr_hdrmagic; 7159a9e119Schristos uint16_t fr_hdrfoff; 7259a9e119Schristos uint16_t fr_hdrfnum; 7359a9e119Schristos uint8_t reserved[8]; 7459a9e119Schristos uint16_t fr_seqnum; 7559a9e119Schristos uint16_t fr_nlink; 7659a9e119Schristos uint16_t fr_attroff; 7759a9e119Schristos uint16_t fr_flags; 7859a9e119Schristos uint32_t fr_size; 7959a9e119Schristos uint32_t fr_allocated; 8059a9e119Schristos uint64_t fr_mainrec; 8159a9e119Schristos uint16_t fr_attrnum; 8259a9e119Schristos } __packed; 8359a9e119Schristos 8459a9e119Schristos struct ntfs_bootfile { 8559a9e119Schristos uint8_t reserved1[3]; 8659a9e119Schristos uint8_t bf_sysid[8]; 8759a9e119Schristos uint16_t bf_bps; 8859a9e119Schristos uint8_t bf_spc; 8959a9e119Schristos uint8_t reserved2[7]; 9059a9e119Schristos uint8_t bf_media; 9159a9e119Schristos uint8_t reserved3[2]; 9259a9e119Schristos uint16_t bf_spt; 9359a9e119Schristos uint16_t bf_heads; 9459a9e119Schristos uint8_t reserver4[12]; 9559a9e119Schristos uint64_t bf_spv; 9659a9e119Schristos uint64_t bf_mftcn; 9759a9e119Schristos uint64_t bf_mftmirrcn; 9859a9e119Schristos int8_t bf_mftrecsz; 9959a9e119Schristos uint32_t bf_ibsz; 10059a9e119Schristos uint32_t bf_volsn; 10159a9e119Schristos } __packed; 10259a9e119Schristos 103*9f7be3f1Stkusumi static void 104*9f7be3f1Stkusumi convert_label(const void *label /* LE */, size_t labellen, char *label_out, 105*9f7be3f1Stkusumi size_t label_sz) 106*9f7be3f1Stkusumi { 107*9f7be3f1Stkusumi char *label_out_orig; 108*9f7be3f1Stkusumi iconv_t cd; 109*9f7be3f1Stkusumi size_t rc; 110*9f7be3f1Stkusumi 111*9f7be3f1Stkusumi /* dstname="" means convert to the current locale. */ 112*9f7be3f1Stkusumi cd = iconv_open("", NTFS_ENC); 113*9f7be3f1Stkusumi if (cd == (iconv_t)-1) { 114*9f7be3f1Stkusumi warn("ntfs: Could not open iconv"); 115*9f7be3f1Stkusumi return; 116*9f7be3f1Stkusumi } 117*9f7be3f1Stkusumi 118*9f7be3f1Stkusumi label_out_orig = label_out; 119*9f7be3f1Stkusumi 120*9f7be3f1Stkusumi rc = iconv(cd, __UNCONST(&label), &labellen, &label_out, 121*9f7be3f1Stkusumi &label_sz); 122*9f7be3f1Stkusumi if (rc == (size_t)-1) { 123*9f7be3f1Stkusumi warn("ntfs: iconv()"); 124*9f7be3f1Stkusumi *label_out_orig = '\0'; 125*9f7be3f1Stkusumi } else { 126*9f7be3f1Stkusumi /* NUL-terminate result (iconv advances label_out). */ 127*9f7be3f1Stkusumi if (label_sz == 0) 128*9f7be3f1Stkusumi label_out--; 129*9f7be3f1Stkusumi *label_out = '\0'; 130*9f7be3f1Stkusumi } 131*9f7be3f1Stkusumi 132*9f7be3f1Stkusumi iconv_close(cd); 133*9f7be3f1Stkusumi } 134*9f7be3f1Stkusumi 13559a9e119Schristos int 13659a9e119Schristos fstyp_ntfs(FILE *fp, char *label, size_t size) 13759a9e119Schristos { 13859a9e119Schristos struct ntfs_bootfile *bf; 13959a9e119Schristos struct ntfs_filerec *fr; 14059a9e119Schristos struct ntfs_attr *atr; 14159a9e119Schristos off_t voloff; 14259a9e119Schristos char *filerecp, *ap; 14359a9e119Schristos int8_t mftrecsz; 144*9f7be3f1Stkusumi size_t recsize; 14559a9e119Schristos 14659a9e119Schristos filerecp = NULL; 14759a9e119Schristos 14859a9e119Schristos bf = read_buf(fp, 0, 512); 14959a9e119Schristos if (bf == NULL || strncmp((char*)bf->bf_sysid, "NTFS ", 8) != 0) 15059a9e119Schristos goto fail; 151*9f7be3f1Stkusumi if (!show_label) 152*9f7be3f1Stkusumi goto ok; 15359a9e119Schristos 15459a9e119Schristos mftrecsz = bf->bf_mftrecsz; 15559a9e119Schristos recsize = mftrecsz > 0 ? (size_t)(mftrecsz * bf->bf_bps * bf->bf_spc) 15659a9e119Schristos : (size_t)(1 << -mftrecsz); 15759a9e119Schristos 158*9f7be3f1Stkusumi voloff = (off_t)((off_t)bf->bf_mftcn * bf->bf_spc * bf->bf_bps + 159*9f7be3f1Stkusumi (off_t)recsize * NTFS_VOLUMEINO); 16059a9e119Schristos 16159a9e119Schristos filerecp = read_buf(fp, voloff, recsize); 16259a9e119Schristos if (filerecp == NULL) 16359a9e119Schristos goto fail; 16459a9e119Schristos fr = (struct ntfs_filerec *)filerecp; 16559a9e119Schristos 16659a9e119Schristos if (fr->fr_hdrmagic != NTFS_FILEMAGIC) 16759a9e119Schristos goto fail; 16859a9e119Schristos 16959a9e119Schristos for (ap = filerecp + fr->fr_attroff; 17059a9e119Schristos atr = (struct ntfs_attr *)ap, (int)atr->a_type != -1; 17159a9e119Schristos ap += atr->reclen) { 172*9f7be3f1Stkusumi if (atr->a_type != NTFS_A_VOLUMENAME) 173*9f7be3f1Stkusumi continue; 174*9f7be3f1Stkusumi 175*9f7be3f1Stkusumi convert_label(ap + atr->a_dataoff, 176*9f7be3f1Stkusumi atr->a_datalen, label, size); 17759a9e119Schristos break; 17859a9e119Schristos } 17959a9e119Schristos 180*9f7be3f1Stkusumi ok: 18159a9e119Schristos free(bf); 18259a9e119Schristos free(filerecp); 18359a9e119Schristos 18459a9e119Schristos return 0; 18559a9e119Schristos 18659a9e119Schristos fail: 18759a9e119Schristos free(bf); 18859a9e119Schristos free(filerecp); 18959a9e119Schristos 19059a9e119Schristos return 1; 19159a9e119Schristos } 192