blob: 99a4abcb6e4bc2f7681cbe1834923f138cc4a827 [file] [log] [blame]
Joe Onorato4535e402009-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 Onorato3ad977b2009-05-05 11:50:51 -070017#define LOG_TAG "file_backup_helper"
18
Mathias Agopian8ae23352009-06-04 13:53:57 -070019#include <utils/BackupHelpers.h>
Joe Onorato3ad977b2009-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 Cataniaf4c46b92009-05-22 13:41:38 -070029#include <sys/time.h> // for utimes
Joe Onorato3ad977b2009-05-05 11:50:51 -070030#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
Joe Onoratoc825d3e2009-05-06 12:55:46 -040033#include <utime.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070034#include <fcntl.h>
35#include <zlib.h>
36
37#include <cutils/log.h>
38
Joe Onorato4535e402009-05-15 09:07:06 -040039namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070040
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
Christopher Tatefbb92382009-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 Tate54118ad2009-06-24 11:20:51 -070071#if 1 // TEST_BACKUP_HELPERS
Joe Onorato23ecae32009-06-10 17:07:15 -070072#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040073#else
Joe Onorato290bb012009-05-13 18:57:29 -040074#define LOGP(x...) LOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040075#endif
Joe Onorato290bb012009-05-13 18:57:29 -040076
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700107 amt = read(fd, &file, sizeof(FileState));
108 if (amt != sizeof(FileState)) {
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700143write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700144{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700145 int fileCount = 0;
Joe Onorato3ad977b2009-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 Onoratoce88cb12009-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 Onorato3ad977b2009-05-05 11:50:51 -0700156 }
157
Joe Onorato4535e402009-05-15 09:07:06 -0400158 LOGP("write_snapshot_file fd=%d\n", fd);
159
Joe Onorato3ad977b2009-05-05 11:50:51 -0700160 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700161 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-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 Onoratoce88cb12009-06-11 11:27:16 -0700169 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700170 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-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 Onorato3ad977b2009-05-05 11:50:51 -0700174
Joe Onoratoce88cb12009-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 Onorato3ad977b2009-05-05 11:50:51 -0700178 return 1;
179 }
Joe Onoratoce88cb12009-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 Onorato3ad977b2009-05-05 11:50:51 -0700197 }
198 }
199
200 return 0;
201}
202
203static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700204write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700205{
Joe Onorato290bb012009-05-13 18:57:29 -0400206 LOGP("write_delete_file %s\n", key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700207 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700208}
209
210static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700211write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700212 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700213{
Christopher Tatefbb92382009-06-23 17:35:11 -0700214 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-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 Tatefbb92382009-06-23 17:35:11 -0700221 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700222
223 char* buf = (char*)malloc(bufsize);
224 int crc = crc32(0L, Z_NULL, 0);
225
226
Christopher Tatefbb92382009-06-23 17:35:11 -0700227 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700228 lseek(fd, 0, SEEK_SET);
229
Christopher Tatefbb92382009-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 Onoratod2110db2009-05-19 13:41:21 -0700235 err = dataStream->WriteEntityHeader(key, bytesLeft);
236 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700237 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700238 return err;
239 }
240
Christopher Tatefbb92382009-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 Tate63bcb792009-06-24 13:57:29 -0700247 free(buf);
Christopher Tatefbb92382009-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 Onoratod2110db2009-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 Tate63bcb792009-06-24 13:57:29 -0700260 free(buf);
Joe Onoratod2110db2009-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 Tate63bcb792009-06-24 13:57:29 -0700274 free(buf);
Joe Onoratod2110db2009-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 Onorato23ecae32009-06-10 17:07:15 -0700280 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700281 }
282
Christopher Tate63bcb792009-06-24 13:57:29 -0700283 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700284 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700285}
286
287static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700288write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700289{
290 int err;
Christopher Tatefbb92382009-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 Onorato23ecae32009-06-10 17:07:15 -0700298 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700299 if (fd == -1) {
300 return errno;
301 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700302
303 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700304 close(fd);
305 return err;
306}
307
308static int
309compute_crc32(int fd)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700310{
311 const int bufsize = 4*1024;
312 int amt;
313
Joe Onorato3ad977b2009-05-05 11:50:51 -0700314 char* buf = (char*)malloc(bufsize);
315 int crc = crc32(0L, Z_NULL, 0);
316
Joe Onoratod2110db2009-05-19 13:41:21 -0700317 lseek(fd, 0, SEEK_SET);
318
Joe Onorato3ad977b2009-05-05 11:50:51 -0700319 while ((amt = read(fd, buf, bufsize)) != 0) {
320 crc = crc32(crc, (Bytef*)buf, amt);
321 }
322
Christopher Tate63bcb792009-06-24 13:57:29 -0700323 free(buf);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700324 return crc;
325}
326
327int
Joe Onoratod2110db2009-05-19 13:41:21 -0700328back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700329 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700330{
331 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700332 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700333 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700344 String8 key(keys[i]);
345 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700346 char const* file = files[i];
347 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700348 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700349
Joe Onorato23ecae32009-06-10 17:07:15 -0700350 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700351 if (err != 0) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700352 LOGW("Error stating file %s", file);
Joe Onoratoce88cb12009-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 Tate11b15772009-06-23 13:03:00 -0700359 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-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 Onorato3ad977b2009-05-05 11:50:51 -0700362
Joe Onoratoce88cb12009-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 Onorato23ecae32009-06-10 17:07:15 -0700367 }
368 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-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 Onoratoce88cb12009-06-11 11:27:16 -0700378 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700379 int cmp = p.compare(q);
Joe Onoratoce88cb12009-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 Onorato3ad977b2009-05-05 11:50:51 -0700388 // file added
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700389 LOGP("file added: %s", g.file.string());
390 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 m++;
392 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700393 else {
394 // both files exist, check them
Joe Onorato3ad977b2009-05-05 11:50:51 -0700395 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700396
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700397 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate0032ce82009-06-04 17:01:06 -0700398 if (fd < 0) {
Joe Onoratod2110db2009-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 Onoratod2d9ceb2009-06-18 13:11:18 -0700402 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700403 } else {
Joe Onorato23ecae32009-06-10 17:07:15 -0700404 g.s.crc32 = compute_crc32(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700405
Joe Onorato23ecae32009-06-10 17:07:15 -0700406 LOGP("%s", q.string());
Christopher Tate11b15772009-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 Onorato23ecae32009-06-10 17:07:15 -0700411 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tate11b15772009-06-23 13:03:00 -0700412 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tatefbb92382009-06-23 17:35:11 -0700413 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700414 }
415
416 close(fd);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700417 }
418 n++;
419 m++;
420 }
421 }
422
423 // these were deleted
424 while (n<N) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700425 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700432 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700433 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700434 m++;
435 }
436
437 err = write_snapshot_file(newSnapshotFD, newSnapshot);
438
439 return 0;
440}
441
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700442#define RESTORE_BUF_SIZE (8*1024)
443
444RestoreHelperBase::RestoreHelperBase()
445{
446 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700447 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-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 Onorato5d605dc2009-06-18 18:23:43 -0700473
Christopher Tatefbb92382009-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 Tate63bcb792009-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 Tatefbb92382009-06-23 17:35:11 -0700491 }
492 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700493
494 // Write the file and compute the crc
495 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-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 Onoratod2d9ceb2009-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 Onorato5d605dc2009-06-18 18:23:43 -0700506 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-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 Tate11b15772009-06-23 13:03:00 -0700526 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-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 Onorato3ad977b2009-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 Tate63bcb792009-06-24 13:57:29 -0700613 free(contents);
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700622 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700681 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-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 Onorato23ecae32009-06-10 17:07:15 -0700696 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700697 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700698
699 states[0].modTime_sec = 0xfedcba98;
700 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700701 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700702 states[0].size = 0xababbcbc;
703 states[0].crc32 = 0x12345678;
704 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700705 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700706 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700707 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700708
709 states[1].modTime_sec = 0x93400031;
710 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700711 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700712 states[1].size = 0x88557766;
713 states[1].crc32 = 0x22334422;
714 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700715 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700716 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700717 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700718
719 states[2].modTime_sec = 0x33221144;
720 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700721 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700722 states[2].size = 0x11223344;
723 states[2].crc32 = 0x01122334;
724 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700725 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700726 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700727 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700728
729 states[3].modTime_sec = 0x33221144;
730 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700731 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -0700732 states[3].size = 0x11223344;
733 states[3].crc32 = 0x01122334;
734 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700735 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700736 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -0700737 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-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 Tate11b15772009-06-23 13:03:00 -0700751 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -0700752
753 // bytes_of_padding
754 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-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 Onorato3ad977b2009-05-05 11:50:51 -0700759
760 // bytes_of_padding3
761 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-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 Cataniaf4c46b92009-05-22 13:41:38 -0700767
Joe Onorato3ad977b2009-05-05 11:50:51 -0700768 // bytes of padding2
769 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-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 Cataniaf4c46b92009-05-22 13:41:38 -0700775
Joe Onorato3ad977b2009-05-05 11:50:51 -0700776 // bytes of padding3
777 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-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 Onorato3ad977b2009-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 Cataniaf4c46b92009-05-22 13:41:38 -0700789
Joe Onorato3ad977b2009-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 Tate11b15772009-06-23 13:03:00 -0700816 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -0700817 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-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 Onorato3ad977b2009-05-05 11:50:51 -0700824 matched = false;
825 }
826 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700827
Joe Onorato3ad977b2009-05-05 11:50:51 -0700828 return matched ? 0 : 1;
829}
830
Joe Onorato4535e402009-05-15 09:07:06 -0400831// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
832const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-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 Onorato5f15d152009-06-16 16:31:35 -0400837 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
838 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -0400839 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
840 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -0400841 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -0400842 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -0400843 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
844 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -0400845 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -0400846 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
847 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -0400848 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-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 Onorato5f15d152009-06-16 16:31:35 -0400852 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
853
Joe Onorato4535e402009-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 Onorato4535e402009-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 Cataniaf4c46b92009-05-22 13:41:38 -0700888
Joe Onorato4535e402009-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 Onorato4535e402009-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 Onorato2e1da322009-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 Onorato5f15d152009-06-16 16:31:35 -0400922 bool done;
923 int type;
Christopher Tate11b15772009-06-23 13:03:00 -0700924 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -0400925
926 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
927
Joe Onorato5f15d152009-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 Onorato2e1da322009-05-15 18:20:19 -0400933 if (err != 0) {
934 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -0400935 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -0400936 }
Joe Onorato5f15d152009-06-16 16:31:35 -0400937 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -0400938 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -0400939 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-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 Onorato5f15d152009-06-16 16:31:35 -0400945 goto finished;
Joe Onorato2e1da322009-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 Onorato5f15d152009-06-16 16:31:35 -0400950 goto finished;
Joe Onorato2e1da322009-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 Onorato5f15d152009-06-16 16:31:35 -0400956 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -0400957 }
958
Christopher Tate11b15772009-06-23 13:03:00 -0700959 nRead = reader.ReadEntityData(buf, bufSize);
960 if (nRead < 0) {
961 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -0400962 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -0400963 goto finished;
Joe Onorato2e1da322009-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 Onorato5f15d152009-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 Onorato2e1da322009-05-15 18:20:19 -0400970 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -0400971 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -0400972 }
973
974 // The next read will confirm whether it got the right amount of data.
975
Joe Onorato5f15d152009-06-16 16:31:35 -0400976finished:
Joe Onorato2e1da322009-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 Tate63bcb792009-06-24 13:57:29 -0700980 free(buf);
Joe Onorato2e1da322009-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 Cataniaf4c46b92009-05-22 13:41:38 -0700994
Joe Onorato2e1da322009-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 Onorato2e1da322009-05-15 18:20:19 -04001036 }
1037
1038 close(fd);
1039
1040 return err;
1041}
1042
Joe Onorato3ad977b2009-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 Onorato3ad977b2009-05-05 11:50:51 -07001054 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-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 Onorato3ad977b2009-05-05 11:50:51 -07001068 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001069#endif
1070
Joe Onorato3ad977b2009-05-05 11:50:51 -07001071 return 0;
1072}
1073
1074int
1075backup_helper_test_files()
1076{
1077 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001078 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001079 int dataStreamFD;
1080 int newSnapshotFD;
Joe Onorato3ad977b2009-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 Onorato23ecae32009-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 Onorato3ad977b2009-05-05 11:50:51 -07001102 "data/b",
1103 "data/c",
1104 "data/d",
1105 "data/e",
1106 "data/f"
1107 };
1108
Joe Onorato4535e402009-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 Onorato3ad977b2009-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 Onoratod2110db2009-05-19 13:41:21 -07001120
1121 {
1122 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001123
Joe Onorato23ecae32009-06-10 17:07:15 -07001124 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001125 if (err != 0) {
1126 return err;
1127 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001128 }
1129
Joe Onorato4535e402009-05-15 09:07:06 -04001130 close(dataStreamFD);
Joe Onorato3ad977b2009-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 Cataniaf4c46b92009-05-22 13:41:38 -07001153
Joe Onorato3ad977b2009-05-05 11:50:51 -07001154 char const* files_after[] = {
Joe Onorato23ecae32009-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 Onorato3ad977b2009-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 Onorato4535e402009-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 Onorato3ad977b2009-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 Onoratod2110db2009-05-19 13:41:21 -07001190 {
1191 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001192
Joe Onorato23ecae32009-06-10 17:07:15 -07001193 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001194 if (err != 0) {
1195 return err;
1196 }
1197}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001198
1199 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001200 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001201 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001202
Joe Onorato3ad977b2009-05-05 11:50:51 -07001203 return 0;
1204}
1205
Joe Onorato23ecae32009-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 Onoratoce88cb12009-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 Onorato23ecae32009-06-10 17:07:15 -07001308
Joe Onorato3ad977b2009-05-05 11:50:51 -07001309#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001310
1311}