blob: e15875f380b7731a8b66f121e4fe0a2340ec076a [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
506 int err = 0;
507 struct stat64 s;
508 if (lstat64(filepath.string(), &s) != 0) {
509 err = errno;
510 LOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
511 return err;
512 }
513
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700514 String8 fullname; // for pax later on
515 String8 prefix;
516
Christopher Tate4a627c72011-04-01 14:43:32 -0700517 const int isdir = S_ISDIR(s.st_mode);
518
519 // !!! TODO: use mmap when possible to avoid churning the buffer cache
520 // !!! TODO: this will break with symlinks; need to use readlink(2)
521 int fd = open(filepath.string(), O_RDONLY);
522 if (fd < 0) {
523 err = errno;
524 LOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
525 return err;
526 }
527
528 // read/write up to this much at a time.
529 const size_t BUFSIZE = 32 * 1024;
Christopher Tate4a627c72011-04-01 14:43:32 -0700530 char* buf = new char[BUFSIZE];
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700531 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
532 char* paxData = buf + 1024;
533
Christopher Tate4a627c72011-04-01 14:43:32 -0700534 if (buf == NULL) {
535 LOGE("Out of mem allocating transfer buffer");
536 err = ENOMEM;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700537 goto cleanup;
Christopher Tate4a627c72011-04-01 14:43:32 -0700538 }
539
540 // Good to go -- first construct the standard tar header at the start of the buffer
Christopher Tatedc92c822011-05-13 15:38:02 -0700541 memset(buf, 0, BUFSIZE);
Christopher Tate4a627c72011-04-01 14:43:32 -0700542
543 // Magic fields for the ustar file format
544 strcat(buf + 257, "ustar");
545 strcat(buf + 263, "00");
546
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700547 // [ 265 : 32 ] user name, ignored on restore
548 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700549
550 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700551 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700552
553 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
554 // [ 116 : 8 ] gid -- ignored in Android format
555 snprintf(buf + 108, 8, "0%lo", s.st_uid);
556 snprintf(buf + 116, 8, "0%lo", s.st_gid);
557
558 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700559 if (s.st_size > 077777777777LL) {
560 // very large files need a pax extended size header
561 needExtended = true;
562 }
563 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700564
565 // [ 136 : 12 ] last mod time as a UTC time_t
566 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
567
Christopher Tate4a627c72011-04-01 14:43:32 -0700568 // [ 156 : 1 ] link/file type
569 uint8_t type;
570 if (isdir) {
571 type = '5'; // tar magic: '5' == directory
572 } else if (S_ISREG(s.st_mode)) {
573 type = '0'; // tar magic: '0' == normal file
574 } else {
575 LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
576 goto cleanup;
577 }
578 buf[156] = type;
579
580 // [ 157 : 100 ] name of linked file [not implemented]
581
Christopher Tate4a627c72011-04-01 14:43:32 -0700582 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700583 // Prefix and main relative path. Path lengths have been preflighted.
584 if (packageName.length() > 0) {
585 prefix = "apps/";
586 prefix += packageName;
587 }
588 if (domain.length() > 0) {
589 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700590 }
591
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700592 // pax extended means we don't put in a prefix field, and put a different
593 // string in the basic name field. We can also construct the full path name
594 // out of the substrings we've now built.
595 fullname = prefix;
596 fullname.appendPath(relpath);
597
598 // ustar:
599 // [ 0 : 100 ]; file name/path
600 // [ 345 : 155 ] filename path prefix
601 // We only use the prefix area if fullname won't fit in the path
602 if (fullname.length() > 100) {
603 strncpy(buf, relpath.string(), 100);
604 strncpy(buf + 345, prefix.string(), 155);
605 } else {
606 strncpy(buf, fullname.string(), 100);
607 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700608 }
609
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700610 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
611
612 LOGI(" Name: %s", fullname.string());
613
614 // If we're using a pax extended header, build & write that here; lengths are
615 // already preflighted
616 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700617 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
618 char* p = paxData;
619
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700620 // construct the pax extended header data block
621 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700622 int len;
623
624 // size header -- calc len in digits by actually rendering the number
625 // to a string - brute force but simple
Christopher Tatedc92c822011-05-13 15:38:02 -0700626 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
627 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700628
629 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700630 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700631
632 // Now we know how big the pax data is
633 int paxLen = p - paxData;
634
635 // Now build the pax *header* templated on the ustar header
636 memcpy(paxHeader, buf, 512);
637
638 String8 leaf = fullname.getPathLeaf();
639 memset(paxHeader, 0, 100); // rewrite the name area
640 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
641 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
642 strncpy(paxHeader + 345, prefix.string(), 155);
643
644 paxHeader[156] = 'x'; // mark it as a pax extended header
645
646 // [ 124 : 12 ] size of pax extended header data
647 memset(paxHeader + 124, 0, 12);
648 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
649
650 // Checksum and write the pax block header
651 calc_tar_checksum(paxHeader);
652 writer->WriteEntityData(paxHeader, 512);
653
654 // Now write the pax data itself
655 int paxblocks = (paxLen + 511) / 512;
656 writer->WriteEntityData(paxData, 512 * paxblocks);
657 }
658
659 // Checksum and write the 512-byte ustar file header block to the output
660 calc_tar_checksum(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700661 writer->WriteEntityData(buf, 512);
662
663 // Now write the file data itself, for real files. We honor tar's convention that
664 // only full 512-byte blocks are sent to write().
665 if (!isdir) {
666 off64_t toWrite = s.st_size;
667 while (toWrite > 0) {
668 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
669 ssize_t nRead = read(fd, buf, toRead);
670 if (nRead < 0) {
671 err = errno;
672 LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
673 err, strerror(err));
674 break;
675 } else if (nRead == 0) {
676 LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
677 filepath.string());
678 err = EIO;
679 break;
680 }
681
682 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
683 // depends on the OS guarantee that for ordinary files, read() will never return
684 // less than the number of bytes requested.
685 ssize_t partial = (nRead+512) % 512;
686 if (partial > 0) {
687 ssize_t remainder = 512 - partial;
688 memset(buf + nRead, 0, remainder);
689 nRead += remainder;
690 }
691 writer->WriteEntityData(buf, nRead);
692 toWrite -= nRead;
693 }
694 }
695
696cleanup:
697 delete [] buf;
698done:
699 close(fd);
700 return err;
701}
702// end tarfile
703
704
705
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700706#define RESTORE_BUF_SIZE (8*1024)
707
708RestoreHelperBase::RestoreHelperBase()
709{
710 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700711 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700712}
713
714RestoreHelperBase::~RestoreHelperBase()
715{
716 free(m_buf);
717}
718
719status_t
720RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
721{
722 ssize_t err;
723 size_t dataSize;
724 String8 key;
725 int fd;
726 void* buf = m_buf;
727 ssize_t amt;
728 int mode;
729 int crc;
730 struct stat st;
731 FileRec r;
732
733 err = in->ReadEntityHeader(&key, &dataSize);
734 if (err != NO_ERROR) {
735 return err;
736 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700737
Christopher Tatefbb92382009-06-23 17:35:11 -0700738 // Get the metadata block off the head of the file entity and use that to
739 // set up the output file
740 file_metadata_v1 metadata;
741 amt = in->ReadEntityData(&metadata, sizeof(metadata));
742 if (amt != sizeof(metadata)) {
743 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
744 (long)amt, strerror(errno));
745 return EIO;
746 }
747 metadata.version = fromlel(metadata.version);
748 metadata.mode = fromlel(metadata.mode);
749 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700750 if (!m_loggedUnknownMetadata) {
751 m_loggedUnknownMetadata = true;
752 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
753 metadata.version, CURRENT_METADATA_VERSION);
754 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700755 }
756 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700757
758 // Write the file and compute the crc
759 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700760 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
761 if (fd == -1) {
762 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700763 return errno;
764 }
765
766 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
767 err = write(fd, buf, amt);
768 if (err != amt) {
769 close(fd);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700770 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700771 return errno;
772 }
773 crc = crc32(crc, (Bytef*)buf, amt);
774 }
775
776 close(fd);
777
778 // Record for the snapshot
779 err = stat(filename.string(), &st);
780 if (err != 0) {
781 LOGW("Error stating file that we just created %s", filename.string());
782 return errno;
783 }
784
785 r.file = filename;
786 r.deleted = false;
787 r.s.modTime_sec = st.st_mtime;
788 r.s.modTime_nsec = 0; // workaround sim breakage
789 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700790 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700791 r.s.size = st.st_size;
792 r.s.crc32 = crc;
793
794 m_files.add(key, r);
795
796 return NO_ERROR;
797}
798
799status_t
800RestoreHelperBase::WriteSnapshot(int fd)
801{
802 return write_snapshot_file(fd, m_files);;
803}
804
Joe Onorato3ad977b2009-05-05 11:50:51 -0700805#if TEST_BACKUP_HELPERS
806
807#define SCRATCH_DIR "/data/backup_helper_test/"
808
809static int
810write_text_file(const char* path, const char* data)
811{
812 int amt;
813 int fd;
814 int len;
815
816 fd = creat(path, 0666);
817 if (fd == -1) {
818 fprintf(stderr, "creat %s failed\n", path);
819 return errno;
820 }
821
822 len = strlen(data);
823 amt = write(fd, data, len);
824 if (amt != len) {
825 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
826 return errno;
827 }
828
829 close(fd);
830
831 return 0;
832}
833
834static int
835compare_file(const char* path, const unsigned char* data, int len)
836{
837 int fd;
838 int amt;
839
840 fd = open(path, O_RDONLY);
841 if (fd == -1) {
842 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
843 return errno;
844 }
845
846 unsigned char* contents = (unsigned char*)malloc(len);
847 if (contents == NULL) {
848 fprintf(stderr, "malloc(%d) failed\n", len);
849 return ENOMEM;
850 }
851
852 bool sizesMatch = true;
853 amt = lseek(fd, 0, SEEK_END);
854 if (amt != len) {
855 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
856 sizesMatch = false;
857 }
858 lseek(fd, 0, SEEK_SET);
859
860 int readLen = amt < len ? amt : len;
861 amt = read(fd, contents, readLen);
862 if (amt != readLen) {
863 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
864 }
865
866 bool contentsMatch = true;
867 for (int i=0; i<readLen; i++) {
868 if (data[i] != contents[i]) {
869 if (contentsMatch) {
870 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
871 contentsMatch = false;
872 }
873 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
874 }
875 }
876
Christopher Tate63bcb792009-06-24 13:57:29 -0700877 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700878 return contentsMatch && sizesMatch ? 0 : 1;
879}
880
881int
882backup_helper_test_empty()
883{
884 int err;
885 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700886 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700887 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
888
889 system("rm -r " SCRATCH_DIR);
890 mkdir(SCRATCH_DIR, 0777);
891
892 // write
893 fd = creat(filename, 0666);
894 if (fd == -1) {
895 fprintf(stderr, "error creating %s\n", filename);
896 return 1;
897 }
898
899 err = write_snapshot_file(fd, snapshot);
900
901 close(fd);
902
903 if (err != 0) {
904 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
905 return err;
906 }
907
908 static const unsigned char correct_data[] = {
909 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
910 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
911 };
912
913 err = compare_file(filename, correct_data, sizeof(correct_data));
914 if (err != 0) {
915 return err;
916 }
917
918 // read
919 fd = open(filename, O_RDONLY);
920 if (fd == -1) {
921 fprintf(stderr, "error opening for read %s\n", filename);
922 return 1;
923 }
924
925 KeyedVector<String8,FileState> readSnapshot;
926 err = read_snapshot_file(fd, &readSnapshot);
927 if (err != 0) {
928 fprintf(stderr, "read_snapshot_file failed %d\n", err);
929 return err;
930 }
931
932 if (readSnapshot.size() != 0) {
933 fprintf(stderr, "readSnapshot should be length 0\n");
934 return 1;
935 }
936
937 return 0;
938}
939
940int
941backup_helper_test_four()
942{
943 int err;
944 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700945 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700946 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
947
948 system("rm -r " SCRATCH_DIR);
949 mkdir(SCRATCH_DIR, 0777);
950
951 // write
952 fd = creat(filename, 0666);
953 if (fd == -1) {
954 fprintf(stderr, "error opening %s\n", filename);
955 return 1;
956 }
957
958 String8 filenames[4];
959 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700960 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700961 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700962
963 states[0].modTime_sec = 0xfedcba98;
964 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700965 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700966 states[0].size = 0xababbcbc;
967 states[0].crc32 = 0x12345678;
968 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700969 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700970 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700971 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700972
973 states[1].modTime_sec = 0x93400031;
974 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700975 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700976 states[1].size = 0x88557766;
977 states[1].crc32 = 0x22334422;
978 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700979 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700980 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700981 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700982
983 states[2].modTime_sec = 0x33221144;
984 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700985 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700986 states[2].size = 0x11223344;
987 states[2].crc32 = 0x01122334;
988 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700989 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700990 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700991 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700992
993 states[3].modTime_sec = 0x33221144;
994 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700995 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -0700996 states[3].size = 0x11223344;
997 states[3].crc32 = 0x01122334;
998 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700999 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001000 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001001 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001002
1003 err = write_snapshot_file(fd, snapshot);
1004
1005 close(fd);
1006
1007 if (err != 0) {
1008 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1009 return err;
1010 }
1011
1012 static const unsigned char correct_data[] = {
1013 // header
1014 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001015 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001016
1017 // bytes_of_padding
1018 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001019 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1020 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1021 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1022 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001023
1024 // bytes_of_padding3
1025 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001026 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1027 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1028 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1029 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1030 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001031
Joe Onorato3ad977b2009-05-05 11:50:51 -07001032 // bytes of padding2
1033 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001034 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1035 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1036 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1037 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1038 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001039
Joe Onorato3ad977b2009-05-05 11:50:51 -07001040 // bytes of padding3
1041 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001042 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1043 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1044 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1045 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1046 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001047 };
1048
1049 err = compare_file(filename, correct_data, sizeof(correct_data));
1050 if (err != 0) {
1051 return err;
1052 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001053
Joe Onorato3ad977b2009-05-05 11:50:51 -07001054 // read
1055 fd = open(filename, O_RDONLY);
1056 if (fd == -1) {
1057 fprintf(stderr, "error opening for read %s\n", filename);
1058 return 1;
1059 }
1060
1061
1062 KeyedVector<String8,FileState> readSnapshot;
1063 err = read_snapshot_file(fd, &readSnapshot);
1064 if (err != 0) {
1065 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1066 return err;
1067 }
1068
1069 if (readSnapshot.size() != 4) {
1070 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1071 return 1;
1072 }
1073
1074 bool matched = true;
1075 for (size_t i=0; i<readSnapshot.size(); i++) {
1076 const String8& name = readSnapshot.keyAt(i);
1077 const FileState state = readSnapshot.valueAt(i);
1078
1079 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001080 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001081 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-06-23 13:03:00 -07001082 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1083 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1084 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1085 states[i].crc32, name.length(), filenames[i].string(),
1086 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1087 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001088 matched = false;
1089 }
1090 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001091
Joe Onorato3ad977b2009-05-05 11:50:51 -07001092 return matched ? 0 : 1;
1093}
1094
Joe Onorato4535e402009-05-15 09:07:06 -04001095// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1096const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001097 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1098 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1099 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1100 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001101 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1102 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001103 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1104 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001105 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001106 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001107 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1108 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001109 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001110 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1111 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001112 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001113 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1114 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1115 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001116 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1117
Joe Onorato4535e402009-05-15 09:07:06 -04001118};
1119const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1120
1121static int
1122test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1123{
1124 int err;
1125 String8 text(str);
1126
Joe Onorato4535e402009-05-15 09:07:06 -04001127 err = writer.WriteEntityHeader(text, text.length()+1);
1128 if (err != 0) {
1129 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1130 return err;
1131 }
1132
1133 err = writer.WriteEntityData(text.string(), text.length()+1);
1134 if (err != 0) {
1135 fprintf(stderr, "write failed for data '%s'\n", text.string());
1136 return errno;
1137 }
1138
1139 return err;
1140}
1141
1142int
1143backup_helper_test_data_writer()
1144{
1145 int err;
1146 int fd;
1147 const char* filename = SCRATCH_DIR "data_writer.data";
1148
1149 system("rm -r " SCRATCH_DIR);
1150 mkdir(SCRATCH_DIR, 0777);
1151 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001152
Joe Onorato4535e402009-05-15 09:07:06 -04001153 fd = creat(filename, 0666);
1154 if (fd == -1) {
1155 fprintf(stderr, "error creating: %s\n", strerror(errno));
1156 return errno;
1157 }
1158
1159 BackupDataWriter writer(fd);
1160
1161 err = 0;
1162 err |= test_write_header_and_entity(writer, "no_padding_");
1163 err |= test_write_header_and_entity(writer, "padded_to__3");
1164 err |= test_write_header_and_entity(writer, "padded_to_2__");
1165 err |= test_write_header_and_entity(writer, "padded_to1");
1166
Joe Onorato4535e402009-05-15 09:07:06 -04001167 close(fd);
1168
1169 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1170 if (err != 0) {
1171 return err;
1172 }
1173
1174 return err;
1175}
1176
Joe Onorato2e1da322009-05-15 18:20:19 -04001177int
1178test_read_header_and_entity(BackupDataReader& reader, const char* str)
1179{
1180 int err;
1181 int bufSize = strlen(str)+1;
1182 char* buf = (char*)malloc(bufSize);
1183 String8 string;
1184 int cookie = 0x11111111;
1185 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001186 bool done;
1187 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001188 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001189
1190 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1191
Joe Onorato5f15d152009-06-16 16:31:35 -04001192 err = reader.ReadNextHeader(&done, &type);
1193 if (done) {
1194 fprintf(stderr, "should not be done yet\n");
1195 goto finished;
1196 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001197 if (err != 0) {
1198 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001199 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001200 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001201 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001202 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001203 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001204 }
1205
1206 err = reader.ReadEntityHeader(&string, &actualSize);
1207 if (err != 0) {
1208 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001209 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001210 }
1211 if (string != str) {
1212 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1213 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001214 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001215 }
1216 if ((int)actualSize != bufSize) {
1217 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1218 actualSize);
1219 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001220 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001221 }
1222
Christopher Tate11b15772009-06-23 13:03:00 -07001223 nRead = reader.ReadEntityData(buf, bufSize);
1224 if (nRead < 0) {
1225 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001227 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001228 }
1229
1230 if (0 != memcmp(buf, str, bufSize)) {
1231 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001232 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1233 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001234 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001235 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001236 }
1237
1238 // The next read will confirm whether it got the right amount of data.
1239
Joe Onorato5f15d152009-06-16 16:31:35 -04001240finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001241 if (err != NO_ERROR) {
1242 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1243 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001244 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001245 return err;
1246}
1247
1248int
1249backup_helper_test_data_reader()
1250{
1251 int err;
1252 int fd;
1253 const char* filename = SCRATCH_DIR "data_reader.data";
1254
1255 system("rm -r " SCRATCH_DIR);
1256 mkdir(SCRATCH_DIR, 0777);
1257 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001258
Joe Onorato2e1da322009-05-15 18:20:19 -04001259 fd = creat(filename, 0666);
1260 if (fd == -1) {
1261 fprintf(stderr, "error creating: %s\n", strerror(errno));
1262 return errno;
1263 }
1264
1265 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1266 if (err != DATA_GOLDEN_FILE_SIZE) {
1267 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1268 return errno;
1269 }
1270
1271 close(fd);
1272
1273 fd = open(filename, O_RDONLY);
1274 if (fd == -1) {
1275 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1276 filename);
1277 return errno;
1278 }
1279
1280 {
1281 BackupDataReader reader(fd);
1282
1283 err = 0;
1284
1285 if (err == NO_ERROR) {
1286 err = test_read_header_and_entity(reader, "no_padding_");
1287 }
1288
1289 if (err == NO_ERROR) {
1290 err = test_read_header_and_entity(reader, "padded_to__3");
1291 }
1292
1293 if (err == NO_ERROR) {
1294 err = test_read_header_and_entity(reader, "padded_to_2__");
1295 }
1296
1297 if (err == NO_ERROR) {
1298 err = test_read_header_and_entity(reader, "padded_to1");
1299 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001300 }
1301
1302 close(fd);
1303
1304 return err;
1305}
1306
Joe Onorato3ad977b2009-05-05 11:50:51 -07001307static int
1308get_mod_time(const char* filename, struct timeval times[2])
1309{
1310 int err;
1311 struct stat64 st;
1312 err = stat64(filename, &st);
1313 if (err != 0) {
1314 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1315 return errno;
1316 }
1317 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001318 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001319
1320 // If st_atime is a macro then struct stat64 uses struct timespec
1321 // to store the access and modif time values and typically
1322 // st_*time_nsec is not defined. In glibc, this is controlled by
1323 // __USE_MISC.
1324#ifdef __USE_MISC
1325#if !defined(st_atime) || defined(st_atime_nsec)
1326#error "Check if this __USE_MISC conditional is still needed."
1327#endif
1328 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1329 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1330#else
1331 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001332 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001333#endif
1334
Joe Onorato3ad977b2009-05-05 11:50:51 -07001335 return 0;
1336}
1337
1338int
1339backup_helper_test_files()
1340{
1341 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001342 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001343 int dataStreamFD;
1344 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001345
1346 system("rm -r " SCRATCH_DIR);
1347 mkdir(SCRATCH_DIR, 0777);
1348 mkdir(SCRATCH_DIR "data", 0777);
1349
1350 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1351 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1352 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1353 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1354 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1355 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1356
1357 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001358 SCRATCH_DIR "data/b",
1359 SCRATCH_DIR "data/c",
1360 SCRATCH_DIR "data/d",
1361 SCRATCH_DIR "data/e",
1362 SCRATCH_DIR "data/f"
1363 };
1364
1365 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001366 "data/b",
1367 "data/c",
1368 "data/d",
1369 "data/e",
1370 "data/f"
1371 };
1372
Joe Onorato4535e402009-05-15 09:07:06 -04001373 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1374 if (dataStreamFD == -1) {
1375 fprintf(stderr, "error creating: %s\n", strerror(errno));
1376 return errno;
1377 }
1378
Joe Onorato3ad977b2009-05-05 11:50:51 -07001379 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1380 if (newSnapshotFD == -1) {
1381 fprintf(stderr, "error creating: %s\n", strerror(errno));
1382 return errno;
1383 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001384
1385 {
1386 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001387
Joe Onorato23ecae32009-06-10 17:07:15 -07001388 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001389 if (err != 0) {
1390 return err;
1391 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001392 }
1393
Joe Onorato4535e402009-05-15 09:07:06 -04001394 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001395 close(newSnapshotFD);
1396
1397 sleep(3);
1398
1399 struct timeval d_times[2];
1400 struct timeval e_times[2];
1401
1402 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1403 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1404 if (err != 0) {
1405 return err;
1406 }
1407
1408 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1409 unlink(SCRATCH_DIR "data/c");
1410 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1411 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1412 utimes(SCRATCH_DIR "data/d", d_times);
1413 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1414 utimes(SCRATCH_DIR "data/e", e_times);
1415 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1416 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001417
Joe Onorato3ad977b2009-05-05 11:50:51 -07001418 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001419 SCRATCH_DIR "data/a", // added
1420 SCRATCH_DIR "data/b", // same
1421 SCRATCH_DIR "data/c", // different mod time
1422 SCRATCH_DIR "data/d", // different size (same mod time)
1423 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1424 SCRATCH_DIR "data/g" // added
1425 };
1426
1427 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001428 "data/a", // added
1429 "data/b", // same
1430 "data/c", // different mod time
1431 "data/d", // different size (same mod time)
1432 "data/e", // different contents (same mod time, same size)
1433 "data/g" // added
1434 };
1435
1436 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1437 if (oldSnapshotFD == -1) {
1438 fprintf(stderr, "error opening: %s\n", strerror(errno));
1439 return errno;
1440 }
1441
Joe Onorato4535e402009-05-15 09:07:06 -04001442 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1443 if (dataStreamFD == -1) {
1444 fprintf(stderr, "error creating: %s\n", strerror(errno));
1445 return errno;
1446 }
1447
Joe Onorato3ad977b2009-05-05 11:50:51 -07001448 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1449 if (newSnapshotFD == -1) {
1450 fprintf(stderr, "error creating: %s\n", strerror(errno));
1451 return errno;
1452 }
1453
Joe Onoratod2110db2009-05-19 13:41:21 -07001454 {
1455 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001456
Joe Onorato23ecae32009-06-10 17:07:15 -07001457 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001458 if (err != 0) {
1459 return err;
1460 }
1461}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001462
1463 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001464 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001465 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001466
Joe Onorato3ad977b2009-05-05 11:50:51 -07001467 return 0;
1468}
1469
Joe Onorato23ecae32009-06-10 17:07:15 -07001470int
1471backup_helper_test_null_base()
1472{
1473 int err;
1474 int oldSnapshotFD;
1475 int dataStreamFD;
1476 int newSnapshotFD;
1477
1478 system("rm -r " SCRATCH_DIR);
1479 mkdir(SCRATCH_DIR, 0777);
1480 mkdir(SCRATCH_DIR "data", 0777);
1481
1482 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1483
1484 char const* files[] = {
1485 SCRATCH_DIR "data/a",
1486 };
1487
1488 char const* keys[] = {
1489 "a",
1490 };
1491
1492 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1493 if (dataStreamFD == -1) {
1494 fprintf(stderr, "error creating: %s\n", strerror(errno));
1495 return errno;
1496 }
1497
1498 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1499 if (newSnapshotFD == -1) {
1500 fprintf(stderr, "error creating: %s\n", strerror(errno));
1501 return errno;
1502 }
1503
1504 {
1505 BackupDataWriter dataStream(dataStreamFD);
1506
1507 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1508 if (err != 0) {
1509 return err;
1510 }
1511 }
1512
1513 close(dataStreamFD);
1514 close(newSnapshotFD);
1515
1516 return 0;
1517}
1518
Joe Onoratoce88cb12009-06-11 11:27:16 -07001519int
1520backup_helper_test_missing_file()
1521{
1522 int err;
1523 int oldSnapshotFD;
1524 int dataStreamFD;
1525 int newSnapshotFD;
1526
1527 system("rm -r " SCRATCH_DIR);
1528 mkdir(SCRATCH_DIR, 0777);
1529 mkdir(SCRATCH_DIR "data", 0777);
1530
1531 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1532
1533 char const* files[] = {
1534 SCRATCH_DIR "data/a",
1535 SCRATCH_DIR "data/b",
1536 SCRATCH_DIR "data/c",
1537 };
1538
1539 char const* keys[] = {
1540 "a",
1541 "b",
1542 "c",
1543 };
1544
1545 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1546 if (dataStreamFD == -1) {
1547 fprintf(stderr, "error creating: %s\n", strerror(errno));
1548 return errno;
1549 }
1550
1551 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1552 if (newSnapshotFD == -1) {
1553 fprintf(stderr, "error creating: %s\n", strerror(errno));
1554 return errno;
1555 }
1556
1557 {
1558 BackupDataWriter dataStream(dataStreamFD);
1559
1560 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1561 if (err != 0) {
1562 return err;
1563 }
1564 }
1565
1566 close(dataStreamFD);
1567 close(newSnapshotFD);
1568
1569 return 0;
1570}
1571
Joe Onorato23ecae32009-06-10 17:07:15 -07001572
Joe Onorato3ad977b2009-05-05 11:50:51 -07001573#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001574
1575}