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