//go:build !windows // Package chattr https://github.com/g0rbe/go-chattr/pull/3 package chattr /* A package for change attribute of a file on Linux, similar to the chattr command. Example to set the immutable attribute to a file: file, err := os.OpenFile("file.txt", os.O_RDONLY, 0666) if err != nil { panic(err) } defer file.Close() err = chattr.SetAttr(file, chattr.FS_IMMUTABLE_FL) if err != nil { panic(err) } */ import ( "os" "syscall" "unsafe" ) // from /usr/include/linux/fs.h const ( FS_SECRM_FL uint32 = 0x00000001 /* Secure deletion */ FS_UNRM_FL uint32 = 0x00000002 /* Undelete */ FS_COMPR_FL uint32 = 0x00000004 /* Compress file */ FS_SYNC_FL uint32 = 0x00000008 /* Synchronous updates */ FS_IMMUTABLE_FL uint32 = 0x00000010 /* Immutable file */ FS_APPEND_FL uint32 = 0x00000020 /* writes to file may only append */ FS_NODUMP_FL uint32 = 0x00000040 /* do not dump file */ FS_NOATIME_FL uint32 = 0x00000080 /* do not update atime */ FS_DIRTY_FL uint32 = 0x00000100 FS_COMPRBLK_FL uint32 = 0x00000200 /* One or more compressed clusters */ FS_NOCOMP_FL uint32 = 0x00000400 /* Don't compress */ FS_ENCRYPT_FL uint32 = 0x00000800 /* Encrypted file */ FS_BTREE_FL uint32 = 0x00001000 /* btree format dir */ FS_INDEX_FL uint32 = 0x00001000 /* hash-indexed directory */ FS_IMAGIC_FL uint32 = 0x00002000 /* AFS directory */ FS_JOURNAL_DATA_FL uint32 = 0x00004000 /* Reserved for ext3 */ FS_NOTAIL_FL uint32 = 0x00008000 /* file tail should not be merged */ FS_DIRSYNC_FL uint32 = 0x00010000 /* dirsync behaviour (directories only) */ FS_TOPDIR_FL uint32 = 0x00020000 /* Top of directory hierarchies*/ FS_HUGE_FILE_FL uint32 = 0x00040000 /* Reserved for ext4 */ FS_EXTENT_FL uint32 = 0x00080000 /* Extents */ FS_EA_INODE_FL uint32 = 0x00200000 /* Inode used for large EA */ FS_EOFBLOCKS_FL uint32 = 0x00400000 /* Reserved for ext4 */ FS_NOCOW_FL uint32 = 0x00800000 /* Do not cow file */ FS_INLINE_DATA_FL uint32 = 0x10000000 /* Reserved for ext4 */ FS_PROJINHERIT_FL uint32 = 0x20000000 /* Create with parents projid */ FS_RESERVED_FL uint32 = 0x80000000 /* reserved for ext2 lib */ ) // from ioctl_list manpage const ( FS_IOC_GETFLAGS uintptr = 0x80086601 FS_IOC_SETFLAGS uintptr = 0x40086602 ) func ioctl(f *os.File, request uintptr, attrp *uint32) error { argp := uintptr(unsafe.Pointer(attrp)) _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), request, argp) if errno != 0 { return os.NewSyscallError("ioctl", errno) } return nil } // GetAttrs retrieves the attributes of a file. func GetAttrs(f *os.File) (uint32, error) { attr := uint32(1) err := ioctl(f, FS_IOC_GETFLAGS, &attr) return attr, err } // SetAttr sets the given attribute. func SetAttr(f *os.File, attr uint32) error { attrs, err := GetAttrs(f) if err != nil { return err } attrs |= attr return ioctl(f, FS_IOC_SETFLAGS, &attrs) } // UnsetAttr unsets the given attribute. func UnsetAttr(f *os.File, attr uint32) error { attrs, err := GetAttrs(f) if err != nil { return err } attrs ^= attrs & attr return ioctl(f, FS_IOC_SETFLAGS, &attrs) } // IsAttr checks whether the given attribute is set. func IsAttr(f *os.File, attr uint32) (bool, error) { attrs, err := GetAttrs(f) if err != nil { return false, err } if (attrs & attr) != 0 { return true, nil } return false, nil }