glusterfs
112 строк · 3.5 Кб
1#
2# Copyright (c) 2011-2014 Red Hat, Inc. <http://www.redhat.com>
3# This file is part of GlusterFS.
4
5# This file is licensed to you under your choice of the GNU Lesser
6# General Public License, version 3 or any later version (LGPLv3 or
7# later), or the GNU General Public License, version 2 (GPLv2), in all
8# cases as published by the Free Software Foundation.
9#
10
11import os12from ctypes import CDLL, get_errno13from py2py3 import (bytearray_to_str, gr_create_string_buffer,14gr_query_xattr, gr_lsetxattr, gr_lremovexattr)15
16
17class Xattr(object):18
19"""singleton that wraps the extended attributes system20interface for python using ctypes
21
22Just implement it to the degree we need it, in particular
23- we need just the l*xattr variants, ie. we never want symlinks to be
24followed
25- don't need size discovery for getxattr, as we always know the exact
26sizes we expect
27"""
28
29libc = CDLL("libc.so.6", use_errno=True)30
31@classmethod32def geterrno(cls):33return get_errno()34
35@classmethod36def raise_oserr(cls):37errn = cls.geterrno()38raise OSError(errn, os.strerror(errn))39
40@classmethod41def _query_xattr(cls, path, siz, syscall, *a):42if siz:43buf = gr_create_string_buffer(siz)44else:45buf = None46ret = getattr(cls.libc, syscall)(*((path,) + a + (buf, siz)))47if ret == -1:48cls.raise_oserr()49if siz:50# py2 and py3 compatibility. Convert bytes array51# to string52result = bytearray_to_str(buf.raw)53return result[:ret]54else:55return ret56
57@classmethod58def lgetxattr(cls, path, attr, siz=0):59return gr_query_xattr(cls, path, siz, 'lgetxattr', attr)60
61@classmethod62def lgetxattr_buf(cls, path, attr):63"""lgetxattr variant with size discovery"""64size = cls.lgetxattr(path, attr)65if size == -1:66cls.raise_oserr()67if size == 0:68return ''69return cls.lgetxattr(path, attr, size)70
71@classmethod72def llistxattr(cls, path, siz=0):73ret = gr_query_xattr(cls, path, siz, 'llistxattr')74if isinstance(ret, str):75ret = ret.strip('\0')76ret = ret.split('\0') if ret else []77return ret78
79@classmethod80def lsetxattr(cls, path, attr, val):81ret = gr_lsetxattr(cls, path, attr, val)82if ret == -1:83cls.raise_oserr()84
85@classmethod86def lremovexattr(cls, path, attr):87ret = gr_lremovexattr(cls, path, attr)88if ret == -1:89cls.raise_oserr()90
91@classmethod92def llistxattr_buf(cls, path):93"""listxattr variant with size discovery"""94try:95# Assuming no more than 100 xattrs in a file/directory and96# each xattr key length will be less than 256 bytes97# llistxattr will be called with bigger size so that98# listxattr will not fail with ERANGE. OSError will be99# raised if fails even with the large size specified.100size = 256 * 100101return cls.llistxattr(path, size)102except OSError:103# If fixed length failed for getting list of xattrs then104# use the llistxattr call to get the size and use that105# size to get the list of xattrs.106size = cls.llistxattr(path)107if size == -1:108cls.raise_oserr()109if size == 0:110return []111
112return cls.llistxattr(path, size)113