// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
// bind mounts.
199845
func parseMountTable(filter FilterFunc) ([]*Info, error) {
	var rawEntries *C.struct_statfs

	count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
	if count == 0 {
		return nil, fmt.Errorf("Failed to call getmntinfo")
	}

	var entries []C.struct_statfs
	header := (*reflect.SliceHeader)(unsafe.Pointer(&entries))
	header.Cap = count
	header.Len = count
	header.Data = uintptr(unsafe.Pointer(rawEntries))

	var out []*Info
	for _, entry := range entries {
		var mountinfo Info
		var skip, stop bool
		mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])

		if filter != nil {
			// filter out entries we're not interested in
			skip, stop = filter(p)
			if skip {
				continue
			}
		}

		mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
		mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])

		out = append(out, &mountinfo)
		if stop {
			break
		}
	}
	return out, nil
}
43133
func checkMountDestination(rootfs, dest string) error {
	invalidDestinations := []string{
		"/proc",
	}
	// White list, it should be sub directories of invalid destinations
	validDestinations := []string{
		// These entries can be bind mounted by files emulated by fuse,
		// so commands like top, free displays stats in container.
		"/proc/cpuinfo",
		"/proc/diskstats",
		"/proc/meminfo",
		"/proc/stat",
		"/proc/net/dev",
	}
	for _, valid := range validDestinations {
		path, err := filepath.Rel(filepath.Join(rootfs, valid), dest)
		if err != nil {
			return err
		}
		if path == "." {
			return nil
		}
	}
	for _, invalid := range invalidDestinations {
		path, err := filepath.Rel(filepath.Join(rootfs, invalid), dest)
		if err != nil {
			return err
		}
		if path == "." || !strings.HasPrefix(path, "..") {
			return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid)
		}

	}
	return nil
}
697976
func (mount *MountInfo) Release() error {
	ret := C.ceph_release(mount.mount)
	if ret != 0 {
		log.Errorf("Release: Failed to release mount")
		return cephError(ret)
	}
	return nil
}
1150604
func IsMountFS(mntType string, mapRoot string) (bool, bool, error) {
	mountInfos, err := GetMountInfo()
	if err != nil {
		return false, false, err
	}

	mounted, mntTypeInstance := isMountFS(mountInfos, mntType, mapRoot)
	return mounted, mntTypeInstance, nil
}
279468
func mounted(mountpoint string) (bool, error) {
	entries, err := parseMountTable()
	if err != nil {
		return false, err
	}

	// Search the table for the mountpoint
	for _, e := range entries {
		if e.MountPoint == mountpoint {
			return true, nil
		}
	}
	return false, nil
}
601496
func (dfs *DistributedFilesystem) TagInfo(tenantID, tagName string) (*SnapshotInfo, error) {
	vol, err := dfs.disk.Get(tenantID)
	if err != nil {
		glog.Errorf("Could not get tenant volume %s: %s", tenantID, err)
		return nil, err
	}
	info, err := vol.GetSnapshotWithTag(tagName)
	if err != nil {
		glog.Errorf("Could not get info for snapshot with tag %s: %s", tagName, err)
		return nil, err
	}
	return readSnapshotInfo(vol, info)
}
1002113
func Lookup(dir string) (Info, error) {
	dir = filepath.Clean(dir)

	mounts, err := Self()
	if err != nil {
		return Info{}, err
	}

	// Sort descending order by Info.Mountpoint
	sort.SliceStable(mounts, func(i, j int) bool {
		return mounts[j].Mountpoint < mounts[i].Mountpoint
	})
	for _, m := range mounts {
		// Note that m.{Major, Minor} are generally unreliable for our purpose here
		// https://www.spinics.net/lists/linux-btrfs/msg58908.html
		// Note that device number is not checked here, because for overlayfs files
		// may have different device number with the mountpoint.
		if strings.HasPrefix(dir, m.Mountpoint) {
			return m, nil
		}
	}

	return Info{}, errors.Errorf("failed to find the mount info for %q", dir)
}
794089
func (web *webAPIHandlers) StorageInfo(r *http.Request, args *WebGenericArgs, reply *StorageInfoRep) error {
	objectAPI := web.ObjectAPI()
	if objectAPI == nil {
		return toJSONError(errServerNotInitialized)
	}
	_, _, authErr := webRequestAuthenticate(r)
	if authErr != nil {
		return toJSONError(authErr)
	}
	reply.StorageInfo = objectAPI.StorageInfo(context.Background())
	reply.UIVersion = browser.UIVersion
	return nil
}
817107
func GetMounts() ([]*mount.Info, error) {
	if os.Getenv(testDeviceEnv) != "" {
		return testGetMounts()
	}
	return mount.GetMounts()
}
491602
func GetCgroupMounts(all bool) ([]Mount, error) {
	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	allSubsystems, err := ParseCgroupFile("/proc/self/cgroup")
	if err != nil {
		return nil, err
	}

	allMap := make(map[string]bool)
	for s := range allSubsystems {
		allMap[s] = false
	}
	return getCgroupMountsHelper(allMap, f, all)
}
981289
func (m *DefaultMounter) Mount(
	source string,
	target string,
	fstype string,
	flags uintptr,
	data string,
	timeout int,
) error {
	return syscall.Mount(source, target, fstype, flags, data)
}
946239
func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) {
	// Field indicators for parsing specific types of data
	const (
		fieldOpts       = "opts:"
		fieldAge        = "age:"
		fieldBytes      = "bytes:"
		fieldEvents     = "events:"
		fieldPerOpStats = "per-op"
		fieldTransport  = "xprt:"
	)

	stats := &MountStatsNFS{
		StatVersion: statVersion,
	}

	for s.Scan() {
		ss := strings.Fields(string(s.Bytes()))
		if len(ss) == 0 {
			break
		}
		if len(ss) < 2 {
			return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
		}

		switch ss[0] {
		case fieldOpts:
			for _, opt := range strings.Split(ss[1], ",") {
				split := strings.Split(opt, "=")
				if len(split) == 2 && split[0] == "mountaddr" {
					stats.MountAddress = split[1]
				}
			}
		case fieldAge:
			// Age integer is in seconds
			d, err := time.ParseDuration(ss[1] + "s")
			if err != nil {
				return nil, err
			}

			stats.Age = d
		case fieldBytes:
			bstats, err := parseNFSBytesStats(ss[1:])
			if err != nil {
				return nil, err
			}

			stats.Bytes = *bstats
		case fieldEvents:
			estats, err := parseNFSEventsStats(ss[1:])
			if err != nil {
				return nil, err
			}

			stats.Events = *estats
		case fieldTransport:
			if len(ss) < 3 {
				return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss)
			}

			tstats, err := parseNFSTransportStats(ss[1:], statVersion)
			if err != nil {
				return nil, err
			}

			stats.Transport = *tstats
		}

		// When encountering "per-operation statistics", we must break this
		// loop and parse them separately to ensure we can terminate parsing
		// before reaching another device entry; hence why this 'if' statement
		// is not just another switch case
		if ss[0] == fieldPerOpStats {
			break
		}
	}

	if err := s.Err(); err != nil {
		return nil, err
	}

	// NFS per-operation stats appear last before the next device entry
	perOpStats, err := parseNFSOperationStats(s)
	if err != nil {
		return nil, err
	}

	stats.Operations = perOpStats

	return stats, nil
}
63629
func Self() ([]Info, error) {
	return nil, fmt.Errorf("mountinfo.Self is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
22276
func parseMountStats(r io.Reader) ([]*Mount, error) {
	const (
		device            = "device"
		statVersionPrefix = "statvers="

		nfs3Type = "nfs"
		nfs4Type = "nfs4"
	)

	var mounts []*Mount

	s := bufio.NewScanner(r)
	for s.Scan() {
		// Only look for device entries in this function
		ss := strings.Fields(string(s.Bytes()))
		if len(ss) == 0 || ss[0] != device {
			continue
		}

		m, err := parseMount(ss)
		if err != nil {
			return nil, err
		}

		// Does this mount also possess statistics information?
		if len(ss) > deviceEntryLen {
			// Only NFSv3 and v4 are supported for parsing statistics
			if m.Type != nfs3Type && m.Type != nfs4Type {
				return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type)
			}

			statVersion := strings.TrimPrefix(ss[8], statVersionPrefix)

			stats, err := parseMountStatsNFS(s, statVersion)
			if err != nil {
				return nil, err
			}

			m.Stats = stats
		}

		mounts = append(mounts, m)
	}

	return mounts, s.Err()
}
1225264
func (dh *DownloadHandler) dirInfo(ctx context.Context, dir blob.Ref) (fi fileInfo, err error) {
	rc, _, err := dh.Fetcher.Fetch(ctx, dir)
	if err != nil {
		return fi, fmt.Errorf("could not fetch %v: %v", dir, err)
	}
	b, err := schema.BlobFromReader(dir, rc)
	rc.Close()
	if err != nil {
		return fi, fmt.Errorf("could not read %v as blob: %v", dir, err)
	}
	tp := b.Type()
	if tp != "directory" {
		return fi, errNotDir
	}
	dr, err := schema.NewDirReader(ctx, dh.Fetcher, dir)
	if err != nil {
		return fi, fmt.Errorf("could not open %v as directory: %v", dir, err)
	}
	children, err := dr.StaticSet(ctx)
	if err != nil {
		return fi, fmt.Errorf("could not get dir entries of %v: %v", dir, err)
	}
	return fileInfo{
		isDir:    true,
		name:     b.FileName(),
		modtime:  b.ModTime(),
		children: children,
	}, nil
}
226873
func (ns NameSpace) stat(ctx context.Context, path string, f func(FileSystem, context.Context, string) (os.FileInfo, error)) (os.FileInfo, error) {
	var err error
	for _, m := range ns.resolve(path) {
		fi, err1 := f(m.fs, ctx, m.translate(path))
		if err1 == nil {
			return fi, nil
		}
		if err == nil {
			err = err1
		}
	}

	// Check if path is an ancestor dir of a mount point.
	if err == nil || os.IsNotExist(err) && len(ns) > 0 {
		for old := range ns {
			if hasPathPrefix(old, path) && old != path {
				return dirInfo(pathpkg.Base(path)), nil
			}
		}
	}

	if err == nil {
		err = &os.PathError{Op: "stat", Path: path, Err: os.ErrNotExist}
	}
	return nil, err
}
684809
func (mts mountInfos) checkCrossMounts(path string) error {
	if !filepath.IsAbs(path) {
		return fmt.Errorf("Invalid argument, path (%s) is expected to be absolute", path)
	}
	var crossMounts mountInfos
	for _, mount := range mts {
		// Add a separator to indicate that this is a proper mount-point.
		// This is to avoid a situation where prefix is '/tmp/fsmount'
		// and mount path is /tmp/fs. In such a scenario we need to check for
		// `/tmp/fs/` to be a common prefix amount other mounts.
		mpath := strings.TrimSuffix(mount.Path, "/") + "/"
		ppath := strings.TrimSuffix(path, "/") + "/"
		if strings.HasPrefix(mpath, ppath) {
			// At this point if the mount point has a common prefix two conditions can happen.
			// - mount.Path matches exact with `path` means we can proceed no error here.
			// - mount.Path doesn't match (means cross-device mount), should error out.
			if mount.Path != path {
				crossMounts = append(crossMounts, mount)
			}
		}
	}
	msg := `Cross-device mounts detected on path (%s) at following locations %s. Export path should not have any sub-mounts, refusing to start.`
	if len(crossMounts) > 0 {
		// if paths didn't match then we do have cross-device mount.
		return fmt.Errorf(msg, path, crossMounts)
	}
	return nil
}