blob: 9300794cf31047437591bb2d008c425d0e623c1e [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,
Christopher Tate11ae7682015-03-24 18:48:10 -0700481 const String8& rootpath, const String8& filepath, off_t* outSize,
482 BackupDataWriter* writer)
Christopher Tate4a627c72011-04-01 14:43:32 -0700483{
484 // In the output stream everything is stored relative to the root
485 const char* relstart = filepath.string() + rootpath.length();
486 if (*relstart == '/') relstart++; // won't be true when path == rootpath
487 String8 relpath(relstart);
488
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700489 // If relpath is empty, it means this is the top of one of the standard named
490 // domain directories, so we should just skip it
491 if (relpath.length() == 0) {
Christopher Tate11ae7682015-03-24 18:48:10 -0700492 *outSize = 0;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700493 return 0;
494 }
495
Christopher Tate4a627c72011-04-01 14:43:32 -0700496 // Too long a name for the ustar format?
497 // "apps/" + packagename + '/' + domainpath < 155 chars
498 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700499 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700500 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700501 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700502 }
503
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700504 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700505 if (!needExtended) {
506 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700507 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700508 needExtended = true;
509 break;
510 }
511 }
512 }
513
Christopher Tate4a627c72011-04-01 14:43:32 -0700514 int err = 0;
515 struct stat64 s;
516 if (lstat64(filepath.string(), &s) != 0) {
517 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000518 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700519 return err;
520 }
521
Christopher Tate11ae7682015-03-24 18:48:10 -0700522 // very large files need a pax extended size header
523 if (s.st_size > 077777777777LL) {
524 needExtended = true;
525 }
526
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700527 String8 fullname; // for pax later on
528 String8 prefix;
529
Christopher Tate4a627c72011-04-01 14:43:32 -0700530 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700531 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700532
Christopher Tate11ae7682015-03-24 18:48:10 -0700533 // Report the size, including a rough tar overhead estimation: 512 bytes for the
534 // overall tar file-block header, plus 2 blocks if using the pax extended format,
535 // plus the raw content size rounded up to a multiple of 512.
536 *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512);
537
538 // Measure case: we've returned the size; now return without moving data
539 if (!writer) return 0;
540
Christopher Tate4a627c72011-04-01 14:43:32 -0700541 // !!! TODO: use mmap when possible to avoid churning the buffer cache
542 // !!! TODO: this will break with symlinks; need to use readlink(2)
543 int fd = open(filepath.string(), O_RDONLY);
544 if (fd < 0) {
545 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000546 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700547 return err;
548 }
549
550 // read/write up to this much at a time.
551 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800552 char* buf = (char *)calloc(1,BUFSIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700553 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
554 char* paxData = buf + 1024;
555
Christopher Tate4a627c72011-04-01 14:43:32 -0700556 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000557 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700558 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800559 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700560 }
561
Christopher Tate4a627c72011-04-01 14:43:32 -0700562 // Magic fields for the ustar file format
563 strcat(buf + 257, "ustar");
564 strcat(buf + 263, "00");
565
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700566 // [ 265 : 32 ] user name, ignored on restore
567 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700568
569 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700570 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700571
572 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
573 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700574 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
575 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700576
577 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700578 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700579
580 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800581 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700582
Christopher Tate4a627c72011-04-01 14:43:32 -0700583 // [ 156 : 1 ] link/file type
584 uint8_t type;
585 if (isdir) {
586 type = '5'; // tar magic: '5' == directory
587 } else if (S_ISREG(s.st_mode)) {
588 type = '0'; // tar magic: '0' == normal file
589 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000590 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700591 goto cleanup;
592 }
593 buf[156] = type;
594
595 // [ 157 : 100 ] name of linked file [not implemented]
596
Christopher Tate4a627c72011-04-01 14:43:32 -0700597 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700598 // Prefix and main relative path. Path lengths have been preflighted.
599 if (packageName.length() > 0) {
600 prefix = "apps/";
601 prefix += packageName;
602 }
603 if (domain.length() > 0) {
604 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700605 }
606
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700607 // pax extended means we don't put in a prefix field, and put a different
608 // string in the basic name field. We can also construct the full path name
609 // out of the substrings we've now built.
610 fullname = prefix;
611 fullname.appendPath(relpath);
612
613 // ustar:
614 // [ 0 : 100 ]; file name/path
615 // [ 345 : 155 ] filename path prefix
616 // We only use the prefix area if fullname won't fit in the path
617 if (fullname.length() > 100) {
618 strncpy(buf, relpath.string(), 100);
619 strncpy(buf + 345, prefix.string(), 155);
620 } else {
621 strncpy(buf, fullname.string(), 100);
622 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700623 }
624
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700625 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
626
Steve Block6215d3f2012-01-04 20:05:49 +0000627 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700628
629 // If we're using a pax extended header, build & write that here; lengths are
630 // already preflighted
631 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700632 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
633 char* p = paxData;
634
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700635 // construct the pax extended header data block
636 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700637
638 // size header -- calc len in digits by actually rendering the number
639 // to a string - brute force but simple
Ashok Bhatf5df7002014-03-25 20:51:35 +0000640 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
Christopher Tatedc92c822011-05-13 15:38:02 -0700641 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700642
643 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700644 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700645
646 // Now we know how big the pax data is
647 int paxLen = p - paxData;
648
649 // Now build the pax *header* templated on the ustar header
650 memcpy(paxHeader, buf, 512);
651
652 String8 leaf = fullname.getPathLeaf();
653 memset(paxHeader, 0, 100); // rewrite the name area
654 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
655 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
656 strncpy(paxHeader + 345, prefix.string(), 155);
657
658 paxHeader[156] = 'x'; // mark it as a pax extended header
659
660 // [ 124 : 12 ] size of pax extended header data
661 memset(paxHeader + 124, 0, 12);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000662 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700663
664 // Checksum and write the pax block header
665 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700666 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700667
668 // Now write the pax data itself
669 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700670 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700671 }
672
673 // Checksum and write the 512-byte ustar file header block to the output
674 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700675 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700676
677 // Now write the file data itself, for real files. We honor tar's convention that
678 // only full 512-byte blocks are sent to write().
679 if (!isdir) {
680 off64_t toWrite = s.st_size;
681 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000682 size_t toRead = toWrite;
683 if (toRead > BUFSIZE) {
684 toRead = BUFSIZE;
685 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700686 ssize_t nRead = read(fd, buf, toRead);
687 if (nRead < 0) {
688 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000689 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700690 err, strerror(err));
691 break;
692 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000693 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700694 filepath.string());
695 err = EIO;
696 break;
697 }
698
699 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
700 // depends on the OS guarantee that for ordinary files, read() will never return
701 // less than the number of bytes requested.
702 ssize_t partial = (nRead+512) % 512;
703 if (partial > 0) {
704 ssize_t remainder = 512 - partial;
705 memset(buf + nRead, 0, remainder);
706 nRead += remainder;
707 }
Christopher Tate7926a692011-07-11 11:31:57 -0700708 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700709 toWrite -= nRead;
710 }
711 }
712
713cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900714 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700715done:
716 close(fd);
717 return err;
718}
719// end tarfile
720
721
722
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700723#define RESTORE_BUF_SIZE (8*1024)
724
725RestoreHelperBase::RestoreHelperBase()
726{
727 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700728 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700729}
730
731RestoreHelperBase::~RestoreHelperBase()
732{
733 free(m_buf);
734}
735
736status_t
737RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
738{
739 ssize_t err;
740 size_t dataSize;
741 String8 key;
742 int fd;
743 void* buf = m_buf;
744 ssize_t amt;
745 int mode;
746 int crc;
747 struct stat st;
748 FileRec r;
749
750 err = in->ReadEntityHeader(&key, &dataSize);
751 if (err != NO_ERROR) {
752 return err;
753 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700754
Christopher Tatefbb92382009-06-23 17:35:11 -0700755 // Get the metadata block off the head of the file entity and use that to
756 // set up the output file
757 file_metadata_v1 metadata;
758 amt = in->ReadEntityData(&metadata, sizeof(metadata));
759 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000760 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700761 (long)amt, strerror(errno));
762 return EIO;
763 }
764 metadata.version = fromlel(metadata.version);
765 metadata.mode = fromlel(metadata.mode);
766 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700767 if (!m_loggedUnknownMetadata) {
768 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000769 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700770 metadata.version, CURRENT_METADATA_VERSION);
771 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700772 }
773 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700774
775 // Write the file and compute the crc
776 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700777 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
778 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000779 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700780 return errno;
781 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700782
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700783 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
784 err = write(fd, buf, amt);
785 if (err != amt) {
786 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000787 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700788 return errno;
789 }
790 crc = crc32(crc, (Bytef*)buf, amt);
791 }
792
793 close(fd);
794
795 // Record for the snapshot
796 err = stat(filename.string(), &st);
797 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000798 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700799 return errno;
800 }
801
802 r.file = filename;
803 r.deleted = false;
804 r.s.modTime_sec = st.st_mtime;
805 r.s.modTime_nsec = 0; // workaround sim breakage
806 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700807 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700808 r.s.size = st.st_size;
809 r.s.crc32 = crc;
810
811 m_files.add(key, r);
812
813 return NO_ERROR;
814}
815
816status_t
817RestoreHelperBase::WriteSnapshot(int fd)
818{
819 return write_snapshot_file(fd, m_files);;
820}
821
Joe Onorato3ad977b2009-05-05 11:50:51 -0700822#if TEST_BACKUP_HELPERS
823
824#define SCRATCH_DIR "/data/backup_helper_test/"
825
826static int
827write_text_file(const char* path, const char* data)
828{
829 int amt;
830 int fd;
831 int len;
832
833 fd = creat(path, 0666);
834 if (fd == -1) {
835 fprintf(stderr, "creat %s failed\n", path);
836 return errno;
837 }
838
839 len = strlen(data);
840 amt = write(fd, data, len);
841 if (amt != len) {
842 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
843 return errno;
844 }
845
846 close(fd);
847
848 return 0;
849}
850
851static int
852compare_file(const char* path, const unsigned char* data, int len)
853{
854 int fd;
855 int amt;
856
857 fd = open(path, O_RDONLY);
858 if (fd == -1) {
859 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
860 return errno;
861 }
862
863 unsigned char* contents = (unsigned char*)malloc(len);
864 if (contents == NULL) {
865 fprintf(stderr, "malloc(%d) failed\n", len);
866 return ENOMEM;
867 }
868
869 bool sizesMatch = true;
870 amt = lseek(fd, 0, SEEK_END);
871 if (amt != len) {
872 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
873 sizesMatch = false;
874 }
875 lseek(fd, 0, SEEK_SET);
876
877 int readLen = amt < len ? amt : len;
878 amt = read(fd, contents, readLen);
879 if (amt != readLen) {
880 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
881 }
882
883 bool contentsMatch = true;
884 for (int i=0; i<readLen; i++) {
885 if (data[i] != contents[i]) {
886 if (contentsMatch) {
887 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
888 contentsMatch = false;
889 }
890 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
891 }
892 }
893
Christopher Tate63bcb792009-06-24 13:57:29 -0700894 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700895 return contentsMatch && sizesMatch ? 0 : 1;
896}
897
898int
899backup_helper_test_empty()
900{
901 int err;
902 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700903 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700904 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
905
906 system("rm -r " SCRATCH_DIR);
907 mkdir(SCRATCH_DIR, 0777);
908
909 // write
910 fd = creat(filename, 0666);
911 if (fd == -1) {
912 fprintf(stderr, "error creating %s\n", filename);
913 return 1;
914 }
915
916 err = write_snapshot_file(fd, snapshot);
917
918 close(fd);
919
920 if (err != 0) {
921 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
922 return err;
923 }
924
925 static const unsigned char correct_data[] = {
926 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
927 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
928 };
929
930 err = compare_file(filename, correct_data, sizeof(correct_data));
931 if (err != 0) {
932 return err;
933 }
934
935 // read
936 fd = open(filename, O_RDONLY);
937 if (fd == -1) {
938 fprintf(stderr, "error opening for read %s\n", filename);
939 return 1;
940 }
941
942 KeyedVector<String8,FileState> readSnapshot;
943 err = read_snapshot_file(fd, &readSnapshot);
944 if (err != 0) {
945 fprintf(stderr, "read_snapshot_file failed %d\n", err);
946 return err;
947 }
948
949 if (readSnapshot.size() != 0) {
950 fprintf(stderr, "readSnapshot should be length 0\n");
951 return 1;
952 }
953
954 return 0;
955}
956
957int
958backup_helper_test_four()
959{
960 int err;
961 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700962 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700963 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
964
965 system("rm -r " SCRATCH_DIR);
966 mkdir(SCRATCH_DIR, 0777);
967
968 // write
969 fd = creat(filename, 0666);
970 if (fd == -1) {
971 fprintf(stderr, "error opening %s\n", filename);
972 return 1;
973 }
974
975 String8 filenames[4];
976 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700977 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700978 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700979
980 states[0].modTime_sec = 0xfedcba98;
981 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700982 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700983 states[0].size = 0xababbcbc;
984 states[0].crc32 = 0x12345678;
985 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700986 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700987 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700988 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700989
990 states[1].modTime_sec = 0x93400031;
991 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700992 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700993 states[1].size = 0x88557766;
994 states[1].crc32 = 0x22334422;
995 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700996 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700997 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700998 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700999
1000 states[2].modTime_sec = 0x33221144;
1001 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001002 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -07001003 states[2].size = 0x11223344;
1004 states[2].crc32 = 0x01122334;
1005 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001006 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001007 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001008 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001009
1010 states[3].modTime_sec = 0x33221144;
1011 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001012 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001013 states[3].size = 0x11223344;
1014 states[3].crc32 = 0x01122334;
1015 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001016 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001017 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001018 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001019
1020 err = write_snapshot_file(fd, snapshot);
1021
1022 close(fd);
1023
1024 if (err != 0) {
1025 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1026 return err;
1027 }
1028
1029 static const unsigned char correct_data[] = {
1030 // header
1031 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001032 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001033
1034 // bytes_of_padding
1035 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001036 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1037 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1038 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1039 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001040
1041 // bytes_of_padding3
1042 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001043 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1044 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1045 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1046 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1047 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001048
Joe Onorato3ad977b2009-05-05 11:50:51 -07001049 // bytes of padding2
1050 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001051 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1052 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1053 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1054 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1055 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001056
Joe Onorato3ad977b2009-05-05 11:50:51 -07001057 // bytes of padding3
1058 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001059 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1060 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1061 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1062 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1063 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001064 };
1065
1066 err = compare_file(filename, correct_data, sizeof(correct_data));
1067 if (err != 0) {
1068 return err;
1069 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001070
Joe Onorato3ad977b2009-05-05 11:50:51 -07001071 // read
1072 fd = open(filename, O_RDONLY);
1073 if (fd == -1) {
1074 fprintf(stderr, "error opening for read %s\n", filename);
1075 return 1;
1076 }
1077
1078
1079 KeyedVector<String8,FileState> readSnapshot;
1080 err = read_snapshot_file(fd, &readSnapshot);
1081 if (err != 0) {
1082 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1083 return err;
1084 }
1085
1086 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001087 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001088 return 1;
1089 }
1090
1091 bool matched = true;
1092 for (size_t i=0; i<readSnapshot.size(); i++) {
1093 const String8& name = readSnapshot.keyAt(i);
1094 const FileState state = readSnapshot.valueAt(i);
1095
1096 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001097 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001098 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001099 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1100 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001101 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1102 states[i].crc32, name.length(), filenames[i].string(),
1103 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1104 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001105 matched = false;
1106 }
1107 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001108
Joe Onorato3ad977b2009-05-05 11:50:51 -07001109 return matched ? 0 : 1;
1110}
1111
Joe Onorato4535e402009-05-15 09:07:06 -04001112// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1113const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001114 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1115 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1116 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1117 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001118 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1119 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001120 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1121 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001122 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001123 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001124 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1125 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001126 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001127 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1128 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001129 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001130 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1131 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1132 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001133 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1134
Joe Onorato4535e402009-05-15 09:07:06 -04001135};
1136const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1137
1138static int
1139test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1140{
1141 int err;
1142 String8 text(str);
1143
Joe Onorato4535e402009-05-15 09:07:06 -04001144 err = writer.WriteEntityHeader(text, text.length()+1);
1145 if (err != 0) {
1146 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1147 return err;
1148 }
1149
1150 err = writer.WriteEntityData(text.string(), text.length()+1);
1151 if (err != 0) {
1152 fprintf(stderr, "write failed for data '%s'\n", text.string());
1153 return errno;
1154 }
1155
1156 return err;
1157}
1158
1159int
1160backup_helper_test_data_writer()
1161{
1162 int err;
1163 int fd;
1164 const char* filename = SCRATCH_DIR "data_writer.data";
1165
1166 system("rm -r " SCRATCH_DIR);
1167 mkdir(SCRATCH_DIR, 0777);
1168 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001169
Joe Onorato4535e402009-05-15 09:07:06 -04001170 fd = creat(filename, 0666);
1171 if (fd == -1) {
1172 fprintf(stderr, "error creating: %s\n", strerror(errno));
1173 return errno;
1174 }
1175
1176 BackupDataWriter writer(fd);
1177
1178 err = 0;
1179 err |= test_write_header_and_entity(writer, "no_padding_");
1180 err |= test_write_header_and_entity(writer, "padded_to__3");
1181 err |= test_write_header_and_entity(writer, "padded_to_2__");
1182 err |= test_write_header_and_entity(writer, "padded_to1");
1183
Joe Onorato4535e402009-05-15 09:07:06 -04001184 close(fd);
1185
1186 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1187 if (err != 0) {
1188 return err;
1189 }
1190
1191 return err;
1192}
1193
Joe Onorato2e1da322009-05-15 18:20:19 -04001194int
1195test_read_header_and_entity(BackupDataReader& reader, const char* str)
1196{
1197 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001198 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001199 char* buf = (char*)malloc(bufSize);
1200 String8 string;
Joe Onorato2e1da322009-05-15 18:20:19 -04001201 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 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001232 if (actualSize != bufSize) {
1233 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1234 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001235 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 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001333
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001334 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001335 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001336
1337 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001338 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001339
Joe Onorato3ad977b2009-05-05 11:50:51 -07001340 return 0;
1341}
1342
1343int
1344backup_helper_test_files()
1345{
1346 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001347 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001348 int dataStreamFD;
1349 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001350
1351 system("rm -r " SCRATCH_DIR);
1352 mkdir(SCRATCH_DIR, 0777);
1353 mkdir(SCRATCH_DIR "data", 0777);
1354
1355 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1356 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1357 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1358 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1359 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1360 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1361
1362 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001363 SCRATCH_DIR "data/b",
1364 SCRATCH_DIR "data/c",
1365 SCRATCH_DIR "data/d",
1366 SCRATCH_DIR "data/e",
1367 SCRATCH_DIR "data/f"
1368 };
1369
1370 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001371 "data/b",
1372 "data/c",
1373 "data/d",
1374 "data/e",
1375 "data/f"
1376 };
1377
Joe Onorato4535e402009-05-15 09:07:06 -04001378 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1379 if (dataStreamFD == -1) {
1380 fprintf(stderr, "error creating: %s\n", strerror(errno));
1381 return errno;
1382 }
1383
Joe Onorato3ad977b2009-05-05 11:50:51 -07001384 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1385 if (newSnapshotFD == -1) {
1386 fprintf(stderr, "error creating: %s\n", strerror(errno));
1387 return errno;
1388 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001389
1390 {
1391 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001392
Joe Onorato23ecae32009-06-10 17:07:15 -07001393 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001394 if (err != 0) {
1395 return err;
1396 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001397 }
1398
Joe Onorato4535e402009-05-15 09:07:06 -04001399 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001400 close(newSnapshotFD);
1401
1402 sleep(3);
1403
1404 struct timeval d_times[2];
1405 struct timeval e_times[2];
1406
1407 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1408 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1409 if (err != 0) {
1410 return err;
1411 }
1412
1413 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1414 unlink(SCRATCH_DIR "data/c");
1415 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1416 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1417 utimes(SCRATCH_DIR "data/d", d_times);
1418 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1419 utimes(SCRATCH_DIR "data/e", e_times);
1420 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1421 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001422
Joe Onorato3ad977b2009-05-05 11:50:51 -07001423 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001424 SCRATCH_DIR "data/a", // added
1425 SCRATCH_DIR "data/b", // same
1426 SCRATCH_DIR "data/c", // different mod time
1427 SCRATCH_DIR "data/d", // different size (same mod time)
1428 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1429 SCRATCH_DIR "data/g" // added
1430 };
1431
1432 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001433 "data/a", // added
1434 "data/b", // same
1435 "data/c", // different mod time
1436 "data/d", // different size (same mod time)
1437 "data/e", // different contents (same mod time, same size)
1438 "data/g" // added
1439 };
1440
1441 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1442 if (oldSnapshotFD == -1) {
1443 fprintf(stderr, "error opening: %s\n", strerror(errno));
1444 return errno;
1445 }
1446
Joe Onorato4535e402009-05-15 09:07:06 -04001447 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1448 if (dataStreamFD == -1) {
1449 fprintf(stderr, "error creating: %s\n", strerror(errno));
1450 return errno;
1451 }
1452
Joe Onorato3ad977b2009-05-05 11:50:51 -07001453 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1454 if (newSnapshotFD == -1) {
1455 fprintf(stderr, "error creating: %s\n", strerror(errno));
1456 return errno;
1457 }
1458
Joe Onoratod2110db2009-05-19 13:41:21 -07001459 {
1460 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001461
Joe Onorato23ecae32009-06-10 17:07:15 -07001462 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001463 if (err != 0) {
1464 return err;
1465 }
1466}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001467
1468 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001469 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001470 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001471
Joe Onorato3ad977b2009-05-05 11:50:51 -07001472 return 0;
1473}
1474
Joe Onorato23ecae32009-06-10 17:07:15 -07001475int
1476backup_helper_test_null_base()
1477{
1478 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001479 int dataStreamFD;
1480 int newSnapshotFD;
1481
1482 system("rm -r " SCRATCH_DIR);
1483 mkdir(SCRATCH_DIR, 0777);
1484 mkdir(SCRATCH_DIR "data", 0777);
1485
1486 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1487
1488 char const* files[] = {
1489 SCRATCH_DIR "data/a",
1490 };
1491
1492 char const* keys[] = {
1493 "a",
1494 };
1495
1496 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1497 if (dataStreamFD == -1) {
1498 fprintf(stderr, "error creating: %s\n", strerror(errno));
1499 return errno;
1500 }
1501
1502 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1503 if (newSnapshotFD == -1) {
1504 fprintf(stderr, "error creating: %s\n", strerror(errno));
1505 return errno;
1506 }
1507
1508 {
1509 BackupDataWriter dataStream(dataStreamFD);
1510
1511 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1512 if (err != 0) {
1513 return err;
1514 }
1515 }
1516
1517 close(dataStreamFD);
1518 close(newSnapshotFD);
1519
1520 return 0;
1521}
1522
Joe Onoratoce88cb12009-06-11 11:27:16 -07001523int
1524backup_helper_test_missing_file()
1525{
1526 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001527 int dataStreamFD;
1528 int newSnapshotFD;
1529
1530 system("rm -r " SCRATCH_DIR);
1531 mkdir(SCRATCH_DIR, 0777);
1532 mkdir(SCRATCH_DIR "data", 0777);
1533
1534 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1535
1536 char const* files[] = {
1537 SCRATCH_DIR "data/a",
1538 SCRATCH_DIR "data/b",
1539 SCRATCH_DIR "data/c",
1540 };
1541
1542 char const* keys[] = {
1543 "a",
1544 "b",
1545 "c",
1546 };
1547
1548 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1549 if (dataStreamFD == -1) {
1550 fprintf(stderr, "error creating: %s\n", strerror(errno));
1551 return errno;
1552 }
1553
1554 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1555 if (newSnapshotFD == -1) {
1556 fprintf(stderr, "error creating: %s\n", strerror(errno));
1557 return errno;
1558 }
1559
1560 {
1561 BackupDataWriter dataStream(dataStreamFD);
1562
1563 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1564 if (err != 0) {
1565 return err;
1566 }
1567 }
1568
1569 close(dataStreamFD);
1570 close(newSnapshotFD);
1571
1572 return 0;
1573}
1574
Joe Onorato23ecae32009-06-10 17:07:15 -07001575
Joe Onorato3ad977b2009-05-05 11:50:51 -07001576#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001577
1578}