blob: 99a4abcb6e4bc2f7681cbe1834923f138cc4a827 [file] [log] [blame]
Joe Onorato8d626d62009-05-15 09:07:06 -04001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joe Onorato0c4863b2009-05-05 11:50:51 -070017#define LOG_TAG "file_backup_helper"
18
Mathias Agopianf446ba92009-06-04 13:53:57 -070019#include <utils/BackupHelpers.h>
Joe Onorato0c4863b2009-05-05 11:50:51 -070020
21#include <utils/KeyedVector.h>
22#include <utils/ByteOrder.h>
23#include <utils/String8.h>
24
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/uio.h>
28#include <sys/stat.h>
Nicolas Cataniab4c42652009-05-22 13:41:38 -070029#include <sys/time.h> // for utimes
Joe Onorato0c4863b2009-05-05 11:50:51 -070030#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
Joe Onorato2a98fb92009-05-06 12:55:46 -040033#include <utime.h>
Joe Onorato0c4863b2009-05-05 11:50:51 -070034#include <fcntl.h>
35#include <zlib.h>
36
37#include <cutils/log.h>
38
Joe Onorato8d626d62009-05-15 09:07:06 -040039namespace android {
Joe Onorato0c4863b2009-05-05 11:50:51 -070040
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
Christopher Tate5c2882b2009-06-23 17:35:11 -070044/*
45 * File entity data format (v1):
46 *
47 * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
48 * - 12 bytes of metadata
49 * - the file data itself
50 *
51 * i.e. a 16-byte metadata header followed by the raw file data. If the
52 * restore code does not recognize the metadata version, it can still
53 * interpret the file data itself correctly.
54 *
55 * file_metadata_v1:
56 *
57 * - 4 byte version number === 0x00000001 (little endian)
58 * - 4-byte access mode (little-endian)
59 * - undefined (8 bytes)
60 */
61
62struct file_metadata_v1 {
63 int version;
64 int mode;
65 int undefined_1;
66 int undefined_2;
67};
68
69const static int CURRENT_METADATA_VERSION = 1;
70
Christopher Tate6441a762009-06-24 11:20:51 -070071#if 1 // TEST_BACKUP_HELPERS
Joe Onorato0ad61202009-06-10 17:07:15 -070072#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato8d626d62009-05-15 09:07:06 -040073#else
Joe Onoratoc7bbc692009-05-13 18:57:29 -040074#define LOGP(x...) LOGD(x)
Joe Onorato8d626d62009-05-15 09:07:06 -040075#endif
Joe Onoratoc7bbc692009-05-13 18:57:29 -040076
Joe Onorato0c4863b2009-05-05 11:50:51 -070077const static int ROUND_UP[4] = { 0, 3, 2, 1 };
78
79static inline int
80round_up(int n)
81{
82 return n + ROUND_UP[n % 4];
83}
84
85static int
86read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
87{
88 int bytesRead = 0;
89 int amt;
90 SnapshotHeader header;
91
92 amt = read(fd, &header, sizeof(header));
93 if (amt != sizeof(header)) {
94 return errno;
95 }
96 bytesRead += amt;
97
98 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
99 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
100 return 1;
101 }
102
103 for (int i=0; i<header.fileCount; i++) {
104 FileState file;
105 char filenameBuf[128];
106
Joe Onorato0ad61202009-06-10 17:07:15 -0700107 amt = read(fd, &file, sizeof(FileState));
108 if (amt != sizeof(FileState)) {
Joe Onorato0c4863b2009-05-05 11:50:51 -0700109 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
110 return 1;
111 }
112 bytesRead += amt;
113
114 // filename is not NULL terminated, but it is padded
115 int nameBufSize = round_up(file.nameLen);
116 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
117 ? filenameBuf
118 : (char*)malloc(nameBufSize);
119 amt = read(fd, filename, nameBufSize);
120 if (amt == nameBufSize) {
121 snapshot->add(String8(filename, file.nameLen), file);
122 }
123 bytesRead += amt;
124 if (filename != filenameBuf) {
125 free(filename);
126 }
127 if (amt != nameBufSize) {
128 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
129 return 1;
130 }
131 }
132
133 if (header.totalSize != bytesRead) {
134 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
135 header.totalSize, bytesRead);
136 return 1;
137 }
138
139 return 0;
140}
141
142static int
Joe Onorato0ad61202009-06-10 17:07:15 -0700143write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700144{
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700145 int fileCount = 0;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700146 int bytesWritten = sizeof(SnapshotHeader);
147 // preflight size
148 const int N = snapshot.size();
149 for (int i=0; i<N; i++) {
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700150 const FileRec& g = snapshot.valueAt(i);
151 if (!g.deleted) {
152 const String8& name = snapshot.keyAt(i);
153 bytesWritten += sizeof(FileState) + round_up(name.length());
154 fileCount++;
155 }
Joe Onorato0c4863b2009-05-05 11:50:51 -0700156 }
157
Joe Onorato8d626d62009-05-15 09:07:06 -0400158 LOGP("write_snapshot_file fd=%d\n", fd);
159
Joe Onorato0c4863b2009-05-05 11:50:51 -0700160 int amt;
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700161 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato0c4863b2009-05-05 11:50:51 -0700162
163 amt = write(fd, &header, sizeof(header));
164 if (amt != sizeof(header)) {
165 LOGW("write_snapshot_file error writing header %s", strerror(errno));
166 return errno;
167 }
168
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700169 for (int i=0; i<N; i++) {
Joe Onorato0ad61202009-06-10 17:07:15 -0700170 FileRec r = snapshot.valueAt(i);
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700171 if (!r.deleted) {
172 const String8& name = snapshot.keyAt(i);
173 int nameLen = r.s.nameLen = name.length();
Joe Onorato0c4863b2009-05-05 11:50:51 -0700174
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700175 amt = write(fd, &r.s, sizeof(FileState));
176 if (amt != sizeof(FileState)) {
177 LOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato0c4863b2009-05-05 11:50:51 -0700178 return 1;
179 }
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700180
181 // filename is not NULL terminated, but it is padded
182 amt = write(fd, name.string(), nameLen);
183 if (amt != nameLen) {
184 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
185 return 1;
186 }
187 int paddingLen = ROUND_UP[nameLen % 4];
188 if (paddingLen != 0) {
189 int padding = 0xabababab;
190 amt = write(fd, &padding, paddingLen);
191 if (amt != paddingLen) {
192 LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
193 paddingLen, strerror(errno));
194 return 1;
195 }
196 }
Joe Onorato0c4863b2009-05-05 11:50:51 -0700197 }
198 }
199
200 return 0;
201}
202
203static int
Joe Onorato473b6e22009-05-19 13:41:21 -0700204write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700205{
Joe Onoratoc7bbc692009-05-13 18:57:29 -0400206 LOGP("write_delete_file %s\n", key.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700207 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700208}
209
210static int
Christopher Tate5c2882b2009-06-23 17:35:11 -0700211write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato0ad61202009-06-10 17:07:15 -0700212 char const* realFilename)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700213{
Christopher Tate5c2882b2009-06-23 17:35:11 -0700214 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onorato473b6e22009-05-19 13:41:21 -0700215
216 const int bufsize = 4*1024;
217 int err;
218 int amt;
219 int fileSize;
220 int bytesLeft;
Christopher Tate5c2882b2009-06-23 17:35:11 -0700221 file_metadata_v1 metadata;
Joe Onorato473b6e22009-05-19 13:41:21 -0700222
223 char* buf = (char*)malloc(bufsize);
224 int crc = crc32(0L, Z_NULL, 0);
225
226
Christopher Tate5c2882b2009-06-23 17:35:11 -0700227 fileSize = lseek(fd, 0, SEEK_END);
Joe Onorato473b6e22009-05-19 13:41:21 -0700228 lseek(fd, 0, SEEK_SET);
229
Christopher Tate5c2882b2009-06-23 17:35:11 -0700230 if (sizeof(metadata) != 16) {
231 LOGE("ERROR: metadata block is the wrong size!");
232 }
233
234 bytesLeft = fileSize + sizeof(metadata);
Joe Onorato473b6e22009-05-19 13:41:21 -0700235 err = dataStream->WriteEntityHeader(key, bytesLeft);
236 if (err != 0) {
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700237 free(buf);
Joe Onorato473b6e22009-05-19 13:41:21 -0700238 return err;
239 }
240
Christopher Tate5c2882b2009-06-23 17:35:11 -0700241 // store the file metadata first
242 metadata.version = tolel(CURRENT_METADATA_VERSION);
243 metadata.mode = tolel(mode);
244 metadata.undefined_1 = metadata.undefined_2 = 0;
245 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
246 if (err != 0) {
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700247 free(buf);
Christopher Tate5c2882b2009-06-23 17:35:11 -0700248 return err;
249 }
250 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
251
252 // now store the file content
Joe Onorato473b6e22009-05-19 13:41:21 -0700253 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
254 bytesLeft -= amt;
255 if (bytesLeft < 0) {
256 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
257 }
258 err = dataStream->WriteEntityData(buf, amt);
259 if (err != 0) {
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700260 free(buf);
Joe Onorato473b6e22009-05-19 13:41:21 -0700261 return err;
262 }
263 }
264 if (bytesLeft != 0) {
265 if (bytesLeft > 0) {
266 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
267 // even though the data we're sending is probably bad.
268 memset(buf, 0, bufsize);
269 while (bytesLeft > 0) {
270 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
271 bytesLeft -= amt;
272 err = dataStream->WriteEntityData(buf, amt);
273 if (err != 0) {
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700274 free(buf);
Joe Onorato473b6e22009-05-19 13:41:21 -0700275 return err;
276 }
277 }
278 }
279 LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato0ad61202009-06-10 17:07:15 -0700280 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onorato473b6e22009-05-19 13:41:21 -0700281 }
282
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700283 free(buf);
Joe Onorato473b6e22009-05-19 13:41:21 -0700284 return NO_ERROR;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700285}
286
287static int
Joe Onorato0ad61202009-06-10 17:07:15 -0700288write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onorato473b6e22009-05-19 13:41:21 -0700289{
290 int err;
Christopher Tate5c2882b2009-06-23 17:35:11 -0700291 struct stat st;
292
293 err = stat(realFilename, &st);
294 if (err < 0) {
295 return errno;
296 }
297
Joe Onorato0ad61202009-06-10 17:07:15 -0700298 int fd = open(realFilename, O_RDONLY);
Joe Onorato473b6e22009-05-19 13:41:21 -0700299 if (fd == -1) {
300 return errno;
301 }
Christopher Tate5c2882b2009-06-23 17:35:11 -0700302
303 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onorato473b6e22009-05-19 13:41:21 -0700304 close(fd);
305 return err;
306}
307
308static int
309compute_crc32(int fd)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700310{
311 const int bufsize = 4*1024;
312 int amt;
313
Joe Onorato0c4863b2009-05-05 11:50:51 -0700314 char* buf = (char*)malloc(bufsize);
315 int crc = crc32(0L, Z_NULL, 0);
316
Joe Onorato473b6e22009-05-19 13:41:21 -0700317 lseek(fd, 0, SEEK_SET);
318
Joe Onorato0c4863b2009-05-05 11:50:51 -0700319 while ((amt = read(fd, buf, bufsize)) != 0) {
320 crc = crc32(crc, (Bytef*)buf, amt);
321 }
322
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700323 free(buf);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700324 return crc;
325}
326
327int
Joe Onorato473b6e22009-05-19 13:41:21 -0700328back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato0ad61202009-06-10 17:07:15 -0700329 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700330{
331 int err;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700332 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato0ad61202009-06-10 17:07:15 -0700333 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700334
335 if (oldSnapshotFD != -1) {
336 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
337 if (err != 0) {
338 // On an error, treat this as a full backup.
339 oldSnapshot.clear();
340 }
341 }
342
343 for (int i=0; i<fileCount; i++) {
Joe Onorato0ad61202009-06-10 17:07:15 -0700344 String8 key(keys[i]);
345 FileRec r;
Joe Onoratoda1430b2009-06-18 13:11:18 -0700346 char const* file = files[i];
347 r.file = file;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700348 struct stat st;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700349
Joe Onorato0ad61202009-06-10 17:07:15 -0700350 err = stat(file, &st);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700351 if (err != 0) {
Joe Onorato0ad61202009-06-10 17:07:15 -0700352 LOGW("Error stating file %s", file);
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700353 r.deleted = true;
354 } else {
355 r.deleted = false;
356 r.s.modTime_sec = st.st_mtime;
357 r.s.modTime_nsec = 0; // workaround sim breakage
358 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700359 r.s.mode = st.st_mode;
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700360 r.s.size = st.st_size;
361 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato0c4863b2009-05-05 11:50:51 -0700362
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700363 if (newSnapshot.indexOfKey(key) >= 0) {
364 LOGP("back_up_files key already in use '%s'", key.string());
365 return -1;
366 }
Joe Onorato0ad61202009-06-10 17:07:15 -0700367 }
368 newSnapshot.add(key, r);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700369 }
370
371 int n = 0;
372 int N = oldSnapshot.size();
373 int m = 0;
374
375 while (n<N && m<fileCount) {
376 const String8& p = oldSnapshot.keyAt(n);
377 const String8& q = newSnapshot.keyAt(m);
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700378 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700379 int cmp = p.compare(q);
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700380 if (g.deleted || cmp < 0) {
381 // file removed
382 LOGP("file removed: %s", p.string());
383 g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
384 dataStream->WriteEntityHeader(p, -1);
385 n++;
386 }
387 else if (cmp > 0) {
Joe Onorato0c4863b2009-05-05 11:50:51 -0700388 // file added
Joe Onoratoda1430b2009-06-18 13:11:18 -0700389 LOGP("file added: %s", g.file.string());
390 write_update_file(dataStream, q, g.file.string());
Joe Onorato0c4863b2009-05-05 11:50:51 -0700391 m++;
392 }
Joe Onorato0c4863b2009-05-05 11:50:51 -0700393 else {
394 // both files exist, check them
Joe Onorato0c4863b2009-05-05 11:50:51 -0700395 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700396
Joe Onoratoda1430b2009-06-18 13:11:18 -0700397 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate173e38d2009-06-04 17:01:06 -0700398 if (fd < 0) {
Joe Onorato473b6e22009-05-19 13:41:21 -0700399 // We can't open the file. Don't report it as a delete either. Let the
400 // server keep the old version. Maybe they'll be able to deal with it
401 // on restore.
Joe Onoratoda1430b2009-06-18 13:11:18 -0700402 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700403 } else {
Joe Onorato0ad61202009-06-10 17:07:15 -0700404 g.s.crc32 = compute_crc32(fd);
Joe Onorato473b6e22009-05-19 13:41:21 -0700405
Joe Onorato0ad61202009-06-10 17:07:15 -0700406 LOGP("%s", q.string());
Christopher Tateab2e9e82009-06-23 13:03:00 -0700407 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
408 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
409 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
410 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
Joe Onorato0ad61202009-06-10 17:07:15 -0700411 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tateab2e9e82009-06-23 13:03:00 -0700412 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tate5c2882b2009-06-23 17:35:11 -0700413 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700414 }
415
416 close(fd);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700417 }
418 n++;
419 m++;
420 }
421 }
422
423 // these were deleted
424 while (n<N) {
Joe Onorato473b6e22009-05-19 13:41:21 -0700425 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700426 n++;
427 }
428
429 // these were added
430 while (m<fileCount) {
431 const String8& q = newSnapshot.keyAt(m);
Joe Onorato0ad61202009-06-10 17:07:15 -0700432 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratoda1430b2009-06-18 13:11:18 -0700433 write_update_file(dataStream, q, g.file.string());
Joe Onorato0c4863b2009-05-05 11:50:51 -0700434 m++;
435 }
436
437 err = write_snapshot_file(newSnapshotFD, newSnapshot);
438
439 return 0;
440}
441
Joe Onoratoda1430b2009-06-18 13:11:18 -0700442#define RESTORE_BUF_SIZE (8*1024)
443
444RestoreHelperBase::RestoreHelperBase()
445{
446 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700447 m_loggedUnknownMetadata = false;
Joe Onoratoda1430b2009-06-18 13:11:18 -0700448}
449
450RestoreHelperBase::~RestoreHelperBase()
451{
452 free(m_buf);
453}
454
455status_t
456RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
457{
458 ssize_t err;
459 size_t dataSize;
460 String8 key;
461 int fd;
462 void* buf = m_buf;
463 ssize_t amt;
464 int mode;
465 int crc;
466 struct stat st;
467 FileRec r;
468
469 err = in->ReadEntityHeader(&key, &dataSize);
470 if (err != NO_ERROR) {
471 return err;
472 }
Joe Onorato6bda7fd2009-06-18 18:23:43 -0700473
Christopher Tate5c2882b2009-06-23 17:35:11 -0700474 // Get the metadata block off the head of the file entity and use that to
475 // set up the output file
476 file_metadata_v1 metadata;
477 amt = in->ReadEntityData(&metadata, sizeof(metadata));
478 if (amt != sizeof(metadata)) {
479 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
480 (long)amt, strerror(errno));
481 return EIO;
482 }
483 metadata.version = fromlel(metadata.version);
484 metadata.mode = fromlel(metadata.mode);
485 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700486 if (!m_loggedUnknownMetadata) {
487 m_loggedUnknownMetadata = true;
488 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
489 metadata.version, CURRENT_METADATA_VERSION);
490 }
Christopher Tate5c2882b2009-06-23 17:35:11 -0700491 }
492 mode = metadata.mode;
Joe Onoratoda1430b2009-06-18 13:11:18 -0700493
494 // Write the file and compute the crc
495 crc = crc32(0L, Z_NULL, 0);
Joe Onorato6bda7fd2009-06-18 18:23:43 -0700496 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
497 if (fd == -1) {
498 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratoda1430b2009-06-18 13:11:18 -0700499 return errno;
500 }
501
502 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
503 err = write(fd, buf, amt);
504 if (err != amt) {
505 close(fd);
Joe Onorato6bda7fd2009-06-18 18:23:43 -0700506 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratoda1430b2009-06-18 13:11:18 -0700507 return errno;
508 }
509 crc = crc32(crc, (Bytef*)buf, amt);
510 }
511
512 close(fd);
513
514 // Record for the snapshot
515 err = stat(filename.string(), &st);
516 if (err != 0) {
517 LOGW("Error stating file that we just created %s", filename.string());
518 return errno;
519 }
520
521 r.file = filename;
522 r.deleted = false;
523 r.s.modTime_sec = st.st_mtime;
524 r.s.modTime_nsec = 0; // workaround sim breakage
525 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700526 r.s.mode = st.st_mode;
Joe Onoratoda1430b2009-06-18 13:11:18 -0700527 r.s.size = st.st_size;
528 r.s.crc32 = crc;
529
530 m_files.add(key, r);
531
532 return NO_ERROR;
533}
534
535status_t
536RestoreHelperBase::WriteSnapshot(int fd)
537{
538 return write_snapshot_file(fd, m_files);;
539}
540
Joe Onorato0c4863b2009-05-05 11:50:51 -0700541#if TEST_BACKUP_HELPERS
542
543#define SCRATCH_DIR "/data/backup_helper_test/"
544
545static int
546write_text_file(const char* path, const char* data)
547{
548 int amt;
549 int fd;
550 int len;
551
552 fd = creat(path, 0666);
553 if (fd == -1) {
554 fprintf(stderr, "creat %s failed\n", path);
555 return errno;
556 }
557
558 len = strlen(data);
559 amt = write(fd, data, len);
560 if (amt != len) {
561 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
562 return errno;
563 }
564
565 close(fd);
566
567 return 0;
568}
569
570static int
571compare_file(const char* path, const unsigned char* data, int len)
572{
573 int fd;
574 int amt;
575
576 fd = open(path, O_RDONLY);
577 if (fd == -1) {
578 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
579 return errno;
580 }
581
582 unsigned char* contents = (unsigned char*)malloc(len);
583 if (contents == NULL) {
584 fprintf(stderr, "malloc(%d) failed\n", len);
585 return ENOMEM;
586 }
587
588 bool sizesMatch = true;
589 amt = lseek(fd, 0, SEEK_END);
590 if (amt != len) {
591 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
592 sizesMatch = false;
593 }
594 lseek(fd, 0, SEEK_SET);
595
596 int readLen = amt < len ? amt : len;
597 amt = read(fd, contents, readLen);
598 if (amt != readLen) {
599 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
600 }
601
602 bool contentsMatch = true;
603 for (int i=0; i<readLen; i++) {
604 if (data[i] != contents[i]) {
605 if (contentsMatch) {
606 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
607 contentsMatch = false;
608 }
609 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
610 }
611 }
612
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700613 free(contents);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700614 return contentsMatch && sizesMatch ? 0 : 1;
615}
616
617int
618backup_helper_test_empty()
619{
620 int err;
621 int fd;
Joe Onorato0ad61202009-06-10 17:07:15 -0700622 KeyedVector<String8,FileRec> snapshot;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700623 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
624
625 system("rm -r " SCRATCH_DIR);
626 mkdir(SCRATCH_DIR, 0777);
627
628 // write
629 fd = creat(filename, 0666);
630 if (fd == -1) {
631 fprintf(stderr, "error creating %s\n", filename);
632 return 1;
633 }
634
635 err = write_snapshot_file(fd, snapshot);
636
637 close(fd);
638
639 if (err != 0) {
640 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
641 return err;
642 }
643
644 static const unsigned char correct_data[] = {
645 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
646 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
647 };
648
649 err = compare_file(filename, correct_data, sizeof(correct_data));
650 if (err != 0) {
651 return err;
652 }
653
654 // read
655 fd = open(filename, O_RDONLY);
656 if (fd == -1) {
657 fprintf(stderr, "error opening for read %s\n", filename);
658 return 1;
659 }
660
661 KeyedVector<String8,FileState> readSnapshot;
662 err = read_snapshot_file(fd, &readSnapshot);
663 if (err != 0) {
664 fprintf(stderr, "read_snapshot_file failed %d\n", err);
665 return err;
666 }
667
668 if (readSnapshot.size() != 0) {
669 fprintf(stderr, "readSnapshot should be length 0\n");
670 return 1;
671 }
672
673 return 0;
674}
675
676int
677backup_helper_test_four()
678{
679 int err;
680 int fd;
Joe Onorato0ad61202009-06-10 17:07:15 -0700681 KeyedVector<String8,FileRec> snapshot;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700682 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
683
684 system("rm -r " SCRATCH_DIR);
685 mkdir(SCRATCH_DIR, 0777);
686
687 // write
688 fd = creat(filename, 0666);
689 if (fd == -1) {
690 fprintf(stderr, "error opening %s\n", filename);
691 return 1;
692 }
693
694 String8 filenames[4];
695 FileState states[4];
Joe Onorato0ad61202009-06-10 17:07:15 -0700696 FileRec r;
Joe Onorato1a9e19a2009-06-11 11:27:16 -0700697 r.deleted = false;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700698
699 states[0].modTime_sec = 0xfedcba98;
700 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700701 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato0c4863b2009-05-05 11:50:51 -0700702 states[0].size = 0xababbcbc;
703 states[0].crc32 = 0x12345678;
704 states[0].nameLen = -12;
Joe Onorato0ad61202009-06-10 17:07:15 -0700705 r.s = states[0];
Joe Onorato0c4863b2009-05-05 11:50:51 -0700706 filenames[0] = String8("bytes_of_padding");
Joe Onorato0ad61202009-06-10 17:07:15 -0700707 snapshot.add(filenames[0], r);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700708
709 states[1].modTime_sec = 0x93400031;
710 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700711 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato0c4863b2009-05-05 11:50:51 -0700712 states[1].size = 0x88557766;
713 states[1].crc32 = 0x22334422;
714 states[1].nameLen = -1;
Joe Onorato0ad61202009-06-10 17:07:15 -0700715 r.s = states[1];
Joe Onorato0c4863b2009-05-05 11:50:51 -0700716 filenames[1] = String8("bytes_of_padding3");
Joe Onorato0ad61202009-06-10 17:07:15 -0700717 snapshot.add(filenames[1], r);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700718
719 states[2].modTime_sec = 0x33221144;
720 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700721 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato0c4863b2009-05-05 11:50:51 -0700722 states[2].size = 0x11223344;
723 states[2].crc32 = 0x01122334;
724 states[2].nameLen = 0;
Joe Onorato0ad61202009-06-10 17:07:15 -0700725 r.s = states[2];
Joe Onorato0c4863b2009-05-05 11:50:51 -0700726 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato0ad61202009-06-10 17:07:15 -0700727 snapshot.add(filenames[2], r);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700728
729 states[3].modTime_sec = 0x33221144;
730 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700731 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato0c4863b2009-05-05 11:50:51 -0700732 states[3].size = 0x11223344;
733 states[3].crc32 = 0x01122334;
734 states[3].nameLen = 0;
Joe Onorato0ad61202009-06-10 17:07:15 -0700735 r.s = states[3];
Joe Onorato0c4863b2009-05-05 11:50:51 -0700736 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato0ad61202009-06-10 17:07:15 -0700737 snapshot.add(filenames[3], r);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700738
739 err = write_snapshot_file(fd, snapshot);
740
741 close(fd);
742
743 if (err != 0) {
744 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
745 return err;
746 }
747
748 static const unsigned char correct_data[] = {
749 // header
750 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tateab2e9e82009-06-23 13:03:00 -0700751 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato0c4863b2009-05-05 11:50:51 -0700752
753 // bytes_of_padding
754 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tateab2e9e82009-06-23 13:03:00 -0700755 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
756 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
757 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
758 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato0c4863b2009-05-05 11:50:51 -0700759
760 // bytes_of_padding3
761 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tateab2e9e82009-06-23 13:03:00 -0700762 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
763 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
764 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
765 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
766 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700767
Joe Onorato0c4863b2009-05-05 11:50:51 -0700768 // bytes of padding2
769 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tateab2e9e82009-06-23 13:03:00 -0700770 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
771 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
772 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
773 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
774 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700775
Joe Onorato0c4863b2009-05-05 11:50:51 -0700776 // bytes of padding3
777 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tateab2e9e82009-06-23 13:03:00 -0700778 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
779 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
780 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
781 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
782 0x5f, 0x5f, 0x31, 0xab
Joe Onorato0c4863b2009-05-05 11:50:51 -0700783 };
784
785 err = compare_file(filename, correct_data, sizeof(correct_data));
786 if (err != 0) {
787 return err;
788 }
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700789
Joe Onorato0c4863b2009-05-05 11:50:51 -0700790 // read
791 fd = open(filename, O_RDONLY);
792 if (fd == -1) {
793 fprintf(stderr, "error opening for read %s\n", filename);
794 return 1;
795 }
796
797
798 KeyedVector<String8,FileState> readSnapshot;
799 err = read_snapshot_file(fd, &readSnapshot);
800 if (err != 0) {
801 fprintf(stderr, "read_snapshot_file failed %d\n", err);
802 return err;
803 }
804
805 if (readSnapshot.size() != 4) {
806 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
807 return 1;
808 }
809
810 bool matched = true;
811 for (size_t i=0; i<readSnapshot.size(); i++) {
812 const String8& name = readSnapshot.keyAt(i);
813 const FileState state = readSnapshot.valueAt(i);
814
815 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tateab2e9e82009-06-23 13:03:00 -0700816 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato0c4863b2009-05-05 11:50:51 -0700817 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tateab2e9e82009-06-23 13:03:00 -0700818 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
819 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
820 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
821 states[i].crc32, name.length(), filenames[i].string(),
822 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
823 state.nameLen, name.string());
Joe Onorato0c4863b2009-05-05 11:50:51 -0700824 matched = false;
825 }
826 }
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700827
Joe Onorato0c4863b2009-05-05 11:50:51 -0700828 return matched ? 0 : 1;
829}
830
Joe Onorato8d626d62009-05-15 09:07:06 -0400831// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
832const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onoratod502f052009-05-15 18:20:19 -0400833 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
834 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
835 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
836 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato03aa8d72009-06-16 16:31:35 -0400837 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
838 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato8d626d62009-05-15 09:07:06 -0400839 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
840 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onoratod502f052009-05-15 18:20:19 -0400841 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato03aa8d72009-06-16 16:31:35 -0400842 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onoratod502f052009-05-15 18:20:19 -0400843 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
844 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato8d626d62009-05-15 09:07:06 -0400845 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onoratod502f052009-05-15 18:20:19 -0400846 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
847 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato03aa8d72009-06-16 16:31:35 -0400848 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato8d626d62009-05-15 09:07:06 -0400849 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
850 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
851 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato03aa8d72009-06-16 16:31:35 -0400852 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
853
Joe Onorato8d626d62009-05-15 09:07:06 -0400854};
855const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
856
857static int
858test_write_header_and_entity(BackupDataWriter& writer, const char* str)
859{
860 int err;
861 String8 text(str);
862
Joe Onorato8d626d62009-05-15 09:07:06 -0400863 err = writer.WriteEntityHeader(text, text.length()+1);
864 if (err != 0) {
865 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
866 return err;
867 }
868
869 err = writer.WriteEntityData(text.string(), text.length()+1);
870 if (err != 0) {
871 fprintf(stderr, "write failed for data '%s'\n", text.string());
872 return errno;
873 }
874
875 return err;
876}
877
878int
879backup_helper_test_data_writer()
880{
881 int err;
882 int fd;
883 const char* filename = SCRATCH_DIR "data_writer.data";
884
885 system("rm -r " SCRATCH_DIR);
886 mkdir(SCRATCH_DIR, 0777);
887 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700888
Joe Onorato8d626d62009-05-15 09:07:06 -0400889 fd = creat(filename, 0666);
890 if (fd == -1) {
891 fprintf(stderr, "error creating: %s\n", strerror(errno));
892 return errno;
893 }
894
895 BackupDataWriter writer(fd);
896
897 err = 0;
898 err |= test_write_header_and_entity(writer, "no_padding_");
899 err |= test_write_header_and_entity(writer, "padded_to__3");
900 err |= test_write_header_and_entity(writer, "padded_to_2__");
901 err |= test_write_header_and_entity(writer, "padded_to1");
902
Joe Onorato8d626d62009-05-15 09:07:06 -0400903 close(fd);
904
905 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
906 if (err != 0) {
907 return err;
908 }
909
910 return err;
911}
912
Joe Onoratod502f052009-05-15 18:20:19 -0400913int
914test_read_header_and_entity(BackupDataReader& reader, const char* str)
915{
916 int err;
917 int bufSize = strlen(str)+1;
918 char* buf = (char*)malloc(bufSize);
919 String8 string;
920 int cookie = 0x11111111;
921 size_t actualSize;
Joe Onorato03aa8d72009-06-16 16:31:35 -0400922 bool done;
923 int type;
Christopher Tateab2e9e82009-06-23 13:03:00 -0700924 ssize_t nRead;
Joe Onoratod502f052009-05-15 18:20:19 -0400925
926 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
927
Joe Onorato03aa8d72009-06-16 16:31:35 -0400928 err = reader.ReadNextHeader(&done, &type);
929 if (done) {
930 fprintf(stderr, "should not be done yet\n");
931 goto finished;
932 }
Joe Onoratod502f052009-05-15 18:20:19 -0400933 if (err != 0) {
934 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato03aa8d72009-06-16 16:31:35 -0400935 goto finished;
Joe Onoratod502f052009-05-15 18:20:19 -0400936 }
Joe Onorato03aa8d72009-06-16 16:31:35 -0400937 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onoratod502f052009-05-15 18:20:19 -0400938 err = EINVAL;
Joe Onorato03aa8d72009-06-16 16:31:35 -0400939 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onoratod502f052009-05-15 18:20:19 -0400940 }
941
942 err = reader.ReadEntityHeader(&string, &actualSize);
943 if (err != 0) {
944 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato03aa8d72009-06-16 16:31:35 -0400945 goto finished;
Joe Onoratod502f052009-05-15 18:20:19 -0400946 }
947 if (string != str) {
948 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
949 err = EINVAL;
Joe Onorato03aa8d72009-06-16 16:31:35 -0400950 goto finished;
Joe Onoratod502f052009-05-15 18:20:19 -0400951 }
952 if ((int)actualSize != bufSize) {
953 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
954 actualSize);
955 err = EINVAL;
Joe Onorato03aa8d72009-06-16 16:31:35 -0400956 goto finished;
Joe Onoratod502f052009-05-15 18:20:19 -0400957 }
958
Christopher Tateab2e9e82009-06-23 13:03:00 -0700959 nRead = reader.ReadEntityData(buf, bufSize);
960 if (nRead < 0) {
961 err = reader.Status();
Joe Onoratod502f052009-05-15 18:20:19 -0400962 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato03aa8d72009-06-16 16:31:35 -0400963 goto finished;
Joe Onoratod502f052009-05-15 18:20:19 -0400964 }
965
966 if (0 != memcmp(buf, str, bufSize)) {
967 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato03aa8d72009-06-16 16:31:35 -0400968 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
969 buf[0], buf[1], buf[2], buf[3]);
Joe Onoratod502f052009-05-15 18:20:19 -0400970 err = EINVAL;
Joe Onorato03aa8d72009-06-16 16:31:35 -0400971 goto finished;
Joe Onoratod502f052009-05-15 18:20:19 -0400972 }
973
974 // The next read will confirm whether it got the right amount of data.
975
Joe Onorato03aa8d72009-06-16 16:31:35 -0400976finished:
Joe Onoratod502f052009-05-15 18:20:19 -0400977 if (err != NO_ERROR) {
978 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
979 }
Christopher Tatebd95c1d2009-06-24 13:57:29 -0700980 free(buf);
Joe Onoratod502f052009-05-15 18:20:19 -0400981 return err;
982}
983
984int
985backup_helper_test_data_reader()
986{
987 int err;
988 int fd;
989 const char* filename = SCRATCH_DIR "data_reader.data";
990
991 system("rm -r " SCRATCH_DIR);
992 mkdir(SCRATCH_DIR, 0777);
993 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700994
Joe Onoratod502f052009-05-15 18:20:19 -0400995 fd = creat(filename, 0666);
996 if (fd == -1) {
997 fprintf(stderr, "error creating: %s\n", strerror(errno));
998 return errno;
999 }
1000
1001 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1002 if (err != DATA_GOLDEN_FILE_SIZE) {
1003 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1004 return errno;
1005 }
1006
1007 close(fd);
1008
1009 fd = open(filename, O_RDONLY);
1010 if (fd == -1) {
1011 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1012 filename);
1013 return errno;
1014 }
1015
1016 {
1017 BackupDataReader reader(fd);
1018
1019 err = 0;
1020
1021 if (err == NO_ERROR) {
1022 err = test_read_header_and_entity(reader, "no_padding_");
1023 }
1024
1025 if (err == NO_ERROR) {
1026 err = test_read_header_and_entity(reader, "padded_to__3");
1027 }
1028
1029 if (err == NO_ERROR) {
1030 err = test_read_header_and_entity(reader, "padded_to_2__");
1031 }
1032
1033 if (err == NO_ERROR) {
1034 err = test_read_header_and_entity(reader, "padded_to1");
1035 }
Joe Onoratod502f052009-05-15 18:20:19 -04001036 }
1037
1038 close(fd);
1039
1040 return err;
1041}
1042
Joe Onorato0c4863b2009-05-05 11:50:51 -07001043static int
1044get_mod_time(const char* filename, struct timeval times[2])
1045{
1046 int err;
1047 struct stat64 st;
1048 err = stat64(filename, &st);
1049 if (err != 0) {
1050 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1051 return errno;
1052 }
1053 times[0].tv_sec = st.st_atime;
Joe Onorato0c4863b2009-05-05 11:50:51 -07001054 times[1].tv_sec = st.st_mtime;
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001055
1056 // If st_atime is a macro then struct stat64 uses struct timespec
1057 // to store the access and modif time values and typically
1058 // st_*time_nsec is not defined. In glibc, this is controlled by
1059 // __USE_MISC.
1060#ifdef __USE_MISC
1061#if !defined(st_atime) || defined(st_atime_nsec)
1062#error "Check if this __USE_MISC conditional is still needed."
1063#endif
1064 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1065 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1066#else
1067 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato0c4863b2009-05-05 11:50:51 -07001068 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001069#endif
1070
Joe Onorato0c4863b2009-05-05 11:50:51 -07001071 return 0;
1072}
1073
1074int
1075backup_helper_test_files()
1076{
1077 int err;
Joe Onorato0c4863b2009-05-05 11:50:51 -07001078 int oldSnapshotFD;
Joe Onorato8d626d62009-05-15 09:07:06 -04001079 int dataStreamFD;
1080 int newSnapshotFD;
Joe Onorato0c4863b2009-05-05 11:50:51 -07001081
1082 system("rm -r " SCRATCH_DIR);
1083 mkdir(SCRATCH_DIR, 0777);
1084 mkdir(SCRATCH_DIR "data", 0777);
1085
1086 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1087 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1088 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1089 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1090 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1091 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1092
1093 char const* files_before[] = {
Joe Onorato0ad61202009-06-10 17:07:15 -07001094 SCRATCH_DIR "data/b",
1095 SCRATCH_DIR "data/c",
1096 SCRATCH_DIR "data/d",
1097 SCRATCH_DIR "data/e",
1098 SCRATCH_DIR "data/f"
1099 };
1100
1101 char const* keys_before[] = {
Joe Onorato0c4863b2009-05-05 11:50:51 -07001102 "data/b",
1103 "data/c",
1104 "data/d",
1105 "data/e",
1106 "data/f"
1107 };
1108
Joe Onorato8d626d62009-05-15 09:07:06 -04001109 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1110 if (dataStreamFD == -1) {
1111 fprintf(stderr, "error creating: %s\n", strerror(errno));
1112 return errno;
1113 }
1114
Joe Onorato0c4863b2009-05-05 11:50:51 -07001115 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1116 if (newSnapshotFD == -1) {
1117 fprintf(stderr, "error creating: %s\n", strerror(errno));
1118 return errno;
1119 }
Joe Onorato473b6e22009-05-19 13:41:21 -07001120
1121 {
1122 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001123
Joe Onorato0ad61202009-06-10 17:07:15 -07001124 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onorato473b6e22009-05-19 13:41:21 -07001125 if (err != 0) {
1126 return err;
1127 }
Joe Onorato0c4863b2009-05-05 11:50:51 -07001128 }
1129
Joe Onorato8d626d62009-05-15 09:07:06 -04001130 close(dataStreamFD);
Joe Onorato0c4863b2009-05-05 11:50:51 -07001131 close(newSnapshotFD);
1132
1133 sleep(3);
1134
1135 struct timeval d_times[2];
1136 struct timeval e_times[2];
1137
1138 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1139 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1140 if (err != 0) {
1141 return err;
1142 }
1143
1144 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1145 unlink(SCRATCH_DIR "data/c");
1146 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1147 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1148 utimes(SCRATCH_DIR "data/d", d_times);
1149 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1150 utimes(SCRATCH_DIR "data/e", e_times);
1151 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1152 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001153
Joe Onorato0c4863b2009-05-05 11:50:51 -07001154 char const* files_after[] = {
Joe Onorato0ad61202009-06-10 17:07:15 -07001155 SCRATCH_DIR "data/a", // added
1156 SCRATCH_DIR "data/b", // same
1157 SCRATCH_DIR "data/c", // different mod time
1158 SCRATCH_DIR "data/d", // different size (same mod time)
1159 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1160 SCRATCH_DIR "data/g" // added
1161 };
1162
1163 char const* keys_after[] = {
Joe Onorato0c4863b2009-05-05 11:50:51 -07001164 "data/a", // added
1165 "data/b", // same
1166 "data/c", // different mod time
1167 "data/d", // different size (same mod time)
1168 "data/e", // different contents (same mod time, same size)
1169 "data/g" // added
1170 };
1171
1172 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1173 if (oldSnapshotFD == -1) {
1174 fprintf(stderr, "error opening: %s\n", strerror(errno));
1175 return errno;
1176 }
1177
Joe Onorato8d626d62009-05-15 09:07:06 -04001178 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1179 if (dataStreamFD == -1) {
1180 fprintf(stderr, "error creating: %s\n", strerror(errno));
1181 return errno;
1182 }
1183
Joe Onorato0c4863b2009-05-05 11:50:51 -07001184 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1185 if (newSnapshotFD == -1) {
1186 fprintf(stderr, "error creating: %s\n", strerror(errno));
1187 return errno;
1188 }
1189
Joe Onorato473b6e22009-05-19 13:41:21 -07001190 {
1191 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001192
Joe Onorato0ad61202009-06-10 17:07:15 -07001193 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onorato473b6e22009-05-19 13:41:21 -07001194 if (err != 0) {
1195 return err;
1196 }
1197}
Joe Onorato0c4863b2009-05-05 11:50:51 -07001198
1199 close(oldSnapshotFD);
Joe Onorato8d626d62009-05-15 09:07:06 -04001200 close(dataStreamFD);
Joe Onorato0c4863b2009-05-05 11:50:51 -07001201 close(newSnapshotFD);
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001202
Joe Onorato0c4863b2009-05-05 11:50:51 -07001203 return 0;
1204}
1205
Joe Onorato0ad61202009-06-10 17:07:15 -07001206int
1207backup_helper_test_null_base()
1208{
1209 int err;
1210 int oldSnapshotFD;
1211 int dataStreamFD;
1212 int newSnapshotFD;
1213
1214 system("rm -r " SCRATCH_DIR);
1215 mkdir(SCRATCH_DIR, 0777);
1216 mkdir(SCRATCH_DIR "data", 0777);
1217
1218 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1219
1220 char const* files[] = {
1221 SCRATCH_DIR "data/a",
1222 };
1223
1224 char const* keys[] = {
1225 "a",
1226 };
1227
1228 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1229 if (dataStreamFD == -1) {
1230 fprintf(stderr, "error creating: %s\n", strerror(errno));
1231 return errno;
1232 }
1233
1234 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1235 if (newSnapshotFD == -1) {
1236 fprintf(stderr, "error creating: %s\n", strerror(errno));
1237 return errno;
1238 }
1239
1240 {
1241 BackupDataWriter dataStream(dataStreamFD);
1242
1243 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1244 if (err != 0) {
1245 return err;
1246 }
1247 }
1248
1249 close(dataStreamFD);
1250 close(newSnapshotFD);
1251
1252 return 0;
1253}
1254
Joe Onorato1a9e19a2009-06-11 11:27:16 -07001255int
1256backup_helper_test_missing_file()
1257{
1258 int err;
1259 int oldSnapshotFD;
1260 int dataStreamFD;
1261 int newSnapshotFD;
1262
1263 system("rm -r " SCRATCH_DIR);
1264 mkdir(SCRATCH_DIR, 0777);
1265 mkdir(SCRATCH_DIR "data", 0777);
1266
1267 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1268
1269 char const* files[] = {
1270 SCRATCH_DIR "data/a",
1271 SCRATCH_DIR "data/b",
1272 SCRATCH_DIR "data/c",
1273 };
1274
1275 char const* keys[] = {
1276 "a",
1277 "b",
1278 "c",
1279 };
1280
1281 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1282 if (dataStreamFD == -1) {
1283 fprintf(stderr, "error creating: %s\n", strerror(errno));
1284 return errno;
1285 }
1286
1287 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1288 if (newSnapshotFD == -1) {
1289 fprintf(stderr, "error creating: %s\n", strerror(errno));
1290 return errno;
1291 }
1292
1293 {
1294 BackupDataWriter dataStream(dataStreamFD);
1295
1296 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1297 if (err != 0) {
1298 return err;
1299 }
1300 }
1301
1302 close(dataStreamFD);
1303 close(newSnapshotFD);
1304
1305 return 0;
1306}
1307
Joe Onorato0ad61202009-06-10 17:07:15 -07001308
Joe Onorato0c4863b2009-05-05 11:50:51 -07001309#endif // TEST_BACKUP_HELPERS
Joe Onorato8d626d62009-05-15 09:07:06 -04001310
1311}