]> git.saurik.com Git - apt.git/blob - methods/store.cc
implement Fallback-Of for IndexTargets
[apt.git] / methods / store.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4
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
11 ##################################################################### */
12 /*}}}*/
13 // Include Files /*{{{*/
14 #include <config.h>
15
16 #include <apt-pkg/configuration.h>
17 #include <apt-pkg/acquire-method.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/fileutl.h>
20 #include <apt-pkg/hashes.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/aptconfiguration.h>
23 #include "aptmethod.h"
24
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28 #include <string>
29 #include <vector>
30
31 #include <apti18n.h>
32 /*}}}*/
33
34 class StoreMethod : public aptMethod
35 {
36 std::string const Prog;
37 virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
38
39 public:
40
41 explicit StoreMethod(std::string const &pProg) : aptMethod(pProg.c_str(),"1.2",SingleInstance | SendConfig), Prog(pProg) {};
42 };
43
44 static bool OpenFileWithCompressorByName(FileFd &fileFd, std::string const &Filename, unsigned int const Mode, std::string const &Name)
45 {
46 if (Name == "store")
47 return fileFd.Open(Filename, Mode, FileFd::Extension);
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)
52 if (compressor->Name == Name)
53 break;
54 if (compressor == compressors.end())
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 /*}}}*/
61 bool 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);
69
70 // Open the source and destination files
71 FileFd From;
72 if (_config->FindB("Method::Compress", false) == false)
73 {
74 if (OpenFileWithCompressorByName(From, Path, FileFd::ReadOnly, Prog) == false)
75 return false;
76 if(From.IsCompressed() && From.FileSize() == 0)
77 return _error->Error(_("Empty files can't be valid archives"));
78 }
79 else
80 From.Open(Path, FileFd::ReadOnly, FileFd::Extension);
81 if (From.IsOpen() == false || From.Failed() == true)
82 return false;
83
84 FileFd To;
85 if (Itm->DestFile != "/dev/null" && Itm->DestFile != Path)
86 {
87 if (_config->FindB("Method::Compress", false) == false)
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;
91
92 if (To.IsOpen() == false || To.Failed() == true)
93 return false;
94 To.EraseOnFailure();
95 }
96
97 // Read data from source, generate checksums and write
98 Hashes Hash(Itm->ExpectedHashes);
99 bool Failed = false;
100 Res.Size = 0;
101 while (1)
102 {
103 unsigned char Buffer[4*1024];
104 unsigned long long Count = 0;
105
106 if (!From.Read(Buffer,sizeof(Buffer),&Count))
107 {
108 if (To.IsOpen())
109 To.OpFail();
110 return false;
111 }
112 if (Count == 0)
113 break;
114 Res.Size += Count;
115
116 Hash.Add(Buffer,Count);
117 if (To.IsOpen() && To.Write(Buffer,Count) == false)
118 {
119 Failed = true;
120 break;
121 }
122 }
123
124 From.Close();
125 To.Close();
126
127 if (Failed == true)
128 return false;
129
130 // Transfer the modification times
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 }
144
145 // Return a Done response
146 Res.TakeHashes(Hash);
147
148 URIDone(Res);
149 return true;
150 }
151 /*}}}*/
152
153 int main(int, char *argv[])
154 {
155 setlocale(LC_ALL, "");
156
157 StoreMethod Mth(flNotDir(argv[0]));
158 return Mth.Run();
159 }