blob: f77a8917c7f958b8a9c9b150805c0a2a2e9a8156 [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
Joe Onorato568bc322009-06-26 17:19:11 -040071#if 1
72#define LOGP(f, x...)
73#else
74#if TEST_BACKUP_HELPERS
Joe Onorato23ecae32009-06-10 17:07:15 -070075#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040076#else
Steve Block5baa3a62011-12-20 16:23:08 +000077#define LOGP(x...) ALOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040078#endif
Joe Onorato568bc322009-06-26 17:19:11 -040079#endif
Joe Onorato290bb012009-05-13 18:57:29 -040080
Joe Onorato3ad977b2009-05-05 11:50:51 -070081const static int ROUND_UP[4] = { 0, 3, 2, 1 };
82
83static inline int
84round_up(int n)
85{
86 return n + ROUND_UP[n % 4];
87}
88
89static int
90read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
91{
92 int bytesRead = 0;
93 int amt;
94 SnapshotHeader header;
95
96 amt = read(fd, &header, sizeof(header));
97 if (amt != sizeof(header)) {
98 return errno;
99 }
100 bytesRead += amt;
101
102 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000103 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700104 return 1;
105 }
106
107 for (int i=0; i<header.fileCount; i++) {
108 FileState file;
109 char filenameBuf[128];
110
Joe Onorato23ecae32009-06-10 17:07:15 -0700111 amt = read(fd, &file, sizeof(FileState));
112 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000113 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700114 return 1;
115 }
116 bytesRead += amt;
117
118 // filename is not NULL terminated, but it is padded
119 int nameBufSize = round_up(file.nameLen);
120 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
121 ? filenameBuf
122 : (char*)malloc(nameBufSize);
123 amt = read(fd, filename, nameBufSize);
124 if (amt == nameBufSize) {
125 snapshot->add(String8(filename, file.nameLen), file);
126 }
127 bytesRead += amt;
128 if (filename != filenameBuf) {
129 free(filename);
130 }
131 if (amt != nameBufSize) {
Steve Block8564c8d2012-01-05 23:22:43 +0000132 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700133 return 1;
134 }
135 }
136
137 if (header.totalSize != bytesRead) {
Steve Block8564c8d2012-01-05 23:22:43 +0000138 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700139 header.totalSize, bytesRead);
140 return 1;
141 }
142
143 return 0;
144}
145
146static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700147write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700148{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700149 int fileCount = 0;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700150 int bytesWritten = sizeof(SnapshotHeader);
151 // preflight size
152 const int N = snapshot.size();
153 for (int i=0; i<N; i++) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700154 const FileRec& g = snapshot.valueAt(i);
155 if (!g.deleted) {
156 const String8& name = snapshot.keyAt(i);
157 bytesWritten += sizeof(FileState) + round_up(name.length());
158 fileCount++;
159 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700160 }
161
Joe Onorato4535e402009-05-15 09:07:06 -0400162 LOGP("write_snapshot_file fd=%d\n", fd);
163
Joe Onorato3ad977b2009-05-05 11:50:51 -0700164 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-05-05 11:50:51 -0700166
167 amt = write(fd, &header, sizeof(header));
168 if (amt != sizeof(header)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000169 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700170 return errno;
171 }
172
Joe Onoratoce88cb12009-06-11 11:27:16 -0700173 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700174 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700175 if (!r.deleted) {
176 const String8& name = snapshot.keyAt(i);
177 int nameLen = r.s.nameLen = name.length();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700178
Joe Onoratoce88cb12009-06-11 11:27:16 -0700179 amt = write(fd, &r.s, sizeof(FileState));
180 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000181 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700182 return 1;
183 }
Joe Onoratoce88cb12009-06-11 11:27:16 -0700184
185 // filename is not NULL terminated, but it is padded
186 amt = write(fd, name.string(), nameLen);
187 if (amt != nameLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000188 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
Joe Onoratoce88cb12009-06-11 11:27:16 -0700189 return 1;
190 }
191 int paddingLen = ROUND_UP[nameLen % 4];
192 if (paddingLen != 0) {
193 int padding = 0xabababab;
194 amt = write(fd, &padding, paddingLen);
195 if (amt != paddingLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000196 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s",
Joe Onoratoce88cb12009-06-11 11:27:16 -0700197 paddingLen, strerror(errno));
198 return 1;
199 }
200 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700201 }
202 }
203
204 return 0;
205}
206
207static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700208write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700209{
Joe Onorato290bb012009-05-13 18:57:29 -0400210 LOGP("write_delete_file %s\n", key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700211 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700212}
213
214static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700215write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700216 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700217{
Christopher Tatefbb92382009-06-23 17:35:11 -0700218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700219
220 const int bufsize = 4*1024;
221 int err;
222 int amt;
223 int fileSize;
224 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700225 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700226
227 char* buf = (char*)malloc(bufsize);
228 int crc = crc32(0L, Z_NULL, 0);
229
230
Christopher Tatefbb92382009-06-23 17:35:11 -0700231 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700232 lseek(fd, 0, SEEK_SET);
233
Christopher Tatefbb92382009-06-23 17:35:11 -0700234 if (sizeof(metadata) != 16) {
Steve Block3762c312012-01-06 19:20:56 +0000235 ALOGE("ERROR: metadata block is the wrong size!");
Christopher Tatefbb92382009-06-23 17:35:11 -0700236 }
237
238 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700239 err = dataStream->WriteEntityHeader(key, bytesLeft);
240 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700241 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700242 return err;
243 }
244
Christopher Tatefbb92382009-06-23 17:35:11 -0700245 // store the file metadata first
246 metadata.version = tolel(CURRENT_METADATA_VERSION);
247 metadata.mode = tolel(mode);
248 metadata.undefined_1 = metadata.undefined_2 = 0;
249 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
250 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700251 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700252 return err;
253 }
254 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
255
256 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700257 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
258 bytesLeft -= amt;
259 if (bytesLeft < 0) {
260 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
261 }
262 err = dataStream->WriteEntityData(buf, amt);
263 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700264 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700265 return err;
266 }
267 }
268 if (bytesLeft != 0) {
269 if (bytesLeft > 0) {
270 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
271 // even though the data we're sending is probably bad.
272 memset(buf, 0, bufsize);
273 while (bytesLeft > 0) {
274 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
275 bytesLeft -= amt;
276 err = dataStream->WriteEntityData(buf, amt);
277 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700278 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700279 return err;
280 }
281 }
282 }
Steve Block3762c312012-01-06 19:20:56 +0000283 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700284 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700285 }
286
Christopher Tate63bcb792009-06-24 13:57:29 -0700287 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700288 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700289}
290
291static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700292write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700293{
294 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700295 struct stat st;
296
297 err = stat(realFilename, &st);
298 if (err < 0) {
299 return errno;
300 }
301
Joe Onorato23ecae32009-06-10 17:07:15 -0700302 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700303 if (fd == -1) {
304 return errno;
305 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700306
307 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700308 close(fd);
309 return err;
310}
311
312static int
313compute_crc32(int fd)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700314{
315 const int bufsize = 4*1024;
316 int amt;
317
Joe Onorato3ad977b2009-05-05 11:50:51 -0700318 char* buf = (char*)malloc(bufsize);
319 int crc = crc32(0L, Z_NULL, 0);
320
Joe Onoratod2110db2009-05-19 13:41:21 -0700321 lseek(fd, 0, SEEK_SET);
322
Joe Onorato3ad977b2009-05-05 11:50:51 -0700323 while ((amt = read(fd, buf, bufsize)) != 0) {
324 crc = crc32(crc, (Bytef*)buf, amt);
325 }
326
Christopher Tate63bcb792009-06-24 13:57:29 -0700327 free(buf);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700328 return crc;
329}
330
331int
Joe Onoratod2110db2009-05-19 13:41:21 -0700332back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700333 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700334{
335 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700336 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700337 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700338
339 if (oldSnapshotFD != -1) {
340 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
341 if (err != 0) {
342 // On an error, treat this as a full backup.
343 oldSnapshot.clear();
344 }
345 }
346
347 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700348 String8 key(keys[i]);
349 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700350 char const* file = files[i];
351 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700352 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700353
Joe Onorato23ecae32009-06-10 17:07:15 -0700354 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700355 if (err != 0) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700356 r.deleted = true;
357 } else {
358 r.deleted = false;
359 r.s.modTime_sec = st.st_mtime;
360 r.s.modTime_nsec = 0; // workaround sim breakage
361 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700362 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700363 r.s.size = st.st_size;
364 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato3ad977b2009-05-05 11:50:51 -0700365
Joe Onoratoce88cb12009-06-11 11:27:16 -0700366 if (newSnapshot.indexOfKey(key) >= 0) {
367 LOGP("back_up_files key already in use '%s'", key.string());
368 return -1;
369 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700370 }
371 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700372 }
373
374 int n = 0;
375 int N = oldSnapshot.size();
376 int m = 0;
377
378 while (n<N && m<fileCount) {
379 const String8& p = oldSnapshot.keyAt(n);
380 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700381 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700382 int cmp = p.compare(q);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700383 if (g.deleted || cmp < 0) {
384 // file removed
385 LOGP("file removed: %s", p.string());
386 g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
387 dataStream->WriteEntityHeader(p, -1);
388 n++;
389 }
390 else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 // file added
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700392 LOGP("file added: %s", g.file.string());
393 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700394 m++;
395 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700396 else {
397 // both files exist, check them
Joe Onorato3ad977b2009-05-05 11:50:51 -0700398 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700399
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700400 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate0032ce82009-06-04 17:01:06 -0700401 if (fd < 0) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700402 // We can't open the file. Don't report it as a delete either. Let the
403 // server keep the old version. Maybe they'll be able to deal with it
404 // on restore.
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700405 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700406 } else {
Joe Onorato23ecae32009-06-10 17:07:15 -0700407 g.s.crc32 = compute_crc32(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700408
Joe Onorato23ecae32009-06-10 17:07:15 -0700409 LOGP("%s", q.string());
Christopher Tate11b15772009-06-23 13:03:00 -0700410 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
411 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
412 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
413 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
Joe Onorato23ecae32009-06-10 17:07:15 -0700414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tate11b15772009-06-23 13:03:00 -0700415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tatefbb92382009-06-23 17:35:11 -0700416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700417 }
418
419 close(fd);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700420 }
421 n++;
422 m++;
423 }
424 }
425
426 // these were deleted
427 while (n<N) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700428 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700429 n++;
430 }
431
432 // these were added
433 while (m<fileCount) {
434 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700435 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700436 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700437 m++;
438 }
439
440 err = write_snapshot_file(newSnapshotFD, newSnapshot);
441
442 return 0;
443}
444
Christopher Tate4a627c72011-04-01 14:43:32 -0700445// Utility function, equivalent to stpcpy(): perform a strcpy, but instead of
446// returning the initial dest, return a pointer to the trailing NUL.
447static char* strcpy_ptr(char* dest, const char* str) {
448 if (dest && str) {
449 while ((*dest = *str) != 0) {
450 dest++;
451 str++;
452 }
453 }
454 return dest;
455}
456
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700457static void calc_tar_checksum(char* buf) {
458 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
459 memset(buf + 148, ' ', 8);
460
461 uint16_t sum = 0;
462 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
463 sum += *p;
464 }
465
466 // Now write the real checksum value:
467 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
468 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
469}
470
Christopher Tatedc92c822011-05-13 15:38:02 -0700471// Returns number of bytes written
472static int write_pax_header_entry(char* buf, const char* key, const char* value) {
473 // start with the size of "1 key=value\n"
474 int len = strlen(key) + strlen(value) + 4;
475 if (len > 9) len++;
476 if (len > 99) len++;
477 if (len > 999) len++;
478 // since PATH_MAX is 4096 we don't expect to have to generate any single
479 // header entry longer than 9999 characters
480
481 return sprintf(buf, "%d %s=%s\n", len, key, value);
482}
483
Christopher Tate7926a692011-07-11 11:31:57 -0700484// Wire format to the backup manager service is chunked: each chunk is prefixed by
485// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
486void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
487 uint32_t chunk_size_no = htonl(size);
488 writer->WriteEntityData(&chunk_size_no, 4);
489 if (size != 0) writer->WriteEntityData(buffer, size);
490}
491
Christopher Tate4a627c72011-04-01 14:43:32 -0700492int write_tarfile(const String8& packageName, const String8& domain,
493 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
494{
495 // In the output stream everything is stored relative to the root
496 const char* relstart = filepath.string() + rootpath.length();
497 if (*relstart == '/') relstart++; // won't be true when path == rootpath
498 String8 relpath(relstart);
499
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700500 // If relpath is empty, it means this is the top of one of the standard named
501 // domain directories, so we should just skip it
502 if (relpath.length() == 0) {
503 return 0;
504 }
505
Christopher Tate4a627c72011-04-01 14:43:32 -0700506 // Too long a name for the ustar format?
507 // "apps/" + packagename + '/' + domainpath < 155 chars
508 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700509 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700510 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700511 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700512 }
513
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700514 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700515 if (!needExtended) {
516 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700517 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700518 needExtended = true;
519 break;
520 }
521 }
522 }
523
Christopher Tate4a627c72011-04-01 14:43:32 -0700524 int err = 0;
525 struct stat64 s;
526 if (lstat64(filepath.string(), &s) != 0) {
527 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000528 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700529 return err;
530 }
531
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700532 String8 fullname; // for pax later on
533 String8 prefix;
534
Christopher Tate4a627c72011-04-01 14:43:32 -0700535 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700536 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700537
538 // !!! TODO: use mmap when possible to avoid churning the buffer cache
539 // !!! TODO: this will break with symlinks; need to use readlink(2)
540 int fd = open(filepath.string(), O_RDONLY);
541 if (fd < 0) {
542 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000543 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700544 return err;
545 }
546
547 // read/write up to this much at a time.
548 const size_t BUFSIZE = 32 * 1024;
Christopher Tate4a627c72011-04-01 14:43:32 -0700549 char* buf = new char[BUFSIZE];
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700550 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
551 char* paxData = buf + 1024;
552
Christopher Tate4a627c72011-04-01 14:43:32 -0700553 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000554 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700555 err = ENOMEM;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700556 goto cleanup;
Christopher Tate4a627c72011-04-01 14:43:32 -0700557 }
558
559 // Good to go -- first construct the standard tar header at the start of the buffer
Christopher Tatedc92c822011-05-13 15:38:02 -0700560 memset(buf, 0, BUFSIZE);
Christopher Tate4a627c72011-04-01 14:43:32 -0700561
562 // Magic fields for the ustar file format
563 strcat(buf + 257, "ustar");
564 strcat(buf + 263, "00");
565
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700566 // [ 265 : 32 ] user name, ignored on restore
567 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700568
569 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700570 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700571
572 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
573 // [ 116 : 8 ] gid -- ignored in Android format
574 snprintf(buf + 108, 8, "0%lo", s.st_uid);
575 snprintf(buf + 116, 8, "0%lo", s.st_gid);
576
577 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700578 if (s.st_size > 077777777777LL) {
579 // very large files need a pax extended size header
580 needExtended = true;
581 }
582 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700583
584 // [ 136 : 12 ] last mod time as a UTC time_t
585 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
586
Christopher Tate4a627c72011-04-01 14:43:32 -0700587 // [ 156 : 1 ] link/file type
588 uint8_t type;
589 if (isdir) {
590 type = '5'; // tar magic: '5' == directory
591 } else if (S_ISREG(s.st_mode)) {
592 type = '0'; // tar magic: '0' == normal file
593 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000594 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700595 goto cleanup;
596 }
597 buf[156] = type;
598
599 // [ 157 : 100 ] name of linked file [not implemented]
600
Christopher Tate4a627c72011-04-01 14:43:32 -0700601 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700602 // Prefix and main relative path. Path lengths have been preflighted.
603 if (packageName.length() > 0) {
604 prefix = "apps/";
605 prefix += packageName;
606 }
607 if (domain.length() > 0) {
608 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700609 }
610
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700611 // pax extended means we don't put in a prefix field, and put a different
612 // string in the basic name field. We can also construct the full path name
613 // out of the substrings we've now built.
614 fullname = prefix;
615 fullname.appendPath(relpath);
616
617 // ustar:
618 // [ 0 : 100 ]; file name/path
619 // [ 345 : 155 ] filename path prefix
620 // We only use the prefix area if fullname won't fit in the path
621 if (fullname.length() > 100) {
622 strncpy(buf, relpath.string(), 100);
623 strncpy(buf + 345, prefix.string(), 155);
624 } else {
625 strncpy(buf, fullname.string(), 100);
626 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700627 }
628
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700629 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
630
Steve Block6215d3f2012-01-04 20:05:49 +0000631 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700632
633 // If we're using a pax extended header, build & write that here; lengths are
634 // already preflighted
635 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700636 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
637 char* p = paxData;
638
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700639 // construct the pax extended header data block
640 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700641 int len;
642
643 // size header -- calc len in digits by actually rendering the number
644 // to a string - brute force but simple
Christopher Tatedc92c822011-05-13 15:38:02 -0700645 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
646 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700647
648 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700649 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700650
651 // Now we know how big the pax data is
652 int paxLen = p - paxData;
653
654 // Now build the pax *header* templated on the ustar header
655 memcpy(paxHeader, buf, 512);
656
657 String8 leaf = fullname.getPathLeaf();
658 memset(paxHeader, 0, 100); // rewrite the name area
659 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
660 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
661 strncpy(paxHeader + 345, prefix.string(), 155);
662
663 paxHeader[156] = 'x'; // mark it as a pax extended header
664
665 // [ 124 : 12 ] size of pax extended header data
666 memset(paxHeader + 124, 0, 12);
667 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
668
669 // Checksum and write the pax block header
670 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700671 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700672
673 // Now write the pax data itself
674 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700675 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700676 }
677
678 // Checksum and write the 512-byte ustar file header block to the output
679 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700680 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700681
682 // Now write the file data itself, for real files. We honor tar's convention that
683 // only full 512-byte blocks are sent to write().
684 if (!isdir) {
685 off64_t toWrite = s.st_size;
686 while (toWrite > 0) {
687 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
688 ssize_t nRead = read(fd, buf, toRead);
689 if (nRead < 0) {
690 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000691 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700692 err, strerror(err));
693 break;
694 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000695 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700696 filepath.string());
697 err = EIO;
698 break;
699 }
700
701 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
702 // depends on the OS guarantee that for ordinary files, read() will never return
703 // less than the number of bytes requested.
704 ssize_t partial = (nRead+512) % 512;
705 if (partial > 0) {
706 ssize_t remainder = 512 - partial;
707 memset(buf + nRead, 0, remainder);
708 nRead += remainder;
709 }
Christopher Tate7926a692011-07-11 11:31:57 -0700710 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700711 toWrite -= nRead;
712 }
713 }
714
715cleanup:
716 delete [] buf;
717done:
718 close(fd);
719 return err;
720}
721// end tarfile
722
723
724
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700725#define RESTORE_BUF_SIZE (8*1024)
726
727RestoreHelperBase::RestoreHelperBase()
728{
729 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700730 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700731}
732
733RestoreHelperBase::~RestoreHelperBase()
734{
735 free(m_buf);
736}
737
738status_t
739RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
740{
741 ssize_t err;
742 size_t dataSize;
743 String8 key;
744 int fd;
745 void* buf = m_buf;
746 ssize_t amt;
747 int mode;
748 int crc;
749 struct stat st;
750 FileRec r;
751
752 err = in->ReadEntityHeader(&key, &dataSize);
753 if (err != NO_ERROR) {
754 return err;
755 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700756
Christopher Tatefbb92382009-06-23 17:35:11 -0700757 // Get the metadata block off the head of the file entity and use that to
758 // set up the output file
759 file_metadata_v1 metadata;
760 amt = in->ReadEntityData(&metadata, sizeof(metadata));
761 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000762 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700763 (long)amt, strerror(errno));
764 return EIO;
765 }
766 metadata.version = fromlel(metadata.version);
767 metadata.mode = fromlel(metadata.mode);
768 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700769 if (!m_loggedUnknownMetadata) {
770 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000771 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700772 metadata.version, CURRENT_METADATA_VERSION);
773 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700774 }
775 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700776
777 // Write the file and compute the crc
778 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700779 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
780 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000781 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700782 return errno;
783 }
784
785 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
786 err = write(fd, buf, amt);
787 if (err != amt) {
788 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000789 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700790 return errno;
791 }
792 crc = crc32(crc, (Bytef*)buf, amt);
793 }
794
795 close(fd);
796
797 // Record for the snapshot
798 err = stat(filename.string(), &st);
799 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000800 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700801 return errno;
802 }
803
804 r.file = filename;
805 r.deleted = false;
806 r.s.modTime_sec = st.st_mtime;
807 r.s.modTime_nsec = 0; // workaround sim breakage
808 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700809 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700810 r.s.size = st.st_size;
811 r.s.crc32 = crc;
812
813 m_files.add(key, r);
814
815 return NO_ERROR;
816}
817
818status_t
819RestoreHelperBase::WriteSnapshot(int fd)
820{
821 return write_snapshot_file(fd, m_files);;
822}
823
Joe Onorato3ad977b2009-05-05 11:50:51 -0700824#if TEST_BACKUP_HELPERS
825
826#define SCRATCH_DIR "/data/backup_helper_test/"
827
828static int
829write_text_file(const char* path, const char* data)
830{
831 int amt;
832 int fd;
833 int len;
834
835 fd = creat(path, 0666);
836 if (fd == -1) {
837 fprintf(stderr, "creat %s failed\n", path);
838 return errno;
839 }
840
841 len = strlen(data);
842 amt = write(fd, data, len);
843 if (amt != len) {
844 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
845 return errno;
846 }
847
848 close(fd);
849
850 return 0;
851}
852
853static int
854compare_file(const char* path, const unsigned char* data, int len)
855{
856 int fd;
857 int amt;
858
859 fd = open(path, O_RDONLY);
860 if (fd == -1) {
861 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
862 return errno;
863 }
864
865 unsigned char* contents = (unsigned char*)malloc(len);
866 if (contents == NULL) {
867 fprintf(stderr, "malloc(%d) failed\n", len);
868 return ENOMEM;
869 }
870
871 bool sizesMatch = true;
872 amt = lseek(fd, 0, SEEK_END);
873 if (amt != len) {
874 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
875 sizesMatch = false;
876 }
877 lseek(fd, 0, SEEK_SET);
878
879 int readLen = amt < len ? amt : len;
880 amt = read(fd, contents, readLen);
881 if (amt != readLen) {
882 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
883 }
884
885 bool contentsMatch = true;
886 for (int i=0; i<readLen; i++) {
887 if (data[i] != contents[i]) {
888 if (contentsMatch) {
889 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
890 contentsMatch = false;
891 }
892 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
893 }
894 }
895
Christopher Tate63bcb792009-06-24 13:57:29 -0700896 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700897 return contentsMatch && sizesMatch ? 0 : 1;
898}
899
900int
901backup_helper_test_empty()
902{
903 int err;
904 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700905 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700906 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
907
908 system("rm -r " SCRATCH_DIR);
909 mkdir(SCRATCH_DIR, 0777);
910
911 // write
912 fd = creat(filename, 0666);
913 if (fd == -1) {
914 fprintf(stderr, "error creating %s\n", filename);
915 return 1;
916 }
917
918 err = write_snapshot_file(fd, snapshot);
919
920 close(fd);
921
922 if (err != 0) {
923 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
924 return err;
925 }
926
927 static const unsigned char correct_data[] = {
928 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
929 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
930 };
931
932 err = compare_file(filename, correct_data, sizeof(correct_data));
933 if (err != 0) {
934 return err;
935 }
936
937 // read
938 fd = open(filename, O_RDONLY);
939 if (fd == -1) {
940 fprintf(stderr, "error opening for read %s\n", filename);
941 return 1;
942 }
943
944 KeyedVector<String8,FileState> readSnapshot;
945 err = read_snapshot_file(fd, &readSnapshot);
946 if (err != 0) {
947 fprintf(stderr, "read_snapshot_file failed %d\n", err);
948 return err;
949 }
950
951 if (readSnapshot.size() != 0) {
952 fprintf(stderr, "readSnapshot should be length 0\n");
953 return 1;
954 }
955
956 return 0;
957}
958
959int
960backup_helper_test_four()
961{
962 int err;
963 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700964 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700965 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
966
967 system("rm -r " SCRATCH_DIR);
968 mkdir(SCRATCH_DIR, 0777);
969
970 // write
971 fd = creat(filename, 0666);
972 if (fd == -1) {
973 fprintf(stderr, "error opening %s\n", filename);
974 return 1;
975 }
976
977 String8 filenames[4];
978 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700979 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700980 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700981
982 states[0].modTime_sec = 0xfedcba98;
983 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700984 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700985 states[0].size = 0xababbcbc;
986 states[0].crc32 = 0x12345678;
987 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700988 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700989 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700990 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700991
992 states[1].modTime_sec = 0x93400031;
993 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700994 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700995 states[1].size = 0x88557766;
996 states[1].crc32 = 0x22334422;
997 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700998 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700999 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -07001000 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001001
1002 states[2].modTime_sec = 0x33221144;
1003 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001004 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -07001005 states[2].size = 0x11223344;
1006 states[2].crc32 = 0x01122334;
1007 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001008 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001009 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001010 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001011
1012 states[3].modTime_sec = 0x33221144;
1013 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001014 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001015 states[3].size = 0x11223344;
1016 states[3].crc32 = 0x01122334;
1017 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001018 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001019 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001020 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001021
1022 err = write_snapshot_file(fd, snapshot);
1023
1024 close(fd);
1025
1026 if (err != 0) {
1027 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1028 return err;
1029 }
1030
1031 static const unsigned char correct_data[] = {
1032 // header
1033 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001034 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001035
1036 // bytes_of_padding
1037 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001038 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1039 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1040 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1041 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001042
1043 // bytes_of_padding3
1044 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001045 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1046 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1047 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1048 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1049 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001050
Joe Onorato3ad977b2009-05-05 11:50:51 -07001051 // bytes of padding2
1052 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001053 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1054 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1055 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1056 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1057 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001058
Joe Onorato3ad977b2009-05-05 11:50:51 -07001059 // bytes of padding3
1060 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001061 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1062 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1063 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1064 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1065 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001066 };
1067
1068 err = compare_file(filename, correct_data, sizeof(correct_data));
1069 if (err != 0) {
1070 return err;
1071 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001072
Joe Onorato3ad977b2009-05-05 11:50:51 -07001073 // read
1074 fd = open(filename, O_RDONLY);
1075 if (fd == -1) {
1076 fprintf(stderr, "error opening for read %s\n", filename);
1077 return 1;
1078 }
1079
1080
1081 KeyedVector<String8,FileState> readSnapshot;
1082 err = read_snapshot_file(fd, &readSnapshot);
1083 if (err != 0) {
1084 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1085 return err;
1086 }
1087
1088 if (readSnapshot.size() != 4) {
1089 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1090 return 1;
1091 }
1092
1093 bool matched = true;
1094 for (size_t i=0; i<readSnapshot.size(); i++) {
1095 const String8& name = readSnapshot.keyAt(i);
1096 const FileState state = readSnapshot.valueAt(i);
1097
1098 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001099 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001100 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-06-23 13:03:00 -07001101 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1102 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1103 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1104 states[i].crc32, name.length(), filenames[i].string(),
1105 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1106 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001107 matched = false;
1108 }
1109 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001110
Joe Onorato3ad977b2009-05-05 11:50:51 -07001111 return matched ? 0 : 1;
1112}
1113
Joe Onorato4535e402009-05-15 09:07:06 -04001114// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1115const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001116 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1117 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1118 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1119 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001120 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1121 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001122 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1123 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001124 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001125 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001126 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1127 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001128 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001129 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1130 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001131 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001132 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1133 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1134 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001135 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1136
Joe Onorato4535e402009-05-15 09:07:06 -04001137};
1138const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1139
1140static int
1141test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1142{
1143 int err;
1144 String8 text(str);
1145
Joe Onorato4535e402009-05-15 09:07:06 -04001146 err = writer.WriteEntityHeader(text, text.length()+1);
1147 if (err != 0) {
1148 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1149 return err;
1150 }
1151
1152 err = writer.WriteEntityData(text.string(), text.length()+1);
1153 if (err != 0) {
1154 fprintf(stderr, "write failed for data '%s'\n", text.string());
1155 return errno;
1156 }
1157
1158 return err;
1159}
1160
1161int
1162backup_helper_test_data_writer()
1163{
1164 int err;
1165 int fd;
1166 const char* filename = SCRATCH_DIR "data_writer.data";
1167
1168 system("rm -r " SCRATCH_DIR);
1169 mkdir(SCRATCH_DIR, 0777);
1170 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001171
Joe Onorato4535e402009-05-15 09:07:06 -04001172 fd = creat(filename, 0666);
1173 if (fd == -1) {
1174 fprintf(stderr, "error creating: %s\n", strerror(errno));
1175 return errno;
1176 }
1177
1178 BackupDataWriter writer(fd);
1179
1180 err = 0;
1181 err |= test_write_header_and_entity(writer, "no_padding_");
1182 err |= test_write_header_and_entity(writer, "padded_to__3");
1183 err |= test_write_header_and_entity(writer, "padded_to_2__");
1184 err |= test_write_header_and_entity(writer, "padded_to1");
1185
Joe Onorato4535e402009-05-15 09:07:06 -04001186 close(fd);
1187
1188 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1189 if (err != 0) {
1190 return err;
1191 }
1192
1193 return err;
1194}
1195
Joe Onorato2e1da322009-05-15 18:20:19 -04001196int
1197test_read_header_and_entity(BackupDataReader& reader, const char* str)
1198{
1199 int err;
1200 int bufSize = strlen(str)+1;
1201 char* buf = (char*)malloc(bufSize);
1202 String8 string;
1203 int cookie = 0x11111111;
1204 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001205 bool done;
1206 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001207 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001208
1209 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1210
Joe Onorato5f15d152009-06-16 16:31:35 -04001211 err = reader.ReadNextHeader(&done, &type);
1212 if (done) {
1213 fprintf(stderr, "should not be done yet\n");
1214 goto finished;
1215 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001216 if (err != 0) {
1217 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001218 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001219 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001220 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001221 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001222 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001223 }
1224
1225 err = reader.ReadEntityHeader(&string, &actualSize);
1226 if (err != 0) {
1227 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001228 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001229 }
1230 if (string != str) {
1231 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1232 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001233 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001234 }
1235 if ((int)actualSize != bufSize) {
1236 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1237 actualSize);
1238 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001239 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001240 }
1241
Christopher Tate11b15772009-06-23 13:03:00 -07001242 nRead = reader.ReadEntityData(buf, bufSize);
1243 if (nRead < 0) {
1244 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001245 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001246 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001247 }
1248
1249 if (0 != memcmp(buf, str, bufSize)) {
1250 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001251 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1252 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001253 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001254 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001255 }
1256
1257 // The next read will confirm whether it got the right amount of data.
1258
Joe Onorato5f15d152009-06-16 16:31:35 -04001259finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001260 if (err != NO_ERROR) {
1261 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1262 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001263 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001264 return err;
1265}
1266
1267int
1268backup_helper_test_data_reader()
1269{
1270 int err;
1271 int fd;
1272 const char* filename = SCRATCH_DIR "data_reader.data";
1273
1274 system("rm -r " SCRATCH_DIR);
1275 mkdir(SCRATCH_DIR, 0777);
1276 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001277
Joe Onorato2e1da322009-05-15 18:20:19 -04001278 fd = creat(filename, 0666);
1279 if (fd == -1) {
1280 fprintf(stderr, "error creating: %s\n", strerror(errno));
1281 return errno;
1282 }
1283
1284 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1285 if (err != DATA_GOLDEN_FILE_SIZE) {
1286 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1287 return errno;
1288 }
1289
1290 close(fd);
1291
1292 fd = open(filename, O_RDONLY);
1293 if (fd == -1) {
1294 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1295 filename);
1296 return errno;
1297 }
1298
1299 {
1300 BackupDataReader reader(fd);
1301
1302 err = 0;
1303
1304 if (err == NO_ERROR) {
1305 err = test_read_header_and_entity(reader, "no_padding_");
1306 }
1307
1308 if (err == NO_ERROR) {
1309 err = test_read_header_and_entity(reader, "padded_to__3");
1310 }
1311
1312 if (err == NO_ERROR) {
1313 err = test_read_header_and_entity(reader, "padded_to_2__");
1314 }
1315
1316 if (err == NO_ERROR) {
1317 err = test_read_header_and_entity(reader, "padded_to1");
1318 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001319 }
1320
1321 close(fd);
1322
1323 return err;
1324}
1325
Joe Onorato3ad977b2009-05-05 11:50:51 -07001326static int
1327get_mod_time(const char* filename, struct timeval times[2])
1328{
1329 int err;
1330 struct stat64 st;
1331 err = stat64(filename, &st);
1332 if (err != 0) {
1333 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1334 return errno;
1335 }
1336 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001337 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001338
1339 // If st_atime is a macro then struct stat64 uses struct timespec
1340 // to store the access and modif time values and typically
1341 // st_*time_nsec is not defined. In glibc, this is controlled by
1342 // __USE_MISC.
1343#ifdef __USE_MISC
1344#if !defined(st_atime) || defined(st_atime_nsec)
1345#error "Check if this __USE_MISC conditional is still needed."
1346#endif
1347 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1348 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1349#else
1350 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001351 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001352#endif
1353
Joe Onorato3ad977b2009-05-05 11:50:51 -07001354 return 0;
1355}
1356
1357int
1358backup_helper_test_files()
1359{
1360 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001361 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001362 int dataStreamFD;
1363 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001364
1365 system("rm -r " SCRATCH_DIR);
1366 mkdir(SCRATCH_DIR, 0777);
1367 mkdir(SCRATCH_DIR "data", 0777);
1368
1369 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1370 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1371 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1372 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1373 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1374 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1375
1376 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001377 SCRATCH_DIR "data/b",
1378 SCRATCH_DIR "data/c",
1379 SCRATCH_DIR "data/d",
1380 SCRATCH_DIR "data/e",
1381 SCRATCH_DIR "data/f"
1382 };
1383
1384 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001385 "data/b",
1386 "data/c",
1387 "data/d",
1388 "data/e",
1389 "data/f"
1390 };
1391
Joe Onorato4535e402009-05-15 09:07:06 -04001392 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1393 if (dataStreamFD == -1) {
1394 fprintf(stderr, "error creating: %s\n", strerror(errno));
1395 return errno;
1396 }
1397
Joe Onorato3ad977b2009-05-05 11:50:51 -07001398 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1399 if (newSnapshotFD == -1) {
1400 fprintf(stderr, "error creating: %s\n", strerror(errno));
1401 return errno;
1402 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001403
1404 {
1405 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001406
Joe Onorato23ecae32009-06-10 17:07:15 -07001407 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001408 if (err != 0) {
1409 return err;
1410 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001411 }
1412
Joe Onorato4535e402009-05-15 09:07:06 -04001413 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001414 close(newSnapshotFD);
1415
1416 sleep(3);
1417
1418 struct timeval d_times[2];
1419 struct timeval e_times[2];
1420
1421 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1422 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1423 if (err != 0) {
1424 return err;
1425 }
1426
1427 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1428 unlink(SCRATCH_DIR "data/c");
1429 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1430 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1431 utimes(SCRATCH_DIR "data/d", d_times);
1432 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1433 utimes(SCRATCH_DIR "data/e", e_times);
1434 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1435 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001436
Joe Onorato3ad977b2009-05-05 11:50:51 -07001437 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001438 SCRATCH_DIR "data/a", // added
1439 SCRATCH_DIR "data/b", // same
1440 SCRATCH_DIR "data/c", // different mod time
1441 SCRATCH_DIR "data/d", // different size (same mod time)
1442 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1443 SCRATCH_DIR "data/g" // added
1444 };
1445
1446 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001447 "data/a", // added
1448 "data/b", // same
1449 "data/c", // different mod time
1450 "data/d", // different size (same mod time)
1451 "data/e", // different contents (same mod time, same size)
1452 "data/g" // added
1453 };
1454
1455 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1456 if (oldSnapshotFD == -1) {
1457 fprintf(stderr, "error opening: %s\n", strerror(errno));
1458 return errno;
1459 }
1460
Joe Onorato4535e402009-05-15 09:07:06 -04001461 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1462 if (dataStreamFD == -1) {
1463 fprintf(stderr, "error creating: %s\n", strerror(errno));
1464 return errno;
1465 }
1466
Joe Onorato3ad977b2009-05-05 11:50:51 -07001467 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1468 if (newSnapshotFD == -1) {
1469 fprintf(stderr, "error creating: %s\n", strerror(errno));
1470 return errno;
1471 }
1472
Joe Onoratod2110db2009-05-19 13:41:21 -07001473 {
1474 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001475
Joe Onorato23ecae32009-06-10 17:07:15 -07001476 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001477 if (err != 0) {
1478 return err;
1479 }
1480}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001481
1482 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001483 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001484 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001485
Joe Onorato3ad977b2009-05-05 11:50:51 -07001486 return 0;
1487}
1488
Joe Onorato23ecae32009-06-10 17:07:15 -07001489int
1490backup_helper_test_null_base()
1491{
1492 int err;
1493 int oldSnapshotFD;
1494 int dataStreamFD;
1495 int newSnapshotFD;
1496
1497 system("rm -r " SCRATCH_DIR);
1498 mkdir(SCRATCH_DIR, 0777);
1499 mkdir(SCRATCH_DIR "data", 0777);
1500
1501 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1502
1503 char const* files[] = {
1504 SCRATCH_DIR "data/a",
1505 };
1506
1507 char const* keys[] = {
1508 "a",
1509 };
1510
1511 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1512 if (dataStreamFD == -1) {
1513 fprintf(stderr, "error creating: %s\n", strerror(errno));
1514 return errno;
1515 }
1516
1517 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1518 if (newSnapshotFD == -1) {
1519 fprintf(stderr, "error creating: %s\n", strerror(errno));
1520 return errno;
1521 }
1522
1523 {
1524 BackupDataWriter dataStream(dataStreamFD);
1525
1526 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1527 if (err != 0) {
1528 return err;
1529 }
1530 }
1531
1532 close(dataStreamFD);
1533 close(newSnapshotFD);
1534
1535 return 0;
1536}
1537
Joe Onoratoce88cb12009-06-11 11:27:16 -07001538int
1539backup_helper_test_missing_file()
1540{
1541 int err;
1542 int oldSnapshotFD;
1543 int dataStreamFD;
1544 int newSnapshotFD;
1545
1546 system("rm -r " SCRATCH_DIR);
1547 mkdir(SCRATCH_DIR, 0777);
1548 mkdir(SCRATCH_DIR "data", 0777);
1549
1550 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1551
1552 char const* files[] = {
1553 SCRATCH_DIR "data/a",
1554 SCRATCH_DIR "data/b",
1555 SCRATCH_DIR "data/c",
1556 };
1557
1558 char const* keys[] = {
1559 "a",
1560 "b",
1561 "c",
1562 };
1563
1564 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1565 if (dataStreamFD == -1) {
1566 fprintf(stderr, "error creating: %s\n", strerror(errno));
1567 return errno;
1568 }
1569
1570 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1571 if (newSnapshotFD == -1) {
1572 fprintf(stderr, "error creating: %s\n", strerror(errno));
1573 return errno;
1574 }
1575
1576 {
1577 BackupDataWriter dataStream(dataStreamFD);
1578
1579 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1580 if (err != 0) {
1581 return err;
1582 }
1583 }
1584
1585 close(dataStreamFD);
1586 close(newSnapshotFD);
1587
1588 return 0;
1589}
1590
Joe Onorato23ecae32009-06-10 17:07:15 -07001591
Joe Onorato3ad977b2009-05-05 11:50:51 -07001592#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001593
1594}