Search code examples
go

How do I distinguish an EISDIR error from other errors?


I have a piece of code which tries to write to a path. If that file turns out to already exist and it's a directory, it writes a file to that directory. The code won't overwrite anything existing anyway but I'm not finding an easy to identify that the path is a directory without hitting obvious potential race conditions. I'm aware that there is a race risk because I will be closing and opening but I don't see a way to avoid that. Here's what I have now

fh, err := os.OpenFile(viper.GetString("output"), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0700)
if err != nil {
  // is it a directory? 
  if errors.Is(err, *WHATHERE*) {
     // close and write to a file in that directory
  } else {
     // some other error (like exists)
     return err 
  }
} else {
  // write to the file, we're done
}

I'm happy with all the parts I've replaced with a comment. What I'm trying to work out is if there is a simple way (or standard-library way) to test that the error returned is "is a directory". Have I missed something obvious?


Solution

  • Try without os.O_EXCL:

        fh, err := os.OpenFile(viper.GetString("output"), os.O_CREATE|os.O_WRONLY, 0o700)
        if err != nil {
            var perr *os.PathError
            var errNo syscall.Errno
            if errors.As(err, &perr) && errors.As(perr.Err, &errNo) && errNo == syscall.EISDIR {
                // close and write to a file in that directory
            }
            // ...
        }
        // ...
    

    Also, since PathError.Unwrap returns the underlying error PathError.Err, you can simplify the above to:

            // ...
            if errors.Is(err, syscall.EISDIR) {
                // close and write to a file in that directory
            }
            // ...
    

    When you use O_EXCL, open() returns EEXIST if the path is a directory:

    Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open() fails with the error EEXIST.