do not pollute namespace in the headers with using (Closes: #500198)
[ntk/apt.git] / methods / bzip2.cc
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 /*{{{*/
16 #include <config.h>
17
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
32 const char *Prog;
33
34 class 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 /* */
47 bool Bzip2Method::Fetch(FetchItem *Itm)
48 {
49 URI Get = Itm->Uri;
50 std::string Path = Get.Host + Get.Path; // To account for relative paths
51
52 std::string GzPathOption = "Dir::bin::" + std::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
61 if(From.FileSize() == 0)
62 return _error->Error(_("Empty files can't be valid archives"));
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 std::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
92 FileFd To(Itm->DestFile,FileFd::WriteAtomic);
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];
103
104 ssize_t Count = read(GzOut[0],Buffer,sizeof(Buffer));
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
164 int 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 }