github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/util/fsutil/mode.go (about)

     1  // Package fsutil implements filesystem utility functions.
     2  package fsutil
     3  
     4  import (
     5  	"io/fs"
     6  
     7  	"github.com/ncruces/go-sqlite3"
     8  	"github.com/ncruces/go-sqlite3/internal/util"
     9  )
    10  
    11  // ParseFileMode parses a file mode as returned by
    12  // [fs.FileMode.String].
    13  func ParseFileMode(str string) (fs.FileMode, error) {
    14  	var mode fs.FileMode
    15  	err := util.ErrorString("invalid mode: " + str)
    16  
    17  	if len(str) < 10 {
    18  		return 0, err
    19  	}
    20  
    21  	for i, c := range []byte("dalTLDpSugct?") {
    22  		if str[0] == c {
    23  			if len(str) < 10 {
    24  				return 0, err
    25  			}
    26  			mode |= 1 << uint(32-1-i)
    27  			str = str[1:]
    28  		}
    29  	}
    30  
    31  	if mode == 0 {
    32  		if str[0] != '-' {
    33  			return 0, err
    34  		}
    35  		str = str[1:]
    36  	}
    37  	if len(str) != 9 {
    38  		return 0, err
    39  	}
    40  
    41  	for i, c := range []byte("rwxrwxrwx") {
    42  		if str[i] == c {
    43  			mode |= 1 << uint(9-1-i)
    44  		}
    45  		if str[i] != '-' {
    46  			return 0, err
    47  		}
    48  	}
    49  
    50  	return mode, nil
    51  }
    52  
    53  // FileModeFromUnix converts a POSIX mode_t to a file mode.
    54  func FileModeFromUnix(mode fs.FileMode) fs.FileMode {
    55  	const (
    56  		S_IFMT   fs.FileMode = 0170000
    57  		S_IFIFO  fs.FileMode = 0010000
    58  		S_IFCHR  fs.FileMode = 0020000
    59  		S_IFDIR  fs.FileMode = 0040000
    60  		S_IFBLK  fs.FileMode = 0060000
    61  		S_IFREG  fs.FileMode = 0100000
    62  		S_IFLNK  fs.FileMode = 0120000
    63  		S_IFSOCK fs.FileMode = 0140000
    64  	)
    65  
    66  	switch mode & S_IFMT {
    67  	case S_IFDIR:
    68  		mode |= fs.ModeDir
    69  	case S_IFLNK:
    70  		mode |= fs.ModeSymlink
    71  	case S_IFBLK:
    72  		mode |= fs.ModeDevice
    73  	case S_IFCHR:
    74  		mode |= fs.ModeCharDevice | fs.ModeDevice
    75  	case S_IFIFO:
    76  		mode |= fs.ModeNamedPipe
    77  	case S_IFSOCK:
    78  		mode |= fs.ModeSocket
    79  	case S_IFREG, 0:
    80  		//
    81  	default:
    82  		mode |= fs.ModeIrregular
    83  	}
    84  
    85  	return mode &^ S_IFMT
    86  }
    87  
    88  // FileModeFromValue calls [FileModeFromUnix] for numeric values,
    89  // and [ParseFileMode] for textual values.
    90  func FileModeFromValue(val sqlite3.Value) fs.FileMode {
    91  	if n := val.Int64(); n != 0 {
    92  		return FileModeFromUnix(fs.FileMode(n))
    93  	}
    94  	mode, _ := ParseFileMode(val.Text())
    95  	return mode
    96  }