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

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

Initial import of bbftp source

Line 
1/*
2 * bbftpd/bbftpd_store.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
26 bbftpd_store.c v 2.0.0 2000/12/19  - Routines creation
27                v 2.0.1 2001/04/17  - Realy wait STARTCHILDTO
28                                    - Correct indentation
29                                    - Port to IRIX
30                v 2.0.2 2001/05/09  - Add storeclosecastfile function
31                v 2.1.0 2001/05/30  - Correct syslog level
32                                    - Reorganise routines as in bbftp_
33
34*****************************************************************************/
35#include <bbftpd.h>
36
37#include <errno.h>
38#include <fcntl.h>
39#include <netinet/in.h>
40#include <signal.h>
41#include <syslog.h>
42#include <sys/stat.h>
43#if TIME_WITH_SYS_TIME
44# include <sys/time.h>
45# include <time.h>
46#else
47# if HAVE_SYS_TIME_H
48#  include <sys/time.h>
49# else
50#  include <time.h>
51# endif
52#endif
53#if HAVE_SYS_TYPES_H
54# include <sys/types.h>
55#endif
56#if HAVE_SYS_SOCKET_H
57# include <sys/socket.h>
58#endif
59#include <unistd.h>
60#include <utime.h>
61#if HAVE_STRING_H
62# include <string.h>
63#endif
64
65#include <common.h>
66#include <daemon.h>
67#include <daemon_proto.h>
68#include <status.h>
69#include <structures.h>
70
71#ifdef WITH_GZIP
72#include <zlib.h>
73#endif
74
75extern int  transferoption ;
76extern my64_t  filesize ;
77extern int  requestedstreamnumber ;
78extern int  buffersizeperstream ;
79extern int  maxstreams ;
80extern int  *myports ;
81extern int  *mysockets ;
82extern char *readbuffer ;
83extern char *compbuffer ;
84extern int  *mychildren ;
85extern int  nbpidchild ;
86extern int  unlinkfile ;
87extern int  incontrolsock ;
88extern int  outcontrolsock ;
89extern  int     datato ;
90extern  int     sendcontrolto ;
91extern int  state ;
92extern int  childendinerror ;
93extern int  flagsighup ;
94extern struct  timeval  tstart ;
95extern int  protocolversion ;
96extern  char            currentusername[MAXLEN] ;
97
98/*******************************************************************************
99** bbftpdstoreclosecastfile :                                                  *
100**                                                                             *
101**      Close CASTOR file                                                      *
102**                                                                             *
103**      OUPUT variable :                                                       *
104**          logmessage :  to write the error message in case of error          *
105**                                                                             *
106**      GLOBAL VARIABLE USED :                                                 *                                                                      *
107**          castfd                  MODIFIED                                   *
108**                                                                             *
109**      RETURN:                                                                *
110**          -1  Failed                                                         *
111**           0  OK                                                             *
112**                                                                             *
113*******************************************************************************/
114
115int bbftpd_storeclosecastfile(char *filename,char *logmessage)
116{
117   
118    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
119#if defined(WITH_RFIO) || defined(WITH_RFIO64)
120        return bbftpd_storeclosecastfile_rfio(filename,logmessage) ;
121#else
122        return 0 ;
123#endif
124    }
125    return 0 ;
126}
127
128/*******************************************************************************
129** bbftpd_storeutime :                                                         *
130**                                                                             *
131**      Routine to chage access time a file                                    *
132**                                                                             *
133**      OUPUT variable :                                                       *
134**          logmessage :  to write the error message in case of error          *
135**                                                                             *
136**      GLOBAL VARIABLE USED :                                                 *                                                                      *
137**          transferoption                   NOT MODIFIED                      *
138**                                                                             *
139**      RETURN:                                                                *
140**          -1  Failed                                                         *
141**           0  OK                                                             *
142**                                                                             *
143*******************************************************************************/
144
145int bbftpd_storeutime(char *filename,struct utimbuf *ftime,char *logmessage)
146{
147    int     retcode ;
148   
149    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
150        return 0 ;
151    }
152    retcode = utime(filename,ftime) ;
153    if ( retcode < 0 ) {
154        sprintf(logmessage,"Error utime on file %s : %s",filename,strerror(errno)) ;
155        return retcode ;
156    }
157    return 0 ;
158}
159
160/*******************************************************************************
161** bbftpd_storechmod :                                                         *
162**                                                                             *
163**      Routine to chmod a file                                                *
164**                                                                             *
165**      OUPUT variable :                                                       *
166**          logmessage :  to write the error message in case of error          *
167**                                                                             *
168**      GLOBAL VARIABLE USED :                                                 *                                                                      *
169**          transferoption                   NOT MODIFIED                      *
170**                                                                             *
171**      RETURN:                                                                *
172**          -1  Failed                                                         *
173**           0  OK                                                             *
174**                                                                             *
175*******************************************************************************/
176
177int bbftpd_storechmod(char *filename,int mode,char *logmessage)
178{
179    int     retcode ;
180   
181    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
182#if defined(WITH_RFIO) || defined(WITH_RFIO64)
183        return bbftpd_storechmod_rfio(filename,mode,logmessage) ;
184#else
185        return 0 ;
186#endif
187    }
188    retcode = chmod(filename,mode) ;
189    if ( retcode < 0 ) {
190        sprintf(logmessage,"Error chmod on file %s : %s",filename,strerror(errno)) ;
191        return retcode ;
192    }
193    return 0 ;
194}
195
196/*******************************************************************************
197** bbftpd_storerename :                                                        *
198**                                                                             *
199**      Routine to unlink a file                                               *
200**                                                                             *
201**      OUPUT variable :                                                       *
202**          logmessage :  to write the error message in case of error          *
203**                                                                             *
204**      GLOBAL VARIABLE USED :                                                 *                                                                      *
205**          transferoption                   NOT MODIFIED                      *
206**                                                                             *
207**      RETURN:                                                                *
208**          -1  Failed                                                         *
209**           0  OK                                                             *
210**                                                                             *
211*******************************************************************************/
212
213int bbftpd_storerename(char *newfilename,char *oldfilename,char *logmessage)
214{
215    int     retcode ;
216   
217    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
218#if defined(WITH_RFIO) || defined(WITH_RFIO64)
219        return bbftpd_storerename_rfio(newfilename,oldfilename,logmessage) ;
220#else
221        return 0 ;
222#endif
223    }
224    retcode = rename(newfilename,oldfilename) ;
225    if ( retcode < 0 ) {
226        sprintf(logmessage,"Error renaming %s to %s : %s",newfilename,oldfilename,strerror(errno)) ;
227        return retcode ;
228    }
229    return 0 ;
230}
231
232/*******************************************************************************
233** bbftpd_storeunlink :                                                        *
234**                                                                             *
235**      Routine to unlink a file                                               *
236**                                                                             *
237**      OUPUT variable :                                                       *
238**          logmessage :  to write the error message in case of error          *
239**                                                                             *
240**      GLOBAL VARIABLE USED :                                                 *                                                                      *
241**          transferoption                   NOT MODIFIED                      *
242**                                                                             *
243**      RETURN:                                                                *
244**          -1  Failed                                                         *
245**           0  OK                                                             *
246**                                                                             *
247*******************************************************************************/
248
249int bbftpd_storeunlink(char *filename)
250{
251    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
252#if defined(WITH_RFIO) || defined(WITH_RFIO64)
253        return bbftpd_storeunlink_rfio(filename) ;
254#else
255        return 0 ;
256#endif
257    }
258    return unlink(filename) ;
259}
260
261/*******************************************************************************
262** bbftpd_storecheckoptions :                                                  *
263**                                                                             *
264**      Routine to check the options parameters                                *
265**                                                                             *
266**      OUPUT variable :                                                       *
267**          logmessage :  to write the error message in case of error          *
268**                                                                             *
269**      GLOBAL VARIABLE USED :                                                 *                                                                      *
270**          transferoption                   POSSIBLY MODIFIED                 *
271**          requestedstreamnumber            POSSIBLY MODIFIED                 *
272**                                                                             *
273**      RETURN:                                                                *
274**          -1  Incorrect options                                              *
275**           0  OK                                                             *
276**                                                                             *
277*******************************************************************************/
278
279int bbftpd_storecheckoptions(char *logmessage)
280{
281    int tmpoptions ;
282#ifndef WITH_GZIP
283    /*
284    ** Check if Compress is available int    case of GZIP option
285    */
286    if ( (transferoption & TROPT_GZIP) == TROPT_GZIP ) {
287        syslog(BBFTPD_WARNING,"Compression is not available for this server: option ignored") ;
288        transferoption = transferoption & ~TROPT_GZIP ;
289    }
290#endif
291    /*
292    ** Check if it is a rfio creation
293    */
294    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
295#if defined(WITH_RFIO) || defined(WITH_RFIO64)
296        return bbftpd_storecheckoptions_rfio(logmessage) ;
297#else
298        sprintf(logmessage,"Fail to store : RFIO not supported") ;
299        return -1 ;
300#endif
301    }
302    /*
303    ** Check all known options
304    */
305    tmpoptions = TROPT_TMP | TROPT_ACC | TROPT_MODE | TROPT_DIR | TROPT_GZIP ;
306    transferoption = transferoption & tmpoptions ;
307    /*
308    ** Check the maxstreams
309    */
310    if ( requestedstreamnumber > maxstreams ) requestedstreamnumber = maxstreams ;
311    return 0 ;
312}
313
314/*******************************************************************************
315** bbftpd_storemkdir :                                                         *
316**                                                                             *
317**      Routine to create a bunch of directory                                 *
318**                                                                             *
319**      INPUT variable :                                                       *
320**          dirname    :  directory to create    NOT MODIFIED                  *
321**          recursif   :  1 recursif             NOT MODIFIED                  *
322**                        0 non recursif                                       *
323**                                                                             *
324**      OUPUT variable :                                                       *
325**          logmessage :  to write the error message in case of error          *
326**                                                                             *
327**      TO FREE before any return : dirpath                                    *
328**                                                                             *
329**      RETURN:                                                                *
330**          -1   Creation failed unrecoverable error                           *
331**           0   OK                                                            *
332**           >0  Creation failed recoverable error                             *
333**                                                                             *
334*******************************************************************************/
335int bbftpd_storemkdir(char *dirname,char *logmessage,int recursif)
336{
337    char    *dirpath;
338    char    *basedir ;
339    char    *slash ;
340    int     savederrno ;
341#ifdef STANDART_FILE_CALL
342    struct stat statbuf;
343#else
344    struct stat64 statbuf ;
345#endif
346
347    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
348#if defined(WITH_RFIO) || defined(WITH_RFIO64)
349        return bbftpd_storemkdir_rfio(dirname,logmessage,recursif) ;
350#else
351        sprintf(logmessage,"Fail to mkdir : RFIO not supported") ;
352        return -1 ;
353#endif
354    }
355    /*
356    ** make a copy of dirname for security
357    */
358    if ( (dirpath = (char *) malloc (strlen(dirname)+1) ) == NULL ) {
359        sprintf(logmessage,"Error allocating memory for dirpath : %s",strerror(errno)) ;
360        return 1 ;
361    }
362    strcpy (dirpath, dirname);
363    /*
364    ** Strip trailing slash
365    */
366    strip_trailing_slashes(dirpath) ;
367    slash = dirpath ;
368    if ( recursif == 1 ) {
369        /*
370        ** Recursif, we are going to create all directory
371        */
372        /*
373        ** If this is an absolute path strip the leading slash
374        */
375        if ( *dirpath == '/' ) {
376            while (*slash == '/') slash++;
377        }
378        while (1) {
379            slash = (char *) strchr (slash, '/');
380            if ( slash == NULL ) break ;
381            basedir = dirpath ;
382            /*
383            ** The mkdir and stat calls below appear to be reversed.
384            ** They are not.  It is important to call mkdir first and then to
385            ** call stat (to distinguish the three cases) only if mkdir fails.
386            ** The alternative to this approach is to `stat' each directory,
387            ** then to call mkdir if it doesn't exist.  But if some other process
388            ** were to create the directory between the stat & mkdir, the mkdir
389            ** would fail with EEXIST.
390            ** We create it with mode = 777 because the umask is set by bbftpd
391            */
392             *slash = '\0';
393            if ( mkdir (basedir, 0777) ) {
394                savederrno = errno ;
395#ifdef STANDART_FILE_CALL
396                if ( stat (basedir,&statbuf ) ) {
397#else
398                if ( stat64 (basedir,&statbuf ) ) {
399#endif
400                    sprintf(logmessage,"Error creation directory %s (%s)",basedir,strerror(savederrno)) ; 
401                    /*
402                    ** We tell the client not to retry in the following case (even in waiting
403                    ** WAITRETRYTIME the problem will not be solved) :
404                    **        EACCES        : Search permission denied
405                    **        EDQUOT        : No more quota
406                    **        ENOSPC        : No more space
407                    **        ELOOP        : To many symbolic links on path
408                    **        ENAMETOOLONG: Path argument too long
409                    **        ENOTDIR        : A component in path is not a directory
410                    **        EROFS        : The path prefix resides on a read-only file system.
411                    **        ENOENT      : A component of the path prefix does not exist or is a null pathname.
412                    **        EEXIST      : The named file already exists.
413                    */
414                     if ( savederrno == EACCES ||
415                            savederrno == EDQUOT ||
416                            savederrno == ENOSPC ||
417                            savederrno == ELOOP ||
418                            savederrno == ENAMETOOLONG ||
419                            savederrno == ENOTDIR ||
420                            savederrno == EROFS ||
421                            savederrno == ENOENT ||
422                            savederrno == EEXIST ) {
423                        FREE(dirpath) ;
424                        return -1 ;
425                    } else {
426                        FREE(dirpath) ;
427                        return 1 ;
428                    }
429                } else if ( (statbuf.st_mode & S_IFDIR) != S_IFDIR) {
430                    sprintf(logmessage,"%s exists but is not a directory",basedir) ; 
431                    FREE(dirpath) ;
432                    return -1 ;
433                } else {
434                     /*
435                    ** dirpath already exists and is a directory.
436                    */
437                }
438            }
439             *slash++ = '/';
440
441            /*
442            ** Avoid unnecessary calls to `stat' when given
443            ** pathnames containing multiple adjacent slashes. 
444            */
445            while (*slash == '/') slash++;
446       }
447    }
448    /*
449    ** We have created all leading directories so let see the last one
450    */
451    basedir = dirpath ;
452    if ( mkdir (basedir, 0777) ) {
453        savederrno = errno ;
454#ifdef STANDART_FILE_CALL
455        if ( stat (basedir,&statbuf ) ) {
456#else
457        if ( stat64 (basedir,&statbuf ) ) {
458#endif
459            sprintf(logmessage,"Error creation directory %s (%s)",basedir,strerror(savederrno)) ; 
460            /*
461            ** We tell the client not to retry in the following case (even in waiting
462            ** WAITRETRYTIME the problem will not be solved) :
463            **        EACCES        : Search permission denied
464            **        EDQUOT        : No more quota
465            **        ENOSPC        : No more space
466            **        ELOOP        : To many symbolic links on path
467            **        ENAMETOOLONG: Path argument too long
468            **        ENOTDIR        : A component in path is not a directory
469            **        EROFS        : The path prefix resides on a read-only file system.
470            **        ENOENT      : A component of the path prefix does not exist or is a null pathname.
471            **        EEXIST      : The named file already exists.
472            */
473             if ( savederrno == EACCES ||
474                    savederrno == EDQUOT ||
475                    savederrno == ENOSPC ||
476                    savederrno == ELOOP ||
477                    savederrno == ENAMETOOLONG ||
478                    savederrno == ENOTDIR ||
479                    savederrno == EROFS ||
480                    savederrno == ENOENT ||
481                    savederrno == EEXIST ) {
482                FREE(dirpath) ;
483                return -1 ;
484            } else {
485                FREE(dirpath) ;
486                return 1 ;
487            }
488        } else if ( (statbuf.st_mode & S_IFDIR) != S_IFDIR) {
489            sprintf(logmessage,"%s exists but is not a directory",basedir) ; 
490            FREE(dirpath) ;
491            return -1 ;
492        } else {
493             /*
494            ** dirpath already exists and is a directory.
495            */
496            FREE(dirpath) ;
497            return 0 ;
498        }
499    }
500    FREE(dirpath) ;
501    return 0 ;
502}
503/*******************************************************************************
504** bbftpd_storecreatefile :                                                    *
505**                                                                             *
506**      Routine to create a file                                               *
507**                                                                             *
508**      OUTPUT variable :                                                      *
509**          logmessage :  to write the error message in case of error          *
510**                                                                             *
511**      GLOBAL VARIABLE USED :                                                 *                                                                      *
512**          transferoption                   NOT MODIFIED                      *
513**          filesize                         NOT MODIFIED                      *
514**                                                                             *
515**      TO FREE before any return : filepath                                   *
516**                                                                             *
517**      RETURN:                                                                *
518**          -1  Transfer failed calling has to close the connection no retry   *
519**           0  OK  (Does not mean the transfer is successfull                 *
520**           1  Transfer failed calling has to close the connection            *
521**                                                                             *
522*******************************************************************************/
523 
524int bbftpd_storecreatefile(char *filename, char *logmessage) 
525{
526    char    *filepath ;
527    int     fd ;
528    int     lastslash ;
529    int     savederrno ;
530    int     retcode ;
531#ifdef STANDART_FILE_CALL
532     off_t        toseek ;
533    struct stat statbuf ;
534#else
535    off64_t        toseek ;
536    struct stat64 statbuf ;
537#endif
538   
539    /*
540    ** Check if it is a rfio creation
541    */
542    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
543#if defined(WITH_RFIO) || defined(WITH_RFIO64)
544        return bbftpd_storecreatefile_rfio(filename,logmessage) ;
545#else
546        sprintf(logmessage,"Fail to create file : RFIO not supported") ;
547        return -1 ;
548#endif
549    }
550    /*
551    ** make a copy of filename for security
552    */
553    if ( (filepath = (char *) malloc (strlen(filename)+1) ) == NULL ) {
554        sprintf(logmessage,"Error allocating memory for filepath : %s",strerror(errno)) ;
555        return 1 ;
556    }
557    strcpy (filepath, filename);
558    /*
559    ** Check if the file exist
560    **      We are going to first see if the directory exist
561    **      and then look at the options
562    **      and then look if the file exist
563    */
564    lastslash = strlen(filepath) - 1 ;
565    while ( lastslash >= 0 && filepath[lastslash] != '/') lastslash-- ;
566    if ( lastslash == -1 ) {
567        /*
568        ** No slash in the path, that means that we have done a chdir
569        ** before so do not care for the directory problem
570        */
571    } else if ( lastslash == 0 ) {
572        /*
573        ** A slash in first position so we suppose the "/" directory
574        ** exist ... nothing to do
575        */
576    } else if ( lastslash == strlen(filepath) - 1 ) {
577        /*
578        ** The filename end with a slash ..... error
579        */
580        sprintf(logmessage,"Filename %s ends with a /",filepath) ;
581        FREE(filepath) ;
582        return -1 ;
583    } else {
584        filepath[lastslash] = '\0';
585        /*
586        ** Check the existence of the directory
587        */
588#ifdef STANDART_FILE_CALL
589        if ( stat(filepath,&statbuf) < 0 ) {
590#else
591        if ( stat64(filepath,&statbuf) < 0 ) {
592#endif
593            /*
594            ** It may be normal to get an error if the directory
595            ** does not exist but some error code must lead
596            ** to the interruption of the transfer:
597            **        EACCES        : Search permission denied
598            **        ELOOP        : To many symbolic links on path
599            **        ENAMETOOLONG: Path argument too long
600            **        ENOTDIR        : A component in path is not a directory
601            */
602             savederrno = errno ;
603            if ( savederrno == EACCES ||
604                savederrno == ELOOP ||
605                savederrno == ENAMETOOLONG ||
606                savederrno == ENOTDIR ) {
607                sprintf(logmessage,"Error stating directory %s : %s ",filepath,strerror(savederrno)) ;
608                FREE(filepath) ;
609                return -1 ;
610            } else if (savederrno == ENOENT) {
611                /*
612                ** The directory does not exist so check for the TROPT_DIR
613                ** option
614                */
615                if ( (transferoption & TROPT_DIR ) != TROPT_DIR ) {
616                    sprintf(logmessage,"Directory (%s) creation needed but TROPT_DIR not set",filepath) ;
617                    FREE(filepath) ;
618                    return -1 ;
619                } else {
620                    if ( (retcode = bbftpd_storemkdir(filepath,logmessage,1)) != 0 ) {
621                        FREE(filepath) ;
622                        return retcode ;
623                    }
624                    filepath[lastslash] = '/';
625                }
626            } else {
627                sprintf(logmessage,"Error stating directory %s : %s ",filepath,strerror(savederrno)) ;
628                FREE(filepath) ;
629                return 1 ;
630            }
631        } else {
632            /*
633            ** The directory exist, check if it is a directory
634            */
635            if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
636                /*
637                ** OK correct
638                */
639                filepath[lastslash] = '/';
640            } else {
641                sprintf(logmessage,"%s is a not a directory",filepath) ;
642                FREE(filepath) ;
643                return -1 ;
644            }
645        }
646    }
647    /*
648    ** At this stage all directory exists so check for the file
649    */
650#ifdef STANDART_FILE_CALL
651    if ( stat(filepath,&statbuf) < 0 ) {
652#else
653    if ( stat64(filepath,&statbuf) < 0 ) {
654#endif
655        /*
656        ** It may be normal to get an error if the file
657        ** does not exist but some error code must lead
658        ** to the interruption of the transfer:
659        **        EACCES        : Search permission denied
660        **        ELOOP        : To many symbolic links on path
661        **        ENAMETOOLONG: Path argument too long
662        **        ENOTDIR        : A component in path is not a directory
663        */
664        savederrno = errno ;
665        if ( savederrno == EACCES ||
666            savederrno == ELOOP ||
667            savederrno == ENAMETOOLONG ||
668            savederrno == ENOTDIR ) {
669            sprintf(logmessage,"Error stating file %s : %s ",filepath,strerror(savederrno)) ;
670            FREE(filepath) ;
671            return -1 ;
672        } else if (savederrno == ENOENT) {
673            /*
674            ** That is normal the file does not exist
675            */
676        } else {
677            sprintf(logmessage,"Error stating file %s : %s ",filepath,strerror(savederrno)) ;
678            FREE(filepath) ;
679            return 1 ;
680        }
681    } else {
682        /*
683        ** The file exists so check if it is a directory
684        */
685        if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
686            sprintf(logmessage,"File %s is a directory",filepath) ;
687            FREE(filepath) ;
688            return -1 ;
689        }
690        /*
691        ** check if it is writable
692        */
693        if ( (statbuf.st_mode & S_IWUSR) != S_IWUSR) {
694            sprintf(logmessage,"File %s is not writable",filepath) ;
695            FREE(filepath) ;
696            return -1 ;
697        }
698        /*
699        ** In order to set correctly the user and group id we
700        ** erase the file first
701        */
702        unlink(filepath) ;
703    }               
704    /*
705    ** We create the file
706    */
707#ifdef STANDART_FILE_CALL
708    if ((fd = open(filepath,O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0 ) {
709#else
710    if ((fd = open64(filepath,O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0 ) {
711#endif
712        /*
713        ** Depending on errno we are going to tell the client to
714        ** retry or not
715        */
716        savederrno = errno ;
717        sprintf(logmessage,"Error creation file %s : %s ",filepath,strerror(errno)) ;
718        /*
719        ** We tell the client not to retry in the following case (even in waiting
720        ** WAITRETRYTIME the problem will not be solved) :
721        **        EACCES        : Search permission denied
722        **        EDQUOT        : No more quota
723        **        ENOSPC        : No more space
724        **        ELOOP        : To many symbolic links on path
725        **        ENAMETOOLONG: Path argument too long
726        **        ENOTDIR        : A component in path is not a directory
727        */
728        if ( savederrno == EACCES ||
729                savederrno == EDQUOT ||
730                savederrno == ENOSPC ||
731                savederrno == ELOOP ||
732                savederrno == ENAMETOOLONG ||
733                savederrno == ENOTDIR ) {
734                FREE(filepath) ;
735                return -1 ;
736        } else {
737            FREE(filepath) ;
738            return 1 ;
739        }
740    }
741    if ( filesize == 0 ) {
742        char statmessage[1024];
743        close(fd) ;
744        sprintf(statmessage,"PUT %s %s 0 0 0.0 0.0", currentusername, filepath);
745        syslog(BBFTPD_NOTICE,statmessage);
746        FREE(filepath) ;
747        return 0 ;
748    }
749    /*
750    ** Lseek to set it to the correct size
751    ** We use toseek because filesize is of type my64t and
752    ** call to lseek can be done with off_t which may be
753    ** of length 64 bits or 32 bits
754    */
755/*    toseek = filesize-1 ;
756*#ifdef STANDART_FILE_CALL
757*    if ( lseek(fd,toseek,SEEK_SET) < 0 ) {
758*#else
759*    if ( lseek64(fd,toseek,SEEK_SET) < 0 ) {
760*#endif
761*        sprintf(logmessage,"Error seeking file %s : %s ",filepath,strerror(errno)) ;
762*        close(fd) ;
763*        unlink(filepath) ;
764*        free(filepath) ;
765*        return 1 ;
766*    }
767*/
768    /*
769    ** Write one byte
770    */
771/*    if ( write(fd,"\0",1) != 1) {
772*        savederrno = errno ;
773*        sprintf(logmessage,"Error writing file %s : %s ",filepath,strerror(errno)) ;
774*        close(fd) ;
775*        unlink(filepath) ;
776*/
777        /*
778        ** We tell the client not to retry in the following case (even in waiting
779        ** WAITRETRYTIME the problem will not be solved) :
780        **        EDQUOT        : No more quota
781        **        ENOSPC        : No space on device
782        */
783/*        if ( savederrno == EDQUOT ||
784*                savederrno == ENOSPC ) {
785*            free(filepath) ;
786*            return -1 ;
787*        } else {
788*            free(filepath) ;
789*            return 1 ;
790*        }
791*    }
792*/
793    /*
794    ** And close the file
795    */
796    if ( close(fd) < 0 ) {
797        savederrno = errno ;
798        unlink(filepath) ;
799        sprintf(logmessage,"Error closing file %s : %s ",filepath,strerror(savederrno)) ;
800        if ( savederrno == ENOSPC ) {
801            FREE(filepath) ;
802            return -1 ;
803        } else {
804            FREE(filepath) ;
805            return 1 ;
806        }
807    }
808    FREE(filepath) ;
809    return 0 ;
810}
811/*******************************************************************************
812** bbftpd_storetransferfile :                                                  *
813**                                                                             *
814**      Routine to transfer a file                                             *
815**                                                                             *
816**      INPUT variable :                                                       *
817**          filename    :  file to create    NOT MODIFIED                      *
818**                                                                             *
819**      OUTPUT variable :                                                      *
820**          logmessage :  to write the error message in case of error          *
821**                                                                             *
822**      GLOBAL VARIABLE USED :                                                 *                                                                      *
823**                                                                             *
824**      RETURN:                                                                *
825**          -1  transfer failed unrecoverable error                            *
826**           0  Keep the connection open (does not mean that the file has been *
827**                successfully transfered)                                       *
828**          >0  Recoverable error but calling has the cleaning to do           *
829**                                                                             *
830*******************************************************************************/
831 
832int bbftpd_storetransferfile(char *filename,int simulation,char *logmessage) 
833{
834#ifdef STANDART_FILE_CALL
835    off_t         nbperchild ;
836    off_t         nbtoget;
837    off_t         startpoint ;
838    off_t         nbget ;
839    struct stat statbuf ;
840#else
841    off64_t     nbperchild ;
842    off64_t     nbtoget;
843    off64_t     startpoint ;
844    off64_t     nbget ;
845    struct stat64 statbuf ;
846#endif
847#ifdef WITH_GZIP
848    uLong    buflen ;
849    uLong    bufcomplen ;
850#endif
851    int     lentowrite;
852    int     lenwrited;
853    int     datatoreceive;
854    int     dataonone;
855
856    int     *pidfree ;
857    int     *sockfree ; /* for PASV mode only */
858    int     *portnumber ;
859    int     i ;
860    int     recsock ;
861    int        retcode ;
862    int        compressionon ;
863    int     nfds ; 
864    fd_set    selectmask ;
865    struct timeval    wait_timer;
866    int     fd ;
867    my64_t    toprint64 ;
868    struct mess_compress *msg_compress ;
869    struct message *msg ;
870    int     waitedtime ;
871    /*
872    ** Check if it is a rfio transfer
873    */
874    if ( (transferoption & TROPT_RFIO) == TROPT_RFIO ) {
875#if defined(WITH_RFIO) || defined(WITH_RFIO64)
876        return bbftpd_storetransferfile_rfio(filename,simulation,logmessage) ;
877#else
878        return 0 ;
879#endif
880    }
881   
882    if ( protocolversion <= 2 ) { /* Active mode */
883      portnumber = myports ;
884        } else {
885          sockfree = mysockets ;
886        }
887    nbperchild = filesize/requestedstreamnumber ;
888    pidfree = mychildren ;
889    nbpidchild = 0 ;
890    /*
891    ** unlinkfile is set to one in case of death of a children by a kill -9
892    ** In this case the child is unable to unlink the file so that
893    ** has to be done by the father
894    */
895    unlinkfile = 1 ;
896    childendinerror = 0 ; /* No child so no error */
897    for (i = 1 ; i <= requestedstreamnumber ; i++) {
898        if ( i == requestedstreamnumber ) {
899            startpoint = (i-1)*nbperchild;
900            nbtoget = filesize-(nbperchild*(requestedstreamnumber-1)) ;
901        } else {
902            startpoint = (i-1)*nbperchild;
903            nbtoget = nbperchild ;
904        }
905        if (protocolversion <= 2) { /* ACTIVE MODE */
906          /*
907          ** Now create the socket to receive
908          */
909          recsock = 0 ;
910          while (recsock == 0 ) {
911            recsock = bbftpd_createreceivesocket(*portnumber,logmessage) ;
912          }
913          if ( recsock < 0 ) {
914           
915            /*
916            ** We set childendinerror to 1 in order to prevent the father
917            ** to send a BAD message which can desynchronize the client and the
918            ** server (We need only one error message)
919            ** Bug discovered by amlutz on 2000/03/11
920            */
921            if ( childendinerror == 0 ) {
922                childendinerror = 1 ;
923                reply(MSG_BAD,logmessage) ;
924            }
925            clean_child() ;
926            return 1 ;
927          }
928          portnumber++ ;
929        } else { /* PASSIVE MODE */
930          recsock = *sockfree ;
931          sockfree++ ;
932        }
933        /*
934        ** Set flagsighup to zero in order to be able in child
935        ** not to wait STARTCHILDTO if signal was sent before
936        ** entering select. (Seen on Linux with one child)
937        */
938        flagsighup = 0 ;
939        if ( ( retcode = fork() ) == 0 ) {
940            int     ns ;
941            /*
942            ** We are in child
943            */
944            /*
945            ** Pause until father send a SIGHUP in order to prevent
946            ** child to die before father has started all children
947            */
948            waitedtime = 0 ;
949            while (flagsighup == 0 && waitedtime < STARTCHILDTO) {
950                wait_timer.tv_sec  = 1 ;
951                wait_timer.tv_usec = 0 ;
952                nfds = sysconf(_SC_OPEN_MAX) ;
953                select(nfds,0,0,0,&wait_timer) ;
954                waitedtime = waitedtime + 1 ;
955            }
956            syslog(BBFTPD_DEBUG,"Child %d starting",getpid()) ;
957            /*
958            ** Close all unnecessary stuff
959            */
960            close(incontrolsock) ;
961            close(outcontrolsock) ; 
962            /*
963            ** Check if file exist
964            */
965#ifdef STANDART_FILE_CALL
966            if ( stat(filename,&statbuf) < 0 ) {
967#else
968            if ( stat64(filename,&statbuf) < 0 ) {
969#endif
970                /*
971                ** If the file does not exist that means that another
972                ** child has detroyed it
973                */ 
974                i = errno ;
975                syslog(BBFTPD_ERR,"Error stating file %s : %s ",filename,strerror(errno)) ;
976                close(recsock) ;
977                exit(i) ;
978            }
979            /*
980            ** Open and seek to position
981            */
982#ifdef STANDART_FILE_CALL
983            if ((fd = open(filename,O_RDWR)) < 0 ) {
984#else
985            if ((fd = open64(filename,O_RDWR)) < 0 ) {
986#endif
987                i = errno ;
988                unlink(filename) ;
989                syslog(BBFTPD_ERR,"Error opening file %s : %s ",filename,strerror(errno)) ;
990                /*
991                ** At this point a non recoverable error is
992                **        EDQUOT        : No more quota
993                **        ENOSPC        : No more space
994                */
995                if ( i == EDQUOT ||
996                        i == ENOSPC ) {
997                    close(recsock) ;
998                    exit(255) ;
999                } else {
1000                    close(recsock) ;
1001                    exit(i) ;
1002                }
1003            }
1004#ifdef STANDART_FILE_CALL
1005            if ( lseek(fd,startpoint,SEEK_SET) < 0 ) {
1006#else
1007            if ( lseek64(fd,startpoint,SEEK_SET) < 0 ) {
1008#endif
1009                i = errno ;
1010                close(fd) ;
1011                unlink(filename) ;
1012                syslog(BBFTPD_ERR,"error seeking file : %s",strerror(errno)) ;
1013                close(recsock) ;
1014                exit(i)  ;
1015            }
1016            if ( protocolversion >= 3 ) {
1017              if ( (ns = accept(recsock,0,0) ) < 0 ) {
1018                i = errno ;
1019                close(fd) ;
1020                unlink(filename) ;
1021                syslog(BBFTPD_ERR,"Error accept socket : %s",strerror(errno)) ;
1022                close(recsock) ;
1023                exit(i)  ;
1024              }
1025              close(recsock) ;
1026            } else {
1027              ns = recsock ;
1028            }
1029            /*
1030            ** start the reading loop
1031            ** Handle the simulation mode
1032            */
1033            if (!simulation) {
1034              nbget = 0 ;
1035              while ( nbget < nbtoget) {
1036                if ( (transferoption & TROPT_GZIP ) == TROPT_GZIP ) {
1037                    /*
1038                    ** Receive the header first
1039                    */
1040                    if (readmessage(ns,readbuffer,COMPMESSLEN,datato) < 0 ) {
1041                        syslog(BBFTPD_ERR,"Error reading compression header") ;
1042                        close(fd) ;
1043                        unlink(filename) ;
1044                        i = ETIMEDOUT ;
1045                        exit(i) ;
1046                    }
1047                    msg_compress = ( struct mess_compress *) readbuffer ;
1048#ifndef WORDS_BIGENDIAN
1049                    msg_compress->datalen = ntohl(msg_compress->datalen) ;
1050#endif
1051                    if ( msg_compress->code == DATA_COMPRESS) {
1052                        compressionon = 1 ;
1053                    } else {
1054                        compressionon = 0 ;
1055                    }
1056                    datatoreceive = msg_compress->datalen ;
1057                } else {
1058                    /*
1059                    ** No compression just adjust the length to receive
1060                    */
1061                    if (buffersizeperstream*1024  <= nbtoget-nbget ) {
1062                        datatoreceive =  buffersizeperstream*1024 ;
1063                    } else {
1064                        datatoreceive = nbtoget-nbget ;
1065                    }
1066                }
1067                /*
1068                ** Start the data collection
1069                */
1070                dataonone = 0 ;
1071                while ( dataonone < datatoreceive ) {
1072                    nfds = sysconf(_SC_OPEN_MAX) ;
1073                    FD_ZERO(&selectmask) ;
1074                    FD_SET(ns,&selectmask) ;
1075                    wait_timer.tv_sec  = datato ;
1076                    wait_timer.tv_usec = 0 ;
1077                    if ( (retcode = select(nfds,&selectmask,0,0,&wait_timer) ) == -1 ) {
1078                        /*
1079                        ** Select error
1080                        */
1081                        i = errno ;
1082                        syslog(BBFTPD_ERR,"Error select while receiving : %s",strerror(errno)) ;
1083                        close(fd) ;
1084                        unlink(filename) ;
1085                        close(ns) ;
1086                        exit(i) ;
1087                    } else if ( retcode == 0 ) {
1088                        syslog(BBFTPD_ERR,"Time out while receiving") ;
1089                        close(fd) ;
1090                        unlink(filename) ;
1091                        i=ETIMEDOUT ;
1092                        close(ns) ;
1093                        exit(i) ;
1094                    } else {
1095                        retcode = recv(ns,&readbuffer[dataonone],datatoreceive-dataonone,0) ;
1096                        if ( retcode < 0 ) {
1097                            i = errno ;
1098                            syslog(BBFTPD_ERR,"Error while receiving : %s",strerror(errno)) ;
1099                            close(fd) ;
1100                            unlink(filename) ;
1101                            close(ns) ;
1102                            exit(i) ;
1103                        } else if ( retcode == 0 ) {
1104                            i = ECONNRESET ;
1105                            syslog(BBFTPD_ERR,"Connexion breaks") ;
1106                            close(fd) ;
1107                            unlink(filename) ;
1108                            close(ns) ;
1109                            exit(i) ;
1110                        } else {
1111                            dataonone = dataonone + retcode ;
1112                        }
1113                    }
1114                }
1115                /*
1116                ** We have received all data needed
1117                */
1118#ifdef WITH_GZIP
1119                if ( (transferoption & TROPT_GZIP ) == TROPT_GZIP ) {
1120                    if ( compressionon == 1 ) {
1121                        bufcomplen = buffersizeperstream*1024 ;
1122                        buflen = dataonone ;
1123                        retcode = uncompress((Bytef *) compbuffer, &bufcomplen, (Bytef *) readbuffer, buflen) ;
1124                        if ( retcode != 0 ) {
1125                            i = EILSEQ ;
1126                            syslog(BBFTPD_ERR,"Error while decompressing %d ",retcode) ;
1127                            close(fd) ;
1128                            unlink(filename) ;
1129                            close(ns) ;
1130                            exit(i) ;
1131                        }
1132                        memcpy(readbuffer,compbuffer,buffersizeperstream*1024) ;
1133                        lentowrite = bufcomplen ;
1134                    } else {
1135                        lentowrite = dataonone ;
1136                    }
1137                } else {
1138                    lentowrite = dataonone ;
1139                }
1140#else
1141                lentowrite = dataonone ;
1142#endif
1143                /*
1144                ** Write it to the file
1145                */
1146                lenwrited = 0 ;
1147                while ( lenwrited < lentowrite ) {
1148                    if ( (retcode = write(fd,&readbuffer[lenwrited],lentowrite-lenwrited)) < 0 ) {
1149                        i = errno ;
1150                        syslog(BBFTPD_ERR,"error writing file : %s",strerror(errno)) ;
1151                        close(fd) ;
1152                        unlink(filename) ;
1153                        if ( i == EDQUOT ||
1154                                i == ENOSPC ) {
1155                            close(ns) ;
1156                            exit(255) ;
1157                        } else {
1158                            close(ns) ;
1159                            exit(i) ;
1160                        }
1161                    } 
1162                    lenwrited = lenwrited + retcode ;
1163                }
1164                nbget = nbget+lenwrited ;
1165              }
1166              /*
1167              ** All data have been received so send the ACK message
1168              */
1169              msg = (struct message *) readbuffer ;
1170              msg->code = MSG_ACK ;
1171              msg->msglen = 0 ;
1172              if ( writemessage(ns,readbuffer,MINMESSLEN,sendcontrolto) < 0 ) {
1173                close(fd) ;
1174                unlink(filename) ;
1175                syslog(BBFTPD_ERR,"Error sending ACK ") ;
1176                close(ns) ;
1177                exit(ETIMEDOUT) ;
1178              }
1179              toprint64 = nbget ;
1180              syslog(BBFTPD_DEBUG,"Child received %" LONG_LONG_FORMAT " bytes ; end correct ",toprint64) ;
1181            }
1182            close(fd) ;
1183            close(ns) ;
1184            exit(0) ;
1185        } else {
1186            /*
1187            ** We are in father
1188            */
1189            if ( retcode == -1 ) {
1190                /*
1191                ** Fork failed ...
1192                */
1193                syslog(BBFTPD_ERR,"fork failed : %s",strerror(errno)) ;
1194                unlink(filename) ;
1195                sprintf(logmessage,"fork failed : %s ",strerror(errno)) ;
1196                if ( childendinerror == 0 ) {
1197                    childendinerror = 1 ;
1198                    reply(MSG_BAD,logmessage) ;
1199                }
1200                clean_child() ;
1201                return 1 ;
1202            } else {
1203                nbpidchild++ ;
1204                *pidfree++ = retcode ;
1205                close(recsock) ;
1206            }
1207        }
1208    }
1209    /*
1210    ** Set the state before starting children because if the file was
1211    ** small the child has ended before state was setup to correct value
1212    */
1213    state = S_RECEIVING ;
1214    /*
1215    ** Start all children
1216    */
1217    pidfree = mychildren ;
1218    for (i = 0 ; i<nbpidchild ; i++) {
1219        if ( *pidfree != 0 ) {
1220            kill(*pidfree,SIGHUP) ;
1221        }
1222       pidfree++ ;
1223    }
1224    if (simulation) {
1225       /*
1226       ** set unlinkfile = 4 in order to delete the file after
1227       ** the simulated transfer
1228       */
1229       unlinkfile = 4 ;
1230    }
1231    (void) gettimeofday(&tstart, (struct timezone *)0);
1232    return 0 ;
1233}
Note: See TracBrowser for help on using the repository browser.