blob: 3f82830c4fa1f14630db59c9bea4a8a5939885a4 [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
301compute_crc32(int fd)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700302{
303 const int bufsize = 4*1024;
304 int amt;
305
Joe Onorato3ad977b2009-05-05 11:50:51 -0700306 char* buf = (char*)malloc(bufsize);
307 int crc = crc32(0L, Z_NULL, 0);
308
Joe Onoratod2110db2009-05-19 13:41:21 -0700309 lseek(fd, 0, SEEK_SET);
310
Joe Onorato3ad977b2009-05-05 11:50:51 -0700311 while ((amt = read(fd, buf, bufsize)) != 0) {
312 crc = crc32(crc, (Bytef*)buf, amt);
313 }
314
Christopher Tate63bcb792009-06-24 13:57:29 -0700315 free(buf);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700316 return crc;
317}
318
319int
Joe Onoratod2110db2009-05-19 13:41:21 -0700320back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700321 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700322{
323 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700324 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700325 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700326
327 if (oldSnapshotFD != -1) {
328 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
329 if (err != 0) {
330 // On an error, treat this as a full backup.
331 oldSnapshot.clear();
332 }
333 }
334
335 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700336 String8 key(keys[i]);
337 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700338 char const* file = files[i];
339 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700340 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700341
Joe Onorato23ecae32009-06-10 17:07:15 -0700342 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700343 if (err != 0) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700344 r.deleted = true;
345 } else {
346 r.deleted = false;
347 r.s.modTime_sec = st.st_mtime;
348 r.s.modTime_nsec = 0; // workaround sim breakage
349 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700350 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700351 r.s.size = st.st_size;
352 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato3ad977b2009-05-05 11:50:51 -0700353
Joe Onoratoce88cb12009-06-11 11:27:16 -0700354 if (newSnapshot.indexOfKey(key) >= 0) {
355 LOGP("back_up_files key already in use '%s'", key.string());
356 return -1;
357 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700358 }
359 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700360 }
361
362 int n = 0;
363 int N = oldSnapshot.size();
364 int m = 0;
365
366 while (n<N && m<fileCount) {
367 const String8& p = oldSnapshot.keyAt(n);
368 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700369 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700370 int cmp = p.compare(q);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700371 if (g.deleted || cmp < 0) {
372 // file removed
373 LOGP("file removed: %s", p.string());
374 g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
375 dataStream->WriteEntityHeader(p, -1);
376 n++;
377 }
378 else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700379 // file added
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700380 LOGP("file added: %s", g.file.string());
381 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700382 m++;
383 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700384 else {
385 // both files exist, check them
Joe Onorato3ad977b2009-05-05 11:50:51 -0700386 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700387
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700388 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate0032ce82009-06-04 17:01:06 -0700389 if (fd < 0) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700390 // We can't open the file. Don't report it as a delete either. Let the
391 // server keep the old version. Maybe they'll be able to deal with it
392 // on restore.
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700393 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700394 } else {
Joe Onorato23ecae32009-06-10 17:07:15 -0700395 g.s.crc32 = compute_crc32(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700396
Joe Onorato23ecae32009-06-10 17:07:15 -0700397 LOGP("%s", q.string());
Christopher Tate11b15772009-06-23 13:03:00 -0700398 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
399 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
400 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
401 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
Joe Onorato23ecae32009-06-10 17:07:15 -0700402 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tate11b15772009-06-23 13:03:00 -0700403 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tatefbb92382009-06-23 17:35:11 -0700404 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700405 }
406
407 close(fd);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700408 }
409 n++;
410 m++;
411 }
412 }
413
414 // these were deleted
415 while (n<N) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700416 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700417 n++;
418 }
419
420 // these were added
421 while (m<fileCount) {
422 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700423 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700424 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700425 m++;
426 }
427
428 err = write_snapshot_file(newSnapshotFD, newSnapshot);
429
430 return 0;
431}
432
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700433static void calc_tar_checksum(char* buf) {
434 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
435 memset(buf + 148, ' ', 8);
436
437 uint16_t sum = 0;
438 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
439 sum += *p;
440 }
441
442 // Now write the real checksum value:
443 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
444 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
445}
446
Christopher Tatedc92c822011-05-13 15:38:02 -0700447// Returns number of bytes written
448static int write_pax_header_entry(char* buf, const char* key, const char* value) {
449 // start with the size of "1 key=value\n"
450 int len = strlen(key) + strlen(value) + 4;
451 if (len > 9) len++;
452 if (len > 99) len++;
453 if (len > 999) len++;
454 // since PATH_MAX is 4096 we don't expect to have to generate any single
455 // header entry longer than 9999 characters
456
457 return sprintf(buf, "%d %s=%s\n", len, key, value);
458}
459
Christopher Tate7926a692011-07-11 11:31:57 -0700460// Wire format to the backup manager service is chunked: each chunk is prefixed by
461// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
462void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
463 uint32_t chunk_size_no = htonl(size);
464 writer->WriteEntityData(&chunk_size_no, 4);
465 if (size != 0) writer->WriteEntityData(buffer, size);
466}
467
Christopher Tate4a627c72011-04-01 14:43:32 -0700468int write_tarfile(const String8& packageName, const String8& domain,
469 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
470{
471 // In the output stream everything is stored relative to the root
472 const char* relstart = filepath.string() + rootpath.length();
473 if (*relstart == '/') relstart++; // won't be true when path == rootpath
474 String8 relpath(relstart);
475
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700476 // If relpath is empty, it means this is the top of one of the standard named
477 // domain directories, so we should just skip it
478 if (relpath.length() == 0) {
479 return 0;
480 }
481
Christopher Tate4a627c72011-04-01 14:43:32 -0700482 // Too long a name for the ustar format?
483 // "apps/" + packagename + '/' + domainpath < 155 chars
484 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700485 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700486 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700487 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700488 }
489
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700490 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700491 if (!needExtended) {
492 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700493 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700494 needExtended = true;
495 break;
496 }
497 }
498 }
499
Christopher Tate4a627c72011-04-01 14:43:32 -0700500 int err = 0;
501 struct stat64 s;
502 if (lstat64(filepath.string(), &s) != 0) {
503 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000504 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700505 return err;
506 }
507
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700508 String8 fullname; // for pax later on
509 String8 prefix;
510
Christopher Tate4a627c72011-04-01 14:43:32 -0700511 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700512 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700513
514 // !!! TODO: use mmap when possible to avoid churning the buffer cache
515 // !!! TODO: this will break with symlinks; need to use readlink(2)
516 int fd = open(filepath.string(), O_RDONLY);
517 if (fd < 0) {
518 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000519 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700520 return err;
521 }
522
523 // read/write up to this much at a time.
524 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800525 char* buf = (char *)calloc(1,BUFSIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700526 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
527 char* paxData = buf + 1024;
528
Christopher Tate4a627c72011-04-01 14:43:32 -0700529 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000530 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700531 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800532 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700533 }
534
Christopher Tate4a627c72011-04-01 14:43:32 -0700535 // Magic fields for the ustar file format
536 strcat(buf + 257, "ustar");
537 strcat(buf + 263, "00");
538
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700539 // [ 265 : 32 ] user name, ignored on restore
540 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700541
542 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700543 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700544
545 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
546 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700547 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
548 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700549
550 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700551 if (s.st_size > 077777777777LL) {
552 // very large files need a pax extended size header
553 needExtended = true;
554 }
555 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700556
557 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800558 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700559
Christopher Tate4a627c72011-04-01 14:43:32 -0700560 // [ 156 : 1 ] link/file type
561 uint8_t type;
562 if (isdir) {
563 type = '5'; // tar magic: '5' == directory
564 } else if (S_ISREG(s.st_mode)) {
565 type = '0'; // tar magic: '0' == normal file
566 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000567 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700568 goto cleanup;
569 }
570 buf[156] = type;
571
572 // [ 157 : 100 ] name of linked file [not implemented]
573
Christopher Tate4a627c72011-04-01 14:43:32 -0700574 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700575 // Prefix and main relative path. Path lengths have been preflighted.
576 if (packageName.length() > 0) {
577 prefix = "apps/";
578 prefix += packageName;
579 }
580 if (domain.length() > 0) {
581 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700582 }
583
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700584 // pax extended means we don't put in a prefix field, and put a different
585 // string in the basic name field. We can also construct the full path name
586 // out of the substrings we've now built.
587 fullname = prefix;
588 fullname.appendPath(relpath);
589
590 // ustar:
591 // [ 0 : 100 ]; file name/path
592 // [ 345 : 155 ] filename path prefix
593 // We only use the prefix area if fullname won't fit in the path
594 if (fullname.length() > 100) {
595 strncpy(buf, relpath.string(), 100);
596 strncpy(buf + 345, prefix.string(), 155);
597 } else {
598 strncpy(buf, fullname.string(), 100);
599 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700600 }
601
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700602 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
603
Steve Block6215d3f2012-01-04 20:05:49 +0000604 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700605
606 // If we're using a pax extended header, build & write that here; lengths are
607 // already preflighted
608 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700609 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
610 char* p = paxData;
611
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700612 // construct the pax extended header data block
613 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700614
615 // size header -- calc len in digits by actually rendering the number
616 // to a string - brute force but simple
Ashok Bhatf5df7002014-03-25 20:51:35 +0000617 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
Christopher Tatedc92c822011-05-13 15:38:02 -0700618 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700619
620 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700621 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700622
623 // Now we know how big the pax data is
624 int paxLen = p - paxData;
625
626 // Now build the pax *header* templated on the ustar header
627 memcpy(paxHeader, buf, 512);
628
629 String8 leaf = fullname.getPathLeaf();
630 memset(paxHeader, 0, 100); // rewrite the name area
631 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
632 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
633 strncpy(paxHeader + 345, prefix.string(), 155);
634
635 paxHeader[156] = 'x'; // mark it as a pax extended header
636
637 // [ 124 : 12 ] size of pax extended header data
638 memset(paxHeader + 124, 0, 12);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000639 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700640
641 // Checksum and write the pax block header
642 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700643 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700644
645 // Now write the pax data itself
646 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700647 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700648 }
649
650 // Checksum and write the 512-byte ustar file header block to the output
651 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700652 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700653
654 // Now write the file data itself, for real files. We honor tar's convention that
655 // only full 512-byte blocks are sent to write().
656 if (!isdir) {
657 off64_t toWrite = s.st_size;
658 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000659 size_t toRead = toWrite;
660 if (toRead > BUFSIZE) {
661 toRead = BUFSIZE;
662 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700663 ssize_t nRead = read(fd, buf, toRead);
664 if (nRead < 0) {
665 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000666 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700667 err, strerror(err));
668 break;
669 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000670 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700671 filepath.string());
672 err = EIO;
673 break;
674 }
675
676 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
677 // depends on the OS guarantee that for ordinary files, read() will never return
678 // less than the number of bytes requested.
679 ssize_t partial = (nRead+512) % 512;
680 if (partial > 0) {
681 ssize_t remainder = 512 - partial;
682 memset(buf + nRead, 0, remainder);
683 nRead += remainder;
684 }
Christopher Tate7926a692011-07-11 11:31:57 -0700685 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700686 toWrite -= nRead;
687 }
688 }
689
690cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900691 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700692done:
693 close(fd);
694 return err;
695}
696// end tarfile
697
698
699
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700700#define RESTORE_BUF_SIZE (8*1024)
701
702RestoreHelperBase::RestoreHelperBase()
703{
704 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700705 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700706}
707
708RestoreHelperBase::~RestoreHelperBase()
709{
710 free(m_buf);
711}
712
713status_t
714RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
715{
716 ssize_t err;
717 size_t dataSize;
718 String8 key;
719 int fd;
720 void* buf = m_buf;
721 ssize_t amt;
722 int mode;
723 int crc;
724 struct stat st;
725 FileRec r;
726
727 err = in->ReadEntityHeader(&key, &dataSize);
728 if (err != NO_ERROR) {
729 return err;
730 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700731
Christopher Tatefbb92382009-06-23 17:35:11 -0700732 // Get the metadata block off the head of the file entity and use that to
733 // set up the output file
734 file_metadata_v1 metadata;
735 amt = in->ReadEntityData(&metadata, sizeof(metadata));
736 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000737 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700738 (long)amt, strerror(errno));
739 return EIO;
740 }
741 metadata.version = fromlel(metadata.version);
742 metadata.mode = fromlel(metadata.mode);
743 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700744 if (!m_loggedUnknownMetadata) {
745 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000746 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700747 metadata.version, CURRENT_METADATA_VERSION);
748 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700749 }
750 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700751
752 // Write the file and compute the crc
753 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700754 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
755 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000756 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700757 return errno;
758 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700759
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700760 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
761 err = write(fd, buf, amt);
762 if (err != amt) {
763 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000764 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700765 return errno;
766 }
767 crc = crc32(crc, (Bytef*)buf, amt);
768 }
769
770 close(fd);
771
772 // Record for the snapshot
773 err = stat(filename.string(), &st);
774 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000775 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700776 return errno;
777 }
778
779 r.file = filename;
780 r.deleted = false;
781 r.s.modTime_sec = st.st_mtime;
782 r.s.modTime_nsec = 0; // workaround sim breakage
783 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700784 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700785 r.s.size = st.st_size;
786 r.s.crc32 = crc;
787
788 m_files.add(key, r);
789
790 return NO_ERROR;
791}
792
793status_t
794RestoreHelperBase::WriteSnapshot(int fd)
795{
796 return write_snapshot_file(fd, m_files);;
797}
798
Joe Onorato3ad977b2009-05-05 11:50:51 -0700799#if TEST_BACKUP_HELPERS
800
801#define SCRATCH_DIR "/data/backup_helper_test/"
802
803static int
804write_text_file(const char* path, const char* data)
805{
806 int amt;
807 int fd;
808 int len;
809
810 fd = creat(path, 0666);
811 if (fd == -1) {
812 fprintf(stderr, "creat %s failed\n", path);
813 return errno;
814 }
815
816 len = strlen(data);
817 amt = write(fd, data, len);
818 if (amt != len) {
819 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
820 return errno;
821 }
822
823 close(fd);
824
825 return 0;
826}
827
828static int
829compare_file(const char* path, const unsigned char* data, int len)
830{
831 int fd;
832 int amt;
833
834 fd = open(path, O_RDONLY);
835 if (fd == -1) {
836 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
837 return errno;
838 }
839
840 unsigned char* contents = (unsigned char*)malloc(len);
841 if (contents == NULL) {
842 fprintf(stderr, "malloc(%d) failed\n", len);
843 return ENOMEM;
844 }
845
846 bool sizesMatch = true;
847 amt = lseek(fd, 0, SEEK_END);
848 if (amt != len) {
849 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
850 sizesMatch = false;
851 }
852 lseek(fd, 0, SEEK_SET);
853
854 int readLen = amt < len ? amt : len;
855 amt = read(fd, contents, readLen);
856 if (amt != readLen) {
857 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
858 }
859
860 bool contentsMatch = true;
861 for (int i=0; i<readLen; i++) {
862 if (data[i] != contents[i]) {
863 if (contentsMatch) {
864 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
865 contentsMatch = false;
866 }
867 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
868 }
869 }
870
Christopher Tate63bcb792009-06-24 13:57:29 -0700871 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700872 return contentsMatch && sizesMatch ? 0 : 1;
873}
874
875int
876backup_helper_test_empty()
877{
878 int err;
879 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700880 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700881 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
882
883 system("rm -r " SCRATCH_DIR);
884 mkdir(SCRATCH_DIR, 0777);
885
886 // write
887 fd = creat(filename, 0666);
888 if (fd == -1) {
889 fprintf(stderr, "error creating %s\n", filename);
890 return 1;
891 }
892
893 err = write_snapshot_file(fd, snapshot);
894
895 close(fd);
896
897 if (err != 0) {
898 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
899 return err;
900 }
901
902 static const unsigned char correct_data[] = {
903 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
904 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
905 };
906
907 err = compare_file(filename, correct_data, sizeof(correct_data));
908 if (err != 0) {
909 return err;
910 }
911
912 // read
913 fd = open(filename, O_RDONLY);
914 if (fd == -1) {
915 fprintf(stderr, "error opening for read %s\n", filename);
916 return 1;
917 }
918
919 KeyedVector<String8,FileState> readSnapshot;
920 err = read_snapshot_file(fd, &readSnapshot);
921 if (err != 0) {
922 fprintf(stderr, "read_snapshot_file failed %d\n", err);
923 return err;
924 }
925
926 if (readSnapshot.size() != 0) {
927 fprintf(stderr, "readSnapshot should be length 0\n");
928 return 1;
929 }
930
931 return 0;
932}
933
934int
935backup_helper_test_four()
936{
937 int err;
938 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700939 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700940 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
941
942 system("rm -r " SCRATCH_DIR);
943 mkdir(SCRATCH_DIR, 0777);
944
945 // write
946 fd = creat(filename, 0666);
947 if (fd == -1) {
948 fprintf(stderr, "error opening %s\n", filename);
949 return 1;
950 }
951
952 String8 filenames[4];
953 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700954 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700955 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700956
957 states[0].modTime_sec = 0xfedcba98;
958 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700959 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700960 states[0].size = 0xababbcbc;
961 states[0].crc32 = 0x12345678;
962 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700963 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700964 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700965 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700966
967 states[1].modTime_sec = 0x93400031;
968 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700969 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700970 states[1].size = 0x88557766;
971 states[1].crc32 = 0x22334422;
972 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700973 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700974 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700975 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700976
977 states[2].modTime_sec = 0x33221144;
978 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700979 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700980 states[2].size = 0x11223344;
981 states[2].crc32 = 0x01122334;
982 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700983 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700984 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700985 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700986
987 states[3].modTime_sec = 0x33221144;
988 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700989 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -0700990 states[3].size = 0x11223344;
991 states[3].crc32 = 0x01122334;
992 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700993 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700994 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -0700995 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700996
997 err = write_snapshot_file(fd, snapshot);
998
999 close(fd);
1000
1001 if (err != 0) {
1002 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1003 return err;
1004 }
1005
1006 static const unsigned char correct_data[] = {
1007 // header
1008 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001009 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001010
1011 // bytes_of_padding
1012 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001013 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1014 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1015 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1016 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001017
1018 // bytes_of_padding3
1019 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001020 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1021 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1022 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1023 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1024 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001025
Joe Onorato3ad977b2009-05-05 11:50:51 -07001026 // bytes of padding2
1027 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001028 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1029 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1030 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1031 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1032 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001033
Joe Onorato3ad977b2009-05-05 11:50:51 -07001034 // bytes of padding3
1035 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001036 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1037 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1038 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1039 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1040 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001041 };
1042
1043 err = compare_file(filename, correct_data, sizeof(correct_data));
1044 if (err != 0) {
1045 return err;
1046 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001047
Joe Onorato3ad977b2009-05-05 11:50:51 -07001048 // read
1049 fd = open(filename, O_RDONLY);
1050 if (fd == -1) {
1051 fprintf(stderr, "error opening for read %s\n", filename);
1052 return 1;
1053 }
1054
1055
1056 KeyedVector<String8,FileState> readSnapshot;
1057 err = read_snapshot_file(fd, &readSnapshot);
1058 if (err != 0) {
1059 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1060 return err;
1061 }
1062
1063 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001064 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001065 return 1;
1066 }
1067
1068 bool matched = true;
1069 for (size_t i=0; i<readSnapshot.size(); i++) {
1070 const String8& name = readSnapshot.keyAt(i);
1071 const FileState state = readSnapshot.valueAt(i);
1072
1073 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001074 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001075 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001076 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1077 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001078 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1079 states[i].crc32, name.length(), filenames[i].string(),
1080 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1081 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001082 matched = false;
1083 }
1084 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001085
Joe Onorato3ad977b2009-05-05 11:50:51 -07001086 return matched ? 0 : 1;
1087}
1088
Joe Onorato4535e402009-05-15 09:07:06 -04001089// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1090const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001091 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1092 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1093 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1094 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001095 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1096 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001097 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1098 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001099 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001100 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001101 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1102 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001103 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001104 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1105 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001106 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001107 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1108 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1109 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001110 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1111
Joe Onorato4535e402009-05-15 09:07:06 -04001112};
1113const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1114
1115static int
1116test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1117{
1118 int err;
1119 String8 text(str);
1120
Joe Onorato4535e402009-05-15 09:07:06 -04001121 err = writer.WriteEntityHeader(text, text.length()+1);
1122 if (err != 0) {
1123 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1124 return err;
1125 }
1126
1127 err = writer.WriteEntityData(text.string(), text.length()+1);
1128 if (err != 0) {
1129 fprintf(stderr, "write failed for data '%s'\n", text.string());
1130 return errno;
1131 }
1132
1133 return err;
1134}
1135
1136int
1137backup_helper_test_data_writer()
1138{
1139 int err;
1140 int fd;
1141 const char* filename = SCRATCH_DIR "data_writer.data";
1142
1143 system("rm -r " SCRATCH_DIR);
1144 mkdir(SCRATCH_DIR, 0777);
1145 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001146
Joe Onorato4535e402009-05-15 09:07:06 -04001147 fd = creat(filename, 0666);
1148 if (fd == -1) {
1149 fprintf(stderr, "error creating: %s\n", strerror(errno));
1150 return errno;
1151 }
1152
1153 BackupDataWriter writer(fd);
1154
1155 err = 0;
1156 err |= test_write_header_and_entity(writer, "no_padding_");
1157 err |= test_write_header_and_entity(writer, "padded_to__3");
1158 err |= test_write_header_and_entity(writer, "padded_to_2__");
1159 err |= test_write_header_and_entity(writer, "padded_to1");
1160
Joe Onorato4535e402009-05-15 09:07:06 -04001161 close(fd);
1162
1163 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1164 if (err != 0) {
1165 return err;
1166 }
1167
1168 return err;
1169}
1170
Joe Onorato2e1da322009-05-15 18:20:19 -04001171int
1172test_read_header_and_entity(BackupDataReader& reader, const char* str)
1173{
1174 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001175 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001176 char* buf = (char*)malloc(bufSize);
1177 String8 string;
Joe Onorato2e1da322009-05-15 18:20:19 -04001178 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001179 bool done;
1180 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001181 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001182
1183 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1184
Joe Onorato5f15d152009-06-16 16:31:35 -04001185 err = reader.ReadNextHeader(&done, &type);
1186 if (done) {
1187 fprintf(stderr, "should not be done yet\n");
1188 goto finished;
1189 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001190 if (err != 0) {
1191 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001192 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001193 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001194 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001195 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001196 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001197 }
1198
1199 err = reader.ReadEntityHeader(&string, &actualSize);
1200 if (err != 0) {
1201 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001202 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001203 }
1204 if (string != str) {
1205 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1206 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001207 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001208 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001209 if (actualSize != bufSize) {
1210 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1211 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001212 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001213 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001214 }
1215
Christopher Tate11b15772009-06-23 13:03:00 -07001216 nRead = reader.ReadEntityData(buf, bufSize);
1217 if (nRead < 0) {
1218 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001219 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001220 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001221 }
1222
1223 if (0 != memcmp(buf, str, bufSize)) {
1224 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001225 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1226 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001227 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001228 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001229 }
1230
1231 // The next read will confirm whether it got the right amount of data.
1232
Joe Onorato5f15d152009-06-16 16:31:35 -04001233finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001234 if (err != NO_ERROR) {
1235 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1236 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001237 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001238 return err;
1239}
1240
1241int
1242backup_helper_test_data_reader()
1243{
1244 int err;
1245 int fd;
1246 const char* filename = SCRATCH_DIR "data_reader.data";
1247
1248 system("rm -r " SCRATCH_DIR);
1249 mkdir(SCRATCH_DIR, 0777);
1250 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001251
Joe Onorato2e1da322009-05-15 18:20:19 -04001252 fd = creat(filename, 0666);
1253 if (fd == -1) {
1254 fprintf(stderr, "error creating: %s\n", strerror(errno));
1255 return errno;
1256 }
1257
1258 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1259 if (err != DATA_GOLDEN_FILE_SIZE) {
1260 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1261 return errno;
1262 }
1263
1264 close(fd);
1265
1266 fd = open(filename, O_RDONLY);
1267 if (fd == -1) {
1268 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1269 filename);
1270 return errno;
1271 }
1272
1273 {
1274 BackupDataReader reader(fd);
1275
1276 err = 0;
1277
1278 if (err == NO_ERROR) {
1279 err = test_read_header_and_entity(reader, "no_padding_");
1280 }
1281
1282 if (err == NO_ERROR) {
1283 err = test_read_header_and_entity(reader, "padded_to__3");
1284 }
1285
1286 if (err == NO_ERROR) {
1287 err = test_read_header_and_entity(reader, "padded_to_2__");
1288 }
1289
1290 if (err == NO_ERROR) {
1291 err = test_read_header_and_entity(reader, "padded_to1");
1292 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001293 }
1294
1295 close(fd);
1296
1297 return err;
1298}
1299
Joe Onorato3ad977b2009-05-05 11:50:51 -07001300static int
1301get_mod_time(const char* filename, struct timeval times[2])
1302{
1303 int err;
1304 struct stat64 st;
1305 err = stat64(filename, &st);
1306 if (err != 0) {
1307 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1308 return errno;
1309 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001310
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001311 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001312 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001313
1314 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001315 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001316
Joe Onorato3ad977b2009-05-05 11:50:51 -07001317 return 0;
1318}
1319
1320int
1321backup_helper_test_files()
1322{
1323 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001324 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001325 int dataStreamFD;
1326 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001327
1328 system("rm -r " SCRATCH_DIR);
1329 mkdir(SCRATCH_DIR, 0777);
1330 mkdir(SCRATCH_DIR "data", 0777);
1331
1332 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1333 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1334 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1335 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1336 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1337 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1338
1339 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001340 SCRATCH_DIR "data/b",
1341 SCRATCH_DIR "data/c",
1342 SCRATCH_DIR "data/d",
1343 SCRATCH_DIR "data/e",
1344 SCRATCH_DIR "data/f"
1345 };
1346
1347 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001348 "data/b",
1349 "data/c",
1350 "data/d",
1351 "data/e",
1352 "data/f"
1353 };
1354
Joe Onorato4535e402009-05-15 09:07:06 -04001355 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1356 if (dataStreamFD == -1) {
1357 fprintf(stderr, "error creating: %s\n", strerror(errno));
1358 return errno;
1359 }
1360
Joe Onorato3ad977b2009-05-05 11:50:51 -07001361 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1362 if (newSnapshotFD == -1) {
1363 fprintf(stderr, "error creating: %s\n", strerror(errno));
1364 return errno;
1365 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001366
1367 {
1368 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001369
Joe Onorato23ecae32009-06-10 17:07:15 -07001370 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001371 if (err != 0) {
1372 return err;
1373 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001374 }
1375
Joe Onorato4535e402009-05-15 09:07:06 -04001376 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001377 close(newSnapshotFD);
1378
1379 sleep(3);
1380
1381 struct timeval d_times[2];
1382 struct timeval e_times[2];
1383
1384 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1385 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1386 if (err != 0) {
1387 return err;
1388 }
1389
1390 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1391 unlink(SCRATCH_DIR "data/c");
1392 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1393 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1394 utimes(SCRATCH_DIR "data/d", d_times);
1395 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1396 utimes(SCRATCH_DIR "data/e", e_times);
1397 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1398 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001399
Joe Onorato3ad977b2009-05-05 11:50:51 -07001400 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001401 SCRATCH_DIR "data/a", // added
1402 SCRATCH_DIR "data/b", // same
1403 SCRATCH_DIR "data/c", // different mod time
1404 SCRATCH_DIR "data/d", // different size (same mod time)
1405 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1406 SCRATCH_DIR "data/g" // added
1407 };
1408
1409 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001410 "data/a", // added
1411 "data/b", // same
1412 "data/c", // different mod time
1413 "data/d", // different size (same mod time)
1414 "data/e", // different contents (same mod time, same size)
1415 "data/g" // added
1416 };
1417
1418 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1419 if (oldSnapshotFD == -1) {
1420 fprintf(stderr, "error opening: %s\n", strerror(errno));
1421 return errno;
1422 }
1423
Joe Onorato4535e402009-05-15 09:07:06 -04001424 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1425 if (dataStreamFD == -1) {
1426 fprintf(stderr, "error creating: %s\n", strerror(errno));
1427 return errno;
1428 }
1429
Joe Onorato3ad977b2009-05-05 11:50:51 -07001430 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1431 if (newSnapshotFD == -1) {
1432 fprintf(stderr, "error creating: %s\n", strerror(errno));
1433 return errno;
1434 }
1435
Joe Onoratod2110db2009-05-19 13:41:21 -07001436 {
1437 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001438
Joe Onorato23ecae32009-06-10 17:07:15 -07001439 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001440 if (err != 0) {
1441 return err;
1442 }
1443}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001444
1445 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001446 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001447 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001448
Joe Onorato3ad977b2009-05-05 11:50:51 -07001449 return 0;
1450}
1451
Joe Onorato23ecae32009-06-10 17:07:15 -07001452int
1453backup_helper_test_null_base()
1454{
1455 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001456 int dataStreamFD;
1457 int newSnapshotFD;
1458
1459 system("rm -r " SCRATCH_DIR);
1460 mkdir(SCRATCH_DIR, 0777);
1461 mkdir(SCRATCH_DIR "data", 0777);
1462
1463 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1464
1465 char const* files[] = {
1466 SCRATCH_DIR "data/a",
1467 };
1468
1469 char const* keys[] = {
1470 "a",
1471 };
1472
1473 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1474 if (dataStreamFD == -1) {
1475 fprintf(stderr, "error creating: %s\n", strerror(errno));
1476 return errno;
1477 }
1478
1479 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1480 if (newSnapshotFD == -1) {
1481 fprintf(stderr, "error creating: %s\n", strerror(errno));
1482 return errno;
1483 }
1484
1485 {
1486 BackupDataWriter dataStream(dataStreamFD);
1487
1488 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1489 if (err != 0) {
1490 return err;
1491 }
1492 }
1493
1494 close(dataStreamFD);
1495 close(newSnapshotFD);
1496
1497 return 0;
1498}
1499
Joe Onoratoce88cb12009-06-11 11:27:16 -07001500int
1501backup_helper_test_missing_file()
1502{
1503 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001504 int dataStreamFD;
1505 int newSnapshotFD;
1506
1507 system("rm -r " SCRATCH_DIR);
1508 mkdir(SCRATCH_DIR, 0777);
1509 mkdir(SCRATCH_DIR "data", 0777);
1510
1511 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1512
1513 char const* files[] = {
1514 SCRATCH_DIR "data/a",
1515 SCRATCH_DIR "data/b",
1516 SCRATCH_DIR "data/c",
1517 };
1518
1519 char const* keys[] = {
1520 "a",
1521 "b",
1522 "c",
1523 };
1524
1525 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1526 if (dataStreamFD == -1) {
1527 fprintf(stderr, "error creating: %s\n", strerror(errno));
1528 return errno;
1529 }
1530
1531 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1532 if (newSnapshotFD == -1) {
1533 fprintf(stderr, "error creating: %s\n", strerror(errno));
1534 return errno;
1535 }
1536
1537 {
1538 BackupDataWriter dataStream(dataStreamFD);
1539
1540 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1541 if (err != 0) {
1542 return err;
1543 }
1544 }
1545
1546 close(dataStreamFD);
1547 close(newSnapshotFD);
1548
1549 return 0;
1550}
1551
Joe Onorato23ecae32009-06-10 17:07:15 -07001552
Joe Onorato3ad977b2009-05-05 11:50:51 -07001553#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001554
1555}