test.c000644 001751 001751 00000002335 11214750014 012174 0ustar00hsnusers000000 000000 #include #include #include #include #include #include #include "fsplib.h" int main (int argc, char *argv[]) { int i; FSP_SESSION* s; FSP_PKT p; FSP_PKT r; FSP_FILE *f; struct dirent *d; FSP_DIR *dir; int port=2000; printf("Checking for fsp/udp service\n"); s=fsp_open_session("localhost",0,NULL); assert(s); fsp_close_session(s); if(argc>1) port=atoi(argv[1]); printf("Running tests against fspd on localhost %d\n",port); s=fsp_open_session("localhost",port,NULL); assert(s); s->timeout=9000; p.cmd=FSP_CC_VERSION; for(i=0;i<100;i++) { assert (fsp_transaction(s,&p,&r)==0 ); } /* dir list test */ dir=fsp_opendir(s,"/"); assert(dir); while ( (d=fsp_readdir(dir)) != NULL ) printf("%s\n",d->d_name); fsp_closedir(dir); /* get a file */ f=fsp_fopen(s,"system.log","rb"); assert(f); while( ( i=fsp_fread(p.buf,1,1000,f) ) ) write(1,p.buf,i); fsp_fclose(f); printf("resends %d, dupes %d, cum. rtt %ld, last rtt %d\n",s->resends,s->dupes,s->rtts/s->trips,s->last_rtt); /* bye! */ fsp_close_session(s); return 0; } fsplib.h000644 001751 001751 00000022020 11214750014 012472 0ustar00hsnusers000000 000000 #ifndef _FSPLIB_H #define _FSPLIB_H 1 #include #include #include #include /* 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-2005 by Radim HSN Kolar (hsn@sendmail.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; typedef union dirent_workaround { struct dirent dirent; char fill[offsetof (struct dirent, d_name) + MAXNAMLEN + 1]; } dirent_workaround; /* 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 lock.h000644 001751 001751 00000001714 11214750014 012152 0ustar00hsnusers000000 000000 #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 lock.c000644 001751 001751 00000013614 11214750014 012147 0ustar00hsnusers000000 000000 #include #include #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 #include #include #include #include #include #include #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 su; 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 */ su.val=1; if(semctl(lock->lock_sem,0,SETVAL,su) == -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 #include #include 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 fsplib.c000644 001751 001751 00000077512 11214750014 012505 0ustar00hsnusers000000 000000 /* This file is part of fsplib - FSP protocol stack implemented in C language. See http://fsp.sourceforge.net for more information. Copyright (c) 2003-2005 by Radim HSN Kolar (hsn@sendmail.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 #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #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; } 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> 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_lenFSP_MAXPACKET) { /* too long */ errno = EMSGSIZE; return -1; } ptr=space; /* check sum */ mysum=-ptr[FSP_OFFSET_SUM]; for(i=0;i> 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); retry = random() & 0xfff8; if (s->seq == retry) s->seq ^= 0x1080; else s->seq = retry; dupes = retry = 0; t_delay = 0; /* compute initial delay here */ /* we are using hardcoded value for now */ f_delay = 1340; l_delay = 0; 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; } /* check command code */ if( (rpkt->cmd != p->cmd) && (rpkt->cmd != FSP_CC_ERR)) { dupes++; continue; } /* check correct filepos */ if( (rpkt->pos != p->pos) && ( p->cmd == FSP_CC_GET_DIR || p->cmd == FSP_CC_GET_FILE || p->cmd == FSP_CC_UP_LOAD || p->cmd == FSP_CC_GRAB_FILE || p->cmd == FSP_CC_INFO) ) { 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 ( (fd = getaddrinfo(host,port_s,&hints,&res)) != 0 ) { if ( fd != EAI_SYSTEM ) { /* We need to set errno ourself */ switch (fd) { case EAI_SOCKTYPE: case EAI_SERVICE: case EAI_FAMILY: errno = EOPNOTSUPP; break; case EAI_AGAIN: errno = EAGAIN; break; case EAI_FAIL: errno = ECONNRESET; break; case EAI_BADFLAGS: errno = EINVAL; break; case EAI_MEMORY: errno = ENOMEM; break; default: errno = EFAULT; } } 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() & 0xfff8; 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_ERR ) { /* 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); } errno = EPERM; return NULL; } dir->inuse=1; dir->blocksize=blocksize; dir->dirname=strdup(dirname); dir->datasize=pos; errno = 0; return dir; } int fsp_readdir_r(FSP_DIR *dir,struct dirent *entry, struct dirent **result) { FSP_RDENTRY fentry,*fresult; int rc; char *c; 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; #ifdef HAVE_DIRENT_TYPE /* convert FSP dirent to OS dirent */ if (fentry.type == FSP_RDTYPE_DIR ) entry->d_type=DT_DIR; else entry->d_type=DT_REG; #endif /* remove symlink destination */ c=strchr(fentry.name,'\n'); if (c) { *c='\0'; rc=fentry.namlen-strlen(fentry.name); fentry.reclen-=rc; fentry.namlen-=rc; } #ifdef HAVE_DIRENT_FILENO entry->d_fileno = 10; #endif entry->d_reclen = fentry.reclen; strncpy(entry->d_name,fentry.name,MAXNAMLEN); if (fentry.namlen >= MAXNAMLEN) { entry->d_name[MAXNAMLEN] = '\0'; #ifdef HAVE_DIRENT_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] = '\0'; strncpy(entry->name,(char *)( dir->data + dir->dirpos ),255); /* check for ASCIIZ encoded filename */ if (memchr(dir->data + dir->dirpos,0,dir->datasize - dir->dirpos) != NULL) { namelen = strlen( (char *) dir->data+dir->dirpos); } else { /* \0 terminator not found at end of filename */ *result = NULL; return 0; } /* 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 dirent_workaround entry; struct dirent *result; if (dirp == NULL) return NULL; if ( fsp_readdir_r(dirp,&entry.dirent,&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_ERR) { 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_ERR) { 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_ERR) { 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_ERR) { 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_ERR) { errno = ENOENT; return -1; } if(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_ERR) { 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_ERR) { 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; } TODO000644 001751 001751 00000000553 11214751230 011542 0ustar00hsnusers000000 000000 high priority ============= low priority ============ caching normalizing of file pathnames cache server flag bits (i.e. readonly, ...) and max. packet size large packets errno ===== set char * fsp_errno from FSP_CC_ERR error messages all functions should set errno now api design ========== open session should ping the server? Or add function for it? NEWS000644 001751 001751 00000001730 11214750014 011546 0ustar00hsnusers000000 000000 0.11 we can optionally build shared library name of static FSPLIB library is libfsplib.a 0.10 GNU autoconf toolchain support removed fsp_open_session now sets errno 0.9 fixed 3 security problems reported by Kalle Olavi Niemitalo 0.8 security bugfix release 0.7 added missing #includes into fsplib.h 0.6 make more tests on received packet -- improve resistance against certain kind of attacks. SCons build framework improved fixed typo in configure.ac 0.5 use stdint.h if available - should fix Mac OSX build problem SCons build framework improved 0.4 Added build time checks for various members of dirent structure. fsplib should built on IRIX as result. 0.3 SCons build system fix: prefix now works, fixed install target, compile with -O by default Filter symlinks from non native directory listings 0.2 fsplib now works! 0.1 Project created, coded and first released to public. README000644 001751 001751 00000004167 11214750014 011736 0ustar00hsnusers000000 000000 FSP v2 protocol stack library fsplib This is C library which support talking with FSP server using FSP v2 protocol and provides posix-like file manipulation interface. For more information about FSP protocol see http://fsp.sourceforge.net/ For library and API info see http://fsp.sourceforge.net/fsplib.html *********************************************************************** This is a free software. Be creative. Let me know of any bugs and suggestions. *********************************************************************** Copyright (c) 2003, 2004, 2005, 2006, 2009 by Radim HSN Kolar (hsn sendmail.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. Building This software is builded by Scons software construction tool - http://www.scons.org/ Scons building run: scons [options] [install] for building/installing the library and header file. Unlike Autotools you must add build-time configure options to install target also. Build time configuration At build time you can configure locking subsystem. There are two lock configuration options. Note: Scons do not uses leading -- before option names. Example: scons with-lockprefix=/tmp/.FSPL install with-lockprefix=path Set lock prefix path to (default /tmp/.FSPL). Most users do not need to change it. with-locking=none/semop/lockf Configure type of locking subsytem used. FSP library support currently 3 types of locking subsystem. none - no locking used lockf - use lockf on lock file semop - use Sys V shared memory and semaphore. Lock file will be still created because of use of ftok, but no locking is done on this file -> it can be on shared filesystem. prefix=/path Where to install builded library and header file. Standard option. enable-maintainer-mode=yes Compile with more debug code inside enable-shared=yes Build and install shared version of fsplib AUTHORS000644 001751 001751 00000000026 11214750014 012114 0ustar00hsnusers000000 000000 Radim Kolar - THE MAN ChangeLog000644 001751 001751 00000004743 11214750014 012630 0ustar00hsnusers000000 000000 0.11 optionally build and install shared library (EXPERIMENTAL FEATURE) based on report by Ahmed El-Mahmoudy, Debian fsplib maintainer name of static fsp library should be libfsplib.a as it used to be in libtool's days. Noticed by Ahmed El-Mahmoudy. 0.10 configure.ac nuked, fsplib builds now with scons tool only INSTALL file removed, it was autoconf specific Makefile.am removed Don't turn on unreachable code GCC compilation warning, it was wrong for all tested 3.x and 4.x GCC versions Check return codes from getaddrinfo and turn them into errno used in fsp_open_session Improved check for valid arguments in function fsp_readdir_native reported by Kalle Olavi Niemitalo, discovered by witekfl 0.9 Solaris compile fix by Brian Masney fix possible security hole if MAXNAMLEN>256 reported by Kalle Olavi Niemitalo add terminating \0 if directory entry is MAXNAMLEN long check if server sends ASCIIZ terminated filenames reported by Kalle Olavi Niemitalo fixed possible buffer overflow on systems not defining dirent.d_name long enough. Reported by Kalle Olavi Niemitalo 0.8 Security bugfix release off by one error, found by David Binderman https://bugzilla.novell.com/show_bug.cgi?id=150399 0.7 Added missing #includes to fsplib.h 0.6 SCons build framework now has full support for distcc and ccache seq. number is now random test received filepos test received command reply fixed typo in configure.ac ./test program can take optional port number 0.5 new configure tests for stdint.h patch from Brian Masney SCons build framework improved, now support CC from command line and supports distcc use. 0.4 renamed configure/scons defines from HAVE_XX to HAVE_DIRENT_XX new tests for dirent.d_type and dirent.d_fileno 0.3 Check for prefix= in scons build scripts Correct install target in scons build scripts Remove symlink destination from directory listing in fsp_readdir_r function. FSP symlinks are returned only from fsp_readdir_native call for better compatibility with other C programs. Scons: compile with -O by default fsplib.c: avoid `l_delay' might be used uninitialized bogus warning. fixed compile warning on test.c 0.2 Protect against multiple including of fsplib internal lock.h file More detailed error reporting on semop failures Corrected fatal pointer retyping error when calling locking subsystem Retry delay changed from 1.25s to standard 1.34s. Old value was used for debug purposes. 0.1 First public release. Let's go! COPYING000644 001751 001751 00000000552 11214750014 012103 0ustar00hsnusers000000 000000 Copyright (c) 2003-2006 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. SConstruct000644 001751 001751 00000013211 11214750014 013076 0ustar00hsnusers000000 000000 # Process this file with http://www.scons.org to build FSPlib. import os # init Scons EnsureSConsVersion(0,96) PACKAGE='fsplib' VERSION='0.11' #Defaults PREFIX='/usr/local' SHARED=0 env = Environment() # Turn CPPFLAGS to list env.Append( CPPFLAGS = []) ################### Functions ###################### def importEnv(list=None, prefix=None): if list: for i in list: if os.environ.get(i): kw={} kw[i]=os.environ.get(i) kw={ 'ENV': kw } env.Append(**kw) if prefix: for i in os.environ.keys(): if i.startswith(prefix): kw={} kw[i]=os.environ.get(i) kw={ 'ENV': kw } env.Append(**kw) #import environment importEnv(['HOME','CC']) importEnv(prefix='DISTCC_') importEnv(prefix='CCACHE_') if env['ENV'].get('CC'): env.Replace( CC = env['ENV'].get('CC')) # Get CC from commandline if ARGUMENTS.get('CC', 0): env.Replace(CC = ARGUMENTS.get('CC')) ############# Custom configure tests ################### def checkForDirentMember(conf,member,symbol): """Checks if dirent structure has specified field member. Keyword arguments: member -- what member we are checking symbol -- symbol to be defined by preprocessor if member exists """ conf.Message("checking whether dirent structure has member "+member+"... ") rc=conf.TryCompile(""" #include #include void dummy(void); void dummy() { struct dirent d; d."""+member+"""=0; } """,".c") if rc: conf.env.Append(CPPFLAGS = '-D'+symbol) conf.Result(rc) return rc def checkForGCCOption(conf,option): """Check if compiler supports specified option""" conf.Message("checking whether CC supports "+option+" ") lastCFLAGS=conf.env['CCFLAGS'] conf.env.Append(CCFLAGS = option) rc = conf.TryCompile(""" void dummy(void); void dummy(void) {} """,'.c') if not rc: conf.env.Replace(CCFLAGS = lastCFLAGS) conf.Result(rc) return rc def checkForMaintainerMode(conf): """Check if maintainer mode is enabled by command line""" conf.Message("checking whether to enable maintainer mode... ") if ARGUMENTS.get('maintainer-mode', 0) or \ ARGUMENTS.get('enable-maintainer-mode', 0): conf.Result(1) conf.env.Append(CCFLAGS = '-O0') conf.env.Append(CPPFLAGS = '-DMAINTAINER_MODE') else: conf.env.Append(CCFLAGS = '-O') conf.Result(0) def checkForLockPrefix(conf): """check for user-supplied lock prefix on command line""" conf.Message("checking for user supplied lockprefix... ") lp = ARGUMENTS.get('lockprefix', 0) or ARGUMENTS.get("with-lockprefix",0) if lp: conf.Result(1) conf.env.Append(CPPFLAGS = '-DFSP_KEY_PREFIX=\\"'+lp+'\\"') else: conf.Result(0) def checkForUserPrefix(conf): """check for user-supplied installation prefix""" global PREFIX conf.Message("checking for user supplied prefix... ") lp = ARGUMENTS.get('prefix', 0) if lp: conf.Result(1) PREFIX=lp else: conf.Result(0) def checkForBuildingSharedLibrary(conf): """check if building shared library was requested""" global SHARED conf.Message("checking whether to build shared library... ") makeshared=ARGUMENTS.get('enable-shared', 0) if makeshared == 0 or makeshared == 'no': conf.Result(0) SHARED=0 else: conf.Result(1) SHARED=1 #Start configuration conf = Configure(env,{'checkForGCCOption':checkForGCCOption, 'MAINTAINER_MODE':checkForMaintainerMode, 'checkForLockPrefix':checkForLockPrefix, 'checkPrefix':checkForUserPrefix, 'checkDirentFor':checkForDirentMember, 'ENABLE_SHARED':checkForBuildingSharedLibrary} ) for option in Split(""" -Wall -W -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Waggregate-return -Wmissing-declarations -Wmissing-format-attribute -Wnested-externs -ggdb -fno-common -Wchar-subscripts -Wcomment -Wimplicit -Wsequence-point -Wreturn-type -Wfloat-equal -Wno-system-headers -Wredundant-decls -Wmissing-noreturn -pedantic -Wlong-long -Wundef -Winline -Wpointer-arith -Wno-unused-parameter """): conf.checkForGCCOption(option) #portability checks if not conf.CheckType("union semun", "#include \n#include \n#include ",'c'): conf.env.Append(CPPFLAGS = "-D_SEM_SEMUN_UNDEFINED=1") conf.checkDirentFor('d_namlen','HAVE_DIRENT_NAMLEN') conf.checkDirentFor('d_fileno','HAVE_DIRENT_FILENO') conf.checkDirentFor('d_type','HAVE_DIRENT_TYPE') if conf.CheckCHeader('stdint.h'): conf.env.Append(CPPFLAGS = "-DHAVE_STDINT_H") #locking type checks fun_lockf=conf.CheckFunc("lockf") fun_semop=conf.CheckFunc("semop") fun_shmget=conf.CheckFunc("shmget") #select locking type lt=ARGUMENTS.get('locking', 0) or ARGUMENTS.get("with-locking",0) or ARGUMENTS.get("lock",0) or ARGUMENTS.get("with-lock",0) if lt == "none": conf.env.Append(CPPFLAGS = '-DFSP_NOLOCKING') elif lt == "lockf" and fun_lockf: conf.env.Append(CPPFLAGS = '-DFSP_USE_LOCKF') elif lt == "semop" and fun_semop and fun_shmget: conf.env.Append(CPPFLAGS = '-DFSP_USE_SHAREMEM_AND_SEMOP') elif fun_semop and fun_shmget: conf.env.Append(CPPFLAGS = '-DFSP_USE_SHAREMEM_AND_SEMOP') elif fun_lockf: conf.env.Append(CPPFLAGS = '-DFSP_USE_LOCKF') else: conf.env.Append(CPPFLAGS = '-DFSP_NOLOCKING') conf.checkForLockPrefix() conf.checkPrefix() conf.ENABLE_SHARED() conf.MAINTAINER_MODE() conf.Finish() # process build rules Export( Split("env PREFIX PACKAGE VERSION SHARED")) env.SConscript(dirs=['.']) SConscript000644 001751 001751 00000002642 11214750014 013064 0ustar00hsnusers000000 000000 Import(Split("env PREFIX VERSION PACKAGE SHARED")) #Build static library libfsp=env.StaticLibrary(target = 'fsplib', source = Split('fsplib.c lock.c')) env.Alias("build", libfsp) #Build shared library if SHARED: env.Append(SHLIBSUFFIX = '.0.0.0') env.Append(SHLINKFLAGS = '-Wl,-soname -Wl,libfsplib.so.0') libfspshared=env.SharedLibrary(target = 'fsplib', source = Split('fsplib.c lock.c')) env.Alias("build", libfspshared) #Install library and header env.Install(dir = PREFIX+'/lib', source = libfsp) env.Install(dir = PREFIX+'/include', source='fsplib.h') if SHARED: env.Install(dir = PREFIX+'/lib', source = libfspshared) #Build test program test=env.Program(target = 'test', source = ['test.c', libfsp]) env.Alias("build",test) if SHARED: testshared=env.Program(target = 'test-shared', source = ['test.c', libfspshared]) env.Alias("build",testshared) # *************** Targets **************** #Add install target env.Alias("install",[ PREFIX+'/lib', PREFIX+'/include']) #Change default target to build env.Default(None) env.Default("build") #Add dist target TARBALL=PACKAGE+'-'+VERSION+'.tar.gz' env.Replace(TARFLAGS = '-c -z') env.Tar(TARBALL,Split("test.c fsplib.h lock.h lock.c fsplib.c")) env.Tar(TARBALL,Split("TODO NEWS README AUTHORS ChangeLog COPYING")) env.Tar(TARBALL,Split("SConstruct SConscript")) env.Alias("dist",TARBALL) #Clean tarball when doing build clean env.Clean("build",TARBALL)