source: TI05-delivery/trunk/src/bbftp-server-3.2.0/bbftpd/storeafile.c @ 1392

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

More missing #includes exposed when compiling on easterly.

Line 
1/*
2 * bbftpd/storeafile.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 RETURN:
26         0  Keep the connection open (does not mean that the file has been
27           successfully transfered)
28        -1 Tell the calling program to close the connection
29
30 Child Exit code:
31         255    MES_BAD_NO_RETRY has to be sent to the client.
32        = 0    Success
33        > 0    MES_BAD has to be sent to the client
34       
35        In fact only the first child ending in error will be taken in account.
36        The absolute value of the exit code will be an errno code and the
37        strerror(errno) will be sent as an explanation message.
38 
39 storeafile.c v 1.6.0  2000/03/25   - Creation of the routine. This part of
40                                      code was contained in readcontrol.c
41              v 1.6.1  2000/03/28   - Portage to OSF1
42                                    - use data socket in non bloking mode
43              v 1.8.0  2000/04/14   - Change location of headers file for zlib
44              v 1.8.3  2000/04/18   - Implement better return code to client
45              v 1.8.7  2000/05/24   - Modify headers
46              v 1.8.8  2000/05/31   - Check if file to store is not already a directory
47                                    - Take care of zero length file
48              v 1.8.10 2000/08/11   - Portage to Linux
49                                    - Better start child (wait only if HUP was
50                                      not sent)
51              v 1.9.0  2000/08/18   - Use configure to help portage
52              v 1.9.4  2000/10/16   - Close correctly data socket in child
53                                      in order not to keep socket in TIME_WAIT
54                                      on the server
55              v 2.0.0  2000/10/18   - Set state before starting children
56              v 2.0.1  2001/04/23   - Correct indentation
57              v 2.0.2  2001/05/04   - Correct return code treatment
58              v 2.1.0  2001/05/30   - Correct bbftpd_log level
59                                     
60 *****************************************************************************/
61
62#include <bbftpd.h>
63
64#if HAVE_STRING_H
65# include <string.h>
66#endif
67#include <stdlib.h>
68
69#include <errno.h>
70#include <fcntl.h>
71#include <limits.h>
72#include <netinet/in.h>
73#include <signal.h>
74#include <stdio.h>
75#include <bbftpd_private_log.h>
76#include <sys/stat.h>
77#include <sys/time.h>
78#include <sys/types.h>
79#include <unistd.h>
80
81#include <bbftpd.h>
82#include <common.h>
83#include <daemon.h>
84#include <status.h>
85#include <structures.h>
86
87#ifdef WITH_GZIP
88#include <zlib.h>
89#endif
90
91extern int flagsighup ;
92extern int msgsock ;
93extern char currentfilename[MAXLENFILE];
94extern int childendinerror ;
95extern int pid_child[MAXPORT] ;
96extern int state ;
97extern int unlinkfile ;
98extern  int     recvcontrolto ;
99extern  int     sendcontrolto ;
100extern  int     datato ;
101
102#ifndef WORDS_BIGENDIAN
103#ifndef HAVE_NTOHLL
104my64_t    ntohll(my64_t v) ;
105#endif
106#endif
107
108int storeafile(int code) {
109
110    int        retcode ;
111    int        i ;
112    char    receive_buffer[MAXMESSLEN] ;
113    struct message *msg ;
114    struct mess_store *msg_store ;
115    struct mess_compress *msg_compress ;
116    int        compressionon ;
117    int        savederrno ;
118
119    char    data_buffer[READBUFLEN] ;
120    char    comp_buffer[READBUFLEN] ;
121   
122    char    logmessage[256] ;
123       
124    int     fd ;
125
126    int    nfds ; /* Max number of file descriptor */
127    fd_set    selectmask ; /* Select mask */
128    struct timeval    wait_timer;
129
130    my64_t    toprint64 ;
131   
132#ifdef STANDART_FILE_CALL
133    off_t         nbperchild ;
134    off_t         nbtoget;
135    off_t         nbget ;
136    off_t         startpoint ;
137    off_t        toseek ;
138    struct stat statbuf ;
139#else
140    off64_t     nbperchild ;
141    off64_t     nbtoget;
142    off64_t     nbget ;
143    off64_t        startpoint ;
144    off64_t        toseek ;
145    struct stat64 statbuf ;
146#endif
147    int lentowrite;
148    int lenwrited;
149    int datatoreceive;
150    int dataonone;
151    int    recsock ;
152
153#ifdef WITH_GZIP   
154    uLong    buflen ;
155    uLong    bufcomplen ;
156#endif
157
158    /*
159    ** Initilize the pid array
160    */
161     for ( i=0 ; i< MAXPORT ; i++) {
162        pid_child[i] = 0 ;
163    }
164    childendinerror = 0 ; /* No child so no error */
165    /*
166    ** Read the characteristics of the file
167    */
168    if ( (retcode = readmessage(msgsock,receive_buffer,STORMESSLEN,recvcontrolto)) < 0 ) {
169        /*
170        ** Error ...
171        */
172        return -1 ;
173    }
174    msg_store = (struct mess_store *)receive_buffer ;
175    strcpy(currentfilename,msg_store->filename) ;
176#ifndef WORDS_BIGENDIAN
177    msg_store->nbport = ntohl(msg_store->nbport) ;
178    for (i = 0 ; i< MAXPORT ; i++ ) {
179        msg_store->port[i] = ntohl(msg_store->port[i]) ;
180    }
181    msg_store->filesize = ntohll(msg_store->filesize) ;
182#endif
183    if ( code == MSG_STORE ) {
184        bbftpd_log(BBFTPD_DEBUG,"Storing file %s of size %" LONG_LONG_FORMAT " with %d children",currentfilename,msg_store->filesize,msg_store->nbport) ;
185    } else {
186        bbftpd_log(BBFTPD_DEBUG,"Storing file %s of size %" LONG_LONG_FORMAT " with %d children in compressed mode",currentfilename,msg_store->filesize,msg_store->nbport) ;
187    }
188    /*
189    ** First stat the file in order to know if it is a directory
190    */
191#ifdef STANDART_FILE_CALL
192    if ( stat(currentfilename,&statbuf) < 0 ) {
193#else
194    if ( stat64(currentfilename,&statbuf) < 0 ) {
195#endif
196        /*
197        ** It may be normal to get an error if the file
198        ** does not exist but some error code must lead
199        ** to the interruption of the transfer:
200        **        EACCES        : Search permission denied
201        **        ELOOP        : To many symbolic links on path
202        **        ENAMETOOLONG: Path argument too long
203        **        ENOTDIR        : A component in path is not a directory
204        */
205        savederrno = errno ;
206        if ( savederrno == EACCES ||
207            savederrno == ELOOP ||
208            savederrno == ENAMETOOLONG ||
209            savederrno == ENOTDIR ) {
210            sprintf(logmessage,"Error stating file %s : %s ",currentfilename,strerror(savederrno)) ;
211            bbftpd_log(BBFTPD_ERR,"Error stating file %s : %s ",currentfilename,strerror(savederrno)) ;
212            reply(MSG_BAD_NO_RETRY,logmessage) ;
213            return 0 ;
214        } else if (savederrno == ENOENT) {
215            /*
216            ** That is normal the file does not exist
217            */
218        } else {
219            sprintf(logmessage,"Error stating file %s : %s ",currentfilename,strerror(savederrno)) ;
220            bbftpd_log(BBFTPD_ERR,"Error stating file %s : %s ",currentfilename,strerror(savederrno)) ;
221            reply(MSG_BAD,logmessage) ;
222            return 0 ;
223        }
224    } else {
225        /*
226        ** The file exists so check if it is a directory
227        */
228        if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
229            bbftpd_log(BBFTPD_ERR,"file %s is a directory",currentfilename) ;
230            sprintf(logmessage,"File %s is a directory",currentfilename) ;
231            reply(MSG_BAD_NO_RETRY,logmessage) ;
232            return 0 ;
233        }
234    }               
235    /*
236    ** We create the file
237    */
238#ifdef STANDART_FILE_CALL
239    if ((fd = open(currentfilename,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) < 0 ) {
240#else
241    if ((fd = open64(currentfilename,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) < 0 ) {
242#endif
243        /*
244        ** Depending on errno we are going to tell the client to
245        ** retry or not
246        */
247        savederrno = errno ;
248        sprintf(logmessage,"Error creation file %s : %s ",currentfilename,strerror(errno)) ;
249        bbftpd_log(BBFTPD_ERR,"Error creation file %s : %s ",currentfilename,strerror(errno)) ;
250        /*
251        ** We tell the client not to retry in the following case (even in waiting
252        ** WAITRETRYTIME the problem will not be solved) :
253        **        EACCES        : Search permission denied
254        **        EDQUOT        : No more quota
255        **        ENOSPC        : No more space
256        **        ELOOP        : To many symbolic links on path
257        **        ENAMETOOLONG: Path argument too long
258        **        ENOTDIR        : A component in path is not a directory
259        */
260        if ( savederrno == EACCES ||
261                savederrno == EDQUOT ||
262                savederrno == ENOSPC ||
263                savederrno == ELOOP ||
264                savederrno == ENAMETOOLONG ||
265                savederrno == ENOTDIR ) {
266            reply(MSG_BAD_NO_RETRY,logmessage) ;
267        } else {
268            reply(MSG_BAD,logmessage) ;
269        }
270        return 0 ;
271    }
272    /*
273    ** If it is a zero length file close it and reply OK
274    */
275    if ( msg_store->filesize == 0 ) {
276        close(fd) ;
277        reply(MSG_OK,"OK") ;
278        return 0 ;
279    }
280    unlinkfile = 1 ;
281    /*
282    ** Lseek to set it to the correct size
283    */
284    toseek = msg_store->filesize-1 ;
285#ifdef STANDART_FILE_CALL
286    if ( lseek(fd,toseek,SEEK_SET) < 0 ) {
287#else
288    if ( lseek64(fd,toseek,SEEK_SET) < 0 ) {
289#endif
290        sprintf(logmessage,"Error seeking file %s : %s ",currentfilename,strerror(errno)) ;
291        close(fd) ;
292        unlink(currentfilename) ;
293        bbftpd_log(BBFTPD_ERR,"Error seeking file %s : %s ",currentfilename,strerror(errno)) ;
294        reply(MSG_BAD,logmessage) ;
295        return 0 ;
296    }
297    /*
298    ** Write one byte
299    */
300    if ( write(fd,"\0",1) != 1) {
301        savederrno = errno ;
302        sprintf(logmessage,"Error writing file %s : %s ",currentfilename,strerror(errno)) ;
303        close(fd) ;
304        unlink(currentfilename) ;
305        bbftpd_log(BBFTPD_ERR,"Error writing file %s : %s ",currentfilename,strerror(errno)) ;
306        /*
307        ** We tell the client not to retry in the following case (even in waiting
308        ** WAITRETRYTIME the problem will not be solved) :
309        **        EDQUOT        : No more quota
310        **        ENOSPC        : No space on device
311        */
312        if ( savederrno == EDQUOT ||
313                savederrno == ENOSPC ) {
314            reply(MSG_BAD_NO_RETRY,logmessage) ;
315        } else {
316            reply(MSG_BAD,logmessage) ;
317        }
318        return 0 ;
319    }
320    /*
321    ** And close the file
322    */
323    if ( close(fd) < 0 ) {
324        savederrno = errno ;
325        unlink(currentfilename) ;
326        bbftpd_log(BBFTPD_ERR,"Error closing file %s : %s ",currentfilename,strerror(savederrno)) ;
327        sprintf(logmessage,"Error closing file %s : %s ",currentfilename,strerror(savederrno)) ;
328        if ( savederrno == ENOSPC ) {
329            reply(MSG_BAD_NO_RETRY,logmessage) ;
330        } else {
331            reply(MSG_BAD,logmessage) ;
332        }
333        return 0 ;
334    }
335    /*
336    ** We calculate the starting point for each child
337    */
338    nbperchild = msg_store->filesize/msg_store->nbport ;
339    for (i = 1 ; i <= msg_store->nbport ; i++) {
340        if ( i == msg_store->nbport) {
341            startpoint = (i-1)*nbperchild;
342            nbtoget = msg_store->filesize-(nbperchild*(msg_store->nbport-1)) ;
343        } else {
344            startpoint = (i-1)*nbperchild;
345            nbtoget = nbperchild ;
346        }
347               
348        /*
349        ** Now create the socket to receive
350        */
351        recsock = 0 ;
352        while (recsock == 0 ) {
353            recsock = createreceivesock(msg_store->port[i-1],i,logmessage) ;
354        }
355        if ( recsock < 0 ) {
356            unlink(currentfilename) ;
357            /*
358            ** We set childendinerror to 1 in order to prevent the father
359            ** to send a BAD message which can desynchronize the client and the
360            ** server (We need only one error message)
361            ** Bug discovered by amlutz on 2000/03/11
362            */
363            if ( childendinerror == 0 ) {
364                childendinerror = 1 ;
365                reply(MSG_BAD,logmessage) ;
366            }
367            clean_child() ;
368            return 0 ;
369        }
370        /*
371        ** Set flagsighup to zero in order to be able in child
372        ** not to wait STARTCHILDTO if signal was sent before
373        ** entering select. (Seen on Linux with one child)
374        */
375        flagsighup = 0 ;
376        /*
377        ** At this stage we are ready to receive packets
378        ** So we are going to fork
379        */
380        if ( (retcode = fork()) == 0 ) {
381            /*
382            ** We are in child
383            */
384            /*
385            ** Pause until father send a SIGHUP in order to prevent
386            ** child to die before father has started all children
387            */
388            if ( flagsighup == 0) {
389                wait_timer.tv_sec  = STARTCHILDTO ;
390                wait_timer.tv_usec = 0 ;
391                nfds = sysconf(_SC_OPEN_MAX) ;
392                select(nfds,0,0,0,&wait_timer) ;
393            }
394            bbftpd_log(BBFTPD_DEBUG,"Child Starting") ;
395            /*
396            ** Close all unnecessary stuff
397            */
398            close(msgsock) ;
399            /*
400            ** Check if file exist
401            */
402#ifdef STANDART_FILE_CALL
403            if ( stat(currentfilename,&statbuf) < 0 ) {
404#else
405            if ( stat64(currentfilename,&statbuf) < 0 ) {
406#endif
407                /*
408                ** If the file does not exist that means that another
409                ** child has detroyed it
410                */ 
411                i = errno ;
412                bbftpd_log(BBFTPD_ERR,"Error stating file %s : %s ",currentfilename,strerror(errno)) ;
413                close(recsock) ;
414                exit(i) ;
415            }
416            /*
417            ** Open and seek to position
418            */
419#ifdef STANDART_FILE_CALL
420            if ((fd = open(currentfilename,O_RDWR,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) < 0 ) {
421#else
422            if ((fd = open64(currentfilename,O_RDWR,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) < 0 ) {
423#endif
424                i = errno ;
425                unlink(currentfilename) ;
426                bbftpd_log(BBFTPD_ERR,"Error opening file %s : %s ",currentfilename,strerror(errno)) ;
427                /*
428                ** At this point a non recoverable error is
429                **        EDQUOT        : No more quota
430                **        ENOSPC        : No more space
431                */
432                if ( i == EDQUOT ||
433                        i == ENOSPC ) {
434                    close(recsock) ;
435                    exit(255) ;
436                } else {
437                    close(recsock) ;
438                    exit(i) ;
439                }
440            }
441#ifdef STANDART_FILE_CALL
442            if ( lseek(fd,startpoint,SEEK_SET) < 0 ) {
443#else
444            if ( lseek64(fd,startpoint,SEEK_SET) < 0 ) {
445#endif
446                i = errno ;
447                close(fd) ;
448                unlink(currentfilename) ;
449                bbftpd_log(BBFTPD_ERR,"error seeking file : %s",strerror(errno)) ;
450                close(recsock) ;
451                exit(i)  ;
452            }
453            /*
454            ** start the reading loop
455            */
456            nbget = 0 ;
457            while ( nbget < nbtoget) {
458#ifdef WITH_GZIP
459                if ( code == MSG_STORE_C ) {
460                    /*
461                    ** Receive the header first
462                    */
463                    if (readmessage(recsock,receive_buffer,COMPMESSLEN,datato) < 0 ) {
464                        bbftpd_log(BBFTPD_ERR,"Error reading compression header") ;
465                        close(fd) ;
466                        unlink(currentfilename) ;
467                        i = ETIMEDOUT ;
468                        exit(i) ;
469                    }
470                    msg_compress = ( struct mess_compress *) receive_buffer ;
471#ifndef WORDS_BIGENDIAN
472                    msg_compress->datalen = ntohl(msg_compress->datalen) ;
473#endif
474                    if ( msg_compress->code == DATA_COMPRESS) {
475                        compressionon = 1 ;
476                    } else {
477                        compressionon = 0 ;
478                    }
479                    datatoreceive = msg_compress->datalen ;
480                } else {
481                    /*
482                    ** No compression just adjust the length to receive
483                    */
484                    if ( READBUFLEN <= nbtoget-nbget ) {
485                        datatoreceive = READBUFLEN  ;
486                    } else {
487                        datatoreceive = nbtoget-nbget ;
488                    }
489                }
490#else
491                if ( READBUFLEN <= nbtoget-nbget ) {
492                    datatoreceive = READBUFLEN  ;
493                } else {
494                    datatoreceive = nbtoget-nbget ;
495                }
496#endif
497                /*
498                ** Start the data collection
499                */
500                dataonone = 0 ;
501                while ( dataonone < datatoreceive ) {
502                    nfds = sysconf(_SC_OPEN_MAX) ;
503                    FD_ZERO(&selectmask) ;
504                    FD_SET(recsock,&selectmask) ;
505                    wait_timer.tv_sec  = datato ;
506                    wait_timer.tv_usec = 0 ;
507                    if ( (retcode = select(nfds,&selectmask,0,0,&wait_timer) ) == -1 ) {
508                        /*
509                        ** Select error
510                        */
511                        i = errno ;
512                        bbftpd_log(BBFTPD_ERR,"Error select while receiving : %s",strerror(errno)) ;
513                        close(fd) ;
514                        unlink(currentfilename) ;
515                        close(recsock) ;
516                        exit(i) ;
517                    } else if ( retcode == 0 ) {
518                        bbftpd_log(BBFTPD_ERR,"Time out while receiving") ;
519                        close(fd) ;
520                        unlink(currentfilename) ;
521                        i=ETIMEDOUT ;
522                        close(recsock) ;
523                        exit(i) ;
524                    } else {
525                        retcode = recv(recsock,&data_buffer[dataonone],datatoreceive-dataonone,0) ;
526                        if ( retcode < 0 ) {
527                            i = errno ;
528                            bbftpd_log(BBFTPD_ERR,"Error while receiving : %s",strerror(errno)) ;
529                            close(fd) ;
530                            unlink(currentfilename) ;
531                            close(recsock) ;
532                            exit(i) ;
533                        } else if ( retcode == 0 ) {
534                            i = ECONNRESET ;
535                            bbftpd_log(BBFTPD_ERR,"Connexion breaks") ;
536                            close(fd) ;
537                            unlink(currentfilename) ;
538                            close(recsock) ;
539                            exit(i) ;
540                        } else {
541                            dataonone = dataonone + retcode ;
542                        }
543                    }
544                }
545                /*
546                ** We have received all data needed
547                */
548#ifdef WITH_GZIP
549                if ( code == MSG_STORE_C ) {
550                    if ( compressionon == 1 ) {
551                        bufcomplen = READBUFLEN ;
552                        buflen = dataonone ;
553                        retcode = uncompress((Bytef *) comp_buffer, &bufcomplen, (Bytef *) data_buffer, buflen) ;
554                        if ( retcode != 0 ) {
555                            i = EILSEQ ;
556                            bbftpd_log(BBFTPD_ERR,"Error while decompressing %d ",retcode) ;
557                            close(fd) ;
558                            unlink(currentfilename) ;
559                            close(recsock) ;
560                            exit(i) ;
561                        }
562                        memcpy(data_buffer,comp_buffer,READBUFLEN) ;
563                        lentowrite = bufcomplen ;
564                    } else {
565                        lentowrite = dataonone ;
566                    }
567                } else {
568                    lentowrite = dataonone ;
569                }
570#else
571                lentowrite = dataonone ;
572#endif
573                /*
574                ** Write it to the file
575                */
576                lenwrited = 0 ;
577                while ( lenwrited < lentowrite ) {
578                    if ( (retcode = write(fd,&data_buffer[lenwrited],lentowrite-lenwrited)) < 0 ) {
579                        i = errno ;
580                        bbftpd_log(BBFTPD_ERR,"error writing file : %s",strerror(errno)) ;
581                        close(fd) ;
582                        unlink(currentfilename) ;
583                        if ( i == EDQUOT ||
584                                i == ENOSPC ) {
585                            close(recsock) ;
586                            exit(255) ;
587                        } else {
588                            close(recsock) ;
589                            exit(i) ;
590                        }
591                    } 
592                    lenwrited = lenwrited + retcode ;
593                }
594                nbget = nbget+lenwrited ;
595            }
596            /*
597            ** All data have been received so send the ACK message
598            */
599            msg = (struct message *) data_buffer ;
600            msg->code = MSG_ACK ;
601            msg->msglen = 0 ;
602            if ( writemessage(recsock,data_buffer,MINMESSLEN,sendcontrolto) < 0 ) {
603                close(fd) ;
604                unlink(currentfilename) ;
605                bbftpd_log(BBFTPD_ERR,"Error sending ACK ") ;
606                close(recsock) ;
607                exit(ETIMEDOUT) ;
608            }
609            toprint64 = nbget ;
610            bbftpd_log(BBFTPD_DEBUG,"Child received %" LONG_LONG_FORMAT " bytes ; end correct ",toprint64) ;
611            close(recsock) ;
612            exit(0) ;
613        } else {
614            /*
615            ** We are in father
616            */
617            if ( retcode == -1 ) {
618                /*
619                ** Fork failed ...
620                */
621                bbftpd_log(BBFTPD_ERR,"fork failed : %s",strerror(errno)) ;
622                unlink(currentfilename) ;
623                sprintf(logmessage,"fork failed : %s ",strerror(errno)) ;
624                if ( childendinerror == 0 ) {
625                    childendinerror = 1 ;
626                    reply(MSG_BAD,logmessage) ;
627                }
628                clean_child() ;
629                return 0 ;
630            } else {
631                /*
632                ** Set the parameter telling the sig child routine to unlink
633                ** in case of error
634                */
635                bbftpd_log(BBFTPD_DEBUG,"Started child pid %d",retcode) ;
636                pid_child[i-1] = retcode ;
637                close(recsock) ;
638            }
639        }
640    }
641    /*
642    ** Set the state before starting children because if the file was
643    ** small the child has ended before state was setup to correct value
644    */
645    state = S_RECEIVING ;
646    /*
647    ** Start all children
648    */
649    for (i = 0 ; i<MAXPORT ; i++) {
650        if (pid_child[i] != 0) {
651            kill(pid_child[i],SIGHUP) ;
652        }
653    }
654    return 0 ;
655}
Note: See TracBrowser for help on using the repository browser.