Repository: gokcehan/lf (language: go)

Issue:
Inaccessible files and directories should be shown in the file listing
In some cases like on NFS the current user may not have permission to access or stat some directories. If you list them with `ls` they will be shown, but cannot be accessed. lf should not hide these directories.

example:
/etc/exports
```
/mnt            10.0.0.0/24(sec=krb5i,ro,fsid=0,no_subtree_check,async,sec=sys,all_squash)
/mnt/data       10.0.0.0/24(sec=krb5i,rw,no_subtree_check,async)
/mnt/backup     10.0.0.0/24(sec=krb5i,rw,no_subtree_check,async)
...
```
The first line allows mounting / both anonymously and authenticated via kerberos, the second and third lines exports other filesystems that can only be accessed as an authenticated user.

if you now mount with `mount -o sec=sys servername:/ /mnt/nfs` then `ls -la` output looks like this:
```
ls: cannot access 'data': Operation not permitted
ls: cannot access 'backup': Operation not permitted
total 12
drwxr-xr-x 6 root root 4096 Sep 10  2021 .
drwxr-xr-x 1 user user   68 Jul 28 17:52 ..
?????????? ? ?    ?       ?            ? backup
?????????? ? ?    ?       ?            ? data
drwxr-xr-x 2 root root 4096 Sep  9  2021 public
drwxr-xr-x 2 root root 4096 Sep 10  2021 public2
```
lf only shows the public and public2 directories.

The same can also happen on corrupted FAT filesystems.


Discussion / hints:
@jantatje Thanks for reporting this. In general, I think this would be an acceptable change, though I'm not sure how this can be implemented. Maybe one could store some dummy values when there is a stat error and show question marks in the ui when there are such dummy values. There could be too many places in the code for these checks though, I'm not sure. If anyone want to give this a try, I think one could start with [the stat error during `readdir` in `nav.go`](https://github.com/gokcehan/lf/blob/dd8294952f3cda8d8671847a5ab4dc3613a2aabd/nav.go#L69).

Fix patch:
diff --git a/nav.go b/nav.go
index 56dab74f..d97087bf 100644
--- a/nav.go
+++ b/nav.go
@@ -37,6 +37,7 @@ type file struct {
 	accessTime time.Time
 	changeTime time.Time
 	ext        string
+	err        error
 }
 
 func (file *file) TotalSize() int64 {
@@ -49,6 +50,17 @@ func (file *file) TotalSize() int64 {
 	return file.Size()
 }
 
+type fakeStat struct {
+	name string
+}
+
+func (fs *fakeStat) Name() string       { return fs.name }
+func (fs *fakeStat) Size() int64        { return 0 }
+func (fs *fakeStat) Mode() os.FileMode  { return os.FileMode(0000) }
+func (fs *fakeStat) ModTime() time.Time { return time.Unix(0, 0) }
+func (fs *fakeStat) IsDir() bool        { return false }
+func (fs *fakeStat) Sys() any           { return nil }
+
 func readdir(path string) ([]*file, error) {
 	f, err := os.Open(path)
 	if err != nil {
@@ -68,6 +80,18 @@ func readdir(path string) ([]*file, error) {
 		}
 		if err != nil {
 			log.Printf("getting file information: %s", err)
+			files = append(files, &file{
+				FileInfo:   &fakeStat{name: fname},
+				linkState:  notLink,
+				linkTarget: "",
+				path:       fpath,
+				dirCount:   -1,
+				dirSize:    -1,
+				accessTime: time.Unix(0, 0),
+				changeTime: time.Unix(0, 0),
+				ext:        filepath.Ext(fpath),
+				err:        err,
+			})
 			continue
 		}
 
@@ -130,6 +154,7 @@ func readdir(path string) ([]*file, error) {
 			accessTime: at,
 			changeTime: ct,
 			ext:        ext,
+			err:        nil,
 		})
 	}
 
diff --git a/ui.go b/ui.go
index c2fa61dd..f85842d6 100644
--- a/ui.go
+++ b/ui.go
@@ -726,6 +726,11 @@ func (ui *ui) loadFileInfo(nav *nav) {
 		return
 	}
 
+	if curr.err != nil {
+		ui.echoerrf("stat: %s", curr.err)
+		return
+	}
+
 	statfmt := strings.ReplaceAll(gOpts.statfmt, "|", "\x1f")
 	replace := func(s string, val string) {
 		if val == "" {


Test patch: