github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/mount/magic.go (about) 1 // Copyright 2021 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build linux 6 // +build linux 7 8 package mount 9 10 import ( 11 "bytes" 12 "fmt" 13 "io" 14 "os" 15 16 "golang.org/x/sys/unix" 17 ) 18 19 const blocksize = 65536 20 21 // These are inferred magic numbers from documents and partitions. 22 // Ones known to work are first, followed by a gap, followed by not 23 // tested ones. Please preserve this pattern. 24 var ( 25 EXT2 = []byte{0x53, 0xef} 26 EXT3 = []byte{0x53, 0xef} 27 EXT4 = []byte{0x53, 0xef} 28 ISOFS = []byte{1, 'C', 'D', '0', '0', '1'} 29 SQUASHFS = []byte{'h', 's', 'q', 's'} 30 XFS = []byte{'X', 'F', 'S', 'B'} 31 // There's no fixed magic number for the different FAT varieties 32 // Usually they start with 0xEB but it's not mandatory. 33 // Therefore we just list a few examples that we have seen in the wild. 34 MSDOS = []byte{0xeb, 0x3c} 35 VFAT = []byte{0xeb, 0x58} 36 // QEMU virtual VFAT 37 VVFAT = []byte{0xeb, 0x3e} 38 39 AAFS = []byte{0x5a, 0x3c, 0x69, 0xf0} 40 ADFS = []byte{0xad, 0xf5} 41 AFFS = []byte{0xad, 0xff} 42 AFS = []byte{0x53, 0x46, 0x41, 0x4F} 43 BDEVFS = []byte{0x62, 0x64, 0x65, 0x76} 44 BINDERFS = []byte{0x6c, 0x6f, 0x6f, 0x70} 45 BINFMTFS = []byte{0x42, 0x49, 0x4e, 0x4d} 46 BPF = []byte{0xca, 0xfe, 0x4a, 0x11} 47 BTRFS = []byte{0x91, 0x23, 0x68, 0x3E} 48 CGROUP = []byte{0x27, 0xe0, 0xeb} 49 CGROUP2 = []byte{0x63, 0x67, 0x72, 0x70} 50 CODA = []byte{0x73, 0x75, 0x72, 0x45} 51 CRAMFS = []byte{0x28, 0xcd, 0x3d, 0x45} 52 CRAMFSOther = []byte{0x45, 0x3d, 0xcd, 0x28} 53 DAXFS = []byte{0x64, 0x64, 0x61, 0x78} 54 DEBUGFS = []byte{0x64, 0x62, 0x67, 0x20} 55 DEVPTS = []byte{0x1c, 0xd1} 56 ECRYPTFS = []byte{0xf1, 0x5f} 57 EFIVARFS = []byte{0xde, 0x5e, 0x81, 0xe4} 58 EFS = []byte{0x41, 0x4A, 0x53} 59 // EXFAT seems to be a samsung file system. 60 // EXFAT = []byte{0x53, 0xef} 61 F2FS = []byte{0xF2, 0xF5, 0x20, 0x10} 62 FUSE = []byte{0x65, 0x73, 0x55, 0x46} 63 FUTEXFS = []byte{0xBA, 0xD1, 0xDE, 0xA} 64 HOSTFS = []byte{0x00, 0xc0, 0xff, 0xee} 65 HPFS = []byte{0xf9, 0x95, 0xe8, 0x49} 66 HUGETLBFS = []byte{0x95, 0x84, 0x58, 0xf6} 67 JFFS2 = []byte{0x72, 0xb6} 68 JFS = []byte{0x31, 0x53, 0x46, 0x4a} 69 MTD = []byte{0x11, 0x30, 0x78, 0x54} 70 NFS = []byte{0x69, 0x69} 71 NILFS = []byte{0x34, 0x34} 72 NSFS = []byte{0x6e, 0x73, 0x66, 0x73} 73 // From docs, not tested. 74 NTFS = []byte{0xeb, 0x52, 0x90, 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' '} 75 OCFS2 = []byte{0x74, 0x61, 0x63, 0x6f} 76 OPENPROM = []byte{0x9f, 0xa1} 77 OVERLAYFS = []byte{0x79, 0x4c, 0x76, 0x30} 78 PIPEFS = []byte{0x50, 0x49, 0x50, 0x45} 79 PROC = []byte{0x9f, 0xa0} 80 PSTOREFS = []byte{0x61, 0x65, 0x67, 0x6C} 81 QNX4 = []byte{0x00, 0x2f} 82 QNX6 = []byte{0x68, 0x19, 0x11, 0x22} 83 RAMFS = []byte{0x85, 0x84, 0x58, 0xf6} 84 RDTGROUP = []byte{0x76, 0x55, 0x82, 1} 85 ROMFS = []byte{0x72, 0x75} 86 SECURITYFS = []byte{0x73, 0x63, 0x66, 0x73} 87 SELINUX = []byte{0xf9, 0x7c, 0xff, 0x8c} 88 SMACK = []byte{0x43, 0x41, 0x5d, 0x53} 89 SMB = []byte{0x51, 0x7B} 90 SOCKFS = []byte{0x53, 0x4F, 0x43, 0x4B} 91 SYSFS = []byte{0x62, 0x65, 0x65, 0x72} 92 TMPFS = []byte{0x01, 0x02, 0x19, 0x94} 93 TRACEFS = []byte{0x74, 0x72, 0x61, 0x63} 94 UBIFS = []byte{0x24, 0x05, 0x19, 0x05} 95 UDF = []byte{0x15, 0x01, 0x33, 0x46} 96 USBDEVICE = []byte{0x9f, 0xa2} 97 V9FS = []byte{0x01, 0x02, 0x19, 0x97} 98 XENFS = []byte{0xab, 0xba, 0x19, 0x74} 99 ZONEFS = []byte{0x5a, 0x4f, 0x46, 0x53} 100 ZSMALLOC = []byte{0x58, 0x29, 0x58, 0x29} 101 ) 102 103 type magic struct { 104 magic []byte 105 off int64 106 name string 107 flags uintptr 108 } 109 110 // magics is just a list of magic structs. 111 // One file system in particular shares a single magic for several types. 112 // For that reason, and reasons of space, this is a list, not a map. 113 // Performance is not really an issue: it is a short list, and there are simply 114 // not enough block devices/file systems for it to really matter. 115 // The ordering for the identical magic number file systems matters: ext4 is more 116 // desirable than ext2, so, we want to find ext4 first. 117 // The order should NOT BE ALPHABETIC, therefore; it should be ordered with known systems 118 // first, and, to break ties, with the most desirable of those systems first. 119 var magics = []magic{ 120 // From the filesystems magic: 121 // 0x438 leshort 0xEF53 Linux 122 {magic: EXT4, name: "ext4", off: 0x438}, 123 {magic: EXT3, name: "ext3", off: 0x438}, 124 {magic: EXT2, name: "ext2", off: 0x438}, 125 // We will always mount vfat; it's backward compatible (we think?) 126 {magic: MSDOS, name: "vfat", off: 0}, 127 {magic: SQUASHFS, name: "squashfs", flags: MS_RDONLY, off: 0}, 128 {magic: ISOFS, name: "iso9660", flags: MS_RDONLY, off: 32768}, 129 {magic: VFAT, name: "vfat", off: 0}, 130 {magic: VVFAT, name: "vfat", off: 0}, 131 {magic: XFS, name: "xfs", off: 0}, 132 } 133 134 var unknownMagics = []magic{ 135 // 136 // here there be dragons. 137 // 138 {magic: V9FS, name: "9p", off: -1}, 139 {magic: ADFS, name: "adfs", off: -1}, 140 {magic: AFFS, name: "affs", off: -1}, 141 {magic: BTRFS, name: "btrfs", off: -1}, 142 {magic: SMB, name: "cifs", off: -1}, 143 {magic: SMB, name: "smb3", off: -1}, 144 {magic: CODA, name: "coda", off: -1}, 145 {magic: DEVPTS, name: "devpts", off: -1}, 146 {magic: ECRYPTFS, name: "ecryptfs", off: -1}, 147 {magic: EFIVARFS, name: "efivarfs", off: -1}, 148 {magic: EFS, name: "efs", off: -1}, 149 {magic: F2FS, name: "f2fs", off: -1}, 150 {magic: FUSE, name: "fuse", off: -1}, 151 // ?? {magic: GFS2, name: "gfs2", off: -1}, 152 // who care ... {magic: HFSPLUS_VOLHEAD_SIG, name: "hfsplus", off: -1}, 153 {magic: HOSTFS, name: "hostfs", off: -1}, 154 {magic: HPFS, name: "hpfs", off: -1}, 155 {magic: HUGETLBFS, name: "hugetlbfs", off: -1}, 156 {magic: JFFS2, name: "jffs2", off: -1}, 157 {magic: JFS, name: "jfs", off: -1}, 158 {magic: NFS, name: "nfs", off: -1}, 159 {magic: NTFS, name: "ntfs", off: -1}, 160 {magic: OPENPROM, name: "openpromfs", off: -1}, 161 {magic: OVERLAYFS, name: "overlay", off: -1}, 162 {magic: PIPEFS, name: "pipefs", off: -1}, 163 {magic: PROC, name: "proc", flags: MS_RDONLY, off: -1}, 164 {magic: PSTOREFS, name: "pstore", off: -1}, 165 {magic: QNX4, name: "qnx4", off: -1}, 166 {magic: QNX6, name: "qnx6", off: -1}, 167 {magic: RAMFS, name: "ramfs", off: -1}, 168 {magic: ROMFS, name: "romfs", flags: MS_RDONLY, off: -1}, 169 {magic: UBIFS, name: "ubifs", flags: MS_RDONLY, off: -1}, 170 {magic: UDF, name: "udf", off: -1}, 171 {magic: ZONEFS, name: "zonefs", off: -1}, 172 } 173 174 // FindMagics finds all the magics matching a magic number. 175 func FindMagics(blk []byte) []magic { 176 b := bytes.NewReader(blk) 177 matches := []magic{} 178 for _, v := range magics { 179 mag := make([]byte, len(v.magic)) 180 if n, err := b.ReadAt(mag, v.off); err != nil || n < len(mag) { 181 continue 182 } 183 if bytes.Equal(v.magic, mag) { 184 matches = append(matches, v) 185 } 186 } 187 return matches 188 } 189 190 // FSFromBlock determines the file system type of a block device. 191 // It returns a string and an error. The error can be for an IO operation, 192 // an unknown magic number, or a magic with an unsupported file system. 193 // There is still a question here about whether this ought to act like 194 // a map and return a bool, not an error, since there are so many bogus 195 // block devices and we don't care about most of them. 196 func FSFromBlock(n string) (fs string, flags uintptr, err error) { 197 // Make sure we can open, read 64k, stat it, find the magic in magics, 198 // and find the file system it names. 199 f, err := os.Open(n) 200 if err != nil { 201 return "", 0, err 202 } 203 defer f.Close() 204 block := make([]byte, blocksize) 205 if _, err := io.ReadAtLeast(f, block, len(block)); err != nil { 206 return "", 0, fmt.Errorf("no suitable filesystem for %q: %v", n, err) 207 } 208 209 magics := FindMagics(block) 210 if len(magics) == 0 { 211 return "", 0, fmt.Errorf("no suitable filesystem for %q", n) 212 } 213 214 for _, m := range magics { 215 if err := FindFileSystem(m.name); err == nil { 216 return m.name, m.flags, nil 217 } 218 } 219 return "", 0, fmt.Errorf("no suitable filesystem for %q, from magics %q", n, magics) 220 } 221 222 // IsTmpRamfs tells if the file path given is under a tmpfs or ramfs. 223 func IsTmpRamfs(path string) (bool, error) { 224 var s unix.Statfs_t 225 if err := unix.Statfs(path, &s); err != nil { 226 return false, err 227 } 228 // Force it to be int64 so that unix.RAMFS_MAGIC won't overflow on an 229 // int32, which is the type for Type on some platforms. 230 t := int64(s.Type) 231 return t == unix.TMPFS_MAGIC || t == unix.RAMFS_MAGIC, nil 232 }