Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell if folder exists and is writable?

Tags:

directory

go

I'd like func FolderExists(path string) bool that will tell whether a folder exists and is writable. I've gotten here:

func FolderExists(path string) bool {
    info, err := os.Stat(path)
    return os.IsExist(err) && info.Mode().IsDir() && info.Mode().???
}

How to tell if this folder is writable? I cannot simply check for filemode permissions (e.g. 0200 for user write permission) because then I'd have to check the owner of the file. Is there a straightforward way to do this in Go?

For those with UNIX backgrounds, looking for the equivalent of the very simple:

if [ -d "$n" && -w "$n" ] ; then ... fi
like image 757
Ana Avatar asked Nov 17 '13 02:11

Ana


Video Answer


1 Answers

There's no platform independent way to achieve this because checking whether the user created a directory is not possible on Windows. So, we will implement it differently for Windows and non-Windows system and then use Golang's build constraints to conditionally compile the files depending upon the OS.

Create 3 .go files under directory file-perm as shown -

file-perm /
    file-perm.go
    is-writable.go
    is-writable_windows.go

File : file-perm.go

package main

import (
    "fmt"
)

func main() {
    path := "/tmp/xyz"

    fmt.Println(IsWritable(path))
}

File : is-writable.go

This builds on all platforms except Windows because syscall.Stat_t is not available on Windows. Please note that there needs to be a blank line after the build constraint // +build !windows

// +build !windows

package main

import (
    "fmt"
    "os"
    "syscall"
)

func IsWritable(path string) (isWritable bool, err error) {
    isWritable = false
    info, err := os.Stat(path)
    if err != nil {
        fmt.Println("Path doesn't exist")
        return
    }

    err = nil
    if !info.IsDir() {
        fmt.Println("Path isn't a directory")
        return
    }

    // Check if the user bit is enabled in file permission
    if info.Mode().Perm() & (1 << (uint(7))) == 0 {
        fmt.Println("Write permission bit is not set on this file for user")
        return
    }

    var stat syscall.Stat_t
    if err = syscall.Stat(path, &stat); err != nil {
        fmt.Println("Unable to get stat")
        return
    }

    err = nil
    if uint32(os.Geteuid()) != stat.Uid {
        isWritable = false
        fmt.Println("User doesn't have permission to write to this directory")
        return
    }

    isWritable = true
    return
}

File : is-writable_windows.go

This file will build only on Windows because of the _windows.go suffix in the filename. For more info please refer to https://golang.org/pkg/go/build/

package main

import (
    "fmt"
    "os"
)

func IsWritable(path string) (isWritable bool, err error) {
    isWritable = false
    info, err := os.Stat(path)
    if err != nil {
        fmt.Println("Path doesn't exist")
        return
    }

    err = nil
    if !info.IsDir() {
        fmt.Println("Path isn't a directory")
        return
    }

    // Check if the user bit is enabled in file permission
    if info.Mode().Perm()&(1<<(uint(7))) == 0 {
        fmt.Println("Write permission bit is not set on this file for user")
        return
    }

    isWritable = true
    return
}

Now, you must use go build in file-perm directory and then run the executable. Please note that it won't work with go run.

like image 111
Gautham Avatar answered Sep 27 '22 23:09

Gautham