#!/usr/bin/env python

""" The Python Unix extended attributes bindings
*********************************************************

This is a Python extension created to manipulate extended attributes
in filesystems that support them.

I am honestly too tired to write documentation or error handling
beyond what I myself might need after this.  Please help me
in this regard.  In the meantime, "man 5 attr" is your friend.

TODO: write a dictionary-style wrapper for file objects or
something like?

"""

__all__ = [ "getfattr","setfattr", "delfattr" ]

from commandsplus import getstatusoutputerror, shell_escape

# maybe we should be strict about what gets into setfattr(...value), it should only be strings maybe, with an assert or value error raised here?

import errno
import os

# thus I Initialize the names codes dictionary
names_codes = {}
for code in errno.errorcode.keys():
	names_codes[os.strerror(code)] = code


def getfattr(file,attrname):
	
	status,output,error = getstatusoutputerror("LANG=C getfattr -n %s --only-values %s"%(shell_escape(attrname),shell_escape(file)))
	
	if status.killed:
		raise Exception, "Error in getfattr: %s"%status
	if status.command_not_found:
		raise Exception, "Error in getfattr: %s"%status
	if status.core_dumped:
		raise Exception, "Error in getfattr: %s"%status
	
	if status.exited:
		for strerror,errcode in names_codes.iteritems():
			emsg = error.strip()[-len(strerror):]
			if output == "" and emsg == strerror:
				raise IOError(errcode,strerror,file)
	
	if status.exited and status.return_value != 0:
		raise Exception, "Error in getfattr: %s: %s"%(status,error)
	
	s = "No such attribute"
	emsg = error.strip()[-len(s):]
	if output == "" and emsg == s:
		raise KeyError, attrname
	
	return output


def setfattr(file,attrname,value):
	status,output,error = getstatusoutputerror("LANG=C setfattr -n %s -v %s %s"%(shell_escape(attrname),shell_escape(value),shell_escape(file)))

	if status.killed:
		raise Exception, "Error in setfattr: %s"%status
	if status.command_not_found:
		raise Exception, "Error in setfattr: %s"%status
	if status.core_dumped:
		raise Exception, "Error in setfattr: %s"%status
	
	if status.exited:
		for strerror,errcode in names_codes.iteritems():
			emsg = error.strip()[-len(strerror):]
			if output == "" and emsg == strerror:
				raise IOError(errcode,strerror,file)
	
	if status.exited and status.return_value != 0:
		raise Exception, "Error in setfattr: %s: %s"%(status,error)


def delfattr(file,attrname):
	status,output,error = getstatusoutputerror("LANG=C setfattr -x %s  %s"%(shell_escape(attrname),shell_escape(file)))
	
	if status.killed:
		raise Exception, "Error in delfattr: %s"%status
	if status.command_not_found:
		raise Exception, "Error in delfattr: %s"%status
	if status.core_dumped:
		raise Exception, "Error in delfattr: %s"%status
	
	if status.exited:
		for strerror,errcode in names_codes.iteritems():
			emsg = error.strip()[-len(strerror):]
			if output == "" and emsg == strerror:
				raise IOError(errcode,strerror,file)
	
	s = "No such attribute"
	emsg = error.strip()[-len(s):]
	if output == "" and emsg == s:
		raise KeyError, attrname
	
	# before the return status checked
	if status.exited and status.return_value != 0:
		raise Exception, "Error in delfattr: %s: %s"%(status,error)
	
	
