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