-
Notifications
You must be signed in to change notification settings - Fork 3
/
mount.go
153 lines (121 loc) · 3.24 KB
/
mount.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package aisap
import (
"bufio"
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
xdg "github.com/adrg/xdg"
helpers "github.com/mgord9518/aisap/helpers"
)
// mount mounts the requested AppImage `src` to `dest`
// Quick, hacky implementation, ideally this should be redone using the
// squashfuse library
func mount(src string, dest string, offset int) error {
squashfuse, present := helpers.CommandExists("squashfuse")
if !present {
return errors.New("failed to find squashfuse binary! cannot mount AppImage")
}
// Store the error message in a string
errBuf := &bytes.Buffer{}
// Convert the offset to a string and mount using squashfuse
o := strconv.Itoa(offset)
mnt := exec.Command(squashfuse, "-o", "offset="+o, src, dest)
mnt.Stderr = errBuf
if mnt.Run() != nil {
return errors.New(errBuf.String())
}
return nil
}
// Takes an optional argument to mount at a specific location (failing if it
// doesn't exist or more than one arg given. If none given, automatically
// create a temporary directory and mount to it
func (ai *AppImage) Mount(dest ...string) error {
// If arg given
if len(dest) > 1 {
panic("only one argument allowed with *AppImage.Mount()!")
} else if len(dest) == 1 {
if !helpers.DirExists(dest[0]) {
return NoMountPoint
}
if !isMountPoint(ai.mountDir) {
return mount(ai.Path, ai.mountDir, ai.Offset)
}
return nil
}
var err error
ai.tempDir, err = helpers.MakeTemp(xdg.RuntimeDir+"/aisap/tmp", ai.md5)
if err != nil {
return err
}
ai.mountDir, err = helpers.MakeTemp(xdg.RuntimeDir+"/aisap/mount", ai.md5)
if err != nil {
return err
}
fmt.Println(ai.mountDir)
fmt.Println(ai.tempDir)
// Only mount if no previous instances (launched of the same version) are
// already mounted there. This is to reuse their libraries, save on RAM and
// to spam the mount list as little as possible
if !isMountPoint(ai.mountDir) {
err = mount(ai.Path, ai.mountDir, ai.Offset)
}
return err
}
// Deprecated: *AppImage.Destroy() should be used instead
func (ai *AppImage) Unmount() error {
return ai.Destroy()
}
// Unmounts an AppImage
func (ai *AppImage) Destroy() error {
if ai == nil {
return NilAppImage
} else if ai.Path == "" {
return NoPath
} else if !ai.IsMounted() {
return NotMounted
}
err := unmountDir(ai.MountDir())
if err != nil {
return err
}
ai.mountDir = ""
ai.file.Close()
// Clean up
err = os.RemoveAll(ai.TempDir())
ai = nil
return err
}
func (ai *AppImage) IsMounted() bool {
return ai.mountDir != ""
}
// Unmounts a directory (lazily in case the process is finishing up)
func unmountDir(mntPt string) error {
var umount *exec.Cmd
if _, err := exec.LookPath("fusermount"); err == nil {
umount = exec.Command("fusermount", "-uz", mntPt)
} else {
umount = exec.Command("umount", "-l", mntPt)
}
// Run unmount command, returning the stdout+stderr if fail
out, err := umount.CombinedOutput()
if err != nil {
err = errors.New(string(out))
}
return err
}
// Returns true if directory is detected as already being mounted
func isMountPoint(dir string) bool {
f, _ := os.Open("/proc/self/mountinfo")
scanner := bufio.NewScanner(f)
for scanner.Scan() {
str := strings.Split(scanner.Text(), " ")[4]
if str == dir {
return true
}
}
return false
}