]> git.saurik.com Git - apt.git/blob - methods/bzip2.cc
merged from the debian branch
[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 <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
30 const char *Prog;
31
32 class 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 /* */
45 bool 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
59 if(From.FileSize() == 0)
60 return _error->Error(_("Empty files can't be valid archives"));
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
90 FileFd To(Itm->DestFile,FileFd::WriteAtomic);
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];
101
102 ssize_t Count = read(GzOut[0],Buffer,sizeof(Buffer));
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
162 int 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 }