]> git.saurik.com Git - apt.git/blame - methods/store.cc
gpgv: cleanup statusfd parsing a bit
[apt.git] / methods / store.cc
CommitLineData
92173b19
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
92173b19
AL
3/* ######################################################################
4
9bd2313a
DK
5 Store method - Takes a file URI and stores its content (for which it will
6 calculate the hashes) in the given destination. The input file will be
7 extracted based on its file extension (or with the given compressor if
8 called with one of the compatible symlinks) and potentially recompressed
9 based on the file extension of the destination filename.
10
92173b19
AL
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
ea542140
DK
14#include <config.h>
15
0ec6b98b 16#include <apt-pkg/configuration.h>
93bf083d 17#include <apt-pkg/acquire-method.h>
453b82a3
DK
18#include <apt-pkg/error.h>
19#include <apt-pkg/fileutl.h>
63b1700f 20#include <apt-pkg/hashes.h>
453b82a3
DK
21#include <apt-pkg/strutl.h>
22#include <apt-pkg/aptconfiguration.h>
23e64f6d 23#include "aptmethod.h"
92173b19 24
453b82a3 25#include <string.h>
92173b19 26#include <sys/stat.h>
246bbb61 27#include <sys/time.h>
453b82a3
DK
28#include <string>
29#include <vector>
30
d77559ac 31#include <apti18n.h>
92173b19
AL
32 /*}}}*/
33
9bd2313a 34class StoreMethod : public aptMethod
92173b19 35{
23e64f6d 36 std::string const Prog;
3b302846 37 virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
9983999d 38
23e64f6d 39 public:
9983999d 40
9bd2313a 41 explicit StoreMethod(std::string const &pProg) : aptMethod(pProg.c_str(),"1.2",SingleInstance | SendConfig), Prog(pProg) {};
23e64f6d 42};
63b1700f 43
9bd2313a 44static bool OpenFileWithCompressorByName(FileFd &fileFd, std::string const &Filename, unsigned int const Mode, std::string const &Name)
92173b19 45{
9bd2313a
DK
46 if (Name == "store")
47 return fileFd.Open(Filename, Mode, FileFd::Extension);
d6bbcaad
DK
48
49 std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
50 std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
51 for (; compressor != compressors.end(); ++compressor)
9bd2313a 52 if (compressor->Name == Name)
d6bbcaad
DK
53 break;
54 if (compressor == compressors.end())
9bd2313a
DK
55 return _error->Error("Extraction of file %s requires unknown compressor %s", Filename.c_str(), Name.c_str());
56 return fileFd.Open(Filename, Mode, *compressor);
57}
58
59
60 /*}}}*/
61bool StoreMethod::Fetch(FetchItem *Itm) /*{{{*/
62{
63 URI Get = Itm->Uri;
64 std::string Path = Get.Host + Get.Path; // To account for relative paths
65
66 FetchResult Res;
67 Res.Filename = Itm->DestFile;
68 URIStart(Res);
d6bbcaad 69
63b1700f 70 // Open the source and destination files
af9e40c9 71 FileFd From;
0ec6b98b
DK
72 if (_config->FindB("Method::Compress", false) == false)
73 {
9bd2313a
DK
74 if (OpenFileWithCompressorByName(From, Path, FileFd::ReadOnly, Prog) == false)
75 return false;
479f6fa4 76 if(From.IsCompressed() && From.FileSize() == 0)
0ec6b98b 77 return _error->Error(_("Empty files can't be valid archives"));
0ec6b98b
DK
78 }
79 else
9bd2313a 80 From.Open(Path, FileFd::ReadOnly, FileFd::Extension);
af9e40c9
DK
81 if (From.IsOpen() == false || From.Failed() == true)
82 return false;
83
84 FileFd To;
9bd2313a 85 if (Itm->DestFile != "/dev/null" && Itm->DestFile != Path)
af9e40c9
DK
86 {
87 if (_config->FindB("Method::Compress", false) == false)
9bd2313a
DK
88 To.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Atomic, FileFd::Extension);
89 else if (OpenFileWithCompressorByName(To, Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty, Prog) == false)
90 return false;
af9e40c9
DK
91
92 if (To.IsOpen() == false || To.Failed() == true)
93 return false;
94 To.EraseOnFailure();
0ec6b98b 95 }
0ec6b98b 96
127e6df3 97 // Read data from source, generate checksums and write
9224ce3d 98 Hashes Hash(Itm->ExpectedHashes);
63b1700f 99 bool Failed = false;
af9e40c9 100 Res.Size = 0;
9bd2313a 101 while (1)
63b1700f
AL
102 {
103 unsigned char Buffer[4*1024];
650faab0 104 unsigned long long Count = 0;
9bd2313a 105
127e6df3 106 if (!From.Read(Buffer,sizeof(Buffer),&Count))
63b1700f 107 {
af9e40c9
DK
108 if (To.IsOpen())
109 To.OpFail();
127e6df3 110 return false;
63b1700f 111 }
63b1700f
AL
112 if (Count == 0)
113 break;
af9e40c9 114 Res.Size += Count;
127e6df3 115
63b1700f 116 Hash.Add(Buffer,Count);
af9e40c9 117 if (To.IsOpen() && To.Write(Buffer,Count) == false)
2204bd80 118 {
678bc33e
AL
119 Failed = true;
120 break;
9bd2313a 121 }
63b1700f 122 }
9bd2313a 123
127e6df3 124 From.Close();
246bbb61 125 To.Close();
9ce3cfc9 126
63b1700f
AL
127 if (Failed == true)
128 return false;
9ce3cfc9 129
93bf083d 130 // Transfer the modification times
af9e40c9
DK
131 if (Itm->DestFile != "/dev/null")
132 {
133 struct stat Buf;
134 if (stat(Path.c_str(),&Buf) != 0)
135 return _error->Errno("stat",_("Failed to stat"));
136
137 struct timeval times[2];
138 times[0].tv_sec = Buf.st_atime;
139 Res.LastModified = times[1].tv_sec = Buf.st_mtime;
140 times[0].tv_usec = times[1].tv_usec = 0;
141 if (utimes(Itm->DestFile.c_str(), times) != 0)
142 return _error->Errno("utimes",_("Failed to set modification time"));
143 }
9ce3cfc9 144
93bf083d 145 // Return a Done response
a7c835af 146 Res.TakeHashes(Hash);
63b1700f 147
93bf083d 148 URIDone(Res);
93bf083d
AL
149 return true;
150}
151 /*}}}*/
152
65512241 153int main(int, char *argv[])
93bf083d 154{
b25423f6
MZ
155 setlocale(LC_ALL, "");
156
9bd2313a 157 StoreMethod Mth(flNotDir(argv[0]));
93bf083d 158 return Mth.Run();
92173b19 159}