Find if a file is readable

2,901 views
Skip to first unread message

Kowshik Prakasam

unread,
Sep 14, 2012, 5:51:21 PM9/14/12
to golan...@googlegroups.com
Is there an easier way to find if a file pointed to by a path is readable?

=============
package main

import "os"
import "log"

func isFileReadable(path) bool {
   if entry, err := os.Stat(path); err != nil {
       log.Print("NO => Cant stat file: ", path)
       return false
   }

   if file, err := os.Open(path); err != nil {
           log.Print("NO => Cant open file for reading: ", path)
           return false
    } else {
          if err = file.Close() != nil {
              log.Print("NO => Cant close file: ", path)
              return false
          }
    }
     
   log.Print("YES => file is readable: ", path)
   return true
}
=============




-Kowshik

Greg Ward

unread,
Sep 14, 2012, 5:59:28 PM9/14/12
to Kowshik Prakasam, golan...@googlegroups.com
On 14 September 2012, Kowshik Prakasam said:
> Is there an easier way to find if a file pointed to by a path is readable?

The traditional POSIX call is access(). However, it's prone to race
conditions: between the time you check if a file is readable by
calling access() and then actually open() it, its mode could have
changed. So open() can still fail, so you have to handle the error
there anyways, so why bother with the access() call?

I guess that's why Go's os package doesn't seem to have an Access()
function.

The usual solution is just open() the file and deal with the
consequences. There's no need to stat() it: if open() fails, you can't
read the file.

Disclaimer: I know my way around Unix/C/Python quite well, but I'm a
Go newbie. I might have missed something.

Greg
--
Greg Ward http://www.gerg.ca/
Earn cash in your spare time -- blackmail your friends!

Matt Kane's Brain

unread,
Sep 14, 2012, 7:25:19 PM9/14/12
to Kowshik Prakasam, golan...@googlegroups.com
Calling os.Stat() gives you a FileInfo, which has a method that
returns a FileMode. According to the package docs, you can test the
least significant nine bits for readability.

On UNIX, you can get the owner and group by calling entry.Sys(), which
will return an interface{} that can be type asserted as a
syscall.Stat_t.

fm := entry.FileMode()
if fm & (1 << 2) != 0 {
// yes
} else if (fm & (1 << 5)) && (os.Getegid() ==
int(entry.Sys().(syscall.Stat_t).Gid)) {
// yes
} else if (fm & (1 << 8)) && (os.Geteuid() ==
int(entry.Sys().(syscall.Stat_t).Uid)) {
//yes
}

Windows and Plan 9 have different concrete types behind the FileInfo
interface. You could do a typeswitch maybe to do this all in one
function.
> --
>
>



--
matt kane's brain
http://hydrogenproject.com

Thomas Bushnell, BSG

unread,
Sep 14, 2012, 7:27:25 PM9/14/12
to Matt Kane's Brain, Kowshik Prakasam, golang-nuts
However, that will not actually tell you if you can read the file on Unix.

Many filesystems enforce remote permissions checks or other things (afs, nfs both in different cases). The only reliable way is to actually try to open it.

But even then, it's best not to have a "readable" function for Posix in general, because the answer might change. Best is to open the file when you're actually going to read it, and properly handle errors at that point.

Doing:

if (readable)
  attempt_open()

is only a lose.


--



Reply all
Reply to author
Forward
0 new messages