blob: cfb013e7cb04535f5fa511e163ccb379caa82eb5 [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 Tate4a627c72011-04-01 14:43:32 -0700471int write_tarfile(const String8& packageName, const String8& domain,
472 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
473{
474 // In the output stream everything is stored relative to the root
475 const char* relstart = filepath.string() + rootpath.length();
476 if (*relstart == '/') relstart++; // won't be true when path == rootpath
477 String8 relpath(relstart);
478
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700479 // If relpath is empty, it means this is the top of one of the standard named
480 // domain directories, so we should just skip it
481 if (relpath.length() == 0) {
482 return 0;
483 }
484
Christopher Tate4a627c72011-04-01 14:43:32 -0700485 // Too long a name for the ustar format?
486 // "apps/" + packagename + '/' + domainpath < 155 chars
487 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700488 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700489 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700490 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700491 }
492
493 int err = 0;
494 struct stat64 s;
495 if (lstat64(filepath.string(), &s) != 0) {
496 err = errno;
497 LOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
498 return err;
499 }
500
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700501 String8 fullname; // for pax later on
502 String8 prefix;
503
Christopher Tate4a627c72011-04-01 14:43:32 -0700504 const int isdir = S_ISDIR(s.st_mode);
505
506 // !!! TODO: use mmap when possible to avoid churning the buffer cache
507 // !!! TODO: this will break with symlinks; need to use readlink(2)
508 int fd = open(filepath.string(), O_RDONLY);
509 if (fd < 0) {
510 err = errno;
511 LOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
512 return err;
513 }
514
515 // read/write up to this much at a time.
516 const size_t BUFSIZE = 32 * 1024;
Christopher Tate4a627c72011-04-01 14:43:32 -0700517 char* buf = new char[BUFSIZE];
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700518 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
519 char* paxData = buf + 1024;
520
Christopher Tate4a627c72011-04-01 14:43:32 -0700521 if (buf == NULL) {
522 LOGE("Out of mem allocating transfer buffer");
523 err = ENOMEM;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700524 goto cleanup;
Christopher Tate4a627c72011-04-01 14:43:32 -0700525 }
526
527 // Good to go -- first construct the standard tar header at the start of the buffer
528 memset(buf, 0, 512); // tar header is 512 bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700529 memset(paxHeader, 0, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700530
531 // Magic fields for the ustar file format
532 strcat(buf + 257, "ustar");
533 strcat(buf + 263, "00");
534
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700535 // [ 265 : 32 ] user name, ignored on restore
536 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700537
538 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700539 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700540
541 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
542 // [ 116 : 8 ] gid -- ignored in Android format
543 snprintf(buf + 108, 8, "0%lo", s.st_uid);
544 snprintf(buf + 116, 8, "0%lo", s.st_gid);
545
546 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700547 if (s.st_size > 077777777777LL) {
548 // very large files need a pax extended size header
549 needExtended = true;
550 }
551 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700552
553 // [ 136 : 12 ] last mod time as a UTC time_t
554 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
555
Christopher Tate4a627c72011-04-01 14:43:32 -0700556 // [ 156 : 1 ] link/file type
557 uint8_t type;
558 if (isdir) {
559 type = '5'; // tar magic: '5' == directory
560 } else if (S_ISREG(s.st_mode)) {
561 type = '0'; // tar magic: '0' == normal file
562 } else {
563 LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
564 goto cleanup;
565 }
566 buf[156] = type;
567
568 // [ 157 : 100 ] name of linked file [not implemented]
569
Christopher Tate4a627c72011-04-01 14:43:32 -0700570 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700571 // Prefix and main relative path. Path lengths have been preflighted.
572 if (packageName.length() > 0) {
573 prefix = "apps/";
574 prefix += packageName;
575 }
576 if (domain.length() > 0) {
577 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700578 }
579
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700580 // pax extended means we don't put in a prefix field, and put a different
581 // string in the basic name field. We can also construct the full path name
582 // out of the substrings we've now built.
583 fullname = prefix;
584 fullname.appendPath(relpath);
585
586 // ustar:
587 // [ 0 : 100 ]; file name/path
588 // [ 345 : 155 ] filename path prefix
589 // We only use the prefix area if fullname won't fit in the path
590 if (fullname.length() > 100) {
591 strncpy(buf, relpath.string(), 100);
592 strncpy(buf + 345, prefix.string(), 155);
593 } else {
594 strncpy(buf, fullname.string(), 100);
595 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700596 }
597
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700598 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
599
600 LOGI(" Name: %s", fullname.string());
601
602 // If we're using a pax extended header, build & write that here; lengths are
603 // already preflighted
604 if (needExtended) {
605 // construct the pax extended header data block
606 memset(paxData, 0, BUFSIZE - (paxData - buf));
607 char* p = paxData;
608 int len;
609
610 // size header -- calc len in digits by actually rendering the number
611 // to a string - brute force but simple
612 len = sprintf(p, "%lld", s.st_size) + 8; // 8 for "1 size=" and final LF
613 if (len >= 10) len++;
614
615 memset(p, 0, 512);
616 p += sprintf(p, "%d size=%lld\n", len, s.st_size);
617
618 // fullname was generated above with the ustar paths
619 len = fullname.length() + 8; // 8 for "1 path=" and final LF
620 if (len >= 10) len++;
621 if (len >= 100) len++;
622 p += sprintf(p, "%d path=%s\n", len, fullname.string());
623
624 // Now we know how big the pax data is
625 int paxLen = p - paxData;
626
627 // Now build the pax *header* templated on the ustar header
628 memcpy(paxHeader, buf, 512);
629
630 String8 leaf = fullname.getPathLeaf();
631 memset(paxHeader, 0, 100); // rewrite the name area
632 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
633 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
634 strncpy(paxHeader + 345, prefix.string(), 155);
635
636 paxHeader[156] = 'x'; // mark it as a pax extended header
637
638 // [ 124 : 12 ] size of pax extended header data
639 memset(paxHeader + 124, 0, 12);
640 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
641
642 // Checksum and write the pax block header
643 calc_tar_checksum(paxHeader);
644 writer->WriteEntityData(paxHeader, 512);
645
646 // Now write the pax data itself
647 int paxblocks = (paxLen + 511) / 512;
648 writer->WriteEntityData(paxData, 512 * paxblocks);
649 }
650
651 // Checksum and write the 512-byte ustar file header block to the output
652 calc_tar_checksum(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700653 writer->WriteEntityData(buf, 512);
654
655 // Now write the file data itself, for real files. We honor tar's convention that
656 // only full 512-byte blocks are sent to write().
657 if (!isdir) {
658 off64_t toWrite = s.st_size;
659 while (toWrite > 0) {
660 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
661 ssize_t nRead = read(fd, buf, toRead);
662 if (nRead < 0) {
663 err = errno;
664 LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
665 err, strerror(err));
666 break;
667 } else if (nRead == 0) {
668 LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
669 filepath.string());
670 err = EIO;
671 break;
672 }
673
674 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
675 // depends on the OS guarantee that for ordinary files, read() will never return
676 // less than the number of bytes requested.
677 ssize_t partial = (nRead+512) % 512;
678 if (partial > 0) {
679 ssize_t remainder = 512 - partial;
680 memset(buf + nRead, 0, remainder);
681 nRead += remainder;
682 }
683 writer->WriteEntityData(buf, nRead);
684 toWrite -= nRead;
685 }
686 }
687
688cleanup:
689 delete [] buf;
690done:
691 close(fd);
692 return err;
693}
694// end tarfile
695
696
697
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700698#define RESTORE_BUF_SIZE (8*1024)
699
700RestoreHelperBase::RestoreHelperBase()
701{
702 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700703 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700704}
705
706RestoreHelperBase::~RestoreHelperBase()
707{
708 free(m_buf);
709}
710
711status_t
712RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
713{
714 ssize_t err;
715 size_t dataSize;
716 String8 key;
717 int fd;
718 void* buf = m_buf;
719 ssize_t amt;
720 int mode;
721 int crc;
722 struct stat st;
723 FileRec r;
724
725 err = in->ReadEntityHeader(&key, &dataSize);
726 if (err != NO_ERROR) {
727 return err;
728 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700729
Christopher Tatefbb92382009-06-23 17:35:11 -0700730 // Get the metadata block off the head of the file entity and use that to
731 // set up the output file
732 file_metadata_v1 metadata;
733 amt = in->ReadEntityData(&metadata, sizeof(metadata));
734 if (amt != sizeof(metadata)) {
735 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
736 (long)amt, strerror(errno));
737 return EIO;
738 }
739 metadata.version = fromlel(metadata.version);
740 metadata.mode = fromlel(metadata.mode);
741 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700742 if (!m_loggedUnknownMetadata) {
743 m_loggedUnknownMetadata = true;
744 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
745 metadata.version, CURRENT_METADATA_VERSION);
746 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700747 }
748 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700749
750 // Write the file and compute the crc
751 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700752 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
753 if (fd == -1) {
754 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700755 return errno;
756 }
757
758 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
759 err = write(fd, buf, amt);
760 if (err != amt) {
761 close(fd);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700762 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700763 return errno;
764 }
765 crc = crc32(crc, (Bytef*)buf, amt);
766 }
767
768 close(fd);
769
770 // Record for the snapshot
771 err = stat(filename.string(), &st);
772 if (err != 0) {
773 LOGW("Error stating file that we just created %s", filename.string());
774 return errno;
775 }
776
777 r.file = filename;
778 r.deleted = false;
779 r.s.modTime_sec = st.st_mtime;
780 r.s.modTime_nsec = 0; // workaround sim breakage
781 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700782 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700783 r.s.size = st.st_size;
784 r.s.crc32 = crc;
785
786 m_files.add(key, r);
787
788 return NO_ERROR;
789}
790
791status_t
792RestoreHelperBase::WriteSnapshot(int fd)
793{
794 return write_snapshot_file(fd, m_files);;
795}
796
Joe Onorato3ad977b2009-05-05 11:50:51 -0700797#if TEST_BACKUP_HELPERS
798
799#define SCRATCH_DIR "/data/backup_helper_test/"
800
801static int
802write_text_file(const char* path, const char* data)
803{
804 int amt;
805 int fd;
806 int len;
807
808 fd = creat(path, 0666);
809 if (fd == -1) {
810 fprintf(stderr, "creat %s failed\n", path);
811 return errno;
812 }
813
814 len = strlen(data);
815 amt = write(fd, data, len);
816 if (amt != len) {
817 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
818 return errno;
819 }
820
821 close(fd);
822
823 return 0;
824}
825
826static int
827compare_file(const char* path, const unsigned char* data, int len)
828{
829 int fd;
830 int amt;
831
832 fd = open(path, O_RDONLY);
833 if (fd == -1) {
834 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
835 return errno;
836 }
837
838 unsigned char* contents = (unsigned char*)malloc(len);
839 if (contents == NULL) {
840 fprintf(stderr, "malloc(%d) failed\n", len);
841 return ENOMEM;
842 }
843
844 bool sizesMatch = true;
845 amt = lseek(fd, 0, SEEK_END);
846 if (amt != len) {
847 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
848 sizesMatch = false;
849 }
850 lseek(fd, 0, SEEK_SET);
851
852 int readLen = amt < len ? amt : len;
853 amt = read(fd, contents, readLen);
854 if (amt != readLen) {
855 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
856 }
857
858 bool contentsMatch = true;
859 for (int i=0; i<readLen; i++) {
860 if (data[i] != contents[i]) {
861 if (contentsMatch) {
862 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
863 contentsMatch = false;
864 }
865 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
866 }
867 }
868
Christopher Tate63bcb792009-06-24 13:57:29 -0700869 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700870 return contentsMatch && sizesMatch ? 0 : 1;
871}
872
873int
874backup_helper_test_empty()
875{
876 int err;
877 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700878 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700879 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
880
881 system("rm -r " SCRATCH_DIR);
882 mkdir(SCRATCH_DIR, 0777);
883
884 // write
885 fd = creat(filename, 0666);
886 if (fd == -1) {
887 fprintf(stderr, "error creating %s\n", filename);
888 return 1;
889 }
890
891 err = write_snapshot_file(fd, snapshot);
892
893 close(fd);
894
895 if (err != 0) {
896 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
897 return err;
898 }
899
900 static const unsigned char correct_data[] = {
901 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
902 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
903 };
904
905 err = compare_file(filename, correct_data, sizeof(correct_data));
906 if (err != 0) {
907 return err;
908 }
909
910 // read
911 fd = open(filename, O_RDONLY);
912 if (fd == -1) {
913 fprintf(stderr, "error opening for read %s\n", filename);
914 return 1;
915 }
916
917 KeyedVector<String8,FileState> readSnapshot;
918 err = read_snapshot_file(fd, &readSnapshot);
919 if (err != 0) {
920 fprintf(stderr, "read_snapshot_file failed %d\n", err);
921 return err;
922 }
923
924 if (readSnapshot.size() != 0) {
925 fprintf(stderr, "readSnapshot should be length 0\n");
926 return 1;
927 }
928
929 return 0;
930}
931
932int
933backup_helper_test_four()
934{
935 int err;
936 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700937 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700938 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
939
940 system("rm -r " SCRATCH_DIR);
941 mkdir(SCRATCH_DIR, 0777);
942
943 // write
944 fd = creat(filename, 0666);
945 if (fd == -1) {
946 fprintf(stderr, "error opening %s\n", filename);
947 return 1;
948 }
949
950 String8 filenames[4];
951 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700952 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700953 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700954
955 states[0].modTime_sec = 0xfedcba98;
956 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700957 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700958 states[0].size = 0xababbcbc;
959 states[0].crc32 = 0x12345678;
960 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700961 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700962 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700963 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700964
965 states[1].modTime_sec = 0x93400031;
966 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700967 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700968 states[1].size = 0x88557766;
969 states[1].crc32 = 0x22334422;
970 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700971 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700972 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700973 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700974
975 states[2].modTime_sec = 0x33221144;
976 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700977 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700978 states[2].size = 0x11223344;
979 states[2].crc32 = 0x01122334;
980 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700981 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700982 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700983 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700984
985 states[3].modTime_sec = 0x33221144;
986 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700987 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -0700988 states[3].size = 0x11223344;
989 states[3].crc32 = 0x01122334;
990 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700991 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700992 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -0700993 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700994
995 err = write_snapshot_file(fd, snapshot);
996
997 close(fd);
998
999 if (err != 0) {
1000 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1001 return err;
1002 }
1003
1004 static const unsigned char correct_data[] = {
1005 // header
1006 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001007 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001008
1009 // bytes_of_padding
1010 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001011 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1012 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1013 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1014 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001015
1016 // bytes_of_padding3
1017 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001018 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1019 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1020 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1021 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1022 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001023
Joe Onorato3ad977b2009-05-05 11:50:51 -07001024 // bytes of padding2
1025 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001026 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1027 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1028 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1029 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1030 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001031
Joe Onorato3ad977b2009-05-05 11:50:51 -07001032 // bytes of padding3
1033 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001034 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1035 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1036 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1037 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1038 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001039 };
1040
1041 err = compare_file(filename, correct_data, sizeof(correct_data));
1042 if (err != 0) {
1043 return err;
1044 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001045
Joe Onorato3ad977b2009-05-05 11:50:51 -07001046 // read
1047 fd = open(filename, O_RDONLY);
1048 if (fd == -1) {
1049 fprintf(stderr, "error opening for read %s\n", filename);
1050 return 1;
1051 }
1052
1053
1054 KeyedVector<String8,FileState> readSnapshot;
1055 err = read_snapshot_file(fd, &readSnapshot);
1056 if (err != 0) {
1057 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1058 return err;
1059 }
1060
1061 if (readSnapshot.size() != 4) {
1062 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1063 return 1;
1064 }
1065
1066 bool matched = true;
1067 for (size_t i=0; i<readSnapshot.size(); i++) {
1068 const String8& name = readSnapshot.keyAt(i);
1069 const FileState state = readSnapshot.valueAt(i);
1070
1071 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001072 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001073 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-06-23 13:03:00 -07001074 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1075 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1076 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1077 states[i].crc32, name.length(), filenames[i].string(),
1078 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1079 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001080 matched = false;
1081 }
1082 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001083
Joe Onorato3ad977b2009-05-05 11:50:51 -07001084 return matched ? 0 : 1;
1085}
1086
Joe Onorato4535e402009-05-15 09:07:06 -04001087// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1088const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001089 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1090 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1091 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1092 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001093 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1094 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001095 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1096 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001097 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001098 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001099 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1100 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001101 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001102 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1103 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001104 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001105 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1106 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1107 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001108 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1109
Joe Onorato4535e402009-05-15 09:07:06 -04001110};
1111const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1112
1113static int
1114test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1115{
1116 int err;
1117 String8 text(str);
1118
Joe Onorato4535e402009-05-15 09:07:06 -04001119 err = writer.WriteEntityHeader(text, text.length()+1);
1120 if (err != 0) {
1121 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1122 return err;
1123 }
1124
1125 err = writer.WriteEntityData(text.string(), text.length()+1);
1126 if (err != 0) {
1127 fprintf(stderr, "write failed for data '%s'\n", text.string());
1128 return errno;
1129 }
1130
1131 return err;
1132}
1133
1134int
1135backup_helper_test_data_writer()
1136{
1137 int err;
1138 int fd;
1139 const char* filename = SCRATCH_DIR "data_writer.data";
1140
1141 system("rm -r " SCRATCH_DIR);
1142 mkdir(SCRATCH_DIR, 0777);
1143 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001144
Joe Onorato4535e402009-05-15 09:07:06 -04001145 fd = creat(filename, 0666);
1146 if (fd == -1) {
1147 fprintf(stderr, "error creating: %s\n", strerror(errno));
1148 return errno;
1149 }
1150
1151 BackupDataWriter writer(fd);
1152
1153 err = 0;
1154 err |= test_write_header_and_entity(writer, "no_padding_");
1155 err |= test_write_header_and_entity(writer, "padded_to__3");
1156 err |= test_write_header_and_entity(writer, "padded_to_2__");
1157 err |= test_write_header_and_entity(writer, "padded_to1");
1158
Joe Onorato4535e402009-05-15 09:07:06 -04001159 close(fd);
1160
1161 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1162 if (err != 0) {
1163 return err;
1164 }
1165
1166 return err;
1167}
1168
Joe Onorato2e1da322009-05-15 18:20:19 -04001169int
1170test_read_header_and_entity(BackupDataReader& reader, const char* str)
1171{
1172 int err;
1173 int bufSize = strlen(str)+1;
1174 char* buf = (char*)malloc(bufSize);
1175 String8 string;
1176 int cookie = 0x11111111;
1177 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001178 bool done;
1179 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001180 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001181
1182 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1183
Joe Onorato5f15d152009-06-16 16:31:35 -04001184 err = reader.ReadNextHeader(&done, &type);
1185 if (done) {
1186 fprintf(stderr, "should not be done yet\n");
1187 goto finished;
1188 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001189 if (err != 0) {
1190 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001191 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001192 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001193 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001194 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001195 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001196 }
1197
1198 err = reader.ReadEntityHeader(&string, &actualSize);
1199 if (err != 0) {
1200 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001201 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001202 }
1203 if (string != str) {
1204 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1205 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001206 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001207 }
1208 if ((int)actualSize != bufSize) {
1209 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1210 actualSize);
1211 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001212 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001213 }
1214
Christopher Tate11b15772009-06-23 13:03:00 -07001215 nRead = reader.ReadEntityData(buf, bufSize);
1216 if (nRead < 0) {
1217 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001218 fprintf(stderr, "ReadEntityData 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
1222 if (0 != memcmp(buf, str, bufSize)) {
1223 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001224 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1225 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001227 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001228 }
1229
1230 // The next read will confirm whether it got the right amount of data.
1231
Joe Onorato5f15d152009-06-16 16:31:35 -04001232finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001233 if (err != NO_ERROR) {
1234 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1235 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001236 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001237 return err;
1238}
1239
1240int
1241backup_helper_test_data_reader()
1242{
1243 int err;
1244 int fd;
1245 const char* filename = SCRATCH_DIR "data_reader.data";
1246
1247 system("rm -r " SCRATCH_DIR);
1248 mkdir(SCRATCH_DIR, 0777);
1249 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001250
Joe Onorato2e1da322009-05-15 18:20:19 -04001251 fd = creat(filename, 0666);
1252 if (fd == -1) {
1253 fprintf(stderr, "error creating: %s\n", strerror(errno));
1254 return errno;
1255 }
1256
1257 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1258 if (err != DATA_GOLDEN_FILE_SIZE) {
1259 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1260 return errno;
1261 }
1262
1263 close(fd);
1264
1265 fd = open(filename, O_RDONLY);
1266 if (fd == -1) {
1267 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1268 filename);
1269 return errno;
1270 }
1271
1272 {
1273 BackupDataReader reader(fd);
1274
1275 err = 0;
1276
1277 if (err == NO_ERROR) {
1278 err = test_read_header_and_entity(reader, "no_padding_");
1279 }
1280
1281 if (err == NO_ERROR) {
1282 err = test_read_header_and_entity(reader, "padded_to__3");
1283 }
1284
1285 if (err == NO_ERROR) {
1286 err = test_read_header_and_entity(reader, "padded_to_2__");
1287 }
1288
1289 if (err == NO_ERROR) {
1290 err = test_read_header_and_entity(reader, "padded_to1");
1291 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001292 }
1293
1294 close(fd);
1295
1296 return err;
1297}
1298
Joe Onorato3ad977b2009-05-05 11:50:51 -07001299static int
1300get_mod_time(const char* filename, struct timeval times[2])
1301{
1302 int err;
1303 struct stat64 st;
1304 err = stat64(filename, &st);
1305 if (err != 0) {
1306 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1307 return errno;
1308 }
1309 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001310 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001311
1312 // If st_atime is a macro then struct stat64 uses struct timespec
1313 // to store the access and modif time values and typically
1314 // st_*time_nsec is not defined. In glibc, this is controlled by
1315 // __USE_MISC.
1316#ifdef __USE_MISC
1317#if !defined(st_atime) || defined(st_atime_nsec)
1318#error "Check if this __USE_MISC conditional is still needed."
1319#endif
1320 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1321 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1322#else
1323 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001324 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001325#endif
1326
Joe Onorato3ad977b2009-05-05 11:50:51 -07001327 return 0;
1328}
1329
1330int
1331backup_helper_test_files()
1332{
1333 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001334 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001335 int dataStreamFD;
1336 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001337
1338 system("rm -r " SCRATCH_DIR);
1339 mkdir(SCRATCH_DIR, 0777);
1340 mkdir(SCRATCH_DIR "data", 0777);
1341
1342 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1343 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1344 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1345 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1346 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1347 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1348
1349 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001350 SCRATCH_DIR "data/b",
1351 SCRATCH_DIR "data/c",
1352 SCRATCH_DIR "data/d",
1353 SCRATCH_DIR "data/e",
1354 SCRATCH_DIR "data/f"
1355 };
1356
1357 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001358 "data/b",
1359 "data/c",
1360 "data/d",
1361 "data/e",
1362 "data/f"
1363 };
1364
Joe Onorato4535e402009-05-15 09:07:06 -04001365 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1366 if (dataStreamFD == -1) {
1367 fprintf(stderr, "error creating: %s\n", strerror(errno));
1368 return errno;
1369 }
1370
Joe Onorato3ad977b2009-05-05 11:50:51 -07001371 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1372 if (newSnapshotFD == -1) {
1373 fprintf(stderr, "error creating: %s\n", strerror(errno));
1374 return errno;
1375 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001376
1377 {
1378 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001379
Joe Onorato23ecae32009-06-10 17:07:15 -07001380 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001381 if (err != 0) {
1382 return err;
1383 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001384 }
1385
Joe Onorato4535e402009-05-15 09:07:06 -04001386 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001387 close(newSnapshotFD);
1388
1389 sleep(3);
1390
1391 struct timeval d_times[2];
1392 struct timeval e_times[2];
1393
1394 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1395 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1396 if (err != 0) {
1397 return err;
1398 }
1399
1400 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1401 unlink(SCRATCH_DIR "data/c");
1402 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1403 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1404 utimes(SCRATCH_DIR "data/d", d_times);
1405 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1406 utimes(SCRATCH_DIR "data/e", e_times);
1407 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1408 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001409
Joe Onorato3ad977b2009-05-05 11:50:51 -07001410 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001411 SCRATCH_DIR "data/a", // added
1412 SCRATCH_DIR "data/b", // same
1413 SCRATCH_DIR "data/c", // different mod time
1414 SCRATCH_DIR "data/d", // different size (same mod time)
1415 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1416 SCRATCH_DIR "data/g" // added
1417 };
1418
1419 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001420 "data/a", // added
1421 "data/b", // same
1422 "data/c", // different mod time
1423 "data/d", // different size (same mod time)
1424 "data/e", // different contents (same mod time, same size)
1425 "data/g" // added
1426 };
1427
1428 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1429 if (oldSnapshotFD == -1) {
1430 fprintf(stderr, "error opening: %s\n", strerror(errno));
1431 return errno;
1432 }
1433
Joe Onorato4535e402009-05-15 09:07:06 -04001434 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1435 if (dataStreamFD == -1) {
1436 fprintf(stderr, "error creating: %s\n", strerror(errno));
1437 return errno;
1438 }
1439
Joe Onorato3ad977b2009-05-05 11:50:51 -07001440 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1441 if (newSnapshotFD == -1) {
1442 fprintf(stderr, "error creating: %s\n", strerror(errno));
1443 return errno;
1444 }
1445
Joe Onoratod2110db2009-05-19 13:41:21 -07001446 {
1447 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001448
Joe Onorato23ecae32009-06-10 17:07:15 -07001449 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001450 if (err != 0) {
1451 return err;
1452 }
1453}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001454
1455 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001456 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001457 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001458
Joe Onorato3ad977b2009-05-05 11:50:51 -07001459 return 0;
1460}
1461
Joe Onorato23ecae32009-06-10 17:07:15 -07001462int
1463backup_helper_test_null_base()
1464{
1465 int err;
1466 int oldSnapshotFD;
1467 int dataStreamFD;
1468 int newSnapshotFD;
1469
1470 system("rm -r " SCRATCH_DIR);
1471 mkdir(SCRATCH_DIR, 0777);
1472 mkdir(SCRATCH_DIR "data", 0777);
1473
1474 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1475
1476 char const* files[] = {
1477 SCRATCH_DIR "data/a",
1478 };
1479
1480 char const* keys[] = {
1481 "a",
1482 };
1483
1484 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1485 if (dataStreamFD == -1) {
1486 fprintf(stderr, "error creating: %s\n", strerror(errno));
1487 return errno;
1488 }
1489
1490 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1491 if (newSnapshotFD == -1) {
1492 fprintf(stderr, "error creating: %s\n", strerror(errno));
1493 return errno;
1494 }
1495
1496 {
1497 BackupDataWriter dataStream(dataStreamFD);
1498
1499 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1500 if (err != 0) {
1501 return err;
1502 }
1503 }
1504
1505 close(dataStreamFD);
1506 close(newSnapshotFD);
1507
1508 return 0;
1509}
1510
Joe Onoratoce88cb12009-06-11 11:27:16 -07001511int
1512backup_helper_test_missing_file()
1513{
1514 int err;
1515 int oldSnapshotFD;
1516 int dataStreamFD;
1517 int newSnapshotFD;
1518
1519 system("rm -r " SCRATCH_DIR);
1520 mkdir(SCRATCH_DIR, 0777);
1521 mkdir(SCRATCH_DIR "data", 0777);
1522
1523 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1524
1525 char const* files[] = {
1526 SCRATCH_DIR "data/a",
1527 SCRATCH_DIR "data/b",
1528 SCRATCH_DIR "data/c",
1529 };
1530
1531 char const* keys[] = {
1532 "a",
1533 "b",
1534 "c",
1535 };
1536
1537 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1538 if (dataStreamFD == -1) {
1539 fprintf(stderr, "error creating: %s\n", strerror(errno));
1540 return errno;
1541 }
1542
1543 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1544 if (newSnapshotFD == -1) {
1545 fprintf(stderr, "error creating: %s\n", strerror(errno));
1546 return errno;
1547 }
1548
1549 {
1550 BackupDataWriter dataStream(dataStreamFD);
1551
1552 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1553 if (err != 0) {
1554 return err;
1555 }
1556 }
1557
1558 close(dataStreamFD);
1559 close(newSnapshotFD);
1560
1561 return 0;
1562}
1563
Joe Onorato23ecae32009-06-10 17:07:15 -07001564
Joe Onorato3ad977b2009-05-05 11:50:51 -07001565#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001566
1567}