]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/fileutl.cc
Join with aliencode
[apt.git] / apt-pkg / contrib / fileutl.cc
index c24a216ef612043e17898f189c25202478536759..0907f4dcd3650a585833b505bb387f67d1688bce 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: fileutl.cc,v 1.29 1999/07/20 05:53:33 jgg Exp $
+// $Id: fileutl.cc,v 1.35 2001/02/20 07:03:17 jgg Exp $
 /* ######################################################################
    
    File Utilities
 /* ######################################################################
    
    File Utilities
 #endif 
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/error.h>
 #endif 
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/sptr.h>
+
+#include <apti18n.h>
 
 #include <unistd.h>
 
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/fcntl.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 #include <signal.h>
 #include <errno.h>
                                                                        /*}}}*/
 #include <signal.h>
 #include <errno.h>
                                                                        /*}}}*/
@@ -38,7 +42,7 @@ bool CopyFile(FileFd &From,FileFd &To)
       return false;
    
    // Buffered copy between fds
       return false;
    
    // Buffered copy between fds
-   unsigned char *Buf = new unsigned char[64000];
+   SPtrArray<unsigned char> Buf = new unsigned char[64000];
    unsigned long Size = From.Size();
    while (Size != 0)
    {
    unsigned long Size = From.Size();
    while (Size != 0)
    {
@@ -48,15 +52,11 @@ bool CopyFile(FileFd &From,FileFd &To)
       
       if (From.Read(Buf,ToRead) == false || 
          To.Write(Buf,ToRead) == false)
       
       if (From.Read(Buf,ToRead) == false || 
          To.Write(Buf,ToRead) == false)
-      {
-        delete [] Buf;
         return false;
         return false;
-      }
       
       Size -= ToRead;
    }
 
       
       Size -= ToRead;
    }
 
-   delete [] Buf;
    return true;   
 }
                                                                        /*}}}*/
    return true;   
 }
                                                                        /*}}}*/
@@ -71,11 +71,22 @@ int GetLock(string File,bool Errors)
    int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
    if (FD < 0)
    {
    int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
    if (FD < 0)
    {
+      // Read only .. cant have locking problems there.
+      if (errno == EROFS)
+      {
+        _error->Warning(_("Not using locking for read only lock file %s"),File.c_str());
+        return dup(0);       // Need something for the caller to close
+      }
+      
       if (Errors == true)
       if (Errors == true)
-        _error->Errno("open","Could not open lock file %s",File.c_str());
+        _error->Errno("open",_("Could not open lock file %s"),File.c_str());
+
+      // Feh.. We do this to distinguish the lock vs open case..
+      errno = EPERM;
       return -1;
    }
       return -1;
    }
-   
+   SetCloseExec(FD,true);
+      
    // Aquire a write lock
    struct flock fl;
    fl.l_type = F_WRLCK;
    // Aquire a write lock
    struct flock fl;
    fl.l_type = F_WRLCK;
@@ -86,12 +97,15 @@ int GetLock(string File,bool Errors)
    {
       if (errno == ENOLCK)
       {
    {
       if (errno == ENOLCK)
       {
-        _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
-        return true;
+        _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
+        return dup(0);       // Need something for the caller to close  
       }      
       if (Errors == true)
       }      
       if (Errors == true)
-        _error->Errno("open","Could not get lock %s",File.c_str());
+        _error->Errno("open",_("Could not get lock %s"),File.c_str());
+      
+      int Tmp = errno;
       close(FD);
       close(FD);
+      errno = Tmp;
       return -1;
    }
 
       return -1;
    }
 
@@ -149,6 +163,75 @@ string flNotFile(string File)
    return string(File,0,Res);
 }
                                                                        /*}}}*/
    return string(File,0,Res);
 }
                                                                        /*}}}*/
+// flExtension - Return the extension for the file                     /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string flExtension(string File)
+{
+   string::size_type Res = File.rfind('.');
+   if (Res == string::npos)
+      return File;
+   Res++;
+   return string(File,Res,Res - File.length());
+}
+                                                                       /*}}}*/
+// flNoLink - If file is a symlink then deref it                       /*{{{*/
+// ---------------------------------------------------------------------
+/* If the name is not a link then the returned path is the input. */
+string flNoLink(string File)
+{
+   struct stat St;
+   if (lstat(File.c_str(),&St) != 0 || S_ISLNK(St.st_mode) == 0)
+      return File;
+   if (stat(File.c_str(),&St) != 0)
+      return File;
+   
+   /* Loop resolving the link. There is no need to limit the number of 
+      loops because the stat call above ensures that the symlink is not 
+      circular */
+   char Buffer[1024];
+   string NFile = File;
+   while (1)
+   {
+      // Read the link
+      int Res;
+      if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 || 
+         (unsigned)Res >= sizeof(Buffer))
+         return File;
+      
+      // Append or replace the previous path
+      Buffer[Res] = 0;
+      if (Buffer[0] == '/')
+        NFile = Buffer;
+      else
+        NFile = flNotFile(NFile) + Buffer;
+      
+      // See if we are done
+      if (lstat(NFile.c_str(),&St) != 0)
+        return File;
+      if (S_ISLNK(St.st_mode) == 0)
+        return NFile;      
+   }   
+}
+                                                                       /*}}}*/
+// flCombine - Combine a file and a directory                          /*{{{*/
+// ---------------------------------------------------------------------
+/* If the file is an absolute path then it is just returned, otherwise
+   the directory is pre-pended to it. */
+string flCombine(string Dir,string File)
+{
+   if (File.empty() == true)
+      return string();
+   
+   if (File[0] == '/' || Dir.empty() == true)
+      return File;
+   if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
+      return File;
+   if (Dir[Dir.length()-1] == '/')
+      return Dir + File;
+   return Dir + '/' + File;
+}
+                                                                       /*}}}*/
 // SetCloseExec - Set the close on exec flag                           /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 // SetCloseExec - Set the close on exec flag                           /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -176,7 +259,7 @@ void SetNonBlock(int Fd,bool Block)
                                                                        /*}}}*/
 // WaitFd - Wait for a FD to become readable                           /*{{{*/
 // ---------------------------------------------------------------------
                                                                        /*}}}*/
 // WaitFd - Wait for a FD to become readable                           /*{{{*/
 // ---------------------------------------------------------------------
-/* This waits for a FD to become readable using select. It is usefull for
+/* This waits for a FD to become readable using select. It is useful for
    applications making use of non-blocking sockets. The timeout is 
    in seconds. */
 bool WaitFd(int Fd,bool write,unsigned long timeout)
    applications making use of non-blocking sockets. The timeout is 
    in seconds. */
 bool WaitFd(int Fd,bool write,unsigned long timeout)
@@ -249,6 +332,47 @@ int ExecFork()
    return Process;
 }
                                                                        /*}}}*/
    return Process;
 }
                                                                        /*}}}*/
+// ExecWait - Fancy waitpid                                            /*{{{*/
+// ---------------------------------------------------------------------
+/* Waits for the given sub process. If Reap is set the no errors are 
+   generated. Otherwise a failed subprocess will generate a proper descriptive
+   message */
+bool ExecWait(int Pid,const char *Name,bool Reap)
+{
+   if (Pid <= 1)
+      return true;
+   
+   // Wait and collect the error code
+   int Status;
+   while (waitpid(Pid,&Status,0) != Pid)
+   {
+      if (errno == EINTR)
+        continue;
+
+      if (Reap == true)
+        return false;
+      
+      return _error->Error(_("Waited, for %s but it wasn't there"),Name);
+   }
+
+   
+   // Check for an error code.
+   if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
+   {
+      if (Reap == true)
+        return false;
+      if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
+        return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
+
+      if (WIFEXITED(Status) != 0)
+        return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
+      
+      return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
+   }      
+   
+   return true;
+}
+                                                                       /*}}}*/
 
 // FileFd::Open - Open a file                                          /*{{{*/
 // ---------------------------------------------------------------------
 
 // FileFd::Open - Open a file                                          /*{{{*/
 // ---------------------------------------------------------------------
@@ -266,7 +390,7 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
       case WriteEmpty:
       {
         struct stat Buf;
       case WriteEmpty:
       {
         struct stat Buf;
-        if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
+        if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
            unlink(FileName.c_str());
         iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
         break;
            unlink(FileName.c_str());
         iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
         break;
@@ -282,7 +406,7 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
    }  
 
    if (iFd < 0)
    }  
 
    if (iFd < 0)
-      return _error->Errno("open","Could not open file %s",FileName.c_str());
+      return _error->Errno("open",_("Could not open file %s"),FileName.c_str());
    
    this->FileName = FileName;
    SetCloseExec(iFd,true);
    
    this->FileName = FileName;
    SetCloseExec(iFd,true);
@@ -302,7 +426,7 @@ FileFd::~FileFd()
 // ---------------------------------------------------------------------
 /* We are carefull to handle interruption by a signal while reading 
    gracefully. */
 // ---------------------------------------------------------------------
 /* We are carefull to handle interruption by a signal while reading 
    gracefully. */
-bool FileFd::Read(void *To,unsigned long Size)
+bool FileFd::Read(void *To,unsigned long Size,bool AllowEof)
 {
    int Res;
    errno = 0;
 {
    int Res;
    errno = 0;
@@ -314,7 +438,7 @@ bool FileFd::Read(void *To,unsigned long Size)
       if (Res < 0)
       {
         Flags |= Fail;
       if (Res < 0)
       {
         Flags |= Fail;
-        return _error->Errno("read","Read error");
+        return _error->Errno("read",_("Read error"));
       }
       
       To = (char *)To + Res;
       }
       
       To = (char *)To + Res;
@@ -325,8 +449,15 @@ bool FileFd::Read(void *To,unsigned long Size)
    if (Size == 0)
       return true;
    
    if (Size == 0)
       return true;
    
+   // Eof handling
+   if (AllowEof == true)
+   {
+      Flags |= HitEof;
+      return true;
+   }
+   
    Flags |= Fail;
    Flags |= Fail;
-   return _error->Error("read, still have %u to read but none left",Size);
+   return _error->Error(_("read, still have %lu to read but none left"),Size);
 }
                                                                        /*}}}*/
 // FileFd::Write - Write to the file                                   /*{{{*/
 }
                                                                        /*}}}*/
 // FileFd::Write - Write to the file                                   /*{{{*/
@@ -344,7 +475,7 @@ bool FileFd::Write(const void *From,unsigned long Size)
       if (Res < 0)
       {
         Flags |= Fail;
       if (Res < 0)
       {
         Flags |= Fail;
-        return _error->Errno("write","Write error");
+        return _error->Errno("write",_("Write error"));
       }
       
       From = (char *)From + Res;
       }
       
       From = (char *)From + Res;
@@ -356,7 +487,7 @@ bool FileFd::Write(const void *From,unsigned long Size)
       return true;
    
    Flags |= Fail;
       return true;
    
    Flags |= Fail;
-   return _error->Error("write, still have %u to write but couldn't",Size);
+   return _error->Error(_("write, still have %lu to write but couldn't"),Size);
 }
                                                                        /*}}}*/
 // FileFd::Seek - Seek in the file                                     /*{{{*/
 }
                                                                        /*}}}*/
 // FileFd::Seek - Seek in the file                                     /*{{{*/
@@ -367,7 +498,7 @@ bool FileFd::Seek(unsigned long To)
    if (lseek(iFd,To,SEEK_SET) != (signed)To)
    {
       Flags |= Fail;
    if (lseek(iFd,To,SEEK_SET) != (signed)To)
    {
       Flags |= Fail;
-      return _error->Error("Unable to seek to %u",To);
+      return _error->Error("Unable to seek to %lu",To);
    }
    
    return true;
    }
    
    return true;
@@ -381,7 +512,7 @@ bool FileFd::Skip(unsigned long Over)
    if (lseek(iFd,Over,SEEK_CUR) < 0)
    {
       Flags |= Fail;
    if (lseek(iFd,Over,SEEK_CUR) < 0)
    {
       Flags |= Fail;
-      return _error->Error("Unable to seek ahead %u",Over);
+      return _error->Error("Unable to seek ahead %lu",Over);
    }
    
    return true;
    }
    
    return true;
@@ -395,7 +526,7 @@ bool FileFd::Truncate(unsigned long To)
    if (ftruncate(iFd,To) != 0)
    {
       Flags |= Fail;
    if (ftruncate(iFd,To) != 0)
    {
       Flags |= Fail;
-      return _error->Error("Unable to truncate to %u",To);
+      return _error->Error("Unable to truncate to %lu",To);
    }
    
    return true;
    }
    
    return true;
@@ -431,13 +562,25 @@ bool FileFd::Close()
    bool Res = true;
    if ((Flags & AutoClose) == AutoClose)
       if (iFd >= 0 && close(iFd) != 0)
    bool Res = true;
    if ((Flags & AutoClose) == AutoClose)
       if (iFd >= 0 && close(iFd) != 0)
-        Res &= _error->Errno("close","Problem closing the file");
+        Res &= _error->Errno("close",_("Problem closing the file"));
    iFd = -1;
    
    if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
        FileName.empty() == false)
       if (unlink(FileName.c_str()) != 0)
    iFd = -1;
    
    if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
        FileName.empty() == false)
       if (unlink(FileName.c_str()) != 0)
-        Res &= _error->Warning("unlnk","Problem unlinking the file");
+        Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
    return Res;
 }
                                                                        /*}}}*/
    return Res;
 }
                                                                        /*}}}*/
+// FileFd::Sync - Sync the file                                                /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FileFd::Sync()
+{
+#ifdef _POSIX_SYNCHRONIZED_IO
+   if (fsync(iFd) != 0)
+      return _error->Errno("sync",_("Problem syncing the file"));
+#endif
+   return true;
+}
+                                                                       /*}}}*/