func (h *fshandler) Open(sessionID [16]byte, request *open.Request) (xrdproto.Marshaler, xrdproto.ResponseStatus) {
	var flag int
	if request.Options&xrdfs.OpenOptionsOpenRead != 0 {
		flag |= os.O_RDONLY
	}
	if request.Options&xrdfs.OpenOptionsOpenUpdate != 0 {
		flag |= os.O_RDWR
	}
	if request.Options&xrdfs.OpenOptionsOpenAppend != 0 {
		flag |= os.O_APPEND
	}
	if request.Options&xrdfs.OpenOptionsNew != 0 || request.Options&xrdfs.OpenOptionsDelete != 0 {
		flag |= os.O_CREATE
		if request.Options&xrdfs.OpenOptionsDelete == 0 {
			flag |= os.O_EXCL
		} else {
			flag |= os.O_TRUNC
		}
	}

	filePath := path.Join(h.basePath, request.Path)
	if request.Options&xrdfs.OpenOptionsMkPath != 0 {
		if err := os.MkdirAll(path.Dir(filePath), os.FileMode(request.Mode)); err != nil {
			return xrdproto.ServerError{
				Code:    xrdproto.IOError,
				Message: fmt.Sprintf("An IO error occurred: %v", err),
			}, xrdproto.Error
		}
	}

	file, err := os.OpenFile(filePath, flag, os.FileMode(request.Mode))
	if err != nil {
		return xrdproto.ServerError{
			Code:    xrdproto.IOError,
			Message: fmt.Sprintf("An IO error occurred: %v", err),
		}, xrdproto.Error
	}

	h.mu.RLock()
	sess, ok := h.sessions[sessionID]
	h.mu.RUnlock()
	if !ok {
		h.mu.Lock()
		// Check that there was no change in state during h.mu.RUnlock and h.mu.Lock.
		sess, ok = h.sessions[sessionID]
		if !ok {
			sess = &srvSession{handles: make(map[xrdfs.FileHandle]*os.File)}
			h.sessions[sessionID] = sess
		}
		h.mu.Unlock()
	}

	sess.mu.Lock()
	defer sess.mu.Unlock()
	var handle xrdfs.FileHandle

	// TODO: make handle obtain more deterministic.
	// Right now, we hope that even if 1000000000 of 256*256*256*256 handles are obtained by single user,
	// we have appr. 0.7 probability to find a free handle by the random guess.
	// Then, probability that no free handle is found by 100 tries is something near pow(0.3,100) = 1e-53.
	for i := 0; i < 100; i++ {
		// TODO: use crypto/rand under Windows (4 times faster than math/rand) if handle generation is on the hot path.
		rand.Read(handle[:])
		if _, dup := sess.handles[handle]; !dup {
			resp := open.Response{FileHandle: handle}
			if request.Options&xrdfs.OpenOptionsReturnStatus != 0 {
				st, err := file.Stat()
				if err != nil {
					return xrdproto.ServerError{
						Code:    xrdproto.IOError,
						Message: fmt.Sprintf("An IO error occurred: %v", err),
					}, xrdproto.Error
				}
				es := xrdfs.EntryStatFrom(st)
				resp.Stat = &es
				if request.Options&xrdfs.OpenOptionsCompress == 0 {
					resp.Compression = &xrdfs.FileCompression{}
				}
			}
			// TODO: return compression info if requested.
			sess.handles[handle] = file

			return resp, xrdproto.Ok
		}
	}

	return xrdproto.ServerError{
		Code:    xrdproto.InvalidRequest,
		Message: "handle limit exceeded",
	}, xrdproto.Error
}
// Open implements server.Handler.Open.
Open implements server.Handler.Open.
// Open implements server . Handler . Open .
func (h *fshandler) Open(sessionID [16]byte, request *open.Request) (xrdproto.Marshaler, xrdproto.ResponseStatus) {
	var flag int
	if request.Options&xrdfs.OpenOptionsOpenRead != 0 {
		flag |= os.O_RDONLY
	}
	if request.Options&xrdfs.OpenOptionsOpenUpdate != 0 {
		flag |= os.O_RDWR
	}
	if request.Options&xrdfs.OpenOptionsOpenAppend != 0 {
		flag |= os.O_APPEND
	}
	if request.Options&xrdfs.OpenOptionsNew != 0 || request.Options&xrdfs.OpenOptionsDelete != 0 {
		flag |= os.O_CREATE
		if request.Options&xrdfs.OpenOptionsDelete == 0 {
			flag |= os.O_EXCL
		} else {
			flag |= os.O_TRUNC
		}
	}
	filePath := path.Join(h.basePath, request.Path)
	if request.Options&xrdfs.OpenOptionsMkPath != 0 {
		if err := os.MkdirAll(path.Dir(filePath), os.FileMode(request.Mode)); err != nil {
			return xrdproto.ServerError{
				Code:    xrdproto.IOError,
				Message: fmt.Sprintf("An IO error occurred: %v", err),
			}, xrdproto.Error
		}
	}
	file, err := os.OpenFile(filePath, flag, os.FileMode(request.Mode))
	if err != nil {
		return xrdproto.ServerError{
			Code:    xrdproto.IOError,
			Message: fmt.Sprintf("An IO error occurred: %v", err),
		}, xrdproto.Error
	}
	h.mu.RLock()
	sess, ok := h.sessions[sessionID]
	h.mu.RUnlock()
	if !ok {
		h.mu.Lock()
		sess, ok = h.sessions[sessionID]
		if !ok {
			sess = &srvSession{handles: make(map[xrdfs.FileHandle]*os.File)}
			h.sessions[sessionID] = sess
		}
		h.mu.Unlock()
	}
	sess.mu.Lock()
	defer sess.mu.Unlock()
	var handle xrdfs.FileHandle
	for i := 0; i < 100; i++ {
		rand.Read(handle[:])
		if _, dup := sess.handles[handle]; !dup {
			resp := open.Response{FileHandle: handle}
			if request.Options&xrdfs.OpenOptionsReturnStatus != 0 {
				st, err := file.Stat()
				if err != nil {
					return xrdproto.ServerError{
						Code:    xrdproto.IOError,
						Message: fmt.Sprintf("An IO error occurred: %v", err),
					}, xrdproto.Error
				}
				es := xrdfs.EntryStatFrom(st)
				resp.Stat = &es
				if request.Options&xrdfs.OpenOptionsCompress == 0 {
					resp.Compression = &xrdfs.FileCompression{}
				}
			}
			sess.handles[handle] = file
			return resp, xrdproto.Ok
		}
	}
	return xrdproto.ServerError{
		Code:    xrdproto.InvalidRequest,
		Message: "handle limit exceeded",
	}, xrdproto.Error
}
func ( h * fshandler ) Open ( sessionID [ 16 ] byte , request * open . Request ) ( xrdproto . Marshaler , xrdproto . ResponseStatus ) { var flag int if request . Options & xrdfs . OpenOptionsOpenRead != 0 { flag |= os . O_RDONLY } if request . Options & xrdfs . OpenOptionsOpenUpdate != 0 { flag |= os . O_RDWR } if request . Options & xrdfs . OpenOptionsOpenAppend != 0 { flag |= os . O_APPEND } if request . Options & xrdfs . OpenOptionsNew != 0 || request . Options & xrdfs . OpenOptionsDelete != 0 { flag |= os . O_CREATE if request . Options & xrdfs . OpenOptionsDelete == 0 { flag |= os . O_EXCL } else { flag |= os . O_TRUNC } } filePath := path . Join ( h . basePath , request . Path ) if request . Options & xrdfs . OpenOptionsMkPath != 0 { if err := os . MkdirAll ( path . Dir ( filePath ) , os . FileMode ( request . Mode ) ) ; err != nil { return xrdproto . ServerError { Code : xrdproto . IOError , Message : fmt . Sprintf ( " " , err ) , } , xrdproto . Error } } file , err := os . OpenFile ( filePath , flag , os . FileMode ( request . Mode ) ) if err != nil { return xrdproto . ServerError { Code : xrdproto . IOError , Message : fmt . Sprintf ( " " , err ) , } , xrdproto . Error } h . mu . RLock ( ) sess , ok := h . sessions [ sessionID ] h . mu . RUnlock ( ) if ! ok { h . mu . Lock ( ) sess , ok = h . sessions [ sessionID ] if ! ok { sess = & srvSession { handles : make ( map [ xrdfs . FileHandle ] * os . File ) } h . sessions [ sessionID ] = sess } h . mu . Unlock ( ) } sess . mu . Lock ( ) defer sess . mu . Unlock ( ) var handle xrdfs . FileHandle for i := 0 ; i < 100 ; i ++ { rand . Read ( handle [ : ] ) if _ , dup := sess . handles [ handle ] ; ! dup { resp := open . Response { FileHandle : handle } if request . Options & xrdfs . OpenOptionsReturnStatus != 0 { st , err := file . Stat ( ) if err != nil { return xrdproto . ServerError { Code : xrdproto . IOError , Message : fmt . Sprintf ( " " , err ) , } , xrdproto . Error } es := xrdfs . EntryStatFrom ( st ) resp . Stat = & es if request . Options & xrdfs . OpenOptionsCompress == 0 { resp . Compression = & xrdfs . FileCompression { } } } sess . handles [ handle ] = file return resp , xrdproto . Ok } } return xrdproto . ServerError { Code : xrdproto . InvalidRequest , Message : " " , } , xrdproto . Error }
Open implements server.Handler.Open.
Open implements server . Handler . Open .
// Check that there was no change in state during h.mu.RUnlock and h.mu.Lock. // TODO: make handle obtain more deterministic. // Right now, we hope that even if 1000000000 of 256*256*256*256 handles are obtained by single user, // we have appr. 0.7 probability to find a free handle by the random guess. // Then, probability that no free handle is found by 100 tries is something near pow(0.3,100) = 1e-53. // TODO: use crypto/rand under Windows (4 times faster than math/rand) if handle generation is on the hot path. // TODO: return compression info if requested.