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  }