merged from apt-get-changelog
[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 <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 // FIXME add an error message saying that empty files can't be valid archives
60 if(From.FileSize() == 0)
61 return false;
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
91 FileFd To(Itm->DestFile,FileFd::WriteAtomic);
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];
102
103 ssize_t Count = read(GzOut[0],Buffer,sizeof(Buffer));
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
163 int 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 }