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

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

Eliminated many socket related compile time warnings. These
were due to missing #include statements in the bbftp source.

MOST test cases now succeed on callisto! cross-platform stability
is looking more optimistic :-)

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