123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- package fuse
- import (
- "errors"
- "strings"
- )
- func dummyOption(conf *mountConfig) error {
- return nil
- }
- // mountConfig holds the configuration for a mount operation.
- // Use it by passing MountOption values to Mount.
- type mountConfig struct {
- options map[string]string
- maxReadahead uint32
- initFlags InitFlags
- osxfuseLocations []OSXFUSEPaths
- }
- func escapeComma(s string) string {
- s = strings.Replace(s, `\`, `\\`, -1)
- s = strings.Replace(s, `,`, `\,`, -1)
- return s
- }
- // getOptions makes a string of options suitable for passing to FUSE
- // mount flag `-o`. Returns an empty string if no options were set.
- // Any platform specific adjustments should happen before the call.
- func (m *mountConfig) getOptions() string {
- var opts []string
- for k, v := range m.options {
- k = escapeComma(k)
- if v != "" {
- k += "=" + escapeComma(v)
- }
- opts = append(opts, k)
- }
- return strings.Join(opts, ",")
- }
- type mountOption func(*mountConfig) error
- // MountOption is passed to Mount to change the behavior of the mount.
- type MountOption mountOption
- // FSName sets the file system name (also called source) that is
- // visible in the list of mounted file systems.
- //
- // FreeBSD ignores this option.
- func FSName(name string) MountOption {
- return func(conf *mountConfig) error {
- conf.options["fsname"] = name
- return nil
- }
- }
- // Subtype sets the subtype of the mount. The main type is always
- // `fuse`. The type in a list of mounted file systems will look like
- // `fuse.foo`.
- //
- // OS X ignores this option.
- // FreeBSD ignores this option.
- func Subtype(fstype string) MountOption {
- return func(conf *mountConfig) error {
- conf.options["subtype"] = fstype
- return nil
- }
- }
- // LocalVolume sets the volume to be local (instead of network),
- // changing the behavior of Finder, Spotlight, and such.
- //
- // OS X only. Others ignore this option.
- func LocalVolume() MountOption {
- return localVolume
- }
- // VolumeName sets the volume name shown in Finder.
- //
- // OS X only. Others ignore this option.
- func VolumeName(name string) MountOption {
- return volumeName(name)
- }
- // NoAppleDouble makes OSXFUSE disallow files with names used by OS X
- // to store extended attributes on file systems that do not support
- // them natively.
- //
- // Such file names are:
- //
- // ._*
- // .DS_Store
- //
- // OS X only. Others ignore this option.
- func NoAppleDouble() MountOption {
- return noAppleDouble
- }
- // NoAppleXattr makes OSXFUSE disallow extended attributes with the
- // prefix "com.apple.". This disables persistent Finder state and
- // other such information.
- //
- // OS X only. Others ignore this option.
- func NoAppleXattr() MountOption {
- return noAppleXattr
- }
- // ExclCreate causes O_EXCL flag to be set for only "truly" exclusive creates,
- // i.e. create calls for which the initiator explicitly set the O_EXCL flag.
- //
- // OSXFUSE expects all create calls to return EEXIST in case the file
- // already exists, regardless of whether O_EXCL was specified or not.
- // To ensure this behavior, it normally sets OpenExclusive for all
- // Create calls, regardless of whether the original call had it set.
- // For distributed filesystems, that may force every file create to be
- // a distributed consensus action, causing undesirable delays.
- //
- // This option makes the FUSE filesystem see the original flag value,
- // and better decide when to ensure global consensus.
- //
- // Note that returning EEXIST on existing file create is still
- // expected with OSXFUSE, regardless of the presence of the
- // OpenExclusive flag.
- //
- // For more information, see
- // https://github.com/osxfuse/osxfuse/issues/209
- //
- // OS X only. Others ignore this options.
- // Requires OSXFUSE 3.4.1 or newer.
- func ExclCreate() MountOption {
- return exclCreate
- }
- // DaemonTimeout sets the time in seconds between a request and a reply before
- // the FUSE mount is declared dead.
- //
- // OS X and FreeBSD only. Others ignore this option.
- func DaemonTimeout(name string) MountOption {
- return daemonTimeout(name)
- }
- var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot")
- // AllowOther allows other users to access the file system.
- //
- // Only one of AllowOther or AllowRoot can be used.
- func AllowOther() MountOption {
- return func(conf *mountConfig) error {
- if _, ok := conf.options["allow_root"]; ok {
- return ErrCannotCombineAllowOtherAndAllowRoot
- }
- conf.options["allow_other"] = ""
- return nil
- }
- }
- // AllowRoot allows other users to access the file system.
- //
- // Only one of AllowOther or AllowRoot can be used.
- //
- // FreeBSD ignores this option.
- func AllowRoot() MountOption {
- return func(conf *mountConfig) error {
- if _, ok := conf.options["allow_other"]; ok {
- return ErrCannotCombineAllowOtherAndAllowRoot
- }
- conf.options["allow_root"] = ""
- return nil
- }
- }
- // AllowDev enables interpreting character or block special devices on the
- // filesystem.
- func AllowDev() MountOption {
- return func(conf *mountConfig) error {
- conf.options["dev"] = ""
- return nil
- }
- }
- // AllowSUID allows set-user-identifier or set-group-identifier bits to take
- // effect.
- func AllowSUID() MountOption {
- return func(conf *mountConfig) error {
- conf.options["suid"] = ""
- return nil
- }
- }
- // DefaultPermissions makes the kernel enforce access control based on
- // the file mode (as in chmod).
- //
- // Without this option, the Node itself decides what is and is not
- // allowed. This is normally ok because FUSE file systems cannot be
- // accessed by other users without AllowOther/AllowRoot.
- //
- // FreeBSD ignores this option.
- func DefaultPermissions() MountOption {
- return func(conf *mountConfig) error {
- conf.options["default_permissions"] = ""
- return nil
- }
- }
- // ReadOnly makes the mount read-only.
- func ReadOnly() MountOption {
- return func(conf *mountConfig) error {
- conf.options["ro"] = ""
- return nil
- }
- }
- // MaxReadahead sets the number of bytes that can be prefetched for
- // sequential reads. The kernel can enforce a maximum value lower than
- // this.
- //
- // This setting makes the kernel perform speculative reads that do not
- // originate from any client process. This usually tremendously
- // improves read performance.
- func MaxReadahead(n uint32) MountOption {
- return func(conf *mountConfig) error {
- conf.maxReadahead = n
- return nil
- }
- }
- // AsyncRead enables multiple outstanding read requests for the same
- // handle. Without this, there is at most one request in flight at a
- // time.
- func AsyncRead() MountOption {
- return func(conf *mountConfig) error {
- conf.initFlags |= InitAsyncRead
- return nil
- }
- }
- // WritebackCache enables the kernel to buffer writes before sending
- // them to the FUSE server. Without this, writethrough caching is
- // used.
- func WritebackCache() MountOption {
- return func(conf *mountConfig) error {
- conf.initFlags |= InitWritebackCache
- return nil
- }
- }
- // OSXFUSEPaths describes the paths used by an installed OSXFUSE
- // version. See OSXFUSELocationV3 for typical values.
- type OSXFUSEPaths struct {
- // Prefix for the device file. At mount time, an incrementing
- // number is suffixed until a free FUSE device is found.
- DevicePrefix string
- // Path of the load helper, used to load the kernel extension if
- // no device files are found.
- Load string
- // Path of the mount helper, used for the actual mount operation.
- Mount string
- // Environment variable used to pass the path to the executable
- // calling the mount helper.
- DaemonVar string
- }
- // Default paths for OSXFUSE. See OSXFUSELocations.
- var (
- OSXFUSELocationV3 = OSXFUSEPaths{
- DevicePrefix: "/dev/osxfuse",
- Load: "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse",
- Mount: "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse",
- DaemonVar: "MOUNT_OSXFUSE_DAEMON_PATH",
- }
- OSXFUSELocationV2 = OSXFUSEPaths{
- DevicePrefix: "/dev/osxfuse",
- Load: "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs",
- Mount: "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
- DaemonVar: "MOUNT_FUSEFS_DAEMON_PATH",
- }
- )
- // OSXFUSELocations sets where to look for OSXFUSE files. The
- // arguments are all the possible locations. The previous locations
- // are replaced.
- //
- // Without this option, OSXFUSELocationV3 and OSXFUSELocationV2 are
- // used.
- //
- // OS X only. Others ignore this option.
- func OSXFUSELocations(paths ...OSXFUSEPaths) MountOption {
- return func(conf *mountConfig) error {
- if len(paths) == 0 {
- return errors.New("must specify at least one location for OSXFUSELocations")
- }
- // replace previous values, but make a copy so there's no
- // worries about caller mutating their slice
- conf.osxfuseLocations = append(conf.osxfuseLocations[:0], paths...)
- return nil
- }
- }
- // AllowNonEmptyMount allows the mounting over a non-empty directory.
- //
- // The files in it will be shadowed by the freshly created mount. By
- // default these mounts are rejected to prevent accidental covering up
- // of data, which could for example prevent automatic backup.
- func AllowNonEmptyMount() MountOption {
- return func(conf *mountConfig) error {
- conf.options["nonempty"] = ""
- return nil
- }
- }
|