blob: 4dcb6e7797d5534b1b849a76ee9c32eaae91f2c7 [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
Christopher Tatefbb92382009-06-23 17:35:11 -0700205write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700206 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700207{
Christopher Tatefbb92382009-06-23 17:35:11 -0700208 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700209
210 const int bufsize = 4*1024;
211 int err;
212 int amt;
213 int fileSize;
214 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700215 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700216
217 char* buf = (char*)malloc(bufsize);
Joe Onoratod2110db2009-05-19 13:41:21 -0700218
Christopher Tatefbb92382009-06-23 17:35:11 -0700219 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700220 lseek(fd, 0, SEEK_SET);
221
Christopher Tatefbb92382009-06-23 17:35:11 -0700222 if (sizeof(metadata) != 16) {
Steve Block3762c312012-01-06 19:20:56 +0000223 ALOGE("ERROR: metadata block is the wrong size!");
Christopher Tatefbb92382009-06-23 17:35:11 -0700224 }
225
226 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700227 err = dataStream->WriteEntityHeader(key, bytesLeft);
228 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700229 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700230 return err;
231 }
232
Christopher Tatefbb92382009-06-23 17:35:11 -0700233 // store the file metadata first
234 metadata.version = tolel(CURRENT_METADATA_VERSION);
235 metadata.mode = tolel(mode);
236 metadata.undefined_1 = metadata.undefined_2 = 0;
237 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
238 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700239 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700240 return err;
241 }
242 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
243
244 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700245 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
246 bytesLeft -= amt;
247 if (bytesLeft < 0) {
248 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
249 }
250 err = dataStream->WriteEntityData(buf, amt);
251 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700252 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700253 return err;
254 }
255 }
256 if (bytesLeft != 0) {
257 if (bytesLeft > 0) {
258 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
259 // even though the data we're sending is probably bad.
260 memset(buf, 0, bufsize);
261 while (bytesLeft > 0) {
262 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
263 bytesLeft -= amt;
264 err = dataStream->WriteEntityData(buf, amt);
265 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700266 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700267 return err;
268 }
269 }
270 }
Steve Block3762c312012-01-06 19:20:56 +0000271 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700272 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700273 }
274
Christopher Tate63bcb792009-06-24 13:57:29 -0700275 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700276 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700277}
278
279static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700280write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700281{
282 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700283 struct stat st;
284
285 err = stat(realFilename, &st);
286 if (err < 0) {
287 return errno;
288 }
289
Joe Onorato23ecae32009-06-10 17:07:15 -0700290 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700291 if (fd == -1) {
292 return errno;
293 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700294
295 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700296 close(fd);
297 return err;
298}
299
300static int
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800301compute_crc32(const char* file, FileRec* out) {
302 int fd = open(file, O_RDONLY);
303 if (fd < 0) {
304 return -1;
305 }
306
Joe Onorato3ad977b2009-05-05 11:50:51 -0700307 const int bufsize = 4*1024;
308 int amt;
309
Joe Onorato3ad977b2009-05-05 11:50:51 -0700310 char* buf = (char*)malloc(bufsize);
311 int crc = crc32(0L, Z_NULL, 0);
312
Joe Onoratod2110db2009-05-19 13:41:21 -0700313 lseek(fd, 0, SEEK_SET);
314
Joe Onorato3ad977b2009-05-05 11:50:51 -0700315 while ((amt = read(fd, buf, bufsize)) != 0) {
316 crc = crc32(crc, (Bytef*)buf, amt);
317 }
318
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800319 close(fd);
Christopher Tate63bcb792009-06-24 13:57:29 -0700320 free(buf);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800321
322 out->s.crc32 = crc;
323 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700324}
325
326int
Joe Onoratod2110db2009-05-19 13:41:21 -0700327back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700328 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700329{
330 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700331 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700332 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700333
334 if (oldSnapshotFD != -1) {
335 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
336 if (err != 0) {
337 // On an error, treat this as a full backup.
338 oldSnapshot.clear();
339 }
340 }
341
342 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700343 String8 key(keys[i]);
344 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700345 char const* file = files[i];
346 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700347 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700348
Joe Onorato23ecae32009-06-10 17:07:15 -0700349 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700350 if (err != 0) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800351 // not found => treat as deleted
352 continue;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700353 } else {
354 r.deleted = false;
355 r.s.modTime_sec = st.st_mtime;
356 r.s.modTime_nsec = 0; // workaround sim breakage
357 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700358 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700359 r.s.size = st.st_size;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700360
Joe Onoratoce88cb12009-06-11 11:27:16 -0700361 if (newSnapshot.indexOfKey(key) >= 0) {
362 LOGP("back_up_files key already in use '%s'", key.string());
363 return -1;
364 }
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800365
366 // compute the CRC
367 if (compute_crc32(file, &r) != NO_ERROR) {
368 ALOGW("Unable to open file %s", file);
369 continue;
370 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700371 }
372 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700373 }
374
375 int n = 0;
376 int N = oldSnapshot.size();
377 int m = 0;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800378 int M = newSnapshot.size();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700379
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800380 while (n<N && m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700381 const String8& p = oldSnapshot.keyAt(n);
382 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700383 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700384 int cmp = p.compare(q);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800385 if (cmp < 0) {
386 // file present in oldSnapshot, but not present in newSnapshot
Joe Onoratoce88cb12009-06-11 11:27:16 -0700387 LOGP("file removed: %s", p.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800388 write_delete_file(dataStream, p);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700389 n++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800390 } else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 // file added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800392 LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700393 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700394 m++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800395 } else {
396 // same file exists in both old and new; check whether to update
Joe Onorato3ad977b2009-05-05 11:50:51 -0700397 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700398
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800399 LOGP("%s", q.string());
400 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
401 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
402 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
403 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
404 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
405 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
406 int fd = open(g.file.string(), O_RDONLY);
407 if (fd < 0) {
408 ALOGE("Unable to read file for backup: %s", g.file.string());
409 } else {
Christopher Tatefbb92382009-06-23 17:35:11 -0700410 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800411 close(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700412 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700413 }
414 n++;
415 m++;
416 }
417 }
418
419 // these were deleted
420 while (n<N) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800421 write_delete_file(dataStream, oldSnapshot.keyAt(n));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700422 n++;
423 }
424
425 // these were added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800426 while (m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700427 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700428 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700429 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700430 m++;
431 }
432
433 err = write_snapshot_file(newSnapshotFD, newSnapshot);
434
435 return 0;
436}
437
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700438static void calc_tar_checksum(char* buf) {
439 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
440 memset(buf + 148, ' ', 8);
441
442 uint16_t sum = 0;
443 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
444 sum += *p;
445 }
446
447 // Now write the real checksum value:
448 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
449 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
450}
451
Christopher Tatedc92c822011-05-13 15:38:02 -0700452// Returns number of bytes written
453static int write_pax_header_entry(char* buf, const char* key, const char* value) {
454 // start with the size of "1 key=value\n"
455 int len = strlen(key) + strlen(value) + 4;
456 if (len > 9) len++;
457 if (len > 99) len++;
458 if (len > 999) len++;
459 // since PATH_MAX is 4096 we don't expect to have to generate any single
460 // header entry longer than 9999 characters
461
462 return sprintf(buf, "%d %s=%s\n", len, key, value);
463}
464
Christopher Tate7926a692011-07-11 11:31:57 -0700465// Wire format to the backup manager service is chunked: each chunk is prefixed by
466// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
467void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
468 uint32_t chunk_size_no = htonl(size);
469 writer->WriteEntityData(&chunk_size_no, 4);
470 if (size != 0) writer->WriteEntityData(buffer, size);
471}
472
Christopher Tate4a627c72011-04-01 14:43:32 -0700473int write_tarfile(const String8& packageName, const String8& domain,
474 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
475{
476 // In the output stream everything is stored relative to the root
477 const char* relstart = filepath.string() + rootpath.length();
478 if (*relstart == '/') relstart++; // won't be true when path == rootpath
479 String8 relpath(relstart);
480
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700481 // If relpath is empty, it means this is the top of one of the standard named
482 // domain directories, so we should just skip it
483 if (relpath.length() == 0) {
484 return 0;
485 }
486
Christopher Tate4a627c72011-04-01 14:43:32 -0700487 // Too long a name for the ustar format?
488 // "apps/" + packagename + '/' + domainpath < 155 chars
489 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700490 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700491 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700492 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700493 }
494
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700495 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700496 if (!needExtended) {
497 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700498 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700499 needExtended = true;
500 break;
501 }
502 }
503 }
504
Christopher Tate4a627c72011-04-01 14:43:32 -0700505 int err = 0;
506 struct stat64 s;
507 if (lstat64(filepath.string(), &s) != 0) {
508 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000509 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700510 return err;
511 }
512
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700513 String8 fullname; // for pax later on
514 String8 prefix;
515
Christopher Tate4a627c72011-04-01 14:43:32 -0700516 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700517 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700518
519 // !!! TODO: use mmap when possible to avoid churning the buffer cache
520 // !!! TODO: this will break with symlinks; need to use readlink(2)
521 int fd = open(filepath.string(), O_RDONLY);
522 if (fd < 0) {
523 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000524 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700525 return err;
526 }
527
528 // read/write up to this much at a time.
529 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800530 char* buf = (char *)calloc(1,BUFSIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700531 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
532 char* paxData = buf + 1024;
533
Christopher Tate4a627c72011-04-01 14:43:32 -0700534 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000535 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700536 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800537 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700538 }
539
Christopher Tate4a627c72011-04-01 14:43:32 -0700540 // Magic fields for the ustar file format
541 strcat(buf + 257, "ustar");
542 strcat(buf + 263, "00");
543
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700544 // [ 265 : 32 ] user name, ignored on restore
545 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700546
547 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700548 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700549
550 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
551 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700552 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
553 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700554
555 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700556 if (s.st_size > 077777777777LL) {
557 // very large files need a pax extended size header
558 needExtended = true;
559 }
560 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700561
562 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800563 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700564
Christopher Tate4a627c72011-04-01 14:43:32 -0700565 // [ 156 : 1 ] link/file type
566 uint8_t type;
567 if (isdir) {
568 type = '5'; // tar magic: '5' == directory
569 } else if (S_ISREG(s.st_mode)) {
570 type = '0'; // tar magic: '0' == normal file
571 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000572 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700573 goto cleanup;
574 }
575 buf[156] = type;
576
577 // [ 157 : 100 ] name of linked file [not implemented]
578
Christopher Tate4a627c72011-04-01 14:43:32 -0700579 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700580 // Prefix and main relative path. Path lengths have been preflighted.
581 if (packageName.length() > 0) {
582 prefix = "apps/";
583 prefix += packageName;
584 }
585 if (domain.length() > 0) {
586 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700587 }
588
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700589 // pax extended means we don't put in a prefix field, and put a different
590 // string in the basic name field. We can also construct the full path name
591 // out of the substrings we've now built.
592 fullname = prefix;
593 fullname.appendPath(relpath);
594
595 // ustar:
596 // [ 0 : 100 ]; file name/path
597 // [ 345 : 155 ] filename path prefix
598 // We only use the prefix area if fullname won't fit in the path
599 if (fullname.length() > 100) {
600 strncpy(buf, relpath.string(), 100);
601 strncpy(buf + 345, prefix.string(), 155);
602 } else {
603 strncpy(buf, fullname.string(), 100);
604 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700605 }
606
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700607 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
608
Steve Block6215d3f2012-01-04 20:05:49 +0000609 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700610
611 // If we're using a pax extended header, build & write that here; lengths are
612 // already preflighted
613 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700614 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
615 char* p = paxData;
616
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700617 // construct the pax extended header data block
618 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700619
620 // size header -- calc len in digits by actually rendering the number
621 // to a string - brute force but simple
Ashok Bhatf5df7002014-03-25 20:51:35 +0000622 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
Christopher Tatedc92c822011-05-13 15:38:02 -0700623 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700624
625 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700626 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700627
628 // Now we know how big the pax data is
629 int paxLen = p - paxData;
630
631 // Now build the pax *header* templated on the ustar header
632 memcpy(paxHeader, buf, 512);
633
634 String8 leaf = fullname.getPathLeaf();
635 memset(paxHeader, 0, 100); // rewrite the name area
636 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
637 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
638 strncpy(paxHeader + 345, prefix.string(), 155);
639
640 paxHeader[156] = 'x'; // mark it as a pax extended header
641
642 // [ 124 : 12 ] size of pax extended header data
643 memset(paxHeader + 124, 0, 12);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000644 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700645
646 // Checksum and write the pax block header
647 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700648 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700649
650 // Now write the pax data itself
651 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700652 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700653 }
654
655 // Checksum and write the 512-byte ustar file header block to the output
656 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700657 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700658
659 // Now write the file data itself, for real files. We honor tar's convention that
660 // only full 512-byte blocks are sent to write().
661 if (!isdir) {
662 off64_t toWrite = s.st_size;
663 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000664 size_t toRead = toWrite;
665 if (toRead > BUFSIZE) {
666 toRead = BUFSIZE;
667 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700668 ssize_t nRead = read(fd, buf, toRead);
669 if (nRead < 0) {
670 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000671 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700672 err, strerror(err));
673 break;
674 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000675 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700676 filepath.string());
677 err = EIO;
678 break;
679 }
680
681 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
682 // depends on the OS guarantee that for ordinary files, read() will never return
683 // less than the number of bytes requested.
684 ssize_t partial = (nRead+512) % 512;
685 if (partial > 0) {
686 ssize_t remainder = 512 - partial;
687 memset(buf + nRead, 0, remainder);
688 nRead += remainder;
689 }
Christopher Tate7926a692011-07-11 11:31:57 -0700690 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700691 toWrite -= nRead;
692 }
693 }
694
695cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900696 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700697done:
698 close(fd);
699 return err;
700}
701// end tarfile
702
703
704
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700705#define RESTORE_BUF_SIZE (8*1024)
706
707RestoreHelperBase::RestoreHelperBase()
708{
709 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700710 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700711}
712
713RestoreHelperBase::~RestoreHelperBase()
714{
715 free(m_buf);
716}
717
718status_t
719RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
720{
721 ssize_t err;
722 size_t dataSize;
723 String8 key;
724 int fd;
725 void* buf = m_buf;
726 ssize_t amt;
727 int mode;
728 int crc;
729 struct stat st;
730 FileRec r;
731
732 err = in->ReadEntityHeader(&key, &dataSize);
733 if (err != NO_ERROR) {
734 return err;
735 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700736
Christopher Tatefbb92382009-06-23 17:35:11 -0700737 // Get the metadata block off the head of the file entity and use that to
738 // set up the output file
739 file_metadata_v1 metadata;
740 amt = in->ReadEntityData(&metadata, sizeof(metadata));
741 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000742 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700743 (long)amt, strerror(errno));
744 return EIO;
745 }
746 metadata.version = fromlel(metadata.version);
747 metadata.mode = fromlel(metadata.mode);
748 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700749 if (!m_loggedUnknownMetadata) {
750 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000751 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700752 metadata.version, CURRENT_METADATA_VERSION);
753 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700754 }
755 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700756
757 // Write the file and compute the crc
758 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700759 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
760 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000761 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700762 return errno;
763 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700764
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700765 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
766 err = write(fd, buf, amt);
767 if (err != amt) {
768 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000769 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700770 return errno;
771 }
772 crc = crc32(crc, (Bytef*)buf, amt);
773 }
774
775 close(fd);
776
777 // Record for the snapshot
778 err = stat(filename.string(), &st);
779 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000780 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700781 return errno;
782 }
783
784 r.file = filename;
785 r.deleted = false;
786 r.s.modTime_sec = st.st_mtime;
787 r.s.modTime_nsec = 0; // workaround sim breakage
788 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700789 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700790 r.s.size = st.st_size;
791 r.s.crc32 = crc;
792
793 m_files.add(key, r);
794
795 return NO_ERROR;
796}
797
798status_t
799RestoreHelperBase::WriteSnapshot(int fd)
800{
801 return write_snapshot_file(fd, m_files);;
802}
803
Joe Onorato3ad977b2009-05-05 11:50:51 -0700804#if TEST_BACKUP_HELPERS
805
806#define SCRATCH_DIR "/data/backup_helper_test/"
807
808static int
809write_text_file(const char* path, const char* data)
810{
811 int amt;
812 int fd;
813 int len;
814
815 fd = creat(path, 0666);
816 if (fd == -1) {
817 fprintf(stderr, "creat %s failed\n", path);
818 return errno;
819 }
820
821 len = strlen(data);
822 amt = write(fd, data, len);
823 if (amt != len) {
824 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
825 return errno;
826 }
827
828 close(fd);
829
830 return 0;
831}
832
833static int
834compare_file(const char* path, const unsigned char* data, int len)
835{
836 int fd;
837 int amt;
838
839 fd = open(path, O_RDONLY);
840 if (fd == -1) {
841 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
842 return errno;
843 }
844
845 unsigned char* contents = (unsigned char*)malloc(len);
846 if (contents == NULL) {
847 fprintf(stderr, "malloc(%d) failed\n", len);
848 return ENOMEM;
849 }
850
851 bool sizesMatch = true;
852 amt = lseek(fd, 0, SEEK_END);
853 if (amt != len) {
854 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
855 sizesMatch = false;
856 }
857 lseek(fd, 0, SEEK_SET);
858
859 int readLen = amt < len ? amt : len;
860 amt = read(fd, contents, readLen);
861 if (amt != readLen) {
862 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
863 }
864
865 bool contentsMatch = true;
866 for (int i=0; i<readLen; i++) {
867 if (data[i] != contents[i]) {
868 if (contentsMatch) {
869 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
870 contentsMatch = false;
871 }
872 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
873 }
874 }
875
Christopher Tate63bcb792009-06-24 13:57:29 -0700876 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700877 return contentsMatch && sizesMatch ? 0 : 1;
878}
879
880int
881backup_helper_test_empty()
882{
883 int err;
884 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700885 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700886 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
887
888 system("rm -r " SCRATCH_DIR);
889 mkdir(SCRATCH_DIR, 0777);
890
891 // write
892 fd = creat(filename, 0666);
893 if (fd == -1) {
894 fprintf(stderr, "error creating %s\n", filename);
895 return 1;
896 }
897
898 err = write_snapshot_file(fd, snapshot);
899
900 close(fd);
901
902 if (err != 0) {
903 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
904 return err;
905 }
906
907 static const unsigned char correct_data[] = {
908 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
909 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
910 };
911
912 err = compare_file(filename, correct_data, sizeof(correct_data));
913 if (err != 0) {
914 return err;
915 }
916
917 // read
918 fd = open(filename, O_RDONLY);
919 if (fd == -1) {
920 fprintf(stderr, "error opening for read %s\n", filename);
921 return 1;
922 }
923
924 KeyedVector<String8,FileState> readSnapshot;
925 err = read_snapshot_file(fd, &readSnapshot);
926 if (err != 0) {
927 fprintf(stderr, "read_snapshot_file failed %d\n", err);
928 return err;
929 }
930
931 if (readSnapshot.size() != 0) {
932 fprintf(stderr, "readSnapshot should be length 0\n");
933 return 1;
934 }
935
936 return 0;
937}
938
939int
940backup_helper_test_four()
941{
942 int err;
943 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700944 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700945 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
946
947 system("rm -r " SCRATCH_DIR);
948 mkdir(SCRATCH_DIR, 0777);
949
950 // write
951 fd = creat(filename, 0666);
952 if (fd == -1) {
953 fprintf(stderr, "error opening %s\n", filename);
954 return 1;
955 }
956
957 String8 filenames[4];
958 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700959 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700960 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700961
962 states[0].modTime_sec = 0xfedcba98;
963 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700964 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700965 states[0].size = 0xababbcbc;
966 states[0].crc32 = 0x12345678;
967 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700968 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700969 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700970 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700971
972 states[1].modTime_sec = 0x93400031;
973 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700974 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700975 states[1].size = 0x88557766;
976 states[1].crc32 = 0x22334422;
977 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700978 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700979 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700980 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700981
982 states[2].modTime_sec = 0x33221144;
983 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700984 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700985 states[2].size = 0x11223344;
986 states[2].crc32 = 0x01122334;
987 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700988 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700989 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700990 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700991
992 states[3].modTime_sec = 0x33221144;
993 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700994 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -0700995 states[3].size = 0x11223344;
996 states[3].crc32 = 0x01122334;
997 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700998 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700999 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001000 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001001
1002 err = write_snapshot_file(fd, snapshot);
1003
1004 close(fd);
1005
1006 if (err != 0) {
1007 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1008 return err;
1009 }
1010
1011 static const unsigned char correct_data[] = {
1012 // header
1013 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001014 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001015
1016 // bytes_of_padding
1017 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001018 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1019 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1020 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1021 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001022
1023 // bytes_of_padding3
1024 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001025 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1026 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1027 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1028 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1029 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001030
Joe Onorato3ad977b2009-05-05 11:50:51 -07001031 // bytes of padding2
1032 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001033 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1034 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1035 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1036 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1037 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001038
Joe Onorato3ad977b2009-05-05 11:50:51 -07001039 // bytes of padding3
1040 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001041 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1042 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1043 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1044 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1045 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001046 };
1047
1048 err = compare_file(filename, correct_data, sizeof(correct_data));
1049 if (err != 0) {
1050 return err;
1051 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001052
Joe Onorato3ad977b2009-05-05 11:50:51 -07001053 // read
1054 fd = open(filename, O_RDONLY);
1055 if (fd == -1) {
1056 fprintf(stderr, "error opening for read %s\n", filename);
1057 return 1;
1058 }
1059
1060
1061 KeyedVector<String8,FileState> readSnapshot;
1062 err = read_snapshot_file(fd, &readSnapshot);
1063 if (err != 0) {
1064 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1065 return err;
1066 }
1067
1068 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001069 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001070 return 1;
1071 }
1072
1073 bool matched = true;
1074 for (size_t i=0; i<readSnapshot.size(); i++) {
1075 const String8& name = readSnapshot.keyAt(i);
1076 const FileState state = readSnapshot.valueAt(i);
1077
1078 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001079 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001080 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001081 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1082 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001083 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1084 states[i].crc32, name.length(), filenames[i].string(),
1085 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1086 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001087 matched = false;
1088 }
1089 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001090
Joe Onorato3ad977b2009-05-05 11:50:51 -07001091 return matched ? 0 : 1;
1092}
1093
Joe Onorato4535e402009-05-15 09:07:06 -04001094// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1095const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001096 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1097 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1098 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1099 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001100 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1101 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001102 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1103 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001104 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001105 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001106 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1107 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001108 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001109 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1110 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001111 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001112 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1113 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1114 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001115 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1116
Joe Onorato4535e402009-05-15 09:07:06 -04001117};
1118const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1119
1120static int
1121test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1122{
1123 int err;
1124 String8 text(str);
1125
Joe Onorato4535e402009-05-15 09:07:06 -04001126 err = writer.WriteEntityHeader(text, text.length()+1);
1127 if (err != 0) {
1128 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1129 return err;
1130 }
1131
1132 err = writer.WriteEntityData(text.string(), text.length()+1);
1133 if (err != 0) {
1134 fprintf(stderr, "write failed for data '%s'\n", text.string());
1135 return errno;
1136 }
1137
1138 return err;
1139}
1140
1141int
1142backup_helper_test_data_writer()
1143{
1144 int err;
1145 int fd;
1146 const char* filename = SCRATCH_DIR "data_writer.data";
1147
1148 system("rm -r " SCRATCH_DIR);
1149 mkdir(SCRATCH_DIR, 0777);
1150 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001151
Joe Onorato4535e402009-05-15 09:07:06 -04001152 fd = creat(filename, 0666);
1153 if (fd == -1) {
1154 fprintf(stderr, "error creating: %s\n", strerror(errno));
1155 return errno;
1156 }
1157
1158 BackupDataWriter writer(fd);
1159
1160 err = 0;
1161 err |= test_write_header_and_entity(writer, "no_padding_");
1162 err |= test_write_header_and_entity(writer, "padded_to__3");
1163 err |= test_write_header_and_entity(writer, "padded_to_2__");
1164 err |= test_write_header_and_entity(writer, "padded_to1");
1165
Joe Onorato4535e402009-05-15 09:07:06 -04001166 close(fd);
1167
1168 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1169 if (err != 0) {
1170 return err;
1171 }
1172
1173 return err;
1174}
1175
Joe Onorato2e1da322009-05-15 18:20:19 -04001176int
1177test_read_header_and_entity(BackupDataReader& reader, const char* str)
1178{
1179 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001180 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001181 char* buf = (char*)malloc(bufSize);
1182 String8 string;
Joe Onorato2e1da322009-05-15 18:20:19 -04001183 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001184 bool done;
1185 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001186 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001187
1188 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1189
Joe Onorato5f15d152009-06-16 16:31:35 -04001190 err = reader.ReadNextHeader(&done, &type);
1191 if (done) {
1192 fprintf(stderr, "should not be done yet\n");
1193 goto finished;
1194 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001195 if (err != 0) {
1196 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001197 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001198 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001199 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001200 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001201 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001202 }
1203
1204 err = reader.ReadEntityHeader(&string, &actualSize);
1205 if (err != 0) {
1206 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001207 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001208 }
1209 if (string != str) {
1210 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1211 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001212 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001213 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001214 if (actualSize != bufSize) {
1215 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1216 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001217 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001218 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001219 }
1220
Christopher Tate11b15772009-06-23 13:03:00 -07001221 nRead = reader.ReadEntityData(buf, bufSize);
1222 if (nRead < 0) {
1223 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001224 fprintf(stderr, "ReadEntityData 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
1228 if (0 != memcmp(buf, str, bufSize)) {
1229 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001230 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1231 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001232 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001233 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001234 }
1235
1236 // The next read will confirm whether it got the right amount of data.
1237
Joe Onorato5f15d152009-06-16 16:31:35 -04001238finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001239 if (err != NO_ERROR) {
1240 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1241 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001242 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001243 return err;
1244}
1245
1246int
1247backup_helper_test_data_reader()
1248{
1249 int err;
1250 int fd;
1251 const char* filename = SCRATCH_DIR "data_reader.data";
1252
1253 system("rm -r " SCRATCH_DIR);
1254 mkdir(SCRATCH_DIR, 0777);
1255 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001256
Joe Onorato2e1da322009-05-15 18:20:19 -04001257 fd = creat(filename, 0666);
1258 if (fd == -1) {
1259 fprintf(stderr, "error creating: %s\n", strerror(errno));
1260 return errno;
1261 }
1262
1263 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1264 if (err != DATA_GOLDEN_FILE_SIZE) {
1265 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1266 return errno;
1267 }
1268
1269 close(fd);
1270
1271 fd = open(filename, O_RDONLY);
1272 if (fd == -1) {
1273 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1274 filename);
1275 return errno;
1276 }
1277
1278 {
1279 BackupDataReader reader(fd);
1280
1281 err = 0;
1282
1283 if (err == NO_ERROR) {
1284 err = test_read_header_and_entity(reader, "no_padding_");
1285 }
1286
1287 if (err == NO_ERROR) {
1288 err = test_read_header_and_entity(reader, "padded_to__3");
1289 }
1290
1291 if (err == NO_ERROR) {
1292 err = test_read_header_and_entity(reader, "padded_to_2__");
1293 }
1294
1295 if (err == NO_ERROR) {
1296 err = test_read_header_and_entity(reader, "padded_to1");
1297 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001298 }
1299
1300 close(fd);
1301
1302 return err;
1303}
1304
Joe Onorato3ad977b2009-05-05 11:50:51 -07001305static int
1306get_mod_time(const char* filename, struct timeval times[2])
1307{
1308 int err;
1309 struct stat64 st;
1310 err = stat64(filename, &st);
1311 if (err != 0) {
1312 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1313 return errno;
1314 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001315
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001316 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001317 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001318
1319 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001320 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001321
Joe Onorato3ad977b2009-05-05 11:50:51 -07001322 return 0;
1323}
1324
1325int
1326backup_helper_test_files()
1327{
1328 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001329 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001330 int dataStreamFD;
1331 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001332
1333 system("rm -r " SCRATCH_DIR);
1334 mkdir(SCRATCH_DIR, 0777);
1335 mkdir(SCRATCH_DIR "data", 0777);
1336
1337 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1338 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1339 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1340 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1341 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1342 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1343
1344 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001345 SCRATCH_DIR "data/b",
1346 SCRATCH_DIR "data/c",
1347 SCRATCH_DIR "data/d",
1348 SCRATCH_DIR "data/e",
1349 SCRATCH_DIR "data/f"
1350 };
1351
1352 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001353 "data/b",
1354 "data/c",
1355 "data/d",
1356 "data/e",
1357 "data/f"
1358 };
1359
Joe Onorato4535e402009-05-15 09:07:06 -04001360 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1361 if (dataStreamFD == -1) {
1362 fprintf(stderr, "error creating: %s\n", strerror(errno));
1363 return errno;
1364 }
1365
Joe Onorato3ad977b2009-05-05 11:50:51 -07001366 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1367 if (newSnapshotFD == -1) {
1368 fprintf(stderr, "error creating: %s\n", strerror(errno));
1369 return errno;
1370 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001371
1372 {
1373 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001374
Joe Onorato23ecae32009-06-10 17:07:15 -07001375 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001376 if (err != 0) {
1377 return err;
1378 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001379 }
1380
Joe Onorato4535e402009-05-15 09:07:06 -04001381 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001382 close(newSnapshotFD);
1383
1384 sleep(3);
1385
1386 struct timeval d_times[2];
1387 struct timeval e_times[2];
1388
1389 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1390 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1391 if (err != 0) {
1392 return err;
1393 }
1394
1395 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1396 unlink(SCRATCH_DIR "data/c");
1397 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1398 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1399 utimes(SCRATCH_DIR "data/d", d_times);
1400 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1401 utimes(SCRATCH_DIR "data/e", e_times);
1402 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1403 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001404
Joe Onorato3ad977b2009-05-05 11:50:51 -07001405 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001406 SCRATCH_DIR "data/a", // added
1407 SCRATCH_DIR "data/b", // same
1408 SCRATCH_DIR "data/c", // different mod time
1409 SCRATCH_DIR "data/d", // different size (same mod time)
1410 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1411 SCRATCH_DIR "data/g" // added
1412 };
1413
1414 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001415 "data/a", // added
1416 "data/b", // same
1417 "data/c", // different mod time
1418 "data/d", // different size (same mod time)
1419 "data/e", // different contents (same mod time, same size)
1420 "data/g" // added
1421 };
1422
1423 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1424 if (oldSnapshotFD == -1) {
1425 fprintf(stderr, "error opening: %s\n", strerror(errno));
1426 return errno;
1427 }
1428
Joe Onorato4535e402009-05-15 09:07:06 -04001429 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1430 if (dataStreamFD == -1) {
1431 fprintf(stderr, "error creating: %s\n", strerror(errno));
1432 return errno;
1433 }
1434
Joe Onorato3ad977b2009-05-05 11:50:51 -07001435 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1436 if (newSnapshotFD == -1) {
1437 fprintf(stderr, "error creating: %s\n", strerror(errno));
1438 return errno;
1439 }
1440
Joe Onoratod2110db2009-05-19 13:41:21 -07001441 {
1442 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001443
Joe Onorato23ecae32009-06-10 17:07:15 -07001444 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001445 if (err != 0) {
1446 return err;
1447 }
1448}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001449
1450 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001451 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001452 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001453
Joe Onorato3ad977b2009-05-05 11:50:51 -07001454 return 0;
1455}
1456
Joe Onorato23ecae32009-06-10 17:07:15 -07001457int
1458backup_helper_test_null_base()
1459{
1460 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001461 int dataStreamFD;
1462 int newSnapshotFD;
1463
1464 system("rm -r " SCRATCH_DIR);
1465 mkdir(SCRATCH_DIR, 0777);
1466 mkdir(SCRATCH_DIR "data", 0777);
1467
1468 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1469
1470 char const* files[] = {
1471 SCRATCH_DIR "data/a",
1472 };
1473
1474 char const* keys[] = {
1475 "a",
1476 };
1477
1478 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1479 if (dataStreamFD == -1) {
1480 fprintf(stderr, "error creating: %s\n", strerror(errno));
1481 return errno;
1482 }
1483
1484 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1485 if (newSnapshotFD == -1) {
1486 fprintf(stderr, "error creating: %s\n", strerror(errno));
1487 return errno;
1488 }
1489
1490 {
1491 BackupDataWriter dataStream(dataStreamFD);
1492
1493 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1494 if (err != 0) {
1495 return err;
1496 }
1497 }
1498
1499 close(dataStreamFD);
1500 close(newSnapshotFD);
1501
1502 return 0;
1503}
1504
Joe Onoratoce88cb12009-06-11 11:27:16 -07001505int
1506backup_helper_test_missing_file()
1507{
1508 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001509 int dataStreamFD;
1510 int newSnapshotFD;
1511
1512 system("rm -r " SCRATCH_DIR);
1513 mkdir(SCRATCH_DIR, 0777);
1514 mkdir(SCRATCH_DIR "data", 0777);
1515
1516 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1517
1518 char const* files[] = {
1519 SCRATCH_DIR "data/a",
1520 SCRATCH_DIR "data/b",
1521 SCRATCH_DIR "data/c",
1522 };
1523
1524 char const* keys[] = {
1525 "a",
1526 "b",
1527 "c",
1528 };
1529
1530 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1531 if (dataStreamFD == -1) {
1532 fprintf(stderr, "error creating: %s\n", strerror(errno));
1533 return errno;
1534 }
1535
1536 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1537 if (newSnapshotFD == -1) {
1538 fprintf(stderr, "error creating: %s\n", strerror(errno));
1539 return errno;
1540 }
1541
1542 {
1543 BackupDataWriter dataStream(dataStreamFD);
1544
1545 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1546 if (err != 0) {
1547 return err;
1548 }
1549 }
1550
1551 close(dataStreamFD);
1552 close(newSnapshotFD);
1553
1554 return 0;
1555}
1556
Joe Onorato23ecae32009-06-10 17:07:15 -07001557
Joe Onorato3ad977b2009-05-05 11:50:51 -07001558#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001559
1560}