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

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

More missing #includes exposed when compiling on easterly.

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