mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
locking.c: Added lock type to is_locked() and do_lock()
as the code in reply_lockingX wasn't taking account of the difference between read and write locks ! How did this ever work :-) ! reply.c: server.c: Add lock type to is_locked() and do_lock(). util.c: Also added code from klausr@ITAP.Physik.Uni-Stuttgart.De to fix problem with log files growing too large if an smbd writes less than 100 debug messages. Jeremy.
This commit is contained in:
parent
339b102222
commit
80080abf77
@ -1149,8 +1149,9 @@ void lp_set_name_resolve_order(char *new_order);
|
||||
|
||||
/*The following definitions come from locking.c */
|
||||
|
||||
BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset);
|
||||
BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
|
||||
BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset, int lock_type);
|
||||
BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int lock_type,
|
||||
int *eclass,uint32 *ecode);
|
||||
BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
|
||||
BOOL locking_init(int read_only);
|
||||
BOOL locking_end(void);
|
||||
@ -1980,6 +1981,7 @@ int sig_usr2(void);
|
||||
int sig_usr1(void);
|
||||
void setup_logging(char *pname,BOOL interactive);
|
||||
void reopen_logs(void);
|
||||
void force_check_log_size(void);
|
||||
char *tmpdir(void);
|
||||
BOOL is_a_socket(int fd);
|
||||
BOOL next_token(char **ptr,char *buff,char *sep);
|
||||
|
@ -184,55 +184,82 @@ void reopen_logs(void)
|
||||
pstring fname;
|
||||
|
||||
if (DEBUGLEVEL > 0)
|
||||
{
|
||||
pstrcpy(fname,debugf);
|
||||
if (lp_loaded() && (*lp_logfile()))
|
||||
pstrcpy(fname,lp_logfile());
|
||||
{
|
||||
pstrcpy(fname,debugf);
|
||||
if (lp_loaded() && (*lp_logfile()))
|
||||
pstrcpy(fname,lp_logfile());
|
||||
|
||||
if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
|
||||
{
|
||||
int oldumask = umask(022);
|
||||
pstrcpy(debugf,fname);
|
||||
if (dbf) fclose(dbf);
|
||||
if (append_log)
|
||||
dbf = fopen(debugf,"a");
|
||||
else
|
||||
dbf = fopen(debugf,"w");
|
||||
if (dbf) setbuf(dbf,NULL);
|
||||
umask(oldumask);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
|
||||
{
|
||||
int oldumask = umask(022);
|
||||
pstrcpy(debugf,fname);
|
||||
if (dbf)
|
||||
{
|
||||
fclose(dbf);
|
||||
dbf = NULL;
|
||||
}
|
||||
fclose(dbf);
|
||||
if (append_log)
|
||||
dbf = fopen(debugf,"a");
|
||||
else
|
||||
dbf = fopen(debugf,"w");
|
||||
/*
|
||||
* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
|
||||
* to fix problem where smbd's that generate less
|
||||
* than 100 messages keep growing the log.
|
||||
*/
|
||||
force_check_log_size();
|
||||
if (dbf)
|
||||
setbuf(dbf,NULL);
|
||||
umask(oldumask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dbf)
|
||||
{
|
||||
fclose(dbf);
|
||||
dbf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Number of debug messages that have been output.
|
||||
Used to check log size.
|
||||
********************************************************************/
|
||||
|
||||
static int debug_count=0;
|
||||
|
||||
/*******************************************************************
|
||||
check if the log has grown too big
|
||||
Force a check of the log size.
|
||||
********************************************************************/
|
||||
|
||||
void force_check_log_size(void)
|
||||
{
|
||||
debug_count = 100;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Check if the log has grown too big
|
||||
********************************************************************/
|
||||
|
||||
static void check_log_size(void)
|
||||
{
|
||||
static int debug_count=0;
|
||||
int maxlog;
|
||||
struct stat st;
|
||||
|
||||
if (debug_count++ < 100 || getuid() != 0) return;
|
||||
if (debug_count++ < 100 || getuid() != 0)
|
||||
return;
|
||||
|
||||
maxlog = lp_max_log_size() * 1024;
|
||||
if (!dbf || maxlog <= 0) return;
|
||||
if (!dbf || maxlog <= 0)
|
||||
return;
|
||||
|
||||
if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
|
||||
fclose(dbf); dbf = NULL;
|
||||
fclose(dbf);
|
||||
dbf = NULL;
|
||||
reopen_logs();
|
||||
if (dbf && file_size(debugf) > maxlog) {
|
||||
pstring name;
|
||||
fclose(dbf); dbf = NULL;
|
||||
fclose(dbf);
|
||||
dbf = NULL;
|
||||
slprintf(name,sizeof(name)-1,"%s.old",debugf);
|
||||
rename(debugf,name);
|
||||
reopen_logs();
|
||||
|
@ -39,11 +39,13 @@ extern files_struct Files[];
|
||||
static struct share_ops *share_ops;
|
||||
|
||||
/****************************************************************************
|
||||
utility function called to see if a file region is locked
|
||||
Utility function called to see if a file region is locked.
|
||||
****************************************************************************/
|
||||
BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
|
||||
|
||||
BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset, int lock_type)
|
||||
{
|
||||
int snum = SNUM(cnum);
|
||||
files_struct *fsp = &Files[fnum];
|
||||
|
||||
if (count == 0)
|
||||
return(False);
|
||||
@ -51,17 +53,22 @@ BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
|
||||
if (!lp_locking(snum) || !lp_strict_locking(snum))
|
||||
return(False);
|
||||
|
||||
return(fcntl_lock(Files[fnum].fd_ptr->fd,F_GETLK,offset,count,
|
||||
(Files[fnum].can_write?F_WRLCK:F_RDLCK)));
|
||||
if((lock_type == F_WRLCK) && !fsp->can_write)
|
||||
lock_type = F_RDLCK;
|
||||
|
||||
return(fcntl_lock(fsp->fd_ptr->fd,F_GETLK,offset,count,lock_type));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
utility function called by locking requests
|
||||
Utility function called by locking requests.
|
||||
****************************************************************************/
|
||||
BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
|
||||
|
||||
BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int lock_type,
|
||||
int *eclass,uint32 *ecode)
|
||||
{
|
||||
BOOL ok = False;
|
||||
files_struct *fsp = &Files[fnum];
|
||||
|
||||
if (!lp_locking(SNUM(cnum)))
|
||||
return(True);
|
||||
@ -72,9 +79,12 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
|
||||
return False;
|
||||
}
|
||||
|
||||
if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
|
||||
ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,
|
||||
(Files[fnum].can_write?F_WRLCK:F_RDLCK));
|
||||
if (OPEN_FNUM(fnum) && fsp->can_lock && (fsp->cnum == cnum)) {
|
||||
if(lock_type == F_WRLCK && !fsp->can_write)
|
||||
lock_type = F_RDLCK;
|
||||
|
||||
ok = fcntl_lock(fsp->fd_ptr->fd,F_SETLK,offset,count,lock_type);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
*eclass = ERRDOS;
|
||||
@ -86,17 +96,19 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
utility function called by unlocking requests
|
||||
Utility function called by unlocking requests.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
|
||||
{
|
||||
BOOL ok = False;
|
||||
files_struct *fsp = &Files[fnum];
|
||||
|
||||
if (!lp_locking(SNUM(cnum)))
|
||||
return(True);
|
||||
|
||||
if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
|
||||
ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,F_UNLCK);
|
||||
if (OPEN_FNUM(fnum) && fsp->can_lock && (fsp->cnum == cnum))
|
||||
ok = fcntl_lock(fsp->fd_ptr->fd,F_SETLK,offset,count,F_UNLCK);
|
||||
|
||||
if (!ok) {
|
||||
*eclass = ERRDOS;
|
||||
@ -109,8 +121,9 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
initialise the locking functions
|
||||
Initialise the locking functions.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL locking_init(int read_only)
|
||||
{
|
||||
if (share_ops) return True;
|
||||
@ -133,8 +146,9 @@ BOOL locking_init(int read_only)
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
deinitialize the share_mode management
|
||||
******************************************************************/
|
||||
Deinitialize the share_mode management.
|
||||
******************************************************************/
|
||||
|
||||
BOOL locking_end(void)
|
||||
{
|
||||
if (share_ops)
|
||||
@ -144,24 +158,27 @@ BOOL locking_end(void)
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
lock a hash bucket entry
|
||||
******************************************************************/
|
||||
Lock a hash bucket entry.
|
||||
******************************************************************/
|
||||
|
||||
BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
|
||||
{
|
||||
return share_ops->lock_entry(cnum, dev, inode, ptok);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
unlock a hash bucket entry
|
||||
******************************************************************/
|
||||
Unlock a hash bucket entry.
|
||||
******************************************************************/
|
||||
|
||||
BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
|
||||
{
|
||||
return share_ops->unlock_entry(cnum, dev, inode, token);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
get all share mode entries for a dev/inode pair.
|
||||
Get all share mode entries for a dev/inode pair.
|
||||
********************************************************************/
|
||||
|
||||
int get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
|
||||
share_mode_entry **shares)
|
||||
{
|
||||
@ -169,42 +186,45 @@ int get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
del the share mode of a file.
|
||||
Del the share mode of a file.
|
||||
********************************************************************/
|
||||
|
||||
void del_share_mode(int token, int fnum)
|
||||
{
|
||||
share_ops->del_entry(token, fnum);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
set the share mode of a file. Return False on fail, True on success.
|
||||
Set the share mode of a file. Return False on fail, True on success.
|
||||
********************************************************************/
|
||||
|
||||
BOOL set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
|
||||
{
|
||||
return share_ops->set_entry(token, fnum, port, op_type);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Remove an oplock port and mode entry from a share mode.
|
||||
Remove an oplock port and mode entry from a share mode.
|
||||
********************************************************************/
|
||||
BOOL remove_share_oplock(int fnum, int token)
|
||||
{
|
||||
return share_ops->remove_oplock(fnum, token);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
call the specified function on each entry under management by the
|
||||
share mode system
|
||||
Call the specified function on each entry under management by the
|
||||
share mode system.
|
||||
********************************************************************/
|
||||
|
||||
int share_mode_forall(void (*fn)(share_mode_entry *, char *))
|
||||
{
|
||||
return share_ops->forall(fn);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
dump the state of the system
|
||||
Dump the state of the system.
|
||||
********************************************************************/
|
||||
|
||||
void share_status(FILE *f)
|
||||
{
|
||||
share_ops->status(f);
|
||||
|
@ -620,12 +620,12 @@ int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
|
||||
p += 8;
|
||||
SIVAL(p,0,fmode); /* File Attributes. */
|
||||
p += 12;
|
||||
if(sizeof(off_t) == 8) {
|
||||
#if OFF_T_IS_64_BITS
|
||||
SIVAL(p,0, file_len & 0xFFFFFFFF);
|
||||
SIVAL(p,4, file_len >> 32);
|
||||
} else {
|
||||
#else /* OFF_T_IS_64_BITS */
|
||||
SIVAL(p,0,file_len);
|
||||
}
|
||||
#endif /* OFF_T_IS_64_BITS */
|
||||
p += 12;
|
||||
SCVAL(p,0,fsp->is_directory ? 1 : 0);
|
||||
}
|
||||
@ -822,12 +822,12 @@ static int call_nt_transact_create(char *inbuf, char *outbuf, int length,
|
||||
p += 8;
|
||||
SIVAL(p,0,fmode); /* File Attributes. */
|
||||
p += 12;
|
||||
if(sizeof(off_t) == 8) {
|
||||
#if OFF_T_IS_64_BITS
|
||||
SIVAL(p,0, file_len & 0xFFFFFFFF);
|
||||
SIVAL(p,4, (file_len >> 32));
|
||||
} else {
|
||||
#else /* OFF_T_IS_64_BITS */
|
||||
SIVAL(p,0,file_len);
|
||||
}
|
||||
#endif /* OFF_T_IS_64_BITS */
|
||||
}
|
||||
|
||||
/* Send the required number of replies */
|
||||
|
@ -1858,7 +1858,7 @@ int reply_readbraw(char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
|
||||
}
|
||||
|
||||
|
||||
if (!is_locked(fnum,cnum,maxcount,startpos))
|
||||
if (!is_locked(fnum,cnum,maxcount,startpos, F_RDLCK))
|
||||
{
|
||||
int size = Files[fnum].size;
|
||||
int sizeneeded = startpos + maxcount;
|
||||
@ -1943,7 +1943,7 @@ int reply_lockread(char *inbuf,char *outbuf, int dum_size, int dum_buffsiz)
|
||||
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
|
||||
data = smb_buf(outbuf) + 3;
|
||||
|
||||
if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
|
||||
if(!do_lock( fnum, cnum, numtoread, startpos, F_RDLCK, &eclass, &ecode))
|
||||
return (ERROR(eclass,ecode));
|
||||
|
||||
nread = read_file(fnum,data,startpos,numtoread);
|
||||
@ -1987,7 +1987,7 @@ int reply_read(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
|
||||
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
|
||||
data = smb_buf(outbuf) + 3;
|
||||
|
||||
if (is_locked(fnum,cnum,numtoread,startpos))
|
||||
if (is_locked(fnum,cnum,numtoread,startpos, F_RDLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
if (numtoread > 0)
|
||||
@ -2035,7 +2035,7 @@ int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
|
||||
set_message(outbuf,12,0,True);
|
||||
data = smb_buf(outbuf);
|
||||
|
||||
if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
|
||||
if (is_locked(fnum,cnum,smb_maxcnt,smb_offs, F_RDLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
nread = read_file(fnum,data,smb_offs,smb_maxcnt);
|
||||
ok = True;
|
||||
@ -2097,7 +2097,7 @@ int reply_writebraw(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
|
||||
CVAL(inbuf,smb_com) = SMBwritec;
|
||||
CVAL(outbuf,smb_com) = SMBwritec;
|
||||
|
||||
if (is_locked(fnum,cnum,tcount,startpos))
|
||||
if (is_locked(fnum,cnum,tcount,startpos, F_WRLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
if (seek_file(fnum,startpos) != startpos)
|
||||
@ -2188,7 +2188,7 @@ int reply_writeunlock(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
|
||||
startpos = IVAL(inbuf,smb_vwv2);
|
||||
data = smb_buf(inbuf) + 3;
|
||||
|
||||
if (is_locked(fnum,cnum,numtowrite,startpos))
|
||||
if (is_locked(fnum,cnum,numtowrite,startpos, F_WRLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
seek_file(fnum,startpos);
|
||||
@ -2243,7 +2243,7 @@ int reply_write(char *inbuf,char *outbuf,int dum_size,int dum_buffsize)
|
||||
startpos = IVAL(inbuf,smb_vwv2);
|
||||
data = smb_buf(inbuf) + 3;
|
||||
|
||||
if (is_locked(fnum,cnum,numtowrite,startpos))
|
||||
if (is_locked(fnum,cnum,numtowrite,startpos, F_WRLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
seek_file(fnum,startpos);
|
||||
@ -2299,7 +2299,7 @@ int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
|
||||
|
||||
data = smb_base(inbuf) + smb_doff;
|
||||
|
||||
if (is_locked(fnum,cnum,smb_dsize,smb_offs))
|
||||
if (is_locked(fnum,cnum,smb_dsize,smb_offs, F_WRLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
seek_file(fnum,smb_offs);
|
||||
@ -2512,7 +2512,7 @@ int reply_writeclose(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
|
||||
mtime = make_unix_date3(inbuf+smb_vwv4);
|
||||
data = smb_buf(inbuf) + 1;
|
||||
|
||||
if (is_locked(fnum,cnum,numtowrite,startpos))
|
||||
if (is_locked(fnum,cnum,numtowrite,startpos, F_WRLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
seek_file(fnum,startpos);
|
||||
@ -2559,7 +2559,7 @@ int reply_lock(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
|
||||
|
||||
DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count));
|
||||
|
||||
if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
|
||||
if(!do_lock( fnum, cnum, count, offset, F_WRLCK, &eclass, &ecode))
|
||||
return (ERROR(eclass,ecode));
|
||||
|
||||
return(outsize);
|
||||
@ -3729,7 +3729,8 @@ dev = %x, inode = %x\n",
|
||||
for(i = 0; i < (int)num_locks; i++) {
|
||||
count = IVAL(data,SMB_LKLEN_OFFSET(i));
|
||||
offset = IVAL(data,SMB_LKOFF_OFFSET(i));
|
||||
if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
|
||||
if(!do_lock(fnum,cnum,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK),
|
||||
&eclass, &ecode))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3796,7 +3797,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
|
||||
tcount = maxcount;
|
||||
total_read = 0;
|
||||
|
||||
if (is_locked(fnum,cnum,maxcount,startpos))
|
||||
if (is_locked(fnum,cnum,maxcount,startpos, F_RDLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
do
|
||||
@ -3858,7 +3859,7 @@ int reply_writebmpx(char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
|
||||
not an SMBwritebmpx - set this up now so we don't forget */
|
||||
CVAL(outbuf,smb_com) = SMBwritec;
|
||||
|
||||
if (is_locked(fnum,cnum,tcount,startpos))
|
||||
if (is_locked(fnum,cnum,tcount,startpos,F_WRLCK))
|
||||
return(ERROR(ERRDOS,ERRlock));
|
||||
|
||||
seek_file(fnum,startpos);
|
||||
|
@ -1948,7 +1948,7 @@ static void truncate_unless_locked(int fnum, int cnum, int token,
|
||||
BOOL *share_locked)
|
||||
{
|
||||
if (Files[fnum].can_write){
|
||||
if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
|
||||
if (is_locked(fnum,cnum,0x3FFFFFFF,0,F_WRLCK)){
|
||||
/* If share modes are in force for this connection we
|
||||
have the share entry locked. Unlock it before closing. */
|
||||
if (*share_locked && lp_share_modes(SNUM(cnum)))
|
||||
@ -2861,6 +2861,20 @@ max can be %d\n", num_interfaces, FD_SETSIZE));
|
||||
return True;
|
||||
}
|
||||
close(Client); /* The parent doesn't need this socket */
|
||||
|
||||
/*
|
||||
* Force parent to check log size after spawning child.
|
||||
* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De.
|
||||
* The parent smbd will log to logserver.smb.
|
||||
* It writes only two messages for each child
|
||||
* started/finished. But each child writes, say, 50 messages also in
|
||||
* logserver.smb, begining with the debug_count of the parent, before the
|
||||
* child opens its own log file logserver.client. In a worst case
|
||||
* scenario the size of logserver.smb would be checked after about
|
||||
* 50*50=2500 messages (ca. 100kb).
|
||||
*/
|
||||
force_check_log_size();
|
||||
|
||||
#endif /* NO_FORK_DEBUG */
|
||||
} /* end for num */
|
||||
} /* end while 1 */
|
||||
|
Loading…
Reference in New Issue
Block a user