blob: 8bfe2b6a259a4236f3aa220ba7edc80cfb9ab2db [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
Joe Onorato3ad977b2009-05-05 11:50:51 -070021#include <errno.h>
Mark Salyzyn52eb4e02016-09-28 16:15:30 -070022#include <fcntl.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070023#include <stdio.h>
24#include <stdlib.h>
Mark Salyzyn52eb4e02016-09-28 16:15:30 -070025#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/time.h> // for utimes
28#include <sys/uio.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070029#include <unistd.h>
Joe Onoratoc825d3e2009-05-06 12:55:46 -040030#include <utime.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070031#include <zlib.h>
32
Mark Salyzyn52eb4e02016-09-28 16:15:30 -070033#include <log/log.h>
34#include <utils/ByteOrder.h>
35#include <utils/KeyedVector.h>
36#include <utils/String8.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070037
Joe Onorato4535e402009-05-15 09:07:06 -040038namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070039
40#define MAGIC0 0x70616e53 // Snap
41#define MAGIC1 0x656c6946 // File
42
Christopher Tatefbb92382009-06-23 17:35:11 -070043/*
44 * File entity data format (v1):
45 *
46 * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
47 * - 12 bytes of metadata
48 * - the file data itself
49 *
50 * i.e. a 16-byte metadata header followed by the raw file data. If the
51 * restore code does not recognize the metadata version, it can still
52 * interpret the file data itself correctly.
53 *
54 * file_metadata_v1:
55 *
56 * - 4 byte version number === 0x00000001 (little endian)
57 * - 4-byte access mode (little-endian)
58 * - undefined (8 bytes)
59 */
60
61struct file_metadata_v1 {
62 int version;
63 int mode;
64 int undefined_1;
65 int undefined_2;
66};
67
68const static int CURRENT_METADATA_VERSION = 1;
69
Andreas Gampe2204f0b2014-10-21 23:04:54 -070070static const bool kIsDebug = false;
Joe Onorato568bc322009-06-26 17:19:11 -040071#if TEST_BACKUP_HELPERS
Andreas Gampe2204f0b2014-10-21 23:04:54 -070072#define LOGP(f, x...) if (kIsDebug) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040073#else
Andreas Gampe2204f0b2014-10-21 23:04:54 -070074#define LOGP(x...) if (kIsDebug) ALOGD(x)
Joe Onorato568bc322009-06-26 17:19:11 -040075#endif
Joe Onorato290bb012009-05-13 18:57:29 -040076
Joe Onorato3ad977b2009-05-05 11:50:51 -070077const static int ROUND_UP[4] = { 0, 3, 2, 1 };
78
79static inline int
80round_up(int n)
81{
82 return n + ROUND_UP[n % 4];
83}
84
85static int
86read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
87{
88 int bytesRead = 0;
89 int amt;
90 SnapshotHeader header;
91
92 amt = read(fd, &header, sizeof(header));
93 if (amt != sizeof(header)) {
94 return errno;
95 }
96 bytesRead += amt;
97
98 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
Steve Block8564c8d2012-01-05 23:22:43 +000099 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700100 return 1;
101 }
102
103 for (int i=0; i<header.fileCount; i++) {
104 FileState file;
105 char filenameBuf[128];
106
Joe Onorato23ecae32009-06-10 17:07:15 -0700107 amt = read(fd, &file, sizeof(FileState));
108 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000109 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700110 return 1;
111 }
112 bytesRead += amt;
113
114 // filename is not NULL terminated, but it is padded
115 int nameBufSize = round_up(file.nameLen);
116 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
117 ? filenameBuf
118 : (char*)malloc(nameBufSize);
119 amt = read(fd, filename, nameBufSize);
120 if (amt == nameBufSize) {
121 snapshot->add(String8(filename, file.nameLen), file);
122 }
123 bytesRead += amt;
124 if (filename != filenameBuf) {
125 free(filename);
126 }
127 if (amt != nameBufSize) {
Steve Block8564c8d2012-01-05 23:22:43 +0000128 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700129 return 1;
130 }
131 }
132
133 if (header.totalSize != bytesRead) {
Steve Block8564c8d2012-01-05 23:22:43 +0000134 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700135 header.totalSize, bytesRead);
136 return 1;
137 }
138
139 return 0;
140}
141
142static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700143write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700144{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700145 int fileCount = 0;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700146 int bytesWritten = sizeof(SnapshotHeader);
147 // preflight size
148 const int N = snapshot.size();
149 for (int i=0; i<N; i++) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700150 const FileRec& g = snapshot.valueAt(i);
151 if (!g.deleted) {
152 const String8& name = snapshot.keyAt(i);
153 bytesWritten += sizeof(FileState) + round_up(name.length());
154 fileCount++;
155 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700156 }
157
Joe Onorato4535e402009-05-15 09:07:06 -0400158 LOGP("write_snapshot_file fd=%d\n", fd);
159
Joe Onorato3ad977b2009-05-05 11:50:51 -0700160 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700161 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-05-05 11:50:51 -0700162
163 amt = write(fd, &header, sizeof(header));
164 if (amt != sizeof(header)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000165 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700166 return errno;
167 }
168
Joe Onoratoce88cb12009-06-11 11:27:16 -0700169 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700170 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700171 if (!r.deleted) {
172 const String8& name = snapshot.keyAt(i);
173 int nameLen = r.s.nameLen = name.length();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700174
Joe Onoratoce88cb12009-06-11 11:27:16 -0700175 amt = write(fd, &r.s, sizeof(FileState));
176 if (amt != sizeof(FileState)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000177 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700178 return 1;
179 }
Joe Onoratoce88cb12009-06-11 11:27:16 -0700180
181 // filename is not NULL terminated, but it is padded
182 amt = write(fd, name.string(), nameLen);
183 if (amt != nameLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000184 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
Joe Onoratoce88cb12009-06-11 11:27:16 -0700185 return 1;
186 }
187 int paddingLen = ROUND_UP[nameLen % 4];
188 if (paddingLen != 0) {
189 int padding = 0xabababab;
190 amt = write(fd, &padding, paddingLen);
191 if (amt != paddingLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000192 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s",
Joe Onoratoce88cb12009-06-11 11:27:16 -0700193 paddingLen, strerror(errno));
194 return 1;
195 }
196 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700197 }
198 }
199
200 return 0;
201}
202
203static int
Brian Carlstrom33d03922015-01-14 18:19:54 -0800204write_delete_file(BackupDataWriter* dataStream, const String8& key)
205{
206 LOGP("write_delete_file %s\n", key.string());
207 return dataStream->WriteEntityHeader(key, -1);
208}
209
210static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700211write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700212 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700213{
Christopher Tatefbb92382009-06-23 17:35:11 -0700214 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700215
216 const int bufsize = 4*1024;
217 int err;
218 int amt;
219 int fileSize;
220 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700221 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700222
223 char* buf = (char*)malloc(bufsize);
Joe Onoratod2110db2009-05-19 13:41:21 -0700224
Christopher Tatefbb92382009-06-23 17:35:11 -0700225 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700226 lseek(fd, 0, SEEK_SET);
227
Christopher Tatefbb92382009-06-23 17:35:11 -0700228 if (sizeof(metadata) != 16) {
Steve Block3762c312012-01-06 19:20:56 +0000229 ALOGE("ERROR: metadata block is the wrong size!");
Christopher Tatefbb92382009-06-23 17:35:11 -0700230 }
231
232 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700233 err = dataStream->WriteEntityHeader(key, bytesLeft);
234 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700235 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700236 return err;
237 }
238
Christopher Tatefbb92382009-06-23 17:35:11 -0700239 // store the file metadata first
240 metadata.version = tolel(CURRENT_METADATA_VERSION);
241 metadata.mode = tolel(mode);
242 metadata.undefined_1 = metadata.undefined_2 = 0;
243 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
244 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700245 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700246 return err;
247 }
248 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
249
250 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700251 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
252 bytesLeft -= amt;
253 if (bytesLeft < 0) {
254 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
255 }
256 err = dataStream->WriteEntityData(buf, amt);
257 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700258 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700259 return err;
260 }
261 }
262 if (bytesLeft != 0) {
263 if (bytesLeft > 0) {
264 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
265 // even though the data we're sending is probably bad.
266 memset(buf, 0, bufsize);
267 while (bytesLeft > 0) {
268 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
269 bytesLeft -= amt;
270 err = dataStream->WriteEntityData(buf, amt);
271 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700272 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700273 return err;
274 }
275 }
276 }
Steve Block3762c312012-01-06 19:20:56 +0000277 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700278 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700279 }
280
Christopher Tate63bcb792009-06-24 13:57:29 -0700281 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700282 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700283}
284
285static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700286write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700287{
288 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700289 struct stat st;
290
291 err = stat(realFilename, &st);
292 if (err < 0) {
293 return errno;
294 }
295
Joe Onorato23ecae32009-06-10 17:07:15 -0700296 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700297 if (fd == -1) {
298 return errno;
299 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700300
301 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700302 close(fd);
303 return err;
304}
305
306static int
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800307compute_crc32(const char* file, FileRec* out) {
308 int fd = open(file, O_RDONLY);
309 if (fd < 0) {
310 return -1;
311 }
312
Joe Onorato3ad977b2009-05-05 11:50:51 -0700313 const int bufsize = 4*1024;
314 int amt;
315
Joe Onorato3ad977b2009-05-05 11:50:51 -0700316 char* buf = (char*)malloc(bufsize);
317 int crc = crc32(0L, Z_NULL, 0);
318
Joe Onoratod2110db2009-05-19 13:41:21 -0700319 lseek(fd, 0, SEEK_SET);
320
Joe Onorato3ad977b2009-05-05 11:50:51 -0700321 while ((amt = read(fd, buf, bufsize)) != 0) {
322 crc = crc32(crc, (Bytef*)buf, amt);
323 }
324
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800325 close(fd);
Christopher Tate63bcb792009-06-24 13:57:29 -0700326 free(buf);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800327
328 out->s.crc32 = crc;
329 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700330}
331
332int
Joe Onoratod2110db2009-05-19 13:41:21 -0700333back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700334 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700335{
336 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700337 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700338 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700339
340 if (oldSnapshotFD != -1) {
341 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
342 if (err != 0) {
343 // On an error, treat this as a full backup.
344 oldSnapshot.clear();
345 }
346 }
347
348 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700349 String8 key(keys[i]);
350 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700351 char const* file = files[i];
352 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700353 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700354
Joe Onorato23ecae32009-06-10 17:07:15 -0700355 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700356 if (err != 0) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800357 // not found => treat as deleted
358 continue;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700359 } else {
360 r.deleted = false;
361 r.s.modTime_sec = st.st_mtime;
362 r.s.modTime_nsec = 0; // workaround sim breakage
363 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700364 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700365 r.s.size = st.st_size;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700366
Joe Onoratoce88cb12009-06-11 11:27:16 -0700367 if (newSnapshot.indexOfKey(key) >= 0) {
368 LOGP("back_up_files key already in use '%s'", key.string());
369 return -1;
370 }
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800371
372 // compute the CRC
373 if (compute_crc32(file, &r) != NO_ERROR) {
374 ALOGW("Unable to open file %s", file);
375 continue;
376 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700377 }
378 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700379 }
380
381 int n = 0;
382 int N = oldSnapshot.size();
383 int m = 0;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800384 int M = newSnapshot.size();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700385
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800386 while (n<N && m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700387 const String8& p = oldSnapshot.keyAt(n);
388 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700389 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700390 int cmp = p.compare(q);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800391 if (cmp < 0) {
392 // file present in oldSnapshot, but not present in newSnapshot
Joe Onoratoce88cb12009-06-11 11:27:16 -0700393 LOGP("file removed: %s", p.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800394 write_delete_file(dataStream, p);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700395 n++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800396 } else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700397 // file added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800398 LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700399 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700400 m++;
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800401 } else {
402 // same file exists in both old and new; check whether to update
Joe Onorato3ad977b2009-05-05 11:50:51 -0700403 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700404
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800405 LOGP("%s", q.string());
406 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
407 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
408 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
409 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
410 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
411 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
412 int fd = open(g.file.string(), O_RDONLY);
413 if (fd < 0) {
414 ALOGE("Unable to read file for backup: %s", g.file.string());
415 } else {
Christopher Tatefbb92382009-06-23 17:35:11 -0700416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800417 close(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700418 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700419 }
420 n++;
421 m++;
422 }
423 }
424
425 // these were deleted
426 while (n<N) {
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800427 write_delete_file(dataStream, oldSnapshot.keyAt(n));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700428 n++;
429 }
430
431 // these were added
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800432 while (m<M) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700433 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700434 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700435 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700436 m++;
437 }
438
439 err = write_snapshot_file(newSnapshotFD, newSnapshot);
440
441 return 0;
442}
443
George Burgess IVa346f542016-03-02 13:34:44 -0800444static void calc_tar_checksum(char* buf, size_t buf_size) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700445 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
446 memset(buf + 148, ' ', 8);
447
448 uint16_t sum = 0;
449 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
450 sum += *p;
451 }
452
453 // Now write the real checksum value:
454 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
George Burgess IVa346f542016-03-02 13:34:44 -0800455 snprintf(buf + 148, buf_size - 148, "%06o", sum); // the trailing space is
456 // already in place
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700457}
458
Christopher Tatedc92c822011-05-13 15:38:02 -0700459// Returns number of bytes written
George Burgess IVa346f542016-03-02 13:34:44 -0800460static int write_pax_header_entry(char* buf, size_t buf_size,
461 const char* key, const char* value) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700462 // start with the size of "1 key=value\n"
463 int len = strlen(key) + strlen(value) + 4;
464 if (len > 9) len++;
465 if (len > 99) len++;
466 if (len > 999) len++;
467 // since PATH_MAX is 4096 we don't expect to have to generate any single
468 // header entry longer than 9999 characters
469
George Burgess IVa346f542016-03-02 13:34:44 -0800470 return snprintf(buf, buf_size, "%d %s=%s\n", len, key, value);
Christopher Tatedc92c822011-05-13 15:38:02 -0700471}
472
Christopher Tate7926a692011-07-11 11:31:57 -0700473// Wire format to the backup manager service is chunked: each chunk is prefixed by
474// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
475void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
476 uint32_t chunk_size_no = htonl(size);
477 writer->WriteEntityData(&chunk_size_no, 4);
478 if (size != 0) writer->WriteEntityData(buffer, size);
479}
480
Christopher Tate4a627c72011-04-01 14:43:32 -0700481int write_tarfile(const String8& packageName, const String8& domain,
Christopher Tate11ae7682015-03-24 18:48:10 -0700482 const String8& rootpath, const String8& filepath, off_t* outSize,
483 BackupDataWriter* writer)
Christopher Tate4a627c72011-04-01 14:43:32 -0700484{
485 // In the output stream everything is stored relative to the root
486 const char* relstart = filepath.string() + rootpath.length();
487 if (*relstart == '/') relstart++; // won't be true when path == rootpath
488 String8 relpath(relstart);
489
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700490 // If relpath is empty, it means this is the top of one of the standard named
491 // domain directories, so we should just skip it
492 if (relpath.length() == 0) {
Christopher Tate11ae7682015-03-24 18:48:10 -0700493 *outSize = 0;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700494 return 0;
495 }
496
Christopher Tate4a627c72011-04-01 14:43:32 -0700497 // Too long a name for the ustar format?
498 // "apps/" + packagename + '/' + domainpath < 155 chars
499 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700500 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700501 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700502 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700503 }
504
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700505 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700506 if (!needExtended) {
507 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700508 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700509 needExtended = true;
510 break;
511 }
512 }
513 }
514
Christopher Tate4a627c72011-04-01 14:43:32 -0700515 int err = 0;
516 struct stat64 s;
517 if (lstat64(filepath.string(), &s) != 0) {
518 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000519 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700520 return err;
521 }
522
Christopher Tate11ae7682015-03-24 18:48:10 -0700523 // very large files need a pax extended size header
524 if (s.st_size > 077777777777LL) {
525 needExtended = true;
526 }
527
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700528 String8 fullname; // for pax later on
529 String8 prefix;
530
Christopher Tate4a627c72011-04-01 14:43:32 -0700531 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700532 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700533
Christopher Tate11ae7682015-03-24 18:48:10 -0700534 // Report the size, including a rough tar overhead estimation: 512 bytes for the
535 // overall tar file-block header, plus 2 blocks if using the pax extended format,
536 // plus the raw content size rounded up to a multiple of 512.
537 *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512);
538
539 // Measure case: we've returned the size; now return without moving data
540 if (!writer) return 0;
541
Christopher Tate4a627c72011-04-01 14:43:32 -0700542 // !!! TODO: use mmap when possible to avoid churning the buffer cache
543 // !!! TODO: this will break with symlinks; need to use readlink(2)
544 int fd = open(filepath.string(), O_RDONLY);
545 if (fd < 0) {
546 err = errno;
Steve Block3762c312012-01-06 19:20:56 +0000547 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700548 return err;
549 }
550
551 // read/write up to this much at a time.
552 const size_t BUFSIZE = 32 * 1024;
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800553 char* buf = (char *)calloc(1,BUFSIZE);
George Burgess IVa346f542016-03-02 13:34:44 -0800554 const size_t PAXHEADER_OFFSET = 512;
555 const size_t PAXHEADER_SIZE = 512;
556 const size_t PAXDATA_SIZE = BUFSIZE - (PAXHEADER_SIZE + PAXHEADER_OFFSET);
557 char* const paxHeader = buf + PAXHEADER_OFFSET; // use a different chunk of
558 // it as separate scratch
559 char* const paxData = paxHeader + PAXHEADER_SIZE;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700560
Christopher Tate4a627c72011-04-01 14:43:32 -0700561 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000562 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700563 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800564 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700565 }
566
Christopher Tate4a627c72011-04-01 14:43:32 -0700567 // Magic fields for the ustar file format
568 strcat(buf + 257, "ustar");
569 strcat(buf + 263, "00");
570
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700571 // [ 265 : 32 ] user name, ignored on restore
572 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700573
574 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700575 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700576
577 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
578 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700579 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
580 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700581
582 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700583 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700584
585 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800586 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700587
Christopher Tate4a627c72011-04-01 14:43:32 -0700588 // [ 156 : 1 ] link/file type
589 uint8_t type;
590 if (isdir) {
591 type = '5'; // tar magic: '5' == directory
592 } else if (S_ISREG(s.st_mode)) {
593 type = '0'; // tar magic: '0' == normal file
594 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000595 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
Christopher Tate4a627c72011-04-01 14:43:32 -0700596 goto cleanup;
597 }
598 buf[156] = type;
599
600 // [ 157 : 100 ] name of linked file [not implemented]
601
Christopher Tate4a627c72011-04-01 14:43:32 -0700602 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700603 // Prefix and main relative path. Path lengths have been preflighted.
604 if (packageName.length() > 0) {
605 prefix = "apps/";
606 prefix += packageName;
607 }
608 if (domain.length() > 0) {
609 prefix.appendPath(domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700610 }
611
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700612 // pax extended means we don't put in a prefix field, and put a different
613 // string in the basic name field. We can also construct the full path name
614 // out of the substrings we've now built.
615 fullname = prefix;
616 fullname.appendPath(relpath);
617
618 // ustar:
619 // [ 0 : 100 ]; file name/path
620 // [ 345 : 155 ] filename path prefix
621 // We only use the prefix area if fullname won't fit in the path
622 if (fullname.length() > 100) {
623 strncpy(buf, relpath.string(), 100);
624 strncpy(buf + 345, prefix.string(), 155);
625 } else {
626 strncpy(buf, fullname.string(), 100);
627 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700628 }
629
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700630 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
631
Steve Block6215d3f2012-01-04 20:05:49 +0000632 ALOGI(" Name: %s", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700633
634 // If we're using a pax extended header, build & write that here; lengths are
635 // already preflighted
636 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700637 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
Christopher Tatedc92c822011-05-13 15:38:02 -0700638
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700639 // construct the pax extended header data block
George Burgess IVa346f542016-03-02 13:34:44 -0800640 memset(paxData, 0, PAXDATA_SIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700641
642 // size header -- calc len in digits by actually rendering the number
643 // to a string - brute force but simple
George Burgess IVa346f542016-03-02 13:34:44 -0800644 int paxLen = 0;
Ashok Bhatf5df7002014-03-25 20:51:35 +0000645 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
George Burgess IVa346f542016-03-02 13:34:44 -0800646 paxLen += write_pax_header_entry(paxData, PAXDATA_SIZE, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700647
648 // fullname was generated above with the ustar paths
George Burgess IVa346f542016-03-02 13:34:44 -0800649 paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen,
650 "path", fullname.string());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700651
652 // Now we know how big the pax data is
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700653
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);
George Burgess IVa346f542016-03-02 13:34:44 -0800667 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)paxLen);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700668
669 // Checksum and write the pax block header
George Burgess IVa346f542016-03-02 13:34:44 -0800670 calc_tar_checksum(paxHeader, PAXHEADER_SIZE);
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
George Burgess IVa346f542016-03-02 13:34:44 -0800679 calc_tar_checksum(buf, BUFSIZE);
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;
Joe Onorato2e1da322009-05-15 18:20:19 -04001206 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001207 bool done;
1208 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001209 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001210
1211 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1212
Joe Onorato5f15d152009-06-16 16:31:35 -04001213 err = reader.ReadNextHeader(&done, &type);
1214 if (done) {
1215 fprintf(stderr, "should not be done yet\n");
1216 goto finished;
1217 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001218 if (err != 0) {
1219 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001220 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001221 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001222 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001223 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001224 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001225 }
1226
1227 err = reader.ReadEntityHeader(&string, &actualSize);
1228 if (err != 0) {
1229 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001230 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001231 }
1232 if (string != str) {
1233 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1234 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001235 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001236 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001237 if (actualSize != bufSize) {
1238 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1239 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001240 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001241 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001242 }
1243
Christopher Tate11b15772009-06-23 13:03:00 -07001244 nRead = reader.ReadEntityData(buf, bufSize);
1245 if (nRead < 0) {
1246 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001247 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001248 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001249 }
1250
1251 if (0 != memcmp(buf, str, bufSize)) {
1252 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001253 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1254 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001255 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001256 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001257 }
1258
1259 // The next read will confirm whether it got the right amount of data.
1260
Joe Onorato5f15d152009-06-16 16:31:35 -04001261finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001262 if (err != NO_ERROR) {
1263 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1264 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001265 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001266 return err;
1267}
1268
1269int
1270backup_helper_test_data_reader()
1271{
1272 int err;
1273 int fd;
1274 const char* filename = SCRATCH_DIR "data_reader.data";
1275
1276 system("rm -r " SCRATCH_DIR);
1277 mkdir(SCRATCH_DIR, 0777);
1278 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001279
Joe Onorato2e1da322009-05-15 18:20:19 -04001280 fd = creat(filename, 0666);
1281 if (fd == -1) {
1282 fprintf(stderr, "error creating: %s\n", strerror(errno));
1283 return errno;
1284 }
1285
1286 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1287 if (err != DATA_GOLDEN_FILE_SIZE) {
1288 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1289 return errno;
1290 }
1291
1292 close(fd);
1293
1294 fd = open(filename, O_RDONLY);
1295 if (fd == -1) {
1296 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1297 filename);
1298 return errno;
1299 }
1300
1301 {
1302 BackupDataReader reader(fd);
1303
1304 err = 0;
1305
1306 if (err == NO_ERROR) {
1307 err = test_read_header_and_entity(reader, "no_padding_");
1308 }
1309
1310 if (err == NO_ERROR) {
1311 err = test_read_header_and_entity(reader, "padded_to__3");
1312 }
1313
1314 if (err == NO_ERROR) {
1315 err = test_read_header_and_entity(reader, "padded_to_2__");
1316 }
1317
1318 if (err == NO_ERROR) {
1319 err = test_read_header_and_entity(reader, "padded_to1");
1320 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001321 }
1322
1323 close(fd);
1324
1325 return err;
1326}
1327
Joe Onorato3ad977b2009-05-05 11:50:51 -07001328static int
1329get_mod_time(const char* filename, struct timeval times[2])
1330{
1331 int err;
1332 struct stat64 st;
1333 err = stat64(filename, &st);
1334 if (err != 0) {
1335 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1336 return errno;
1337 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001338
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001339 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001340 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001341
1342 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001343 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001344
Joe Onorato3ad977b2009-05-05 11:50:51 -07001345 return 0;
1346}
1347
1348int
1349backup_helper_test_files()
1350{
1351 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001352 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001353 int dataStreamFD;
1354 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001355
1356 system("rm -r " SCRATCH_DIR);
1357 mkdir(SCRATCH_DIR, 0777);
1358 mkdir(SCRATCH_DIR "data", 0777);
1359
1360 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1361 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1362 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1363 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1364 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1365 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1366
1367 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001368 SCRATCH_DIR "data/b",
1369 SCRATCH_DIR "data/c",
1370 SCRATCH_DIR "data/d",
1371 SCRATCH_DIR "data/e",
1372 SCRATCH_DIR "data/f"
1373 };
1374
1375 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001376 "data/b",
1377 "data/c",
1378 "data/d",
1379 "data/e",
1380 "data/f"
1381 };
1382
Joe Onorato4535e402009-05-15 09:07:06 -04001383 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1384 if (dataStreamFD == -1) {
1385 fprintf(stderr, "error creating: %s\n", strerror(errno));
1386 return errno;
1387 }
1388
Joe Onorato3ad977b2009-05-05 11:50:51 -07001389 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1390 if (newSnapshotFD == -1) {
1391 fprintf(stderr, "error creating: %s\n", strerror(errno));
1392 return errno;
1393 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001394
1395 {
1396 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001397
Joe Onorato23ecae32009-06-10 17:07:15 -07001398 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001399 if (err != 0) {
1400 return err;
1401 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001402 }
1403
Joe Onorato4535e402009-05-15 09:07:06 -04001404 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001405 close(newSnapshotFD);
1406
1407 sleep(3);
1408
1409 struct timeval d_times[2];
1410 struct timeval e_times[2];
1411
1412 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1413 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1414 if (err != 0) {
1415 return err;
1416 }
1417
1418 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1419 unlink(SCRATCH_DIR "data/c");
1420 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1421 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1422 utimes(SCRATCH_DIR "data/d", d_times);
1423 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1424 utimes(SCRATCH_DIR "data/e", e_times);
1425 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1426 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001427
Joe Onorato3ad977b2009-05-05 11:50:51 -07001428 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001429 SCRATCH_DIR "data/a", // added
1430 SCRATCH_DIR "data/b", // same
1431 SCRATCH_DIR "data/c", // different mod time
1432 SCRATCH_DIR "data/d", // different size (same mod time)
1433 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1434 SCRATCH_DIR "data/g" // added
1435 };
1436
1437 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001438 "data/a", // added
1439 "data/b", // same
1440 "data/c", // different mod time
1441 "data/d", // different size (same mod time)
1442 "data/e", // different contents (same mod time, same size)
1443 "data/g" // added
1444 };
1445
1446 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1447 if (oldSnapshotFD == -1) {
1448 fprintf(stderr, "error opening: %s\n", strerror(errno));
1449 return errno;
1450 }
1451
Joe Onorato4535e402009-05-15 09:07:06 -04001452 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1453 if (dataStreamFD == -1) {
1454 fprintf(stderr, "error creating: %s\n", strerror(errno));
1455 return errno;
1456 }
1457
Joe Onorato3ad977b2009-05-05 11:50:51 -07001458 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1459 if (newSnapshotFD == -1) {
1460 fprintf(stderr, "error creating: %s\n", strerror(errno));
1461 return errno;
1462 }
1463
Joe Onoratod2110db2009-05-19 13:41:21 -07001464 {
1465 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001466
Joe Onorato23ecae32009-06-10 17:07:15 -07001467 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001468 if (err != 0) {
1469 return err;
1470 }
1471}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001472
1473 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001474 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001475 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001476
Joe Onorato3ad977b2009-05-05 11:50:51 -07001477 return 0;
1478}
1479
Joe Onorato23ecae32009-06-10 17:07:15 -07001480int
1481backup_helper_test_null_base()
1482{
1483 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001484 int dataStreamFD;
1485 int newSnapshotFD;
1486
1487 system("rm -r " SCRATCH_DIR);
1488 mkdir(SCRATCH_DIR, 0777);
1489 mkdir(SCRATCH_DIR "data", 0777);
1490
1491 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1492
1493 char const* files[] = {
1494 SCRATCH_DIR "data/a",
1495 };
1496
1497 char const* keys[] = {
1498 "a",
1499 };
1500
1501 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1502 if (dataStreamFD == -1) {
1503 fprintf(stderr, "error creating: %s\n", strerror(errno));
1504 return errno;
1505 }
1506
1507 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1508 if (newSnapshotFD == -1) {
1509 fprintf(stderr, "error creating: %s\n", strerror(errno));
1510 return errno;
1511 }
1512
1513 {
1514 BackupDataWriter dataStream(dataStreamFD);
1515
1516 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1517 if (err != 0) {
1518 return err;
1519 }
1520 }
1521
1522 close(dataStreamFD);
1523 close(newSnapshotFD);
1524
1525 return 0;
1526}
1527
Joe Onoratoce88cb12009-06-11 11:27:16 -07001528int
1529backup_helper_test_missing_file()
1530{
1531 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001532 int dataStreamFD;
1533 int newSnapshotFD;
1534
1535 system("rm -r " SCRATCH_DIR);
1536 mkdir(SCRATCH_DIR, 0777);
1537 mkdir(SCRATCH_DIR "data", 0777);
1538
1539 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1540
1541 char const* files[] = {
1542 SCRATCH_DIR "data/a",
1543 SCRATCH_DIR "data/b",
1544 SCRATCH_DIR "data/c",
1545 };
1546
1547 char const* keys[] = {
1548 "a",
1549 "b",
1550 "c",
1551 };
1552
1553 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1554 if (dataStreamFD == -1) {
1555 fprintf(stderr, "error creating: %s\n", strerror(errno));
1556 return errno;
1557 }
1558
1559 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1560 if (newSnapshotFD == -1) {
1561 fprintf(stderr, "error creating: %s\n", strerror(errno));
1562 return errno;
1563 }
1564
1565 {
1566 BackupDataWriter dataStream(dataStreamFD);
1567
1568 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1569 if (err != 0) {
1570 return err;
1571 }
1572 }
1573
1574 close(dataStreamFD);
1575 close(newSnapshotFD);
1576
1577 return 0;
1578}
1579
Joe Onorato23ecae32009-06-10 17:07:15 -07001580
Joe Onorato3ad977b2009-05-05 11:50:51 -07001581#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001582
1583}