//go:build darwin package tempfile import ( "context" "fmt" "os" "os/exec" "strings" "time" "github.com/cenkalti/backoff/v4" "github.com/gopasspw/gopass/pkg/debug" ) var shmDir = "" func tempdirBase() string { return "" } func (t *File) mount(ctx context.Context) error { // create 32MB ramdisk cmd := exec.CommandContext(ctx, "hdid", "-drivekey", "system-image=yes", "-nomount", "ram://32768") cmd.Stderr = os.Stderr debug.Log("CMD: %s %+v", cmd.Path, cmd.Args) cmdout, err := cmd.Output() if err != nil { return fmt.Errorf("failed to create disk with hdid: %w", err) } debug.Log("Output: %s\n", cmdout) p := strings.Split(string(cmdout), " ") if len(p) < 1 { return fmt.Errorf("unhandeled hdid output: %s", string(cmdout)) } t.dev = p[0] // create filesystem on ramdisk cmd = exec.CommandContext(ctx, "newfs_hfs", "-M", "700", t.dev) cmd.Stderr = os.Stderr if debug.IsEnabled() { cmd.Stdout = os.Stdout } debug.Log("CMD: %s %+v", cmd.Path, cmd.Args) if err := cmd.Run(); err != nil { return fmt.Errorf("failed to make filesystem on %s: %w", t.dev, err) } // mount ramdisk cmd = exec.CommandContext(ctx, "diskutil", "mount", "nobrowse", "-mountOptions", "noatime", "-mountpoint", t.dir, t.dev) cmd.Stderr = os.Stderr if debug.IsEnabled() { cmd.Stdout = os.Stdout } debug.Log("CMD: %s %+v", cmd.Path, cmd.Args) if err := cmd.Run(); err != nil { return fmt.Errorf("failed to mount filesystem %s to %s: %w", t.dev, t.dir, err) } // Wait for the mount to settle. This is a hack. time.Sleep(100 * time.Millisecond) return nil } func (t *File) unmount(ctx context.Context) error { bo := backoff.NewExponentialBackOff() bo.MaxElapsedTime = 10 * time.Second return backoff.Retry(func() error { return t.tryUnmount(ctx) }, bo) } func (t *File) tryUnmount(ctx context.Context) error { if t.dir == "" || t.dev == "" { return nil } // unmount ramdisk cmd := exec.CommandContext(ctx, "diskutil", "unmountDisk", t.dev) cmd.Stderr = os.Stderr if debug.IsEnabled() { cmd.Stdout = os.Stdout } debug.Log("CMD: %s %+v", cmd.Path, cmd.Args) if err := cmd.Run(); err != nil { return fmt.Errorf("failed to run command '%+v': %w", cmd.Args, err) } // eject disk cmd = exec.CommandContext(ctx, "diskutil", "quiet", "eject", t.dev) cmd.Stderr = os.Stderr if debug.IsEnabled() { cmd.Stdout = os.Stdout } debug.Log("CMD: %s %+v", cmd.Path, cmd.Args) return cmd.Run() }