]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/fileutl.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $ 
   4 /* ###################################################################### 
   8    CopyFile - Buffered copy of a single file 
   9    GetLock - dpkg compatible lock file manipulation (fcntl) 
  11    Most of this source is placed in the Public Domain, do with it what  
  13    It was originally written by Jason Gunthorpe <jgg@debian.org>. 
  14    FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com> 
  16    The exception is RunScripts() it is under the GPLv2 
  18    ##################################################################### */ 
  20 // Include Files                                                        /*{{{*/ 
  21 #include <apt-pkg/fileutl.h> 
  22 #include <apt-pkg/strutl.h> 
  23 #include <apt-pkg/error.h> 
  24 #include <apt-pkg/sptr.h> 
  25 #include <apt-pkg/configuration.h> 
  37 #include <sys/types.h> 
  49 // RunScripts - Run a set of scripts from a configuration subtree       /*{{{*/ 
  50 // --------------------------------------------------------------------- 
  52 bool RunScripts(const char *Cnf
) 
  54    Configuration::Item 
const *Opts 
= _config
->Tree(Cnf
); 
  55    if (Opts 
== 0 || Opts
->Child 
== 0) 
  59    // Fork for running the system calls 
  60    pid_t Child 
= ExecFork(); 
  65       if (chdir("/tmp/") != 0) 
  68       unsigned int Count 
= 1; 
  69       for (; Opts 
!= 0; Opts 
= Opts
->Next
, Count
++) 
  71          if (Opts
->Value
.empty() == true) 
  74          if (system(Opts
->Value
.c_str()) != 0) 
  82    while (waitpid(Child
,&Status
,0) != Child
) 
  86       return _error
->Errno("waitpid","Couldn't wait for subprocess"); 
  89    // Restore sig int/quit 
  90    signal(SIGQUIT
,SIG_DFL
); 
  91    signal(SIGINT
,SIG_DFL
);    
  93    // Check for an error code. 
  94    if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0) 
  96       unsigned int Count 
= WEXITSTATUS(Status
); 
 100          for (; Opts 
!= 0 && Count 
!= 1; Opts 
= Opts
->Next
, Count
--); 
 101          _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str()); 
 104       return _error
->Error("Sub-process returned an error code"); 
 111 // CopyFile - Buffered copy of a file                                   /*{{{*/ 
 112 // --------------------------------------------------------------------- 
 113 /* The caller is expected to set things so that failure causes erasure */ 
 114 bool CopyFile(FileFd 
&From
,FileFd 
&To
) 
 116    if (From
.IsOpen() == false || To
.IsOpen() == false) 
 119    // Buffered copy between fds 
 120    SPtrArray
<unsigned char> Buf 
= new unsigned char[64000]; 
 121    unsigned long Size 
= From
.Size(); 
 124       unsigned long ToRead 
= Size
; 
 128       if (From
.Read(Buf
,ToRead
) == false ||  
 129           To
.Write(Buf
,ToRead
) == false) 
 138 // GetLock - Gets a lock file                                           /*{{{*/ 
 139 // --------------------------------------------------------------------- 
 140 /* This will create an empty file of the given name and lock it. Once this 
 141    is done all other calls to GetLock in any other process will fail with 
 142    -1. The return result is the fd of the file, the call should call 
 143    close at some time. */ 
 144 int GetLock(string File
,bool Errors
) 
 146    // GetLock() is used in aptitude on directories with public-write access 
 147    // Use O_NOFOLLOW here to prevent symlink traversal attacks 
 148    int FD 
= open(File
.c_str(),O_RDWR 
| O_CREAT 
| O_NOFOLLOW
,0640); 
 151       // Read only .. cant have locking problems there. 
 154          _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str()); 
 155          return dup(0);       // Need something for the caller to close 
 159          _error
->Errno("open",_("Could not open lock file %s"),File
.c_str()); 
 161       // Feh.. We do this to distinguish the lock vs open case.. 
 165    SetCloseExec(FD
,true); 
 167    // Aquire a write lock 
 170    fl
.l_whence 
= SEEK_SET
; 
 173    if (fcntl(FD
,F_SETLK
,&fl
) == -1) 
 177          _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str()); 
 178          return dup(0);       // Need something for the caller to close   
 181          _error
->Errno("open",_("Could not get lock %s"),File
.c_str()); 
 192 // FileExists - Check if a file exists                                  /*{{{*/ 
 193 // --------------------------------------------------------------------- 
 195 bool FileExists(string File
) 
 198    if (stat(File
.c_str(),&Buf
) != 0) 
 203 // DirectoryExists - Check if a directory exists and is really one      /*{{{*/ 
 204 // --------------------------------------------------------------------- 
 206 bool DirectoryExists(string 
const &Path
) 
 209    if (stat(Path
.c_str(),&Buf
) != 0) 
 211    return ((Buf
.st_mode 
& S_IFDIR
) != 0); 
 214 // CreateDirectory - poor man's mkdir -p guarded by a parent directory  /*{{{*/ 
 215 // --------------------------------------------------------------------- 
 216 /* This method will create all directories needed for path in good old 
 217    mkdir -p style but refuses to do this if Parent is not a prefix of 
 218    this Path. Example: /var/cache/ and /var/cache/apt/archives are given, 
 219    so it will create apt/archives if /var/cache exists - on the other 
 220    hand if the parent is /var/lib the creation will fail as this path 
 221    is not a parent of the path to be generated. */ 
 222 bool CreateDirectory(string 
const &Parent
, string 
const &Path
) 
 224    if (Parent
.empty() == true || Path
.empty() == true) 
 227    if (DirectoryExists(Path
) == true) 
 230    if (DirectoryExists(Parent
) == false) 
 233    // we are not going to create directories "into the blue" 
 234    if (Path
.find(Parent
, 0) != 0) 
 237    vector
<string
> const dirs 
= VectorizeString(Path
.substr(Parent
.size()), '/'); 
 238    string progress 
= Parent
; 
 239    for (vector
<string
>::const_iterator d 
= dirs
.begin(); d 
!= dirs
.end(); ++d
) 
 241       if (d
->empty() == true) 
 244       progress
.append("/").append(*d
); 
 245       if (DirectoryExists(progress
) == true) 
 248       if (mkdir(progress
.c_str(), 0755) != 0) 
 254 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists          /*{{{*/ 
 255 // --------------------------------------------------------------------- 
 256 /* a small wrapper around CreateDirectory to check if it exists and to 
 257    remove the trailing "/apt/" from the parent directory if needed */ 
 258 bool CreateAPTDirectoryIfNeeded(string 
const &Parent
, string 
const &Path
) 
 260    if (DirectoryExists(Path
) == true) 
 263    size_t const len 
= Parent
.size(); 
 264    if (len 
> 5 && Parent
.find("/apt/", len 
- 6, 5) == len 
- 5) 
 266       if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true) 
 269    else if (CreateDirectory(Parent
, Path
) == true) 
 275 // GetListOfFilesInDir - returns a vector of files in the given dir     /*{{{*/ 
 276 // --------------------------------------------------------------------- 
 277 /* If an extension is given only files with this extension are included 
 278    in the returned vector, otherwise every "normal" file is included. */ 
 279 std::vector
<string
> GetListOfFilesInDir(string 
const &Dir
, string 
const &Ext
, 
 280                                         bool const &SortList
, bool const &AllowNoExt
) 
 282    std::vector
<string
> ext
; 
 284    if (Ext
.empty() == false) 
 286    if (AllowNoExt 
== true && ext
.empty() == false) 
 288    return GetListOfFilesInDir(Dir
, ext
, SortList
); 
 290 std::vector
<string
> GetListOfFilesInDir(string 
const &Dir
, std::vector
<string
> const &Ext
, 
 291                                         bool const &SortList
) 
 293    // Attention debuggers: need to be set with the environment config file! 
 294    bool const Debug 
= _config
->FindB("Debug::GetListOfFilesInDir", false); 
 297       std::clog 
<< "Accept in " << Dir 
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
; 
 298       if (Ext
.empty() == true) 
 299          std::clog 
<< "\tNO extension" << std::endl
; 
 301          for (std::vector
<string
>::const_iterator e 
= Ext
.begin(); 
 303             std::clog 
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
; 
 306    std::vector
<string
> List
; 
 307    Configuration::MatchAgainstConfig 
SilentIgnore("Dir::Ignore-Files-Silently"); 
 308    DIR *D 
= opendir(Dir
.c_str()); 
 311       _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str()); 
 315    for (struct dirent 
*Ent 
= readdir(D
); Ent 
!= 0; Ent 
= readdir(D
))  
 317       // skip "hidden" files 
 318       if (Ent
->d_name
[0] == '.') 
 321       // check for accepted extension: 
 322       // no extension given -> periods are bad as hell! 
 323       // extensions given -> "" extension allows no extension 
 324       if (Ext
.empty() == false) 
 326          string d_ext 
= flExtension(Ent
->d_name
); 
 327          if (d_ext 
== Ent
->d_name
) // no extension 
 329             if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end()) 
 332                   std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → no extension" << std::endl
; 
 333                if (SilentIgnore
.Match(Ent
->d_name
) == false) 
 334                   _error
->Notice("Ignoring file '%s' in directory '%s' as it has no filename extension", Ent
->d_name
, Dir
.c_str()); 
 338          else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end()) 
 341                std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
; 
 342             if (SilentIgnore
.Match(Ent
->d_name
) == false) 
 343                _error
->Notice("Ignoring file '%s' in directory '%s' as it has an invalid filename extension", Ent
->d_name
, Dir
.c_str()); 
 348       // Skip bad filenames ala run-parts 
 349       const char *C 
= Ent
->d_name
; 
 351          if (isalpha(*C
) == 0 && isdigit(*C
) == 0 
 352              && *C 
!= '_' && *C 
!= '-') { 
 353             // no required extension -> dot is a bad character 
 354             if (*C 
== '.' && Ext
.empty() == false) 
 359       // we don't reach the end of the name -> bad character included 
 363             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → bad character »" 
 364                << *C 
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
; 
 368       // skip filenames which end with a period. These are never valid 
 372             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → Period as last character" << std::endl
; 
 376       // Make sure it is a file and not something else 
 377       string 
const File 
= flCombine(Dir
,Ent
->d_name
); 
 379       if (stat(File
.c_str(),&St
) != 0 || S_ISREG(St
.st_mode
) == 0) 
 382             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → stat says not a good file" << std::endl
; 
 387          std::clog 
<< "Accept file: " << Ent
->d_name 
<< " in " << Dir 
<< std::endl
; 
 388       List
.push_back(File
); 
 392    if (SortList 
== true) 
 393       std::sort(List
.begin(),List
.end()); 
 397 // SafeGetCWD - This is a safer getcwd that returns a dynamic string    /*{{{*/ 
 398 // --------------------------------------------------------------------- 
 399 /* We return / on failure. */ 
 402    // Stash the current dir. 
 405    if (getcwd(S
,sizeof(S
)-2) == 0) 
 407    unsigned int Len 
= strlen(S
); 
 413 // flNotDir - Strip the directory from the filename                     /*{{{*/ 
 414 // --------------------------------------------------------------------- 
 416 string 
flNotDir(string File
) 
 418    string::size_type Res 
= File
.rfind('/'); 
 419    if (Res 
== string::npos
) 
 422    return string(File
,Res
,Res 
- File
.length()); 
 425 // flNotFile - Strip the file from the directory name                   /*{{{*/ 
 426 // --------------------------------------------------------------------- 
 427 /* Result ends in a / */ 
 428 string 
flNotFile(string File
) 
 430    string::size_type Res 
= File
.rfind('/'); 
 431    if (Res 
== string::npos
) 
 434    return string(File
,0,Res
); 
 437 // flExtension - Return the extension for the file                      /*{{{*/ 
 438 // --------------------------------------------------------------------- 
 440 string 
flExtension(string File
) 
 442    string::size_type Res 
= File
.rfind('.'); 
 443    if (Res 
== string::npos
) 
 446    return string(File
,Res
,Res 
- File
.length()); 
 449 // flNoLink - If file is a symlink then deref it                        /*{{{*/ 
 450 // --------------------------------------------------------------------- 
 451 /* If the name is not a link then the returned path is the input. */ 
 452 string 
flNoLink(string File
) 
 455    if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0) 
 457    if (stat(File
.c_str(),&St
) != 0) 
 460    /* Loop resolving the link. There is no need to limit the number of  
 461       loops because the stat call above ensures that the symlink is not  
 469       if ((Res 
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||  
 470           (unsigned)Res 
>= sizeof(Buffer
)) 
 473       // Append or replace the previous path 
 475       if (Buffer
[0] == '/') 
 478          NFile 
= flNotFile(NFile
) + Buffer
; 
 480       // See if we are done 
 481       if (lstat(NFile
.c_str(),&St
) != 0) 
 483       if (S_ISLNK(St
.st_mode
) == 0) 
 488 // flCombine - Combine a file and a directory                           /*{{{*/ 
 489 // --------------------------------------------------------------------- 
 490 /* If the file is an absolute path then it is just returned, otherwise 
 491    the directory is pre-pended to it. */ 
 492 string 
flCombine(string Dir
,string File
) 
 494    if (File
.empty() == true) 
 497    if (File
[0] == '/' || Dir
.empty() == true) 
 499    if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/') 
 501    if (Dir
[Dir
.length()-1] == '/') 
 503    return Dir 
+ '/' + File
; 
 506 // SetCloseExec - Set the close on exec flag                            /*{{{*/ 
 507 // --------------------------------------------------------------------- 
 509 void SetCloseExec(int Fd
,bool Close
) 
 511    if (fcntl(Fd
,F_SETFD
,(Close 
== false)?0:FD_CLOEXEC
) != 0) 
 513       cerr 
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
; 
 518 // SetNonBlock - Set the nonblocking flag                               /*{{{*/ 
 519 // --------------------------------------------------------------------- 
 521 void SetNonBlock(int Fd
,bool Block
) 
 523    int Flags 
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
); 
 524    if (fcntl(Fd
,F_SETFL
,Flags 
| ((Block 
== false)?0:O_NONBLOCK
)) != 0) 
 526       cerr 
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
; 
 531 // WaitFd - Wait for a FD to become readable                            /*{{{*/ 
 532 // --------------------------------------------------------------------- 
 533 /* This waits for a FD to become readable using select. It is useful for 
 534    applications making use of non-blocking sockets. The timeout is  
 536 bool WaitFd(int Fd
,bool write
,unsigned long timeout
) 
 549          Res 
= select(Fd
+1,0,&Set
,0,(timeout 
!= 0?&tv
:0)); 
 551       while (Res 
< 0 && errno 
== EINTR
); 
 561          Res 
= select(Fd
+1,&Set
,0,0,(timeout 
!= 0?&tv
:0)); 
 563       while (Res 
< 0 && errno 
== EINTR
); 
 572 // ExecFork - Magical fork that sanitizes the context before execing    /*{{{*/ 
 573 // --------------------------------------------------------------------- 
 574 /* This is used if you want to cleanse the environment for the forked  
 575    child, it fixes up the important signals and nukes all of the fds, 
 576    otherwise acts like normal fork. */ 
 579    // Fork off the process 
 580    pid_t Process 
= fork(); 
 583       cerr 
<< "FATAL -> Failed to fork." << endl
; 
 587    // Spawn the subprocess 
 591       signal(SIGPIPE
,SIG_DFL
); 
 592       signal(SIGQUIT
,SIG_DFL
); 
 593       signal(SIGINT
,SIG_DFL
); 
 594       signal(SIGWINCH
,SIG_DFL
); 
 595       signal(SIGCONT
,SIG_DFL
); 
 596       signal(SIGTSTP
,SIG_DFL
); 
 599       Configuration::Item 
const *Opts 
= _config
->Tree("APT::Keep-Fds"); 
 600       if (Opts 
!= 0 && Opts
->Child 
!= 0) 
 603          for (; Opts 
!= 0; Opts 
= Opts
->Next
) 
 605             if (Opts
->Value
.empty() == true) 
 607             int fd 
= atoi(Opts
->Value
.c_str()); 
 612       // Close all of our FDs - just in case 
 613       for (int K 
= 3; K 
!= 40; K
++) 
 615          if(KeepFDs
.find(K
) == KeepFDs
.end()) 
 616             fcntl(K
,F_SETFD
,FD_CLOEXEC
); 
 623 // ExecWait - Fancy waitpid                                             /*{{{*/ 
 624 // --------------------------------------------------------------------- 
 625 /* Waits for the given sub process. If Reap is set then no errors are  
 626    generated. Otherwise a failed subprocess will generate a proper descriptive 
 628 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
) 
 633    // Wait and collect the error code 
 635    while (waitpid(Pid
,&Status
,0) != Pid
) 
 643       return _error
->Error(_("Waited for %s but it wasn't there"),Name
); 
 647    // Check for an error code. 
 648    if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0) 
 652       if (WIFSIGNALED(Status
) != 0) 
 654          if( WTERMSIG(Status
) == SIGSEGV
) 
 655             return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
); 
 657             return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
)); 
 660       if (WIFEXITED(Status
) != 0) 
 661          return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
)); 
 663       return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
); 
 670 // FileFd::Open - Open a file                                           /*{{{*/ 
 671 // --------------------------------------------------------------------- 
 672 /* The most commonly used open mode combinations are given with Mode */ 
 673 bool FileFd::Open(string FileName
,OpenMode Mode
, unsigned long Perms
) 
 680       iFd 
= open(FileName
.c_str(),O_RDONLY
); 
 684       iFd 
= open(FileName
.c_str(),O_RDONLY
); 
 686          gz 
= gzdopen (iFd
, "r"); 
 697          char *name 
= strdup((FileName 
+ ".XXXXXX").c_str()); 
 698          TemporaryFileName 
= string(mktemp(name
)); 
 699          iFd 
= open(TemporaryFileName
.c_str(),O_RDWR 
| O_CREAT 
| O_EXCL
,Perms
); 
 707          if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
)) 
 708             unlink(FileName
.c_str()); 
 709          iFd 
= open(FileName
.c_str(),O_RDWR 
| O_CREAT 
| O_TRUNC
,Perms
); 
 714       iFd 
= open(FileName
.c_str(),O_RDWR
); 
 718       iFd 
= open(FileName
.c_str(),O_RDWR 
| O_CREAT
,Perms
); 
 722       unlink(FileName
.c_str()); 
 723       iFd 
= open(FileName
.c_str(),O_RDWR 
| O_CREAT 
| O_EXCL
,Perms
); 
 728       return _error
->Errno("open",_("Could not open file %s"),FileName
.c_str()); 
 730    this->FileName 
= FileName
; 
 731    SetCloseExec(iFd
,true); 
 735 bool FileFd::OpenDescriptor(int Fd
, OpenMode Mode
, bool AutoClose
) 
 738    Flags 
= (AutoClose
) ? FileFd::AutoClose 
: 0; 
 740    if (Mode 
== ReadOnlyGzip
) { 
 741       gz 
= gzdopen (iFd
, "r"); 
 745          return _error
->Errno("gzdopen",_("Could not open file descriptor %d"), 
 753 // FileFd::~File - Closes the file                                      /*{{{*/ 
 754 // --------------------------------------------------------------------- 
 755 /* If the proper modes are selected then we close the Fd and possibly 
 756    unlink the file on error. */ 
 762 // FileFd::Read - Read a bit of the file                                /*{{{*/ 
 763 // --------------------------------------------------------------------- 
 764 /* We are carefull to handle interruption by a signal while reading  
 766 bool FileFd::Read(void *To
,unsigned long Size
,unsigned long *Actual
) 
 776          Res 
= gzread(gz
,To
,Size
); 
 778          Res 
= read(iFd
,To
,Size
); 
 779       if (Res 
< 0 && errno 
== EINTR
) 
 784          return _error
->Errno("read",_("Read error")); 
 787       To 
= (char *)To 
+ Res
; 
 792    while (Res 
> 0 && Size 
> 0); 
 805    return _error
->Error(_("read, still have %lu to read but none left"),Size
); 
 808 // FileFd::Write - Write to the file                                    /*{{{*/ 
 809 // --------------------------------------------------------------------- 
 811 bool FileFd::Write(const void *From
,unsigned long Size
) 
 818          Res 
= gzwrite(gz
,From
,Size
); 
 820          Res 
= write(iFd
,From
,Size
); 
 821       if (Res 
< 0 && errno 
== EINTR
) 
 826          return _error
->Errno("write",_("Write error")); 
 829       From 
= (char *)From 
+ Res
; 
 832    while (Res 
> 0 && Size 
> 0); 
 838    return _error
->Error(_("write, still have %lu to write but couldn't"),Size
); 
 841 // FileFd::Seek - Seek in the file                                      /*{{{*/ 
 842 // --------------------------------------------------------------------- 
 844 bool FileFd::Seek(unsigned long To
) 
 848       res 
= gzseek(gz
,To
,SEEK_SET
); 
 850       res 
= lseek(iFd
,To
,SEEK_SET
); 
 851    if (res 
!= (signed)To
) 
 854       return _error
->Error("Unable to seek to %lu",To
); 
 860 // FileFd::Skip - Seek in the file                                      /*{{{*/ 
 861 // --------------------------------------------------------------------- 
 863 bool FileFd::Skip(unsigned long Over
) 
 867       res 
= gzseek(gz
,Over
,SEEK_CUR
); 
 869       res 
= lseek(iFd
,Over
,SEEK_CUR
); 
 873       return _error
->Error("Unable to seek ahead %lu",Over
); 
 879 // FileFd::Truncate - Truncate the file                                 /*{{{*/ 
 880 // --------------------------------------------------------------------- 
 882 bool FileFd::Truncate(unsigned long To
) 
 887       return _error
->Error("Truncating gzipped files is not implemented (%s)", FileName
.c_str()); 
 889    if (ftruncate(iFd
,To
) != 0) 
 892       return _error
->Error("Unable to truncate to %lu",To
); 
 898 // FileFd::Tell - Current seek position                                 /*{{{*/ 
 899 // --------------------------------------------------------------------- 
 901 unsigned long FileFd::Tell() 
 907      Res 
= lseek(iFd
,0,SEEK_CUR
); 
 908    if (Res 
== (off_t
)-1) 
 909       _error
->Errno("lseek","Failed to determine the current file position"); 
 913 // FileFd::FileSize - Return the size of the file                       /*{{{*/ 
 914 // --------------------------------------------------------------------- 
 916 unsigned long FileFd::FileSize() 
 920    if (fstat(iFd
,&Buf
) != 0) 
 921       return _error
->Errno("fstat","Unable to determine the file size"); 
 925 // FileFd::Size - Return the size of the content in the file            /*{{{*/ 
 926 // --------------------------------------------------------------------- 
 928 unsigned long FileFd::Size() 
 930    unsigned long size 
= FileSize(); 
 932    // only check gzsize if we are actually a gzip file, just checking for 
 933    // "gz" is not sufficient as uncompressed files will be opened with 
 934    // gzopen in "direct" mode as well 
 935    if (gz 
&& !gzdirect(gz
) && size 
> 0) 
 937        /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do 
 938         * this ourselves; the original (uncompressed) file size is the last 32 
 939         * bits of the file */ 
 940        off_t orig_pos 
= lseek(iFd
, 0, SEEK_CUR
); 
 941        if (lseek(iFd
, -4, SEEK_END
) < 0) 
 942            return _error
->Errno("lseek","Unable to seek to end of gzipped file"); 
 943        if (read(iFd
, &size
, 4) != 4) 
 944            return _error
->Errno("read","Unable to read original size of gzipped file"); 
 947        if (lseek(iFd
, orig_pos
, SEEK_SET
) < 0) 
 948            return _error
->Errno("lseek","Unable to seek in gzipped file"); 
 955 // FileFd::Close - Close the file if the close flag is set              /*{{{*/ 
 956 // --------------------------------------------------------------------- 
 961    if ((Flags 
& AutoClose
) == AutoClose
) 
 964          int const e 
= gzclose(gz
); 
 965          // gzdopen() on empty files always fails with "buffer error" here, ignore that 
 966          if (e 
!= 0 && e 
!= Z_BUF_ERROR
) 
 967             Res 
&= _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str()); 
 969          if (iFd 
> 0 && close(iFd
) != 0) 
 970             Res 
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str()); 
 973    if ((Flags 
& Replace
) == Replace 
&& iFd 
>= 0) { 
 974       if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0) 
 975          Res 
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str()); 
 977       FileName 
= TemporaryFileName
; // for the unlink() below. 
 983    if ((Flags 
& Fail
) == Fail 
&& (Flags 
& DelOnFail
) == DelOnFail 
&& 
 984        FileName
.empty() == false) 
 985       if (unlink(FileName
.c_str()) != 0) 
 986          Res 
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str()); 
 992 // FileFd::Sync - Sync the file                                         /*{{{*/ 
 993 // --------------------------------------------------------------------- 
 997 #ifdef _POSIX_SYNCHRONIZED_IO 
 999       return _error
->Errno("sync",_("Problem syncing the file"));