blob: f933199fe8d1c7d1a6eb83a990cc38125bbea0ae [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
Joe Onorato290bb012009-05-13 18:57:29 -040077#define LOGP(x...) LOGD(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) {
103 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
104 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)) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700113 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
114 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) {
132 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
133 return 1;
134 }
135 }
136
137 if (header.totalSize != bytesRead) {
138 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
139 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)) {
169 LOGW("write_snapshot_file error writing header %s", strerror(errno));
170 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)) {
181 LOGW("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) {
188 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
189 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) {
196 LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
197 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) {
235 LOGE("ERROR: metadata block is the wrong size!");
236 }
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 }
283 LOGE("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 Tate4a627c72011-04-01 14:43:32 -0700484int write_tarfile(const String8& packageName, const String8& domain,
485 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
486{
487 // In the output stream everything is stored relative to the root
488 const char* relstart = filepath.string() + rootpath.length();
489 if (*relstart == '/') relstart++; // won't be true when path == rootpath
490 String8 relpath(relstart);
491
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700492 // If relpath is empty, it means this is the top of one of the standard named
493 // domain directories, so we should just skip it
494 if (relpath.length() == 0) {
495 return 0;
496 }
497
Christopher Tate4a627c72011-04-01 14:43:32 -0700498 // Too long a name for the ustar format?
499 // "apps/" + packagename + '/' + domainpath < 155 chars
500 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700501 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700502 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700503 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700504 }
505
Christopher Tate75a99702011-05-18 16:28:19 -0700506 // Non-7bit-clean path also means needing pax extended format
507 if (!needExtended) {
508 for (size_t i = 0; i < filepath.length(); i++) {
509 if ((filepath[i] & 0x80) != 0) {
510 needExtended = true;
511 break;
512 }
513 }
514 }
515
Christopher Tate4a627c72011-04-01 14:43:32 -0700516 int err = 0;
517 struct stat64 s;
518 if (lstat64(filepath.string(), &s) != 0) {
519 err = errno;
520 LOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
521 return err;
522 }
523
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700524 String8 fullname; // for pax later on
525 String8 prefix;
526
Christopher Tate4a627c72011-04-01 14:43:32 -0700527 const int isdir = S_ISDIR(s.st_mode);
528
529 // !!! TODO: use mmap when possible to avoid churning the buffer cache
530 // !!! TODO: this will break with symlinks; need to use readlink(2)
531 int fd = open(filepath.string(), O_RDONLY);
532 if (fd < 0) {
533 err = errno;
534 LOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
535 return err;
536 }
537
538 // read/write up to this much at a time.
539 const size_t BUFSIZE = 32 * 1024;
Christopher Tate4a627c72011-04-01 14:43:32 -0700540 char* buf = new char[BUFSIZE];
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700541 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
542 char* paxData = buf + 1024;
543
Christopher Tate4a627c72011-04-01 14:43:32 -0700544 if (buf == NULL) {
545 LOGE("Out of mem allocating transfer buffer");
546 err = ENOMEM;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700547 goto cleanup;
Christopher Tate4a627c72011-04-01 14:43:32 -0700548 }
549
550 // Good to go -- first construct the standard tar header at the start of the buffer
Christopher Tatedc92c822011-05-13 15:38:02 -0700551 memset(buf, 0, BUFSIZE);
Christopher Tate4a627c72011-04-01 14:43:32 -0700552
553 // Magic fields for the ustar file format
554 strcat(buf + 257, "ustar");
555 strcat(buf + 263, "00");
556
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700557 // [ 265 : 32 ] user name, ignored on restore
558 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700559
560 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700561 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700562
563 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
564 // [ 116 : 8 ] gid -- ignored in Android format
565 snprintf(buf + 108, 8, "0%lo", s.st_uid);
566 snprintf(buf + 116, 8, "0%lo", s.st_gid);
567
568 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700569 if (s.st_size > 077777777777LL) {
570 // very large files need a pax extended size header
571 needExtended = true;
572 }
573 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700574
575 // [ 136 : 12 ] last mod time as a UTC time_t
576 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
577
Christopher Tate4a627c72011-04-01 14:43:32 -0700578 // [ 156 : 1 ] link/file type
579 uint8_t type;
580 if (isdir) {
581 type = '5'; // tar magic: '5' == directory
582 } else if (S_ISREG(s.st_mode)) {
583 type = '0'; // tar magic: '0' == normal file
584 } else {
585 LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
586 goto cleanup;
587 }
588 buf[156] = type;
589
590 // [ 157 : 100 ] name of linked file [not implemented]
591
Christopher Tate4a627c72011-04-01 14:43:32 -0700592 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700593 // Prefix and main relative path. Path lengths have been preflighted.
594 if (packageName.length() > 0) {
595 prefix = "apps/";
596 prefix += packageName;
597 }
598 if (domain.length() > 0) {
599 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700600 }
601
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700602 // pax extended means we don't put in a prefix field, and put a different
603 // string in the basic name field. We can also construct the full path name
604 // out of the substrings we've now built.
605 fullname = prefix;
606 fullname.appendPath(relpath);
607
608 // ustar:
609 // [ 0 : 100 ]; file name/path
610 // [ 345 : 155 ] filename path prefix
611 // We only use the prefix area if fullname won't fit in the path
612 if (fullname.length() > 100) {
613 strncpy(buf, relpath.string(), 100);
614 strncpy(buf + 345, prefix.string(), 155);
615 } else {
616 strncpy(buf, fullname.string(), 100);
617 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700618 }
619
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700620 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
621
622 LOGI(" Name: %s", fullname.string());
623
624 // If we're using a pax extended header, build & write that here; lengths are
625 // already preflighted
626 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700627 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
628 char* p = paxData;
629
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700630 // construct the pax extended header data block
631 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700632 int len;
633
634 // size header -- calc len in digits by actually rendering the number
635 // to a string - brute force but simple
Christopher Tatedc92c822011-05-13 15:38:02 -0700636 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
637 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700638
639 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700640 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700641
642 // Now we know how big the pax data is
643 int paxLen = p - paxData;
644
645 // Now build the pax *header* templated on the ustar header
646 memcpy(paxHeader, buf, 512);
647
648 String8 leaf = fullname.getPathLeaf();
649 memset(paxHeader, 0, 100); // rewrite the name area
650 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
651 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
652 strncpy(paxHeader + 345, prefix.string(), 155);
653
654 paxHeader[156] = 'x'; // mark it as a pax extended header
655
656 // [ 124 : 12 ] size of pax extended header data
657 memset(paxHeader + 124, 0, 12);
658 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
659
660 // Checksum and write the pax block header
661 calc_tar_checksum(paxHeader);
662 writer->WriteEntityData(paxHeader, 512);
663
664 // Now write the pax data itself
665 int paxblocks = (paxLen + 511) / 512;
666 writer->WriteEntityData(paxData, 512 * paxblocks);
667 }
668
669 // Checksum and write the 512-byte ustar file header block to the output
670 calc_tar_checksum(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700671 writer->WriteEntityData(buf, 512);
672
673 // Now write the file data itself, for real files. We honor tar's convention that
674 // only full 512-byte blocks are sent to write().
675 if (!isdir) {
676 off64_t toWrite = s.st_size;
677 while (toWrite > 0) {
678 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
679 ssize_t nRead = read(fd, buf, toRead);
680 if (nRead < 0) {
681 err = errno;
682 LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
683 err, strerror(err));
684 break;
685 } else if (nRead == 0) {
686 LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
687 filepath.string());
688 err = EIO;
689 break;
690 }
691
692 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
693 // depends on the OS guarantee that for ordinary files, read() will never return
694 // less than the number of bytes requested.
695 ssize_t partial = (nRead+512) % 512;
696 if (partial > 0) {
697 ssize_t remainder = 512 - partial;
698 memset(buf + nRead, 0, remainder);
699 nRead += remainder;
700 }
701 writer->WriteEntityData(buf, nRead);
702 toWrite -= nRead;
703 }
704 }
705
706cleanup:
707 delete [] buf;
708done:
709 close(fd);
710 return err;
711}
712// end tarfile
713
714
715
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700716#define RESTORE_BUF_SIZE (8*1024)
717
718RestoreHelperBase::RestoreHelperBase()
719{
720 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700721 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700722}
723
724RestoreHelperBase::~RestoreHelperBase()
725{
726 free(m_buf);
727}
728
729status_t
730RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
731{
732 ssize_t err;
733 size_t dataSize;
734 String8 key;
735 int fd;
736 void* buf = m_buf;
737 ssize_t amt;
738 int mode;
739 int crc;
740 struct stat st;
741 FileRec r;
742
743 err = in->ReadEntityHeader(&key, &dataSize);
744 if (err != NO_ERROR) {
745 return err;
746 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700747
Christopher Tatefbb92382009-06-23 17:35:11 -0700748 // Get the metadata block off the head of the file entity and use that to
749 // set up the output file
750 file_metadata_v1 metadata;
751 amt = in->ReadEntityData(&metadata, sizeof(metadata));
752 if (amt != sizeof(metadata)) {
753 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
754 (long)amt, strerror(errno));
755 return EIO;
756 }
757 metadata.version = fromlel(metadata.version);
758 metadata.mode = fromlel(metadata.mode);
759 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700760 if (!m_loggedUnknownMetadata) {
761 m_loggedUnknownMetadata = true;
762 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
763 metadata.version, CURRENT_METADATA_VERSION);
764 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700765 }
766 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700767
768 // Write the file and compute the crc
769 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700770 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
771 if (fd == -1) {
772 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700773 return errno;
774 }
775
776 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
777 err = write(fd, buf, amt);
778 if (err != amt) {
779 close(fd);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700780 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700781 return errno;
782 }
783 crc = crc32(crc, (Bytef*)buf, amt);
784 }
785
786 close(fd);
787
788 // Record for the snapshot
789 err = stat(filename.string(), &st);
790 if (err != 0) {
791 LOGW("Error stating file that we just created %s", filename.string());
792 return errno;
793 }
794
795 r.file = filename;
796 r.deleted = false;
797 r.s.modTime_sec = st.st_mtime;
798 r.s.modTime_nsec = 0; // workaround sim breakage
799 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700800 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700801 r.s.size = st.st_size;
802 r.s.crc32 = crc;
803
804 m_files.add(key, r);
805
806 return NO_ERROR;
807}
808
809status_t
810RestoreHelperBase::WriteSnapshot(int fd)
811{
812 return write_snapshot_file(fd, m_files);;
813}
814
Joe Onorato3ad977b2009-05-05 11:50:51 -0700815#if TEST_BACKUP_HELPERS
816
817#define SCRATCH_DIR "/data/backup_helper_test/"
818
819static int
820write_text_file(const char* path, const char* data)
821{
822 int amt;
823 int fd;
824 int len;
825
826 fd = creat(path, 0666);
827 if (fd == -1) {
828 fprintf(stderr, "creat %s failed\n", path);
829 return errno;
830 }
831
832 len = strlen(data);
833 amt = write(fd, data, len);
834 if (amt != len) {
835 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
836 return errno;
837 }
838
839 close(fd);
840
841 return 0;
842}
843
844static int
845compare_file(const char* path, const unsigned char* data, int len)
846{
847 int fd;
848 int amt;
849
850 fd = open(path, O_RDONLY);
851 if (fd == -1) {
852 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
853 return errno;
854 }
855
856 unsigned char* contents = (unsigned char*)malloc(len);
857 if (contents == NULL) {
858 fprintf(stderr, "malloc(%d) failed\n", len);
859 return ENOMEM;
860 }
861
862 bool sizesMatch = true;
863 amt = lseek(fd, 0, SEEK_END);
864 if (amt != len) {
865 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
866 sizesMatch = false;
867 }
868 lseek(fd, 0, SEEK_SET);
869
870 int readLen = amt < len ? amt : len;
871 amt = read(fd, contents, readLen);
872 if (amt != readLen) {
873 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
874 }
875
876 bool contentsMatch = true;
877 for (int i=0; i<readLen; i++) {
878 if (data[i] != contents[i]) {
879 if (contentsMatch) {
880 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
881 contentsMatch = false;
882 }
883 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
884 }
885 }
886
Christopher Tate63bcb792009-06-24 13:57:29 -0700887 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700888 return contentsMatch && sizesMatch ? 0 : 1;
889}
890
891int
892backup_helper_test_empty()
893{
894 int err;
895 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700896 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700897 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
898
899 system("rm -r " SCRATCH_DIR);
900 mkdir(SCRATCH_DIR, 0777);
901
902 // write
903 fd = creat(filename, 0666);
904 if (fd == -1) {
905 fprintf(stderr, "error creating %s\n", filename);
906 return 1;
907 }
908
909 err = write_snapshot_file(fd, snapshot);
910
911 close(fd);
912
913 if (err != 0) {
914 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
915 return err;
916 }
917
918 static const unsigned char correct_data[] = {
919 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
920 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
921 };
922
923 err = compare_file(filename, correct_data, sizeof(correct_data));
924 if (err != 0) {
925 return err;
926 }
927
928 // read
929 fd = open(filename, O_RDONLY);
930 if (fd == -1) {
931 fprintf(stderr, "error opening for read %s\n", filename);
932 return 1;
933 }
934
935 KeyedVector<String8,FileState> readSnapshot;
936 err = read_snapshot_file(fd, &readSnapshot);
937 if (err != 0) {
938 fprintf(stderr, "read_snapshot_file failed %d\n", err);
939 return err;
940 }
941
942 if (readSnapshot.size() != 0) {
943 fprintf(stderr, "readSnapshot should be length 0\n");
944 return 1;
945 }
946
947 return 0;
948}
949
950int
951backup_helper_test_four()
952{
953 int err;
954 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700955 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700956 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
957
958 system("rm -r " SCRATCH_DIR);
959 mkdir(SCRATCH_DIR, 0777);
960
961 // write
962 fd = creat(filename, 0666);
963 if (fd == -1) {
964 fprintf(stderr, "error opening %s\n", filename);
965 return 1;
966 }
967
968 String8 filenames[4];
969 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700970 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700971 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700972
973 states[0].modTime_sec = 0xfedcba98;
974 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700975 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700976 states[0].size = 0xababbcbc;
977 states[0].crc32 = 0x12345678;
978 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700979 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700980 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700981 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700982
983 states[1].modTime_sec = 0x93400031;
984 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700985 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700986 states[1].size = 0x88557766;
987 states[1].crc32 = 0x22334422;
988 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700989 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700990 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700991 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700992
993 states[2].modTime_sec = 0x33221144;
994 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700995 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700996 states[2].size = 0x11223344;
997 states[2].crc32 = 0x01122334;
998 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700999 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001000 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001001 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001002
1003 states[3].modTime_sec = 0x33221144;
1004 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001005 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001006 states[3].size = 0x11223344;
1007 states[3].crc32 = 0x01122334;
1008 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001009 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001010 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001011 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001012
1013 err = write_snapshot_file(fd, snapshot);
1014
1015 close(fd);
1016
1017 if (err != 0) {
1018 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1019 return err;
1020 }
1021
1022 static const unsigned char correct_data[] = {
1023 // header
1024 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001025 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001026
1027 // bytes_of_padding
1028 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001029 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1030 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1031 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1032 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001033
1034 // bytes_of_padding3
1035 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001036 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1037 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1038 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1039 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1040 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001041
Joe Onorato3ad977b2009-05-05 11:50:51 -07001042 // bytes of padding2
1043 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001044 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1045 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1046 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1047 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1048 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001049
Joe Onorato3ad977b2009-05-05 11:50:51 -07001050 // bytes of padding3
1051 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001052 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1053 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1054 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1055 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1056 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001057 };
1058
1059 err = compare_file(filename, correct_data, sizeof(correct_data));
1060 if (err != 0) {
1061 return err;
1062 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001063
Joe Onorato3ad977b2009-05-05 11:50:51 -07001064 // read
1065 fd = open(filename, O_RDONLY);
1066 if (fd == -1) {
1067 fprintf(stderr, "error opening for read %s\n", filename);
1068 return 1;
1069 }
1070
1071
1072 KeyedVector<String8,FileState> readSnapshot;
1073 err = read_snapshot_file(fd, &readSnapshot);
1074 if (err != 0) {
1075 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1076 return err;
1077 }
1078
1079 if (readSnapshot.size() != 4) {
1080 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1081 return 1;
1082 }
1083
1084 bool matched = true;
1085 for (size_t i=0; i<readSnapshot.size(); i++) {
1086 const String8& name = readSnapshot.keyAt(i);
1087 const FileState state = readSnapshot.valueAt(i);
1088
1089 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001090 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001091 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-06-23 13:03:00 -07001092 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1093 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1094 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1095 states[i].crc32, name.length(), filenames[i].string(),
1096 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1097 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001098 matched = false;
1099 }
1100 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001101
Joe Onorato3ad977b2009-05-05 11:50:51 -07001102 return matched ? 0 : 1;
1103}
1104
Joe Onorato4535e402009-05-15 09:07:06 -04001105// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1106const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001107 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1108 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1109 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1110 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001111 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1112 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001113 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1114 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001115 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001116 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001117 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1118 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001119 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001120 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1121 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001122 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001123 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1124 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1125 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001126 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1127
Joe Onorato4535e402009-05-15 09:07:06 -04001128};
1129const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1130
1131static int
1132test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1133{
1134 int err;
1135 String8 text(str);
1136
Joe Onorato4535e402009-05-15 09:07:06 -04001137 err = writer.WriteEntityHeader(text, text.length()+1);
1138 if (err != 0) {
1139 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1140 return err;
1141 }
1142
1143 err = writer.WriteEntityData(text.string(), text.length()+1);
1144 if (err != 0) {
1145 fprintf(stderr, "write failed for data '%s'\n", text.string());
1146 return errno;
1147 }
1148
1149 return err;
1150}
1151
1152int
1153backup_helper_test_data_writer()
1154{
1155 int err;
1156 int fd;
1157 const char* filename = SCRATCH_DIR "data_writer.data";
1158
1159 system("rm -r " SCRATCH_DIR);
1160 mkdir(SCRATCH_DIR, 0777);
1161 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001162
Joe Onorato4535e402009-05-15 09:07:06 -04001163 fd = creat(filename, 0666);
1164 if (fd == -1) {
1165 fprintf(stderr, "error creating: %s\n", strerror(errno));
1166 return errno;
1167 }
1168
1169 BackupDataWriter writer(fd);
1170
1171 err = 0;
1172 err |= test_write_header_and_entity(writer, "no_padding_");
1173 err |= test_write_header_and_entity(writer, "padded_to__3");
1174 err |= test_write_header_and_entity(writer, "padded_to_2__");
1175 err |= test_write_header_and_entity(writer, "padded_to1");
1176
Joe Onorato4535e402009-05-15 09:07:06 -04001177 close(fd);
1178
1179 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1180 if (err != 0) {
1181 return err;
1182 }
1183
1184 return err;
1185}
1186
Joe Onorato2e1da322009-05-15 18:20:19 -04001187int
1188test_read_header_and_entity(BackupDataReader& reader, const char* str)
1189{
1190 int err;
1191 int bufSize = strlen(str)+1;
1192 char* buf = (char*)malloc(bufSize);
1193 String8 string;
1194 int cookie = 0x11111111;
1195 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001196 bool done;
1197 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001198 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001199
1200 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1201
Joe Onorato5f15d152009-06-16 16:31:35 -04001202 err = reader.ReadNextHeader(&done, &type);
1203 if (done) {
1204 fprintf(stderr, "should not be done yet\n");
1205 goto finished;
1206 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001207 if (err != 0) {
1208 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001209 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001210 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001211 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001212 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001213 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001214 }
1215
1216 err = reader.ReadEntityHeader(&string, &actualSize);
1217 if (err != 0) {
1218 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001219 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001220 }
1221 if (string != str) {
1222 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1223 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001224 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001225 }
1226 if ((int)actualSize != bufSize) {
1227 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1228 actualSize);
1229 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001230 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001231 }
1232
Christopher Tate11b15772009-06-23 13:03:00 -07001233 nRead = reader.ReadEntityData(buf, bufSize);
1234 if (nRead < 0) {
1235 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001236 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001237 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001238 }
1239
1240 if (0 != memcmp(buf, str, bufSize)) {
1241 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001242 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1243 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001244 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001245 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001246 }
1247
1248 // The next read will confirm whether it got the right amount of data.
1249
Joe Onorato5f15d152009-06-16 16:31:35 -04001250finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001251 if (err != NO_ERROR) {
1252 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1253 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001254 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001255 return err;
1256}
1257
1258int
1259backup_helper_test_data_reader()
1260{
1261 int err;
1262 int fd;
1263 const char* filename = SCRATCH_DIR "data_reader.data";
1264
1265 system("rm -r " SCRATCH_DIR);
1266 mkdir(SCRATCH_DIR, 0777);
1267 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001268
Joe Onorato2e1da322009-05-15 18:20:19 -04001269 fd = creat(filename, 0666);
1270 if (fd == -1) {
1271 fprintf(stderr, "error creating: %s\n", strerror(errno));
1272 return errno;
1273 }
1274
1275 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1276 if (err != DATA_GOLDEN_FILE_SIZE) {
1277 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1278 return errno;
1279 }
1280
1281 close(fd);
1282
1283 fd = open(filename, O_RDONLY);
1284 if (fd == -1) {
1285 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1286 filename);
1287 return errno;
1288 }
1289
1290 {
1291 BackupDataReader reader(fd);
1292
1293 err = 0;
1294
1295 if (err == NO_ERROR) {
1296 err = test_read_header_and_entity(reader, "no_padding_");
1297 }
1298
1299 if (err == NO_ERROR) {
1300 err = test_read_header_and_entity(reader, "padded_to__3");
1301 }
1302
1303 if (err == NO_ERROR) {
1304 err = test_read_header_and_entity(reader, "padded_to_2__");
1305 }
1306
1307 if (err == NO_ERROR) {
1308 err = test_read_header_and_entity(reader, "padded_to1");
1309 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001310 }
1311
1312 close(fd);
1313
1314 return err;
1315}
1316
Joe Onorato3ad977b2009-05-05 11:50:51 -07001317static int
1318get_mod_time(const char* filename, struct timeval times[2])
1319{
1320 int err;
1321 struct stat64 st;
1322 err = stat64(filename, &st);
1323 if (err != 0) {
1324 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1325 return errno;
1326 }
1327 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001328 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001329
1330 // If st_atime is a macro then struct stat64 uses struct timespec
1331 // to store the access and modif time values and typically
1332 // st_*time_nsec is not defined. In glibc, this is controlled by
1333 // __USE_MISC.
1334#ifdef __USE_MISC
1335#if !defined(st_atime) || defined(st_atime_nsec)
1336#error "Check if this __USE_MISC conditional is still needed."
1337#endif
1338 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1339 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1340#else
1341 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001342 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001343#endif
1344
Joe Onorato3ad977b2009-05-05 11:50:51 -07001345 return 0;
1346}
1347
1348int
1349backup_helper_test_files()
1350{
1351 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001352 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001353 int dataStreamFD;
1354 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001355
1356 system("rm -r " SCRATCH_DIR);
1357 mkdir(SCRATCH_DIR, 0777);
1358 mkdir(SCRATCH_DIR "data", 0777);
1359
1360 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1361 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1362 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1363 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1364 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1365 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1366
1367 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001368 SCRATCH_DIR "data/b",
1369 SCRATCH_DIR "data/c",
1370 SCRATCH_DIR "data/d",
1371 SCRATCH_DIR "data/e",
1372 SCRATCH_DIR "data/f"
1373 };
1374
1375 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001376 "data/b",
1377 "data/c",
1378 "data/d",
1379 "data/e",
1380 "data/f"
1381 };
1382
Joe Onorato4535e402009-05-15 09:07:06 -04001383 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1384 if (dataStreamFD == -1) {
1385 fprintf(stderr, "error creating: %s\n", strerror(errno));
1386 return errno;
1387 }
1388
Joe Onorato3ad977b2009-05-05 11:50:51 -07001389 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1390 if (newSnapshotFD == -1) {
1391 fprintf(stderr, "error creating: %s\n", strerror(errno));
1392 return errno;
1393 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001394
1395 {
1396 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001397
Joe Onorato23ecae32009-06-10 17:07:15 -07001398 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001399 if (err != 0) {
1400 return err;
1401 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001402 }
1403
Joe Onorato4535e402009-05-15 09:07:06 -04001404 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001405 close(newSnapshotFD);
1406
1407 sleep(3);
1408
1409 struct timeval d_times[2];
1410 struct timeval e_times[2];
1411
1412 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1413 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1414 if (err != 0) {
1415 return err;
1416 }
1417
1418 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1419 unlink(SCRATCH_DIR "data/c");
1420 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1421 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1422 utimes(SCRATCH_DIR "data/d", d_times);
1423 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1424 utimes(SCRATCH_DIR "data/e", e_times);
1425 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1426 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001427
Joe Onorato3ad977b2009-05-05 11:50:51 -07001428 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001429 SCRATCH_DIR "data/a", // added
1430 SCRATCH_DIR "data/b", // same
1431 SCRATCH_DIR "data/c", // different mod time
1432 SCRATCH_DIR "data/d", // different size (same mod time)
1433 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1434 SCRATCH_DIR "data/g" // added
1435 };
1436
1437 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001438 "data/a", // added
1439 "data/b", // same
1440 "data/c", // different mod time
1441 "data/d", // different size (same mod time)
1442 "data/e", // different contents (same mod time, same size)
1443 "data/g" // added
1444 };
1445
1446 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1447 if (oldSnapshotFD == -1) {
1448 fprintf(stderr, "error opening: %s\n", strerror(errno));
1449 return errno;
1450 }
1451
Joe Onorato4535e402009-05-15 09:07:06 -04001452 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1453 if (dataStreamFD == -1) {
1454 fprintf(stderr, "error creating: %s\n", strerror(errno));
1455 return errno;
1456 }
1457
Joe Onorato3ad977b2009-05-05 11:50:51 -07001458 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1459 if (newSnapshotFD == -1) {
1460 fprintf(stderr, "error creating: %s\n", strerror(errno));
1461 return errno;
1462 }
1463
Joe Onoratod2110db2009-05-19 13:41:21 -07001464 {
1465 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001466
Joe Onorato23ecae32009-06-10 17:07:15 -07001467 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001468 if (err != 0) {
1469 return err;
1470 }
1471}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001472
1473 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001474 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001475 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001476
Joe Onorato3ad977b2009-05-05 11:50:51 -07001477 return 0;
1478}
1479
Joe Onorato23ecae32009-06-10 17:07:15 -07001480int
1481backup_helper_test_null_base()
1482{
1483 int err;
1484 int oldSnapshotFD;
1485 int dataStreamFD;
1486 int newSnapshotFD;
1487
1488 system("rm -r " SCRATCH_DIR);
1489 mkdir(SCRATCH_DIR, 0777);
1490 mkdir(SCRATCH_DIR "data", 0777);
1491
1492 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1493
1494 char const* files[] = {
1495 SCRATCH_DIR "data/a",
1496 };
1497
1498 char const* keys[] = {
1499 "a",
1500 };
1501
1502 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1503 if (dataStreamFD == -1) {
1504 fprintf(stderr, "error creating: %s\n", strerror(errno));
1505 return errno;
1506 }
1507
1508 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1509 if (newSnapshotFD == -1) {
1510 fprintf(stderr, "error creating: %s\n", strerror(errno));
1511 return errno;
1512 }
1513
1514 {
1515 BackupDataWriter dataStream(dataStreamFD);
1516
1517 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1518 if (err != 0) {
1519 return err;
1520 }
1521 }
1522
1523 close(dataStreamFD);
1524 close(newSnapshotFD);
1525
1526 return 0;
1527}
1528
Joe Onoratoce88cb12009-06-11 11:27:16 -07001529int
1530backup_helper_test_missing_file()
1531{
1532 int err;
1533 int oldSnapshotFD;
1534 int dataStreamFD;
1535 int newSnapshotFD;
1536
1537 system("rm -r " SCRATCH_DIR);
1538 mkdir(SCRATCH_DIR, 0777);
1539 mkdir(SCRATCH_DIR "data", 0777);
1540
1541 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1542
1543 char const* files[] = {
1544 SCRATCH_DIR "data/a",
1545 SCRATCH_DIR "data/b",
1546 SCRATCH_DIR "data/c",
1547 };
1548
1549 char const* keys[] = {
1550 "a",
1551 "b",
1552 "c",
1553 };
1554
1555 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1556 if (dataStreamFD == -1) {
1557 fprintf(stderr, "error creating: %s\n", strerror(errno));
1558 return errno;
1559 }
1560
1561 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1562 if (newSnapshotFD == -1) {
1563 fprintf(stderr, "error creating: %s\n", strerror(errno));
1564 return errno;
1565 }
1566
1567 {
1568 BackupDataWriter dataStream(dataStreamFD);
1569
1570 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1571 if (err != 0) {
1572 return err;
1573 }
1574 }
1575
1576 close(dataStreamFD);
1577 close(newSnapshotFD);
1578
1579 return 0;
1580}
1581
Joe Onorato23ecae32009-06-10 17:07:15 -07001582
Joe Onorato3ad977b2009-05-05 11:50:51 -07001583#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001584
1585}