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