package cephfs /* #cgo LDFLAGS: -lcephfs #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64 #define _GNU_SOURCE #include #include #include #include */ import "C" import ( "unsafe" "github.com/ceph/go-ceph/internal/cutil" "github.com/ceph/go-ceph/internal/retry" ) // XattrFlags are used to control the behavior of set-xattr calls. type XattrFlags int const ( // XattrDefault specifies that set-xattr calls use the default behavior of // creating or updating an xattr. XattrDefault = XattrFlags(0) // XattrCreate specifies that set-xattr calls only set new xattrs. XattrCreate = XattrFlags(C.XATTR_CREATE) // XattrReplace specifies that set-xattr calls only replace existing xattr // values. XattrReplace = XattrFlags(C.XATTR_REPLACE) ) // SetXattr sets an extended attribute on the open file. // // NOTE: Attempting to set an xattr value with an empty value may cause the // xattr to be unset on some older versions of ceph. // Please refer to https://tracker.ceph.com/issues/46084 // // Implements: // int ceph_fsetxattr(struct ceph_mount_info *cmount, int fd, const char *name, // const void *value, size_t size, int flags); func (f *File) SetXattr(name string, value []byte, flags XattrFlags) error { if err := f.validate(); err != nil { return err } if name == "" { return errInvalid } var vptr unsafe.Pointer if len(value) > 0 { vptr = unsafe.Pointer(&value[0]) } cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) ret := C.ceph_fsetxattr( f.mount.mount, f.fd, cName, vptr, C.size_t(len(value)), C.int(flags)) return getError(ret) } // GetXattr gets an extended attribute from the open file. // // Implements: // int ceph_fgetxattr(struct ceph_mount_info *cmount, int fd, const char *name, // void *value, size_t size); func (f *File) GetXattr(name string) ([]byte, error) { if err := f.validate(); err != nil { return nil, err } if name == "" { return nil, errInvalid } cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) var ( ret C.int err error buf []byte ) // range from 1k to 64KiB retry.WithSizes(1024, 1<<16, func(size int) retry.Hint { buf = make([]byte, size) ret = C.ceph_fgetxattr( f.mount.mount, f.fd, cName, unsafe.Pointer(&buf[0]), C.size_t(size)) err = getErrorIfNegative(ret) return retry.DoubleSize.If(err == errRange) }) if err != nil { return nil, err } return buf[:ret], nil } // ListXattr returns a slice containing strings for the name of each xattr set // on the file. // // Implements: // int ceph_flistxattr(struct ceph_mount_info *cmount, int fd, char *list, size_t size); func (f *File) ListXattr() ([]string, error) { if err := f.validate(); err != nil { return nil, err } var ( ret C.int err error buf []byte ) // range from 1k to 64KiB retry.WithSizes(1024, 1<<16, func(size int) retry.Hint { buf = make([]byte, size) ret = C.ceph_flistxattr( f.mount.mount, f.fd, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(size)) err = getErrorIfNegative(ret) return retry.DoubleSize.If(err == errRange) }) if err != nil { return nil, err } names := cutil.SplitSparseBuffer(buf[:ret]) return names, nil } // RemoveXattr removes the named xattr from the open file. // // Implements: // int ceph_fremovexattr(struct ceph_mount_info *cmount, int fd, const char *name); func (f *File) RemoveXattr(name string) error { if err := f.validate(); err != nil { return err } if name == "" { return errInvalid } cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) ret := C.ceph_fremovexattr( f.mount.mount, f.fd, cName) return getError(ret) }