- initial import of revision 374 from cnc
[apt.git] / methods / gzip.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: gzip.cc,v 1.17 2003/02/10 07:34:41 doogie Exp $
4 /* ######################################################################
5
6    GZip method - Take a file URI in and decompress it into the target 
7    file.
8    
9    ##################################################################### */
10                                                                         /*}}}*/
11 // Include Files                                                        /*{{{*/
12 #include <apt-pkg/fileutl.h>
13 #include <apt-pkg/error.h>
14 #include <apt-pkg/acquire-method.h>
15 #include <apt-pkg/strutl.h>
16 #include <apt-pkg/hashes.h>
17
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <utime.h>
21 #include <stdio.h>
22 #include <errno.h>
23
24 // CNC:2003-02-20 - Moved header to fix compilation error when
25 //                  --disable-nls is used.
26 #include <apti18n.h>
27                                                                         /*}}}*/
28
29 const char *Prog;
30
31 class GzipMethod : public pkgAcqMethod
32 {
33    virtual bool Fetch(FetchItem *Itm);
34    
35    public:
36    
37    GzipMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig) {};
38 };
39
40
41 // GzipMethod::Fetch - Decompress the passed URI                        /*{{{*/
42 // ---------------------------------------------------------------------
43 /* */
44 bool GzipMethod::Fetch(FetchItem *Itm)
45 {
46    URI Get = Itm->Uri;
47    string Path = Get.Host + Get.Path; // To account for relative paths
48    
49    string GzPathOption = "Dir::bin::"+string(Prog);
50
51    FetchResult Res;
52    Res.Filename = Itm->DestFile;
53    URIStart(Res);
54    
55    // Open the source and destination files
56    FileFd From(Path,FileFd::ReadOnly);
57
58    int GzOut[2];   
59    if (pipe(GzOut) < 0)
60       return _error->Errno("pipe",_("Couldn't open pipe for %s"),Prog);
61
62    // Fork gzip
63    int Process = ExecFork();
64    if (Process == 0)
65    {
66       close(GzOut[0]);
67       dup2(From.Fd(),STDIN_FILENO);
68       dup2(GzOut[1],STDOUT_FILENO);
69       From.Close();
70       close(GzOut[1]);
71       SetCloseExec(STDIN_FILENO,false);
72       SetCloseExec(STDOUT_FILENO,false);
73       
74       const char *Args[3];
75       string Tmp = _config->Find(GzPathOption,Prog);
76       Args[0] = Tmp.c_str();
77       Args[1] = "-d";
78       Args[2] = 0;
79       execvp(Args[0],(char **)Args);
80       _exit(100);
81    }
82    From.Close();
83    close(GzOut[1]);
84    
85    FileFd FromGz(GzOut[0]);  // For autoclose   
86    FileFd To(Itm->DestFile,FileFd::WriteEmpty);   
87    To.EraseOnFailure();
88    if (_error->PendingError() == true)
89       return false;
90    
91    // Read data from gzip, generate checksums and write
92    Hashes Hash;
93    bool Failed = false;
94    while (1) 
95    {
96       unsigned char Buffer[4*1024];
97       unsigned long Count;
98       
99       Count = read(GzOut[0],Buffer,sizeof(Buffer));
100       if (Count < 0 && errno == EINTR)
101          continue;
102       
103       if (Count < 0)
104       {
105          _error->Errno("read", _("Read error from %s process"),Prog);
106          Failed = true;
107          break;
108       }
109       
110       if (Count == 0)
111          break;
112       
113       Hash.Add(Buffer,Count);
114       if (To.Write(Buffer,Count) == false)
115       {
116          Failed = true;
117          break;
118       }      
119    }
120    
121    // Wait for gzip to finish
122    if (ExecWait(Process,_config->Find(GzPathOption,Prog).c_str(),false) == false)
123    {
124       To.OpFail();
125       return false;
126    }  
127        
128    To.Close();
129    
130    if (Failed == true)
131       return false;
132    
133    // Transfer the modification times
134    struct stat Buf;
135    if (stat(Path.c_str(),&Buf) != 0)
136       return _error->Errno("stat",_("Failed to stat"));
137
138    struct utimbuf TimeBuf;
139    TimeBuf.actime = Buf.st_atime;
140    TimeBuf.modtime = Buf.st_mtime;
141    if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0)
142       return _error->Errno("utime",_("Failed to set modification time"));
143
144    if (stat(Itm->DestFile.c_str(),&Buf) != 0)
145       return _error->Errno("stat",_("Failed to stat"));
146    
147    // Return a Done response
148    Res.LastModified = Buf.st_mtime;
149    Res.Size = Buf.st_size;
150    Res.TakeHashes(Hash);
151
152    URIDone(Res);
153    
154    return true;
155 }
156                                                                         /*}}}*/
157
158 int main(int argc, char *argv[])
159 {
160    GzipMethod Mth;
161
162    Prog = strrchr(argv[0],'/');
163    Prog++;
164    
165    return Mth.Run();
166 }