blob: 78e9d91c4d67d31d1051f064b5d009a53f3a3023 [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
George Burgess IVa346f542016-03-02 13:34:44 -0800445static void calc_tar_checksum(char* buf, size_t buf_size) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700446 // [ 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
George Burgess IVa346f542016-03-02 13:34:44 -0800456 snprintf(buf + 148, buf_size - 148, "%06o", sum); // the trailing space is
457 // already in place
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700458}
459
Christopher Tatedc92c822011-05-13 15:38:02 -0700460// Returns number of bytes written
George Burgess IVa346f542016-03-02 13:34:44 -0800461static int write_pax_header_entry(char* buf, size_t buf_size,
462 const char* key, const char* value) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700463 // start with the size of "1 key=value\n"
464 int len = strlen(key) + strlen(value) + 4;
465 if (len > 9) len++;
466 if (len > 99) len++;
467 if (len > 999) len++;
468 // since PATH_MAX is 4096 we don't expect to have to generate any single
469 // header entry longer than 9999 characters
470
George Burgess IVa346f542016-03-02 13:34:44 -0800471 return snprintf(buf, buf_size, "%d %s=%s\n", len, key, value);
Christopher Tatedc92c822011-05-13 15:38:02 -0700472}
473
Christopher Tate7926a692011-07-11 11:31:57 -0700474// Wire format to the backup manager service is chunked: each chunk is prefixed by
475// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
476void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
477 uint32_t chunk_size_no = htonl(size);
478 writer->WriteEntityData(&chunk_size_no, 4);
479 if (size != 0) writer->WriteEntityData(buffer, size);
480}
481
Christopher Tate4a627c72011-04-01 14:43:32 -0700482int write_tarfile(const String8& packageName, const String8& domain,
Christopher Tate11ae7682015-03-24 18:48:10 -0700483 const String8& rootpath, const String8& filepath, off_t* outSize,
484 BackupDataWriter* writer)
Christopher Tate4a627c72011-04-01 14:43:32 -0700485{
486 // In the output stream everything is stored relative to the root
487 const char* relstart = filepath.string() + rootpath.length();
488 if (*relstart == '/') relstart++; // won't be true when path == rootpath
489 String8 relpath(relstart);
490
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700491 // If relpath is empty, it means this is the top of one of the standard named
492 // domain directories, so we should just skip it
493 if (relpath.length() == 0) {
Christopher Tate11ae7682015-03-24 18:48:10 -0700494 *outSize = 0;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700495 return 0;
496 }
497
Christopher Tate4a627c72011-04-01 14:43:32 -0700498 // Too long a name for the ustar format?
499 // "apps/" + packagename + '/' + domainpath < 155 chars
500 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700501 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700502 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700503 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700504 }
505
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700506 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700507 if (!needExtended) {
508 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700509 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700510 needExtended = true;
511 break;
512 }
513 }
514 }
515
Christopher Tate4a627c72011-04-01 14:43:32 -0700516 int err = 0;
517 struct stat64 s;
518 if (lstat64(filepath.string(), &s) != 0) {
519 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000520 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700521 return err;
522 }
523
Christopher Tate11ae7682015-03-24 18:48:10 -0700524 // very large files need a pax extended size header
525 if (s.st_size > 077777777777LL) {
526 needExtended = true;
527 }
528
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700529 String8 fullname; // for pax later on
530 String8 prefix;
531
Christopher Tate4a627c72011-04-01 14:43:32 -0700532 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700533 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700534
Christopher Tate11ae7682015-03-24 18:48:10 -0700535 // Report the size, including a rough tar overhead estimation: 512 bytes for the
536 // overall tar file-block header, plus 2 blocks if using the pax extended format,
537 // plus the raw content size rounded up to a multiple of 512.
538 *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512);
539
540 // Measure case: we've returned the size; now return without moving data
541 if (!writer) return 0;
542
Christopher Tate4a627c72011-04-01 14:43:32 -0700543 // !!! TODO: use mmap when possible to avoid churning the buffer cache
544 // !!! TODO: this will break with symlinks; need to use readlink(2)
545 int fd = open(filepath.string(), O_RDONLY);
546 if (fd < 0) {
547 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000548 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700549 return err;
550 }
551
552 // read/write up to this much at a time.
553 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800554 char* buf = (char *)calloc(1,BUFSIZE);
George Burgess IVa346f542016-03-02 13:34:44 -0800555 const size_t PAXHEADER_OFFSET = 512;
556 const size_t PAXHEADER_SIZE = 512;
557 const size_t PAXDATA_SIZE = BUFSIZE - (PAXHEADER_SIZE + PAXHEADER_OFFSET);
558 char* const paxHeader = buf + PAXHEADER_OFFSET; // use a different chunk of
559 // it as separate scratch
560 char* const paxData = paxHeader + PAXHEADER_SIZE;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700561
Christopher Tate4a627c72011-04-01 14:43:32 -0700562 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000563 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700564 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800565 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700566 }
567
Christopher Tate4a627c72011-04-01 14:43:32 -0700568 // Magic fields for the ustar file format
569 strcat(buf + 257, "ustar");
570 strcat(buf + 263, "00");
571
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700572 // [ 265 : 32 ] user name, ignored on restore
573 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700574
575 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700576 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700577
578 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
579 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700580 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
581 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700582
583 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700584 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700585
586 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800587 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700588
Christopher Tate4a627c72011-04-01 14:43:32 -0700589 // [ 156 : 1 ] link/file type
590 uint8_t type;
591 if (isdir) {
592 type = '5'; // tar magic: '5' == directory
593 } else if (S_ISREG(s.st_mode)) {
594 type = '0'; // tar magic: '0' == normal file
595 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000596 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700597 goto cleanup;
598 }
599 buf[156] = type;
600
601 // [ 157 : 100 ] name of linked file [not implemented]
602
Christopher Tate4a627c72011-04-01 14:43:32 -0700603 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700604 // Prefix and main relative path. Path lengths have been preflighted.
605 if (packageName.length() > 0) {
606 prefix = "apps/";
607 prefix += packageName;
608 }
609 if (domain.length() > 0) {
610 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700611 }
612
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700613 // pax extended means we don't put in a prefix field, and put a different
614 // string in the basic name field. We can also construct the full path name
615 // out of the substrings we've now built.
616 fullname = prefix;
617 fullname.appendPath(relpath);
618
619 // ustar:
620 // [ 0 : 100 ]; file name/path
621 // [ 345 : 155 ] filename path prefix
622 // We only use the prefix area if fullname won't fit in the path
623 if (fullname.length() > 100) {
624 strncpy(buf, relpath.string(), 100);
625 strncpy(buf + 345, prefix.string(), 155);
626 } else {
627 strncpy(buf, fullname.string(), 100);
628 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700629 }
630
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700631 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
632
Steve Block6215d3f2012-01-04 20:05:49 +0000633 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700634
635 // If we're using a pax extended header, build & write that here; lengths are
636 // already preflighted
637 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700638 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
Christopher Tatedc92c822011-05-13 15:38:02 -0700639
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700640 // construct the pax extended header data block
George Burgess IVa346f542016-03-02 13:34:44 -0800641 memset(paxData, 0, PAXDATA_SIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700642
643 // size header -- calc len in digits by actually rendering the number
644 // to a string - brute force but simple
George Burgess IVa346f542016-03-02 13:34:44 -0800645 int paxLen = 0;
Ashok Bhatf5df7002014-03-25 20:51:35 +0000646 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
George Burgess IVa346f542016-03-02 13:34:44 -0800647 paxLen += write_pax_header_entry(paxData, PAXDATA_SIZE, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700648
649 // fullname was generated above with the ustar paths
George Burgess IVa346f542016-03-02 13:34:44 -0800650 paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen,
651 "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700652
653 // Now we know how big the pax data is
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700654
655 // Now build the pax *header* templated on the ustar header
656 memcpy(paxHeader, buf, 512);
657
658 String8 leaf = fullname.getPathLeaf();
659 memset(paxHeader, 0, 100); // rewrite the name area
660 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
661 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
662 strncpy(paxHeader + 345, prefix.string(), 155);
663
664 paxHeader[156] = 'x'; // mark it as a pax extended header
665
666 // [ 124 : 12 ] size of pax extended header data
667 memset(paxHeader + 124, 0, 12);
George Burgess IVa346f542016-03-02 13:34:44 -0800668 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)paxLen);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700669
670 // Checksum and write the pax block header
George Burgess IVa346f542016-03-02 13:34:44 -0800671 calc_tar_checksum(paxHeader, PAXHEADER_SIZE);
Christopher Tate7926a692011-07-11 11:31:57 -0700672 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700673
674 // Now write the pax data itself
675 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700676 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700677 }
678
679 // Checksum and write the 512-byte ustar file header block to the output
George Burgess IVa346f542016-03-02 13:34:44 -0800680 calc_tar_checksum(buf, BUFSIZE);
Christopher Tate7926a692011-07-11 11:31:57 -0700681 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700682
683 // Now write the file data itself, for real files. We honor tar's convention that
684 // only full 512-byte blocks are sent to write().
685 if (!isdir) {
686 off64_t toWrite = s.st_size;
687 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000688 size_t toRead = toWrite;
689 if (toRead > BUFSIZE) {
690 toRead = BUFSIZE;
691 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700692 ssize_t nRead = read(fd, buf, toRead);
693 if (nRead < 0) {
694 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000695 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700696 err, strerror(err));
697 break;
698 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000699 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700700 filepath.string());
701 err = EIO;
702 break;
703 }
704
705 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
706 // depends on the OS guarantee that for ordinary files, read() will never return
707 // less than the number of bytes requested.
708 ssize_t partial = (nRead+512) % 512;
709 if (partial > 0) {
710 ssize_t remainder = 512 - partial;
711 memset(buf + nRead, 0, remainder);
712 nRead += remainder;
713 }
Christopher Tate7926a692011-07-11 11:31:57 -0700714 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700715 toWrite -= nRead;
716 }
717 }
718
719cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900720 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700721done:
722 close(fd);
723 return err;
724}
725// end tarfile
726
727
728
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700729#define RESTORE_BUF_SIZE (8*1024)
730
731RestoreHelperBase::RestoreHelperBase()
732{
733 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700734 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700735}
736
737RestoreHelperBase::~RestoreHelperBase()
738{
739 free(m_buf);
740}
741
742status_t
743RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
744{
745 ssize_t err;
746 size_t dataSize;
747 String8 key;
748 int fd;
749 void* buf = m_buf;
750 ssize_t amt;
751 int mode;
752 int crc;
753 struct stat st;
754 FileRec r;
755
756 err = in->ReadEntityHeader(&key, &dataSize);
757 if (err != NO_ERROR) {
758 return err;
759 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700760
Christopher Tatefbb92382009-06-23 17:35:11 -0700761 // Get the metadata block off the head of the file entity and use that to
762 // set up the output file
763 file_metadata_v1 metadata;
764 amt = in->ReadEntityData(&metadata, sizeof(metadata));
765 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000766 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700767 (long)amt, strerror(errno));
768 return EIO;
769 }
770 metadata.version = fromlel(metadata.version);
771 metadata.mode = fromlel(metadata.mode);
772 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700773 if (!m_loggedUnknownMetadata) {
774 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000775 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700776 metadata.version, CURRENT_METADATA_VERSION);
777 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700778 }
779 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700780
781 // Write the file and compute the crc
782 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700783 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
784 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000785 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700786 return errno;
787 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700788
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700789 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
790 err = write(fd, buf, amt);
791 if (err != amt) {
792 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000793 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700794 return errno;
795 }
796 crc = crc32(crc, (Bytef*)buf, amt);
797 }
798
799 close(fd);
800
801 // Record for the snapshot
802 err = stat(filename.string(), &st);
803 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000804 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700805 return errno;
806 }
807
808 r.file = filename;
809 r.deleted = false;
810 r.s.modTime_sec = st.st_mtime;
811 r.s.modTime_nsec = 0; // workaround sim breakage
812 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700813 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700814 r.s.size = st.st_size;
815 r.s.crc32 = crc;
816
817 m_files.add(key, r);
818
819 return NO_ERROR;
820}
821
822status_t
823RestoreHelperBase::WriteSnapshot(int fd)
824{
825 return write_snapshot_file(fd, m_files);;
826}
827
Joe Onorato3ad977b2009-05-05 11:50:51 -0700828#if TEST_BACKUP_HELPERS
829
830#define SCRATCH_DIR "/data/backup_helper_test/"
831
832static int
833write_text_file(const char* path, const char* data)
834{
835 int amt;
836 int fd;
837 int len;
838
839 fd = creat(path, 0666);
840 if (fd == -1) {
841 fprintf(stderr, "creat %s failed\n", path);
842 return errno;
843 }
844
845 len = strlen(data);
846 amt = write(fd, data, len);
847 if (amt != len) {
848 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
849 return errno;
850 }
851
852 close(fd);
853
854 return 0;
855}
856
857static int
858compare_file(const char* path, const unsigned char* data, int len)
859{
860 int fd;
861 int amt;
862
863 fd = open(path, O_RDONLY);
864 if (fd == -1) {
865 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
866 return errno;
867 }
868
869 unsigned char* contents = (unsigned char*)malloc(len);
870 if (contents == NULL) {
871 fprintf(stderr, "malloc(%d) failed\n", len);
872 return ENOMEM;
873 }
874
875 bool sizesMatch = true;
876 amt = lseek(fd, 0, SEEK_END);
877 if (amt != len) {
878 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
879 sizesMatch = false;
880 }
881 lseek(fd, 0, SEEK_SET);
882
883 int readLen = amt < len ? amt : len;
884 amt = read(fd, contents, readLen);
885 if (amt != readLen) {
886 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
887 }
888
889 bool contentsMatch = true;
890 for (int i=0; i<readLen; i++) {
891 if (data[i] != contents[i]) {
892 if (contentsMatch) {
893 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
894 contentsMatch = false;
895 }
896 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
897 }
898 }
899
Christopher Tate63bcb792009-06-24 13:57:29 -0700900 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700901 return contentsMatch && sizesMatch ? 0 : 1;
902}
903
904int
905backup_helper_test_empty()
906{
907 int err;
908 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700909 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700910 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
911
912 system("rm -r " SCRATCH_DIR);
913 mkdir(SCRATCH_DIR, 0777);
914
915 // write
916 fd = creat(filename, 0666);
917 if (fd == -1) {
918 fprintf(stderr, "error creating %s\n", filename);
919 return 1;
920 }
921
922 err = write_snapshot_file(fd, snapshot);
923
924 close(fd);
925
926 if (err != 0) {
927 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
928 return err;
929 }
930
931 static const unsigned char correct_data[] = {
932 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
933 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
934 };
935
936 err = compare_file(filename, correct_data, sizeof(correct_data));
937 if (err != 0) {
938 return err;
939 }
940
941 // read
942 fd = open(filename, O_RDONLY);
943 if (fd == -1) {
944 fprintf(stderr, "error opening for read %s\n", filename);
945 return 1;
946 }
947
948 KeyedVector<String8,FileState> readSnapshot;
949 err = read_snapshot_file(fd, &readSnapshot);
950 if (err != 0) {
951 fprintf(stderr, "read_snapshot_file failed %d\n", err);
952 return err;
953 }
954
955 if (readSnapshot.size() != 0) {
956 fprintf(stderr, "readSnapshot should be length 0\n");
957 return 1;
958 }
959
960 return 0;
961}
962
963int
964backup_helper_test_four()
965{
966 int err;
967 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700968 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700969 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
970
971 system("rm -r " SCRATCH_DIR);
972 mkdir(SCRATCH_DIR, 0777);
973
974 // write
975 fd = creat(filename, 0666);
976 if (fd == -1) {
977 fprintf(stderr, "error opening %s\n", filename);
978 return 1;
979 }
980
981 String8 filenames[4];
982 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700983 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700984 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700985
986 states[0].modTime_sec = 0xfedcba98;
987 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700988 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700989 states[0].size = 0xababbcbc;
990 states[0].crc32 = 0x12345678;
991 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700992 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700993 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700994 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700995
996 states[1].modTime_sec = 0x93400031;
997 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700998 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700999 states[1].size = 0x88557766;
1000 states[1].crc32 = 0x22334422;
1001 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -07001002 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001003 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -07001004 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001005
1006 states[2].modTime_sec = 0x33221144;
1007 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001008 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -07001009 states[2].size = 0x11223344;
1010 states[2].crc32 = 0x01122334;
1011 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001012 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001013 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001014 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001015
1016 states[3].modTime_sec = 0x33221144;
1017 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001018 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001019 states[3].size = 0x11223344;
1020 states[3].crc32 = 0x01122334;
1021 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001022 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001023 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001024 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001025
1026 err = write_snapshot_file(fd, snapshot);
1027
1028 close(fd);
1029
1030 if (err != 0) {
1031 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1032 return err;
1033 }
1034
1035 static const unsigned char correct_data[] = {
1036 // header
1037 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001038 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001039
1040 // bytes_of_padding
1041 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001042 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1043 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1044 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1045 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001046
1047 // bytes_of_padding3
1048 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001049 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1050 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1051 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1052 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1053 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001054
Joe Onorato3ad977b2009-05-05 11:50:51 -07001055 // bytes of padding2
1056 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001057 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1058 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1059 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1060 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1061 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001062
Joe Onorato3ad977b2009-05-05 11:50:51 -07001063 // bytes of padding3
1064 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001065 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1066 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1067 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1068 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1069 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001070 };
1071
1072 err = compare_file(filename, correct_data, sizeof(correct_data));
1073 if (err != 0) {
1074 return err;
1075 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001076
Joe Onorato3ad977b2009-05-05 11:50:51 -07001077 // read
1078 fd = open(filename, O_RDONLY);
1079 if (fd == -1) {
1080 fprintf(stderr, "error opening for read %s\n", filename);
1081 return 1;
1082 }
1083
1084
1085 KeyedVector<String8,FileState> readSnapshot;
1086 err = read_snapshot_file(fd, &readSnapshot);
1087 if (err != 0) {
1088 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1089 return err;
1090 }
1091
1092 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001093 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001094 return 1;
1095 }
1096
1097 bool matched = true;
1098 for (size_t i=0; i<readSnapshot.size(); i++) {
1099 const String8& name = readSnapshot.keyAt(i);
1100 const FileState state = readSnapshot.valueAt(i);
1101
1102 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001103 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001104 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001105 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1106 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001107 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1108 states[i].crc32, name.length(), filenames[i].string(),
1109 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1110 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001111 matched = false;
1112 }
1113 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001114
Joe Onorato3ad977b2009-05-05 11:50:51 -07001115 return matched ? 0 : 1;
1116}
1117
Joe Onorato4535e402009-05-15 09:07:06 -04001118// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1119const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001120 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1121 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1122 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1123 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001124 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1125 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001126 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1127 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001128 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001129 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001130 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1131 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001132 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001133 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1134 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001135 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001136 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1137 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1138 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001139 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1140
Joe Onorato4535e402009-05-15 09:07:06 -04001141};
1142const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1143
1144static int
1145test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1146{
1147 int err;
1148 String8 text(str);
1149
Joe Onorato4535e402009-05-15 09:07:06 -04001150 err = writer.WriteEntityHeader(text, text.length()+1);
1151 if (err != 0) {
1152 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1153 return err;
1154 }
1155
1156 err = writer.WriteEntityData(text.string(), text.length()+1);
1157 if (err != 0) {
1158 fprintf(stderr, "write failed for data '%s'\n", text.string());
1159 return errno;
1160 }
1161
1162 return err;
1163}
1164
1165int
1166backup_helper_test_data_writer()
1167{
1168 int err;
1169 int fd;
1170 const char* filename = SCRATCH_DIR "data_writer.data";
1171
1172 system("rm -r " SCRATCH_DIR);
1173 mkdir(SCRATCH_DIR, 0777);
1174 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001175
Joe Onorato4535e402009-05-15 09:07:06 -04001176 fd = creat(filename, 0666);
1177 if (fd == -1) {
1178 fprintf(stderr, "error creating: %s\n", strerror(errno));
1179 return errno;
1180 }
1181
1182 BackupDataWriter writer(fd);
1183
1184 err = 0;
1185 err |= test_write_header_and_entity(writer, "no_padding_");
1186 err |= test_write_header_and_entity(writer, "padded_to__3");
1187 err |= test_write_header_and_entity(writer, "padded_to_2__");
1188 err |= test_write_header_and_entity(writer, "padded_to1");
1189
Joe Onorato4535e402009-05-15 09:07:06 -04001190 close(fd);
1191
1192 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1193 if (err != 0) {
1194 return err;
1195 }
1196
1197 return err;
1198}
1199
Joe Onorato2e1da322009-05-15 18:20:19 -04001200int
1201test_read_header_and_entity(BackupDataReader& reader, const char* str)
1202{
1203 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001204 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001205 char* buf = (char*)malloc(bufSize);
1206 String8 string;
Joe Onorato2e1da322009-05-15 18:20:19 -04001207 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001208 bool done;
1209 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001210 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001211
1212 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1213
Joe Onorato5f15d152009-06-16 16:31:35 -04001214 err = reader.ReadNextHeader(&done, &type);
1215 if (done) {
1216 fprintf(stderr, "should not be done yet\n");
1217 goto finished;
1218 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001219 if (err != 0) {
1220 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001221 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001222 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001223 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001224 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001225 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 }
1227
1228 err = reader.ReadEntityHeader(&string, &actualSize);
1229 if (err != 0) {
1230 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001231 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001232 }
1233 if (string != str) {
1234 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1235 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001236 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001237 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001238 if (actualSize != bufSize) {
1239 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1240 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001241 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001242 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001243 }
1244
Christopher Tate11b15772009-06-23 13:03:00 -07001245 nRead = reader.ReadEntityData(buf, bufSize);
1246 if (nRead < 0) {
1247 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001248 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001249 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001250 }
1251
1252 if (0 != memcmp(buf, str, bufSize)) {
1253 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001254 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1255 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001256 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001257 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001258 }
1259
1260 // The next read will confirm whether it got the right amount of data.
1261
Joe Onorato5f15d152009-06-16 16:31:35 -04001262finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001263 if (err != NO_ERROR) {
1264 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1265 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001266 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001267 return err;
1268}
1269
1270int
1271backup_helper_test_data_reader()
1272{
1273 int err;
1274 int fd;
1275 const char* filename = SCRATCH_DIR "data_reader.data";
1276
1277 system("rm -r " SCRATCH_DIR);
1278 mkdir(SCRATCH_DIR, 0777);
1279 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001280
Joe Onorato2e1da322009-05-15 18:20:19 -04001281 fd = creat(filename, 0666);
1282 if (fd == -1) {
1283 fprintf(stderr, "error creating: %s\n", strerror(errno));
1284 return errno;
1285 }
1286
1287 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1288 if (err != DATA_GOLDEN_FILE_SIZE) {
1289 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1290 return errno;
1291 }
1292
1293 close(fd);
1294
1295 fd = open(filename, O_RDONLY);
1296 if (fd == -1) {
1297 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1298 filename);
1299 return errno;
1300 }
1301
1302 {
1303 BackupDataReader reader(fd);
1304
1305 err = 0;
1306
1307 if (err == NO_ERROR) {
1308 err = test_read_header_and_entity(reader, "no_padding_");
1309 }
1310
1311 if (err == NO_ERROR) {
1312 err = test_read_header_and_entity(reader, "padded_to__3");
1313 }
1314
1315 if (err == NO_ERROR) {
1316 err = test_read_header_and_entity(reader, "padded_to_2__");
1317 }
1318
1319 if (err == NO_ERROR) {
1320 err = test_read_header_and_entity(reader, "padded_to1");
1321 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001322 }
1323
1324 close(fd);
1325
1326 return err;
1327}
1328
Joe Onorato3ad977b2009-05-05 11:50:51 -07001329static int
1330get_mod_time(const char* filename, struct timeval times[2])
1331{
1332 int err;
1333 struct stat64 st;
1334 err = stat64(filename, &st);
1335 if (err != 0) {
1336 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1337 return errno;
1338 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001339
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001340 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001341 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001342
1343 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001344 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001345
Joe Onorato3ad977b2009-05-05 11:50:51 -07001346 return 0;
1347}
1348
1349int
1350backup_helper_test_files()
1351{
1352 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001353 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001354 int dataStreamFD;
1355 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001356
1357 system("rm -r " SCRATCH_DIR);
1358 mkdir(SCRATCH_DIR, 0777);
1359 mkdir(SCRATCH_DIR "data", 0777);
1360
1361 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1362 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1363 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1364 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1365 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1366 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1367
1368 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001369 SCRATCH_DIR "data/b",
1370 SCRATCH_DIR "data/c",
1371 SCRATCH_DIR "data/d",
1372 SCRATCH_DIR "data/e",
1373 SCRATCH_DIR "data/f"
1374 };
1375
1376 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001377 "data/b",
1378 "data/c",
1379 "data/d",
1380 "data/e",
1381 "data/f"
1382 };
1383
Joe Onorato4535e402009-05-15 09:07:06 -04001384 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1385 if (dataStreamFD == -1) {
1386 fprintf(stderr, "error creating: %s\n", strerror(errno));
1387 return errno;
1388 }
1389
Joe Onorato3ad977b2009-05-05 11:50:51 -07001390 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1391 if (newSnapshotFD == -1) {
1392 fprintf(stderr, "error creating: %s\n", strerror(errno));
1393 return errno;
1394 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001395
1396 {
1397 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001398
Joe Onorato23ecae32009-06-10 17:07:15 -07001399 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001400 if (err != 0) {
1401 return err;
1402 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001403 }
1404
Joe Onorato4535e402009-05-15 09:07:06 -04001405 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001406 close(newSnapshotFD);
1407
1408 sleep(3);
1409
1410 struct timeval d_times[2];
1411 struct timeval e_times[2];
1412
1413 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1414 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1415 if (err != 0) {
1416 return err;
1417 }
1418
1419 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1420 unlink(SCRATCH_DIR "data/c");
1421 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1422 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1423 utimes(SCRATCH_DIR "data/d", d_times);
1424 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1425 utimes(SCRATCH_DIR "data/e", e_times);
1426 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1427 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001428
Joe Onorato3ad977b2009-05-05 11:50:51 -07001429 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001430 SCRATCH_DIR "data/a", // added
1431 SCRATCH_DIR "data/b", // same
1432 SCRATCH_DIR "data/c", // different mod time
1433 SCRATCH_DIR "data/d", // different size (same mod time)
1434 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1435 SCRATCH_DIR "data/g" // added
1436 };
1437
1438 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001439 "data/a", // added
1440 "data/b", // same
1441 "data/c", // different mod time
1442 "data/d", // different size (same mod time)
1443 "data/e", // different contents (same mod time, same size)
1444 "data/g" // added
1445 };
1446
1447 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1448 if (oldSnapshotFD == -1) {
1449 fprintf(stderr, "error opening: %s\n", strerror(errno));
1450 return errno;
1451 }
1452
Joe Onorato4535e402009-05-15 09:07:06 -04001453 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1454 if (dataStreamFD == -1) {
1455 fprintf(stderr, "error creating: %s\n", strerror(errno));
1456 return errno;
1457 }
1458
Joe Onorato3ad977b2009-05-05 11:50:51 -07001459 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1460 if (newSnapshotFD == -1) {
1461 fprintf(stderr, "error creating: %s\n", strerror(errno));
1462 return errno;
1463 }
1464
Joe Onoratod2110db2009-05-19 13:41:21 -07001465 {
1466 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001467
Joe Onorato23ecae32009-06-10 17:07:15 -07001468 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001469 if (err != 0) {
1470 return err;
1471 }
1472}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001473
1474 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001475 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001476 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001477
Joe Onorato3ad977b2009-05-05 11:50:51 -07001478 return 0;
1479}
1480
Joe Onorato23ecae32009-06-10 17:07:15 -07001481int
1482backup_helper_test_null_base()
1483{
1484 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001485 int dataStreamFD;
1486 int newSnapshotFD;
1487
1488 system("rm -r " SCRATCH_DIR);
1489 mkdir(SCRATCH_DIR, 0777);
1490 mkdir(SCRATCH_DIR "data", 0777);
1491
1492 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1493
1494 char const* files[] = {
1495 SCRATCH_DIR "data/a",
1496 };
1497
1498 char const* keys[] = {
1499 "a",
1500 };
1501
1502 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1503 if (dataStreamFD == -1) {
1504 fprintf(stderr, "error creating: %s\n", strerror(errno));
1505 return errno;
1506 }
1507
1508 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1509 if (newSnapshotFD == -1) {
1510 fprintf(stderr, "error creating: %s\n", strerror(errno));
1511 return errno;
1512 }
1513
1514 {
1515 BackupDataWriter dataStream(dataStreamFD);
1516
1517 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1518 if (err != 0) {
1519 return err;
1520 }
1521 }
1522
1523 close(dataStreamFD);
1524 close(newSnapshotFD);
1525
1526 return 0;
1527}
1528
Joe Onoratoce88cb12009-06-11 11:27:16 -07001529int
1530backup_helper_test_missing_file()
1531{
1532 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001533 int dataStreamFD;
1534 int newSnapshotFD;
1535
1536 system("rm -r " SCRATCH_DIR);
1537 mkdir(SCRATCH_DIR, 0777);
1538 mkdir(SCRATCH_DIR "data", 0777);
1539
1540 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1541
1542 char const* files[] = {
1543 SCRATCH_DIR "data/a",
1544 SCRATCH_DIR "data/b",
1545 SCRATCH_DIR "data/c",
1546 };
1547
1548 char const* keys[] = {
1549 "a",
1550 "b",
1551 "c",
1552 };
1553
1554 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1555 if (dataStreamFD == -1) {
1556 fprintf(stderr, "error creating: %s\n", strerror(errno));
1557 return errno;
1558 }
1559
1560 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1561 if (newSnapshotFD == -1) {
1562 fprintf(stderr, "error creating: %s\n", strerror(errno));
1563 return errno;
1564 }
1565
1566 {
1567 BackupDataWriter dataStream(dataStreamFD);
1568
1569 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1570 if (err != 0) {
1571 return err;
1572 }
1573 }
1574
1575 close(dataStreamFD);
1576 close(newSnapshotFD);
1577
1578 return 0;
1579}
1580
Joe Onorato23ecae32009-06-10 17:07:15 -07001581
Joe Onorato3ad977b2009-05-05 11:50:51 -07001582#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001583
1584}