blob: 33cf8ef6f65c4e87c65a9742e6f3bc097644fc55 [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
Joe Onorato568bc322009-06-26 17:19:11 -040071#if 1
72#define LOGP(f, x...)
73#else
74#if TEST_BACKUP_HELPERS
Joe Onorato23ecae32009-06-10 17:07:15 -070075#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040076#else
Steve Block5baa3a62011-12-20 16:23:08 +000077#define LOGP(x...) ALOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040078#endif
Joe Onorato568bc322009-06-26 17:19:11 -040079#endif
Joe Onorato290bb012009-05-13 18:57:29 -040080
Joe Onorato3ad977b2009-05-05 11:50:51 -070081const static int ROUND_UP[4] = { 0, 3, 2, 1 };
82
83static inline int
84round_up(int n)
85{
86 return n + ROUND_UP[n % 4];
87}
88
89static int
90read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
91{
92 int bytesRead = 0;
93 int amt;
94 SnapshotHeader header;
95
96 amt = read(fd, &header, sizeof(header));
97 if (amt != sizeof(header)) {
98 return errno;
99 }
100 bytesRead += amt;
101
102 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000103 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700104 return 1;
105 }
106
107 for (int i=0; i<header.fileCount; i++) {
108 FileState file;
109 char filenameBuf[128];
110
Joe Onorato23ecae32009-06-10 17:07:15 -0700111 amt = read(fd, &file, sizeof(FileState));
112 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000113 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700114 return 1;
115 }
116 bytesRead += amt;
117
118 // filename is not NULL terminated, but it is padded
119 int nameBufSize = round_up(file.nameLen);
120 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
121 ? filenameBuf
122 : (char*)malloc(nameBufSize);
123 amt = read(fd, filename, nameBufSize);
124 if (amt == nameBufSize) {
125 snapshot->add(String8(filename, file.nameLen), file);
126 }
127 bytesRead += amt;
128 if (filename != filenameBuf) {
129 free(filename);
130 }
131 if (amt != nameBufSize) {
Steve Block8564c8d2012-01-05 23:22:43 +0000132 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700133 return 1;
134 }
135 }
136
137 if (header.totalSize != bytesRead) {
Steve Block8564c8d2012-01-05 23:22:43 +0000138 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700139 header.totalSize, bytesRead);
140 return 1;
141 }
142
143 return 0;
144}
145
146static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700147write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700148{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700149 int fileCount = 0;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700150 int bytesWritten = sizeof(SnapshotHeader);
151 // preflight size
152 const int N = snapshot.size();
153 for (int i=0; i<N; i++) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700154 const FileRec& g = snapshot.valueAt(i);
155 if (!g.deleted) {
156 const String8& name = snapshot.keyAt(i);
157 bytesWritten += sizeof(FileState) + round_up(name.length());
158 fileCount++;
159 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700160 }
161
Joe Onorato4535e402009-05-15 09:07:06 -0400162 LOGP("write_snapshot_file fd=%d\n", fd);
163
Joe Onorato3ad977b2009-05-05 11:50:51 -0700164 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-05-05 11:50:51 -0700166
167 amt = write(fd, &header, sizeof(header));
168 if (amt != sizeof(header)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000169 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700170 return errno;
171 }
172
Joe Onoratoce88cb12009-06-11 11:27:16 -0700173 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700174 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700175 if (!r.deleted) {
176 const String8& name = snapshot.keyAt(i);
177 int nameLen = r.s.nameLen = name.length();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700178
Joe Onoratoce88cb12009-06-11 11:27:16 -0700179 amt = write(fd, &r.s, sizeof(FileState));
180 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000181 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700182 return 1;
183 }
Joe Onoratoce88cb12009-06-11 11:27:16 -0700184
185 // filename is not NULL terminated, but it is padded
186 amt = write(fd, name.string(), nameLen);
187 if (amt != nameLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000188 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
Joe Onoratoce88cb12009-06-11 11:27:16 -0700189 return 1;
190 }
191 int paddingLen = ROUND_UP[nameLen % 4];
192 if (paddingLen != 0) {
193 int padding = 0xabababab;
194 amt = write(fd, &padding, paddingLen);
195 if (amt != paddingLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000196 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s",
Joe Onoratoce88cb12009-06-11 11:27:16 -0700197 paddingLen, strerror(errno));
198 return 1;
199 }
200 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700201 }
202 }
203
204 return 0;
205}
206
207static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700208write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700209{
Joe Onorato290bb012009-05-13 18:57:29 -0400210 LOGP("write_delete_file %s\n", key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700211 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700212}
213
214static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700215write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700216 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700217{
Christopher Tatefbb92382009-06-23 17:35:11 -0700218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700219
220 const int bufsize = 4*1024;
221 int err;
222 int amt;
223 int fileSize;
224 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700225 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700226
227 char* buf = (char*)malloc(bufsize);
Joe Onoratod2110db2009-05-19 13:41:21 -0700228
Christopher Tatefbb92382009-06-23 17:35:11 -0700229 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700230 lseek(fd, 0, SEEK_SET);
231
Christopher Tatefbb92382009-06-23 17:35:11 -0700232 if (sizeof(metadata) != 16) {
Steve Block3762c312012-01-06 19:20:56 +0000233 ALOGE("ERROR: metadata block is the wrong size!");
Christopher Tatefbb92382009-06-23 17:35:11 -0700234 }
235
236 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700237 err = dataStream->WriteEntityHeader(key, bytesLeft);
238 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700239 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700240 return err;
241 }
242
Christopher Tatefbb92382009-06-23 17:35:11 -0700243 // store the file metadata first
244 metadata.version = tolel(CURRENT_METADATA_VERSION);
245 metadata.mode = tolel(mode);
246 metadata.undefined_1 = metadata.undefined_2 = 0;
247 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
248 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700249 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700250 return err;
251 }
252 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
253
254 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700255 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
256 bytesLeft -= amt;
257 if (bytesLeft < 0) {
258 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
259 }
260 err = dataStream->WriteEntityData(buf, amt);
261 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700262 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700263 return err;
264 }
265 }
266 if (bytesLeft != 0) {
267 if (bytesLeft > 0) {
268 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
269 // even though the data we're sending is probably bad.
270 memset(buf, 0, bufsize);
271 while (bytesLeft > 0) {
272 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
273 bytesLeft -= amt;
274 err = dataStream->WriteEntityData(buf, amt);
275 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700276 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700277 return err;
278 }
279 }
280 }
Steve Block3762c312012-01-06 19:20:56 +0000281 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700282 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700283 }
284
Christopher Tate63bcb792009-06-24 13:57:29 -0700285 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700286 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700287}
288
289static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700290write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700291{
292 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700293 struct stat st;
294
295 err = stat(realFilename, &st);
296 if (err < 0) {
297 return errno;
298 }
299
Joe Onorato23ecae32009-06-10 17:07:15 -0700300 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700301 if (fd == -1) {
302 return errno;
303 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700304
305 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700306 close(fd);
307 return err;
308}
309
310static int
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800311compute_crc32(const char* file, FileRec* out) {
312 int fd = open(file, O_RDONLY);
313 if (fd < 0) {
314 return -1;
315 }
316
Joe Onorato3ad977b2009-05-05 11:50:51 -0700317 const int bufsize = 4*1024;
318 int amt;
319
Joe Onorato3ad977b2009-05-05 11:50:51 -0700320 char* buf = (char*)malloc(bufsize);
321 int crc = crc32(0L, Z_NULL, 0);
322
Joe Onoratod2110db2009-05-19 13:41:21 -0700323 lseek(fd, 0, SEEK_SET);
324
Joe Onorato3ad977b2009-05-05 11:50:51 -0700325 while ((amt = read(fd, buf, bufsize)) != 0) {
326 crc = crc32(crc, (Bytef*)buf, amt);
327 }
328
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800329 close(fd);
Christopher Tate63bcb792009-06-24 13:57:29 -0700330 free(buf);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800331
332 out->s.crc32 = crc;
333 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700334}
335
336int
Joe Onoratod2110db2009-05-19 13:41:21 -0700337back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700338 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700339{
340 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700341 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700342 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700343
344 if (oldSnapshotFD != -1) {
345 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
346 if (err != 0) {
347 // On an error, treat this as a full backup.
348 oldSnapshot.clear();
349 }
350 }
351
352 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700353 String8 key(keys[i]);
354 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700355 char const* file = files[i];
356 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700357 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700358
Joe Onorato23ecae32009-06-10 17:07:15 -0700359 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700360 if (err != 0) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800361 // not found => treat as deleted
362 continue;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700363 } else {
364 r.deleted = false;
365 r.s.modTime_sec = st.st_mtime;
366 r.s.modTime_nsec = 0; // workaround sim breakage
367 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700368 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700369 r.s.size = st.st_size;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700370
Joe Onoratoce88cb12009-06-11 11:27:16 -0700371 if (newSnapshot.indexOfKey(key) >= 0) {
372 LOGP("back_up_files key already in use '%s'", key.string());
373 return -1;
374 }
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800375
376 // compute the CRC
377 if (compute_crc32(file, &r) != NO_ERROR) {
378 ALOGW("Unable to open file %s", file);
379 continue;
380 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700381 }
382 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700383 }
384
385 int n = 0;
386 int N = oldSnapshot.size();
387 int m = 0;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800388 int M = newSnapshot.size();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700389
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800390 while (n<N && m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 const String8& p = oldSnapshot.keyAt(n);
392 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700393 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700394 int cmp = p.compare(q);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800395 if (cmp < 0) {
396 // file present in oldSnapshot, but not present in newSnapshot
Joe Onoratoce88cb12009-06-11 11:27:16 -0700397 LOGP("file removed: %s", p.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800398 write_delete_file(dataStream, p);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700399 n++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800400 } else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700401 // file added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800402 LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700403 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700404 m++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800405 } else {
406 // same file exists in both old and new; check whether to update
Joe Onorato3ad977b2009-05-05 11:50:51 -0700407 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700408
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800409 LOGP("%s", q.string());
410 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
411 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
412 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
413 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
416 int fd = open(g.file.string(), O_RDONLY);
417 if (fd < 0) {
418 ALOGE("Unable to read file for backup: %s", g.file.string());
419 } else {
Christopher Tatefbb92382009-06-23 17:35:11 -0700420 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800421 close(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700422 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700423 }
424 n++;
425 m++;
426 }
427 }
428
429 // these were deleted
430 while (n<N) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800431 write_delete_file(dataStream, oldSnapshot.keyAt(n));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700432 n++;
433 }
434
435 // these were added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800436 while (m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700437 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700438 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700439 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700440 m++;
441 }
442
443 err = write_snapshot_file(newSnapshotFD, newSnapshot);
444
445 return 0;
446}
447
Christopher Tate4a627c72011-04-01 14:43:32 -0700448// Utility function, equivalent to stpcpy(): perform a strcpy, but instead of
449// returning the initial dest, return a pointer to the trailing NUL.
450static char* strcpy_ptr(char* dest, const char* str) {
451 if (dest && str) {
452 while ((*dest = *str) != 0) {
453 dest++;
454 str++;
455 }
456 }
457 return dest;
458}
459
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700460static void calc_tar_checksum(char* buf) {
461 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
462 memset(buf + 148, ' ', 8);
463
464 uint16_t sum = 0;
465 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
466 sum += *p;
467 }
468
469 // Now write the real checksum value:
470 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
471 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
472}
473
Christopher Tatedc92c822011-05-13 15:38:02 -0700474// Returns number of bytes written
475static int write_pax_header_entry(char* buf, const char* key, const char* value) {
476 // start with the size of "1 key=value\n"
477 int len = strlen(key) + strlen(value) + 4;
478 if (len > 9) len++;
479 if (len > 99) len++;
480 if (len > 999) len++;
481 // since PATH_MAX is 4096 we don't expect to have to generate any single
482 // header entry longer than 9999 characters
483
484 return sprintf(buf, "%d %s=%s\n", len, key, value);
485}
486
Christopher Tate7926a692011-07-11 11:31:57 -0700487// Wire format to the backup manager service is chunked: each chunk is prefixed by
488// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
489void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
490 uint32_t chunk_size_no = htonl(size);
491 writer->WriteEntityData(&chunk_size_no, 4);
492 if (size != 0) writer->WriteEntityData(buffer, size);
493}
494
Christopher Tate4a627c72011-04-01 14:43:32 -0700495int write_tarfile(const String8& packageName, const String8& domain,
496 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
497{
498 // In the output stream everything is stored relative to the root
499 const char* relstart = filepath.string() + rootpath.length();
500 if (*relstart == '/') relstart++; // won't be true when path == rootpath
501 String8 relpath(relstart);
502
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700503 // If relpath is empty, it means this is the top of one of the standard named
504 // domain directories, so we should just skip it
505 if (relpath.length() == 0) {
506 return 0;
507 }
508
Christopher Tate4a627c72011-04-01 14:43:32 -0700509 // Too long a name for the ustar format?
510 // "apps/" + packagename + '/' + domainpath < 155 chars
511 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700512 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700513 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700514 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700515 }
516
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700517 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700518 if (!needExtended) {
519 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700520 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700521 needExtended = true;
522 break;
523 }
524 }
525 }
526
Christopher Tate4a627c72011-04-01 14:43:32 -0700527 int err = 0;
528 struct stat64 s;
529 if (lstat64(filepath.string(), &s) != 0) {
530 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000531 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700532 return err;
533 }
534
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700535 String8 fullname; // for pax later on
536 String8 prefix;
537
Christopher Tate4a627c72011-04-01 14:43:32 -0700538 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700539 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700540
541 // !!! TODO: use mmap when possible to avoid churning the buffer cache
542 // !!! TODO: this will break with symlinks; need to use readlink(2)
543 int fd = open(filepath.string(), O_RDONLY);
544 if (fd < 0) {
545 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000546 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700547 return err;
548 }
549
550 // read/write up to this much at a time.
551 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800552 char* buf = (char *)calloc(1,BUFSIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700553 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
554 char* paxData = buf + 1024;
555
Christopher Tate4a627c72011-04-01 14:43:32 -0700556 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000557 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700558 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800559 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700560 }
561
Christopher Tate4a627c72011-04-01 14:43:32 -0700562 // Magic fields for the ustar file format
563 strcat(buf + 257, "ustar");
564 strcat(buf + 263, "00");
565
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700566 // [ 265 : 32 ] user name, ignored on restore
567 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700568
569 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700570 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700571
572 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
573 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700574 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
575 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700576
577 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700578 if (s.st_size > 077777777777LL) {
579 // very large files need a pax extended size header
580 needExtended = true;
581 }
582 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700583
584 // [ 136 : 12 ] last mod time as a UTC time_t
585 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
586
Christopher Tate4a627c72011-04-01 14:43:32 -0700587 // [ 156 : 1 ] link/file type
588 uint8_t type;
589 if (isdir) {
590 type = '5'; // tar magic: '5' == directory
591 } else if (S_ISREG(s.st_mode)) {
592 type = '0'; // tar magic: '0' == normal file
593 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000594 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700595 goto cleanup;
596 }
597 buf[156] = type;
598
599 // [ 157 : 100 ] name of linked file [not implemented]
600
Christopher Tate4a627c72011-04-01 14:43:32 -0700601 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700602 // Prefix and main relative path. Path lengths have been preflighted.
603 if (packageName.length() > 0) {
604 prefix = "apps/";
605 prefix += packageName;
606 }
607 if (domain.length() > 0) {
608 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700609 }
610
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700611 // pax extended means we don't put in a prefix field, and put a different
612 // string in the basic name field. We can also construct the full path name
613 // out of the substrings we've now built.
614 fullname = prefix;
615 fullname.appendPath(relpath);
616
617 // ustar:
618 // [ 0 : 100 ]; file name/path
619 // [ 345 : 155 ] filename path prefix
620 // We only use the prefix area if fullname won't fit in the path
621 if (fullname.length() > 100) {
622 strncpy(buf, relpath.string(), 100);
623 strncpy(buf + 345, prefix.string(), 155);
624 } else {
625 strncpy(buf, fullname.string(), 100);
626 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700627 }
628
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700629 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
630
Steve Block6215d3f2012-01-04 20:05:49 +0000631 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700632
633 // If we're using a pax extended header, build & write that here; lengths are
634 // already preflighted
635 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700636 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
637 char* p = paxData;
638
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700639 // construct the pax extended header data block
640 memset(paxData, 0, BUFSIZE - (paxData - buf));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700641 int len;
642
643 // size header -- calc len in digits by actually rendering the number
644 // to a string - brute force but simple
Ashok Bhatf5df7002014-03-25 20:51:35 +0000645 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
Christopher Tatedc92c822011-05-13 15:38:02 -0700646 p += write_pax_header_entry(p, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700647
648 // fullname was generated above with the ustar paths
Christopher Tatedc92c822011-05-13 15:38:02 -0700649 p += write_pax_header_entry(p, "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700650
651 // Now we know how big the pax data is
652 int paxLen = p - paxData;
653
654 // Now build the pax *header* templated on the ustar header
655 memcpy(paxHeader, buf, 512);
656
657 String8 leaf = fullname.getPathLeaf();
658 memset(paxHeader, 0, 100); // rewrite the name area
659 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
660 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
661 strncpy(paxHeader + 345, prefix.string(), 155);
662
663 paxHeader[156] = 'x'; // mark it as a pax extended header
664
665 // [ 124 : 12 ] size of pax extended header data
666 memset(paxHeader + 124, 0, 12);
Ashok Bhatf5df7002014-03-25 20:51:35 +0000667 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData));
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700668
669 // Checksum and write the pax block header
670 calc_tar_checksum(paxHeader);
Christopher Tate7926a692011-07-11 11:31:57 -0700671 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700672
673 // Now write the pax data itself
674 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700675 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700676 }
677
678 // Checksum and write the 512-byte ustar file header block to the output
679 calc_tar_checksum(buf);
Christopher Tate7926a692011-07-11 11:31:57 -0700680 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700681
682 // Now write the file data itself, for real files. We honor tar's convention that
683 // only full 512-byte blocks are sent to write().
684 if (!isdir) {
685 off64_t toWrite = s.st_size;
686 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000687 size_t toRead = toWrite;
688 if (toRead > BUFSIZE) {
689 toRead = BUFSIZE;
690 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700691 ssize_t nRead = read(fd, buf, toRead);
692 if (nRead < 0) {
693 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000694 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700695 err, strerror(err));
696 break;
697 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000698 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Christopher Tate4a627c72011-04-01 14:43:32 -0700699 filepath.string());
700 err = EIO;
701 break;
702 }
703
704 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
705 // depends on the OS guarantee that for ordinary files, read() will never return
706 // less than the number of bytes requested.
707 ssize_t partial = (nRead+512) % 512;
708 if (partial > 0) {
709 ssize_t remainder = 512 - partial;
710 memset(buf + nRead, 0, remainder);
711 nRead += remainder;
712 }
Christopher Tate7926a692011-07-11 11:31:57 -0700713 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700714 toWrite -= nRead;
715 }
716 }
717
718cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900719 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700720done:
721 close(fd);
722 return err;
723}
724// end tarfile
725
726
727
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700728#define RESTORE_BUF_SIZE (8*1024)
729
730RestoreHelperBase::RestoreHelperBase()
731{
732 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700733 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700734}
735
736RestoreHelperBase::~RestoreHelperBase()
737{
738 free(m_buf);
739}
740
741status_t
742RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
743{
744 ssize_t err;
745 size_t dataSize;
746 String8 key;
747 int fd;
748 void* buf = m_buf;
749 ssize_t amt;
750 int mode;
751 int crc;
752 struct stat st;
753 FileRec r;
754
755 err = in->ReadEntityHeader(&key, &dataSize);
756 if (err != NO_ERROR) {
757 return err;
758 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700759
Christopher Tatefbb92382009-06-23 17:35:11 -0700760 // Get the metadata block off the head of the file entity and use that to
761 // set up the output file
762 file_metadata_v1 metadata;
763 amt = in->ReadEntityData(&metadata, sizeof(metadata));
764 if (amt != sizeof(metadata)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000765 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700766 (long)amt, strerror(errno));
767 return EIO;
768 }
769 metadata.version = fromlel(metadata.version);
770 metadata.mode = fromlel(metadata.mode);
771 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700772 if (!m_loggedUnknownMetadata) {
773 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000774 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700775 metadata.version, CURRENT_METADATA_VERSION);
776 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700777 }
778 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700779
780 // Write the file and compute the crc
781 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700782 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
783 if (fd == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000784 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700785 return errno;
786 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700787
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700788 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
789 err = write(fd, buf, amt);
790 if (err != amt) {
791 close(fd);
Steve Block8564c8d2012-01-05 23:22:43 +0000792 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700793 return errno;
794 }
795 crc = crc32(crc, (Bytef*)buf, amt);
796 }
797
798 close(fd);
799
800 // Record for the snapshot
801 err = stat(filename.string(), &st);
802 if (err != 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000803 ALOGW("Error stating file that we just created %s", filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700804 return errno;
805 }
806
807 r.file = filename;
808 r.deleted = false;
809 r.s.modTime_sec = st.st_mtime;
810 r.s.modTime_nsec = 0; // workaround sim breakage
811 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700812 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700813 r.s.size = st.st_size;
814 r.s.crc32 = crc;
815
816 m_files.add(key, r);
817
818 return NO_ERROR;
819}
820
821status_t
822RestoreHelperBase::WriteSnapshot(int fd)
823{
824 return write_snapshot_file(fd, m_files);;
825}
826
Joe Onorato3ad977b2009-05-05 11:50:51 -0700827#if TEST_BACKUP_HELPERS
828
829#define SCRATCH_DIR "/data/backup_helper_test/"
830
831static int
832write_text_file(const char* path, const char* data)
833{
834 int amt;
835 int fd;
836 int len;
837
838 fd = creat(path, 0666);
839 if (fd == -1) {
840 fprintf(stderr, "creat %s failed\n", path);
841 return errno;
842 }
843
844 len = strlen(data);
845 amt = write(fd, data, len);
846 if (amt != len) {
847 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
848 return errno;
849 }
850
851 close(fd);
852
853 return 0;
854}
855
856static int
857compare_file(const char* path, const unsigned char* data, int len)
858{
859 int fd;
860 int amt;
861
862 fd = open(path, O_RDONLY);
863 if (fd == -1) {
864 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
865 return errno;
866 }
867
868 unsigned char* contents = (unsigned char*)malloc(len);
869 if (contents == NULL) {
870 fprintf(stderr, "malloc(%d) failed\n", len);
871 return ENOMEM;
872 }
873
874 bool sizesMatch = true;
875 amt = lseek(fd, 0, SEEK_END);
876 if (amt != len) {
877 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
878 sizesMatch = false;
879 }
880 lseek(fd, 0, SEEK_SET);
881
882 int readLen = amt < len ? amt : len;
883 amt = read(fd, contents, readLen);
884 if (amt != readLen) {
885 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
886 }
887
888 bool contentsMatch = true;
889 for (int i=0; i<readLen; i++) {
890 if (data[i] != contents[i]) {
891 if (contentsMatch) {
892 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
893 contentsMatch = false;
894 }
895 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
896 }
897 }
898
Christopher Tate63bcb792009-06-24 13:57:29 -0700899 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700900 return contentsMatch && sizesMatch ? 0 : 1;
901}
902
903int
904backup_helper_test_empty()
905{
906 int err;
907 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700908 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700909 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
910
911 system("rm -r " SCRATCH_DIR);
912 mkdir(SCRATCH_DIR, 0777);
913
914 // write
915 fd = creat(filename, 0666);
916 if (fd == -1) {
917 fprintf(stderr, "error creating %s\n", filename);
918 return 1;
919 }
920
921 err = write_snapshot_file(fd, snapshot);
922
923 close(fd);
924
925 if (err != 0) {
926 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
927 return err;
928 }
929
930 static const unsigned char correct_data[] = {
931 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
932 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
933 };
934
935 err = compare_file(filename, correct_data, sizeof(correct_data));
936 if (err != 0) {
937 return err;
938 }
939
940 // read
941 fd = open(filename, O_RDONLY);
942 if (fd == -1) {
943 fprintf(stderr, "error opening for read %s\n", filename);
944 return 1;
945 }
946
947 KeyedVector<String8,FileState> readSnapshot;
948 err = read_snapshot_file(fd, &readSnapshot);
949 if (err != 0) {
950 fprintf(stderr, "read_snapshot_file failed %d\n", err);
951 return err;
952 }
953
954 if (readSnapshot.size() != 0) {
955 fprintf(stderr, "readSnapshot should be length 0\n");
956 return 1;
957 }
958
959 return 0;
960}
961
962int
963backup_helper_test_four()
964{
965 int err;
966 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700967 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700968 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
969
970 system("rm -r " SCRATCH_DIR);
971 mkdir(SCRATCH_DIR, 0777);
972
973 // write
974 fd = creat(filename, 0666);
975 if (fd == -1) {
976 fprintf(stderr, "error opening %s\n", filename);
977 return 1;
978 }
979
980 String8 filenames[4];
981 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700982 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700983 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700984
985 states[0].modTime_sec = 0xfedcba98;
986 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700987 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700988 states[0].size = 0xababbcbc;
989 states[0].crc32 = 0x12345678;
990 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700991 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700992 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700993 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700994
995 states[1].modTime_sec = 0x93400031;
996 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700997 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700998 states[1].size = 0x88557766;
999 states[1].crc32 = 0x22334422;
1000 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -07001001 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001002 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -07001003 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001004
1005 states[2].modTime_sec = 0x33221144;
1006 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001007 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -07001008 states[2].size = 0x11223344;
1009 states[2].crc32 = 0x01122334;
1010 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001011 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001012 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001013 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001014
1015 states[3].modTime_sec = 0x33221144;
1016 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001017 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001018 states[3].size = 0x11223344;
1019 states[3].crc32 = 0x01122334;
1020 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001021 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001022 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001023 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001024
1025 err = write_snapshot_file(fd, snapshot);
1026
1027 close(fd);
1028
1029 if (err != 0) {
1030 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1031 return err;
1032 }
1033
1034 static const unsigned char correct_data[] = {
1035 // header
1036 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001037 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001038
1039 // bytes_of_padding
1040 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001041 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1042 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1043 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1044 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001045
1046 // bytes_of_padding3
1047 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001048 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1049 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1050 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1051 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1052 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001053
Joe Onorato3ad977b2009-05-05 11:50:51 -07001054 // bytes of padding2
1055 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001056 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1057 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1058 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1059 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1060 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001061
Joe Onorato3ad977b2009-05-05 11:50:51 -07001062 // bytes of padding3
1063 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001064 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1065 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1066 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1067 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1068 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001069 };
1070
1071 err = compare_file(filename, correct_data, sizeof(correct_data));
1072 if (err != 0) {
1073 return err;
1074 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001075
Joe Onorato3ad977b2009-05-05 11:50:51 -07001076 // read
1077 fd = open(filename, O_RDONLY);
1078 if (fd == -1) {
1079 fprintf(stderr, "error opening for read %s\n", filename);
1080 return 1;
1081 }
1082
1083
1084 KeyedVector<String8,FileState> readSnapshot;
1085 err = read_snapshot_file(fd, &readSnapshot);
1086 if (err != 0) {
1087 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1088 return err;
1089 }
1090
1091 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001092 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001093 return 1;
1094 }
1095
1096 bool matched = true;
1097 for (size_t i=0; i<readSnapshot.size(); i++) {
1098 const String8& name = readSnapshot.keyAt(i);
1099 const FileState state = readSnapshot.valueAt(i);
1100
1101 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001102 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001103 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001104 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1105 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001106 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1107 states[i].crc32, name.length(), filenames[i].string(),
1108 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1109 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001110 matched = false;
1111 }
1112 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001113
Joe Onorato3ad977b2009-05-05 11:50:51 -07001114 return matched ? 0 : 1;
1115}
1116
Joe Onorato4535e402009-05-15 09:07:06 -04001117// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1118const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001119 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1120 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1121 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1122 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001123 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1124 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001125 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1126 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001127 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001128 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001129 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1130 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001131 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001132 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1133 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001134 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001135 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1136 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1137 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001138 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1139
Joe Onorato4535e402009-05-15 09:07:06 -04001140};
1141const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1142
1143static int
1144test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1145{
1146 int err;
1147 String8 text(str);
1148
Joe Onorato4535e402009-05-15 09:07:06 -04001149 err = writer.WriteEntityHeader(text, text.length()+1);
1150 if (err != 0) {
1151 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1152 return err;
1153 }
1154
1155 err = writer.WriteEntityData(text.string(), text.length()+1);
1156 if (err != 0) {
1157 fprintf(stderr, "write failed for data '%s'\n", text.string());
1158 return errno;
1159 }
1160
1161 return err;
1162}
1163
1164int
1165backup_helper_test_data_writer()
1166{
1167 int err;
1168 int fd;
1169 const char* filename = SCRATCH_DIR "data_writer.data";
1170
1171 system("rm -r " SCRATCH_DIR);
1172 mkdir(SCRATCH_DIR, 0777);
1173 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001174
Joe Onorato4535e402009-05-15 09:07:06 -04001175 fd = creat(filename, 0666);
1176 if (fd == -1) {
1177 fprintf(stderr, "error creating: %s\n", strerror(errno));
1178 return errno;
1179 }
1180
1181 BackupDataWriter writer(fd);
1182
1183 err = 0;
1184 err |= test_write_header_and_entity(writer, "no_padding_");
1185 err |= test_write_header_and_entity(writer, "padded_to__3");
1186 err |= test_write_header_and_entity(writer, "padded_to_2__");
1187 err |= test_write_header_and_entity(writer, "padded_to1");
1188
Joe Onorato4535e402009-05-15 09:07:06 -04001189 close(fd);
1190
1191 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1192 if (err != 0) {
1193 return err;
1194 }
1195
1196 return err;
1197}
1198
Joe Onorato2e1da322009-05-15 18:20:19 -04001199int
1200test_read_header_and_entity(BackupDataReader& reader, const char* str)
1201{
1202 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001203 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001204 char* buf = (char*)malloc(bufSize);
1205 String8 string;
1206 int cookie = 0x11111111;
1207 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001208 bool done;
1209 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001210 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001211
1212 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1213
Joe Onorato5f15d152009-06-16 16:31:35 -04001214 err = reader.ReadNextHeader(&done, &type);
1215 if (done) {
1216 fprintf(stderr, "should not be done yet\n");
1217 goto finished;
1218 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001219 if (err != 0) {
1220 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001221 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001222 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001223 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001224 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001225 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 }
1227
1228 err = reader.ReadEntityHeader(&string, &actualSize);
1229 if (err != 0) {
1230 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001231 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001232 }
1233 if (string != str) {
1234 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1235 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001236 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001237 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001238 if (actualSize != bufSize) {
1239 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1240 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001241 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001242 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001243 }
1244
Christopher Tate11b15772009-06-23 13:03:00 -07001245 nRead = reader.ReadEntityData(buf, bufSize);
1246 if (nRead < 0) {
1247 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001248 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001249 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001250 }
1251
1252 if (0 != memcmp(buf, str, bufSize)) {
1253 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001254 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1255 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001256 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001257 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001258 }
1259
1260 // The next read will confirm whether it got the right amount of data.
1261
Joe Onorato5f15d152009-06-16 16:31:35 -04001262finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001263 if (err != NO_ERROR) {
1264 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1265 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001266 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001267 return err;
1268}
1269
1270int
1271backup_helper_test_data_reader()
1272{
1273 int err;
1274 int fd;
1275 const char* filename = SCRATCH_DIR "data_reader.data";
1276
1277 system("rm -r " SCRATCH_DIR);
1278 mkdir(SCRATCH_DIR, 0777);
1279 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001280
Joe Onorato2e1da322009-05-15 18:20:19 -04001281 fd = creat(filename, 0666);
1282 if (fd == -1) {
1283 fprintf(stderr, "error creating: %s\n", strerror(errno));
1284 return errno;
1285 }
1286
1287 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1288 if (err != DATA_GOLDEN_FILE_SIZE) {
1289 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1290 return errno;
1291 }
1292
1293 close(fd);
1294
1295 fd = open(filename, O_RDONLY);
1296 if (fd == -1) {
1297 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1298 filename);
1299 return errno;
1300 }
1301
1302 {
1303 BackupDataReader reader(fd);
1304
1305 err = 0;
1306
1307 if (err == NO_ERROR) {
1308 err = test_read_header_and_entity(reader, "no_padding_");
1309 }
1310
1311 if (err == NO_ERROR) {
1312 err = test_read_header_and_entity(reader, "padded_to__3");
1313 }
1314
1315 if (err == NO_ERROR) {
1316 err = test_read_header_and_entity(reader, "padded_to_2__");
1317 }
1318
1319 if (err == NO_ERROR) {
1320 err = test_read_header_and_entity(reader, "padded_to1");
1321 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001322 }
1323
1324 close(fd);
1325
1326 return err;
1327}
1328
Joe Onorato3ad977b2009-05-05 11:50:51 -07001329static int
1330get_mod_time(const char* filename, struct timeval times[2])
1331{
1332 int err;
1333 struct stat64 st;
1334 err = stat64(filename, &st);
1335 if (err != 0) {
1336 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1337 return errno;
1338 }
1339 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001340 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001341
1342 // If st_atime is a macro then struct stat64 uses struct timespec
1343 // to store the access and modif time values and typically
1344 // st_*time_nsec is not defined. In glibc, this is controlled by
1345 // __USE_MISC.
1346#ifdef __USE_MISC
1347#if !defined(st_atime) || defined(st_atime_nsec)
1348#error "Check if this __USE_MISC conditional is still needed."
1349#endif
1350 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1351 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1352#else
1353 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001354 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001355#endif
1356
Joe Onorato3ad977b2009-05-05 11:50:51 -07001357 return 0;
1358}
1359
1360int
1361backup_helper_test_files()
1362{
1363 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001364 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001365 int dataStreamFD;
1366 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001367
1368 system("rm -r " SCRATCH_DIR);
1369 mkdir(SCRATCH_DIR, 0777);
1370 mkdir(SCRATCH_DIR "data", 0777);
1371
1372 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1373 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1374 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1375 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1376 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1377 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1378
1379 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001380 SCRATCH_DIR "data/b",
1381 SCRATCH_DIR "data/c",
1382 SCRATCH_DIR "data/d",
1383 SCRATCH_DIR "data/e",
1384 SCRATCH_DIR "data/f"
1385 };
1386
1387 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001388 "data/b",
1389 "data/c",
1390 "data/d",
1391 "data/e",
1392 "data/f"
1393 };
1394
Joe Onorato4535e402009-05-15 09:07:06 -04001395 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1396 if (dataStreamFD == -1) {
1397 fprintf(stderr, "error creating: %s\n", strerror(errno));
1398 return errno;
1399 }
1400
Joe Onorato3ad977b2009-05-05 11:50:51 -07001401 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1402 if (newSnapshotFD == -1) {
1403 fprintf(stderr, "error creating: %s\n", strerror(errno));
1404 return errno;
1405 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001406
1407 {
1408 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001409
Joe Onorato23ecae32009-06-10 17:07:15 -07001410 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001411 if (err != 0) {
1412 return err;
1413 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001414 }
1415
Joe Onorato4535e402009-05-15 09:07:06 -04001416 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001417 close(newSnapshotFD);
1418
1419 sleep(3);
1420
1421 struct timeval d_times[2];
1422 struct timeval e_times[2];
1423
1424 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1425 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1426 if (err != 0) {
1427 return err;
1428 }
1429
1430 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1431 unlink(SCRATCH_DIR "data/c");
1432 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1433 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1434 utimes(SCRATCH_DIR "data/d", d_times);
1435 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1436 utimes(SCRATCH_DIR "data/e", e_times);
1437 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1438 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001439
Joe Onorato3ad977b2009-05-05 11:50:51 -07001440 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001441 SCRATCH_DIR "data/a", // added
1442 SCRATCH_DIR "data/b", // same
1443 SCRATCH_DIR "data/c", // different mod time
1444 SCRATCH_DIR "data/d", // different size (same mod time)
1445 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1446 SCRATCH_DIR "data/g" // added
1447 };
1448
1449 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001450 "data/a", // added
1451 "data/b", // same
1452 "data/c", // different mod time
1453 "data/d", // different size (same mod time)
1454 "data/e", // different contents (same mod time, same size)
1455 "data/g" // added
1456 };
1457
1458 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1459 if (oldSnapshotFD == -1) {
1460 fprintf(stderr, "error opening: %s\n", strerror(errno));
1461 return errno;
1462 }
1463
Joe Onorato4535e402009-05-15 09:07:06 -04001464 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1465 if (dataStreamFD == -1) {
1466 fprintf(stderr, "error creating: %s\n", strerror(errno));
1467 return errno;
1468 }
1469
Joe Onorato3ad977b2009-05-05 11:50:51 -07001470 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1471 if (newSnapshotFD == -1) {
1472 fprintf(stderr, "error creating: %s\n", strerror(errno));
1473 return errno;
1474 }
1475
Joe Onoratod2110db2009-05-19 13:41:21 -07001476 {
1477 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001478
Joe Onorato23ecae32009-06-10 17:07:15 -07001479 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001480 if (err != 0) {
1481 return err;
1482 }
1483}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001484
1485 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001486 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001487 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001488
Joe Onorato3ad977b2009-05-05 11:50:51 -07001489 return 0;
1490}
1491
Joe Onorato23ecae32009-06-10 17:07:15 -07001492int
1493backup_helper_test_null_base()
1494{
1495 int err;
1496 int oldSnapshotFD;
1497 int dataStreamFD;
1498 int newSnapshotFD;
1499
1500 system("rm -r " SCRATCH_DIR);
1501 mkdir(SCRATCH_DIR, 0777);
1502 mkdir(SCRATCH_DIR "data", 0777);
1503
1504 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1505
1506 char const* files[] = {
1507 SCRATCH_DIR "data/a",
1508 };
1509
1510 char const* keys[] = {
1511 "a",
1512 };
1513
1514 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1515 if (dataStreamFD == -1) {
1516 fprintf(stderr, "error creating: %s\n", strerror(errno));
1517 return errno;
1518 }
1519
1520 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1521 if (newSnapshotFD == -1) {
1522 fprintf(stderr, "error creating: %s\n", strerror(errno));
1523 return errno;
1524 }
1525
1526 {
1527 BackupDataWriter dataStream(dataStreamFD);
1528
1529 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1530 if (err != 0) {
1531 return err;
1532 }
1533 }
1534
1535 close(dataStreamFD);
1536 close(newSnapshotFD);
1537
1538 return 0;
1539}
1540
Joe Onoratoce88cb12009-06-11 11:27:16 -07001541int
1542backup_helper_test_missing_file()
1543{
1544 int err;
1545 int oldSnapshotFD;
1546 int dataStreamFD;
1547 int newSnapshotFD;
1548
1549 system("rm -r " SCRATCH_DIR);
1550 mkdir(SCRATCH_DIR, 0777);
1551 mkdir(SCRATCH_DIR "data", 0777);
1552
1553 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1554
1555 char const* files[] = {
1556 SCRATCH_DIR "data/a",
1557 SCRATCH_DIR "data/b",
1558 SCRATCH_DIR "data/c",
1559 };
1560
1561 char const* keys[] = {
1562 "a",
1563 "b",
1564 "c",
1565 };
1566
1567 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1568 if (dataStreamFD == -1) {
1569 fprintf(stderr, "error creating: %s\n", strerror(errno));
1570 return errno;
1571 }
1572
1573 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1574 if (newSnapshotFD == -1) {
1575 fprintf(stderr, "error creating: %s\n", strerror(errno));
1576 return errno;
1577 }
1578
1579 {
1580 BackupDataWriter dataStream(dataStreamFD);
1581
1582 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1583 if (err != 0) {
1584 return err;
1585 }
1586 }
1587
1588 close(dataStreamFD);
1589 close(newSnapshotFD);
1590
1591 return 0;
1592}
1593
Joe Onorato23ecae32009-06-10 17:07:15 -07001594
Joe Onorato3ad977b2009-05-05 11:50:51 -07001595#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001596
1597}