@@ -14,6 +14,7 @@ import (
14
14
15
15
"github.com/moby/sys/mountinfo"
16
16
"github.com/umlx5h/gtrash/internal/env"
17
+ "github.com/yookoala/realpath"
17
18
)
18
19
19
20
type trashDirType string
@@ -238,55 +239,39 @@ func getAllMountpoints() ([]string, error) {
238
239
return mountpoints , nil
239
240
}
240
241
241
- // Obtain a mount point associated with a file
242
+ // Obtain a mount point associated with a file.
242
243
// Same as df <PATH>
243
244
func getMountpoint (path string ) (string , error ) {
244
- // get mountpoints from /proc/self/mountinfo on Linux
245
- // getfsstat(2) used on Mac (BSD)
246
245
247
- fi , err := os .Lstat (path )
246
+ // iterate over the parents of the real (without symlinks) path until we find a mount point
247
+
248
+ candidate , err := realpath .Realpath (path )
248
249
if err != nil {
249
250
return "" , err
250
251
}
251
252
252
- fromInfo , ok := fi .Sys ().(* syscall.Stat_t )
253
- if ! ok {
254
- return "" , fmt .Errorf ("get stat(2) st_dev" )
255
- }
256
-
257
- // this list could contain duplicate (bind) mount paths for the filesystem we are looking for,
258
- // any one of them qualifies as $topdir
259
- mountpoints , err := mountinfo .GetMounts (func (i * mountinfo.Info ) (skip bool , stop bool ) {
260
- // skip bind mounts into subdirectories
261
- if i .Root != "/" {
262
- return true , false
263
- }
264
-
265
- mi , err := os .Stat (i .Mountpoint )
266
- if err != nil {
267
- return true , false
253
+ OUTER:
254
+ for {
255
+ // root is always mounted
256
+ if candidate == string (os .PathSeparator ) {
257
+ slog .Debug ("root mountpoint is detected" , "path" , path )
258
+ break OUTER
268
259
}
269
260
270
- mountInfo , ok := mi .Sys ().(* syscall.Stat_t )
271
- if ! ok {
272
- return true , false
261
+ if candidate == "." {
262
+ // should not reached here
263
+ // check to prevent busy loop
264
+ return "" , errors .New ("mountpoint is '.'" )
273
265
}
274
266
275
- if mountInfo . Dev != fromInfo . Dev {
276
- return true , false
267
+ if mounted , err := mountinfo . Mounted ( candidate ); err == nil && mounted {
268
+ break OUTER
277
269
}
278
270
279
- return false , false
280
- })
281
- if err != nil {
282
- return "" , err
283
- }
284
-
285
- if len (mountpoints ) == 0 {
286
- return "" , fmt .Errorf ("no mount for device %d" , fromInfo .Dev )
271
+ candidate = filepath .Dir (candidate )
287
272
}
288
273
289
- return mountpoints [ 0 ]. Mountpoint , nil
274
+ return candidate , nil
290
275
}
291
276
292
277
func useHomeTrash (path string ) (sameFS bool , err error ) {
0 commit comments