]> git.saurik.com Git - apt.git/blob - methods/bzip2.cc
use forward declaration in headers if possible instead of includes
[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 #include <apt-pkg/configuration.h>
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
33 const char *Prog;
34
35 class 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 /* */
48 bool Bzip2Method::Fetch(FetchItem *Itm)
49 {
50 URI Get = Itm->Uri;
51 std::string Path = Get.Host + Get.Path; // To account for relative paths
52
53 std::string GzPathOption = "Dir::bin::" + std::string(Prog);
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
62 if(From.FileSize() == 0)
63 return _error->Error(_("Empty files can't be valid archives"));
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];
82 std::string Tmp = _config->Find(GzPathOption,Prog);
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
93 FileFd To(Itm->DestFile,FileFd::WriteAtomic);
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];
104
105 ssize_t Count = read(GzOut[0],Buffer,sizeof(Buffer));
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
165 int 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 }