Index: head/usr.sbin/fstyp/Makefile =================================================================== --- head/usr.sbin/fstyp/Makefile (revision 356040) +++ head/usr.sbin/fstyp/Makefile (revision 356041) @@ -1,45 +1,49 @@ # $FreeBSD$ .include PROG= fstyp SRCS= apfs.c cd9660.c exfat.c ext2fs.c fstyp.c geli.c hfsplus.c msdosfs.c ntfs.c ufs.c .if ${MK_ZFS} != "no" SRCS += zfs.c .endif MAN= fstyp.8 WARNS?= 2 +.if ${MK_ICONV} == "yes" +CFLAGS+= -DWITH_ICONV +.endif + .include .if ${TARGET_ENDIANNESS} == 1234 HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .endif .if ${MK_ZFS} != "no" IGNORE_PRAGMA= YES CFLAGS+= -DNEED_SOLARIS_BOOLEAN -DHAVE_ZFS CFLAGS+= -I${SRCTOP}/sys/cddl/compat/opensolaris CFLAGS+= -I${SRCTOP}/cddl/compat/opensolaris/include CFLAGS+= -I${SRCTOP}/cddl/compat/opensolaris/lib/libumem CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libnvpair CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libzpool/common CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common/fs/zfs CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/head .endif CFLAGS+=-I${SRCTOP}/sys LIBADD= geom md ufs .if ${MK_ZFS} != "no" LIBADD+=nvpair zfs .endif .include Index: head/usr.sbin/fstyp/apfs.c =================================================================== --- head/usr.sbin/fstyp/apfs.c (revision 356040) +++ head/usr.sbin/fstyp/apfs.c (revision 356041) @@ -1,108 +1,107 @@ /* * Copyright (c) 2019 Conrad Meyer . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include #include #include #include "fstyp.h" /* * This really detects the container format, which might be best supported by * geom_part or a special GEOM class. * * https://developer.apple.com/support/downloads/Apple-File-System-Reference.pdf */ #define NX_CKSUM_SZ 8 typedef uint64_t nx_oid_t; typedef uint64_t nx_xid_t; struct nx_obj { uint8_t o_cksum[NX_CKSUM_SZ]; /* Fletcher 64 */ nx_oid_t o_oid; nx_xid_t o_xid; uint32_t o_type; uint32_t o_subtype; }; /* nx_obj::o_oid */ #define OID_NX_SUPERBLOCK 1 /* nx_obj::o_type: */ #define OBJECT_TYPE_MASK 0x0000ffff #define OBJECT_TYPE_NX_SUPERBLOCK 0x00000001 #define OBJECT_TYPE_FLAGS_MASK 0xffff0000 #define OBJ_STORAGETYPE_MASK 0xc0000000 #define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000 #define OBJ_STORAGE_VIRTUAL 0x00000000 #define OBJ_STORAGE_EPHEMERAL 0x80000000 #define OBJ_STORAGE_PHYSICAL 0x40000000 #define OBJ_NOHEADER 0x20000000 #define OBJ_ENCRYPTED 0x10000000 #define OBJ_NONPERSISTENT 0x08000000 struct nx_superblock { struct nx_obj nx_o; char nx_magic[4]; /* ... other stuff that doesn't matter */ }; int fstyp_apfs(FILE *fp, char *label, size_t size) { struct nx_superblock *csb; int retval; retval = 1; csb = read_buf(fp, 0, sizeof(*csb)); if (csb == NULL) goto fail; /* Ideally, checksum the SB here. */ if (strncmp(csb->nx_magic, "NXSB", 4) != 0 || csb->nx_o.o_oid != OID_NX_SUPERBLOCK || (csb->nx_o.o_type & OBJECT_TYPE_MASK) != OBJECT_TYPE_NX_SUPERBLOCK) goto fail; retval = 0; /* No label support yet. */ fail: free(csb); return (retval); } Index: head/usr.sbin/fstyp/exfat.c =================================================================== --- head/usr.sbin/fstyp/exfat.c (revision 356040) +++ head/usr.sbin/fstyp/exfat.c (revision 356041) @@ -1,370 +1,376 @@ /* * Copyright (c) 2017 Conrad Meyer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include +#ifdef WITH_ICONV #include +#endif #include #include #include #include #include #include "fstyp.h" /* * https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification */ struct exfat_vbr { char ev_jmp[3]; char ev_fsname[8]; char ev_zeros[53]; uint64_t ev_part_offset; uint64_t ev_vol_length; uint32_t ev_fat_offset; uint32_t ev_fat_length; uint32_t ev_cluster_offset; uint32_t ev_cluster_count; uint32_t ev_rootdir_cluster; uint32_t ev_vol_serial; uint16_t ev_fs_revision; uint16_t ev_vol_flags; uint8_t ev_log_bytes_per_sect; uint8_t ev_log_sect_per_clust; uint8_t ev_num_fats; uint8_t ev_drive_sel; uint8_t ev_percent_used; } __packed; struct exfat_dirent { uint8_t xde_type; #define XDE_TYPE_INUSE_MASK 0x80 /* 1=in use */ #define XDE_TYPE_INUSE_SHIFT 7 #define XDE_TYPE_CATEGORY_MASK 0x40 /* 0=primary */ #define XDE_TYPE_CATEGORY_SHIFT 6 #define XDE_TYPE_IMPORTNC_MASK 0x20 /* 0=critical */ #define XDE_TYPE_IMPORTNC_SHIFT 5 #define XDE_TYPE_CODE_MASK 0x1f /* InUse=0, ..., TypeCode=0: EOD. */ #define XDE_TYPE_EOD 0x00 #define XDE_TYPE_ALLOC_BITMAP (XDE_TYPE_INUSE_MASK | 0x01) #define XDE_TYPE_UPCASE_TABLE (XDE_TYPE_INUSE_MASK | 0x02) #define XDE_TYPE_VOL_LABEL (XDE_TYPE_INUSE_MASK | 0x03) #define XDE_TYPE_FILE (XDE_TYPE_INUSE_MASK | 0x05) #define XDE_TYPE_VOL_GUID (XDE_TYPE_INUSE_MASK | XDE_TYPE_IMPORTNC_MASK) #define XDE_TYPE_STREAM_EXT (XDE_TYPE_INUSE_MASK | XDE_TYPE_CATEGORY_MASK) #define XDE_TYPE_FILE_NAME (XDE_TYPE_INUSE_MASK | XDE_TYPE_CATEGORY_MASK | 0x01) #define XDE_TYPE_VENDOR (XDE_TYPE_INUSE_MASK | XDE_TYPE_CATEGORY_MASK | XDE_TYPE_IMPORTNC_MASK) #define XDE_TYPE_VENDOR_ALLOC (XDE_TYPE_INUSE_MASK | XDE_TYPE_CATEGORY_MASK | XDE_TYPE_IMPORTNC_MASK | 0x01) union { uint8_t xde_generic_[19]; struct exde_primary { /* * Count of "secondary" dirents following this one. * * A single logical entity may be composed of a * sequence of several dirents, starting with a primary * one; the rest are secondary dirents. */ uint8_t xde_secondary_count_; uint16_t xde_set_chksum_; uint16_t xde_prim_flags_; uint8_t xde_prim_generic_[14]; } __packed xde_primary_; struct exde_secondary { uint8_t xde_sec_flags_; uint8_t xde_sec_generic_[18]; } __packed xde_secondary_; } u; uint32_t xde_first_cluster; uint64_t xde_data_len; } __packed; #define xde_generic u.xde_generic_ #define xde_secondary_count u.xde_primary_.xde_secondary_count #define xde_set_chksum u.xde_primary_.xde_set_chksum_ #define xde_prim_flags u.xde_primary_.xde_prim_flags_ #define xde_sec_flags u.xde_secondary_.xde_sec_flags_ _Static_assert(sizeof(struct exfat_dirent) == 32, "spec"); struct exfat_de_label { uint8_t xdel_type; /* XDE_TYPE_VOL_LABEL */ uint8_t xdel_char_cnt; /* Length of UCS-2 label */ uint16_t xdel_vol_lbl[11]; uint8_t xdel_reserved[8]; } __packed; _Static_assert(sizeof(struct exfat_de_label) == 32, "spec"); #define MAIN_BOOT_REGION_SECT 0 #define BACKUP_BOOT_REGION_SECT 12 #define SUBREGION_CHKSUM_SECT 11 #define FIRST_CLUSTER 2 #define BAD_BLOCK_SENTINEL 0xfffffff7u #define END_CLUSTER_SENTINEL 0xffffffffu static inline void * read_sectn(FILE *fp, off_t sect, unsigned count, unsigned bytespersec) { return (read_buf(fp, sect * bytespersec, bytespersec * count)); } static inline void * read_sect(FILE *fp, off_t sect, unsigned bytespersec) { return (read_sectn(fp, sect, 1, bytespersec)); } /* * Compute the byte-by-byte multi-sector checksum of the given boot region * (MAIN or BACKUP), for a given bytespersec (typically 512 or 4096). * * Endian-safe; result is host endian. */ static int exfat_compute_boot_chksum(FILE *fp, unsigned region, unsigned bytespersec, uint32_t *result) { unsigned char *sector; unsigned n, sect; uint32_t checksum; checksum = 0; for (sect = 0; sect < 11; sect++) { sector = read_sect(fp, region + sect, bytespersec); if (sector == NULL) return (ENXIO); for (n = 0; n < bytespersec; n++) { if (sect == 0) { switch (n) { case 106: case 107: case 112: continue; } } checksum = ((checksum & 1) ? 0x80000000u : 0u) + (checksum >> 1) + (uint32_t)sector[n]; } free(sector); } *result = checksum; return (0); } +#ifdef WITH_ICONV static void convert_label(const uint16_t *ucs2label /* LE */, unsigned ucs2len, char *label_out, size_t label_sz) { const char *label; char *label_out_orig; iconv_t cd; size_t srcleft, rc; /* Currently hardcoded in fstyp.c as 256 or so. */ assert(label_sz > 1); if (ucs2len == 0) { /* * Kind of seems bogus, but the spec allows an empty label * entry with the same meaning as no label. */ return; } if (ucs2len > 11) { warnx("exfat: Bogus volume label length: %u", ucs2len); return; } /* dstname="" means convert to the current locale. */ cd = iconv_open("", EXFAT_ENC); if (cd == (iconv_t)-1) { warn("exfat: Could not open iconv"); return; } label_out_orig = label_out; /* Dummy up the byte pointer and byte length iconv's API wants. */ label = (const void *)ucs2label; srcleft = ucs2len * sizeof(*ucs2label); rc = iconv(cd, __DECONST(char **, &label), &srcleft, &label_out, &label_sz); if (rc == (size_t)-1) { warn("exfat: iconv()"); *label_out_orig = '\0'; } else { /* NUL-terminate result (iconv advances label_out). */ if (label_sz == 0) label_out--; *label_out = '\0'; } iconv_close(cd); } /* * Using the FAT table, look up the next cluster in this chain. */ static uint32_t exfat_fat_next(FILE *fp, const struct exfat_vbr *ev, unsigned BPS, uint32_t cluster) { uint32_t fat_offset_sect, clsect, clsectoff; uint32_t *fatsect, nextclust; fat_offset_sect = le32toh(ev->ev_fat_offset); clsect = fat_offset_sect + (cluster / (BPS / sizeof(cluster))); clsectoff = (cluster % (BPS / sizeof(cluster))); /* XXX This is pretty wasteful without a block cache for the FAT. */ fatsect = read_sect(fp, clsect, BPS); nextclust = le32toh(fatsect[clsectoff]); free(fatsect); return (nextclust); } static void exfat_find_label(FILE *fp, const struct exfat_vbr *ev, unsigned BPS, char *label_out, size_t label_sz) { uint32_t rootdir_cluster, sects_per_clust, cluster_offset_sect; off_t rootdir_sect; struct exfat_dirent *declust, *it; cluster_offset_sect = le32toh(ev->ev_cluster_offset); rootdir_cluster = le32toh(ev->ev_rootdir_cluster); sects_per_clust = (1u << ev->ev_log_sect_per_clust); if (rootdir_cluster < FIRST_CLUSTER) { warnx("%s: invalid rootdir cluster %u < %d", __func__, rootdir_cluster, FIRST_CLUSTER); return; } for (; rootdir_cluster != END_CLUSTER_SENTINEL; rootdir_cluster = exfat_fat_next(fp, ev, BPS, rootdir_cluster)) { if (rootdir_cluster == BAD_BLOCK_SENTINEL) { warnx("%s: Bogus bad block in root directory chain", __func__); return; } rootdir_sect = (rootdir_cluster - FIRST_CLUSTER) * sects_per_clust + cluster_offset_sect; declust = read_sectn(fp, rootdir_sect, sects_per_clust, BPS); for (it = declust; it < declust + (sects_per_clust * BPS / sizeof(*it)); it++) { bool eod = false; /* * Simplistic directory traversal; doesn't do any * validation of "MUST" requirements in spec. */ switch (it->xde_type) { case XDE_TYPE_EOD: eod = true; break; case XDE_TYPE_VOL_LABEL: { struct exfat_de_label *lde = (void*)it; convert_label(lde->xdel_vol_lbl, lde->xdel_char_cnt, label_out, label_sz); free(declust); return; } } if (eod) break; } free(declust); } } +#endif /* WITH_ICONV */ int fstyp_exfat(FILE *fp, char *label, size_t size) { struct exfat_vbr *ev; uint32_t *cksect; unsigned bytespersec; uint32_t chksum; int error; cksect = NULL; ev = (struct exfat_vbr *)read_buf(fp, 0, 512); if (ev == NULL || strncmp(ev->ev_fsname, "EXFAT ", 8) != 0) goto fail; if (ev->ev_log_bytes_per_sect < 9 || ev->ev_log_bytes_per_sect > 12) { warnx("exfat: Invalid BytesPerSectorShift"); goto done; } bytespersec = (1u << ev->ev_log_bytes_per_sect); error = exfat_compute_boot_chksum(fp, MAIN_BOOT_REGION_SECT, bytespersec, &chksum); if (error != 0) goto done; cksect = read_sect(fp, MAIN_BOOT_REGION_SECT + SUBREGION_CHKSUM_SECT, bytespersec); /* * Technically the entire sector should be full of repeating 4-byte * checksum pattern, but we only verify the first. */ if (chksum != le32toh(cksect[0])) { warnx("exfat: Found checksum 0x%08x != computed 0x%08x", le32toh(cksect[0]), chksum); goto done; } +#ifdef WITH_ICONV if (show_label) exfat_find_label(fp, ev, bytespersec, label, size); +#endif done: free(cksect); free(ev); return (0); fail: free(ev); return (1); } Index: head/usr.sbin/fstyp/fstyp.c =================================================================== --- head/usr.sbin/fstyp/fstyp.c (revision 356040) +++ head/usr.sbin/fstyp/fstyp.c (revision 356041) @@ -1,263 +1,267 @@ /*- * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#ifdef WITH_ICONV #include +#endif #include #include #include #include #include #include #include #include #include "fstyp.h" #define LABEL_LEN 256 bool show_label = false; typedef int (*fstyp_function)(FILE *, char *, size_t); static struct { const char *name; fstyp_function function; bool unmountable; char *precache_encoding; } fstypes[] = { { "apfs", &fstyp_apfs, true, NULL }, { "cd9660", &fstyp_cd9660, false, NULL }, { "exfat", &fstyp_exfat, false, EXFAT_ENC }, { "ext2fs", &fstyp_ext2fs, false, NULL }, { "geli", &fstyp_geli, true, NULL }, { "hfs+", &fstyp_hfsp, false, NULL }, { "msdosfs", &fstyp_msdosfs, false, NULL }, { "ntfs", &fstyp_ntfs, false, NTFS_ENC }, { "ufs", &fstyp_ufs, false, NULL }, #ifdef HAVE_ZFS { "zfs", &fstyp_zfs, true, NULL }, #endif { NULL, NULL, NULL, NULL } }; void * read_buf(FILE *fp, off_t off, size_t len) { int error; size_t nread; void *buf; error = fseek(fp, off, SEEK_SET); if (error != 0) { warn("cannot seek to %jd", (uintmax_t)off); return (NULL); } buf = malloc(len); if (buf == NULL) { warn("cannot malloc %zd bytes of memory", len); return (NULL); } nread = fread(buf, len, 1, fp); if (nread != 1) { free(buf); if (feof(fp) == 0) warn("fread"); return (NULL); } return (buf); } char * checked_strdup(const char *s) { char *c; c = strdup(s); if (c == NULL) err(1, "strdup"); return (c); } void rtrim(char *label, size_t size) { ptrdiff_t i; for (i = size - 1; i >= 0; i--) { if (label[i] == '\0') continue; else if (label[i] == ' ') label[i] = '\0'; else break; } } static void usage(void) { fprintf(stderr, "usage: fstyp [-l] [-s] [-u] special\n"); exit(1); } static void type_check(const char *path, FILE *fp) { int error, fd; off_t mediasize; struct stat sb; fd = fileno(fp); error = fstat(fd, &sb); if (error != 0) err(1, "%s: fstat", path); if (S_ISREG(sb.st_mode)) return; error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); if (error != 0) errx(1, "%s: not a disk", path); } int main(int argc, char **argv) { int ch, error, i, nbytes; bool ignore_type = false, show_unmountable = false; char label[LABEL_LEN + 1], strvised[LABEL_LEN * 4 + 1]; char *path; FILE *fp; fstyp_function fstyp_f; while ((ch = getopt(argc, argv, "lsu")) != -1) { switch (ch) { case 'l': show_label = true; break; case 's': ignore_type = true; break; case 'u': show_unmountable = true; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); path = argv[0]; if (setlocale(LC_CTYPE, "") == NULL) err(1, "setlocale"); caph_cache_catpages(); +#ifdef WITH_ICONV /* Cache iconv conversion data before entering capability mode. */ if (show_label) { for (i = 0; i < nitems(fstypes); i++) { iconv_t cd; if (fstypes[i].precache_encoding == NULL) continue; cd = iconv_open("", fstypes[i].precache_encoding); if (cd == (iconv_t)-1) err(1, "%s: iconv_open %s", fstypes[i].name, fstypes[i].precache_encoding); /* Iconv keeps a small cache of unused encodings. */ iconv_close(cd); } } +#endif fp = fopen(path, "r"); if (fp == NULL) err(1, "%s", path); if (caph_enter() < 0) err(1, "cap_enter"); if (ignore_type == false) type_check(path, fp); memset(label, '\0', sizeof(label)); for (i = 0;; i++) { if (show_unmountable == false && fstypes[i].unmountable == true) continue; fstyp_f = fstypes[i].function; if (fstyp_f == NULL) break; error = fstyp_f(fp, label, sizeof(label)); if (error == 0) break; } if (fstypes[i].name == NULL) { warnx("%s: filesystem not recognized", path); return (1); } if (show_label && label[0] != '\0') { /* * XXX: I'd prefer VIS_HTTPSTYLE, but it unconditionally * encodes spaces. */ nbytes = strsnvis(strvised, sizeof(strvised), label, VIS_GLOB | VIS_NL, "\"'$"); if (nbytes == -1) err(1, "strsnvis"); printf("%s %s\n", fstypes[i].name, strvised); } else { printf("%s\n", fstypes[i].name); } return (0); } Index: head/usr.sbin/fstyp/hfsplus.c =================================================================== --- head/usr.sbin/fstyp/hfsplus.c (revision 356040) +++ head/usr.sbin/fstyp/hfsplus.c (revision 356041) @@ -1,126 +1,125 @@ /* * Copyright (c) 2019 Conrad Meyer . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include #include #include #include "fstyp.h" /* * https://developer.apple.com/library/archive/technotes/tn/tn1150.html */ #define VOL_HDR_OFF 1024 typedef uint32_t hfsp_cat_nodeid; typedef struct hfsp_ext_desc { uint32_t ex_startBlock; uint32_t ex_blockCount; } hfsp_ext_desc; typedef struct hfsp_fork_data { uint64_t fd_logicalSz; uint32_t fd_clumpSz; uint32_t fd_totalBlocks; hfsp_ext_desc fd_extents[8]; } hfsp_fork_data; struct hfsp_vol_hdr { char hp_signature[2]; uint16_t hp_version; uint32_t hp_attributes; uint32_t hp_lastMounted; uint32_t hp_journalInfoBlock; /* Creation / etc dates. */ uint32_t hp_create; uint32_t hp_modify; uint32_t hp_backup; uint32_t hp_checked; /* Stats */ uint32_t hp_files; uint32_t hp_folders; /* Parameters */ uint32_t hp_blockSize; uint32_t hp_totalBlocks; uint32_t hp_freeBlocks; uint32_t hp_nextAlloc; uint32_t hp_rsrcClumpSz; uint32_t hp_dataClumpSz; hfsp_cat_nodeid hp_nextCatID; uint32_t hp_writeCount; uint64_t hp_encodingsBM; uint32_t hp_finderInfo[8]; hfsp_fork_data hp_allocationFile; hfsp_fork_data hp_extentsFile; hfsp_fork_data hp_catalogFile; hfsp_fork_data hp_attributesFile; hfsp_fork_data hp_startupFile; }; _Static_assert(sizeof(struct hfsp_vol_hdr) == 512, ""); int fstyp_hfsp(FILE *fp, char *label, size_t size) { struct hfsp_vol_hdr *hdr; int retval; retval = 1; hdr = read_buf(fp, VOL_HDR_OFF, sizeof(*hdr)); if (hdr == NULL) goto fail; if ((strncmp(hdr->hp_signature, "H+", 2) != 0 || hdr->hp_version != 4) && (strncmp(hdr->hp_signature, "HX", 2) != 0 || hdr->hp_version != 5)) goto fail; /* This is an HFS+ volume. */ retval = 0; /* No label support yet. */ fail: free(hdr); return (retval); } Index: head/usr.sbin/fstyp/ntfs.c =================================================================== --- head/usr.sbin/fstyp/ntfs.c (revision 356040) +++ head/usr.sbin/fstyp/ntfs.c (revision 356041) @@ -1,184 +1,190 @@ /*- * Copyright (c) 2005 Takanori Watanabe * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include +#ifdef WITH_ICONV #include +#endif #include #include #include #include #include "fstyp.h" #define NTFS_A_VOLUMENAME 0x60 #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946)) #define NTFS_VOLUMEINO 3 struct ntfs_attr { uint32_t a_type; uint32_t reclen; uint8_t a_flag; uint8_t a_namelen; uint8_t a_nameoff; uint8_t reserved1; uint8_t a_compression; uint8_t reserved2; uint16_t a_index; uint16_t a_datalen; uint16_t reserved3; uint16_t a_dataoff; uint16_t a_indexed; } __packed; struct ntfs_filerec { uint32_t fr_hdrmagic; uint16_t fr_hdrfoff; uint16_t fr_hdrfnum; uint8_t reserved[8]; uint16_t fr_seqnum; uint16_t fr_nlink; uint16_t fr_attroff; uint16_t fr_flags; uint32_t fr_size; uint32_t fr_allocated; uint64_t fr_mainrec; uint16_t fr_attrnum; } __packed; struct ntfs_bootfile { uint8_t reserved1[3]; uint8_t bf_sysid[8]; uint16_t bf_bps; uint8_t bf_spc; uint8_t reserved2[7]; uint8_t bf_media; uint8_t reserved3[2]; uint16_t bf_spt; uint16_t bf_heads; uint8_t reserver4[12]; uint64_t bf_spv; uint64_t bf_mftcn; uint64_t bf_mftmirrcn; int8_t bf_mftrecsz; uint32_t bf_ibsz; uint32_t bf_volsn; } __packed; +#ifdef WITH_ICONV static void convert_label(const void *label /* LE */, size_t labellen, char *label_out, size_t label_sz) { char *label_out_orig; iconv_t cd; size_t rc; /* dstname="" means convert to the current locale. */ cd = iconv_open("", NTFS_ENC); if (cd == (iconv_t)-1) { warn("ntfs: Could not open iconv"); return; } label_out_orig = label_out; rc = iconv(cd, __DECONST(char **, &label), &labellen, &label_out, &label_sz); if (rc == (size_t)-1) { warn("ntfs: iconv()"); *label_out_orig = '\0'; } else { /* NUL-terminate result (iconv advances label_out). */ if (label_sz == 0) label_out--; *label_out = '\0'; } iconv_close(cd); } +#endif int fstyp_ntfs(FILE *fp, char *label, size_t size) { struct ntfs_bootfile *bf; struct ntfs_filerec *fr; struct ntfs_attr *atr; off_t voloff; char *filerecp, *ap; int8_t mftrecsz; int recsize; filerecp = NULL; bf = (struct ntfs_bootfile *)read_buf(fp, 0, 512); if (bf == NULL || strncmp(bf->bf_sysid, "NTFS ", 8) != 0) goto fail; +#ifdef WITH_ICONV if (!show_label) goto ok; mftrecsz = bf->bf_mftrecsz; recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz); voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps + recsize * NTFS_VOLUMEINO; filerecp = read_buf(fp, voloff, recsize); if (filerecp == NULL) goto fail; fr = (struct ntfs_filerec *)filerecp; if (fr->fr_hdrmagic != NTFS_FILEMAGIC) goto fail; for (ap = filerecp + fr->fr_attroff; atr = (struct ntfs_attr *)ap, (int)atr->a_type != -1; ap += atr->reclen) { if (atr->a_type != NTFS_A_VOLUMENAME) continue; convert_label(ap + atr->a_dataoff, atr->a_datalen, label, size); break; } ok: +#endif /* WITH_ICONV */ free(bf); free(filerecp); return (0); fail: free(bf); free(filerecp); return (1); }