From 12de4034c72ea5054d716bf848c2b16bef7a4d89 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 19 Aug 1998 01:49:34 +0000 Subject: Makefile.in: Moved blocking lock code into smbd/blocking.c for link purposes. include/includes.h: Added nterr.h. locking/locking.c: Moved blocking lock code into smbd/blocking.c for link purposes. smbd/close.c: Added blocking lock removal to file close. smbd/filename.c: Tidied up unix_convert() so I could read it (:-) in preparation for the stat_cache code. smbd/nttrans.c: Added WRITE_ATTRIBUTES check. smbd/reply.c: Fixed multibyte char problem in wildcard mask. Jeremy. (This used to be commit 148eaba3dadb1d0bd3ac3ef53da3d9811636e89a) --- source3/Makefile.in | 2 +- source3/include/includes.h | 2 + source3/include/proto.h | 9 +- source3/locking/locking.c | 290 --------------------------------------------- source3/smbd/close.c | 6 +- source3/smbd/filename.c | 254 +++++++++++++++++++++++---------------- source3/smbd/nttrans.c | 5 +- source3/smbd/reply.c | 28 +++-- 8 files changed, 186 insertions(+), 410 deletions(-) (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index dfb2d0e80b..b9fd30d9ba 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -126,7 +126,7 @@ SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/groupname.o smbd/ipc.o smbd/mangle.o smbd/negprot.o \ smbd/message.o smbd/nttrans.o smbd/pipes.o smbd/predict.o \ smbd/quotas.o smbd/reply.o smbd/ssl.o smbd/trans2.o smbd/uid.o \ - smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \ + smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o smbd/blocking.o \ smbd/process.o smbd/oplock.o smbd/service.o smbd/error.o PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/printing.o diff --git a/source3/include/includes.h b/source3/include/includes.h index 3fd5f7be08..a2419bc42c 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -329,6 +329,8 @@ extern int errno; #include "kanji.h" #include "charset.h" +#include "nterr.h" + #ifndef MAXCODEPAGELINES #define MAXCODEPAGELINES 256 #endif diff --git a/source3/include/proto.h b/source3/include/proto.h index 07e3b70dba..9b7267658d 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -480,8 +480,6 @@ char *smb_errstr(char *inbuf); /*The following definitions come from locking/locking.c */ -BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num); -void process_blocking_lock_queue(time_t t); BOOL is_locked(files_struct *fsp,connection_struct *conn, uint32 count,uint32 offset, int lock_type); BOOL do_lock(files_struct *fsp,connection_struct *conn, @@ -1899,6 +1897,13 @@ uint32 lookup_user_rid(char *user_name, uint32 *rid); BOOL api_wkssvc_rpc(pipes_struct *p, prs_struct *data); +/*The following definitions come from smbd/blocking.c */ + +BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num); +void remove_pending_lock_requests_by_fid(files_struct *fsp); +void remove_pending_lock_requests_by_mid(int mid); +void process_blocking_lock_queue(time_t t); + /*The following definitions come from smbd/chgpasswd.c */ BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root); diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 873e382b46..f5e27317b5 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -33,299 +33,9 @@ #include "includes.h" extern int DEBUGLEVEL; -extern int Client; static struct share_ops *share_ops; -#if 0 /* JRATEST - blocking lock code - under development. */ - -/**************************************************************************** - This is the structure to queue to implement blocking locks. - notify. It consists of the requesting SMB and the expiry time. -*****************************************************************************/ - -typedef struct { - ubi_slNode msg_next; - time_t expire_time; - int lock_num; - char *inbuf; - int length; -} blocking_lock_record; - -static ubi_slList blocking_lock_queue = { NULL, (ubi_slNodePtr)&blocking_lock_queue, 0}; - -/**************************************************************************** - Function to push a blocking lockingX request onto the lock queue. -****************************************************************************/ - -BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num) -{ - blocking_lock_record *blr; - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - - /* - * Now queue an entry on the blocking lock queue. We setup - * the expiration time here. - */ - - if((blr = (blocking_lock_record *)malloc(sizeof(blocking_lock_record))) == NULL) { - DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" )); - return False; - } - - if((blr->inbuf = (char *)malloc(length)) == NULL) { - DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" )); - free((char *)blr); - return False; - } - - memcpy(blr->inbuf, inbuf, length); - blr->length = length; - blr->lock_num = lock_num; - blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout; - - ubi_slAddTail(&blocking_lock_queue, blr); - - DEBUG(3,("push_blocking_lock_request: lock request blocked with expiry time %d \ -for fnum = %d, name = %s\n", blr->expire_time, fsp->fnum, fsp->name )); - - return True; -} - -/**************************************************************************** - Return a blocking lock success SMB. -*****************************************************************************/ -static void blocking_lock_reply_success(blocking_lock_record *blr) -{ - extern int chain_size; - extern char *OutBuffer; - char *outbuf = OutBuffer; - int bufsize = BUFFER_SIZE; - char *inbuf = blr->inbuf; - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - int outsize = 0; - - construct_reply_common(inbuf, outbuf); - set_message(outbuf,2,0,True); - - /* - * As this message is a lockingX call we must handle - * any following chained message correctly. - * This is normally handled in construct_reply(), - * but as that calls switch_message, we can't use - * that here and must set up the chain info manually. - */ - - chain_size = 0; - - outsize = chain_reply(inbuf,outbuf,blr->length,bufsize); - - outsize += chain_size; - - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - - send_smb(Client,outbuf); -} - -/**************************************************************************** - Return a lock fail error. Undo all the locks we have obtained first. -*****************************************************************************/ - -static void blocking_lock_reply_error(blocking_lock_record *blr, int eclass, int32 ecode) -{ - extern char *OutBuffer; - char *outbuf = OutBuffer; - int bufsize = BUFFER_SIZE; - char *inbuf = blr->inbuf; - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - uint32 count, offset; - int lock_num = blr->lock_num; - char *data; - int i; - - data = smb_buf(inbuf) + 10*num_ulocks; - - /* - * Data now points at the beginning of the list - * of smb_lkrng structs. - */ - - for(i = blr->lock_num; i >= 0; i--) { - count = IVAL(data,SMB_LKLEN_OFFSET(i)); - offset = IVAL(data,SMB_LKOFF_OFFSET(i)); - do_unlock(fsp,conn,count,offset,&dummy1,&dummy2); - } - - construct_reply_common(inbuf, outbuf); - ERROR(eclass,ecode); - send_smb(Client,outbuf); -} - -/**************************************************************************** - Attempt to finish off getting all pending blocking locks. - Returns True if we want to be removed from the list. -*****************************************************************************/ - -static BOOL blocking_lock_record_process(blocking_lock_record *blr) -{ - char *inbuf = blr->inbuf; - unsigned char locktype = CVAL(inbuf,smb_vwv3); - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - uint32 count, offset; - int lock_num = blr->lock_num; - char *data; - int eclass=0; - uint32 ecode=0; - - data = smb_buf(inbuf) + 10*num_ulocks; - - /* - * Data now points at the beginning of the list - * of smb_lkrng structs. - */ - - for(; blr->lock_num < num_locks; blr->lock_num++) { - count = IVAL(data,SMB_LKLEN_OFFSET(blr->lock_num)); - offset = IVAL(data,SMB_LKOFF_OFFSET(blr->lock_num)); - if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK), - &eclass, &ecode)) - break; - } - - if(blr->lock_num == num_locks) { - - /* - * Success - we got all the locks. - */ - - DEBUG(3,("blocking_lock_record_process fnum=%d type=%d num_locks=%d\n", - fsp->fnum, (unsigned int)locktype, num_locks) ); - - blocking_lock_reply_success(blr); - return True; - - } else if((errno != EACCES) && (errno != EAGAIN)) { - - /* - * We have other than a "can't get lock" POSIX - * error. Free any locks we had and return an error. - * Return True so we get dequeued. - */ - - blocking_lock_reply_error(blr, eclass, ecode); - return True; - } - - /* - * Still can't get all the locks - keep waiting. - */ - - DEBUG(10,("blocking_lock_record_process: only got %d locks of %d needed for fnum = %d. \ -Waiting....\n", blr->lock_num, num_locks, fsp->fnum)); - - return False; -} - -/**************************************************************************** - Process the blocking lock queue. Note that this is only called as root. -*****************************************************************************/ - -void process_blocking_lock_queue(time_t t) -{ - blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst( &blocking_lock_queue ); - blocking_lock_record *prev = NULL; - - if(blr == NULL) - return; - - /* - * Go through the queue and see if we can get any of the locks. - */ - - while(blr != NULL) { - files_struct *fsp = NULL; - uint16 vuid; - - /* - * Ensure we don't have any old chain_fnum values - * sitting around.... - */ - file_chain_reset(); - - fsp = file_fsp(blr->inbuf,smb_vwv2); - vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : - SVAL(blr->inbuf,smb_uid); - - DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n", - fsp->fnum, fsp->name )); - - if((blr->expire_time != -1) && (blr->expire_time > t)) { - /* - * Lock expired - throw away all previously - * obtained locks and return lock error. - */ - DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n", - fsp->fnum, fsp->name )); - - blocking_lock_reply_error(blr,ERRSRV,ERRaccess); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue)); - continue; - } - - if(!become_user(conn,vuid)) { - DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n", - vuid )); - /* - * Remove the entry and return an error to the client. - */ - blocking_lock_reply_error(blr,ERRSRV,ERRaccess); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue)); - continue; - } - - if(!become_service(conn,True)) { - DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) )); - /* - * Remove the entry and return an error to the client. - */ - blocking_lock_reply_error(blr,ERRSRV,ERRaccess); - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue)); - unbecome_user(); - continue; - } - - /* - * Go through the remaining locks and try and obtain them. - * The call returns True if all locks were obtained successfully - * and False if we still need to wait. - */ - - if(blocking_lock_record_process(blr)) { - free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev)); - blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue)); - unbecome_user(); - continue; - } - - unbecome_user(); - - /* - * Move to the next in the list. - */ - prev = blr; - blr = (blocking_lock_record *)ubi_slNext(blr); - } -} -#endif /* JRATEST */ - /**************************************************************************** Utility function to map a lock type correctly depending on the real open mode of a file. diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 9bc0a89338..b8063ca3f4 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -142,6 +142,8 @@ void close_file(files_struct *fsp, BOOL normal_close) string_free(&fsp->fsp_name); } + remove_pending_lock_requests_by_fid(fsp); + file_free(fsp); } @@ -151,10 +153,6 @@ void close_file(files_struct *fsp, BOOL normal_close) void close_directory(files_struct *fsp) { - /* TODO - walk the list of pending - change notify requests and free - any pertaining to this fsp. */ - remove_pending_change_notify_requests_by_fid(fsp); /* diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index a6a9e7e7f0..ab5851fb5e 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -102,6 +102,7 @@ used to pick the correct error code to return between ENOENT and ENOTDIR as Windows applications depend on ERRbadpath being returned if a component of a pathname does not exist. ****************************************************************************/ + BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, BOOL *bad_path) { struct stat st; @@ -115,17 +116,24 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, if(saved_last_component) *saved_last_component = 0; - /* convert to basic unix format - removing \ chars and cleaning it up */ + /* + * Convert to basic unix format - removing \ chars and cleaning it up. + */ + unix_format(name); unix_clean_name(name); - /* names must be relative to the root of the service - trim any leading /. - also trim trailing /'s */ + /* + * Names must be relative to the root of the service - trim any leading /. + * also trim trailing /'s. + */ + trim_string(name,"/","/"); /* * Ensure saved_last_component is valid even if file exists. */ + if(saved_last_component) { end = strrchr(name, '/'); if(end) @@ -138,23 +146,30 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, (!case_preserve || (is_8_3(name, False) && !short_case_preserve))) strnorm(name); - /* check if it's a printer file */ - if (conn->printer) - { - if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) - { - char *s; - fstring name2; - slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine); - /* sanitise the name */ - for (s=name2 ; *s ; s++) - if (!issafe(*s)) *s = '_'; - pstrcpy(name,(char *)mktemp(name2)); - } - return(True); - } + /* + * Check if it's a printer file. + */ + if (conn->printer) { + if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) { + char *s; + fstring name2; + slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine); + + /* + * Sanitise the name. + */ + + for (s=name2 ; *s ; s++) + if (!issafe(*s)) *s = '_'; + pstrcpy(name,(char *)mktemp(name2)); + } + return(True); + } + + /* + * stat the name - if it exists then we are all done! + */ - /* stat the name - if it exists then we are all done! */ if (sys_stat(name,&st) == 0) return(True); @@ -162,109 +177,144 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, DEBUG(5,("unix_convert(%s)\n",name)); - /* a special case - if we don't have any mangling chars and are case - sensitive then searching won't help */ + /* + * A special case - if we don't have any mangling chars and are case + * sensitive then searching won't help. + */ + if (case_sensitive && !is_mangled(name) && !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT)) return(False); - /* now we need to recursively match the name against the real - directory structure */ + /* + * Now we need to recursively match the name against the real + * directory structure. + */ start = name; while (strncmp(start,"./",2) == 0) start += 2; - /* now match each part of the path name separately, trying the names - as is first, then trying to scan the directory for matching names */ - for (;start;start = (end?end+1:(char *)NULL)) - { - /* pinpoint the end of this section of the filename */ + /* + * Match each part of the path name separately, trying the names + * as is first, then trying to scan the directory for matching names. + */ + + for (;start;start = (end?end+1:(char *)NULL)) { + /* + * Pinpoint the end of this section of the filename. + */ end = strchr(start, '/'); - /* chop the name at this point */ - if (end) *end = 0; + /* + * Chop the name at this point. + */ + if (end) + *end = 0; if(saved_last_component != 0) pstrcpy(saved_last_component, end ? end + 1 : start); - /* check if the name exists up to this point */ - if (sys_stat(name, &st) == 0) - { - /* it exists. it must either be a directory or this must be - the last part of the path for it to be OK */ - if (end && !(st.st_mode & S_IFDIR)) - { - /* an intermediate part of the name isn't a directory */ - DEBUG(5,("Not a dir %s\n",start)); - *end = '/'; - return(False); - } - } - else - { - pstring rest; - - *rest = 0; - - /* remember the rest of the pathname so it can be restored - later */ - if (end) pstrcpy(rest,end+1); - - /* try to find this part of the path in the directory */ - if (strchr(start,'?') || strchr(start,'*') || - !scan_directory(dirpath, start, conn, end?True:False)) - { - if (end) - { - /* an intermediate part of the name can't be found */ - DEBUG(5,("Intermediate not found %s\n",start)); - *end = '/'; - /* We need to return the fact that the intermediate - name resolution failed. This is used to return an - error of ERRbadpath rather than ERRbadfile. Some - Windows applications depend on the difference between - these two errors. - */ - *bad_path = True; - return(False); - } + /* + * Check if the name exists up to this point. + */ + if (sys_stat(name, &st) == 0) { + /* + * It exists. it must either be a directory or this must be + * the last part of the path for it to be OK. + */ + if (end && !(st.st_mode & S_IFDIR)) { + /* + * An intermediate part of the name isn't a directory. + */ + DEBUG(5,("Not a dir %s\n",start)); + *end = '/'; + return(False); + } + } else { + pstring rest; + + *rest = 0; + + /* + * Remember the rest of the pathname so it can be restored + * later. + */ + + if (end) + pstrcpy(rest,end+1); + + /* + * Try to find this part of the path in the directory. + */ + if (strchr(start,'?') || strchr(start,'*') || + !scan_directory(dirpath, start, conn, end?True:False)) { + if (end) { + /* + * An intermediate part of the name can't be found. + */ + DEBUG(5,("Intermediate not found %s\n",start)); + *end = '/'; + + /* + * We need to return the fact that the intermediate + * name resolution failed. This is used to return an + * error of ERRbadpath rather than ERRbadfile. Some + * Windows applications depend on the difference between + * these two errors. + */ + *bad_path = True; + return(False); + } - /* just the last part of the name doesn't exist */ - /* we may need to strupper() or strlower() it in case - this conversion is being used for file creation - purposes */ - /* if the filename is of mixed case then don't normalise it */ - if (!case_preserve && - (!strhasupper(start) || !strhaslower(start))) - strnorm(start); - - /* check on the mangled stack to see if we can recover the - base of the filename */ - if (is_mangled(start)) - check_mangled_cache( start ); - - DEBUG(5,("New file %s\n",start)); - return(True); - } - - /* restore the rest of the string */ - if (end) - { - pstrcpy(start+strlen(start)+1,rest); - end = start + strlen(start); - } - } + /* + * Just the last part of the name doesn't exist. + * We may need to strupper() or strlower() it in case + * this conversion is being used for file creation + * purposes. If the filename is of mixed case then + * don't normalise it. + */ + + if (!case_preserve && (!strhasupper(start) || !strhaslower(start))) + strnorm(start); + + /* + * check on the mangled stack to see if we can recover the + * base of the filename. + */ + + if (is_mangled(start)) + check_mangled_cache( start ); + + DEBUG(5,("New file %s\n",start)); + return(True); + } - /* add to the dirpath that we have resolved so far */ - if (*dirpath) pstrcat(dirpath,"/"); + /* + * Restore the rest of the string. + */ + if (end) { + pstrcpy(start+strlen(start)+1,rest); + end = start + strlen(start); + } + } /* end else */ + + /* + * Add to the dirpath that we have resolved so far. + */ + if (*dirpath) pstrcat(dirpath,"/"); pstrcat(dirpath,start); - /* restore the / that we wiped out earlier */ - if (end) *end = '/'; - } + /* + * Restore the / that we wiped out earlier. + */ + if (end) + *end = '/'; + } - /* the name has been resolved */ + /* + * The name has been resolved. + */ DEBUG(5,("conversion finished %s\n",name)); return(True); } diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index b5ed42fbb3..9a9fc51d36 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -321,7 +321,7 @@ static int map_share_mode( uint32 desired_access, uint32 share_access, uint32 fi } if (smb_open_mode == -1) { - if(desired_access & DELETE_ACCESS) + if(desired_access & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) smb_open_mode = 2; else if( desired_access & FILE_EXECUTE) smb_open_mode = 0; @@ -909,12 +909,11 @@ int reply_ntcancel(connection_struct *conn, { /* * Go through and cancel any pending change notifies. - * TODO: When we add blocking locks we will add cancel - * for them here too. */ int mid = SVAL(inbuf,smb_mid); remove_pending_change_notify_requests_by_mid(mid); + remove_pending_lock_requests_by_mid(mid); DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", mid)); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 6b91d9d152..28fed8bc04 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1051,14 +1051,24 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size mask_convert(mask); { - for (p=mask; *p; p++) + int skip; + p = mask; + while(*p) + { + if((skip = skip_multibyte_char( *p )) != 0 ) { - if (*p != '?' && *p != '*' && !isdoschar(*p)) - { - DEBUG(5,("Invalid char [%c] in search mask?\n",*p)); - *p = '?'; - } + p += skip; } + else + { + if (*p != '?' && *p != '*' && !isdoschar(*p)) + { + DEBUG(5,("Invalid char [%c] in search mask?\n",*p)); + *p = '?'; + } + p++; + } + } } if (!strchr(mask,'.') && strlen(mask)>8) @@ -3569,8 +3579,8 @@ dev = %x, inode = %x\n", count = IVAL(data,SMB_LKLEN_OFFSET(i)); offset = IVAL(data,SMB_LKOFF_OFFSET(i)); if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK), - &eclass, &ecode)) -#if 0 /* JRATEST - blocking lock code. */ + &eclass, &ecode)) { +#if 0 /* JRATEST */ if((ecode == ERRlock) && (lock_timeout != 0)) { /* * A blocking lock was requested. Package up @@ -3579,8 +3589,10 @@ dev = %x, inode = %x\n", */ if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) return -1; + } #endif /* JRATEST */ break; + } } /* If any of the above locks failed, then we must unlock -- cgit