func (obj *DataObj) OpenRW() error {
	var errMsg *C.char
	path := C.CString(obj.path)
	resourceName := C.CString(obj.resource.Name())
	replNum := C.CString(strconv.Itoa(obj.replNum))
	defer C.free(unsafe.Pointer(path))
	defer C.free(unsafe.Pointer(resourceName))
	defer C.free(unsafe.Pointer(replNum))
	ccon := obj.con.GetCcon()
	defer obj.con.ReturnCcon(ccon)
	if status := C.gorods_open_dataobject(path, resourceName, replNum, C.O_RDWR, &obj.chandle, ccon, &errMsg); status != 0 {
		return newError(Fatal, status, fmt.Sprintf("iRODS OpenRW DataObject Failed: %v, %v", obj.path, C.GoString(errMsg)))
	}
	obj.openedAs = C.O_RDWR
	return nil
}
OpenRW opens a connection to iRODS and sets the data object handle for read/write access
package gorods
import "C"
import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unsafe"
)
type DataObj struct {
	path     string
	name     string
	checksum string
	size     int64
	offset   int64
	typ      int
	replNum    int
	rescHier   string
	replStatus int
	dataId   string
	resource *Resource
	phyPath  string
	openedAs C.int
	ownerName string
	owner     *User
	createTime time.Time
	modifyTime time.Time
	metaCol *MetaCollection
	con *Connection
	col *Collection
	chandle C.int
}
type Reader struct {
	d   *DataObj
	pos int64
}
func (r *Reader) Read(p []byte) (n int, err error) {
	var rsp []byte
	readUpTo := len(p)
	rsp, err = r.d.ReadBytes(r.pos, readUpTo)
	n = len(rsp)
	if err == nil {
		copy(p, rsp)
		r.pos += int64(n)
		if n == 0 {
			err = io.EOF
		}
	}
	return
}
type Writer struct {
	d *DataObj
}
func (w *Writer) Write(p []byte) (n int, err error) {
	err = w.d.WriteBytes(p)
	if err == nil {
		n = len(p)
	}
	return
}
type DataObjOptions struct {
	Name     string
	Size     int64
	Mode     int
	Force    bool
	Resource interface{}
}
func (obj *DataObj) String() string {
	return "DataObject: " + obj.path
}
func initDataObj(data *C.collEnt_t, col *Collection, con *Connection) *DataObj {
	dataObj := new(DataObj)
	dataObj.typ = DataObjType
	dataObj.col = col
	dataObj.con = con
	dataObj.offset = 0
	dataObj.name = C.GoString(data.dataName)
	dataObj.path = C.GoString(data.collName) + "/" + dataObj.name
	dataObj.size = int64(data.dataSize)
	dataObj.chandle = C.int(-1)
	dataObj.checksum = C.GoString(data.chksum)
	dataObj.dataId = C.GoString(data.dataId)
	dataObj.phyPath = C.GoString(data.phyPath)
	dataObj.openedAs = C.int(-1)
	dataObj.replNum = int(data.replNum)
	dataObj.rescHier = C.GoString(data.resc_hier)
	dataObj.replStatus = int(data.replStatus)
	dataObj.ownerName = C.GoString(data.ownerName)
	dataObj.createTime = cTimeToTime(data.createTime)
	dataObj.modifyTime = cTimeToTime(data.modifyTime)
	if rsrcs, err := dataObj.con.Resources(); err != nil {
		return nil
	} else {
		if r := rsrcs.FindByName(C.GoString(data.resource)); r != nil {
			dataObj.resource = r
		}
	}
	if usrs, err := dataObj.con.Users(); err != nil {
		return nil
	} else {
		if u := usrs.FindByName(dataObj.ownerName, dataObj.con); u != nil {
			dataObj.owner = u
		}
	}
	return dataObj
}
func getDataObjByParentCollection(startPath string, con *Connection) (*DataObj, error) {
	collectionDir := filepath.Dir(startPath)
	dataObjName := filepath.Base(startPath)
	opts := CollectionOptions{
		Path:      collectionDir,
		Recursive: false,
	}
	if col, err := con.Collection(opts); err == nil {
		if obj := col.FindObj(dataObjName); obj != nil {
			return obj, nil
		} else {
			return nil, newError(Fatal, -1, fmt.Sprintf("Can't find DataObj within collection %v", collectionDir))
		}
	} else {
		return nil, err
	}
}
func getDataObj(startPath string, con *Connection) (*DataObj, error) {
	var cObjData C.collEnt_t
	ccon := con.GetCcon()
	cPath := C.CString(startPath)
	defer C.free(unsafe.Pointer(cPath))
	if status := C.gorods_get_dataobject(ccon, cPath, &cObjData); status < 0 {
		con.ReturnCcon(ccon)
		return nil, newError(Fatal, -1, fmt.Sprintf("Error getting data object at %v", startPath))
	}
	con.ReturnCcon(ccon)
	collectionDir := filepath.Dir(startPath)
	opts := CollectionOptions{
		Path:      collectionDir,
		Recursive: false,
	}
	if col, err := con.Collection(opts); err == nil {
		return initDataObj(&cObjData, col, con), nil
	} else {
		return initDataObj(&cObjData, nil, con), nil
	}
}
func CreateDataObj(opts DataObjOptions, coll *Collection) (*DataObj, error) {
	var (
		errMsg   *C.char
		handle   C.int
		force    int
		resource *C.char
	)
	if opts.Force {
		force = 1
	} else {
		force = 0
	}
	if opts.Resource != nil {
		switch opts.Resource.(type) {
		case string:
			resource = C.CString(opts.Resource.(string))
		case *Resource:
			r := opts.Resource.(*Resource)
			resource = C.CString(r.Name())
		default:
			return nil, newError(Fatal, -1, fmt.Sprintf("Wrong variable type passed in Resource field"))
		}
	} else {
		resource = C.CString("")
	}
	path := C.CString(coll.path + "/" + opts.Name)
	defer C.free(unsafe.Pointer(path))
	defer C.free(unsafe.Pointer(resource))
	ccon := coll.con.GetCcon()
	if status := C.gorods_create_dataobject(path, C.rodsLong_t(opts.Size), C.int(opts.Mode), C.int(force), resource, &handle, ccon, &errMsg); status != 0 {
		coll.con.ReturnCcon(ccon)
		return nil, newError(Fatal, status, fmt.Sprintf("iRODS Create DataObject Failed: %v, Does the file already exist?", C.GoString(errMsg)))
	}
	coll.con.ReturnCcon(ccon)
	if do, err := getDataObj(C.GoString(path), coll.con); err != nil {
		return nil, err
	} else {
		return do, nil
	}
}
func (obj *DataObj) init() error {
	if int(obj.chandle) < 0 {
		return obj.Open()
	}
	return nil
}
func (obj *DataObj) initRW() error {
	if int(obj.chandle) < 0 {
		return obj.OpenRW()
	}
	return nil
}
func (obj *DataObj) Reader() *Reader {
	return &Reader{obj, int64(0)}
}
func (obj *DataObj) Writer() *Writer {
	return &Writer{obj}
}
func (obj *DataObj) ACL() (ACLs, error) {
	var (
		result   C.goRodsACLResult_t
		err      *C.char
		zoneHint *C.char
	)
	zone, zErr := obj.con.LocalZone()
	if zErr != nil {
		return nil, zErr
	} else {
		zoneHint = C.CString(zone.Name())
	}
	cDataId := C.CString(obj.dataId)
	defer C.free(unsafe.Pointer(cDataId))
	defer C.free(unsafe.Pointer(zoneHint))
	ccon := obj.con.GetCcon()
	if status := C.gorods_get_dataobject_acl(ccon, cDataId, &result, zoneHint, &err); status != 0 {
		obj.con.ReturnCcon(ccon)
		return nil, newError(Fatal, status, fmt.Sprintf("iRODS Get Data Object ACL Failed: %v", C.GoString(err)))
	}
	obj.con.ReturnCcon(ccon)
	return aclSliceToResponse(&result, obj.con)
}
func (obj *DataObj) Chmod(userOrGroup string, accessLevel int, recursive bool) error {
	return chmod(obj, userOrGroup, accessLevel, false, true)
}
func (obj *DataObj) GrantAccess(userOrGroup AccessObject, accessLevel int, recursive bool) error {
	return chmod(obj, userOrGroup.Name(), accessLevel, false, true)
}
func (obj *DataObj) Handle() int {
	return int(obj.chandle)
}
func (obj *DataObj) Type() int {
	return obj.typ
}
func (obj *DataObj) Con() *Connection {
	return obj.con
}
func (obj *DataObj) Name() string {
	return obj.name
}
func (obj *DataObj) Path() string {
	return obj.path
}
func (obj *DataObj) Col() *Collection {
	return obj.col
}
func (obj *DataObj) OwnerName() string {
	return obj.ownerName
}
func (obj *DataObj) Owner() *User {
	return obj.owner
}
func (obj *DataObj) Resource() *Resource {
	return obj.resource
}
func (obj *DataObj) DataId() string {
	return obj.dataId
}
func (obj *DataObj) PhyPath() string {
	return obj.phyPath
}
func (obj *DataObj) ReplNum() int {
	return obj.replNum
}
func (obj *DataObj) RescHier() string {
	return obj.rescHier
}
func (obj *DataObj) ReplStatus() int {
	return obj.replStatus
}
func (obj *DataObj) Checksum() string {
	return obj.checksum
}
func (obj *DataObj) Offset() int64 {
	return obj.offset
}
func (obj *DataObj) Size() int64 {
	return obj.size
}
func (obj *DataObj) Mode() os.FileMode {
	return 0644
}
func (obj *DataObj) ModTime() time.Time {
	return obj.ModifyTime()
}
func (obj *DataObj) IsDir() bool {
	return false
}
func (obj *DataObj) Sys() interface{} {
	return nil
}
func (obj *DataObj) CreateTime() time.Time {
	return obj.createTime
}
func (obj *DataObj) ModifyTime() time.Time {
	return obj.modifyTime
}
func (obj *DataObj) Destroy() error {
	return obj.Rm(true, true)
}
func (obj *DataObj) Delete(recursive bool) error {
	return obj.Rm(recursive, true)
}
func (obj *DataObj) Trash(recursive bool) error {
	return obj.Rm(recursive, false)
}
func (obj *DataObj) Rm(recursive bool, force bool) error {
	var errMsg *C.char
	path := C.CString(obj.path)
	defer C.free(unsafe.Pointer(path))
	var (
		cForce     C.int
		cRecursive C.int
	)
	if force {
		cForce = C.int(1)
	}
	if recursive {
		cRecursive = C.int(1)
	}
	ccon := obj.con.GetCcon()
	defer obj.con.ReturnCcon(ccon)
	if status := C.gorods_rm(path, 0, cRecursive, cForce, C.int(0), ccon, &errMsg); status != 0 {
		return newError(Fatal, status, fmt.Sprintf("iRODS Rm DataObject Failed: %v", C.GoString(errMsg)))
	}
	return nil
}
func (obj *DataObj) RmTrash() error {
	var errMsg *C.char
	path := C.CString(obj.path)
	defer C.free(unsafe.Pointer(path))
	ccon := obj.con.GetCcon()
	defer obj.con.ReturnCcon(ccon)
	if status := C.gorods_rm(path, C.int(0), C.int(1), C.int(1), C.int(1), ccon, &errMsg); status != 0 {
		return newError(Fatal, status, fmt.Sprintf("iRODS RmTrash DataObject Failed: %v", C.GoString(errMsg)))
	}
	return nil
}
func (obj *DataObj) Open() error {
	var errMsg *C.char
	path := C.CString(obj.path)
	resourceName := C.CString(obj.resource.Name())
	replNum := C.CString(strconv.Itoa(obj.replNum))
	defer C.free(unsafe.Pointer(path))
	defer C.free(unsafe.Pointer(resourceName))
	defer C.free(unsafe.Pointer(replNum))
	ccon := obj.con.GetCcon()
	defer obj.con.ReturnCcon(ccon)
	if status := C.gorods_open_dataobject(path, resourceName, replNum, C.O_RDONLY, &obj.chandle, ccon, &errMsg); status != 0 {
		return newError(Fatal, status, fmt.Sprintf("iRODS Open DataObject Failed: %v, %v", obj.path, C.GoString(errMsg)))
	}
	obj.openedAs = C.O_RDONLY
	return nil
}