releasing version 0.8.16~exp3
[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
4260fd39 59 if(From.FileSize() == 0)
5d885723 60 return _error->Error(_("Empty files can't be valid archives"));
b0966366
DK
61
62 int GzOut[2];
63 if (pipe(GzOut) < 0)
64 return _error->Errno("pipe",_("Couldn't open pipe for %s"),Prog);
65
66 // Fork bzip2
67 pid_t Process = ExecFork();
68 if (Process == 0)
69 {
70 close(GzOut[0]);
71 dup2(From.Fd(),STDIN_FILENO);
72 dup2(GzOut[1],STDOUT_FILENO);
73 From.Close();
74 close(GzOut[1]);
75 SetCloseExec(STDIN_FILENO,false);
76 SetCloseExec(STDOUT_FILENO,false);
77
78 const char *Args[3];
79 string Tmp = _config->Find(GzPathOption,Prog);
80 Args[0] = Tmp.c_str();
81 Args[1] = "-d";
82 Args[2] = 0;
83 execvp(Args[0],(char **)Args);
84 _exit(100);
85 }
86 From.Close();
87 close(GzOut[1]);
88
89 FileFd FromGz(GzOut[0]); // For autoclose
22041bd2 90 FileFd To(Itm->DestFile,FileFd::WriteAtomic);
b0966366
DK
91 To.EraseOnFailure();
92 if (_error->PendingError() == true)
93 return false;
94
95 // Read data from bzip2, generate checksums and write
96 Hashes Hash;
97 bool Failed = false;
98 while (1)
99 {
100 unsigned char Buffer[4*1024];
b0966366 101
6802b90c 102 ssize_t Count = read(GzOut[0],Buffer,sizeof(Buffer));
b0966366
DK
103 if (Count < 0 && errno == EINTR)
104 continue;
105
106 if (Count < 0)
107 {
108 _error->Errno("read", _("Read error from %s process"),Prog);
109 Failed = true;
110 break;
111 }
112
113 if (Count == 0)
114 break;
115
116 Hash.Add(Buffer,Count);
117 if (To.Write(Buffer,Count) == false)
118 {
119 Failed = true;
120 FromGz.Close();
121 break;
122 }
123 }
124
125 // Wait for bzip2 to finish
126 if (ExecWait(Process,_config->Find(GzPathOption,Prog).c_str(),false) == false)
127 {
128 To.OpFail();
129 return false;
130 }
131
132 To.Close();
133
134 if (Failed == true)
135 return false;
136
137 // Transfer the modification times
138 struct stat Buf;
139 if (stat(Path.c_str(),&Buf) != 0)
140 return _error->Errno("stat",_("Failed to stat"));
141
142 struct utimbuf TimeBuf;
143 TimeBuf.actime = Buf.st_atime;
144 TimeBuf.modtime = Buf.st_mtime;
145 if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0)
146 return _error->Errno("utime",_("Failed to set modification time"));
147
148 if (stat(Itm->DestFile.c_str(),&Buf) != 0)
149 return _error->Errno("stat",_("Failed to stat"));
150
151 // Return a Done response
152 Res.LastModified = Buf.st_mtime;
153 Res.Size = Buf.st_size;
154 Res.TakeHashes(Hash);
155
156 URIDone(Res);
157
158 return true;
159}
160 /*}}}*/
161
162int main(int argc, char *argv[])
163{
164 setlocale(LC_ALL, "");
165
166 Bzip2Method Mth;
167
168 Prog = strrchr(argv[0],'/');
169 Prog++;
170
171 return Mth.Run();
172}