reworked path parse engine
This commit is contained in:
parent
488c23e932
commit
5cc1497967
24
ChangeLog
24
ChangeLog
|
|
@ -1,3 +1,27 @@
|
|||
Version NEXT
|
||||
PROTOCOL updated. Made rules about breaking directory header on
|
||||
packet boundary more clear. Previous text was from fspd code comment
|
||||
and was bad.
|
||||
fixed tests/mklargefile.py
|
||||
log uploads to wuftpd logfile also
|
||||
PROTOCOL file updated. Added required commands section.
|
||||
PROTOCOL file updated. Added recommended delay management section.
|
||||
default delay in clients adjusted from 1.5 to 1.34 sec as recommended
|
||||
in PROTOCOL
|
||||
support for MIN_DELAY, MAX_DELAY and DEFAULT_DELAY in source
|
||||
path parsing moved to separate file server/path.c
|
||||
new test tool parsecheck
|
||||
reworked parse path: separate error messages for high bit chars,
|
||||
control chars
|
||||
do not segfault when parsing password protected files. Looks like
|
||||
nobody used password protected files for a long time. This means
|
||||
that in future version of FSP I can change protocol definition
|
||||
without worry about breaking anything
|
||||
path with trailing / or starting / is now parsed correctly
|
||||
pathes with dot after slash are now detected at parse level (side
|
||||
effect of prev. fix)
|
||||
tests moved from server/ into tests/ directory
|
||||
|
||||
Version 2.8.1b17 -- 17 Nov 2003
|
||||
Allow filenames with spaces inside
|
||||
check for fork() and setsid() in configure.ac
|
||||
|
|
|
|||
5
TODO
5
TODO
|
|
@ -59,7 +59,7 @@ bind-ip-address for server (and client via FSP_LOCAL_IP)
|
|||
report number of clients connected, size of hostable in new command
|
||||
CC_INFO command
|
||||
special defence against rapid/double fire clients
|
||||
new common log format
|
||||
common log format - replace custom fspd log
|
||||
|
||||
:midle:may not be in 2.8.2
|
||||
Native Supports for symbolic links (needed for mirroring Debian)
|
||||
|
|
@ -80,6 +80,7 @@ PERFORMANCE:
|
|||
host hashtable shrinking sometimes
|
||||
stat cache pro FSP_STAT a ostatni
|
||||
background time() alarm() caller
|
||||
Current performance 1925648b/s
|
||||
|
||||
MAN:
|
||||
update FAQ - urgent!!
|
||||
|
|
@ -93,4 +94,4 @@ FSP plugin do Netscape/MSIE
|
|||
FSP library for Java
|
||||
Transfer HTTP over fsp transport
|
||||
FSP backend for APT
|
||||
FSP support to lftp
|
||||
FSP support to lftp,wget,curl
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ static unsigned short key;
|
|||
|
||||
int client_trace = 0;
|
||||
int client_intr_state = 0;
|
||||
unsigned long target_delay = MIN_DELAY; /* expected max delay */
|
||||
unsigned long busy_delay = MIN_DELAY; /* busy retransmit timer */
|
||||
unsigned long idle_delay = MIN_DELAY; /* idle retransmit timer */
|
||||
unsigned long target_delay = DEFAULT_DELAY; /* expected max delay */
|
||||
unsigned long busy_delay = DEFAULT_DELAY; /* busy retransmit timer */
|
||||
unsigned long idle_delay = DEFAULT_DELAY; /* idle retransmit timer */
|
||||
unsigned long udp_sent_time;
|
||||
|
||||
UBUF *client_interact PROTO6(unsigned char, cmd, unsigned long, pos,
|
||||
|
|
@ -79,7 +79,8 @@ UBUF *client_interact PROTO6(unsigned char, cmd, unsigned long, pos,
|
|||
case 1:
|
||||
busy_delay = busy_delay * 3 / 2;
|
||||
w_delay = busy_delay;
|
||||
if(client_trace) write(2,"R",1); break;
|
||||
if(client_trace) write(2,"R",1);
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef CLIENT_TIMEOUT
|
||||
|
|
|
|||
|
|
@ -448,6 +448,7 @@ static void util_get_env PROTO0((void))
|
|||
|
||||
if( (p = getenv("FSP_DELAY")) ) target_delay = atol(p);
|
||||
if(target_delay < MIN_DELAY) target_delay = MIN_DELAY;
|
||||
if(target_delay > MAX_DELAY) target_delay = MAX_DELAY;
|
||||
|
||||
if(!(env_local_dir = getenv("FSP_LOCAL_DIR"))) env_local_dir=".";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
dnl Process this file with autoconf to produce a working configure script.
|
||||
dnl tested with autoconf 2.57
|
||||
AC_INIT(fsp,2.8.1b17,hsn@cybermail.net)
|
||||
AC_INIT(fsp,2.8.1b17+cvs,hsn@cybermail.net)
|
||||
AC_CONFIG_SRCDIR(server/main.c)
|
||||
AM_INIT_AUTOMAKE([dist-bzip2])
|
||||
AM_MAINTAINER_MODE
|
||||
|
|
@ -53,10 +53,10 @@ then
|
|||
-Wimplicit -Wsequence-point -Wreturn-type \
|
||||
-Wfloat-equal $addopts \
|
||||
-Wno-system-headers -Wredundant-decls \
|
||||
-Wmissing-noreturn -Wconversion -pedantic \
|
||||
-Wmissing-noreturn -pedantic \
|
||||
-Wlong-long -Wundef -Winline \
|
||||
-Wno-unused-parameter
|
||||
# -Wunreachable-code
|
||||
# -Wunreachable-code -Wconversion
|
||||
do
|
||||
if $CC $i $ac_cv_prog_gcc_flags -c configure-dummy.c >/dev/null 2>&1
|
||||
then ac_cv_prog_gcc_flags="$ac_cv_prog_gcc_flags $i"
|
||||
|
|
|
|||
27
doc/PROTOCOL
27
doc/PROTOCOL
|
|
@ -1,8 +1,8 @@
|
|||
File Service Protocol (FSP)
|
||||
definition
|
||||
File Service Protocol version 2
|
||||
specification
|
||||
|
||||
Document version 0.8
|
||||
Last updated 29 Sep 2003
|
||||
Document version 0.9
|
||||
Last updated 18 Nov 2003
|
||||
|
||||
Also known as
|
||||
File Slurping Protocol,
|
||||
|
|
@ -72,7 +72,10 @@ by server.
|
|||
TIMEOUTS
|
||||
Resends:
|
||||
Server will accept resent message from client with old KEY after 3 seconds.
|
||||
Client MUST wait at least 1 second before resending a message.
|
||||
Client MUST wait at least 1 second before resending a message.
|
||||
It is recommended to use initial delay of 1.34 second and after each
|
||||
unsuccessfull resend multiply delay time by 1.5. Maximum recommended delay
|
||||
time is 300 seconds.
|
||||
Session:
|
||||
Server will accept message with bad key after 60 seconds. Clients should
|
||||
sent CC_BYE at end of their session, CC_BYE terminates a session.
|
||||
|
|
@ -82,7 +85,7 @@ SEQUENCE
|
|||
Similarly, the server's message to client contains a SEQUENCE value
|
||||
that is the same as the SEQUENCE value of the previous message from the client.
|
||||
Client can choose any SEQUENCE number and can use it for detection of lost
|
||||
packets (increase sequence number on retry).
|
||||
packets (increase sequence number on message resend).
|
||||
|
||||
DATA_LENGTH
|
||||
Size of DATA field in packet. Packet can also contain XTRA DATA field but
|
||||
|
|
@ -96,6 +99,16 @@ data.
|
|||
FSP COMMANDS
|
||||
============
|
||||
|
||||
REQUIRED COMMANDS
|
||||
FSP File servers MUST supports following commands:
|
||||
- sending error messages back to client with CC_ERR
|
||||
- directory listings CC_GET_DIR
|
||||
- file transfer CC_GET_FILE
|
||||
- file status CC_STAT
|
||||
- information about directory flags CC_GET_PRO
|
||||
- terminate session CC_BYE
|
||||
|
||||
|
||||
CC_VERSION 0x10 - Get server version string and setup
|
||||
|
||||
request
|
||||
|
|
@ -157,7 +170,7 @@ boundary, then two possible things will happen:
|
|||
|
||||
1) if the HEADER fits between this entry and the 1k boundary,
|
||||
a complete header will be filled in with a 'type' set to RDTYPE_SKIP.
|
||||
And then enough bytes to pad to 1k boundary.
|
||||
Repeat this step as neceseary until no HEADER fits.
|
||||
2) if the HEADER does not fit, then simply pad to the 1k boundary.
|
||||
|
||||
This will make sure that messages carrying directory information carry only
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ typedef struct RDIRENT { unsigned char bb_time[4];
|
|||
|
||||
#define NULLP ((char *) 0)
|
||||
|
||||
#define MIN_DELAY 1500L
|
||||
#define MIN_DELAY 1000L
|
||||
#define DEFAULT_DELAY 1340L
|
||||
#define MAX_DELAY 300000L
|
||||
|
||||
#endif /* _FSP_COMMON_DEF_H_ */
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ int init_caches PROTO0((void));
|
|||
void shutdown_caches PROTO0((void));
|
||||
void stat_caches PROTO1(FILE *,fp);
|
||||
const char *validate_path PROTO0((char *, unsigned, PPATH *,DIRINFO **, int));
|
||||
const char *parse_path PROTO3(char *, fullp, unsigned int, len, PPATH *, pp);
|
||||
const char *server_get_dir PROTO0((DIRLISTING **,const DIRINFO *));
|
||||
const char *server_del_file PROTO0((PPATH *, DIRINFO *));
|
||||
const char *server_del_dir PROTO2(PPATH *, pp, DIRINFO *,di);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
bin_PROGRAMS=fspd
|
||||
if MAINTAINER_MODE
|
||||
noinst_PROGRAMS=cachecheck
|
||||
endif
|
||||
|
||||
fspd_SOURCES=file.c host.c main.c conf.c filecache.c server.c fifocache.c \
|
||||
log.c iprange.c acl.c
|
||||
log.c iprange.c acl.c path.c
|
||||
fspd_CFLAGS=-DSYSCONFDIR="\"@sysconfdir@\"" $(AM_CFLAGS)
|
||||
fspd_LDADD=-L../common -lcommon
|
||||
|
||||
cachecheck_SOURCES=fifocache.c cachecheck.c
|
||||
|
||||
noinst_HEADERS=fifocache.h
|
||||
|
|
|
|||
|
|
@ -227,72 +227,6 @@ void shutdown_caches PROTO0((void))
|
|||
f_cache_destroy(fpcache);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Routine to parse a path string given by the client.
|
||||
* Will replace null string by ".".
|
||||
* In case of error, returns the error string.
|
||||
*
|
||||
* The PPATH structure is filled in by the function check_path when given a
|
||||
* path string. The elements are filled in as such:
|
||||
*
|
||||
* fullp pointer to a string containing the full path name
|
||||
* f_ptr pointer to begining of the last component of the path
|
||||
* f_len length of the last component of the path
|
||||
* d_ptr pointer to begining of the directory part of path
|
||||
* d_len length of the directory part of the path
|
||||
* passwd ptr to password
|
||||
*
|
||||
* fullp is a null-terminated full path string.
|
||||
* f_ptr is always a null-terminated sub-string of fullp.
|
||||
* d_ptr is generally not null-terminated.
|
||||
*****************************************************************************/
|
||||
|
||||
static const char *parse_path PROTO3(char *, fullp, unsigned int, len, PPATH *, pp)
|
||||
{
|
||||
char *s;
|
||||
int state;
|
||||
|
||||
if(len < 1) return("Path must have non-zero length");
|
||||
if(fullp[len-1]) return("Path not null terminated");
|
||||
|
||||
pp->d_ptr = "."; pp->d_len = 1; /* initial dir part ---> root */
|
||||
pp->passwd = NULL; /* default, no password */
|
||||
|
||||
if(len == 1 && fullp[0] == 0) { /* null path --> root */
|
||||
pp->fullp = pp->f_ptr = ".";
|
||||
pp->f_len = 1;
|
||||
return(NULLP);
|
||||
}
|
||||
|
||||
for(s = pp->fullp = pp->f_ptr = fullp, state = 0; *s; s++) {
|
||||
if(*s == '\n') {
|
||||
pp->passwd = s+1;
|
||||
*s = '\0';
|
||||
if(dbug) fprintf(stderr,"parse_path: found password field %s\n", s+1);
|
||||
}
|
||||
else if(*s < ' ' || *s >= '~') return("Path contains illegal chars");
|
||||
|
||||
switch(*s) {
|
||||
case '\\':
|
||||
case '.':
|
||||
if(state==0) return("Path can't begin with '.' or '\\'");
|
||||
break;
|
||||
case '/':
|
||||
if(state!=0)
|
||||
{
|
||||
pp->d_ptr=fullp;
|
||||
pp->d_len=s-fullp;
|
||||
pp->f_ptr=s+1;
|
||||
}
|
||||
default:
|
||||
state = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pp->f_len = s - pp->f_ptr;
|
||||
return(NULLP);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
|||
119
server/path.c
Normal file
119
server/path.c
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*********************************************************************\
|
||||
* Copyright (c) 2003 by Radim Kolar (hsn@cybermail.net) *
|
||||
* Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) *
|
||||
* *
|
||||
* You may copy or modify this file in any manner you wish, provided *
|
||||
* that this notice is always included, and that you hold the author *
|
||||
* harmless for any loss or damage resulting from the installation or *
|
||||
* use of this software. *
|
||||
\*********************************************************************/
|
||||
|
||||
#include "tweak.h"
|
||||
#include "server_def.h"
|
||||
#include "s_extern.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Routine to parse a path string given by the client.
|
||||
* input: fullp - pointer to path for parsing
|
||||
* len - length of the path for parsing
|
||||
* Will replace null string by ".".
|
||||
* In case of error, returns the error string.
|
||||
*
|
||||
* The PPATH structure is filled in by the function check_path when given a
|
||||
* path string. The elements are filled in as such:
|
||||
*
|
||||
* fullp pointer to a string containing the full path name
|
||||
* f_ptr pointer to begining of the last component of the path
|
||||
* f_len length of the last component of the path
|
||||
* d_ptr pointer to begining of the directory part of path
|
||||
* d_len length of the directory part of the path
|
||||
* passwd ptr to password
|
||||
*
|
||||
* fullp is a null-terminated full path string.
|
||||
* f_ptr is always a null-terminated sub-string of fullp.
|
||||
* d_ptr is generally not null-terminated.
|
||||
*****************************************************************************/
|
||||
|
||||
const char *parse_path PROTO3(char *, fullp, unsigned int, len, PPATH *, pp)
|
||||
{
|
||||
char *s;
|
||||
int state;
|
||||
|
||||
if(len < 1) return("Path must have non-zero length");
|
||||
if(fullp[len-1]) return("Path not null terminated");
|
||||
|
||||
pp->passwd = NULL; /* default, no password */
|
||||
pp->d_len = 0;
|
||||
|
||||
if(len == 1 && fullp[0] == 0)
|
||||
{
|
||||
/* null path --> root */
|
||||
pp->fullp = pp->f_ptr = pp->d_ptr = ".";
|
||||
pp->f_len = pp->d_len = 1;
|
||||
return(NULLP);
|
||||
}
|
||||
|
||||
for(s = pp->fullp = pp->f_ptr = pp->d_ptr = fullp, state = 0; *s; s++)
|
||||
{
|
||||
if(*s == '\n')
|
||||
{
|
||||
pp->passwd = s+1;
|
||||
*s = '\0';
|
||||
if(dbug) fprintf(stderr,"parse_path: found password field %s\n", s+1);
|
||||
break;
|
||||
}
|
||||
else
|
||||
if(*s < ' ') return("Path contains control chars");
|
||||
else
|
||||
if(*s >= '~') return("Path contains high chars");
|
||||
|
||||
switch(*s)
|
||||
{
|
||||
case '\\':
|
||||
case '.':
|
||||
if(state==0) return("Path can't begin with '.' or '\\'");
|
||||
if(state==2) return("Files can't begin with '.'");
|
||||
default:
|
||||
state = 1;
|
||||
break;
|
||||
case '/':
|
||||
pp->f_ptr=s+1;
|
||||
switch(state)
|
||||
{
|
||||
case 0:
|
||||
/* state 0: front slashes */
|
||||
pp->fullp=s+1;
|
||||
pp->d_ptr=s+1;
|
||||
pp->d_len=0;
|
||||
break;
|
||||
case 1:
|
||||
/* state 1: slash after nonslash */
|
||||
pp->d_len= s-pp->fullp;
|
||||
state=2;
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* pp->d_len = pp->f_ptr - pp->fullp; */
|
||||
|
||||
/* turn empty directory into "." */
|
||||
if(pp->d_len == 0)
|
||||
{
|
||||
pp->d_ptr = ".";
|
||||
pp->d_len = 1;
|
||||
}
|
||||
|
||||
pp->f_len = s - pp->f_ptr;
|
||||
|
||||
/* turn empty file into "." */
|
||||
if(pp->f_len == 0)
|
||||
{
|
||||
pp->f_ptr = ".";
|
||||
pp->f_len = 1;
|
||||
}
|
||||
|
||||
return(NULLP);
|
||||
}
|
||||
|
|
@ -701,6 +701,8 @@ static void server_process_packet PROTO5(unsigned, bytes, UBUF *, ub, int, old,
|
|||
return;
|
||||
}
|
||||
ACTIONOK(L_INSTALL);
|
||||
FSP_STAT(pp.fullp,&sd); /* log filesizes */
|
||||
xferlog('i',pp.fullp,sd.st_size,inetstr);
|
||||
}
|
||||
server_reply(from,ub,0,0);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -2,3 +2,5 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
mklargefile
|
||||
cachecheck
|
||||
parsecheck
|
||||
|
|
|
|||
|
|
@ -1,2 +1,7 @@
|
|||
noinst_PROGRAMS=mklargefile
|
||||
noinst_PROGRAMS=mklargefile cachecheck parsecheck
|
||||
|
||||
extra_DIST=mklargefile.py
|
||||
|
||||
cachecheck_SOURCES=../server/fifocache.c cachecheck.c
|
||||
parsecheck_SOURCES=parsecheck.c ../server/path.c
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "tweak.h"
|
||||
#include "fifocache.h"
|
||||
#include "../server/fifocache.h"
|
||||
|
||||
static int intcompare(const int *i1,const int *i2)
|
||||
{
|
||||
|
|
@ -7,6 +7,6 @@ if __name__ == '__main__':
|
|||
else:
|
||||
GB=1024*1024*1024
|
||||
f=open(sys.argv[1],'w')
|
||||
f.seek(long(sys.argv[2])*GB)
|
||||
f.seek(long(float(sys.argv[2])*GB))
|
||||
f.write('!')
|
||||
f.close();
|
||||
|
|
|
|||
62
tests/parsecheck.c
Normal file
62
tests/parsecheck.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include "tweak.h"
|
||||
#include "server_def.h"
|
||||
#include "s_extern.h"
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "my-string.h"
|
||||
|
||||
int dbug=0;
|
||||
|
||||
const char *testcases[]={ "", ".","filename","/filename","//filename","//dirname/filename","//dirname//filename","dirname//dir3name//","filename\npasswd",
|
||||
"file/.dir","directory.ext/filename.",
|
||||
NULL};
|
||||
|
||||
static void print_path(PPATH *pp)
|
||||
{
|
||||
printf("fullpath: %s ",pp->fullp);
|
||||
if(strcmp(pp->fullp,pp->d_ptr))
|
||||
{
|
||||
printf("d_ptr: %s (%d) ",pp->d_ptr,pp->d_len);
|
||||
} else
|
||||
printf("(%d) ",pp->d_len);
|
||||
|
||||
printf("f_ptr: %s (%d) ",pp->f_ptr,pp->f_len);
|
||||
if(pp->passwd)
|
||||
printf("passwd: %s",pp->passwd);
|
||||
}
|
||||
|
||||
static void runtestcase(void)
|
||||
{
|
||||
int i=0;
|
||||
PPATH pp;
|
||||
const char *err;
|
||||
const char *test;
|
||||
|
||||
for(;testcases[i];i++)
|
||||
{
|
||||
test=strdup(testcases[i]);
|
||||
err=parse_path(test,strlen(test)+1,&pp);
|
||||
printf("parsing: '%s'",test);
|
||||
if(err)
|
||||
{
|
||||
printf(" err: %s\n",err);
|
||||
free(test);
|
||||
continue;
|
||||
} else
|
||||
printf(" okay.\n");
|
||||
printf(" ");
|
||||
print_path(&pp);
|
||||
printf("\n");
|
||||
free(test);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,const char *argv[])
|
||||
{
|
||||
runtestcase();
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user