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

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

Implemented two hooks in the bbftpd source that allow
python code to be executed before and afer a fork(). This is needed
to reset python logging and will probably be usefull for other things
in the future.

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