blob: 227de3b7d8bf9edefb538ea5de3f23719f1825df [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
Andreas Gampe2204f0b2014-10-21 23:04:54 -070071static const bool kIsDebug = false;
Joe Onorato568bc322009-06-26 17:19:11 -040072#if TEST_BACKUP_HELPERS
Andreas Gampe2204f0b2014-10-21 23:04:54 -070073#define LOGP(f, x...) if (kIsDebug) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040074#else
Andreas Gampe2204f0b2014-10-21 23:04:54 -070075#define LOGP(x...) if (kIsDebug) ALOGD(x)
Joe Onorato568bc322009-06-26 17:19:11 -040076#endif
Joe Onorato290bb012009-05-13 18:57:29 -040077
Joe Onorato3ad977b2009-05-05 11:50:51 -070078const static int ROUND_UP[4] = { 0, 3, 2, 1 };
79
80static inline int
81round_up(int n)
82{
83 return n + ROUND_UP[n % 4];
84}
85
86static int
87read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
88{
89 int bytesRead = 0;
90 int amt;
91 SnapshotHeader header;
92
93 amt = read(fd, &header, sizeof(header));
94 if (amt != sizeof(header)) {
95 return errno;
96 }
97 bytesRead += amt;
98
99 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000100 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700101 return 1;
102 }
103
104 for (int i=0; i<header.fileCount; i++) {
105 FileState file;
106 char filenameBuf[128];
107
Joe Onorato23ecae32009-06-10 17:07:15 -0700108 amt = read(fd, &file, sizeof(FileState));
109 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000110 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700111 return 1;
112 }
113 bytesRead += amt;
114
115 // filename is not NULL terminated, but it is padded
116 int nameBufSize = round_up(file.nameLen);
117 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
118 ? filenameBuf
119 : (char*)malloc(nameBufSize);
120 amt = read(fd, filename, nameBufSize);
121 if (amt == nameBufSize) {
122 snapshot->add(String8(filename, file.nameLen), file);
123 }
124 bytesRead += amt;
125 if (filename != filenameBuf) {
126 free(filename);
127 }
128 if (amt != nameBufSize) {
Steve Block8564c8d2012-01-05 23:22:43 +0000129 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700130 return 1;
131 }
132 }
133
134 if (header.totalSize != bytesRead) {
Steve Block8564c8d2012-01-05 23:22:43 +0000135 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700136 header.totalSize, bytesRead);
137 return 1;
138 }
139
140 return 0;
141}
142
143static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700144write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700145{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700146 int fileCount = 0;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700147 int bytesWritten = sizeof(SnapshotHeader);
148 // preflight size
149 const int N = snapshot.size();
150 for (int i=0; i<N; i++) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700151 const FileRec& g = snapshot.valueAt(i);
152 if (!g.deleted) {
153 const String8& name = snapshot.keyAt(i);
154 bytesWritten += sizeof(FileState) + round_up(name.length());
155 fileCount++;
156 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700157 }
158
Joe Onorato4535e402009-05-15 09:07:06 -0400159 LOGP("write_snapshot_file fd=%d\n", fd);
160
Joe Onorato3ad977b2009-05-05 11:50:51 -0700161 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700162 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-05-05 11:50:51 -0700163
164 amt = write(fd, &header, sizeof(header));
165 if (amt != sizeof(header)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000166 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700167 return errno;
168 }
169
Joe Onoratoce88cb12009-06-11 11:27:16 -0700170 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700171 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700172 if (!r.deleted) {
173 const String8& name = snapshot.keyAt(i);
174 int nameLen = r.s.nameLen = name.length();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700175
Joe Onoratoce88cb12009-06-11 11:27:16 -0700176 amt = write(fd, &r.s, sizeof(FileState));
177 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000178 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700179 return 1;
180 }
Joe Onoratoce88cb12009-06-11 11:27:16 -0700181
182 // filename is not NULL terminated, but it is padded
183 amt = write(fd, name.string(), nameLen);
184 if (amt != nameLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000185 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
Joe Onoratoce88cb12009-06-11 11:27:16 -0700186 return 1;
187 }
188 int paddingLen = ROUND_UP[nameLen % 4];
189 if (paddingLen != 0) {
190 int padding = 0xabababab;
191 amt = write(fd, &padding, paddingLen);
192 if (amt != paddingLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000193 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s",
Joe Onoratoce88cb12009-06-11 11:27:16 -0700194 paddingLen, strerror(errno));
195 return 1;
196 }
197 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700198 }
199 }
200
201 return 0;
202}
203
204static int
Brian Carlstrom33d03922015-01-14 18:19:54 -0800205write_delete_file(BackupDataWriter* dataStream, const String8& key)
206{
207 LOGP("write_delete_file %s\n", key.string());
208 return dataStream->WriteEntityHeader(key, -1);
209}
210
211static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700212write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700213 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700214{
Christopher Tatefbb92382009-06-23 17:35:11 -0700215 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700216
217 const int bufsize = 4*1024;
218 int err;
219 int amt;
220 int fileSize;
221 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700222 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700223
224 char* buf = (char*)malloc(bufsize);
Joe Onoratod2110db2009-05-19 13:41:21 -0700225
Christopher Tatefbb92382009-06-23 17:35:11 -0700226 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700227 lseek(fd, 0, SEEK_SET);
228
Christopher Tatefbb92382009-06-23 17:35:11 -0700229 if (sizeof(metadata) != 16) {
Steve Block3762c312012-01-06 19:20:56 +0000230 ALOGE("ERROR: metadata block is the wrong size!");
Christopher Tatefbb92382009-06-23 17:35:11 -0700231 }
232
233 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700234 err = dataStream->WriteEntityHeader(key, bytesLeft);
235 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700236 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700237 return err;
238 }
239
Christopher Tatefbb92382009-06-23 17:35:11 -0700240 // store the file metadata first
241 metadata.version = tolel(CURRENT_METADATA_VERSION);
242 metadata.mode = tolel(mode);
243 metadata.undefined_1 = metadata.undefined_2 = 0;
244 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
245 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700246 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700247 return err;
248 }
249 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
250
251 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700252 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
253 bytesLeft -= amt;
254 if (bytesLeft < 0) {
255 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
256 }
257 err = dataStream->WriteEntityData(buf, amt);
258 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700259 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700260 return err;
261 }
262 }
263 if (bytesLeft != 0) {
264 if (bytesLeft > 0) {
265 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
266 // even though the data we're sending is probably bad.
267 memset(buf, 0, bufsize);
268 while (bytesLeft > 0) {
269 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
270 bytesLeft -= amt;
271 err = dataStream->WriteEntityData(buf, amt);
272 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700273 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700274 return err;
275 }
276 }
277 }
Steve Block3762c312012-01-06 19:20:56 +0000278 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700279 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700280 }
281
Christopher Tate63bcb792009-06-24 13:57:29 -0700282 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700283 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700284}
285
286static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700287write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700288{
289 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700290 struct stat st;
291
292 err = stat(realFilename, &st);
293 if (err < 0) {
294 return errno;
295 }
296
Joe Onorato23ecae32009-06-10 17:07:15 -0700297 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700298 if (fd == -1) {
299 return errno;
300 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700301
302 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700303 close(fd);
304 return err;
305}
306
307static int
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800308compute_crc32(const char* file, FileRec* out) {
309 int fd = open(file, O_RDONLY);
310 if (fd < 0) {
311 return -1;
312 }
313
Joe Onorato3ad977b2009-05-05 11:50:51 -0700314 const int bufsize = 4*1024;
315 int amt;
316
Joe Onorato3ad977b2009-05-05 11:50:51 -0700317 char* buf = (char*)malloc(bufsize);
318 int crc = crc32(0L, Z_NULL, 0);
319
Joe Onoratod2110db2009-05-19 13:41:21 -0700320 lseek(fd, 0, SEEK_SET);
321
Joe Onorato3ad977b2009-05-05 11:50:51 -0700322 while ((amt = read(fd, buf, bufsize)) != 0) {
323 crc = crc32(crc, (Bytef*)buf, amt);
324 }
325
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800326 close(fd);
Christopher Tate63bcb792009-06-24 13:57:29 -0700327 free(buf);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800328
329 out->s.crc32 = crc;
330 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700331}
332
333int
Joe Onoratod2110db2009-05-19 13:41:21 -0700334back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700335 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700336{
337 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700338 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700339 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700340
341 if (oldSnapshotFD != -1) {
342 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
343 if (err != 0) {
344 // On an error, treat this as a full backup.
345 oldSnapshot.clear();
346 }
347 }
348
349 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700350 String8 key(keys[i]);
351 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700352 char const* file = files[i];
353 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700354 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700355
Joe Onorato23ecae32009-06-10 17:07:15 -0700356 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700357 if (err != 0) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800358 // not found => treat as deleted
359 continue;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700360 } else {
361 r.deleted = false;
362 r.s.modTime_sec = st.st_mtime;
363 r.s.modTime_nsec = 0; // workaround sim breakage
364 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700365 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700366 r.s.size = st.st_size;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700367
Joe Onoratoce88cb12009-06-11 11:27:16 -0700368 if (newSnapshot.indexOfKey(key) >= 0) {
369 LOGP("back_up_files key already in use '%s'", key.string());
370 return -1;
371 }
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800372
373 // compute the CRC
374 if (compute_crc32(file, &r) != NO_ERROR) {
375 ALOGW("Unable to open file %s", file);
376 continue;
377 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700378 }
379 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700380 }
381
382 int n = 0;
383 int N = oldSnapshot.size();
384 int m = 0;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800385 int M = newSnapshot.size();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700386
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800387 while (n<N && m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700388 const String8& p = oldSnapshot.keyAt(n);
389 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700390 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 int cmp = p.compare(q);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800392 if (cmp < 0) {
393 // file present in oldSnapshot, but not present in newSnapshot
Joe Onoratoce88cb12009-06-11 11:27:16 -0700394 LOGP("file removed: %s", p.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800395 write_delete_file(dataStream, p);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700396 n++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800397 } else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700398 // file added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800399 LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700400 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700401 m++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800402 } else {
403 // same file exists in both old and new; check whether to update
Joe Onorato3ad977b2009-05-05 11:50:51 -0700404 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700405
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800406 LOGP("%s", q.string());
407 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
408 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
409 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
410 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
411 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
412 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
413 int fd = open(g.file.string(), O_RDONLY);
414 if (fd < 0) {
415 ALOGE("Unable to read file for backup: %s", g.file.string());
416 } else {
Christopher Tatefbb92382009-06-23 17:35:11 -0700417 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800418 close(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700419 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700420 }
421 n++;
422 m++;
423 }
424 }
425
426 // these were deleted
427 while (n<N) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800428 write_delete_file(dataStream, oldSnapshot.keyAt(n));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700429 n++;
430 }
431
432 // these were added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800433 while (m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700434 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 Tate83a7cdc52011-05-12 17:47:12 -0700445static void calc_tar_checksum(char* buf) {
446 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
447 memset(buf + 148, ' ', 8);
448
449 uint16_t sum = 0;
450 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
451 sum += *p;
452 }
453
454 // Now write the real checksum value:
455 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
456 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
457}
458
Christopher Tatedc92c822011-05-13 15:38:02 -0700459// Returns number of bytes written
460static int write_pax_header_entry(char* buf, const char* key, const char* value) {
461 // start with the size of "1 key=value\n"
462 int len = strlen(key) + strlen(value) + 4;
463 if (len > 9) len++;
464 if (len > 99) len++;
465 if (len > 999) len++;
466 // since PATH_MAX is 4096 we don't expect to have to generate any single
467 // header entry longer than 9999 characters
468
469 return sprintf(buf, "%d %s=%s\n", len, key, value);
470}
471
Christopher Tate7926a692011-07-11 11:31:57 -0700472// Wire format to the backup manager service is chunked: each chunk is prefixed by
473// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
474void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
475 uint32_t chunk_size_no = htonl(size);
476 writer->WriteEntityData(&chunk_size_no, 4);
477 if (size != 0) writer->WriteEntityData(buffer, size);
478}
479
Christopher Tate4a627c72011-04-01 14:43:32 -0700480int write_tarfile(const String8& packageName, const String8& domain,
481 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
482{
483 // In the output stream everything is stored relative to the root
484 const char* relstart = filepath.string() + rootpath.length();
485 if (*relstart == '/') relstart++; // won't be true when path == rootpath
486 String8 relpath(relstart);
487
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700488 // If relpath is empty, it means this is the top of one of the standard named
489 // domain directories, so we should just skip it
490 if (relpath.length() == 0) {
491 return 0;
492 }
493
Christopher Tate4a627c72011-04-01 14:43:32 -0700494 // Too long a name for the ustar format?
495 // "apps/" + packagename + '/' + domainpath < 155 chars
496 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700497 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700498 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700499 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700500 }
501
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700502 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700503 if (!needExtended) {
504 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700505 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700506 needExtended = true;
507 break;
508 }
509 }
510 }
511
Christopher Tate4a627c72011-04-01 14:43:32 -0700512 int err = 0;
513 struct stat64 s;
514 if (lstat64(filepath.string(), &s) != 0) {
515 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000516 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700517 return err;
518 }
519
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700520 String8 fullname; // for pax later on
521 String8 prefix;
522
Christopher Tate4a627c72011-04-01 14:43:32 -0700523 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700524 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700525
526 // !!! TODO: use mmap when possible to avoid churning the buffer cache
527 // !!! TODO: this will break with symlinks; need to use readlink(2)
528 int fd = open(filepath.string(), O_RDONLY);
529 if (fd < 0) {
530 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000531 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700532 return err;
533 }
534
535 // read/write up to this much at a time.
536 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800537 char* buf = (char *)calloc(1,BUFSIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700538 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
539 char* paxData = buf + 1024;
540
Christopher Tate4a627c72011-04-01 14:43:32 -0700541 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000542 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700543 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800544 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700545 }
546
Christopher Tate4a627c72011-04-01 14:43:32 -0700547 // Magic fields for the ustar file format
548 strcat(buf + 257, "ustar");
549 strcat(buf + 263, "00");
550
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700551 // [ 265 : 32 ] user name, ignored on restore
552 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700553
554 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700555 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700556
557 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
558 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700559 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
560 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700561
562 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700563 if (s.st_size > 077777777777LL) {
564 // very large files need a pax extended size header
565 needExtended = true;
566 }
567 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700568
569 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800570 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700571
Christopher Tate4a627c72011-04-01 14:43:32 -0700572 // [ 156 : 1 ] link/file type
573 uint8_t type;
574 if (isdir) {
575 type = '5'; // tar magic: '5' == directory
576 } else if (S_ISREG(s.st_mode)) {
577 type = '0'; // tar magic: '0' == normal file
578 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000579 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700580 goto cleanup;
581 }
582 buf[156] = type;
583
584 // [ 157 : 100 ] name of linked file [not implemented]
585
Christopher Tate4a627c72011-04-01 14:43:32 -0700586 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700587 // Prefix and main relative path. Path lengths have been preflighted.
588 if (packageName.length() > 0) {
589 prefix = "apps/";
590 prefix += packageName;
591 }
592 if (domain.length() > 0) {
593 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700594 }
595
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700596 // pax extended means we don't put in a prefix field, and put a different
597 // string in the basic name field. We can also construct the full path name
598 // out of the substrings we've now built.
599 fullname = prefix;
600 fullname.appendPath(relpath);
601
602 // ustar:
603 // [ 0 : 100 ]; file name/path
604 // [ 345 : 155 ] filename path prefix
605 // We only use the prefix area if fullname won't fit in the path
606 if (fullname.length() > 100) {
607 strncpy(buf, relpath.string(), 100);
608 strncpy(buf + 345, prefix.string(), 155);
609 } else {
610 strncpy(buf, fullname.string(), 100);
611 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700612 }
613
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700614 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
615
Steve Block6215d3f2012-01-04 20:05:49 +0000616 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700617
618 // If we're using a pax extended header, build & write that here; lengths are
619 // already preflighted
620 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700621 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
622 char* p = paxData;
623
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700624 // construct the pax extended header data block
625 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700626
627 // size header -- calc len in digits by actually rendering the number
628 // to a string - brute force but simple
Ashok Bhatf5df7002014-03-25 20:51:35 +0000629 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
Christopher Tatedc92c822011-05-13 15:38:02 -0700630 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700631
632 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700633 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700634
635 // Now we know how big the pax data is
636 int paxLen = p - paxData;
637
638 // Now build the pax *header* templated on the ustar header
639 memcpy(paxHeader, buf, 512);
640
641 String8 leaf = fullname.getPathLeaf();
642 memset(paxHeader, 0, 100); // rewrite the name area
643 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
644 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
645 strncpy(paxHeader + 345, prefix.string(), 155);
646
647 paxHeader[156] = 'x'; // mark it as a pax extended header
648
649 // [ 124 : 12 ] size of pax extended header data
650 memset(paxHeader + 124, 0, 12);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000651 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700652
653 // Checksum and write the pax block header
654 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700655 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700656
657 // Now write the pax data itself
658 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700659 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700660 }
661
662 // Checksum and write the 512-byte ustar file header block to the output
663 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700664 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700665
666 // Now write the file data itself, for real files. We honor tar's convention that
667 // only full 512-byte blocks are sent to write().
668 if (!isdir) {
669 off64_t toWrite = s.st_size;
670 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000671 size_t toRead = toWrite;
672 if (toRead > BUFSIZE) {
673 toRead = BUFSIZE;
674 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700675 ssize_t nRead = read(fd, buf, toRead);
676 if (nRead < 0) {
677 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000678 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700679 err, strerror(err));
680 break;
681 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000682 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700683 filepath.string());
684 err = EIO;
685 break;
686 }
687
688 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
689 // depends on the OS guarantee that for ordinary files, read() will never return
690 // less than the number of bytes requested.
691 ssize_t partial = (nRead+512) % 512;
692 if (partial > 0) {
693 ssize_t remainder = 512 - partial;
694 memset(buf + nRead, 0, remainder);
695 nRead += remainder;
696 }
Christopher Tate7926a692011-07-11 11:31:57 -0700697 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700698 toWrite -= nRead;
699 }
700 }
701
702cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900703 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700704done:
705 close(fd);
706 return err;
707}
708// end tarfile
709
710
711
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700712#define RESTORE_BUF_SIZE (8*1024)
713
714RestoreHelperBase::RestoreHelperBase()
715{
716 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700717 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700718}
719
720RestoreHelperBase::~RestoreHelperBase()
721{
722 free(m_buf);
723}
724
725status_t
726RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
727{
728 ssize_t err;
729 size_t dataSize;
730 String8 key;
731 int fd;
732 void* buf = m_buf;
733 ssize_t amt;
734 int mode;
735 int crc;
736 struct stat st;
737 FileRec r;
738
739 err = in->ReadEntityHeader(&key, &dataSize);
740 if (err != NO_ERROR) {
741 return err;
742 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700743
Christopher Tatefbb92382009-06-23 17:35:11 -0700744 // Get the metadata block off the head of the file entity and use that to
745 // set up the output file
746 file_metadata_v1 metadata;
747 amt = in->ReadEntityData(&metadata, sizeof(metadata));
748 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000749 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700750 (long)amt, strerror(errno));
751 return EIO;
752 }
753 metadata.version = fromlel(metadata.version);
754 metadata.mode = fromlel(metadata.mode);
755 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700756 if (!m_loggedUnknownMetadata) {
757 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000758 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700759 metadata.version, CURRENT_METADATA_VERSION);
760 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700761 }
762 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700763
764 // Write the file and compute the crc
765 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700766 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
767 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000768 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700769 return errno;
770 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700771
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700772 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
773 err = write(fd, buf, amt);
774 if (err != amt) {
775 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000776 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700777 return errno;
778 }
779 crc = crc32(crc, (Bytef*)buf, amt);
780 }
781
782 close(fd);
783
784 // Record for the snapshot
785 err = stat(filename.string(), &st);
786 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000787 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700788 return errno;
789 }
790
791 r.file = filename;
792 r.deleted = false;
793 r.s.modTime_sec = st.st_mtime;
794 r.s.modTime_nsec = 0; // workaround sim breakage
795 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700796 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700797 r.s.size = st.st_size;
798 r.s.crc32 = crc;
799
800 m_files.add(key, r);
801
802 return NO_ERROR;
803}
804
805status_t
806RestoreHelperBase::WriteSnapshot(int fd)
807{
808 return write_snapshot_file(fd, m_files);;
809}
810
Joe Onorato3ad977b2009-05-05 11:50:51 -0700811#if TEST_BACKUP_HELPERS
812
813#define SCRATCH_DIR "/data/backup_helper_test/"
814
815static int
816write_text_file(const char* path, const char* data)
817{
818 int amt;
819 int fd;
820 int len;
821
822 fd = creat(path, 0666);
823 if (fd == -1) {
824 fprintf(stderr, "creat %s failed\n", path);
825 return errno;
826 }
827
828 len = strlen(data);
829 amt = write(fd, data, len);
830 if (amt != len) {
831 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
832 return errno;
833 }
834
835 close(fd);
836
837 return 0;
838}
839
840static int
841compare_file(const char* path, const unsigned char* data, int len)
842{
843 int fd;
844 int amt;
845
846 fd = open(path, O_RDONLY);
847 if (fd == -1) {
848 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
849 return errno;
850 }
851
852 unsigned char* contents = (unsigned char*)malloc(len);
853 if (contents == NULL) {
854 fprintf(stderr, "malloc(%d) failed\n", len);
855 return ENOMEM;
856 }
857
858 bool sizesMatch = true;
859 amt = lseek(fd, 0, SEEK_END);
860 if (amt != len) {
861 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
862 sizesMatch = false;
863 }
864 lseek(fd, 0, SEEK_SET);
865
866 int readLen = amt < len ? amt : len;
867 amt = read(fd, contents, readLen);
868 if (amt != readLen) {
869 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
870 }
871
872 bool contentsMatch = true;
873 for (int i=0; i<readLen; i++) {
874 if (data[i] != contents[i]) {
875 if (contentsMatch) {
876 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
877 contentsMatch = false;
878 }
879 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
880 }
881 }
882
Christopher Tate63bcb792009-06-24 13:57:29 -0700883 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700884 return contentsMatch && sizesMatch ? 0 : 1;
885}
886
887int
888backup_helper_test_empty()
889{
890 int err;
891 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700892 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700893 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
894
895 system("rm -r " SCRATCH_DIR);
896 mkdir(SCRATCH_DIR, 0777);
897
898 // write
899 fd = creat(filename, 0666);
900 if (fd == -1) {
901 fprintf(stderr, "error creating %s\n", filename);
902 return 1;
903 }
904
905 err = write_snapshot_file(fd, snapshot);
906
907 close(fd);
908
909 if (err != 0) {
910 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
911 return err;
912 }
913
914 static const unsigned char correct_data[] = {
915 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
916 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
917 };
918
919 err = compare_file(filename, correct_data, sizeof(correct_data));
920 if (err != 0) {
921 return err;
922 }
923
924 // read
925 fd = open(filename, O_RDONLY);
926 if (fd == -1) {
927 fprintf(stderr, "error opening for read %s\n", filename);
928 return 1;
929 }
930
931 KeyedVector<String8,FileState> readSnapshot;
932 err = read_snapshot_file(fd, &readSnapshot);
933 if (err != 0) {
934 fprintf(stderr, "read_snapshot_file failed %d\n", err);
935 return err;
936 }
937
938 if (readSnapshot.size() != 0) {
939 fprintf(stderr, "readSnapshot should be length 0\n");
940 return 1;
941 }
942
943 return 0;
944}
945
946int
947backup_helper_test_four()
948{
949 int err;
950 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700951 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700952 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
953
954 system("rm -r " SCRATCH_DIR);
955 mkdir(SCRATCH_DIR, 0777);
956
957 // write
958 fd = creat(filename, 0666);
959 if (fd == -1) {
960 fprintf(stderr, "error opening %s\n", filename);
961 return 1;
962 }
963
964 String8 filenames[4];
965 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700966 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700967 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700968
969 states[0].modTime_sec = 0xfedcba98;
970 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700971 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700972 states[0].size = 0xababbcbc;
973 states[0].crc32 = 0x12345678;
974 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700975 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700976 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700977 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700978
979 states[1].modTime_sec = 0x93400031;
980 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700981 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700982 states[1].size = 0x88557766;
983 states[1].crc32 = 0x22334422;
984 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700985 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700986 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700987 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700988
989 states[2].modTime_sec = 0x33221144;
990 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700991 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700992 states[2].size = 0x11223344;
993 states[2].crc32 = 0x01122334;
994 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700995 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700996 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700997 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700998
999 states[3].modTime_sec = 0x33221144;
1000 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001001 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001002 states[3].size = 0x11223344;
1003 states[3].crc32 = 0x01122334;
1004 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001005 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001006 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001007 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001008
1009 err = write_snapshot_file(fd, snapshot);
1010
1011 close(fd);
1012
1013 if (err != 0) {
1014 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1015 return err;
1016 }
1017
1018 static const unsigned char correct_data[] = {
1019 // header
1020 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001021 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001022
1023 // bytes_of_padding
1024 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001025 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1026 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1027 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1028 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001029
1030 // bytes_of_padding3
1031 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001032 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1033 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1034 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1035 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1036 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001037
Joe Onorato3ad977b2009-05-05 11:50:51 -07001038 // bytes of padding2
1039 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001040 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1041 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1042 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1043 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1044 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001045
Joe Onorato3ad977b2009-05-05 11:50:51 -07001046 // bytes of padding3
1047 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001048 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1049 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1050 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1051 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1052 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001053 };
1054
1055 err = compare_file(filename, correct_data, sizeof(correct_data));
1056 if (err != 0) {
1057 return err;
1058 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001059
Joe Onorato3ad977b2009-05-05 11:50:51 -07001060 // read
1061 fd = open(filename, O_RDONLY);
1062 if (fd == -1) {
1063 fprintf(stderr, "error opening for read %s\n", filename);
1064 return 1;
1065 }
1066
1067
1068 KeyedVector<String8,FileState> readSnapshot;
1069 err = read_snapshot_file(fd, &readSnapshot);
1070 if (err != 0) {
1071 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1072 return err;
1073 }
1074
1075 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001076 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001077 return 1;
1078 }
1079
1080 bool matched = true;
1081 for (size_t i=0; i<readSnapshot.size(); i++) {
1082 const String8& name = readSnapshot.keyAt(i);
1083 const FileState state = readSnapshot.valueAt(i);
1084
1085 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001086 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001087 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001088 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1089 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001090 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1091 states[i].crc32, name.length(), filenames[i].string(),
1092 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1093 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001094 matched = false;
1095 }
1096 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001097
Joe Onorato3ad977b2009-05-05 11:50:51 -07001098 return matched ? 0 : 1;
1099}
1100
Joe Onorato4535e402009-05-15 09:07:06 -04001101// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1102const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001103 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1104 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1105 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1106 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001107 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1108 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001109 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1110 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001111 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001112 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001113 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1114 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001115 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001116 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1117 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001118 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001119 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1120 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1121 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001122 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1123
Joe Onorato4535e402009-05-15 09:07:06 -04001124};
1125const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1126
1127static int
1128test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1129{
1130 int err;
1131 String8 text(str);
1132
Joe Onorato4535e402009-05-15 09:07:06 -04001133 err = writer.WriteEntityHeader(text, text.length()+1);
1134 if (err != 0) {
1135 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1136 return err;
1137 }
1138
1139 err = writer.WriteEntityData(text.string(), text.length()+1);
1140 if (err != 0) {
1141 fprintf(stderr, "write failed for data '%s'\n", text.string());
1142 return errno;
1143 }
1144
1145 return err;
1146}
1147
1148int
1149backup_helper_test_data_writer()
1150{
1151 int err;
1152 int fd;
1153 const char* filename = SCRATCH_DIR "data_writer.data";
1154
1155 system("rm -r " SCRATCH_DIR);
1156 mkdir(SCRATCH_DIR, 0777);
1157 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001158
Joe Onorato4535e402009-05-15 09:07:06 -04001159 fd = creat(filename, 0666);
1160 if (fd == -1) {
1161 fprintf(stderr, "error creating: %s\n", strerror(errno));
1162 return errno;
1163 }
1164
1165 BackupDataWriter writer(fd);
1166
1167 err = 0;
1168 err |= test_write_header_and_entity(writer, "no_padding_");
1169 err |= test_write_header_and_entity(writer, "padded_to__3");
1170 err |= test_write_header_and_entity(writer, "padded_to_2__");
1171 err |= test_write_header_and_entity(writer, "padded_to1");
1172
Joe Onorato4535e402009-05-15 09:07:06 -04001173 close(fd);
1174
1175 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1176 if (err != 0) {
1177 return err;
1178 }
1179
1180 return err;
1181}
1182
Joe Onorato2e1da322009-05-15 18:20:19 -04001183int
1184test_read_header_and_entity(BackupDataReader& reader, const char* str)
1185{
1186 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001187 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001188 char* buf = (char*)malloc(bufSize);
1189 String8 string;
Joe Onorato2e1da322009-05-15 18:20:19 -04001190 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001191 bool done;
1192 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001193 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001194
1195 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1196
Joe Onorato5f15d152009-06-16 16:31:35 -04001197 err = reader.ReadNextHeader(&done, &type);
1198 if (done) {
1199 fprintf(stderr, "should not be done yet\n");
1200 goto finished;
1201 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001202 if (err != 0) {
1203 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001204 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001205 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001206 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001207 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001208 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001209 }
1210
1211 err = reader.ReadEntityHeader(&string, &actualSize);
1212 if (err != 0) {
1213 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001214 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001215 }
1216 if (string != str) {
1217 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1218 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001219 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001220 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001221 if (actualSize != bufSize) {
1222 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1223 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001224 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001225 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 }
1227
Christopher Tate11b15772009-06-23 13:03:00 -07001228 nRead = reader.ReadEntityData(buf, bufSize);
1229 if (nRead < 0) {
1230 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001231 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001232 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001233 }
1234
1235 if (0 != memcmp(buf, str, bufSize)) {
1236 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001237 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1238 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001239 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001240 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001241 }
1242
1243 // The next read will confirm whether it got the right amount of data.
1244
Joe Onorato5f15d152009-06-16 16:31:35 -04001245finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001246 if (err != NO_ERROR) {
1247 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1248 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001249 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001250 return err;
1251}
1252
1253int
1254backup_helper_test_data_reader()
1255{
1256 int err;
1257 int fd;
1258 const char* filename = SCRATCH_DIR "data_reader.data";
1259
1260 system("rm -r " SCRATCH_DIR);
1261 mkdir(SCRATCH_DIR, 0777);
1262 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001263
Joe Onorato2e1da322009-05-15 18:20:19 -04001264 fd = creat(filename, 0666);
1265 if (fd == -1) {
1266 fprintf(stderr, "error creating: %s\n", strerror(errno));
1267 return errno;
1268 }
1269
1270 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1271 if (err != DATA_GOLDEN_FILE_SIZE) {
1272 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1273 return errno;
1274 }
1275
1276 close(fd);
1277
1278 fd = open(filename, O_RDONLY);
1279 if (fd == -1) {
1280 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1281 filename);
1282 return errno;
1283 }
1284
1285 {
1286 BackupDataReader reader(fd);
1287
1288 err = 0;
1289
1290 if (err == NO_ERROR) {
1291 err = test_read_header_and_entity(reader, "no_padding_");
1292 }
1293
1294 if (err == NO_ERROR) {
1295 err = test_read_header_and_entity(reader, "padded_to__3");
1296 }
1297
1298 if (err == NO_ERROR) {
1299 err = test_read_header_and_entity(reader, "padded_to_2__");
1300 }
1301
1302 if (err == NO_ERROR) {
1303 err = test_read_header_and_entity(reader, "padded_to1");
1304 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001305 }
1306
1307 close(fd);
1308
1309 return err;
1310}
1311
Joe Onorato3ad977b2009-05-05 11:50:51 -07001312static int
1313get_mod_time(const char* filename, struct timeval times[2])
1314{
1315 int err;
1316 struct stat64 st;
1317 err = stat64(filename, &st);
1318 if (err != 0) {
1319 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1320 return errno;
1321 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001322
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001323 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001324 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001325
1326 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001327 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001328
Joe Onorato3ad977b2009-05-05 11:50:51 -07001329 return 0;
1330}
1331
1332int
1333backup_helper_test_files()
1334{
1335 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001336 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001337 int dataStreamFD;
1338 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001339
1340 system("rm -r " SCRATCH_DIR);
1341 mkdir(SCRATCH_DIR, 0777);
1342 mkdir(SCRATCH_DIR "data", 0777);
1343
1344 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1345 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1346 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1347 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1348 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1349 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1350
1351 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001352 SCRATCH_DIR "data/b",
1353 SCRATCH_DIR "data/c",
1354 SCRATCH_DIR "data/d",
1355 SCRATCH_DIR "data/e",
1356 SCRATCH_DIR "data/f"
1357 };
1358
1359 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001360 "data/b",
1361 "data/c",
1362 "data/d",
1363 "data/e",
1364 "data/f"
1365 };
1366
Joe Onorato4535e402009-05-15 09:07:06 -04001367 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1368 if (dataStreamFD == -1) {
1369 fprintf(stderr, "error creating: %s\n", strerror(errno));
1370 return errno;
1371 }
1372
Joe Onorato3ad977b2009-05-05 11:50:51 -07001373 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1374 if (newSnapshotFD == -1) {
1375 fprintf(stderr, "error creating: %s\n", strerror(errno));
1376 return errno;
1377 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001378
1379 {
1380 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001381
Joe Onorato23ecae32009-06-10 17:07:15 -07001382 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001383 if (err != 0) {
1384 return err;
1385 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001386 }
1387
Joe Onorato4535e402009-05-15 09:07:06 -04001388 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001389 close(newSnapshotFD);
1390
1391 sleep(3);
1392
1393 struct timeval d_times[2];
1394 struct timeval e_times[2];
1395
1396 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1397 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1398 if (err != 0) {
1399 return err;
1400 }
1401
1402 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1403 unlink(SCRATCH_DIR "data/c");
1404 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1405 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1406 utimes(SCRATCH_DIR "data/d", d_times);
1407 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1408 utimes(SCRATCH_DIR "data/e", e_times);
1409 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1410 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001411
Joe Onorato3ad977b2009-05-05 11:50:51 -07001412 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001413 SCRATCH_DIR "data/a", // added
1414 SCRATCH_DIR "data/b", // same
1415 SCRATCH_DIR "data/c", // different mod time
1416 SCRATCH_DIR "data/d", // different size (same mod time)
1417 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1418 SCRATCH_DIR "data/g" // added
1419 };
1420
1421 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001422 "data/a", // added
1423 "data/b", // same
1424 "data/c", // different mod time
1425 "data/d", // different size (same mod time)
1426 "data/e", // different contents (same mod time, same size)
1427 "data/g" // added
1428 };
1429
1430 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1431 if (oldSnapshotFD == -1) {
1432 fprintf(stderr, "error opening: %s\n", strerror(errno));
1433 return errno;
1434 }
1435
Joe Onorato4535e402009-05-15 09:07:06 -04001436 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1437 if (dataStreamFD == -1) {
1438 fprintf(stderr, "error creating: %s\n", strerror(errno));
1439 return errno;
1440 }
1441
Joe Onorato3ad977b2009-05-05 11:50:51 -07001442 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1443 if (newSnapshotFD == -1) {
1444 fprintf(stderr, "error creating: %s\n", strerror(errno));
1445 return errno;
1446 }
1447
Joe Onoratod2110db2009-05-19 13:41:21 -07001448 {
1449 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001450
Joe Onorato23ecae32009-06-10 17:07:15 -07001451 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001452 if (err != 0) {
1453 return err;
1454 }
1455}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001456
1457 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001458 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001459 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001460
Joe Onorato3ad977b2009-05-05 11:50:51 -07001461 return 0;
1462}
1463
Joe Onorato23ecae32009-06-10 17:07:15 -07001464int
1465backup_helper_test_null_base()
1466{
1467 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001468 int dataStreamFD;
1469 int newSnapshotFD;
1470
1471 system("rm -r " SCRATCH_DIR);
1472 mkdir(SCRATCH_DIR, 0777);
1473 mkdir(SCRATCH_DIR "data", 0777);
1474
1475 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1476
1477 char const* files[] = {
1478 SCRATCH_DIR "data/a",
1479 };
1480
1481 char const* keys[] = {
1482 "a",
1483 };
1484
1485 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1486 if (dataStreamFD == -1) {
1487 fprintf(stderr, "error creating: %s\n", strerror(errno));
1488 return errno;
1489 }
1490
1491 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1492 if (newSnapshotFD == -1) {
1493 fprintf(stderr, "error creating: %s\n", strerror(errno));
1494 return errno;
1495 }
1496
1497 {
1498 BackupDataWriter dataStream(dataStreamFD);
1499
1500 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1501 if (err != 0) {
1502 return err;
1503 }
1504 }
1505
1506 close(dataStreamFD);
1507 close(newSnapshotFD);
1508
1509 return 0;
1510}
1511
Joe Onoratoce88cb12009-06-11 11:27:16 -07001512int
1513backup_helper_test_missing_file()
1514{
1515 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001516 int dataStreamFD;
1517 int newSnapshotFD;
1518
1519 system("rm -r " SCRATCH_DIR);
1520 mkdir(SCRATCH_DIR, 0777);
1521 mkdir(SCRATCH_DIR "data", 0777);
1522
1523 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1524
1525 char const* files[] = {
1526 SCRATCH_DIR "data/a",
1527 SCRATCH_DIR "data/b",
1528 SCRATCH_DIR "data/c",
1529 };
1530
1531 char const* keys[] = {
1532 "a",
1533 "b",
1534 "c",
1535 };
1536
1537 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1538 if (dataStreamFD == -1) {
1539 fprintf(stderr, "error creating: %s\n", strerror(errno));
1540 return errno;
1541 }
1542
1543 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1544 if (newSnapshotFD == -1) {
1545 fprintf(stderr, "error creating: %s\n", strerror(errno));
1546 return errno;
1547 }
1548
1549 {
1550 BackupDataWriter dataStream(dataStreamFD);
1551
1552 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1553 if (err != 0) {
1554 return err;
1555 }
1556 }
1557
1558 close(dataStreamFD);
1559 close(newSnapshotFD);
1560
1561 return 0;
1562}
1563
Joe Onorato23ecae32009-06-10 17:07:15 -07001564
Joe Onorato3ad977b2009-05-05 11:50:51 -07001565#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001566
1567}