blob: b8d3f48e3347e964735400d4ae0ace38bda350bc [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 Agopianb13b9bd2012-02-17 18:27:36 -080019#include <androidfw/BackupHelpers.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070020
21#include <utils/KeyedVector.h>
22#include <utils/ByteOrder.h>
23#include <utils/String8.h>
24
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/uio.h>
28#include <sys/stat.h>
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -070029#include <sys/time.h> // for utimes
Joe Onorato3ad977b2009-05-05 11:50:51 -070030#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
Joe Onoratoc825d3e2009-05-06 12:55:46 -040033#include <utime.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070034#include <fcntl.h>
35#include <zlib.h>
36
37#include <cutils/log.h>
38
Joe Onorato4535e402009-05-15 09:07:06 -040039namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070040
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
Christopher Tatefbb92382009-06-23 17:35:11 -070044/*
45 * File entity data format (v1):
46 *
47 * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
48 * - 12 bytes of metadata
49 * - the file data itself
50 *
51 * i.e. a 16-byte metadata header followed by the raw file data. If the
52 * restore code does not recognize the metadata version, it can still
53 * interpret the file data itself correctly.
54 *
55 * file_metadata_v1:
56 *
57 * - 4 byte version number === 0x00000001 (little endian)
58 * - 4-byte access mode (little-endian)
59 * - undefined (8 bytes)
60 */
61
62struct file_metadata_v1 {
63 int version;
64 int mode;
65 int undefined_1;
66 int undefined_2;
67};
68
69const static int CURRENT_METADATA_VERSION = 1;
70
Joe Onorato568bc322009-06-26 17:19:11 -040071#if 1
72#define LOGP(f, x...)
73#else
74#if TEST_BACKUP_HELPERS
Joe Onorato23ecae32009-06-10 17:07:15 -070075#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040076#else
Steve Block5baa3a62011-12-20 16:23:08 +000077#define LOGP(x...) ALOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040078#endif
Joe Onorato568bc322009-06-26 17:19:11 -040079#endif
Joe Onorato290bb012009-05-13 18:57:29 -040080
Joe Onorato3ad977b2009-05-05 11:50:51 -070081const static int ROUND_UP[4] = { 0, 3, 2, 1 };
82
83static inline int
84round_up(int n)
85{
86 return n + ROUND_UP[n % 4];
87}
88
89static int
90read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
91{
92 int bytesRead = 0;
93 int amt;
94 SnapshotHeader header;
95
96 amt = read(fd, &header, sizeof(header));
97 if (amt != sizeof(header)) {
98 return errno;
99 }
100 bytesRead += amt;
101
102 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000103 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700104 return 1;
105 }
106
107 for (int i=0; i<header.fileCount; i++) {
108 FileState file;
109 char filenameBuf[128];
110
Joe Onorato23ecae32009-06-10 17:07:15 -0700111 amt = read(fd, &file, sizeof(FileState));
112 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000113 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700114 return 1;
115 }
116 bytesRead += amt;
117
118 // filename is not NULL terminated, but it is padded
119 int nameBufSize = round_up(file.nameLen);
120 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
121 ? filenameBuf
122 : (char*)malloc(nameBufSize);
123 amt = read(fd, filename, nameBufSize);
124 if (amt == nameBufSize) {
125 snapshot->add(String8(filename, file.nameLen), file);
126 }
127 bytesRead += amt;
128 if (filename != filenameBuf) {
129 free(filename);
130 }
131 if (amt != nameBufSize) {
Steve Block8564c8d2012-01-05 23:22:43 +0000132 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700133 return 1;
134 }
135 }
136
137 if (header.totalSize != bytesRead) {
Steve Block8564c8d2012-01-05 23:22:43 +0000138 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700139 header.totalSize, bytesRead);
140 return 1;
141 }
142
143 return 0;
144}
145
146static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700147write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700148{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700149 int fileCount = 0;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700150 int bytesWritten = sizeof(SnapshotHeader);
151 // preflight size
152 const int N = snapshot.size();
153 for (int i=0; i<N; i++) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700154 const FileRec& g = snapshot.valueAt(i);
155 if (!g.deleted) {
156 const String8& name = snapshot.keyAt(i);
157 bytesWritten += sizeof(FileState) + round_up(name.length());
158 fileCount++;
159 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700160 }
161
Joe Onorato4535e402009-05-15 09:07:06 -0400162 LOGP("write_snapshot_file fd=%d\n", fd);
163
Joe Onorato3ad977b2009-05-05 11:50:51 -0700164 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-05-05 11:50:51 -0700166
167 amt = write(fd, &header, sizeof(header));
168 if (amt != sizeof(header)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000169 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700170 return errno;
171 }
172
Joe Onoratoce88cb12009-06-11 11:27:16 -0700173 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700174 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700175 if (!r.deleted) {
176 const String8& name = snapshot.keyAt(i);
177 int nameLen = r.s.nameLen = name.length();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700178
Joe Onoratoce88cb12009-06-11 11:27:16 -0700179 amt = write(fd, &r.s, sizeof(FileState));
180 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000181 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700182 return 1;
183 }
Joe Onoratoce88cb12009-06-11 11:27:16 -0700184
185 // filename is not NULL terminated, but it is padded
186 amt = write(fd, name.string(), nameLen);
187 if (amt != nameLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000188 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
Joe Onoratoce88cb12009-06-11 11:27:16 -0700189 return 1;
190 }
191 int paddingLen = ROUND_UP[nameLen % 4];
192 if (paddingLen != 0) {
193 int padding = 0xabababab;
194 amt = write(fd, &padding, paddingLen);
195 if (amt != paddingLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000196 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s",
Joe Onoratoce88cb12009-06-11 11:27:16 -0700197 paddingLen, strerror(errno));
198 return 1;
199 }
200 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700201 }
202 }
203
204 return 0;
205}
206
207static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700208write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700209{
Joe Onorato290bb012009-05-13 18:57:29 -0400210 LOGP("write_delete_file %s\n", key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700211 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700212}
213
214static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700215write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700216 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700217{
Christopher Tatefbb92382009-06-23 17:35:11 -0700218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700219
220 const int bufsize = 4*1024;
221 int err;
222 int amt;
223 int fileSize;
224 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700225 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700226
227 char* buf = (char*)malloc(bufsize);
228 int crc = crc32(0L, Z_NULL, 0);
229
230
Christopher Tatefbb92382009-06-23 17:35:11 -0700231 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700232 lseek(fd, 0, SEEK_SET);
233
Christopher Tatefbb92382009-06-23 17:35:11 -0700234 if (sizeof(metadata) != 16) {
Steve Block3762c312012-01-06 19:20:56 +0000235 ALOGE("ERROR: metadata block is the wrong size!");
Christopher Tatefbb92382009-06-23 17:35:11 -0700236 }
237
238 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700239 err = dataStream->WriteEntityHeader(key, bytesLeft);
240 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700241 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700242 return err;
243 }
244
Christopher Tatefbb92382009-06-23 17:35:11 -0700245 // store the file metadata first
246 metadata.version = tolel(CURRENT_METADATA_VERSION);
247 metadata.mode = tolel(mode);
248 metadata.undefined_1 = metadata.undefined_2 = 0;
249 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
250 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700251 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700252 return err;
253 }
254 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
255
256 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700257 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
258 bytesLeft -= amt;
259 if (bytesLeft < 0) {
260 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
261 }
262 err = dataStream->WriteEntityData(buf, amt);
263 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700264 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700265 return err;
266 }
267 }
268 if (bytesLeft != 0) {
269 if (bytesLeft > 0) {
270 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
271 // even though the data we're sending is probably bad.
272 memset(buf, 0, bufsize);
273 while (bytesLeft > 0) {
274 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
275 bytesLeft -= amt;
276 err = dataStream->WriteEntityData(buf, amt);
277 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700278 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700279 return err;
280 }
281 }
282 }
Steve Block3762c312012-01-06 19:20:56 +0000283 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700284 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700285 }
286
Christopher Tate63bcb792009-06-24 13:57:29 -0700287 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700288 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700289}
290
291static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700292write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700293{
294 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700295 struct stat st;
296
297 err = stat(realFilename, &st);
298 if (err < 0) {
299 return errno;
300 }
301
Joe Onorato23ecae32009-06-10 17:07:15 -0700302 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700303 if (fd == -1) {
304 return errno;
305 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700306
307 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700308 close(fd);
309 return err;
310}
311
312static int
313compute_crc32(int fd)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700314{
315 const int bufsize = 4*1024;
316 int amt;
317
Joe Onorato3ad977b2009-05-05 11:50:51 -0700318 char* buf = (char*)malloc(bufsize);
319 int crc = crc32(0L, Z_NULL, 0);
320
Joe Onoratod2110db2009-05-19 13:41:21 -0700321 lseek(fd, 0, SEEK_SET);
322
Joe Onorato3ad977b2009-05-05 11:50:51 -0700323 while ((amt = read(fd, buf, bufsize)) != 0) {
324 crc = crc32(crc, (Bytef*)buf, amt);
325 }
326
Christopher Tate63bcb792009-06-24 13:57:29 -0700327 free(buf);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700328 return crc;
329}
330
331int
Joe Onoratod2110db2009-05-19 13:41:21 -0700332back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700333 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700334{
335 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700336 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700337 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700338
339 if (oldSnapshotFD != -1) {
340 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
341 if (err != 0) {
342 // On an error, treat this as a full backup.
343 oldSnapshot.clear();
344 }
345 }
346
347 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700348 String8 key(keys[i]);
349 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700350 char const* file = files[i];
351 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700352 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700353
Joe Onorato23ecae32009-06-10 17:07:15 -0700354 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700355 if (err != 0) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700356 r.deleted = true;
357 } else {
358 r.deleted = false;
359 r.s.modTime_sec = st.st_mtime;
360 r.s.modTime_nsec = 0; // workaround sim breakage
361 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700362 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700363 r.s.size = st.st_size;
364 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato3ad977b2009-05-05 11:50:51 -0700365
Joe Onoratoce88cb12009-06-11 11:27:16 -0700366 if (newSnapshot.indexOfKey(key) >= 0) {
367 LOGP("back_up_files key already in use '%s'", key.string());
368 return -1;
369 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700370 }
371 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700372 }
373
374 int n = 0;
375 int N = oldSnapshot.size();
376 int m = 0;
377
378 while (n<N && m<fileCount) {
379 const String8& p = oldSnapshot.keyAt(n);
380 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700381 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700382 int cmp = p.compare(q);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700383 if (g.deleted || cmp < 0) {
384 // file removed
385 LOGP("file removed: %s", p.string());
386 g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
387 dataStream->WriteEntityHeader(p, -1);
388 n++;
389 }
390 else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 // file added
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700392 LOGP("file added: %s", g.file.string());
393 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700394 m++;
395 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700396 else {
397 // both files exist, check them
Joe Onorato3ad977b2009-05-05 11:50:51 -0700398 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700399
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700400 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate0032ce82009-06-04 17:01:06 -0700401 if (fd < 0) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700402 // We can't open the file. Don't report it as a delete either. Let the
403 // server keep the old version. Maybe they'll be able to deal with it
404 // on restore.
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700405 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700406 } else {
Joe Onorato23ecae32009-06-10 17:07:15 -0700407 g.s.crc32 = compute_crc32(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700408
Joe Onorato23ecae32009-06-10 17:07:15 -0700409 LOGP("%s", q.string());
Christopher Tate11b15772009-06-23 13:03:00 -0700410 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
411 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
412 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
413 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
Joe Onorato23ecae32009-06-10 17:07:15 -0700414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tate11b15772009-06-23 13:03:00 -0700415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tatefbb92382009-06-23 17:35:11 -0700416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700417 }
418
419 close(fd);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700420 }
421 n++;
422 m++;
423 }
424 }
425
426 // these were deleted
427 while (n<N) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700428 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700429 n++;
430 }
431
432 // these were added
433 while (m<fileCount) {
434 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700435 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700436 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700437 m++;
438 }
439
440 err = write_snapshot_file(newSnapshotFD, newSnapshot);
441
442 return 0;
443}
444
Christopher Tate4a627c72011-04-01 14:43:32 -0700445// Utility function, equivalent to stpcpy(): perform a strcpy, but instead of
446// returning the initial dest, return a pointer to the trailing NUL.
447static char* strcpy_ptr(char* dest, const char* str) {
448 if (dest && str) {
449 while ((*dest = *str) != 0) {
450 dest++;
451 str++;
452 }
453 }
454 return dest;
455}
456
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700457static void calc_tar_checksum(char* buf) {
458 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
459 memset(buf + 148, ' ', 8);
460
461 uint16_t sum = 0;
462 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
463 sum += *p;
464 }
465
466 // Now write the real checksum value:
467 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
468 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
469}
470
Christopher Tatedc92c822011-05-13 15:38:02 -0700471// Returns number of bytes written
472static int write_pax_header_entry(char* buf, const char* key, const char* value) {
473 // start with the size of "1 key=value\n"
474 int len = strlen(key) + strlen(value) + 4;
475 if (len > 9) len++;
476 if (len > 99) len++;
477 if (len > 999) len++;
478 // since PATH_MAX is 4096 we don't expect to have to generate any single
479 // header entry longer than 9999 characters
480
481 return sprintf(buf, "%d %s=%s\n", len, key, value);
482}
483
Christopher Tate7926a692011-07-11 11:31:57 -0700484// Wire format to the backup manager service is chunked: each chunk is prefixed by
485// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
486void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
487 uint32_t chunk_size_no = htonl(size);
488 writer->WriteEntityData(&chunk_size_no, 4);
489 if (size != 0) writer->WriteEntityData(buffer, size);
490}
491
Christopher Tate4a627c72011-04-01 14:43:32 -0700492int write_tarfile(const String8& packageName, const String8& domain,
493 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
494{
495 // In the output stream everything is stored relative to the root
496 const char* relstart = filepath.string() + rootpath.length();
497 if (*relstart == '/') relstart++; // won't be true when path == rootpath
498 String8 relpath(relstart);
499
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700500 // If relpath is empty, it means this is the top of one of the standard named
501 // domain directories, so we should just skip it
502 if (relpath.length() == 0) {
503 return 0;
504 }
505
Christopher Tate4a627c72011-04-01 14:43:32 -0700506 // Too long a name for the ustar format?
507 // "apps/" + packagename + '/' + domainpath < 155 chars
508 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700509 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700510 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700511 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700512 }
513
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700514 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700515 if (!needExtended) {
516 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700517 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700518 needExtended = true;
519 break;
520 }
521 }
522 }
523
Christopher Tate4a627c72011-04-01 14:43:32 -0700524 int err = 0;
525 struct stat64 s;
526 if (lstat64(filepath.string(), &s) != 0) {
527 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000528 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700529 return err;
530 }
531
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700532 String8 fullname; // for pax later on
533 String8 prefix;
534
Christopher Tate4a627c72011-04-01 14:43:32 -0700535 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700536 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700537
538 // !!! TODO: use mmap when possible to avoid churning the buffer cache
539 // !!! TODO: this will break with symlinks; need to use readlink(2)
540 int fd = open(filepath.string(), O_RDONLY);
541 if (fd < 0) {
542 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000543 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700544 return err;
545 }
546
547 // read/write up to this much at a time.
548 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800549 char* buf = (char *)calloc(1,BUFSIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700550 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
551 char* paxData = buf + 1024;
552
Christopher Tate4a627c72011-04-01 14:43:32 -0700553 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000554 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700555 err = ENOMEM;
Christopher Tate46cc43c2013-02-19 14:08:59 -0800556 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700557 }
558
Christopher Tate4a627c72011-04-01 14:43:32 -0700559 // Magic fields for the ustar file format
560 strcat(buf + 257, "ustar");
561 strcat(buf + 263, "00");
562
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700563 // [ 265 : 32 ] user name, ignored on restore
564 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700565
566 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700567 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700568
569 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
570 // [ 116 : 8 ] gid -- ignored in Android format
571 snprintf(buf + 108, 8, "0%lo", s.st_uid);
572 snprintf(buf + 116, 8, "0%lo", s.st_gid);
573
574 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700575 if (s.st_size > 077777777777LL) {
576 // very large files need a pax extended size header
577 needExtended = true;
578 }
579 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700580
581 // [ 136 : 12 ] last mod time as a UTC time_t
582 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
583
Christopher Tate4a627c72011-04-01 14:43:32 -0700584 // [ 156 : 1 ] link/file type
585 uint8_t type;
586 if (isdir) {
587 type = '5'; // tar magic: '5' == directory
588 } else if (S_ISREG(s.st_mode)) {
589 type = '0'; // tar magic: '0' == normal file
590 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000591 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700592 goto cleanup;
593 }
594 buf[156] = type;
595
596 // [ 157 : 100 ] name of linked file [not implemented]
597
Christopher Tate4a627c72011-04-01 14:43:32 -0700598 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700599 // Prefix and main relative path. Path lengths have been preflighted.
600 if (packageName.length() > 0) {
601 prefix = "apps/";
602 prefix += packageName;
603 }
604 if (domain.length() > 0) {
605 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700606 }
607
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700608 // pax extended means we don't put in a prefix field, and put a different
609 // string in the basic name field. We can also construct the full path name
610 // out of the substrings we've now built.
611 fullname = prefix;
612 fullname.appendPath(relpath);
613
614 // ustar:
615 // [ 0 : 100 ]; file name/path
616 // [ 345 : 155 ] filename path prefix
617 // We only use the prefix area if fullname won't fit in the path
618 if (fullname.length() > 100) {
619 strncpy(buf, relpath.string(), 100);
620 strncpy(buf + 345, prefix.string(), 155);
621 } else {
622 strncpy(buf, fullname.string(), 100);
623 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700624 }
625
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700626 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
627
Steve Block6215d3f2012-01-04 20:05:49 +0000628 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700629
630 // If we're using a pax extended header, build & write that here; lengths are
631 // already preflighted
632 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700633 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
634 char* p = paxData;
635
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700636 // construct the pax extended header data block
637 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700638 int len;
639
640 // size header -- calc len in digits by actually rendering the number
641 // to a string - brute force but simple
Christopher Tatedc92c822011-05-13 15:38:02 -0700642 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
643 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700644
645 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700646 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700647
648 // Now we know how big the pax data is
649 int paxLen = p - paxData;
650
651 // Now build the pax *header* templated on the ustar header
652 memcpy(paxHeader, buf, 512);
653
654 String8 leaf = fullname.getPathLeaf();
655 memset(paxHeader, 0, 100); // rewrite the name area
656 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
657 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
658 strncpy(paxHeader + 345, prefix.string(), 155);
659
660 paxHeader[156] = 'x'; // mark it as a pax extended header
661
662 // [ 124 : 12 ] size of pax extended header data
663 memset(paxHeader + 124, 0, 12);
664 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
665
666 // Checksum and write the pax block header
667 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700668 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700669
670 // Now write the pax data itself
671 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700672 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700673 }
674
675 // Checksum and write the 512-byte ustar file header block to the output
676 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700677 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700678
679 // Now write the file data itself, for real files. We honor tar's convention that
680 // only full 512-byte blocks are sent to write().
681 if (!isdir) {
682 off64_t toWrite = s.st_size;
683 while (toWrite > 0) {
684 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
685 ssize_t nRead = read(fd, buf, toRead);
686 if (nRead < 0) {
687 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000688 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700689 err, strerror(err));
690 break;
691 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000692 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700693 filepath.string());
694 err = EIO;
695 break;
696 }
697
698 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
699 // depends on the OS guarantee that for ordinary files, read() will never return
700 // less than the number of bytes requested.
701 ssize_t partial = (nRead+512) % 512;
702 if (partial > 0) {
703 ssize_t remainder = 512 - partial;
704 memset(buf + nRead, 0, remainder);
705 nRead += remainder;
706 }
Christopher Tate7926a692011-07-11 11:31:57 -0700707 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700708 toWrite -= nRead;
709 }
710 }
711
712cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900713 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700714done:
715 close(fd);
716 return err;
717}
718// end tarfile
719
720
721
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700722#define RESTORE_BUF_SIZE (8*1024)
723
724RestoreHelperBase::RestoreHelperBase()
725{
726 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700727 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700728}
729
730RestoreHelperBase::~RestoreHelperBase()
731{
732 free(m_buf);
733}
734
735status_t
736RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
737{
738 ssize_t err;
739 size_t dataSize;
740 String8 key;
741 int fd;
742 void* buf = m_buf;
743 ssize_t amt;
744 int mode;
745 int crc;
746 struct stat st;
747 FileRec r;
748
749 err = in->ReadEntityHeader(&key, &dataSize);
750 if (err != NO_ERROR) {
751 return err;
752 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700753
Christopher Tatefbb92382009-06-23 17:35:11 -0700754 // Get the metadata block off the head of the file entity and use that to
755 // set up the output file
756 file_metadata_v1 metadata;
757 amt = in->ReadEntityData(&metadata, sizeof(metadata));
758 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000759 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700760 (long)amt, strerror(errno));
761 return EIO;
762 }
763 metadata.version = fromlel(metadata.version);
764 metadata.mode = fromlel(metadata.mode);
765 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700766 if (!m_loggedUnknownMetadata) {
767 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000768 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700769 metadata.version, CURRENT_METADATA_VERSION);
770 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700771 }
772 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700773
774 // Write the file and compute the crc
775 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700776 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
777 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000778 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700779 return errno;
780 }
781
782 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
783 err = write(fd, buf, amt);
784 if (err != amt) {
785 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000786 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700787 return errno;
788 }
789 crc = crc32(crc, (Bytef*)buf, amt);
790 }
791
792 close(fd);
793
794 // Record for the snapshot
795 err = stat(filename.string(), &st);
796 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000797 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700798 return errno;
799 }
800
801 r.file = filename;
802 r.deleted = false;
803 r.s.modTime_sec = st.st_mtime;
804 r.s.modTime_nsec = 0; // workaround sim breakage
805 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700806 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700807 r.s.size = st.st_size;
808 r.s.crc32 = crc;
809
810 m_files.add(key, r);
811
812 return NO_ERROR;
813}
814
815status_t
816RestoreHelperBase::WriteSnapshot(int fd)
817{
818 return write_snapshot_file(fd, m_files);;
819}
820
Joe Onorato3ad977b2009-05-05 11:50:51 -0700821#if TEST_BACKUP_HELPERS
822
823#define SCRATCH_DIR "/data/backup_helper_test/"
824
825static int
826write_text_file(const char* path, const char* data)
827{
828 int amt;
829 int fd;
830 int len;
831
832 fd = creat(path, 0666);
833 if (fd == -1) {
834 fprintf(stderr, "creat %s failed\n", path);
835 return errno;
836 }
837
838 len = strlen(data);
839 amt = write(fd, data, len);
840 if (amt != len) {
841 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
842 return errno;
843 }
844
845 close(fd);
846
847 return 0;
848}
849
850static int
851compare_file(const char* path, const unsigned char* data, int len)
852{
853 int fd;
854 int amt;
855
856 fd = open(path, O_RDONLY);
857 if (fd == -1) {
858 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
859 return errno;
860 }
861
862 unsigned char* contents = (unsigned char*)malloc(len);
863 if (contents == NULL) {
864 fprintf(stderr, "malloc(%d) failed\n", len);
865 return ENOMEM;
866 }
867
868 bool sizesMatch = true;
869 amt = lseek(fd, 0, SEEK_END);
870 if (amt != len) {
871 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
872 sizesMatch = false;
873 }
874 lseek(fd, 0, SEEK_SET);
875
876 int readLen = amt < len ? amt : len;
877 amt = read(fd, contents, readLen);
878 if (amt != readLen) {
879 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
880 }
881
882 bool contentsMatch = true;
883 for (int i=0; i<readLen; i++) {
884 if (data[i] != contents[i]) {
885 if (contentsMatch) {
886 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
887 contentsMatch = false;
888 }
889 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
890 }
891 }
892
Christopher Tate63bcb792009-06-24 13:57:29 -0700893 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700894 return contentsMatch && sizesMatch ? 0 : 1;
895}
896
897int
898backup_helper_test_empty()
899{
900 int err;
901 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700902 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700903 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
904
905 system("rm -r " SCRATCH_DIR);
906 mkdir(SCRATCH_DIR, 0777);
907
908 // write
909 fd = creat(filename, 0666);
910 if (fd == -1) {
911 fprintf(stderr, "error creating %s\n", filename);
912 return 1;
913 }
914
915 err = write_snapshot_file(fd, snapshot);
916
917 close(fd);
918
919 if (err != 0) {
920 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
921 return err;
922 }
923
924 static const unsigned char correct_data[] = {
925 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
926 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
927 };
928
929 err = compare_file(filename, correct_data, sizeof(correct_data));
930 if (err != 0) {
931 return err;
932 }
933
934 // read
935 fd = open(filename, O_RDONLY);
936 if (fd == -1) {
937 fprintf(stderr, "error opening for read %s\n", filename);
938 return 1;
939 }
940
941 KeyedVector<String8,FileState> readSnapshot;
942 err = read_snapshot_file(fd, &readSnapshot);
943 if (err != 0) {
944 fprintf(stderr, "read_snapshot_file failed %d\n", err);
945 return err;
946 }
947
948 if (readSnapshot.size() != 0) {
949 fprintf(stderr, "readSnapshot should be length 0\n");
950 return 1;
951 }
952
953 return 0;
954}
955
956int
957backup_helper_test_four()
958{
959 int err;
960 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700961 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700962 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
963
964 system("rm -r " SCRATCH_DIR);
965 mkdir(SCRATCH_DIR, 0777);
966
967 // write
968 fd = creat(filename, 0666);
969 if (fd == -1) {
970 fprintf(stderr, "error opening %s\n", filename);
971 return 1;
972 }
973
974 String8 filenames[4];
975 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700976 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700977 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700978
979 states[0].modTime_sec = 0xfedcba98;
980 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700981 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700982 states[0].size = 0xababbcbc;
983 states[0].crc32 = 0x12345678;
984 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700985 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700986 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700987 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700988
989 states[1].modTime_sec = 0x93400031;
990 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700991 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700992 states[1].size = 0x88557766;
993 states[1].crc32 = 0x22334422;
994 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700995 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700996 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700997 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700998
999 states[2].modTime_sec = 0x33221144;
1000 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001001 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -07001002 states[2].size = 0x11223344;
1003 states[2].crc32 = 0x01122334;
1004 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001005 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001006 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001007 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001008
1009 states[3].modTime_sec = 0x33221144;
1010 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001011 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001012 states[3].size = 0x11223344;
1013 states[3].crc32 = 0x01122334;
1014 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001015 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001016 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001017 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001018
1019 err = write_snapshot_file(fd, snapshot);
1020
1021 close(fd);
1022
1023 if (err != 0) {
1024 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1025 return err;
1026 }
1027
1028 static const unsigned char correct_data[] = {
1029 // header
1030 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001031 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001032
1033 // bytes_of_padding
1034 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001035 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1036 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1037 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1038 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001039
1040 // bytes_of_padding3
1041 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001042 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1043 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1044 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1045 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1046 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001047
Joe Onorato3ad977b2009-05-05 11:50:51 -07001048 // bytes of padding2
1049 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001050 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1051 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1052 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1053 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1054 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001055
Joe Onorato3ad977b2009-05-05 11:50:51 -07001056 // bytes of padding3
1057 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001058 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1059 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1060 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1061 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1062 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001063 };
1064
1065 err = compare_file(filename, correct_data, sizeof(correct_data));
1066 if (err != 0) {
1067 return err;
1068 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001069
Joe Onorato3ad977b2009-05-05 11:50:51 -07001070 // read
1071 fd = open(filename, O_RDONLY);
1072 if (fd == -1) {
1073 fprintf(stderr, "error opening for read %s\n", filename);
1074 return 1;
1075 }
1076
1077
1078 KeyedVector<String8,FileState> readSnapshot;
1079 err = read_snapshot_file(fd, &readSnapshot);
1080 if (err != 0) {
1081 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1082 return err;
1083 }
1084
1085 if (readSnapshot.size() != 4) {
1086 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1087 return 1;
1088 }
1089
1090 bool matched = true;
1091 for (size_t i=0; i<readSnapshot.size(); i++) {
1092 const String8& name = readSnapshot.keyAt(i);
1093 const FileState state = readSnapshot.valueAt(i);
1094
1095 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001096 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001097 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-06-23 13:03:00 -07001098 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1099 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1100 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1101 states[i].crc32, name.length(), filenames[i].string(),
1102 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1103 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001104 matched = false;
1105 }
1106 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001107
Joe Onorato3ad977b2009-05-05 11:50:51 -07001108 return matched ? 0 : 1;
1109}
1110
Joe Onorato4535e402009-05-15 09:07:06 -04001111// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1112const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001113 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1114 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1115 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1116 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001117 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1118 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001119 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1120 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001121 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001122 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001123 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1124 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001125 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001126 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1127 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001128 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001129 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1130 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1131 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001132 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1133
Joe Onorato4535e402009-05-15 09:07:06 -04001134};
1135const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1136
1137static int
1138test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1139{
1140 int err;
1141 String8 text(str);
1142
Joe Onorato4535e402009-05-15 09:07:06 -04001143 err = writer.WriteEntityHeader(text, text.length()+1);
1144 if (err != 0) {
1145 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1146 return err;
1147 }
1148
1149 err = writer.WriteEntityData(text.string(), text.length()+1);
1150 if (err != 0) {
1151 fprintf(stderr, "write failed for data '%s'\n", text.string());
1152 return errno;
1153 }
1154
1155 return err;
1156}
1157
1158int
1159backup_helper_test_data_writer()
1160{
1161 int err;
1162 int fd;
1163 const char* filename = SCRATCH_DIR "data_writer.data";
1164
1165 system("rm -r " SCRATCH_DIR);
1166 mkdir(SCRATCH_DIR, 0777);
1167 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001168
Joe Onorato4535e402009-05-15 09:07:06 -04001169 fd = creat(filename, 0666);
1170 if (fd == -1) {
1171 fprintf(stderr, "error creating: %s\n", strerror(errno));
1172 return errno;
1173 }
1174
1175 BackupDataWriter writer(fd);
1176
1177 err = 0;
1178 err |= test_write_header_and_entity(writer, "no_padding_");
1179 err |= test_write_header_and_entity(writer, "padded_to__3");
1180 err |= test_write_header_and_entity(writer, "padded_to_2__");
1181 err |= test_write_header_and_entity(writer, "padded_to1");
1182
Joe Onorato4535e402009-05-15 09:07:06 -04001183 close(fd);
1184
1185 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1186 if (err != 0) {
1187 return err;
1188 }
1189
1190 return err;
1191}
1192
Joe Onorato2e1da322009-05-15 18:20:19 -04001193int
1194test_read_header_and_entity(BackupDataReader& reader, const char* str)
1195{
1196 int err;
1197 int bufSize = strlen(str)+1;
1198 char* buf = (char*)malloc(bufSize);
1199 String8 string;
1200 int cookie = 0x11111111;
1201 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001202 bool done;
1203 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001204 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001205
1206 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1207
Joe Onorato5f15d152009-06-16 16:31:35 -04001208 err = reader.ReadNextHeader(&done, &type);
1209 if (done) {
1210 fprintf(stderr, "should not be done yet\n");
1211 goto finished;
1212 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001213 if (err != 0) {
1214 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001215 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001216 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001217 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001218 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001219 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001220 }
1221
1222 err = reader.ReadEntityHeader(&string, &actualSize);
1223 if (err != 0) {
1224 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001225 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 }
1227 if (string != str) {
1228 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1229 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001230 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001231 }
1232 if ((int)actualSize != bufSize) {
1233 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1234 actualSize);
1235 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001236 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001237 }
1238
Christopher Tate11b15772009-06-23 13:03:00 -07001239 nRead = reader.ReadEntityData(buf, bufSize);
1240 if (nRead < 0) {
1241 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001242 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001243 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001244 }
1245
1246 if (0 != memcmp(buf, str, bufSize)) {
1247 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001248 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1249 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001250 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001251 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001252 }
1253
1254 // The next read will confirm whether it got the right amount of data.
1255
Joe Onorato5f15d152009-06-16 16:31:35 -04001256finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001257 if (err != NO_ERROR) {
1258 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1259 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001260 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001261 return err;
1262}
1263
1264int
1265backup_helper_test_data_reader()
1266{
1267 int err;
1268 int fd;
1269 const char* filename = SCRATCH_DIR "data_reader.data";
1270
1271 system("rm -r " SCRATCH_DIR);
1272 mkdir(SCRATCH_DIR, 0777);
1273 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001274
Joe Onorato2e1da322009-05-15 18:20:19 -04001275 fd = creat(filename, 0666);
1276 if (fd == -1) {
1277 fprintf(stderr, "error creating: %s\n", strerror(errno));
1278 return errno;
1279 }
1280
1281 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1282 if (err != DATA_GOLDEN_FILE_SIZE) {
1283 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1284 return errno;
1285 }
1286
1287 close(fd);
1288
1289 fd = open(filename, O_RDONLY);
1290 if (fd == -1) {
1291 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1292 filename);
1293 return errno;
1294 }
1295
1296 {
1297 BackupDataReader reader(fd);
1298
1299 err = 0;
1300
1301 if (err == NO_ERROR) {
1302 err = test_read_header_and_entity(reader, "no_padding_");
1303 }
1304
1305 if (err == NO_ERROR) {
1306 err = test_read_header_and_entity(reader, "padded_to__3");
1307 }
1308
1309 if (err == NO_ERROR) {
1310 err = test_read_header_and_entity(reader, "padded_to_2__");
1311 }
1312
1313 if (err == NO_ERROR) {
1314 err = test_read_header_and_entity(reader, "padded_to1");
1315 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001316 }
1317
1318 close(fd);
1319
1320 return err;
1321}
1322
Joe Onorato3ad977b2009-05-05 11:50:51 -07001323static int
1324get_mod_time(const char* filename, struct timeval times[2])
1325{
1326 int err;
1327 struct stat64 st;
1328 err = stat64(filename, &st);
1329 if (err != 0) {
1330 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1331 return errno;
1332 }
1333 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001334 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001335
1336 // If st_atime is a macro then struct stat64 uses struct timespec
1337 // to store the access and modif time values and typically
1338 // st_*time_nsec is not defined. In glibc, this is controlled by
1339 // __USE_MISC.
1340#ifdef __USE_MISC
1341#if !defined(st_atime) || defined(st_atime_nsec)
1342#error "Check if this __USE_MISC conditional is still needed."
1343#endif
1344 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1345 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1346#else
1347 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001348 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001349#endif
1350
Joe Onorato3ad977b2009-05-05 11:50:51 -07001351 return 0;
1352}
1353
1354int
1355backup_helper_test_files()
1356{
1357 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001358 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001359 int dataStreamFD;
1360 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001361
1362 system("rm -r " SCRATCH_DIR);
1363 mkdir(SCRATCH_DIR, 0777);
1364 mkdir(SCRATCH_DIR "data", 0777);
1365
1366 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1367 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1368 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1369 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1370 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1371 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1372
1373 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001374 SCRATCH_DIR "data/b",
1375 SCRATCH_DIR "data/c",
1376 SCRATCH_DIR "data/d",
1377 SCRATCH_DIR "data/e",
1378 SCRATCH_DIR "data/f"
1379 };
1380
1381 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001382 "data/b",
1383 "data/c",
1384 "data/d",
1385 "data/e",
1386 "data/f"
1387 };
1388
Joe Onorato4535e402009-05-15 09:07:06 -04001389 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1390 if (dataStreamFD == -1) {
1391 fprintf(stderr, "error creating: %s\n", strerror(errno));
1392 return errno;
1393 }
1394
Joe Onorato3ad977b2009-05-05 11:50:51 -07001395 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1396 if (newSnapshotFD == -1) {
1397 fprintf(stderr, "error creating: %s\n", strerror(errno));
1398 return errno;
1399 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001400
1401 {
1402 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001403
Joe Onorato23ecae32009-06-10 17:07:15 -07001404 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001405 if (err != 0) {
1406 return err;
1407 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001408 }
1409
Joe Onorato4535e402009-05-15 09:07:06 -04001410 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001411 close(newSnapshotFD);
1412
1413 sleep(3);
1414
1415 struct timeval d_times[2];
1416 struct timeval e_times[2];
1417
1418 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1419 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1420 if (err != 0) {
1421 return err;
1422 }
1423
1424 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1425 unlink(SCRATCH_DIR "data/c");
1426 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1427 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1428 utimes(SCRATCH_DIR "data/d", d_times);
1429 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1430 utimes(SCRATCH_DIR "data/e", e_times);
1431 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1432 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001433
Joe Onorato3ad977b2009-05-05 11:50:51 -07001434 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001435 SCRATCH_DIR "data/a", // added
1436 SCRATCH_DIR "data/b", // same
1437 SCRATCH_DIR "data/c", // different mod time
1438 SCRATCH_DIR "data/d", // different size (same mod time)
1439 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1440 SCRATCH_DIR "data/g" // added
1441 };
1442
1443 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001444 "data/a", // added
1445 "data/b", // same
1446 "data/c", // different mod time
1447 "data/d", // different size (same mod time)
1448 "data/e", // different contents (same mod time, same size)
1449 "data/g" // added
1450 };
1451
1452 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1453 if (oldSnapshotFD == -1) {
1454 fprintf(stderr, "error opening: %s\n", strerror(errno));
1455 return errno;
1456 }
1457
Joe Onorato4535e402009-05-15 09:07:06 -04001458 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1459 if (dataStreamFD == -1) {
1460 fprintf(stderr, "error creating: %s\n", strerror(errno));
1461 return errno;
1462 }
1463
Joe Onorato3ad977b2009-05-05 11:50:51 -07001464 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1465 if (newSnapshotFD == -1) {
1466 fprintf(stderr, "error creating: %s\n", strerror(errno));
1467 return errno;
1468 }
1469
Joe Onoratod2110db2009-05-19 13:41:21 -07001470 {
1471 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001472
Joe Onorato23ecae32009-06-10 17:07:15 -07001473 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001474 if (err != 0) {
1475 return err;
1476 }
1477}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001478
1479 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001480 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001481 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001482
Joe Onorato3ad977b2009-05-05 11:50:51 -07001483 return 0;
1484}
1485
Joe Onorato23ecae32009-06-10 17:07:15 -07001486int
1487backup_helper_test_null_base()
1488{
1489 int err;
1490 int oldSnapshotFD;
1491 int dataStreamFD;
1492 int newSnapshotFD;
1493
1494 system("rm -r " SCRATCH_DIR);
1495 mkdir(SCRATCH_DIR, 0777);
1496 mkdir(SCRATCH_DIR "data", 0777);
1497
1498 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1499
1500 char const* files[] = {
1501 SCRATCH_DIR "data/a",
1502 };
1503
1504 char const* keys[] = {
1505 "a",
1506 };
1507
1508 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1509 if (dataStreamFD == -1) {
1510 fprintf(stderr, "error creating: %s\n", strerror(errno));
1511 return errno;
1512 }
1513
1514 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1515 if (newSnapshotFD == -1) {
1516 fprintf(stderr, "error creating: %s\n", strerror(errno));
1517 return errno;
1518 }
1519
1520 {
1521 BackupDataWriter dataStream(dataStreamFD);
1522
1523 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1524 if (err != 0) {
1525 return err;
1526 }
1527 }
1528
1529 close(dataStreamFD);
1530 close(newSnapshotFD);
1531
1532 return 0;
1533}
1534
Joe Onoratoce88cb12009-06-11 11:27:16 -07001535int
1536backup_helper_test_missing_file()
1537{
1538 int err;
1539 int oldSnapshotFD;
1540 int dataStreamFD;
1541 int newSnapshotFD;
1542
1543 system("rm -r " SCRATCH_DIR);
1544 mkdir(SCRATCH_DIR, 0777);
1545 mkdir(SCRATCH_DIR "data", 0777);
1546
1547 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1548
1549 char const* files[] = {
1550 SCRATCH_DIR "data/a",
1551 SCRATCH_DIR "data/b",
1552 SCRATCH_DIR "data/c",
1553 };
1554
1555 char const* keys[] = {
1556 "a",
1557 "b",
1558 "c",
1559 };
1560
1561 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1562 if (dataStreamFD == -1) {
1563 fprintf(stderr, "error creating: %s\n", strerror(errno));
1564 return errno;
1565 }
1566
1567 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1568 if (newSnapshotFD == -1) {
1569 fprintf(stderr, "error creating: %s\n", strerror(errno));
1570 return errno;
1571 }
1572
1573 {
1574 BackupDataWriter dataStream(dataStreamFD);
1575
1576 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1577 if (err != 0) {
1578 return err;
1579 }
1580 }
1581
1582 close(dataStreamFD);
1583 close(newSnapshotFD);
1584
1585 return 0;
1586}
1587
Joe Onorato23ecae32009-06-10 17:07:15 -07001588
Joe Onorato3ad977b2009-05-05 11:50:51 -07001589#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001590
1591}