blob: 87549fe97771b950e4a54755c4b3a5357e7a22c6 [file] [log] [blame]
Joe Onorato62a381b2009-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 Onoratoaaead202009-05-05 11:50:51 -070017#define LOG_TAG "file_backup_helper"
18
Mathias Agopian7c889142009-06-04 13:53:57 -070019#include <utils/BackupHelpers.h>
Joe Onoratoaaead202009-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 Cataniad5e0fd42009-05-22 13:41:38 -070029#include <sys/time.h> // for utimes
Joe Onoratoaaead202009-05-05 11:50:51 -070030#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
Joe Onorato52223552009-05-06 12:55:46 -040033#include <utime.h>
Joe Onoratoaaead202009-05-05 11:50:51 -070034#include <fcntl.h>
35#include <zlib.h>
36
37#include <cutils/log.h>
38
Joe Onorato62a381b2009-05-15 09:07:06 -040039namespace android {
Joe Onoratoaaead202009-05-05 11:50:51 -070040
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
Christopher Tatead2030d2009-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 Onoratoff574332009-06-26 17:19:11 -040071#if 1
72#define LOGP(f, x...)
73#else
74#if TEST_BACKUP_HELPERS
Joe Onorato0d1d7ae2009-06-10 17:07:15 -070075#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato62a381b2009-05-15 09:07:06 -040076#else
Joe Onoratob81a9a12009-05-13 18:57:29 -040077#define LOGP(x...) LOGD(x)
Joe Onorato62a381b2009-05-15 09:07:06 -040078#endif
Joe Onoratoff574332009-06-26 17:19:11 -040079#endif
Joe Onoratob81a9a12009-05-13 18:57:29 -040080
Joe Onoratoaaead202009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700111 amt = read(fd, &file, sizeof(FileState));
112 if (amt != sizeof(FileState)) {
Joe Onoratoaaead202009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700147write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onoratoaaead202009-05-05 11:50:51 -0700148{
Joe Onorato9becbac2009-06-11 11:27:16 -0700149 int fileCount = 0;
Joe Onoratoaaead202009-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 Onorato9becbac2009-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 Onoratoaaead202009-05-05 11:50:51 -0700160 }
161
Joe Onorato62a381b2009-05-15 09:07:06 -0400162 LOGP("write_snapshot_file fd=%d\n", fd);
163
Joe Onoratoaaead202009-05-05 11:50:51 -0700164 int amt;
Joe Onorato9becbac2009-06-11 11:27:16 -0700165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onoratoaaead202009-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 Onorato9becbac2009-06-11 11:27:16 -0700173 for (int i=0; i<N; i++) {
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700174 FileRec r = snapshot.valueAt(i);
Joe Onorato9becbac2009-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 Onoratoaaead202009-05-05 11:50:51 -0700178
Joe Onorato9becbac2009-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 Onoratoaaead202009-05-05 11:50:51 -0700182 return 1;
183 }
Joe Onorato9becbac2009-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 Onoratoaaead202009-05-05 11:50:51 -0700201 }
202 }
203
204 return 0;
205}
206
207static int
Joe Onorato062a4882009-05-19 13:41:21 -0700208write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onoratoaaead202009-05-05 11:50:51 -0700209{
Joe Onoratob81a9a12009-05-13 18:57:29 -0400210 LOGP("write_delete_file %s\n", key.string());
Joe Onorato062a4882009-05-19 13:41:21 -0700211 return dataStream->WriteEntityHeader(key, -1);
Joe Onoratoaaead202009-05-05 11:50:51 -0700212}
213
214static int
Christopher Tatead2030d2009-06-23 17:35:11 -0700215write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700216 char const* realFilename)
Joe Onoratoaaead202009-05-05 11:50:51 -0700217{
Christopher Tatead2030d2009-06-23 17:35:11 -0700218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onorato062a4882009-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 Tatead2030d2009-06-23 17:35:11 -0700225 file_metadata_v1 metadata;
Joe Onorato062a4882009-05-19 13:41:21 -0700226
227 char* buf = (char*)malloc(bufsize);
228 int crc = crc32(0L, Z_NULL, 0);
229
230
Christopher Tatead2030d2009-06-23 17:35:11 -0700231 fileSize = lseek(fd, 0, SEEK_END);
Joe Onorato062a4882009-05-19 13:41:21 -0700232 lseek(fd, 0, SEEK_SET);
233
Christopher Tatead2030d2009-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 Onorato062a4882009-05-19 13:41:21 -0700239 err = dataStream->WriteEntityHeader(key, bytesLeft);
240 if (err != 0) {
Christopher Tate585d4f42009-06-24 13:57:29 -0700241 free(buf);
Joe Onorato062a4882009-05-19 13:41:21 -0700242 return err;
243 }
244
Christopher Tatead2030d2009-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 Tate585d4f42009-06-24 13:57:29 -0700251 free(buf);
Christopher Tatead2030d2009-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 Onorato062a4882009-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 Tate585d4f42009-06-24 13:57:29 -0700264 free(buf);
Joe Onorato062a4882009-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 Tate585d4f42009-06-24 13:57:29 -0700278 free(buf);
Joe Onorato062a4882009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700284 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onorato062a4882009-05-19 13:41:21 -0700285 }
286
Christopher Tate585d4f42009-06-24 13:57:29 -0700287 free(buf);
Joe Onorato062a4882009-05-19 13:41:21 -0700288 return NO_ERROR;
Joe Onoratoaaead202009-05-05 11:50:51 -0700289}
290
291static int
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700292write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onorato062a4882009-05-19 13:41:21 -0700293{
294 int err;
Christopher Tatead2030d2009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700302 int fd = open(realFilename, O_RDONLY);
Joe Onorato062a4882009-05-19 13:41:21 -0700303 if (fd == -1) {
304 return errno;
305 }
Christopher Tatead2030d2009-06-23 17:35:11 -0700306
307 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onorato062a4882009-05-19 13:41:21 -0700308 close(fd);
309 return err;
310}
311
312static int
313compute_crc32(int fd)
Joe Onoratoaaead202009-05-05 11:50:51 -0700314{
315 const int bufsize = 4*1024;
316 int amt;
317
Joe Onoratoaaead202009-05-05 11:50:51 -0700318 char* buf = (char*)malloc(bufsize);
319 int crc = crc32(0L, Z_NULL, 0);
320
Joe Onorato062a4882009-05-19 13:41:21 -0700321 lseek(fd, 0, SEEK_SET);
322
Joe Onoratoaaead202009-05-05 11:50:51 -0700323 while ((amt = read(fd, buf, bufsize)) != 0) {
324 crc = crc32(crc, (Bytef*)buf, amt);
325 }
326
Christopher Tate585d4f42009-06-24 13:57:29 -0700327 free(buf);
Joe Onoratoaaead202009-05-05 11:50:51 -0700328 return crc;
329}
330
331int
Joe Onorato062a4882009-05-19 13:41:21 -0700332back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700333 char const* const* files, char const* const* keys, int fileCount)
Joe Onoratoaaead202009-05-05 11:50:51 -0700334{
335 int err;
Joe Onoratoaaead202009-05-05 11:50:51 -0700336 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700337 KeyedVector<String8,FileRec> newSnapshot;
Joe Onoratoaaead202009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700348 String8 key(keys[i]);
349 FileRec r;
Joe Onoratob90ae552009-06-18 13:11:18 -0700350 char const* file = files[i];
351 r.file = file;
Joe Onoratoaaead202009-05-05 11:50:51 -0700352 struct stat st;
Joe Onoratoaaead202009-05-05 11:50:51 -0700353
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700354 err = stat(file, &st);
Joe Onoratoaaead202009-05-05 11:50:51 -0700355 if (err != 0) {
Joe Onorato9becbac2009-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 Tate02abe532009-06-23 13:03:00 -0700362 r.s.mode = st.st_mode;
Joe Onorato9becbac2009-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 Onoratoaaead202009-05-05 11:50:51 -0700365
Joe Onorato9becbac2009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700370 }
371 newSnapshot.add(key, r);
Joe Onoratoaaead202009-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 Onorato9becbac2009-06-11 11:27:16 -0700381 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratoaaead202009-05-05 11:50:51 -0700382 int cmp = p.compare(q);
Joe Onorato9becbac2009-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 Onoratoaaead202009-05-05 11:50:51 -0700391 // file added
Joe Onoratob90ae552009-06-18 13:11:18 -0700392 LOGP("file added: %s", g.file.string());
393 write_update_file(dataStream, q, g.file.string());
Joe Onoratoaaead202009-05-05 11:50:51 -0700394 m++;
395 }
Joe Onoratoaaead202009-05-05 11:50:51 -0700396 else {
397 // both files exist, check them
Joe Onoratoaaead202009-05-05 11:50:51 -0700398 const FileState& f = oldSnapshot.valueAt(n);
Joe Onoratoaaead202009-05-05 11:50:51 -0700399
Joe Onoratob90ae552009-06-18 13:11:18 -0700400 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate2972a142009-06-04 17:01:06 -0700401 if (fd < 0) {
Joe Onorato062a4882009-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 Onoratob90ae552009-06-18 13:11:18 -0700405 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onorato062a4882009-05-19 13:41:21 -0700406 } else {
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700407 g.s.crc32 = compute_crc32(fd);
Joe Onorato062a4882009-05-19 13:41:21 -0700408
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700409 LOGP("%s", q.string());
Christopher Tate02abe532009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tate02abe532009-06-23 13:03:00 -0700415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tatead2030d2009-06-23 17:35:11 -0700416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onorato062a4882009-05-19 13:41:21 -0700417 }
418
419 close(fd);
Joe Onoratoaaead202009-05-05 11:50:51 -0700420 }
421 n++;
422 m++;
423 }
424 }
425
426 // these were deleted
427 while (n<N) {
Joe Onorato062a4882009-05-19 13:41:21 -0700428 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onoratoaaead202009-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 Onorato0d1d7ae2009-06-10 17:07:15 -0700435 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratob90ae552009-06-18 13:11:18 -0700436 write_update_file(dataStream, q, g.file.string());
Joe Onoratoaaead202009-05-05 11:50:51 -0700437 m++;
438 }
439
440 err = write_snapshot_file(newSnapshotFD, newSnapshot);
441
442 return 0;
443}
444
Christopher Tate424ec5a2011-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 Tatefc5e7032011-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 Tatecd122332011-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 Tate424ec5a2011-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 Tatefc5e7032011-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 Tate424ec5a2011-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 Tatefc5e7032011-05-12 17:47:12 -0700501 bool needExtended = false;
Christopher Tate424ec5a2011-04-01 14:43:32 -0700502 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tatefc5e7032011-05-12 17:47:12 -0700503 needExtended = true;
Christopher Tate424ec5a2011-04-01 14:43:32 -0700504 }
505
Christopher Tate7c9f6732011-06-07 13:17:17 -0700506 // Non-7bit-clean path also means needing pax extended format
Christopher Tate8deb51e2011-05-18 16:28:19 -0700507 if (!needExtended) {
508 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate7c9f6732011-06-07 13:17:17 -0700509 if ((filepath[i] & 0x80) != 0) {
Christopher Tate8deb51e2011-05-18 16:28:19 -0700510 needExtended = true;
511 break;
512 }
513 }
514 }
515
Christopher Tate424ec5a2011-04-01 14:43:32 -0700516 int err = 0;
517 struct stat64 s;
518 if (lstat64(filepath.string(), &s) != 0) {
519 err = errno;
520 LOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
521 return err;
522 }
523
Christopher Tatefc5e7032011-05-12 17:47:12 -0700524 String8 fullname; // for pax later on
525 String8 prefix;
526
Christopher Tate424ec5a2011-04-01 14:43:32 -0700527 const int isdir = S_ISDIR(s.st_mode);
Christopher Tate384f13a2011-06-08 20:09:31 -0700528 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate424ec5a2011-04-01 14:43:32 -0700529
530 // !!! TODO: use mmap when possible to avoid churning the buffer cache
531 // !!! TODO: this will break with symlinks; need to use readlink(2)
532 int fd = open(filepath.string(), O_RDONLY);
533 if (fd < 0) {
534 err = errno;
535 LOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
536 return err;
537 }
538
539 // read/write up to this much at a time.
540 const size_t BUFSIZE = 32 * 1024;
Christopher Tate424ec5a2011-04-01 14:43:32 -0700541 char* buf = new char[BUFSIZE];
Christopher Tatefc5e7032011-05-12 17:47:12 -0700542 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
543 char* paxData = buf + 1024;
544
Christopher Tate424ec5a2011-04-01 14:43:32 -0700545 if (buf == NULL) {
546 LOGE("Out of mem allocating transfer buffer");
547 err = ENOMEM;
Christopher Tatefc5e7032011-05-12 17:47:12 -0700548 goto cleanup;
Christopher Tate424ec5a2011-04-01 14:43:32 -0700549 }
550
551 // Good to go -- first construct the standard tar header at the start of the buffer
Christopher Tatecd122332011-05-13 15:38:02 -0700552 memset(buf, 0, BUFSIZE);
Christopher Tate424ec5a2011-04-01 14:43:32 -0700553
554 // Magic fields for the ustar file format
555 strcat(buf + 257, "ustar");
556 strcat(buf + 263, "00");
557
Christopher Tatefc5e7032011-05-12 17:47:12 -0700558 // [ 265 : 32 ] user name, ignored on restore
559 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate424ec5a2011-04-01 14:43:32 -0700560
561 // [ 100 : 8 ] file mode
Christopher Tatefc5e7032011-05-12 17:47:12 -0700562 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate424ec5a2011-04-01 14:43:32 -0700563
564 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
565 // [ 116 : 8 ] gid -- ignored in Android format
566 snprintf(buf + 108, 8, "0%lo", s.st_uid);
567 snprintf(buf + 116, 8, "0%lo", s.st_gid);
568
569 // [ 124 : 12 ] file size in bytes
Christopher Tatefc5e7032011-05-12 17:47:12 -0700570 if (s.st_size > 077777777777LL) {
571 // very large files need a pax extended size header
572 needExtended = true;
573 }
574 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate424ec5a2011-04-01 14:43:32 -0700575
576 // [ 136 : 12 ] last mod time as a UTC time_t
577 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
578
Christopher Tate424ec5a2011-04-01 14:43:32 -0700579 // [ 156 : 1 ] link/file type
580 uint8_t type;
581 if (isdir) {
582 type = '5'; // tar magic: '5' == directory
583 } else if (S_ISREG(s.st_mode)) {
584 type = '0'; // tar magic: '0' == normal file
585 } else {
586 LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
587 goto cleanup;
588 }
589 buf[156] = type;
590
591 // [ 157 : 100 ] name of linked file [not implemented]
592
Christopher Tate424ec5a2011-04-01 14:43:32 -0700593 {
Christopher Tatefc5e7032011-05-12 17:47:12 -0700594 // Prefix and main relative path. Path lengths have been preflighted.
595 if (packageName.length() > 0) {
596 prefix = "apps/";
597 prefix += packageName;
598 }
599 if (domain.length() > 0) {
600 prefix.appendPath(domain);
Christopher Tate424ec5a2011-04-01 14:43:32 -0700601 }
602
Christopher Tatefc5e7032011-05-12 17:47:12 -0700603 // pax extended means we don't put in a prefix field, and put a different
604 // string in the basic name field. We can also construct the full path name
605 // out of the substrings we've now built.
606 fullname = prefix;
607 fullname.appendPath(relpath);
608
609 // ustar:
610 // [ 0 : 100 ]; file name/path
611 // [ 345 : 155 ] filename path prefix
612 // We only use the prefix area if fullname won't fit in the path
613 if (fullname.length() > 100) {
614 strncpy(buf, relpath.string(), 100);
615 strncpy(buf + 345, prefix.string(), 155);
616 } else {
617 strncpy(buf, fullname.string(), 100);
618 }
Christopher Tate424ec5a2011-04-01 14:43:32 -0700619 }
620
Christopher Tatefc5e7032011-05-12 17:47:12 -0700621 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
622
623 LOGI(" Name: %s", fullname.string());
624
625 // If we're using a pax extended header, build & write that here; lengths are
626 // already preflighted
627 if (needExtended) {
Christopher Tatecd122332011-05-13 15:38:02 -0700628 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
629 char* p = paxData;
630
Christopher Tatefc5e7032011-05-12 17:47:12 -0700631 // construct the pax extended header data block
632 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tatefc5e7032011-05-12 17:47:12 -0700633 int len;
634
635 // size header -- calc len in digits by actually rendering the number
636 // to a string - brute force but simple
Christopher Tatecd122332011-05-13 15:38:02 -0700637 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
638 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tatefc5e7032011-05-12 17:47:12 -0700639
640 // fullname was generated above with the ustar paths
Christopher Tatecd122332011-05-13 15:38:02 -0700641 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tatefc5e7032011-05-12 17:47:12 -0700642
643 // Now we know how big the pax data is
644 int paxLen = p - paxData;
645
646 // Now build the pax *header* templated on the ustar header
647 memcpy(paxHeader, buf, 512);
648
649 String8 leaf = fullname.getPathLeaf();
650 memset(paxHeader, 0, 100); // rewrite the name area
651 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
652 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
653 strncpy(paxHeader + 345, prefix.string(), 155);
654
655 paxHeader[156] = 'x'; // mark it as a pax extended header
656
657 // [ 124 : 12 ] size of pax extended header data
658 memset(paxHeader + 124, 0, 12);
659 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
660
661 // Checksum and write the pax block header
662 calc_tar_checksum(paxHeader);
663 writer->WriteEntityData(paxHeader, 512);
664
665 // Now write the pax data itself
666 int paxblocks = (paxLen + 511) / 512;
667 writer->WriteEntityData(paxData, 512 * paxblocks);
668 }
669
670 // Checksum and write the 512-byte ustar file header block to the output
671 calc_tar_checksum(buf);
Christopher Tate424ec5a2011-04-01 14:43:32 -0700672 writer->WriteEntityData(buf, 512);
673
674 // Now write the file data itself, for real files. We honor tar's convention that
675 // only full 512-byte blocks are sent to write().
676 if (!isdir) {
677 off64_t toWrite = s.st_size;
678 while (toWrite > 0) {
679 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
680 ssize_t nRead = read(fd, buf, toRead);
681 if (nRead < 0) {
682 err = errno;
683 LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
684 err, strerror(err));
685 break;
686 } else if (nRead == 0) {
687 LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
688 filepath.string());
689 err = EIO;
690 break;
691 }
692
693 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
694 // depends on the OS guarantee that for ordinary files, read() will never return
695 // less than the number of bytes requested.
696 ssize_t partial = (nRead+512) % 512;
697 if (partial > 0) {
698 ssize_t remainder = 512 - partial;
699 memset(buf + nRead, 0, remainder);
700 nRead += remainder;
701 }
702 writer->WriteEntityData(buf, nRead);
703 toWrite -= nRead;
704 }
705 }
706
707cleanup:
708 delete [] buf;
709done:
710 close(fd);
711 return err;
712}
713// end tarfile
714
715
716
Joe Onoratob90ae552009-06-18 13:11:18 -0700717#define RESTORE_BUF_SIZE (8*1024)
718
719RestoreHelperBase::RestoreHelperBase()
720{
721 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate585d4f42009-06-24 13:57:29 -0700722 m_loggedUnknownMetadata = false;
Joe Onoratob90ae552009-06-18 13:11:18 -0700723}
724
725RestoreHelperBase::~RestoreHelperBase()
726{
727 free(m_buf);
728}
729
730status_t
731RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
732{
733 ssize_t err;
734 size_t dataSize;
735 String8 key;
736 int fd;
737 void* buf = m_buf;
738 ssize_t amt;
739 int mode;
740 int crc;
741 struct stat st;
742 FileRec r;
743
744 err = in->ReadEntityHeader(&key, &dataSize);
745 if (err != NO_ERROR) {
746 return err;
747 }
Joe Onoratoaebb1ce2009-06-18 18:23:43 -0700748
Christopher Tatead2030d2009-06-23 17:35:11 -0700749 // Get the metadata block off the head of the file entity and use that to
750 // set up the output file
751 file_metadata_v1 metadata;
752 amt = in->ReadEntityData(&metadata, sizeof(metadata));
753 if (amt != sizeof(metadata)) {
754 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
755 (long)amt, strerror(errno));
756 return EIO;
757 }
758 metadata.version = fromlel(metadata.version);
759 metadata.mode = fromlel(metadata.mode);
760 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate585d4f42009-06-24 13:57:29 -0700761 if (!m_loggedUnknownMetadata) {
762 m_loggedUnknownMetadata = true;
763 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
764 metadata.version, CURRENT_METADATA_VERSION);
765 }
Christopher Tatead2030d2009-06-23 17:35:11 -0700766 }
767 mode = metadata.mode;
Joe Onoratob90ae552009-06-18 13:11:18 -0700768
769 // Write the file and compute the crc
770 crc = crc32(0L, Z_NULL, 0);
Joe Onoratoaebb1ce2009-06-18 18:23:43 -0700771 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
772 if (fd == -1) {
773 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratob90ae552009-06-18 13:11:18 -0700774 return errno;
775 }
776
777 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
778 err = write(fd, buf, amt);
779 if (err != amt) {
780 close(fd);
Joe Onoratoaebb1ce2009-06-18 18:23:43 -0700781 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratob90ae552009-06-18 13:11:18 -0700782 return errno;
783 }
784 crc = crc32(crc, (Bytef*)buf, amt);
785 }
786
787 close(fd);
788
789 // Record for the snapshot
790 err = stat(filename.string(), &st);
791 if (err != 0) {
792 LOGW("Error stating file that we just created %s", filename.string());
793 return errno;
794 }
795
796 r.file = filename;
797 r.deleted = false;
798 r.s.modTime_sec = st.st_mtime;
799 r.s.modTime_nsec = 0; // workaround sim breakage
800 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate02abe532009-06-23 13:03:00 -0700801 r.s.mode = st.st_mode;
Joe Onoratob90ae552009-06-18 13:11:18 -0700802 r.s.size = st.st_size;
803 r.s.crc32 = crc;
804
805 m_files.add(key, r);
806
807 return NO_ERROR;
808}
809
810status_t
811RestoreHelperBase::WriteSnapshot(int fd)
812{
813 return write_snapshot_file(fd, m_files);;
814}
815
Joe Onoratoaaead202009-05-05 11:50:51 -0700816#if TEST_BACKUP_HELPERS
817
818#define SCRATCH_DIR "/data/backup_helper_test/"
819
820static int
821write_text_file(const char* path, const char* data)
822{
823 int amt;
824 int fd;
825 int len;
826
827 fd = creat(path, 0666);
828 if (fd == -1) {
829 fprintf(stderr, "creat %s failed\n", path);
830 return errno;
831 }
832
833 len = strlen(data);
834 amt = write(fd, data, len);
835 if (amt != len) {
836 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
837 return errno;
838 }
839
840 close(fd);
841
842 return 0;
843}
844
845static int
846compare_file(const char* path, const unsigned char* data, int len)
847{
848 int fd;
849 int amt;
850
851 fd = open(path, O_RDONLY);
852 if (fd == -1) {
853 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
854 return errno;
855 }
856
857 unsigned char* contents = (unsigned char*)malloc(len);
858 if (contents == NULL) {
859 fprintf(stderr, "malloc(%d) failed\n", len);
860 return ENOMEM;
861 }
862
863 bool sizesMatch = true;
864 amt = lseek(fd, 0, SEEK_END);
865 if (amt != len) {
866 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
867 sizesMatch = false;
868 }
869 lseek(fd, 0, SEEK_SET);
870
871 int readLen = amt < len ? amt : len;
872 amt = read(fd, contents, readLen);
873 if (amt != readLen) {
874 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
875 }
876
877 bool contentsMatch = true;
878 for (int i=0; i<readLen; i++) {
879 if (data[i] != contents[i]) {
880 if (contentsMatch) {
881 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
882 contentsMatch = false;
883 }
884 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
885 }
886 }
887
Christopher Tate585d4f42009-06-24 13:57:29 -0700888 free(contents);
Joe Onoratoaaead202009-05-05 11:50:51 -0700889 return contentsMatch && sizesMatch ? 0 : 1;
890}
891
892int
893backup_helper_test_empty()
894{
895 int err;
896 int fd;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700897 KeyedVector<String8,FileRec> snapshot;
Joe Onoratoaaead202009-05-05 11:50:51 -0700898 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
899
900 system("rm -r " SCRATCH_DIR);
901 mkdir(SCRATCH_DIR, 0777);
902
903 // write
904 fd = creat(filename, 0666);
905 if (fd == -1) {
906 fprintf(stderr, "error creating %s\n", filename);
907 return 1;
908 }
909
910 err = write_snapshot_file(fd, snapshot);
911
912 close(fd);
913
914 if (err != 0) {
915 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
916 return err;
917 }
918
919 static const unsigned char correct_data[] = {
920 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
921 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
922 };
923
924 err = compare_file(filename, correct_data, sizeof(correct_data));
925 if (err != 0) {
926 return err;
927 }
928
929 // read
930 fd = open(filename, O_RDONLY);
931 if (fd == -1) {
932 fprintf(stderr, "error opening for read %s\n", filename);
933 return 1;
934 }
935
936 KeyedVector<String8,FileState> readSnapshot;
937 err = read_snapshot_file(fd, &readSnapshot);
938 if (err != 0) {
939 fprintf(stderr, "read_snapshot_file failed %d\n", err);
940 return err;
941 }
942
943 if (readSnapshot.size() != 0) {
944 fprintf(stderr, "readSnapshot should be length 0\n");
945 return 1;
946 }
947
948 return 0;
949}
950
951int
952backup_helper_test_four()
953{
954 int err;
955 int fd;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700956 KeyedVector<String8,FileRec> snapshot;
Joe Onoratoaaead202009-05-05 11:50:51 -0700957 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
958
959 system("rm -r " SCRATCH_DIR);
960 mkdir(SCRATCH_DIR, 0777);
961
962 // write
963 fd = creat(filename, 0666);
964 if (fd == -1) {
965 fprintf(stderr, "error opening %s\n", filename);
966 return 1;
967 }
968
969 String8 filenames[4];
970 FileState states[4];
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700971 FileRec r;
Joe Onorato9becbac2009-06-11 11:27:16 -0700972 r.deleted = false;
Joe Onoratoaaead202009-05-05 11:50:51 -0700973
974 states[0].modTime_sec = 0xfedcba98;
975 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate02abe532009-06-23 13:03:00 -0700976 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onoratoaaead202009-05-05 11:50:51 -0700977 states[0].size = 0xababbcbc;
978 states[0].crc32 = 0x12345678;
979 states[0].nameLen = -12;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700980 r.s = states[0];
Joe Onoratoaaead202009-05-05 11:50:51 -0700981 filenames[0] = String8("bytes_of_padding");
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700982 snapshot.add(filenames[0], r);
Joe Onoratoaaead202009-05-05 11:50:51 -0700983
984 states[1].modTime_sec = 0x93400031;
985 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate02abe532009-06-23 13:03:00 -0700986 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onoratoaaead202009-05-05 11:50:51 -0700987 states[1].size = 0x88557766;
988 states[1].crc32 = 0x22334422;
989 states[1].nameLen = -1;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700990 r.s = states[1];
Joe Onoratoaaead202009-05-05 11:50:51 -0700991 filenames[1] = String8("bytes_of_padding3");
Joe Onorato0d1d7ae2009-06-10 17:07:15 -0700992 snapshot.add(filenames[1], r);
Joe Onoratoaaead202009-05-05 11:50:51 -0700993
994 states[2].modTime_sec = 0x33221144;
995 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate02abe532009-06-23 13:03:00 -0700996 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onoratoaaead202009-05-05 11:50:51 -0700997 states[2].size = 0x11223344;
998 states[2].crc32 = 0x01122334;
999 states[2].nameLen = 0;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001000 r.s = states[2];
Joe Onoratoaaead202009-05-05 11:50:51 -07001001 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001002 snapshot.add(filenames[2], r);
Joe Onoratoaaead202009-05-05 11:50:51 -07001003
1004 states[3].modTime_sec = 0x33221144;
1005 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate02abe532009-06-23 13:03:00 -07001006 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onoratoaaead202009-05-05 11:50:51 -07001007 states[3].size = 0x11223344;
1008 states[3].crc32 = 0x01122334;
1009 states[3].nameLen = 0;
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001010 r.s = states[3];
Joe Onoratoaaead202009-05-05 11:50:51 -07001011 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001012 snapshot.add(filenames[3], r);
Joe Onoratoaaead202009-05-05 11:50:51 -07001013
1014 err = write_snapshot_file(fd, snapshot);
1015
1016 close(fd);
1017
1018 if (err != 0) {
1019 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1020 return err;
1021 }
1022
1023 static const unsigned char correct_data[] = {
1024 // header
1025 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate02abe532009-06-23 13:03:00 -07001026 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onoratoaaead202009-05-05 11:50:51 -07001027
1028 // bytes_of_padding
1029 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate02abe532009-06-23 13:03:00 -07001030 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1031 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1032 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1033 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onoratoaaead202009-05-05 11:50:51 -07001034
1035 // bytes_of_padding3
1036 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate02abe532009-06-23 13:03:00 -07001037 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1038 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1039 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1040 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1041 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001042
Joe Onoratoaaead202009-05-05 11:50:51 -07001043 // bytes of padding2
1044 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate02abe532009-06-23 13:03:00 -07001045 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1046 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1047 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1048 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1049 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001050
Joe Onoratoaaead202009-05-05 11:50:51 -07001051 // bytes of padding3
1052 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate02abe532009-06-23 13:03:00 -07001053 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1054 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1055 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1056 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1057 0x5f, 0x5f, 0x31, 0xab
Joe Onoratoaaead202009-05-05 11:50:51 -07001058 };
1059
1060 err = compare_file(filename, correct_data, sizeof(correct_data));
1061 if (err != 0) {
1062 return err;
1063 }
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001064
Joe Onoratoaaead202009-05-05 11:50:51 -07001065 // read
1066 fd = open(filename, O_RDONLY);
1067 if (fd == -1) {
1068 fprintf(stderr, "error opening for read %s\n", filename);
1069 return 1;
1070 }
1071
1072
1073 KeyedVector<String8,FileState> readSnapshot;
1074 err = read_snapshot_file(fd, &readSnapshot);
1075 if (err != 0) {
1076 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1077 return err;
1078 }
1079
1080 if (readSnapshot.size() != 4) {
1081 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1082 return 1;
1083 }
1084
1085 bool matched = true;
1086 for (size_t i=0; i<readSnapshot.size(); i++) {
1087 const String8& name = readSnapshot.keyAt(i);
1088 const FileState state = readSnapshot.valueAt(i);
1089
1090 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate02abe532009-06-23 13:03:00 -07001091 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onoratoaaead202009-05-05 11:50:51 -07001092 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate02abe532009-06-23 13:03:00 -07001093 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1094 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1095 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1096 states[i].crc32, name.length(), filenames[i].string(),
1097 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1098 state.nameLen, name.string());
Joe Onoratoaaead202009-05-05 11:50:51 -07001099 matched = false;
1100 }
1101 }
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001102
Joe Onoratoaaead202009-05-05 11:50:51 -07001103 return matched ? 0 : 1;
1104}
1105
Joe Onorato62a381b2009-05-15 09:07:06 -04001106// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1107const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001108 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1109 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1110 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1111 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato1781fd12009-06-16 16:31:35 -04001112 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1113 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato62a381b2009-05-15 09:07:06 -04001114 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1115 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001116 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato1781fd12009-06-16 16:31:35 -04001117 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001118 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1119 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato62a381b2009-05-15 09:07:06 -04001120 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001121 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1122 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato1781fd12009-06-16 16:31:35 -04001123 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato62a381b2009-05-15 09:07:06 -04001124 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1125 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1126 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato1781fd12009-06-16 16:31:35 -04001127 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1128
Joe Onorato62a381b2009-05-15 09:07:06 -04001129};
1130const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1131
1132static int
1133test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1134{
1135 int err;
1136 String8 text(str);
1137
Joe Onorato62a381b2009-05-15 09:07:06 -04001138 err = writer.WriteEntityHeader(text, text.length()+1);
1139 if (err != 0) {
1140 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1141 return err;
1142 }
1143
1144 err = writer.WriteEntityData(text.string(), text.length()+1);
1145 if (err != 0) {
1146 fprintf(stderr, "write failed for data '%s'\n", text.string());
1147 return errno;
1148 }
1149
1150 return err;
1151}
1152
1153int
1154backup_helper_test_data_writer()
1155{
1156 int err;
1157 int fd;
1158 const char* filename = SCRATCH_DIR "data_writer.data";
1159
1160 system("rm -r " SCRATCH_DIR);
1161 mkdir(SCRATCH_DIR, 0777);
1162 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001163
Joe Onorato62a381b2009-05-15 09:07:06 -04001164 fd = creat(filename, 0666);
1165 if (fd == -1) {
1166 fprintf(stderr, "error creating: %s\n", strerror(errno));
1167 return errno;
1168 }
1169
1170 BackupDataWriter writer(fd);
1171
1172 err = 0;
1173 err |= test_write_header_and_entity(writer, "no_padding_");
1174 err |= test_write_header_and_entity(writer, "padded_to__3");
1175 err |= test_write_header_and_entity(writer, "padded_to_2__");
1176 err |= test_write_header_and_entity(writer, "padded_to1");
1177
Joe Onorato62a381b2009-05-15 09:07:06 -04001178 close(fd);
1179
1180 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1181 if (err != 0) {
1182 return err;
1183 }
1184
1185 return err;
1186}
1187
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001188int
1189test_read_header_and_entity(BackupDataReader& reader, const char* str)
1190{
1191 int err;
1192 int bufSize = strlen(str)+1;
1193 char* buf = (char*)malloc(bufSize);
1194 String8 string;
1195 int cookie = 0x11111111;
1196 size_t actualSize;
Joe Onorato1781fd12009-06-16 16:31:35 -04001197 bool done;
1198 int type;
Christopher Tate02abe532009-06-23 13:03:00 -07001199 ssize_t nRead;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001200
1201 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1202
Joe Onorato1781fd12009-06-16 16:31:35 -04001203 err = reader.ReadNextHeader(&done, &type);
1204 if (done) {
1205 fprintf(stderr, "should not be done yet\n");
1206 goto finished;
1207 }
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001208 if (err != 0) {
1209 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato1781fd12009-06-16 16:31:35 -04001210 goto finished;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001211 }
Joe Onorato1781fd12009-06-16 16:31:35 -04001212 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001213 err = EINVAL;
Joe Onorato1781fd12009-06-16 16:31:35 -04001214 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001215 }
1216
1217 err = reader.ReadEntityHeader(&string, &actualSize);
1218 if (err != 0) {
1219 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato1781fd12009-06-16 16:31:35 -04001220 goto finished;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001221 }
1222 if (string != str) {
1223 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1224 err = EINVAL;
Joe Onorato1781fd12009-06-16 16:31:35 -04001225 goto finished;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001226 }
1227 if ((int)actualSize != bufSize) {
1228 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1229 actualSize);
1230 err = EINVAL;
Joe Onorato1781fd12009-06-16 16:31:35 -04001231 goto finished;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001232 }
1233
Christopher Tate02abe532009-06-23 13:03:00 -07001234 nRead = reader.ReadEntityData(buf, bufSize);
1235 if (nRead < 0) {
1236 err = reader.Status();
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001237 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato1781fd12009-06-16 16:31:35 -04001238 goto finished;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001239 }
1240
1241 if (0 != memcmp(buf, str, bufSize)) {
1242 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato1781fd12009-06-16 16:31:35 -04001243 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1244 buf[0], buf[1], buf[2], buf[3]);
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001245 err = EINVAL;
Joe Onorato1781fd12009-06-16 16:31:35 -04001246 goto finished;
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001247 }
1248
1249 // The next read will confirm whether it got the right amount of data.
1250
Joe Onorato1781fd12009-06-16 16:31:35 -04001251finished:
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001252 if (err != NO_ERROR) {
1253 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1254 }
Christopher Tate585d4f42009-06-24 13:57:29 -07001255 free(buf);
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001256 return err;
1257}
1258
1259int
1260backup_helper_test_data_reader()
1261{
1262 int err;
1263 int fd;
1264 const char* filename = SCRATCH_DIR "data_reader.data";
1265
1266 system("rm -r " SCRATCH_DIR);
1267 mkdir(SCRATCH_DIR, 0777);
1268 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001269
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001270 fd = creat(filename, 0666);
1271 if (fd == -1) {
1272 fprintf(stderr, "error creating: %s\n", strerror(errno));
1273 return errno;
1274 }
1275
1276 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1277 if (err != DATA_GOLDEN_FILE_SIZE) {
1278 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1279 return errno;
1280 }
1281
1282 close(fd);
1283
1284 fd = open(filename, O_RDONLY);
1285 if (fd == -1) {
1286 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1287 filename);
1288 return errno;
1289 }
1290
1291 {
1292 BackupDataReader reader(fd);
1293
1294 err = 0;
1295
1296 if (err == NO_ERROR) {
1297 err = test_read_header_and_entity(reader, "no_padding_");
1298 }
1299
1300 if (err == NO_ERROR) {
1301 err = test_read_header_and_entity(reader, "padded_to__3");
1302 }
1303
1304 if (err == NO_ERROR) {
1305 err = test_read_header_and_entity(reader, "padded_to_2__");
1306 }
1307
1308 if (err == NO_ERROR) {
1309 err = test_read_header_and_entity(reader, "padded_to1");
1310 }
Joe Onoratocd1c1c82009-05-15 18:20:19 -04001311 }
1312
1313 close(fd);
1314
1315 return err;
1316}
1317
Joe Onoratoaaead202009-05-05 11:50:51 -07001318static int
1319get_mod_time(const char* filename, struct timeval times[2])
1320{
1321 int err;
1322 struct stat64 st;
1323 err = stat64(filename, &st);
1324 if (err != 0) {
1325 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1326 return errno;
1327 }
1328 times[0].tv_sec = st.st_atime;
Joe Onoratoaaead202009-05-05 11:50:51 -07001329 times[1].tv_sec = st.st_mtime;
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001330
1331 // If st_atime is a macro then struct stat64 uses struct timespec
1332 // to store the access and modif time values and typically
1333 // st_*time_nsec is not defined. In glibc, this is controlled by
1334 // __USE_MISC.
1335#ifdef __USE_MISC
1336#if !defined(st_atime) || defined(st_atime_nsec)
1337#error "Check if this __USE_MISC conditional is still needed."
1338#endif
1339 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1340 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1341#else
1342 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onoratoaaead202009-05-05 11:50:51 -07001343 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001344#endif
1345
Joe Onoratoaaead202009-05-05 11:50:51 -07001346 return 0;
1347}
1348
1349int
1350backup_helper_test_files()
1351{
1352 int err;
Joe Onoratoaaead202009-05-05 11:50:51 -07001353 int oldSnapshotFD;
Joe Onorato62a381b2009-05-15 09:07:06 -04001354 int dataStreamFD;
1355 int newSnapshotFD;
Joe Onoratoaaead202009-05-05 11:50:51 -07001356
1357 system("rm -r " SCRATCH_DIR);
1358 mkdir(SCRATCH_DIR, 0777);
1359 mkdir(SCRATCH_DIR "data", 0777);
1360
1361 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1362 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1363 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1364 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1365 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1366 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1367
1368 char const* files_before[] = {
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001369 SCRATCH_DIR "data/b",
1370 SCRATCH_DIR "data/c",
1371 SCRATCH_DIR "data/d",
1372 SCRATCH_DIR "data/e",
1373 SCRATCH_DIR "data/f"
1374 };
1375
1376 char const* keys_before[] = {
Joe Onoratoaaead202009-05-05 11:50:51 -07001377 "data/b",
1378 "data/c",
1379 "data/d",
1380 "data/e",
1381 "data/f"
1382 };
1383
Joe Onorato62a381b2009-05-15 09:07:06 -04001384 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1385 if (dataStreamFD == -1) {
1386 fprintf(stderr, "error creating: %s\n", strerror(errno));
1387 return errno;
1388 }
1389
Joe Onoratoaaead202009-05-05 11:50:51 -07001390 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1391 if (newSnapshotFD == -1) {
1392 fprintf(stderr, "error creating: %s\n", strerror(errno));
1393 return errno;
1394 }
Joe Onorato062a4882009-05-19 13:41:21 -07001395
1396 {
1397 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001398
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001399 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onorato062a4882009-05-19 13:41:21 -07001400 if (err != 0) {
1401 return err;
1402 }
Joe Onoratoaaead202009-05-05 11:50:51 -07001403 }
1404
Joe Onorato62a381b2009-05-15 09:07:06 -04001405 close(dataStreamFD);
Joe Onoratoaaead202009-05-05 11:50:51 -07001406 close(newSnapshotFD);
1407
1408 sleep(3);
1409
1410 struct timeval d_times[2];
1411 struct timeval e_times[2];
1412
1413 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1414 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1415 if (err != 0) {
1416 return err;
1417 }
1418
1419 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1420 unlink(SCRATCH_DIR "data/c");
1421 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1422 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1423 utimes(SCRATCH_DIR "data/d", d_times);
1424 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1425 utimes(SCRATCH_DIR "data/e", e_times);
1426 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1427 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001428
Joe Onoratoaaead202009-05-05 11:50:51 -07001429 char const* files_after[] = {
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001430 SCRATCH_DIR "data/a", // added
1431 SCRATCH_DIR "data/b", // same
1432 SCRATCH_DIR "data/c", // different mod time
1433 SCRATCH_DIR "data/d", // different size (same mod time)
1434 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1435 SCRATCH_DIR "data/g" // added
1436 };
1437
1438 char const* keys_after[] = {
Joe Onoratoaaead202009-05-05 11:50:51 -07001439 "data/a", // added
1440 "data/b", // same
1441 "data/c", // different mod time
1442 "data/d", // different size (same mod time)
1443 "data/e", // different contents (same mod time, same size)
1444 "data/g" // added
1445 };
1446
1447 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1448 if (oldSnapshotFD == -1) {
1449 fprintf(stderr, "error opening: %s\n", strerror(errno));
1450 return errno;
1451 }
1452
Joe Onorato62a381b2009-05-15 09:07:06 -04001453 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1454 if (dataStreamFD == -1) {
1455 fprintf(stderr, "error creating: %s\n", strerror(errno));
1456 return errno;
1457 }
1458
Joe Onoratoaaead202009-05-05 11:50:51 -07001459 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1460 if (newSnapshotFD == -1) {
1461 fprintf(stderr, "error creating: %s\n", strerror(errno));
1462 return errno;
1463 }
1464
Joe Onorato062a4882009-05-19 13:41:21 -07001465 {
1466 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001467
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001468 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onorato062a4882009-05-19 13:41:21 -07001469 if (err != 0) {
1470 return err;
1471 }
1472}
Joe Onoratoaaead202009-05-05 11:50:51 -07001473
1474 close(oldSnapshotFD);
Joe Onorato62a381b2009-05-15 09:07:06 -04001475 close(dataStreamFD);
Joe Onoratoaaead202009-05-05 11:50:51 -07001476 close(newSnapshotFD);
Nicolas Cataniad5e0fd42009-05-22 13:41:38 -07001477
Joe Onoratoaaead202009-05-05 11:50:51 -07001478 return 0;
1479}
1480
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001481int
1482backup_helper_test_null_base()
1483{
1484 int err;
1485 int oldSnapshotFD;
1486 int dataStreamFD;
1487 int newSnapshotFD;
1488
1489 system("rm -r " SCRATCH_DIR);
1490 mkdir(SCRATCH_DIR, 0777);
1491 mkdir(SCRATCH_DIR "data", 0777);
1492
1493 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1494
1495 char const* files[] = {
1496 SCRATCH_DIR "data/a",
1497 };
1498
1499 char const* keys[] = {
1500 "a",
1501 };
1502
1503 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1504 if (dataStreamFD == -1) {
1505 fprintf(stderr, "error creating: %s\n", strerror(errno));
1506 return errno;
1507 }
1508
1509 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1510 if (newSnapshotFD == -1) {
1511 fprintf(stderr, "error creating: %s\n", strerror(errno));
1512 return errno;
1513 }
1514
1515 {
1516 BackupDataWriter dataStream(dataStreamFD);
1517
1518 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1519 if (err != 0) {
1520 return err;
1521 }
1522 }
1523
1524 close(dataStreamFD);
1525 close(newSnapshotFD);
1526
1527 return 0;
1528}
1529
Joe Onorato9becbac2009-06-11 11:27:16 -07001530int
1531backup_helper_test_missing_file()
1532{
1533 int err;
1534 int oldSnapshotFD;
1535 int dataStreamFD;
1536 int newSnapshotFD;
1537
1538 system("rm -r " SCRATCH_DIR);
1539 mkdir(SCRATCH_DIR, 0777);
1540 mkdir(SCRATCH_DIR "data", 0777);
1541
1542 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1543
1544 char const* files[] = {
1545 SCRATCH_DIR "data/a",
1546 SCRATCH_DIR "data/b",
1547 SCRATCH_DIR "data/c",
1548 };
1549
1550 char const* keys[] = {
1551 "a",
1552 "b",
1553 "c",
1554 };
1555
1556 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1557 if (dataStreamFD == -1) {
1558 fprintf(stderr, "error creating: %s\n", strerror(errno));
1559 return errno;
1560 }
1561
1562 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1563 if (newSnapshotFD == -1) {
1564 fprintf(stderr, "error creating: %s\n", strerror(errno));
1565 return errno;
1566 }
1567
1568 {
1569 BackupDataWriter dataStream(dataStreamFD);
1570
1571 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1572 if (err != 0) {
1573 return err;
1574 }
1575 }
1576
1577 close(dataStreamFD);
1578 close(newSnapshotFD);
1579
1580 return 0;
1581}
1582
Joe Onorato0d1d7ae2009-06-10 17:07:15 -07001583
Joe Onoratoaaead202009-05-05 11:50:51 -07001584#endif // TEST_BACKUP_HELPERS
Joe Onorato62a381b2009-05-15 09:07:06 -04001585
1586}