changeset 662:be9663e0be00

2005-1-16 Brian Masney <masneyb@gftp.org> * lib/fsplib/COPYING lib/fsplib/Makefile.am lib/fsplib/fsplib.c lib/fsplib/fsplib.h lib/fsplib/lock.c lib/fsplib/lock.h - added FSPLIB This library is written by Radim Kolar <hsn@netmag.cz> and was included with his permission
author masneyb
date Sun, 16 Jan 2005 16:12:13 +0000
parents 2e718fba351e
children 2d3ea4db3106
files ChangeLog lib/fsplib/COPYING lib/fsplib/Makefile.am lib/fsplib/fsplib.c lib/fsplib/fsplib.h lib/fsplib/lock.c lib/fsplib/lock.h
diffstat 7 files changed, 1897 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jan 16 15:48:24 2005 +0000
+++ b/ChangeLog	Sun Jan 16 16:12:13 2005 +0000
@@ -1,4 +1,9 @@
 2005-1-16 Brian Masney <masneyb@gftp.org>
+	* lib/fsplib/COPYING lib/fsplib/Makefile.am lib/fsplib/fsplib.c
+	lib/fsplib/fsplib.h lib/fsplib/lock.c lib/fsplib/lock.h - added FSPLIB
+	This library is written by Radim Kolar <hsn@netmag.cz> and was included
+	with his permission
+
 	* lib/fsp.c lib/options.h lib/gftp.h - added support for the FSP
 	protocol (from Radim Kolar <hsn@netmag.cz>). Note, I need to update
 	the build system for gftp to compile properly
@@ -3212,7 +3217,7 @@
 
 	* cvsclean - added this script
 
-	* *.[ch] - added $Id: ChangeLog,v 1.391 2005/01/16 15:48:23 masneyb Exp $ tags
+	* *.[ch] - added $Id: ChangeLog,v 1.392 2005/01/16 16:12:13 masneyb Exp $ tags
 
 	* debian/* - updated files from Debian maintainer
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsplib/COPYING	Sun Jan 16 16:12:13 2005 +0000
@@ -0,0 +1,9 @@
+Copyright (c) 2003-2004 by Radim HSN Kolar
+
+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.
+
+		     This is a free software.  Be creative. 
+		    Let me know of any bugs and suggestions.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsplib/Makefile.am	Sun Jan 16 16:12:13 2005 +0000
@@ -0,0 +1,6 @@
+## Process this file with automake to produce Makefile.in 
+
+noinst_LIBRARIES = libfsp.a
+libfsp_a_SOURCES=fsplib.c lock.c
+INCLUDES=-DFSP_USE_SHAREMEM_AND_SEMOP=1
+noinst_HEADERS=fsplib.h lock.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsplib/fsplib.c	Sun Jan 16 16:12:13 2005 +0000
@@ -0,0 +1,1362 @@
+/*
+This file is part of fsplib - FSP protocol stack implemented in C
+language. See http://fsp.sourceforge.net for more information.
+
+Copyright (c) 2003-2004 by Radim HSN Kolar (hsn@netmag.cz)
+
+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.
+
+                     This is a free software.  Be creative.
+                    Let me know of any bugs and suggestions.
+*/                  
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include "fsplib.h"
+#include "lock.h"
+
+/* ************ Internal functions **************** */ 
+
+/* builds filename in packet output buffer, appends password if needed */
+static int buildfilename(const FSP_SESSION *s,FSP_PKT *out,const char *dirname)
+{
+    int len;
+    
+    len=strlen(dirname);
+    if(len >= FSP_SPACE - 1)
+    {
+	errno = ENAMETOOLONG;
+        return -1;
+    }
+    /* copy name + \0 */
+    memcpy(out->buf,dirname,len+1);
+    out->len=len;
+    if(s->password)
+    {
+        out->buf[len]='\n';
+        out->len++;
+	
+        len=strlen(s->password);
+	if(out->len+ len >= FSP_SPACE -1 )
+	{
+	    errno = ENAMETOOLONG;
+	    return -1;
+	}
+        memcpy(out->buf+out->len,s->password,len+1);
+        out->len+=len;
+    }
+    /* add terminating \0 */
+    out->len++;
+    return 0;
+}
+
+/* simple FSP command */
+static int simplecommand(FSP_SESSION *s,const char *directory,unsigned char command)
+{
+   FSP_PKT in,out;
+   
+   if(buildfilename(s,&out,directory))
+       return -1;
+   out.cmd=command;
+   out.xlen=0;
+   out.pos=0;
+
+   if(fsp_transaction(s,&out,&in))
+       return -1;
+   
+   if(in.cmd == FSP_CC_ERR)
+   {
+       errno = EPERM;
+       return -1;
+   }
+
+   if(in.cmd != command)
+   {
+       errno = ENOMSG;
+       return -1;
+   }
+
+   errno = 0;
+   return  0;
+}
+/* Get directory part of filename. You must free() the result */
+static char * directoryfromfilename(const char *filename)
+{
+    char *result;
+    char *tmp;
+    int pos;
+
+    result=strrchr(filename,'/');
+    if (result == NULL)
+	return strdup("");
+    pos=result-filename;
+    tmp=malloc(pos+1);
+    if(!tmp)
+	return NULL;
+    memcpy(tmp,filename,pos);
+    tmp[pos]='\0';
+    return tmp;		
+}
+
+/* ************  Packet encoding / decoding *************** */
+
+/* write binary representation of FSP packet p into *space. */
+/* returns number of bytes used or zero on error            */
+/* Space must be long enough to hold created packet.        */
+/* Maximum created packet size is FSP_MAXPACKET             */
+
+size_t fsp_pkt_write(const FSP_PKT *p,void *space)
+{
+    size_t used;
+    unsigned char *ptr;
+    int checksum;
+    size_t i;
+
+    if(p->xlen + p->len > FSP_SPACE )
+    {
+        /* not enough space */
+	errno = EMSGSIZE;
+        return 0;
+    }
+    ptr=space;
+    /* pack header */
+    ptr[FSP_OFFSET_CMD]=p->cmd;
+    ptr[FSP_OFFSET_SUM]=0;
+    *(uint16_t *)(ptr+FSP_OFFSET_KEY)=htons(p->key);
+    *(uint16_t *)(ptr+FSP_OFFSET_SEQ)=htons(p->seq);
+    *(uint16_t *)(ptr+FSP_OFFSET_LEN)=htons(p->len);
+    *(uint32_t *)(ptr+FSP_OFFSET_POS)=htonl(p->pos);
+    used=FSP_HSIZE;
+    /* copy data block */
+    memcpy(ptr+FSP_HSIZE,p->buf,p->len);
+    used+=p->len;
+    /* copy extra data block */
+    memcpy(ptr+used,p->buf+p->len,p->xlen);
+    used+=p->xlen;
+    /* compute checksum */
+    checksum = 0;
+    for(i=0;i<used;i++)
+    {
+        checksum += ptr[i];
+    }
+    checksum +=used;
+    ptr[FSP_OFFSET_SUM] =  checksum + (checksum >> 8);
+    return used;
+}
+
+/* read binary representation of FSP packet received from network into p  */
+/* return zero on success */
+int fsp_pkt_read(FSP_PKT *p,const void *space,size_t recv_len)
+{
+    int mysum;
+    size_t i;
+    const unsigned char *ptr;
+    
+    if(recv_len<FSP_HSIZE)
+    {
+	/* too short */
+	errno = ERANGE;
+        return -1;
+    }
+    if(recv_len>FSP_MAXPACKET)
+    {
+	/* too long */
+	errno = EMSGSIZE;
+        return -1;
+    }
+
+    ptr=space;
+    /* check sum */
+    mysum=-ptr[FSP_OFFSET_SUM];
+    for(i=0;i<recv_len;i++)
+    {
+        mysum+=ptr[i];
+    }
+
+   mysum = (mysum + (mysum >> 8)) & 0xff;
+
+   if(mysum != ptr[FSP_OFFSET_SUM])
+   {
+       /* checksum failed */
+
+#ifdef MAINTAINER_MODE
+       printf("mysum: %x, got %x\n",mysum,ptr[FSP_OFFSET_SUM]);
+#endif
+       errno = EIO;
+       return -1;
+   }
+
+   /* unpack header */
+   p->cmd=ptr[FSP_OFFSET_CMD];
+   p->sum=mysum;
+   p->key=ntohs( *(const uint16_t *)(ptr+FSP_OFFSET_KEY) );
+   p->seq=ntohs( *(const uint16_t *)(ptr+FSP_OFFSET_SEQ) );
+   p->len=ntohs( *(const uint16_t *)(ptr+FSP_OFFSET_LEN) );
+   p->pos=ntohl( *(const uint32_t *)(ptr+FSP_OFFSET_POS) );
+   if(p->len > recv_len)
+   {
+       /* bad length field, should not never happen */
+       errno = EMSGSIZE;
+       return -1;
+   }   
+   p->xlen=recv_len - p->len - FSP_HSIZE;
+   /* now copy data */
+   memcpy(p->buf,ptr+FSP_HSIZE,recv_len - FSP_HSIZE);
+   return 0;
+}
+
+/* ****************** packet sending functions ************** */
+
+/* make one send + receive transaction with server */
+/* outgoing packet is in p, incomming in rpkt */
+int fsp_transaction(FSP_SESSION *s,FSP_PKT *p,FSP_PKT *rpkt)
+{
+    char buf[FSP_MAXPACKET];
+    size_t l;
+    ssize_t r;
+    fd_set mask;
+    struct timeval start[8],stop;
+    int i;
+    unsigned int retry,dupes;
+    int w_delay; /* how long to wait on next packet */
+    int f_delay; /* how long to wait after first send */
+    int l_delay; /* last delay */
+    unsigned int t_delay; /* time from first send */
+    
+
+    if(p == rpkt)
+    {
+	errno = EINVAL;
+	return -2;
+    }
+    FD_ZERO(&mask);
+    /* get the next key */
+    p->key = client_get_key((FSP_LOCK *)s->lock);
+
+    dupes = retry = 0;
+    s->seq = (s-> seq + 0x08) & 0xfff8;
+    t_delay = 0;
+    /* compute initial delay here */
+    /* we are using hardcoded value for now */
+    f_delay = 1340;
+    for(;;retry++)
+    {
+	if(t_delay >= s->timeout)
+	{
+            client_set_key((FSP_LOCK *)s->lock,p->key);
+	    errno = ETIMEDOUT;
+	    return -1;
+	}
+        /* make a packet */
+        p->seq = (s->seq) | (retry & 0x7);
+        l=fsp_pkt_write(p,buf);
+        
+        /* We should compute next delay wait time here */
+        gettimeofday(&start[retry & 0x7],NULL);
+	if(retry == 0 )
+	    w_delay=f_delay;
+	else
+	{
+	    w_delay=l_delay*3/2; 
+	}
+
+	l_delay=w_delay;
+
+        /* send packet */
+        if( send(s->fd,buf,l,0) < 0 )
+        {
+#ifdef MAINTAINER_MODE
+            printf("Send failed.\n");
+#endif
+	    if(errno == EBADF || errno == ENOTSOCK)
+	    {
+                client_set_key((FSP_LOCK *)s->lock,p->key);
+		errno = EBADF;
+		return -1;
+	    }
+            /* io terror */
+            sleep(1);
+            /* avoid wasting retry slot */
+            retry--;
+	    t_delay += 1000;
+            continue; 
+        }
+
+        /* keep delay value within sane limits */
+	if (w_delay > (int) s->maxdelay) 
+	    w_delay=s->maxdelay;
+	else
+	    if(w_delay < 1000 ) 
+		w_delay = 1000;
+
+	t_delay += w_delay;
+        /* receive loop */
+        while(1)
+        {
+            if(w_delay <= 0 ) break;
+            /* convert w_delay to timeval */
+            stop.tv_sec=w_delay/1000;
+            stop.tv_usec=(w_delay % 1000)*1000;
+            FD_SET(s->fd,&mask);
+            i=select(s->fd+1,&mask,NULL,NULL,&stop);
+            if(i==0)
+                break; /* timed out */
+            if(i<0)
+                    {
+                        if(errno==EINTR)
+                        {
+                            /* lower w_delay */
+                            gettimeofday(&stop,NULL);
+                            w_delay-=1000*(stop.tv_sec -  start[retry & 0x7].tv_sec);
+                            w_delay-=     (stop.tv_usec -  start[retry & 0x7].tv_usec)/1000;
+                            continue;
+                        }
+                        /* hard select error */
+                        client_set_key((FSP_LOCK *)s->lock,p->key);
+                        return -1;
+                    }
+            r=recv(s->fd,buf,FSP_MAXPACKET,0);
+            if(r < 0 )
+	    {
+                /* serious recv error */
+                client_set_key((FSP_LOCK *)s->lock,p->key);
+                return -1;
+	    }
+
+            gettimeofday(&stop,NULL);
+            w_delay-=1000*(stop.tv_sec -  start[retry & 0x7].tv_sec);
+            w_delay-=     (stop.tv_usec -  start[retry & 0x7].tv_usec)/1000;
+
+            /* process received packet */
+            if ( fsp_pkt_read(rpkt,buf,r) < 0)
+            {
+                /* unpack failed */
+                continue;
+            }
+
+            /* check sequence number */
+            if( (rpkt->seq & 0xfff8) != s->seq )
+            {
+#ifdef MAINTAINER_MODE
+                printf("dupe\n");
+#endif
+                /* duplicate */
+                dupes++;
+                continue;
+            }
+
+            /* now we have a correct packet */
+
+            /* compute rtt delay */
+            w_delay=1000*(stop.tv_sec - start[retry & 0x7].tv_sec);
+            w_delay+=(stop.tv_usec -  start[retry & 0x7].tv_usec)/1000;
+            /* update last stats */
+            s->last_rtt=w_delay;
+            s->last_delay=f_delay;
+            s->last_dupes=dupes;
+            s->last_resends=retry;
+            /* update cumul. stats */
+            s->dupes+=dupes;
+            s->resends+=retry;
+            s->trips++;
+            s->rtts+=w_delay;
+
+            /* grab a next key */
+            client_set_key((FSP_LOCK *)s->lock,rpkt->key);
+	    errno = 0;
+            return 0;
+        }
+    }
+}
+
+/* ******************* Session management functions ************ */
+
+/* initializes a session */
+FSP_SESSION * fsp_open_session(const char *host,unsigned short port,const char *password)
+{
+    FSP_SESSION *s;
+    int fd;
+    struct addrinfo hints,*res;
+    char port_s[6];
+    struct sockaddr_in *addrin;
+    FSP_LOCK *lock;
+
+    memset (&hints, 0, sizeof (hints));
+    /* fspd do not supports inet6 */
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = SOCK_DGRAM;
+
+    if (port == 0)
+	strcpy(port_s,"fsp");
+    else
+        sprintf(port_s,"%hu",port);
+
+    if ( getaddrinfo(host,port_s,&hints,&res) )
+    {
+        return NULL; /* host not found */
+    }
+
+    /* create socket */
+    fd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
+    if ( fd < 0)
+        return NULL;
+    
+    /* connect socket */
+    if( connect(fd, res->ai_addr, res->ai_addrlen))
+    {
+        close(fd);
+        return NULL;
+    }
+
+    /* allocate memory */
+    s=calloc(1,sizeof(FSP_SESSION));
+    if ( !s )
+    {
+	close(fd);
+	errno = ENOMEM;
+        return NULL;
+    }
+
+    lock=malloc(sizeof(FSP_LOCK));
+
+    if ( !lock )
+    {
+	close(fd);
+	free(s);
+	errno = ENOMEM;
+	return NULL;
+    }
+
+    s->lock=lock;
+
+    /* init locking subsystem */
+    addrin = (struct sockaddr_in *)res->ai_addr;
+    if ( client_init_key( (FSP_LOCK *)s->lock,addrin->sin_addr.s_addr,ntohs(addrin->sin_port)))
+    {
+	free(s);
+	close(fd);
+	free(lock);
+	return NULL;
+    }
+
+    s->fd=fd;
+    s->timeout=300000; /* 5 minutes */
+    s->maxdelay=60000; /* 1 minute  */
+    s->seq=random();
+    if ( password ) 
+        s->password = strdup(password);
+    return s;
+}
+
+/* closes a session */
+void fsp_close_session(FSP_SESSION *s)
+{
+    FSP_PKT bye,in;
+    
+    if( s == NULL)
+        return;
+    if ( s->fd == -1)
+	return;	
+    /* Send bye packet */
+    bye.cmd=FSP_CC_BYE;
+    bye.len=bye.xlen=0;
+    bye.pos=0;
+    s->timeout=7000;
+    fsp_transaction(s,&bye,&in);
+
+    close(s->fd);
+    if (s->password) free(s->password);
+    client_destroy_key((FSP_LOCK *)s->lock);
+    free(s->lock);
+    memset(s,0,sizeof(FSP_SESSION));
+    s->fd=-1;
+    free(s);
+}
+
+/* *************** Directory listing functions *************** */
+
+/* get a directory listing from a server */
+FSP_DIR * fsp_opendir(FSP_SESSION *s,const char *dirname)
+{
+    FSP_PKT in,out;
+    int pos;
+    unsigned short blocksize;
+    FSP_DIR *dir;
+    unsigned char *tmp;
+
+    if (s == NULL) return NULL;
+    if (dirname == NULL) return NULL;
+
+    if(buildfilename(s,&out,dirname))
+    {
+	return NULL;
+    }
+    pos=0;
+    blocksize=0;
+    dir=NULL;
+    out.cmd = FSP_CC_GET_DIR;
+    out.xlen=0;
+    
+    /* load directory listing from the server */
+    while(1)
+    {
+        out.pos=pos;
+        if ( fsp_transaction(s,&out,&in) )
+        {
+            pos = -1;
+            break;
+        }
+        if ( in.cmd != FSP_CC_GET_DIR )
+        {
+            /* bad reply from the server */
+            pos = -1;
+            break;
+        }
+        /* End of directory? */
+        if ( in.len == 0)
+            break;
+        /* set blocksize */
+        if (blocksize == 0 )
+            blocksize = in.len;
+        /* alloc directory */
+        if (dir == NULL)
+        {
+            dir = calloc(1,sizeof(FSP_DIR));
+            if (dir == NULL)
+            {
+                pos = -1;
+                break;
+            }
+        }
+        /* append data */
+        tmp=realloc(dir->data,pos+in.len);
+        if(tmp == NULL)
+        {
+            pos = -1;
+            break;
+        }
+        dir->data=tmp;
+	memcpy(dir->data + pos, in.buf,in.len);
+        pos += in.len;
+	if (in.len < blocksize)
+	    /* last block is smaller */
+	    break;
+    }
+    if (pos == -1)
+    {
+        /* failure */
+        if (dir)
+        {
+            if(dir->data)
+                free(dir->data);
+            free(dir);
+        }
+        return NULL;
+    }
+
+    dir->inuse=1;
+    dir->blocksize=blocksize;
+    dir->dirname=strdup(dirname);
+    dir->datasize=pos;
+
+    return dir;
+}
+
+int fsp_readdir_r(FSP_DIR *dir,struct dirent *entry, struct dirent **result)
+{
+    FSP_RDENTRY fentry,*fresult;
+    int rc;
+
+    if (dir == NULL || entry == NULL || *result == NULL)
+        return -EINVAL;
+    if (dir->dirpos<0 || dir->dirpos % 4)
+        return -ESPIPE;
+
+    rc=fsp_readdir_native(dir,&fentry,&fresult);
+
+    if (rc != 0)
+	return rc;
+
+    /* convert FSP dirent to OS dirent */
+
+    if (fentry.type == FSP_RDTYPE_DIR )
+	entry->d_type=DT_DIR;
+    else
+	entry->d_type=DT_REG;
+    entry->d_fileno = 10;
+    entry->d_reclen = fentry.reclen;
+    strncpy(entry->d_name,fentry.name,MAXNAMLEN);
+
+    if (fentry.namlen > MAXNAMLEN)
+    {
+	entry->d_name[MAXNAMLEN + 1 ] = '\0';
+#ifdef HAVE_NAMLEN	
+	entry->d_namlen = MAXNAMLEN;
+    } else
+    {
+       entry->d_namlen = fentry.namlen;
+#endif       
+    }
+
+    if (fresult == &fentry )
+    {
+	*result = entry;
+    }
+    else
+	*result = NULL;	
+
+    return 0; 
+}
+
+/* native FSP directory reader */
+int fsp_readdir_native(FSP_DIR *dir,FSP_RDENTRY *entry, FSP_RDENTRY **result)
+{
+    unsigned char ftype;
+    int namelen;
+
+    if (dir == NULL || entry == NULL || *result == NULL)
+        return -EINVAL;
+    if (dir->dirpos<0 || dir->dirpos % 4)
+        return -ESPIPE;
+
+    while(1)
+    {
+       if ( dir->dirpos >= (int)dir->datasize )
+       {
+            /* end of the directory */
+            *result = NULL;
+            return 0;
+       }
+       if (dir->blocksize - (dir->dirpos % dir->blocksize) < 9)
+	   ftype= FSP_RDTYPE_SKIP;
+       else
+           /* get the file type */
+           ftype=dir->data[dir->dirpos+8];
+
+       if (ftype == FSP_RDTYPE_END )
+       {
+           dir->dirpos=dir->datasize;
+           continue;
+       }
+       if (ftype == FSP_RDTYPE_SKIP )
+       {
+           /* skip to next directory block */
+           dir->dirpos = ( dir->dirpos / dir->blocksize + 1 ) * dir->blocksize;
+#ifdef MAINTAINER_MODE
+	   printf("new block dirpos: %d\n",dir->dirpos);
+#endif
+           continue;
+       }
+       /* extract binary data */
+       entry->lastmod=ntohl( *(const uint32_t *)( dir->data+ dir->dirpos ));
+       entry->size=ntohl( *(const uint32_t *)(dir->data+ dir->dirpos +4 ));
+       entry->type=ftype;
+
+       /* skip file date and file size */
+       dir->dirpos += 9;
+       /* read file name */
+       entry->name[255 + 1] = '\0';
+       strncpy(entry->name,(char *)( dir->data + dir->dirpos ),MAXNAMLEN);
+       namelen = strlen( (char *) dir->data+dir->dirpos);
+       /* skip over file name */
+       dir->dirpos += namelen +1;
+
+       /* set entry namelen field */
+       if (namelen > 255)
+           entry->namlen = 255;
+       else
+           entry->namlen = namelen;
+       /* set record length */	   
+       entry->reclen = 10+namelen;
+
+       /* pad to 4 byte boundary */
+       while( dir->dirpos & 0x3 )
+       {
+         dir->dirpos++;
+         entry->reclen++;
+       }
+
+       /* and return it */
+       *result=entry;
+       return 0;  
+    }
+}
+
+struct dirent * fsp_readdir(FSP_DIR *dirp)
+{
+    static struct dirent entry;
+    struct dirent *result;
+    
+    
+    if (dirp == NULL) return NULL;
+    if ( fsp_readdir_r(dirp,&entry,&result) )
+        return NULL;
+    else
+        return result;
+}
+
+long fsp_telldir(FSP_DIR *dirp)
+{
+    return dirp->dirpos;
+}
+
+void fsp_seekdir(FSP_DIR *dirp, long loc)
+{
+    dirp->dirpos=loc;
+}
+
+void fsp_rewinddir(FSP_DIR *dirp)
+{
+    dirp->dirpos=0;
+}
+
+int fsp_closedir(FSP_DIR *dirp)
+{
+    if (dirp == NULL) 
+        return -1;
+    if(dirp->dirname) free(dirp->dirname);
+    free(dirp->data);
+    free(dirp);
+    return 0;
+}
+
+/*  ***************** File input/output functions *********  */
+FSP_FILE * fsp_fopen(FSP_SESSION *session, const char *path,const char *modeflags)
+{
+    FSP_FILE   *f;
+
+    if(session == NULL || path == NULL || modeflags == NULL)
+    {
+	errno = EINVAL;
+	return NULL;
+    }
+
+    f=calloc(1,sizeof(FSP_FILE));
+    if (f == NULL)
+    {
+	return NULL;
+    }
+
+    /* check and parse flags */
+    switch (*modeflags++)
+    {
+	case 'r':
+		  break;
+        case 'w':
+		  f->writing=1;
+		  break;
+        case 'a':
+	          /* not supported */
+		  free(f);
+		  errno = ENOTSUP;
+		  return NULL;
+        default:
+		  free(f);
+		  errno = EINVAL;
+		  return NULL;
+    }
+
+    if (*modeflags == '+' || ( *modeflags=='b' && modeflags[1]=='+'))
+    {
+	free(f);
+	errno = ENOTSUP;
+	return NULL;
+    }
+
+    /* build request packet */
+    if(f->writing)
+    {
+	f->out.cmd=FSP_CC_UP_LOAD;
+    }
+    else
+    {
+        if(buildfilename(session,&f->out,path))
+	{
+	    free(f);
+            return NULL;
+	}
+        f->bufpos=FSP_SPACE;
+	f->out.cmd=FSP_CC_GET_FILE;
+    }
+    f->out.xlen=0;
+
+    /* setup control variables */
+    f->s=session;
+    f->name=strdup(path);
+    if(f->name == NULL)
+    {
+	free(f);
+	errno = ENOMEM;
+	return NULL;
+    }
+
+    return f;
+}
+
+size_t fsp_fread(void *dest,size_t size,size_t count,FSP_FILE *file)
+{
+    size_t total,done,havebytes;
+    char *ptr;
+
+    total=count*size;
+    done=0;
+    ptr=dest;
+    
+    if(file->eof) return 0;
+
+    while(1)
+    {
+	/* need more data? */
+	if(file->bufpos>=FSP_SPACE)
+	{
+	    /* fill the buffer */
+	    file->out.pos=file->pos;
+	    if(fsp_transaction(file->s,&file->out,&file->in))
+	    {
+	         file->err=1;
+		 return done/size;
+	    }
+	    if(file->in.cmd != FSP_CC_GET_FILE)
+	    {
+		errno = EIO;
+		file->err=1;
+		return done/size;
+	    }
+	    file->bufpos=FSP_SPACE-file->in.len;
+	    if(file->bufpos > 0)
+	    {
+	       memmove(file->in.buf+file->bufpos,file->in.buf,file->in.len);
+	    }
+	    file->pos+=file->in.len;
+	}
+	havebytes=FSP_SPACE - file->bufpos;
+	if (havebytes == 0 )
+	{
+	    /* end of file! */
+	    file->eof=1;
+	    errno = 0;
+	    return done/size;
+	}
+	/* copy ready data to output buffer */
+	if(havebytes <= total )
+	{
+	    /* copy all we have */
+	    memcpy(ptr,file->in.buf+file->bufpos,havebytes);
+	    ptr+=havebytes;
+	    file->bufpos=FSP_SPACE;
+	    done+=havebytes;
+	    total-=havebytes;
+	} else
+	{
+	    /* copy bytes left */
+	    memcpy(ptr,file->in.buf+file->bufpos,total);
+	    file->bufpos+=total;
+	    errno = 0;
+	    return count;
+	}
+    }
+}
+
+size_t fsp_fwrite(const void * source, size_t size, size_t count, FSP_FILE * file)
+{
+    size_t total,done,freebytes;
+    const char *ptr;
+
+    if(file->eof || file->err)
+	return 0;
+
+    file->out.len=FSP_SPACE;
+    total=count*size;
+    done=0;
+    ptr=source;
+
+    while(1)
+    {
+	/* need to write some data? */
+	if(file->bufpos>=FSP_SPACE)
+	{
+	    /* fill the buffer */
+	    file->out.pos=file->pos;
+	    if(fsp_transaction(file->s,&file->out,&file->in))
+	    {
+	         file->err=1;
+		 return done/size;
+	    }
+	    if(file->in.cmd != FSP_CC_UP_LOAD)
+	    {
+		errno = EIO;
+		file->err=1;
+		return done/size;
+	    }
+	    file->bufpos=0;
+	    file->pos+=file->out.len;
+	    done+=file->out.len;
+	}
+	freebytes=FSP_SPACE - file->bufpos;
+	/* copy input data to output buffer */
+	if(freebytes <= total )
+	{
+	    /* copy all we have */
+	    memcpy(file->out.buf+file->bufpos,ptr,freebytes);
+	    ptr+=freebytes;
+	    file->bufpos=FSP_SPACE;
+	    total-=freebytes;
+	} else
+	{
+	    /* copy bytes left */
+	    memcpy(file->out.buf+file->bufpos,ptr,total);
+	    file->bufpos+=total;
+	    errno = 0;
+	    return count;
+	}
+    }
+}
+
+int fsp_fpurge(FSP_FILE *file)
+{
+    if(file->writing)
+    {
+	file->bufpos=0;
+    }
+    else
+    {
+	file->bufpos=FSP_SPACE;
+    }
+    errno = 0;
+    return 0;
+}
+
+int fsp_fflush(FSP_FILE *file)
+{
+    if(file == NULL)
+    {
+	errno = ENOTSUP;
+	return -1;
+    }
+    if(!file->writing)
+    {
+	errno = EBADF;
+	return -1;
+    }
+    if(file->eof || file->bufpos==0)
+    {
+	errno = 0;
+	return 0;
+    }
+
+    file->out.pos=file->pos;
+    file->out.len=file->bufpos;
+    if(fsp_transaction(file->s,&file->out,&file->in))
+    {
+	 file->err=1;
+	 return -1;
+    }
+    if(file->in.cmd != FSP_CC_UP_LOAD)
+    {
+	errno = EIO;
+	file->err=1;
+	return -1;
+    }
+    file->bufpos=0;
+    file->pos+=file->out.len;
+    
+    errno = 0;
+    return 0;
+}
+
+
+
+int fsp_fclose(FSP_FILE *file)
+{
+    int rc;
+
+    rc=0;
+    errno = 0;
+    if(file->writing)
+    {
+        if(fsp_fflush(file))
+	{  
+	    rc=-1;
+	}
+	else if(fsp_install(file->s,file->name,0))
+	{
+	    rc=-1;
+	}
+    }
+    free(file->name);
+    free(file);
+    return rc;
+}
+
+int fsp_fseek(FSP_FILE *stream, long offset, int whence)
+{
+    long newoffset;
+
+    switch(whence)
+    {
+	case SEEK_SET:
+	              newoffset = offset;
+		      break;
+        case SEEK_CUR:
+		      newoffset = stream->pos + offset;
+		      break;
+        case SEEK_END:
+	              errno = ENOTSUP;
+		      return -1;
+	default:
+		      errno = EINVAL;
+		      return -1;
+    }
+    if(stream->writing)
+    {
+	if(fsp_fflush(stream))
+	{
+	    return -1;
+	}
+    }
+    stream->pos=newoffset;
+    stream->eof=0;
+    fsp_fpurge(stream);
+    return 0;
+}
+
+long fsp_ftell(FSP_FILE *f)
+{
+    return f->pos + f->bufpos;
+}
+
+void fsp_rewind(FSP_FILE *f)
+{
+    if(f->writing)
+	fsp_fflush(f);
+    f->pos=0;
+    f->err=0;
+    f->eof=0;
+    fsp_fpurge(f);
+}
+
+/*  **************** Utility functions ****************** */
+
+/* return 0 if user has enough privs for uploading the file */
+int fsp_canupload(FSP_SESSION *s,const char *fname)
+{
+  char *dir;
+  unsigned char dirpro;
+  int rc;
+  struct stat sb;
+
+  dir=directoryfromfilename(fname);
+  if(dir == NULL)
+  {
+      errno = ENOMEM;
+      return -1;
+  }
+  
+  rc=fsp_getpro(s,dir,&dirpro);
+  free(dir);
+
+  if(rc)
+  {
+      return -1;
+  }
+  
+  if(dirpro & FSP_DIR_OWNER) 
+      return 0;
+  
+  if( ! (dirpro & FSP_DIR_ADD))
+      return -1;
+      
+  if (dirpro & FSP_DIR_DEL)
+     return 0;
+     
+  /* we need to check file existence, because we can not overwrite files */
+  
+  rc = fsp_stat(s,fname,&sb);
+  
+  if (rc == 0)
+      return -1;
+  else
+      return 0;
+}
+
+/* install file opened for writing */
+int fsp_install(FSP_SESSION *s,const char *fname,time_t timestamp)
+{
+    int rc;
+    FSP_PKT in,out;
+
+    /* and install a new file */
+    out.cmd=FSP_CC_INSTALL;
+    out.xlen=0;
+    out.pos=0;
+    rc=0;
+    if( buildfilename(s,&out,fname) )
+	rc=-1;
+    else
+	{
+	    if (timestamp != 0)
+	    {
+		/* add timestamp extra data */
+		*(uint32_t *)(out.buf+out.len)=htonl(timestamp);
+		out.xlen=4;
+		out.pos=4;
+	    }
+	    if(fsp_transaction(s,&out,&in))
+	    {
+		rc=-1;
+	    } else
+	    {
+		if(in.cmd != FSP_CC_INSTALL)
+		{
+		    rc=-1;
+		    errno = EPERM;
+		}
+	    }
+	}
+
+    return rc;
+}
+/* Get protection byte from the directory */
+int fsp_getpro(FSP_SESSION *s,const char *directory,unsigned char *result)
+{
+   FSP_PKT in,out;
+   
+   if(buildfilename(s,&out,directory))
+       return -1;
+   out.cmd=FSP_CC_GET_PRO;
+   out.xlen=0;
+   out.pos=0;
+
+   if(fsp_transaction(s,&out,&in))
+       return -1;
+
+   if(in.cmd != FSP_CC_GET_PRO || in.pos != FSP_PRO_BYTES)
+   {
+       errno = ENOMSG;
+       return -1;
+   }
+
+   if(result)
+      *result=in.buf[in.len];
+   errno = 0;
+   return  0;
+}
+
+int fsp_stat(FSP_SESSION *s,const char *path,struct stat *sb)
+{
+   FSP_PKT in,out;
+   unsigned char ftype;
+   
+   if(buildfilename(s,&out,path))
+       return -1;
+   out.cmd=FSP_CC_STAT;
+   out.xlen=0;
+   out.pos=0;
+
+   if(fsp_transaction(s,&out,&in))
+       return -1;
+
+   if(in.cmd != FSP_CC_STAT)
+   {
+       errno = ENOTSUP;
+       return -1;
+   }
+   /* parse results */
+   ftype=in.buf[8];
+   if(ftype == 0)
+   {
+       errno = ENOENT;
+       return -1;
+   }
+   sb->st_uid=sb->st_gid=0;
+   sb->st_mtime=sb->st_ctime=sb->st_atime=ntohl( *(const uint32_t *)( in.buf ));
+   sb->st_size=ntohl( *(const uint32_t *)(in.buf + 4 ));
+   sb->st_blocks=(sb->st_size+511)/512;
+   if (ftype==FSP_RDTYPE_DIR)
+   {
+       sb->st_mode=S_IFDIR | 0755;
+       sb->st_nlink=2;
+   }
+   else
+   {
+       sb->st_mode=S_IFREG | 0644;
+       sb->st_nlink=1;
+   }
+
+   errno = 0;
+   return  0;
+}
+
+int fsp_mkdir(FSP_SESSION *s,const char *directory)
+{
+   return simplecommand(s,directory,FSP_CC_MAKE_DIR);
+}
+
+int fsp_rmdir(FSP_SESSION *s,const char *directory)
+{
+   return simplecommand(s,directory,FSP_CC_DEL_DIR);
+}
+
+int fsp_unlink(FSP_SESSION *s,const char *directory)
+{
+   return simplecommand(s,directory,FSP_CC_DEL_FILE);
+}
+
+int fsp_rename(FSP_SESSION *s,const char *from, const char *to)
+{
+   FSP_PKT in,out;
+   int l;
+   
+   if(buildfilename(s,&out,from))
+       return -1;
+   /* append target name */
+   l=strlen(to)+1;
+   if( l + out.len > FSP_SPACE )
+   {
+       errno = ENAMETOOLONG;
+       return -1;
+   }
+   memcpy(out.buf+out.len,to,l);
+   out.xlen = l;
+
+   if(s->password)
+   {
+       l=strlen(s->password)+1;
+       if(out.len + out.xlen + l > FSP_SPACE)
+       {
+	   errno = ENAMETOOLONG;
+	   return -1;
+       }
+       out.buf[out.len+out.xlen-1] = '\n';
+       memcpy(out.buf+out.len+out.xlen,s->password,l);
+       out.xlen += l;
+   }
+
+   out.cmd=FSP_CC_RENAME;
+   out.pos=out.xlen;
+    
+   if(fsp_transaction(s,&out,&in))
+       return -1;
+
+   if(in.cmd != FSP_CC_RENAME)
+   {
+       errno = EPERM;
+       return -1;
+   }
+
+   errno = 0; 
+   return 0;
+}
+
+int fsp_access(FSP_SESSION *s,const char *path, int mode)
+{
+    struct stat sb;
+    int rc;
+    unsigned char dirpro;
+    char *dir;
+
+    rc=fsp_stat(s,path,&sb);
+    if(rc == -1)
+    {
+	/* not found */
+	/* errno is set by fsp_stat */
+	return -1;
+    }
+
+    /* just test file existence */
+    if(mode == F_OK)
+    {
+	errno = 0;
+	return  0;
+    }
+
+    /* deny execute access to file */
+    if (mode & X_OK)
+    {
+	if(S_ISREG(sb.st_mode))
+	{
+	    errno = EACCES;
+	    return -1;
+	}
+    }
+    
+    /* Need to get ACL of directory */
+    if(S_ISDIR(sb.st_mode))
+	dir=NULL;
+    else
+	dir=directoryfromfilename(path);	
+    
+    rc=fsp_getpro(s,dir==NULL?path:dir,&dirpro);
+    /* get pro failure */
+    if(rc)
+    {
+	if(dir) free(dir);
+	errno = EACCES;
+	return -1;
+    }
+    /* owner shortcut */
+    if(dirpro & FSP_DIR_OWNER)
+    {
+	if(dir) free(dir);
+	errno = 0;
+	return 0;
+    }
+    /* check read access */
+    if(mode & R_OK)
+    {
+	if(dir)
+	{
+	    if(! (dirpro & FSP_DIR_GET))
+	    {
+		free(dir);
+		errno = EACCES;
+		return -1;
+	    }
+	} else
+	{
+	    if(! (dirpro & FSP_DIR_LIST))
+	    {
+		errno = EACCES;
+		return -1;
+	    }
+	}
+    }
+    /* check write access */
+    if(mode & W_OK)
+    {
+	if(dir)
+	{
+	    if( !(dirpro & FSP_DIR_DEL) || !(dirpro & FSP_DIR_ADD))
+	    {
+		free(dir);
+		errno = EACCES;
+		return -1;
+	    }
+	} else
+	{
+	    /* when checking directory for write access we are cheating
+	       by allowing ADD or DEL right */
+	    if( !(dirpro & FSP_DIR_DEL) && !(dirpro & FSP_DIR_ADD))
+	    {
+		errno = EACCES;
+		return -1;
+	    }
+	}
+    }
+
+    if(dir) free(dir);
+    errno = 0;
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsplib/fsplib.h	Sun Jan 16 16:12:13 2005 +0000
@@ -0,0 +1,184 @@
+#ifndef _FSPLIB_H
+#define _FSPLIB_H 1
+#include <time.h>
+/* The FSP v2 protocol support library - public interface */
+
+/*
+This file is part of fsplib - FSP protocol stack implemented in C
+language. See http://fsp.sourceforge.net for more information.
+
+Copyright (c) 2003-2004 by Radim HSN Kolar (hsn@netmag.cz)
+
+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.
+
+                     This is a free software.  Be creative.
+                    Let me know of any bugs and suggestions.
+*/
+
+/* definition of FSP protocol v2 commands */
+
+#define FSP_CC_VERSION      0x10    /* return server's version string.      */
+#define FSP_CC_INFO         0x11    /* return server's extended info block  */
+#define FSP_CC_ERR          0x40    /* error response from server.          */
+#define FSP_CC_GET_DIR      0x41    /* get a directory listing.             */
+#define FSP_CC_GET_FILE     0x42    /* get a file.                          */
+#define FSP_CC_UP_LOAD      0x43    /* open a file for writing.             */
+#define FSP_CC_INSTALL      0x44    /* close a file opened for writing.     */
+#define FSP_CC_DEL_FILE     0x45    /* delete a file.                       */
+#define FSP_CC_DEL_DIR      0x46    /* delete a directory.                  */
+#define FSP_CC_GET_PRO      0x47    /* get directory protection.            */
+#define FSP_CC_SET_PRO      0x48    /* set directory protection.            */
+#define FSP_CC_MAKE_DIR     0x49    /* create a directory.                  */
+#define FSP_CC_BYE          0x4A    /* finish a session.                    */
+#define FSP_CC_GRAB_FILE    0x4B    /* atomic get+delete a file.            */
+#define FSP_CC_GRAB_DONE    0x4C    /* atomic get+delete a file done.       */
+#define FSP_CC_STAT         0x4D    /* get information about file.          */
+#define FSP_CC_RENAME       0x4E    /* rename file or directory.            */
+#define FSP_CC_CH_PASSWD    0x4F    /* change password                      */
+#define FSP_CC_LIMIT        0x80    /* # > 0x7f for future cntrl blk ext.   */
+#define FSP_CC_TEST         0x81    /* reserved for testing                 */
+
+/* FSP v2 packet size */
+#define FSP_HSIZE 12                           /* 12 bytes for v2 header */
+#define FSP_SPACE 1024                         /* maximum payload.       */
+#define FSP_MAXPACKET   FSP_HSIZE+FSP_SPACE    /* maximum packet size.   */
+
+/* byte offsets of fields in the FSP v2 header */
+#define FSP_OFFSET_CMD          0
+#define FSP_OFFSET_SUM          1
+#define FSP_OFFSET_KEY          2
+#define FSP_OFFSET_SEQ          4
+#define FSP_OFFSET_LEN          6
+#define FSP_OFFSET_POS          8
+
+/* types of directory entry */ 
+#define FSP_RDTYPE_END      0x00
+#define FSP_RDTYPE_FILE     0x01
+#define FSP_RDTYPE_DIR      0x02
+#define FSP_RDTYPE_LINK	    0x03
+#define FSP_RDTYPE_SKIP     0x2A
+
+/* definition of directory bitfield for directory information */
+/* directory information is just going to be a bitfield encoding
+ * of which protection bits are set/unset
+ */
+
+#define FSP_PRO_BYTES	1	/* currently only 8 bits or less of info  */
+#define FSP_DIR_OWNER	0x01	/* does caller own directory              */
+#define FSP_DIR_DEL	0x02	/* can files be deleted from this dir     */
+#define FSP_DIR_ADD	0x04	/* can files be added to this dir         */
+#define FSP_DIR_MKDIR	0x08	/* can new subdirectories be created      */
+#define FSP_DIR_GET	0x10	/* are files readable by non-owners?      */
+#define FSP_DIR_README	0x20	/* does this dir contain an readme file?  */
+#define FSP_DIR_LIST    0x40    /* public can list directory              */
+#define FSP_DIR_RENAME  0x80    /* can files be renamed in this dir       */
+ 
+/* decoded FSP packet */
+typedef struct FSP_PKT {
+                        unsigned char       cmd; /* message code.             */
+                        unsigned char       sum; /* message checksum.         */
+                        unsigned short      key; /* message key.              */
+                        unsigned short      seq; /* message sequence number.  */
+                        unsigned short      len; /* number of bytes in buf 1. */
+                        unsigned int        pos; /* location in the file.     */                        unsigned short     xlen; /* number of bytes in buf 2  */
+
+                        unsigned char   buf[FSP_SPACE];   /* packet payload */
+              } FSP_PKT;
+
+/* FSP host:port */
+typedef struct FSP_SESSION {
+			void *   lock;            /* key locking         */
+                        unsigned int   timeout;   /* send timeout 1/1000s*/
+			unsigned int   maxdelay;  /* maximum recv. delay */
+                        unsigned short seq;       /* sequence number     */
+                        unsigned int dupes;       /* total pkt. dupes    */
+                        unsigned int resends;     /* total pkt. sends    */
+                        unsigned int trips;       /* total pkt trips     */
+                        unsigned long rtts;       /* cumul. rtt          */
+                        unsigned int last_rtt;    /* last rtt            */
+                        unsigned int last_delay;  /* last delay time     */
+                        unsigned int last_dupes;  /* last dupes          */
+                        unsigned int last_resends;/* last resends        */
+                        int fd;                   /* i/o descriptor      */
+                        char *password;           /* host acccess password */
+                } FSP_SESSION;
+
+/* fsp directory handle */
+typedef struct FSP_DIR {
+                        char   *dirname;          /* directory name */
+                        short   inuse;            /* in use counter */
+                        int     dirpos;           /* current directory pos. */
+                        unsigned short blocksize; /* size of directory block */
+                        unsigned char  *data;     /* raw directory data */
+                        unsigned int   datasize;  /* size of raw dir. data */
+} FSP_DIR;
+
+/* fsp directory entry */
+typedef struct FSP_RDENTRY  {
+                       char name[255 + 1];        /* entry name */
+		       unsigned short namlen;     /* length     */
+		       unsigned char type;        /* field type */
+		       unsigned short reclen;     /* directory record length */
+		       unsigned int  size;
+		       unsigned int  lastmod;
+} FSP_RDENTRY;
+
+/* fsp file handle */
+typedef struct FSP_FILE {
+    		      FSP_PKT in,out;            /* io packets */
+		      FSP_SESSION *s;            /* master session */
+		      char *name;                /* filename for upload */
+		      unsigned char writing;     /* opened for writing */
+		      unsigned char eof;         /* EOF reached? */
+		      unsigned char err;         /* i/o error? */
+		      int bufpos;                /* position in buffer */
+		      unsigned int pos;          /* position of next packet */
+} FSP_FILE;
+
+/* function prototypes */
+
+/* session management */
+FSP_SESSION * fsp_open_session(const char *host,unsigned short port, const char *password);
+void fsp_close_session(FSP_SESSION *s);
+
+/* packet encoding/decoding */
+size_t fsp_pkt_write(const FSP_PKT *p,void *space);
+int fsp_pkt_read(FSP_PKT *p,const void *space,size_t recv_len);
+
+/* send/receive round-trip */
+int fsp_transaction(FSP_SESSION *s,FSP_PKT *p,FSP_PKT *rpkt);
+
+/* directory listing commands */
+FSP_DIR * fsp_opendir(FSP_SESSION *s,const char *dirname);
+int fsp_readdir_r(FSP_DIR *dir,struct dirent *entry, struct dirent **result);
+long fsp_telldir(FSP_DIR *dirp);
+void fsp_seekdir(FSP_DIR *dirp, long loc);
+void fsp_rewinddir(FSP_DIR *dirp);
+struct dirent * fsp_readdir(FSP_DIR *dirp);
+int fsp_readdir_native(FSP_DIR *dir,FSP_RDENTRY *entry, FSP_RDENTRY **result);
+int fsp_closedir(FSP_DIR *dirp);
+/* high level  file i/o */
+FSP_FILE * fsp_fopen(FSP_SESSION *session, const char *path,const char *modeflags);
+size_t fsp_fread(void *ptr,size_t size,size_t nmemb,FSP_FILE *file);
+size_t fsp_fwrite(const void * source, size_t size, size_t count, FSP_FILE * file);
+int fsp_fclose(FSP_FILE *file);
+int fsp_fpurge(FSP_FILE *file);
+int fsp_fflush(FSP_FILE *file);
+int fsp_fseek(FSP_FILE *stream, long offset, int whence);
+long fsp_ftell(FSP_FILE *f);
+void fsp_rewind(FSP_FILE *f);
+/* misc. functions */
+int fsp_stat(FSP_SESSION *s,const char *path,struct stat *sb);
+int fsp_mkdir(FSP_SESSION *s,const char *directory);
+int fsp_rmdir(FSP_SESSION *s,const char *directory);
+int fsp_unlink(FSP_SESSION *s,const char *directory);
+int fsp_rename(FSP_SESSION *s,const char *from, const char *to);
+int fsp_access(FSP_SESSION *s,const char *path, int mode);
+/* fsp protocol specific functions */
+int fsp_getpro(FSP_SESSION *s,const char *directory,unsigned char *result);
+int fsp_install(FSP_SESSION *s,const char *fname,time_t timestamp);
+int fsp_canupload(FSP_SESSION *s,const char *fname);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsplib/lock.c	Sun Jan 16 16:12:13 2005 +0000
@@ -0,0 +1,285 @@
+#include <string.h>
+#include <stdio.h>
+#include "lock.h"
+
+/* ************ Locking functions ***************** */
+#ifndef FSP_NOLOCKING
+
+static char code_str[] =
+    "0123456789:_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void make_key_string(	FSP_LOCK *lock,
+                                unsigned long server_addr,
+			   	unsigned long server_port)
+{
+  unsigned long v1, v2;
+  char *p;
+
+  strcpy(lock->key_string,FSP_KEY_PREFIX);
+  for(p = lock->key_string; *p; p++);
+  v1 = server_addr;
+  v2 = server_port;
+
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  v1 = v1 | (v2 << (32-3*6));
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
+  *p   = 0;
+}
+#endif
+
+/********************************************************************/
+/******* For those systems that has SysV shared memory + semop ******/
+/********************************************************************/
+#ifdef FSP_USE_SHAREMEM_AND_SEMOP
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef _SEM_SEMUN_UNDEFINED
+union semun
+{
+  int val;
+  struct semid_ds *buf;
+  unsigned short int *array;
+  struct seminfo *__buf;
+};
+#endif
+
+unsigned short client_get_key (FSP_LOCK *lock)
+{
+  struct sembuf sem;
+  sem.sem_num = 0;
+  sem.sem_op = -1;
+  sem.sem_flg = SEM_UNDO;
+  
+  if(semop(lock->lock_sem,&sem,1) == -1 )
+  {
+      perror("semop lock");
+  }
+  return(*lock->share_key);
+}
+
+void client_set_key (FSP_LOCK *lock,unsigned short key)
+{
+  struct sembuf sem;
+
+  sem.sem_num = 0;
+  sem.sem_op  = 1;
+  sem.sem_flg = SEM_UNDO;
+
+  *lock->share_key = key;
+  if(semop(lock->lock_sem,&sem,1) == -1) {
+    perror("semop unlock");
+  }
+}
+
+int client_init_key (FSP_LOCK *lock,
+                            unsigned long server_addr,
+			    unsigned short server_port)
+{
+  mode_t omask;
+  key_t lock_key;
+  int fd;
+  union semun sun;
+  struct sembuf sem;
+
+  make_key_string(lock,server_addr,server_port);
+
+  omask = umask(0);
+  fd = open(lock->key_string,O_RDWR|O_CREAT,0666);
+  umask(omask);
+  close(fd);
+
+  if((lock_key = ftok(lock->key_string,238)) == -1) {
+    perror("ftok");
+    return -1;
+  }
+
+  if((lock->lock_shm = shmget(lock_key,2*sizeof(unsigned int),IPC_CREAT|0666)) == -1) {
+    perror("shmget");
+    return -1;
+  }
+
+  if(!(lock->share_key = (unsigned int *) shmat(lock->lock_shm,NULL,0))) {
+    perror("shmat");
+    return -1;
+  }
+
+  if((lock->lock_sem = semget(lock_key,0,0)) == -1) {
+      /* create a new semaphore and init it */
+      if((lock->lock_sem = semget(lock_key,2,IPC_CREAT|0666)) == -1) {
+	  perror("semget");
+	  return -1;
+      }
+      /* we need to init this semaphore */
+      sun.val=1;
+      if(semctl(lock->lock_sem,0,SETVAL,sun) == -1)
+      {
+	  perror("semctl setval");
+	  return -1;
+      }
+  }
+
+  /* increase in use counter */
+  sem.sem_num = 1;
+  sem.sem_op = 1;
+  sem.sem_flg = SEM_UNDO;
+
+  if(semop(lock->lock_sem,&sem,1) == -1) {
+      perror("semop incuse");
+  }
+
+  return 0;
+}
+
+void client_destroy_key(FSP_LOCK *lock)
+{
+    int rc;
+    struct sembuf sem;
+    
+    if (shmdt(lock->share_key) < 0)
+    {
+	perror("shmdt");
+	return;
+    }
+    /* check if we are only one process holding lock */
+    rc = semctl(lock->lock_sem,1,GETVAL);
+    if (rc == 1)
+    {
+	/* safe to destroy */
+	if (
+	     (semctl(lock->lock_sem,0,IPC_RMID) < 0) ||
+	     (shmctl(lock->lock_shm,IPC_RMID,NULL) < 0) ||
+	     (unlink(lock->key_string) < 0) )
+	    rc=0;/* ignore cleanup errors */
+    }
+    else 
+	if(rc > 1)
+	{
+	      /* we need to decrease sem. */
+	      sem.sem_num = 1;
+	      sem.sem_op = -1;
+	      sem.sem_flg = SEM_UNDO;
+
+	      if(semop(lock->lock_sem,&sem,1) == -1) {
+		  perror("semop decuse");
+	      }
+	}
+}
+#endif
+
+
+/********************************************************************/
+/******* For those who do not want to use locking *******************/
+/********************************************************************/
+#ifdef FSP_NOLOCKING
+
+unsigned short client_get_key (FSP_LOCK *lock)
+{
+    return lock->share_key;
+}
+
+void client_set_key (FSP_LOCK *lock,unsigned short key)
+{
+    lock->share_key=key;
+}
+
+int client_init_key (FSP_LOCK *lock,
+                            unsigned long server_addr,
+			    unsigned short server_port)
+{
+    return 0;
+}
+
+void client_destroy_key(FSP_LOCK *lock)
+{
+    return;
+}
+#endif
+
+/********************************************************************/
+/******* For those systems that has lockf function call *************/
+/********************************************************************/
+#ifdef FSP_USE_LOCKF
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+unsigned short client_get_key (FSP_LOCK *lock)
+{
+     unsigned int okey;
+
+     if (lockf(lock->lock_fd, F_LOCK, sizeof(okey)) < 0)
+     {
+	    perror("lockf");
+     }
+
+     if (read(lock->lock_fd, &okey, sizeof(okey)) < 0)
+     {
+	    perror("readlk");
+     }
+
+     if (lseek(lock->lock_fd, 0L, 0) < 0)
+     {
+            perror("seek");
+     }
+
+    return(okey);
+}
+
+void client_set_key (FSP_LOCK *lock,unsigned short nkey)
+{
+    unsigned int key;
+
+    key=nkey;
+
+    if (write(lock->lock_fd, &key, sizeof(key)) < 0)
+    {
+	perror("write");
+    }
+    if (lseek(lock->lock_fd, 0L, 0) < 0)
+    {
+	perror("seek");
+    }
+    if (lockf(lock->lock_fd, F_ULOCK, sizeof(key)) < 0)
+    {
+	perror("unlockf");
+    }
+}
+
+int client_init_key (FSP_LOCK *lock,
+                            unsigned long server_addr,
+			    unsigned short server_port)
+{
+    mode_t omask;
+
+    make_key_string(lock,server_addr, server_port);
+
+    omask = umask(0);
+    lock->lock_fd = open(lock->key_string, O_RDWR | O_CREAT, 0666);
+    (void)umask(omask);
+
+    if(lock->lock_fd < 0)
+	return -1;
+    else
+	return 0;	
+}
+
+void
+client_destroy_key(FSP_LOCK *lock)
+{
+    (void)close(lock->lock_fd);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/fsplib/lock.h	Sun Jan 16 16:12:13 2005 +0000
@@ -0,0 +1,45 @@
+#ifndef _FSPLIB_H_LOCK
+#define _FSPLIB_H_LOCK 1
+
+#ifndef FSP_NOLOCKING
+/* define locking prefix if needed */
+# ifndef FSP_KEY_PREFIX
+#  define FSP_KEY_PREFIX "/tmp/.FSPL"
+# endif
+#endif
+
+#ifdef FSP_USE_SHAREMEM_AND_SEMOP
+
+typedef struct FSP_LOCK {
+		unsigned int *share_key;
+		int   lock_shm;
+		int   lock_sem;
+		char key_string[sizeof(FSP_KEY_PREFIX)+32];
+} FSP_LOCK;
+
+#elif defined(FSP_NOLOCKING)
+
+typedef struct FSP_LOCK {
+               unsigned short share_key;
+} FSP_LOCK;
+
+#elif defined(FSP_USE_LOCKF)
+
+typedef struct FSP_LOCK {  
+	       int lock_fd;
+	       char key_string[sizeof(FSP_KEY_PREFIX)+32];
+} FSP_LOCK;
+
+#else
+#error "No locking type specified"
+#endif
+
+/* prototypes */
+
+unsigned short client_get_key (FSP_LOCK *lock);
+void client_set_key (FSP_LOCK *lock,unsigned short key);
+int client_init_key (FSP_LOCK *lock,
+                            unsigned long server_addr,
+			    unsigned short server_port);
+void client_destroy_key(FSP_LOCK *lock);
+#endif