]>
Commit | Line | Data |
---|---|---|
453b82a3 DK |
1 | #include <config.h> |
2 | ||
488011fa MV |
3 | #include <apt-pkg/error.h> |
4 | #include <apt-pkg/fileutl.h> | |
f00832cc | 5 | #include <apt-pkg/strutl.h> |
f7feb041 | 6 | #include <apt-pkg/aptconfiguration.h> |
488011fa | 7 | |
488011fa MV |
8 | #include <string> |
9 | #include <vector> | |
488011fa | 10 | #include <stdlib.h> |
f7feb041 | 11 | #include <string.h> |
488011fa | 12 | |
f00832cc | 13 | #include <gtest/gtest.h> |
488011fa | 14 | |
f00832cc | 15 | #include "file-helpers.h" |
f7feb041 | 16 | |
f00832cc DK |
17 | static void TestFileFd(mode_t const a_umask, mode_t const ExpectedFilePermission, |
18 | unsigned int const filemode, APT::Configuration::Compressor const &compressor) | |
f22b65b4 | 19 | { |
f00832cc DK |
20 | std::string trace; |
21 | strprintf(trace, "TestFileFd: Compressor: %s umask: %#o permission: %#o mode: %d", compressor.Name.c_str(), a_umask, ExpectedFilePermission, filemode); | |
22 | SCOPED_TRACE(trace); | |
23 | ||
bb93178b DK |
24 | static const char* fname = "apt-filefd-test.txt"; |
25 | if (FileExists(fname) == true) | |
f00832cc | 26 | EXPECT_EQ(0, unlink(fname)); |
f22b65b4 | 27 | |
f00832cc | 28 | FileFd f; |
f22b65b4 | 29 | umask(a_umask); |
f00832cc DK |
30 | EXPECT_TRUE(f.Open(fname, filemode, compressor)); |
31 | EXPECT_TRUE(f.IsOpen()); | |
32 | EXPECT_FALSE(f.Failed()); | |
33 | EXPECT_EQ(umask(a_umask), a_umask); | |
f7feb041 | 34 | |
bb93178b | 35 | std::string test = "This is a test!\n"; |
f00832cc DK |
36 | EXPECT_TRUE(f.Write(test.c_str(), test.size())); |
37 | EXPECT_TRUE(f.IsOpen()); | |
38 | EXPECT_FALSE(f.Failed()); | |
f7feb041 | 39 | |
f22b65b4 | 40 | f.Close(); |
f00832cc DK |
41 | EXPECT_FALSE(f.IsOpen()); |
42 | EXPECT_FALSE(f.Failed()); | |
43 | ||
44 | EXPECT_TRUE(f.Open(fname, FileFd::ReadOnly, compressor)); | |
45 | EXPECT_TRUE(f.IsOpen()); | |
46 | EXPECT_FALSE(f.Failed()); | |
47 | EXPECT_FALSE(f.Eof()); | |
48 | EXPECT_NE(0, f.FileSize()); | |
49 | EXPECT_FALSE(f.Failed()); | |
50 | EXPECT_NE(0, f.ModificationTime()); | |
51 | EXPECT_FALSE(f.Failed()); | |
f7feb041 | 52 | |
bb93178b | 53 | // ensure the memory is as predictably messed up |
f00832cc | 54 | #define APT_INIT_READBACK \ |
bb93178b | 55 | char readback[20]; \ |
ad5ffe1f | 56 | memset(readback, 'D', sizeof(readback)*sizeof(readback[0])); \ |
bb93178b | 57 | readback[19] = '\0'; |
f00832cc DK |
58 | #define EXPECT_N_STR(expect, actual) \ |
59 | EXPECT_EQ(0, strncmp(expect, actual, strlen(expect))); | |
ad5ffe1f DK |
60 | { |
61 | APT_INIT_READBACK | |
62 | char const * const expect = "DDDDDDDDDDDDDDDDDDD"; | |
63 | EXPECT_STREQ(expect,readback); | |
64 | EXPECT_N_STR(expect, readback); | |
65 | } | |
f7feb041 | 66 | { |
bb93178b | 67 | APT_INIT_READBACK |
f7feb041 | 68 | char const * const expect = "This"; |
f00832cc DK |
69 | EXPECT_TRUE(f.Read(readback, strlen(expect))); |
70 | EXPECT_FALSE(f.Failed()); | |
71 | EXPECT_FALSE(f.Eof()); | |
72 | EXPECT_N_STR(expect, readback); | |
73 | EXPECT_EQ(strlen(expect), f.Tell()); | |
f7feb041 DK |
74 | } |
75 | { | |
bb93178b DK |
76 | APT_INIT_READBACK |
77 | char const * const expect = "test!\n"; | |
f00832cc DK |
78 | EXPECT_TRUE(f.Skip((test.size() - f.Tell()) - strlen(expect))); |
79 | EXPECT_TRUE(f.Read(readback, strlen(expect))); | |
80 | EXPECT_FALSE(f.Failed()); | |
81 | EXPECT_FALSE(f.Eof()); | |
82 | EXPECT_N_STR(expect, readback); | |
83 | EXPECT_EQ(test.size(), f.Tell()); | |
f7feb041 | 84 | } |
bb93178b DK |
85 | { |
86 | APT_INIT_READBACK | |
f00832cc DK |
87 | EXPECT_TRUE(f.Seek(0)); |
88 | EXPECT_FALSE(f.Eof()); | |
89 | EXPECT_TRUE(f.Read(readback, 20, true)); | |
90 | EXPECT_FALSE(f.Failed()); | |
91 | EXPECT_TRUE(f.Eof()); | |
92 | EXPECT_N_STR(test.c_str(), readback); | |
93 | EXPECT_EQ(f.Size(), f.Tell()); | |
bb93178b DK |
94 | } |
95 | { | |
96 | APT_INIT_READBACK | |
f00832cc DK |
97 | EXPECT_TRUE(f.Seek(0)); |
98 | EXPECT_FALSE(f.Eof()); | |
99 | EXPECT_TRUE(f.Read(readback, test.size(), true)); | |
100 | EXPECT_FALSE(f.Failed()); | |
101 | EXPECT_FALSE(f.Eof()); | |
102 | EXPECT_N_STR(test.c_str(), readback); | |
103 | EXPECT_EQ(f.Size(), f.Tell()); | |
bb93178b DK |
104 | } |
105 | { | |
106 | APT_INIT_READBACK | |
f00832cc DK |
107 | EXPECT_TRUE(f.Seek(0)); |
108 | EXPECT_FALSE(f.Eof()); | |
bb93178b | 109 | unsigned long long actual; |
f00832cc DK |
110 | EXPECT_TRUE(f.Read(readback, 20, &actual)); |
111 | EXPECT_FALSE(f.Failed()); | |
112 | EXPECT_TRUE(f.Eof()); | |
113 | EXPECT_EQ(test.size(), actual); | |
114 | EXPECT_N_STR(test.c_str(), readback); | |
115 | EXPECT_EQ(f.Size(), f.Tell()); | |
bb93178b DK |
116 | } |
117 | { | |
118 | APT_INIT_READBACK | |
f00832cc DK |
119 | EXPECT_TRUE(f.Seek(0)); |
120 | EXPECT_FALSE(f.Eof()); | |
bb93178b | 121 | f.ReadLine(readback, 20); |
f00832cc DK |
122 | EXPECT_FALSE(f.Failed()); |
123 | EXPECT_FALSE(f.Eof()); | |
124 | EXPECT_EQ(test, readback); | |
125 | EXPECT_EQ(f.Size(), f.Tell()); | |
bb93178b DK |
126 | } |
127 | { | |
128 | APT_INIT_READBACK | |
f00832cc DK |
129 | EXPECT_TRUE(f.Seek(0)); |
130 | EXPECT_FALSE(f.Eof()); | |
bb93178b DK |
131 | char const * const expect = "This"; |
132 | f.ReadLine(readback, strlen(expect) + 1); | |
f00832cc DK |
133 | EXPECT_FALSE(f.Failed()); |
134 | EXPECT_FALSE(f.Eof()); | |
135 | EXPECT_N_STR(expect, readback); | |
136 | EXPECT_EQ(strlen(expect), f.Tell()); | |
bb93178b DK |
137 | } |
138 | #undef APT_INIT_READBACK | |
f7feb041 DK |
139 | |
140 | f.Close(); | |
f00832cc DK |
141 | EXPECT_FALSE(f.IsOpen()); |
142 | EXPECT_FALSE(f.Failed()); | |
f7feb041 DK |
143 | |
144 | // regression test for permission bug LP: #1304657 | |
f00832cc DK |
145 | struct stat buf; |
146 | EXPECT_EQ(0, stat(fname, &buf)); | |
147 | EXPECT_EQ(0, unlink(fname)); | |
148 | EXPECT_EQ(ExpectedFilePermission, buf.st_mode & 0777); | |
f22b65b4 MV |
149 | } |
150 | ||
f00832cc | 151 | static void TestFileFd(unsigned int const filemode) |
488011fa | 152 | { |
bb93178b DK |
153 | std::vector<APT::Configuration::Compressor> compressors = APT::Configuration::getCompressors(); |
154 | ||
155 | // testing the (un)compress via pipe, as the 'real' compressors are usually built in via libraries | |
156 | compressors.push_back(APT::Configuration::Compressor("rev", ".reversed", "rev", NULL, NULL, 42)); | |
157 | //compressors.push_back(APT::Configuration::Compressor("cat", ".ident", "cat", NULL, NULL, 42)); | |
158 | ||
f7feb041 DK |
159 | for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin(); c != compressors.end(); ++c) |
160 | { | |
161 | if ((filemode & FileFd::ReadWrite) == FileFd::ReadWrite && | |
162 | (c->Name.empty() != true && c->Binary.empty() != true)) | |
163 | continue; | |
f00832cc DK |
164 | TestFileFd(0002, 0664, filemode, *c); |
165 | TestFileFd(0022, 0644, filemode, *c); | |
166 | TestFileFd(0077, 0600, filemode, *c); | |
167 | TestFileFd(0026, 0640, filemode, *c); | |
f7feb041 | 168 | } |
f7feb041 | 169 | } |
488011fa | 170 | |
f00832cc DK |
171 | TEST(FileUtlTest, FileFD) |
172 | { | |
173 | std::string const startdir = SafeGetCWD(); | |
174 | EXPECT_FALSE(startdir.empty()); | |
175 | std::string tempdir; | |
176 | createTemporaryDirectory("filefd", tempdir); | |
177 | EXPECT_EQ(0, chdir(tempdir.c_str())); | |
178 | ||
179 | TestFileFd(FileFd::WriteOnly | FileFd::Create); | |
180 | TestFileFd(FileFd::WriteOnly | FileFd::Create | FileFd::Empty); | |
181 | TestFileFd(FileFd::WriteOnly | FileFd::Create | FileFd::Exclusive); | |
182 | TestFileFd(FileFd::WriteOnly | FileFd::Atomic); | |
183 | TestFileFd(FileFd::WriteOnly | FileFd::Create | FileFd::Atomic); | |
184 | // short-hands for ReadWrite with these modes | |
185 | TestFileFd(FileFd::WriteEmpty); | |
186 | TestFileFd(FileFd::WriteAny); | |
187 | TestFileFd(FileFd::WriteTemp); | |
188 | TestFileFd(FileFd::WriteAtomic); | |
189 | ||
190 | EXPECT_EQ(0, chdir(startdir.c_str())); | |
191 | removeDirectory(tempdir); | |
192 | } | |
193 | TEST(FileUtlTest, Glob) | |
f7feb041 | 194 | { |
f7feb041 | 195 | std::vector<std::string> files; |
488011fa | 196 | // normal match |
f00832cc DK |
197 | files = Glob("*akefile"); |
198 | EXPECT_EQ(1, files.size()); | |
488011fa MV |
199 | |
200 | // not there | |
201 | files = Glob("xxxyyyzzz"); | |
f00832cc DK |
202 | EXPECT_TRUE(files.empty()); |
203 | EXPECT_FALSE(_error->PendingError()); | |
488011fa MV |
204 | |
205 | // many matches (number is a bit random) | |
206 | files = Glob("*.cc"); | |
f00832cc DK |
207 | EXPECT_LT(10, files.size()); |
208 | } | |
209 | TEST(FileUtlTest, GetTempDir) | |
210 | { | |
211 | char const * const envtmp = getenv("TMPDIR"); | |
212 | std::string old_tmpdir; | |
213 | if (envtmp != NULL) | |
214 | old_tmpdir = envtmp; | |
488011fa | 215 | |
a077861a | 216 | unsetenv("TMPDIR"); |
f00832cc | 217 | EXPECT_EQ("/tmp", GetTempDir()); |
a077861a MV |
218 | |
219 | setenv("TMPDIR", "", 1); | |
f00832cc | 220 | EXPECT_EQ("/tmp", GetTempDir()); |
a077861a MV |
221 | |
222 | setenv("TMPDIR", "/not-there-no-really-not", 1); | |
f00832cc | 223 | EXPECT_EQ("/tmp", GetTempDir()); |
a077861a | 224 | |
0d303f17 | 225 | // here but not accessible for non-roots |
a077861a | 226 | setenv("TMPDIR", "/usr", 1); |
0d303f17 DK |
227 | EXPECT_EQ("/tmp", GetTempDir()); |
228 | ||
229 | // files are no good for tmpdirs, too | |
230 | setenv("TMPDIR", "/dev/null", 1); | |
231 | EXPECT_EQ("/tmp", GetTempDir()); | |
232 | ||
233 | setenv("TMPDIR", "/var/tmp", 1); | |
234 | EXPECT_EQ("/var/tmp", GetTempDir()); | |
a077861a | 235 | |
f00832cc DK |
236 | unsetenv("TMPDIR"); |
237 | if (old_tmpdir.empty() == false) | |
238 | setenv("TMPDIR", old_tmpdir.c_str(), 1); | |
488011fa | 239 | } |
7ad2a347 MV |
240 | TEST(FileUtlTest, Popen) |
241 | { | |
242 | FileFd Fd; | |
243 | pid_t Child; | |
244 | char buf[1024]; | |
245 | std::string s; | |
246 | unsigned long long n = 0; | |
247 | std::vector<std::string> OpenFds; | |
248 | ||
249 | // count Fds to ensure we don't have a resource leak | |
250 | if(FileExists("/proc/self/fd")) | |
251 | OpenFds = Glob("/proc/self/fd/*"); | |
252 | ||
253 | // output something | |
254 | const char* Args[10] = {"/bin/echo", "meepmeep", NULL}; | |
23fb7b2c DK |
255 | EXPECT_TRUE(Popen(Args, Fd, Child, FileFd::ReadOnly)); |
256 | EXPECT_TRUE(Fd.Read(buf, sizeof(buf)-1, &n)); | |
7ad2a347 MV |
257 | buf[n] = 0; |
258 | EXPECT_NE(n, 0); | |
7ad2a347 MV |
259 | EXPECT_STREQ(buf, "meepmeep\n"); |
260 | ||
261 | // wait for the child to exit and cleanup | |
23fb7b2c DK |
262 | EXPECT_TRUE(ExecWait(Child, "PopenRead")); |
263 | EXPECT_TRUE(Fd.Close()); | |
7ad2a347 MV |
264 | |
265 | // ensure that after a close all is good again | |
266 | if(FileExists("/proc/self/fd")) | |
267 | EXPECT_EQ(Glob("/proc/self/fd/*").size(), OpenFds.size()); | |
268 | ||
7ad2a347 | 269 | // ReadWrite is not supported |
23fb7b2c DK |
270 | _error->PushToStack(); |
271 | EXPECT_FALSE(Popen(Args, Fd, Child, FileFd::ReadWrite)); | |
272 | EXPECT_FALSE(Fd.IsOpen()); | |
273 | EXPECT_FALSE(Fd.Failed()); | |
274 | EXPECT_TRUE(_error->PendingError()); | |
275 | _error->RevertToStack(); | |
7ad2a347 MV |
276 | |
277 | // write something | |
278 | Args[0] = "/bin/bash"; | |
279 | Args[1] = "-c"; | |
280 | Args[2] = "read"; | |
281 | Args[3] = NULL; | |
23fb7b2c | 282 | EXPECT_TRUE(Popen(Args, Fd, Child, FileFd::WriteOnly)); |
7ad2a347 | 283 | s = "\n"; |
23fb7b2c DK |
284 | EXPECT_TRUE(Fd.Write(s.c_str(), s.length())); |
285 | EXPECT_TRUE(Fd.Close()); | |
286 | EXPECT_FALSE(Fd.IsOpen()); | |
287 | EXPECT_FALSE(Fd.Failed()); | |
288 | EXPECT_TRUE(ExecWait(Child, "PopenWrite")); | |
7ad2a347 | 289 | } |
53ac87ac MV |
290 | TEST(FileUtlTest, flAbsPath) |
291 | { | |
a111a024 | 292 | std::string cwd = SafeGetCWD(); |
20cf708a | 293 | int res = chdir("/etc/"); |
53ac87ac | 294 | EXPECT_EQ(res, 0); |
20cf708a JAK |
295 | std::string p = flAbsPath("passwd"); |
296 | EXPECT_EQ(p, "/etc/passwd"); | |
a111a024 MV |
297 | |
298 | res = chdir(cwd.c_str()); | |
299 | EXPECT_EQ(res, 0); | |
53ac87ac | 300 | } |
cd46d4eb DK |
301 | |
302 | static void TestDevNullFileFd(unsigned int const filemode) | |
303 | { | |
304 | FileFd f("/dev/null", filemode); | |
305 | EXPECT_FALSE(f.Failed()); | |
306 | EXPECT_TRUE(f.IsOpen()); | |
307 | EXPECT_TRUE(f.IsOpen()); | |
308 | ||
309 | std::string test = "This is a test!\n"; | |
310 | EXPECT_TRUE(f.Write(test.c_str(), test.size())); | |
311 | EXPECT_TRUE(f.IsOpen()); | |
312 | EXPECT_FALSE(f.Failed()); | |
313 | ||
314 | f.Close(); | |
315 | EXPECT_FALSE(f.IsOpen()); | |
316 | EXPECT_FALSE(f.Failed()); | |
317 | } | |
318 | TEST(FileUtlTest, WorkingWithDevNull) | |
319 | { | |
320 | TestDevNullFileFd(FileFd::WriteOnly | FileFd::Create); | |
321 | TestDevNullFileFd(FileFd::WriteOnly | FileFd::Create | FileFd::Empty); | |
322 | TestDevNullFileFd(FileFd::WriteOnly | FileFd::Create | FileFd::Exclusive); | |
323 | TestDevNullFileFd(FileFd::WriteOnly | FileFd::Atomic); | |
324 | TestDevNullFileFd(FileFd::WriteOnly | FileFd::Create | FileFd::Atomic); | |
325 | // short-hands for ReadWrite with these modes | |
326 | TestDevNullFileFd(FileFd::WriteEmpty); | |
327 | TestDevNullFileFd(FileFd::WriteAny); | |
328 | TestDevNullFileFd(FileFd::WriteTemp); | |
329 | TestDevNullFileFd(FileFd::WriteAtomic); | |
330 | } |