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

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

Eliminated all "implicit declaration" warnings from "python setup.py
build"

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