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