17ba4d2eaSTakanori Watanabe /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
47ba4d2eaSTakanori Watanabe * Copyright (c) 2005 Takanori Watanabe
57ba4d2eaSTakanori Watanabe * All rights reserved.
67ba4d2eaSTakanori Watanabe *
77ba4d2eaSTakanori Watanabe * Redistribution and use in source and binary forms, with or without
87ba4d2eaSTakanori Watanabe * modification, are permitted provided that the following conditions
97ba4d2eaSTakanori Watanabe * are met:
107ba4d2eaSTakanori Watanabe * 1. Redistributions of source code must retain the above copyright
117ba4d2eaSTakanori Watanabe * notice, this list of conditions and the following disclaimer.
127ba4d2eaSTakanori Watanabe * 2. Redistributions in binary form must reproduce the above copyright
137ba4d2eaSTakanori Watanabe * notice, this list of conditions and the following disclaimer in the
147ba4d2eaSTakanori Watanabe * documentation and/or other materials provided with the distribution.
157ba4d2eaSTakanori Watanabe *
167ba4d2eaSTakanori Watanabe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177ba4d2eaSTakanori Watanabe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187ba4d2eaSTakanori Watanabe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197ba4d2eaSTakanori Watanabe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207ba4d2eaSTakanori Watanabe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217ba4d2eaSTakanori Watanabe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227ba4d2eaSTakanori Watanabe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237ba4d2eaSTakanori Watanabe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247ba4d2eaSTakanori Watanabe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257ba4d2eaSTakanori Watanabe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267ba4d2eaSTakanori Watanabe * SUCH DAMAGE.
277ba4d2eaSTakanori Watanabe */
287ba4d2eaSTakanori Watanabe
297ba4d2eaSTakanori Watanabe #include <sys/param.h>
307ba4d2eaSTakanori Watanabe #include <sys/systm.h>
317ba4d2eaSTakanori Watanabe #include <sys/kernel.h>
327ba4d2eaSTakanori Watanabe #include <sys/malloc.h>
337ba4d2eaSTakanori Watanabe
347ba4d2eaSTakanori Watanabe #include <geom/geom.h>
357ba4d2eaSTakanori Watanabe #include <geom/label/g_label.h>
367ba4d2eaSTakanori Watanabe
370f90e981SAttilio Rao #define NTFS_A_VOLUMENAME 0x60
380f90e981SAttilio Rao #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946))
390f90e981SAttilio Rao #define NTFS_VOLUMEINO 3
400f90e981SAttilio Rao
410f90e981SAttilio Rao struct ntfs_attr {
420f90e981SAttilio Rao uint32_t a_type;
430f90e981SAttilio Rao uint32_t reclen;
440f90e981SAttilio Rao uint8_t a_flag;
450f90e981SAttilio Rao uint8_t a_namelen;
460f90e981SAttilio Rao uint8_t a_nameoff;
470f90e981SAttilio Rao uint8_t reserved1;
480f90e981SAttilio Rao uint8_t a_compression;
490f90e981SAttilio Rao uint8_t reserved2;
500f90e981SAttilio Rao uint16_t a_index;
510f90e981SAttilio Rao uint16_t a_datalen;
520f90e981SAttilio Rao uint16_t reserved3;
530f90e981SAttilio Rao uint16_t a_dataoff;
540f90e981SAttilio Rao uint16_t a_indexed;
555943eed4SJean-Sébastien Pédron } __packed;
560f90e981SAttilio Rao
570f90e981SAttilio Rao struct ntfs_filerec {
580f90e981SAttilio Rao uint32_t fr_hdrmagic;
590f90e981SAttilio Rao uint16_t fr_hdrfoff;
600f90e981SAttilio Rao uint16_t fr_hdrfnum;
610f90e981SAttilio Rao uint8_t reserved[8];
620f90e981SAttilio Rao uint16_t fr_seqnum;
630f90e981SAttilio Rao uint16_t fr_nlink;
640f90e981SAttilio Rao uint16_t fr_attroff;
650f90e981SAttilio Rao uint16_t fr_flags;
660f90e981SAttilio Rao uint32_t fr_size;
670f90e981SAttilio Rao uint32_t fr_allocated;
680f90e981SAttilio Rao uint64_t fr_mainrec;
690f90e981SAttilio Rao uint16_t fr_attrnum;
705943eed4SJean-Sébastien Pédron } __packed;
710f90e981SAttilio Rao
720f90e981SAttilio Rao struct ntfs_bootfile {
730f90e981SAttilio Rao uint8_t reserved1[3];
740f90e981SAttilio Rao uint8_t bf_sysid[8];
750f90e981SAttilio Rao uint16_t bf_bps;
760f90e981SAttilio Rao uint8_t bf_spc;
770f90e981SAttilio Rao uint8_t reserved2[7];
780f90e981SAttilio Rao uint8_t bf_media;
790f90e981SAttilio Rao uint8_t reserved3[2];
800f90e981SAttilio Rao uint16_t bf_spt;
810f90e981SAttilio Rao uint16_t bf_heads;
820f90e981SAttilio Rao uint8_t reserver4[12];
830f90e981SAttilio Rao uint64_t bf_spv;
840f90e981SAttilio Rao uint64_t bf_mftcn;
850f90e981SAttilio Rao uint64_t bf_mftmirrcn;
8677f86064SStanislav Sedov int8_t bf_mftrecsz;
870f90e981SAttilio Rao uint32_t bf_ibsz;
880f90e981SAttilio Rao uint32_t bf_volsn;
895943eed4SJean-Sébastien Pédron } __packed;
907ba4d2eaSTakanori Watanabe
917ba4d2eaSTakanori Watanabe static void
g_label_ntfs_taste(struct g_consumer * cp,char * label,size_t size)927ba4d2eaSTakanori Watanabe g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
937ba4d2eaSTakanori Watanabe {
947ba4d2eaSTakanori Watanabe struct g_provider *pp;
950f90e981SAttilio Rao struct ntfs_bootfile *bf;
960f90e981SAttilio Rao struct ntfs_filerec *fr;
970f90e981SAttilio Rao struct ntfs_attr *atr;
987ba4d2eaSTakanori Watanabe off_t voloff;
99f0a08fa9SMark Johnston size_t recoff;
100f0a08fa9SMark Johnston char *filerecp;
10177f86064SStanislav Sedov int8_t mftrecsz;
10277f86064SStanislav Sedov char vnchar;
103481b55b1SPawel Jakub Dawidek int recsize, j;
104481b55b1SPawel Jakub Dawidek
1057ba4d2eaSTakanori Watanabe g_topology_assert_not();
106481b55b1SPawel Jakub Dawidek
1077ba4d2eaSTakanori Watanabe label[0] = '\0';
108481b55b1SPawel Jakub Dawidek pp = cp->provider;
1095402baa5SMark Johnston bf = NULL;
110481b55b1SPawel Jakub Dawidek filerecp = NULL;
1117ba4d2eaSTakanori Watanabe
1125402baa5SMark Johnston if (pp->sectorsize < sizeof(*bf))
1135402baa5SMark Johnston goto done;
1145402baa5SMark Johnston
1155402baa5SMark Johnston bf = g_read_data(cp, 0, pp->sectorsize, NULL);
116481b55b1SPawel Jakub Dawidek if (bf == NULL || strncmp(bf->bf_sysid, "NTFS ", 8) != 0)
1177ba4d2eaSTakanori Watanabe goto done;
1187ba4d2eaSTakanori Watanabe
11977f86064SStanislav Sedov mftrecsz = bf->bf_mftrecsz;
120f0a08fa9SMark Johnston recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) :
121f0a08fa9SMark Johnston (1 << -mftrecsz);
122f0a08fa9SMark Johnston if (recsize <= 0 || recsize > maxphys || recsize % pp->sectorsize != 0)
1233ae0e7d8SPawel Jakub Dawidek goto done;
1247ba4d2eaSTakanori Watanabe
1257ba4d2eaSTakanori Watanabe voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps +
1267ba4d2eaSTakanori Watanabe recsize * NTFS_VOLUMEINO;
1277ba4d2eaSTakanori Watanabe if (voloff % pp->sectorsize != 0)
1287ba4d2eaSTakanori Watanabe goto done;
1297ba4d2eaSTakanori Watanabe
13088d17294SPawel Jakub Dawidek filerecp = g_read_data(cp, voloff, recsize, NULL);
1315c8a6f63SMaxim Sobolev if (filerecp == NULL)
1325c8a6f63SMaxim Sobolev goto done;
1330f90e981SAttilio Rao fr = (struct ntfs_filerec *)filerecp;
1340f90e981SAttilio Rao if (fr->fr_hdrmagic != NTFS_FILEMAGIC)
135f83da457STakanori Watanabe goto done;
136f83da457STakanori Watanabe
137f0a08fa9SMark Johnston for (recoff = fr->fr_attroff;
138f0a08fa9SMark Johnston recoff <= recsize - 2 * sizeof(uint32_t);
139f0a08fa9SMark Johnston recoff += atr->reclen) {
140f0a08fa9SMark Johnston atr = (struct ntfs_attr *)(filerecp + recoff);
141f0a08fa9SMark Johnston if (atr->a_type == -1)
142f0a08fa9SMark Johnston break;
143f0a08fa9SMark Johnston if (atr->reclen < sizeof(*atr))
144f0a08fa9SMark Johnston break;
145f0a08fa9SMark Johnston if (recsize - recoff < atr->reclen)
146f0a08fa9SMark Johnston break;
1470f90e981SAttilio Rao if (atr->a_type == NTFS_A_VOLUMENAME) {
148f0a08fa9SMark Johnston if (atr->a_dataoff > atr->reclen ||
149f0a08fa9SMark Johnston atr->a_datalen > atr->reclen - atr->a_dataoff)
150f0a08fa9SMark Johnston break;
151f0a08fa9SMark Johnston
1527ba4d2eaSTakanori Watanabe /*
1537ba4d2eaSTakanori Watanabe * UNICODE to ASCII.
1547ba4d2eaSTakanori Watanabe * Should we need to use iconv(9)?
1557ba4d2eaSTakanori Watanabe */
156f0a08fa9SMark Johnston if (atr->a_datalen >= size * 2 ||
157f0a08fa9SMark Johnston atr->a_datalen % 2 != 0)
158f0a08fa9SMark Johnston break;
1590f90e981SAttilio Rao for (j = 0; j < atr->a_datalen; j++) {
160f0a08fa9SMark Johnston vnchar = ((char *)atr)[atr->a_dataoff + j];
161481b55b1SPawel Jakub Dawidek if (j & 1) {
1627ba4d2eaSTakanori Watanabe if (vnchar) {
1637ba4d2eaSTakanori Watanabe label[0] = 0;
1647ba4d2eaSTakanori Watanabe goto done;
1657ba4d2eaSTakanori Watanabe }
1667ba4d2eaSTakanori Watanabe } else {
1677ba4d2eaSTakanori Watanabe label[j / 2] = vnchar;
1687ba4d2eaSTakanori Watanabe }
1697ba4d2eaSTakanori Watanabe }
1707ba4d2eaSTakanori Watanabe label[j / 2] = 0;
1717ba4d2eaSTakanori Watanabe break;
1727ba4d2eaSTakanori Watanabe }
1737ba4d2eaSTakanori Watanabe }
1747ba4d2eaSTakanori Watanabe done:
1757ba4d2eaSTakanori Watanabe g_free(bf);
1767ba4d2eaSTakanori Watanabe g_free(filerecp);
1777ba4d2eaSTakanori Watanabe }
1787ba4d2eaSTakanori Watanabe
1793ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ntfs = {
1807ba4d2eaSTakanori Watanabe .ld_taste = g_label_ntfs_taste,
181795c5f36SXin LI .ld_dirprefix = "ntfs/",
1823ce9ca89SEdward Tomasz Napierala .ld_enabled = 1
1837ba4d2eaSTakanori Watanabe };
1843ce9ca89SEdward Tomasz Napierala
1853ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ntfs, g_label_ntfs, "Create device nodes for NTFS volumes");
186