source: TI05-delivery/trunk/src/bbftp-server-3.2.0/bbftpd/bbftpd_retr.c @ 773

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/trunk/src/bbftp-server-3.2.0/bbftpd/bbftpd_retr.c@773
Revision 773, 32.9 KB checked in by spascoe, 14 years ago (diff)

Initial import of bbftp source

Line 
1/*
2 * bbftpd/bbftpd_retr.c
3 * Copyright (C) 1999, 2000, 2001, 2002 IN2P3, CNRS
4 * bbftp@in2p3.fr
5 * http://doc.in2p3.fr/bbftp
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */ 
21
22/****************************************************************************
23
24 
25 bbftpd_retr.c  v 2.0.0 2001/02/22  - Routines creation
26                v 2.0.1 2001/04/17  - Realy wait STARTCHILDTO
27                                    - Correct indentation
28                                    - Port to IRIX
29                v 2.0.2 2001/05/04  - Correct include for RFIO
30                v 2.1.0 2001/05/30  - Correct syslog level
31                                    - Reorganise routines as in bbftp_
32             
33*****************************************************************************/
34#include <bbftpd.h>
35
36#include <dirent.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <fnmatch.h>
40#include <netinet/in.h>
41#include <signal.h>
42#include <syslog.h>
43#include <sys/stat.h>
44#include <sys/types.h>
45#if TIME_WITH_SYS_TIME
46# include <sys/time.h>
47# include <time.h>
48#else
49# if HAVE_SYS_TIME_H
50#  include <sys/time.h>
51# else
52#  include <time.h>
53# endif
54#endif
55#include <unistd.h>
56#include <utime.h>
57#if HAVE_STRING_H
58# include <string.h>
59#endif
60
61#include <common.h>
62#include <daemon.h>
63#include <daemon_proto.h>
64#include <status.h>
65#include <structures.h>
66
67#ifdef WITH_GZIP
68#include <zlib.h>
69#endif
70
71extern int  transferoption ;
72extern my64_t  filesize ;
73extern int  requestedstreamnumber ;
74extern int  buffersizeperstream ;
75extern int  maxstreams ;
76extern int  filemode ;
77extern int  *myports ;
78extern char *readbuffer ;
79extern char *compbuffer ;
80extern int  *mychildren ;
81extern int  *mysockets ;
82extern int  nbpidchild ;
83extern int  unlinkfile ;
84extern int  incontrolsock ;
85extern int  outcontrolsock ;
86extern  int     datato ;
87extern  int     ackto ;
88extern int  state ;
89extern int  childendinerror ;
90extern int  flagsighup ;
91extern char lastaccess[9] ;
92extern char lastmodif[9] ;
93extern struct  timeval  tstart ;
94extern int  protocolversion ;
95
96/*******************************************************************************
97** bbftpd_retrlisdir :                                                         *
98**                                                                             *
99**      Routine to list a directory                                            *
100**                                                                             *
101**      OUPUT variable :                                                       *
102**          filelist   :  Where to store the file list (to be freed by caller  *
103**          filelistlen:  Length of filelist buffer                            *
104**          logmessage :  to write the error message in case of error          *
105**                                                                             *
106**      GLOBAL VARIABLE USED :                                                 *                                                                      *
107**                                                                             *
108**      RETURN:                                                                *
109**          -1  Unrecoverable error                                            *
110**           0  OK                                                             *
111**           1  recoverable error                                              *
112**                                                                             *
113*******************************************************************************/
114
115int bbftpd_retrlistdir(char *pattern,char **filelist,int *filelistlen,char *logmessage)
116{
117    int     lastslash ;
118    char    *pointer ;
119    char    *dirpath ;
120     DIR     *curdir ;
121#ifdef STANDART_FILE_CALL
122    struct dirent *dp ;
123    struct stat statbuf;
124#else
125#ifdef STANDART_READDIR_CALL
126    struct dirent *dp ;
127#else
128    struct dirent64 *dp ;
129#endif
130    struct stat64 statbuf ;
131#endif
132    int     lengthtosend;
133    int     numberoffile ;
134    /*
135    ** Structure to keep the filenames
136    */
137    struct keepfile {
138        char    *filename ;
139        char    filechar[3] ;
140        struct  keepfile *next ;
141    } ;
142    struct keepfile *first_item ;
143    struct keepfile *current_item ;
144    struct keepfile *used_item ;
145    char    *filepos ;
146    int     i ;
147    int     savederrno ;
148   
149    /*
150    ** Check if it is a rfio list
151    */
152    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
153#if defined(WITH_RFIO) || defined(WITH_RFIO64)
154        return bbftpd_retrlistdir_rfio(pattern,filelist,filelistlen,logmessage) ;
155#else
156        /*
157        ** Just reply that RFIO is not supported
158        */
159        sprintf(logmessage,"Fail to LIST : RFIO not supported") ;
160        return -1 ;
161#endif
162    }
163    /*
164    **  We are going allocate memory for the directory name
165    **  We allocate stelent(pattern) + 1 char for \0 + 3 char
166    **  if the directory is "."
167    */
168    if ( (dirpath = (char *) malloc ( strlen(pattern) + 1 + 3 )) == NULL ) {
169        sprintf(logmessage,"Error allocating memory for dirpath %s",strerror(errno)) ;
170        return -1 ;
171    } 
172    pointer = pattern ;
173    lastslash = strlen(pointer) - 1 ;
174    while ( lastslash >= 0 && pointer[lastslash] != '/') lastslash-- ;
175    if ( lastslash == -1 ) {
176        /*
177        ** No slash in the path, so this is a pattern and we have
178        ** to opendir .
179        */
180        if ( (curdir = opendir(".")) == NULL ) {
181            savederrno = errno ;
182            sprintf(logmessage,"opendir . failed : %s ",strerror(errno)) ;
183            if ( savederrno == EACCES ) {
184                FREE(dirpath) ;
185                return -1 ;
186            } else {
187                FREE(dirpath) ;
188                return 1 ;
189            }
190        }
191        strcpy(dirpath,"./") ;
192    } else if ( lastslash == 0 ) {
193        /*
194        ** A slash in first position so we are going to open the
195        ** / directory
196        */
197        if ( (curdir = opendir("/")) == NULL ) {
198            savederrno = errno ;
199            sprintf(logmessage,"opendir / failed : %s ",strerror(errno)) ;
200            if ( savederrno == EACCES ) {
201                FREE(dirpath) ;
202                return -1 ;
203            } else {
204                FREE(dirpath) ;
205                return 1 ;
206            }
207        }
208        strcpy(dirpath,"/") ;
209        pointer++ ;
210    } else if ( lastslash == strlen(pointer) - 1 ) {
211        /*
212        ** The filename end with a slash ..... error
213        */
214        sprintf(logmessage,"Pattern %s ends with a /",pattern) ;
215        FREE(dirpath) ;
216        return -1 ;
217    } else {
218        pointer[lastslash] = '\0';
219        /*
220        ** Srip unnecessary / at the end of dirpath and reset
221        ** only one
222        */
223        strcpy(dirpath,pointer) ;
224        strip_trailing_slashes(dirpath) ;
225        dirpath[strlen(dirpath)+1] = '\0';
226        dirpath[strlen(dirpath)] = '/';
227        if ( (curdir = opendir(dirpath)) == NULL ) {
228            savederrno = errno ;
229            sprintf(logmessage,"opendir %s failed : %s ",dirpath,strerror(errno)) ;
230            if ( savederrno == EACCES ) {
231                FREE(dirpath) ;
232                return -1 ;
233            } else {
234                FREE(dirpath) ;
235                return 1 ;
236            }
237        }
238        for ( i = 0 ; i <= lastslash ; i++ ) pointer++ ;
239    }
240    /*
241    ** At this stage pointer point to the pattern and curdir
242    ** is the opened directory and dirpath contain the
243    ** directory name
244    */
245    /*
246    ** As we are using the fnmatch routine we are obliged to
247    ** first count the number of bytes we are sending.
248    */
249    lengthtosend = 0 ;
250    numberoffile = 0 ;
251    errno = 0 ;
252    first_item = NULL ;
253#ifdef STANDART_FILE_CALL
254    while ( (dp = readdir(curdir) ) != NULL) {
255#else
256#ifdef STANDART_READDIR_CALL
257    while ( (dp = readdir(curdir) ) != NULL) {
258#else
259    while ( (dp = readdir64(curdir) ) != NULL) {
260#endif
261#endif
262        if ( fnmatch(pointer, dp->d_name,0) == 0) {
263            numberoffile++ ;
264            lengthtosend = lengthtosend +  strlen(dirpath) + strlen(dp->d_name) + 1 + 3 ;
265            if ( ( current_item = (struct keepfile *) malloc( sizeof(struct keepfile)) ) == NULL ) {
266                sprintf(logmessage,"Error getting memory for structure : %s",strerror(errno)) ;
267                current_item = first_item ;
268                while ( current_item != NULL ) {
269                    free(current_item->filename) ;
270                    used_item = current_item->next ;
271                    free(current_item) ;
272                    current_item = used_item ;
273                }
274                closedir(curdir) ;
275                FREE(dirpath) ;
276                return 1 ;
277            }
278            if ( ( current_item->filename = (char *) malloc( strlen(dirpath) + strlen(dp->d_name) + 1) ) == NULL ) {
279                sprintf(logmessage,"Error getting memory for filename : %s",strerror(errno)) ;
280                /*
281                ** Clean memory
282                */
283                FREE(current_item) ;
284                current_item = first_item ;
285                while ( current_item != NULL ) {
286                    free(current_item->filename) ;
287                    used_item = current_item->next ;
288                    free(current_item) ;
289                    current_item = used_item ;
290                }
291                closedir(curdir) ;
292                FREE(dirpath) ;
293                return 1 ;
294            }
295            current_item->next = NULL ;
296            if ( first_item == NULL ) {
297                first_item = current_item ;
298                used_item = first_item ;
299            } else {
300                used_item = first_item ;
301                while ( used_item->next != NULL ) used_item = used_item->next ;
302                used_item->next = current_item ;
303            }
304            sprintf(current_item->filename,"%s%s",dirpath,dp->d_name) ;
305#ifdef STANDART_FILE_CALL
306            if ( lstat(current_item->filename,&statbuf) < 0 ) {
307#else
308            if ( lstat64(current_item->filename,&statbuf) < 0 ) {
309#endif
310                sprintf(logmessage,"Error lstating file %s",current_item->filename) ;
311                current_item = first_item ;
312                while ( current_item != NULL ) {
313                    free(current_item->filename) ;
314                    used_item = current_item->next ;
315                    free(current_item) ;
316                    current_item = used_item ;
317                }
318                closedir(curdir) ;
319                FREE(dirpath) ;
320                return 1 ;
321             }
322             if ( (statbuf.st_mode & S_IFLNK) == S_IFLNK) {
323                current_item->filechar[0] = 'l' ;
324#ifdef STANDART_FILE_CALL
325                if ( stat(current_item->filename,&statbuf) < 0 ) {
326#else
327                if ( stat64(current_item->filename,&statbuf) < 0 ) {
328#endif
329                    /*
330                    ** That means that the link refer to an unexisting file
331                    */
332                    current_item->filechar[1] = 'u' ;
333                } else {
334                    if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
335                        current_item->filechar[1] = 'd' ;
336                    } else {
337                        current_item->filechar[1] = 'f' ;
338                    }
339                }
340            } else {
341                current_item->filechar[0] = ' ' ;
342                if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
343                    current_item->filechar[1] = 'd' ;
344                } else {
345                    current_item->filechar[1] = 'f' ;
346                }
347            }
348            current_item->filechar[2] = '\0' ;
349        }
350        errno = 0 ;
351    }
352    /*
353    ** Check errno in case of error during readdir
354    ** for the following readir we are not going to check
355    ** so that may be a cause of problem
356    */
357    if ( errno != 0 ) {
358        sprintf(logmessage,"Error on readdir %s (%s) ",dirpath,strerror(errno)) ;
359        current_item = first_item ;
360        while ( current_item != NULL ) {
361            free(current_item->filename) ;
362            used_item = current_item->next ;
363            free(current_item) ;
364            current_item = used_item ;
365        }
366        closedir(curdir) ;
367        FREE(dirpath) ;
368        return 1 ;
369    }
370    /*
371    ** Check if numberoffile is zero and reply now in this
372    ** case
373    */
374    if ( numberoffile == 0 ) {
375        *filelistlen = 0 ;
376        closedir(curdir) ;
377        current_item = first_item ;
378        while ( current_item != NULL ) {
379            free(current_item->filename) ;
380            used_item = current_item->next ;
381            free(current_item) ;
382            current_item = used_item ;
383        }
384        FREE(dirpath) ;
385        return 0 ;
386    }
387    /*
388    ** Now everything is ready so prepare the answer
389    */
390    if ( ( *filelist = (char *) malloc (lengthtosend) ) == NULL ) {
391        sprintf(logmessage,"Error allocating memory for filelist %s",strerror(errno)) ;
392        closedir(curdir) ;
393        current_item = first_item ;
394        while ( current_item != NULL ) {
395            free(current_item->filename) ;
396            used_item = current_item->next ;
397            free(current_item) ;
398            current_item = used_item ;
399        }
400        FREE(dirpath) ;
401        return -1 ;
402    }
403    current_item = first_item ;
404    filepos = *filelist ;
405    while ( current_item != NULL ) {
406        sprintf(filepos,"%s",current_item->filename) ;
407        filepos = filepos + strlen(filepos) + 1 ;
408        sprintf(filepos,"%s",current_item->filechar) ;
409        filepos = filepos + strlen(filepos) + 1 ;
410        current_item = current_item->next ;
411    }
412    *filelistlen = lengthtosend ;
413    closedir(curdir) ;
414    current_item = first_item ;
415    while ( current_item != NULL ) {
416        free(current_item->filename) ;
417        used_item = current_item->next ;
418        free(current_item) ;
419        current_item = used_item ;
420    }
421    FREE(dirpath) ;
422    return 0 ;   
423}
424
425
426
427
428
429/*******************************************************************************
430** bbftpd_retrcheckfile :                                                      *
431**                                                                             *
432**      Routine to check a file and set the global parameters                  *
433**                                                                             *
434**      OUPUT variable :                                                       *
435**          logmessage :  to write the error message in case of error          *
436**                                                                             *
437**      GLOBAL VARIABLE USED :                                                 *                                                                      *
438**          transferoption                      NOT MODIFIED                   *
439**          filemode                            MODIFIED                       *
440**          lastaccess                          MODIFIED                       *
441**          lastmodif                           MODIFIED                       *
442**          filesize                            MODIFIED                       *
443**          requestedstreamnumber               POSSIBLY MODIFIED              *
444**                                                                             *
445**      RETURN:                                                                *
446**          -1  Incorrect check unrecoverable error                            *
447**           0  OK                                                             *
448**          >0  Incorrect check recoverable error                              *
449**                                                                             *
450*******************************************************************************/
451
452int bbftpd_retrcheckfile(char *filename,char *logmessage)
453{
454#ifdef STANDART_FILE_CALL
455    struct stat statbuf;
456#else
457    struct stat64 statbuf ;
458#endif
459    int     tmpnbport ;
460    int     savederrno ;
461    /*
462    ** Check if it is a rfio creation
463    */
464    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
465#if defined(WITH_RFIO) || defined(WITH_RFIO64)
466        return bbftpd_retrcheckfile_rfio(filename,logmessage) ;
467#else
468        sprintf(logmessage,"Fail to retreive : RFIO not supported") ;
469        return -1 ;
470#endif
471    }
472
473#ifdef STANDART_FILE_CALL
474    if ( stat(filename,&statbuf) < 0 ) {
475#else
476    if ( stat64(filename,&statbuf) < 0 ) {
477#endif
478        /*
479        ** It may be normal to get an error if the file
480        ** does not exist but some error code must lead
481        ** to the interruption of the transfer:
482        **        EACCES        : Search permission denied
483        **        ELOOP        : To many symbolic links on path
484        **        ENAMETOOLONG: Path argument too long
485        **        ENOENT        : The file does not exists
486        **        ENOTDIR        : A component in path is not a directory
487        */
488        savederrno = errno ;
489        sprintf(logmessage,"Error stating file %s : %s ",filename,strerror(savederrno)) ;
490        if ( savederrno == EACCES ||
491            savederrno == ELOOP ||
492            savederrno == ENAMETOOLONG ||
493            savederrno == ENOENT ||
494            savederrno == ENOTDIR ) {
495            return -1 ;
496        } else {
497            return 1 ;
498        }
499    } else {
500        /*
501        ** The file exists so check if it is a directory
502        */
503        if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
504            sprintf(logmessage,"File %s is a directory",filename) ;
505            return -1 ;
506        }
507    }
508    sprintf(lastaccess,"%08x",statbuf.st_atime) ;
509    sprintf(lastmodif,"%08x",statbuf.st_mtime) ;
510    lastaccess[8] = '\0' ;
511    lastmodif[8]  = '\0' ;
512    if (S_ISREG(statbuf.st_mode)) {
513        filemode = statbuf.st_mode & ~S_IFREG;
514    } else {
515        filemode = statbuf.st_mode;
516    }
517    filesize = statbuf.st_size ;
518    tmpnbport = filesize/(buffersizeperstream*1024) ;
519    if ( tmpnbport == 0 ) {
520        requestedstreamnumber = 1 ;
521    } else if ( tmpnbport < requestedstreamnumber ) {
522        requestedstreamnumber = tmpnbport ;
523    }
524    if ( requestedstreamnumber > maxstreams ) requestedstreamnumber = maxstreams ;
525    return 0 ;   
526}
527
528/*******************************************************************************
529** bbftpd_retrtransferfile :                                                   *
530**                                                                             *
531**      Routine to transfer a file                                             *
532**                                                                             *
533**      INPUT variable :                                                       *
534**          filename    :  file to send    NOT MODIFIED                        *
535**                                                                             *
536**      OUTPUT variable :                                                      *
537**          logmessage :  to write the error message in case of error          *
538**                                                                             *
539**      GLOBAL VARIABLE USED :                                                 *                                                                      *
540**                                                                             *
541**      RETURN:                                                                *
542**          -1  transfer failed unrecoverable error                            *
543**           0  Keep the connection open (does not mean that the file has been *
544**                successfully transfered)                                     *
545**          >0  Recoverable error but calling has the cleaning to do           *
546**                                                                             *
547*******************************************************************************/
548 
549int bbftpd_retrtransferfile(char *filename,int simulation,char *logmessage) 
550{
551#ifdef STANDART_FILE_CALL
552    off_t         nbperchild ;
553    off_t         nbtosend;
554    off_t         startpoint ;
555    off_t         nbread ;
556    off_t         numberread ;
557    off_t         nbsent ;
558    off_t        realnbtosend ;
559#else
560    off64_t     nbperchild ;
561    off64_t     nbtosend;
562    off64_t        startpoint ;
563    off64_t     nbread ;
564    off64_t     numberread ;
565    off64_t     nbsent ;
566    off64_t        realnbtosend ;
567#endif
568    my64_t    toprint64 ;
569#ifdef WITH_GZIP                       
570    uLong    buflen ;
571    uLong    bufcomplen ;
572#endif
573    int        lentosend ;
574    int     sendsock ;
575    int        retcode ;
576
577    int     *pidfree ;
578    int     *sockfree ; /* for PASV mode only */
579    int     *portnumber ;
580    int     i ;
581    int     nfds ; 
582    fd_set    selectmask ;
583    struct timeval    wait_timer;
584    int     fd ;
585
586    struct mess_compress *msg_compress ;
587    struct message *msg ;
588    int     waitedtime ;
589    /*
590    ** Check if it is a rfio transfer
591    */
592    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
593#if defined(WITH_RFIO) || defined(WITH_RFIO64)
594        return bbftpd_retrtransferfile_rfio(filename,simulation,logmessage) ;
595#else
596        return 0 ;
597#endif
598    }
599    childendinerror = 0 ; /* No child so no error */
600    if ( protocolversion <= 2 ) { /* Active mode */
601      portnumber = myports ;
602        } else {
603          sockfree = mysockets ;
604        }
605    nbperchild = filesize/requestedstreamnumber ;
606    pidfree = mychildren ;
607    nbpidchild = 0 ;
608    unlinkfile = 3 ;
609
610    /*
611    ** Now start all our children
612    */
613    for (i = 1 ; i <= requestedstreamnumber ; i++) {
614        if ( i == requestedstreamnumber ) {
615            startpoint = (i-1)*nbperchild;
616            nbtosend = filesize-(nbperchild*(requestedstreamnumber-1)) ;
617        } else {
618            startpoint = (i-1)*nbperchild;
619            nbtosend = nbperchild ;
620        }
621        if (protocolversion <= 2) { /* ACTIVE MODE */
622          /*
623          ** Now create the socket to send
624          */
625          sendsock = 0 ;
626          while (sendsock == 0 ) {
627            sendsock = bbftpd_createreceivesocket(*portnumber,logmessage) ;
628          }
629          if ( sendsock < 0 ) {
630            /*
631            ** We set childendinerror to 1 in order to prevent the father
632            ** to send a BAD message which can desynchronize the client and the
633            ** server (We need only one error message)
634            ** Bug discovered by amlutz on 2000/03/11
635            */
636            if ( childendinerror == 0 ) {
637                childendinerror = 1 ;
638                reply(MSG_BAD,logmessage) ;
639            }
640            clean_child() ;
641            return 1 ;
642          }
643          portnumber++ ;
644        } else { /* PASSIVE MODE */
645          sendsock = *sockfree ;
646          sockfree++ ;
647        }
648        /*
649        ** Set flagsighup to zero in order to be able in child
650        ** not to wait STARTCHILDTO if signal was sent before
651        ** entering select. (Seen on Linux with one child)
652        */
653        flagsighup = 0 ;
654        /*
655        ** At this stage we are ready to receive packets
656        ** So we are going to fork
657        */
658        if ( (retcode = fork()) == 0 ) {
659                    int     ns ;
660            /*
661            ** We are in child
662            */
663            /*
664            ** Pause until father send a SIGHUP in order to prevent
665            ** child to die before father has started all children
666            */
667            waitedtime = 0 ;
668            while (flagsighup == 0 && waitedtime < STARTCHILDTO) {
669                int nfds2 ;
670                                wait_timer.tv_sec  = 1 ;
671                wait_timer.tv_usec = 0 ;
672                nfds2 = sysconf(_SC_OPEN_MAX) ;
673                select(nfds2,0,0,0,&wait_timer) ;
674                waitedtime = waitedtime + 1 ;
675            }
676            syslog(BBFTPD_DEBUG,"Child %d starting",getpid()) ;
677            /*
678            ** Close all unnecessary stuff
679            */
680            close(incontrolsock) ;
681            close(outcontrolsock) ; 
682            /*
683            ** And open the file
684            */
685#ifdef STANDART_FILE_CALL
686            if ( (fd = open(filename,O_RDONLY)) < 0 ) {
687#else
688            if ( (fd = open64(filename,O_RDONLY)) < 0 ) {
689#endif
690                /*
691                ** An error on openning the local file is considered
692                ** as fatal. Maybe this need to be improved depending
693                ** on errno
694                */
695                i = errno ;
696                syslog(BBFTPD_ERR,"Error opening local file %s : %s",filename,strerror(errno)) ;
697                close(sendsock) ;
698                exit(i) ;
699            }
700#ifdef STANDART_FILE_CALL
701            if ( lseek(fd,startpoint,SEEK_SET) < 0 ) {
702#else
703            if ( lseek64(fd,startpoint,SEEK_SET) < 0 ) {
704#endif
705                i = errno ;
706                close(fd) ;
707                syslog(BBFTPD_ERR,"Error seeking file : %s",strerror(errno)) ;
708                close(sendsock) ;
709                exit(i)  ;
710            }
711            /*
712                        ** PASSIVE MODE: accept connection
713                        */
714            if ( protocolversion >= 3 ) {
715              if ( (ns = accept(sendsock,0,0) ) < 0 ) {
716                i = errno ;
717                close(fd) ;
718                syslog(BBFTPD_ERR,"Error accept socket : %s",strerror(errno)) ;
719                close(sendsock) ;
720                exit(i)  ;
721              }
722                          close(sendsock) ;
723                        } else {
724                          ns = sendsock ;
725                        }
726
727            /*
728            ** Start the sending loop
729            ** Handle the simulation mode
730            */
731            if (!simulation) {
732              nbread = 0 ;
733              while ( nbread < nbtosend ) {
734                if ( (numberread = read ( fd, readbuffer, ( (buffersizeperstream*1024) <= nbtosend - nbread) ?  (buffersizeperstream*1024) : nbtosend-nbread) ) > 0 ) {
735                    nbread = nbread+numberread ;
736                    if ( (transferoption & TROPT_GZIP ) == TROPT_GZIP ) {
737#ifdef WITH_GZIP                       
738                        /*
739                        ** In case of compression we are going to use
740                        ** a temporary buffer
741                        */
742                        bufcomplen = buffersizeperstream*1024 ;
743                        buflen = numberread ;
744                        retcode = compress((Bytef *)compbuffer,&bufcomplen,(Bytef *)readbuffer,buflen) ;
745                        if ( retcode != 0 ) {
746                            msg_compress = ( struct mess_compress *) compbuffer;
747                            /*
748                            ** Compress error, in this cas we are sending the
749                            ** date uncompressed
750                            */
751                            msg_compress->code = DATA_NOCOMPRESS ;
752                            lentosend = numberread ;
753#ifndef WORDS_BIGENDIAN
754                            msg_compress->datalen = ntohl(lentosend) ;
755#else
756                            msg_compress->datalen = lentosend ;
757#endif
758                            realnbtosend = numberread ;
759                        } else {
760                            memcpy(readbuffer,compbuffer,buffersizeperstream*1024) ;
761                            msg_compress = ( struct mess_compress *) compbuffer;
762                            msg_compress->code = DATA_COMPRESS ;
763                            lentosend = bufcomplen ;
764#ifndef WORDS_BIGENDIAN
765                            msg_compress->datalen = ntohl(lentosend) ;
766#else
767                            msg_compress->datalen = lentosend ;
768#endif
769                            realnbtosend =  bufcomplen ;
770                        }
771#else
772                        msg_compress = ( struct mess_compress *) compbuffer;
773                        /*
774                        ** Compress unavailable, in this cas we are sending the
775                        ** date uncompressed
776                        */
777                        msg_compress->code = DATA_NOCOMPRESS ;
778                        lentosend = numberread ;
779#ifndef WORDS_BIGENDIAN
780                        msg_compress->datalen = ntohl(lentosend) ;
781#else
782                        msg_compress->datalen = lentosend ;
783#endif
784                        realnbtosend = numberread ;
785#endif                       
786                        /*
787                        ** Send the header
788                        */
789                        if ( writemessage(ns,compbuffer,COMPMESSLEN,datato) < 0 ) {
790                            i = ETIMEDOUT ;
791                            syslog(BBFTPD_ERR,"Error sending header data") ;
792                            close(ns) ;
793                            exit(i) ;
794                        }
795                    } else {
796                        realnbtosend = numberread ;
797                    }
798                    /*
799                    ** Send the data
800                    */
801                    nbsent = 0 ;
802                    while ( nbsent < realnbtosend ) {
803                        lentosend = realnbtosend-nbsent ;
804                        nfds = sysconf(_SC_OPEN_MAX) ;
805                        FD_ZERO(&selectmask) ;
806                        FD_SET(ns,&selectmask) ;
807                        wait_timer.tv_sec  = datato  ;
808                        wait_timer.tv_usec = 0 ;
809                        if ( (retcode = select(nfds,0,&selectmask,0,&wait_timer) ) == -1 ) {
810                            /*
811                            ** Select error
812                            */
813                            i = errno ;
814                            syslog(BBFTPD_ERR,"Error select while sending : %s",strerror(errno)) ;
815                            close(fd) ;
816                            close(ns) ;
817                            exit(i) ;
818                        } else if ( retcode == 0 ) {
819                            syslog(BBFTPD_ERR,"Time out while selecting") ;
820                            close(fd) ;
821                            i=ETIMEDOUT ;
822                            close(ns) ;
823                            exit(i) ;
824                        } else {
825                            retcode = send(ns,&readbuffer[nbsent],lentosend,0) ;
826                            if ( retcode < 0 ) {
827                                i = errno ;
828                                syslog(BBFTPD_ERR,"Error while sending %s",strerror(i)) ;
829                                close(ns) ;
830                                exit(i) ;
831                            } else if ( retcode == 0 ) {
832                                i = ECONNRESET ;
833                                syslog(BBFTPD_ERR,"Connexion breaks") ;
834                                close(fd) ;
835                                close(ns) ;
836                                exit(i) ;
837                            } else {
838                                nbsent = nbsent+retcode ;
839                            }
840                        }
841                    }
842                } else {
843                    i = errno ;
844                    syslog(BBFTPD_ERR,"Child Error reading : %s",strerror(errno)) ;
845                    close(ns) ;
846                    close(fd) ;
847                    exit(i) ;
848                }
849              }
850              /*
851              ** All data has been sent so wait for the acknoledge
852              */
853              if ( readmessage(ns,readbuffer,MINMESSLEN,ackto) < 0 ) {
854                syslog(BBFTPD_ERR,"Error waiting ACK") ;
855                close(ns) ;
856                exit(ETIMEDOUT) ;
857              }
858              msg = (struct message *) readbuffer ;
859              if ( msg->code != MSG_ACK) {
860                syslog(BBFTPD_ERR,"Error unknown messge while waiting ACK %d",msg->code) ;
861                close(ns) ;
862                exit(1) ;
863              }
864              toprint64 = nbtosend ;
865              syslog(BBFTPD_DEBUG,"Child send %" LONG_LONG_FORMAT " bytes ; end correct ",toprint64) ;
866            }
867            close(fd) ;
868            close(ns) ;
869            exit(0) ;
870        } else {
871            /*
872            ** We are in father
873            */
874            if ( retcode == -1 ) {
875                /*
876                ** Fork failed ...
877                */
878                syslog(BBFTPD_ERR,"fork failed : %s",strerror(errno)) ;
879                sprintf(logmessage,"fork failed : %s ",strerror(errno)) ;
880                if ( childendinerror == 0 ) {
881                    childendinerror = 1 ;
882                    reply(MSG_BAD,logmessage) ;
883                }
884                clean_child() ;
885                return 1 ;
886            } else {
887                nbpidchild++ ;
888                *pidfree++ = retcode ;
889                close (sendsock) ;
890            }
891        }
892    }
893    /*
894    ** Set the state before starting children because if the file was
895    ** small the child has ended before state was setup to correct value
896    */
897    state = S_SENDING ;
898    /*
899    ** Start all children
900    */
901    pidfree = mychildren ;
902    for (i = 0 ; i<nbpidchild ; i++) {
903        if ( *pidfree != 0 ) {
904            kill(*pidfree,SIGHUP) ;
905        }
906       pidfree++ ;
907    }
908    (void) gettimeofday(&tstart, (struct timezone *)0);
909    return 0 ;
910}
Note: See TracBrowser for help on using the repository browser.