blob: a1e7c2ffc1b129e10aa193c5e2eef9fb59843fde [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
Tomasz Wasilczyk804e8192023-08-23 02:22:53 +000033#include <androidfw/PathUtils.h>
Mark Salyzyn52eb4e02016-09-28 16:15:30 -070034#include <log/log.h>
35#include <utils/ByteOrder.h>
36#include <utils/KeyedVector.h>
37#include <utils/String8.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070038
Piyush Mehrotraa10db392024-01-09 20:15:16 +000039#include <com_android_server_backup.h>
40namespace backup_flags = com::android::server::backup;
41
Joe Onorato4535e402009-05-15 09:07:06 -040042namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070043
44#define MAGIC0 0x70616e53 // Snap
45#define MAGIC1 0x656c6946 // File
46
Christopher Tatefbb92382009-06-23 17:35:11 -070047/*
48 * File entity data format (v1):
49 *
50 * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
51 * - 12 bytes of metadata
52 * - the file data itself
53 *
54 * i.e. a 16-byte metadata header followed by the raw file data. If the
55 * restore code does not recognize the metadata version, it can still
56 * interpret the file data itself correctly.
57 *
58 * file_metadata_v1:
59 *
60 * - 4 byte version number === 0x00000001 (little endian)
61 * - 4-byte access mode (little-endian)
62 * - undefined (8 bytes)
63 */
64
65struct file_metadata_v1 {
66 int version;
67 int mode;
68 int undefined_1;
69 int undefined_2;
70};
71
72const static int CURRENT_METADATA_VERSION = 1;
73
Andreas Gampe2204f0b2014-10-21 23:04:54 -070074static const bool kIsDebug = false;
Joe Onorato568bc322009-06-26 17:19:11 -040075#if TEST_BACKUP_HELPERS
Andreas Gampe2204f0b2014-10-21 23:04:54 -070076#define LOGP(f, x...) if (kIsDebug) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040077#else
Andreas Gampe2204f0b2014-10-21 23:04:54 -070078#define LOGP(x...) if (kIsDebug) ALOGD(x)
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
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000186 amt = write(fd, name.c_str(), nameLen);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700187 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
Brian Carlstrom33d03922015-01-14 18:19:54 -0800208write_delete_file(BackupDataWriter* dataStream, const String8& key)
209{
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000210 LOGP("write_delete_file %s\n", key.c_str());
Brian Carlstrom33d03922015-01-14 18:19:54 -0800211 return dataStream->WriteEntityHeader(key, -1);
212}
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{
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.c_str(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700219
Piyush Mehrotraa10db392024-01-09 20:15:16 +0000220 const int bufsize = backup_flags::enable_max_size_writes_to_pipes() ? (64*1024) : (4*1024);
Joe Onoratod2110db2009-05-19 13:41:21 -0700221 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) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000372 LOGP("back_up_files key already in use '%s'", key.c_str());
Joe Onoratoce88cb12009-06-11 11:27:16 -0700373 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
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000397 LOGP("file removed: %s", p.c_str());
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
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000402 LOGP("file added: %s crc=0x%08x", g.file.c_str(), g.s.crc32);
403 write_update_file(dataStream, q, g.file.c_str());
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
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000409 LOGP("%s", q.c_str());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800410 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) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000416 int fd = open(g.file.c_str(), O_RDONLY);
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800417 if (fd < 0) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000418 ALOGE("Unable to read file for backup: %s", g.file.c_str());
Christopher Tate43a4a8c2015-01-08 18:42:33 -0800419 } else {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000420 write_update_file(dataStream, fd, g.s.mode, p, g.file.c_str());
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);
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000439 write_update_file(dataStream, q, g.file.c_str());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700440 m++;
441 }
442
443 err = write_snapshot_file(newSnapshotFD, newSnapshot);
444
445 return 0;
446}
447
George Burgess IVa346f542016-03-02 13:34:44 -0800448static void calc_tar_checksum(char* buf, size_t buf_size) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700449 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
450 memset(buf + 148, ' ', 8);
451
452 uint16_t sum = 0;
453 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
454 sum += *p;
455 }
456
457 // Now write the real checksum value:
458 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
George Burgess IVa346f542016-03-02 13:34:44 -0800459 snprintf(buf + 148, buf_size - 148, "%06o", sum); // the trailing space is
460 // already in place
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700461}
462
Christopher Tatedc92c822011-05-13 15:38:02 -0700463// Returns number of bytes written
George Burgess IVa346f542016-03-02 13:34:44 -0800464static int write_pax_header_entry(char* buf, size_t buf_size,
465 const char* key, const char* value) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700466 // start with the size of "1 key=value\n"
467 int len = strlen(key) + strlen(value) + 4;
468 if (len > 9) len++;
469 if (len > 99) len++;
470 if (len > 999) len++;
471 // since PATH_MAX is 4096 we don't expect to have to generate any single
472 // header entry longer than 9999 characters
473
George Burgess IVa346f542016-03-02 13:34:44 -0800474 return snprintf(buf, buf_size, "%d %s=%s\n", len, key, value);
Christopher Tatedc92c822011-05-13 15:38:02 -0700475}
476
Christopher Tate7926a692011-07-11 11:31:57 -0700477// Wire format to the backup manager service is chunked: each chunk is prefixed by
478// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
479void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
480 uint32_t chunk_size_no = htonl(size);
481 writer->WriteEntityData(&chunk_size_no, 4);
482 if (size != 0) writer->WriteEntityData(buffer, size);
483}
484
Christopher Tate4a627c72011-04-01 14:43:32 -0700485int write_tarfile(const String8& packageName, const String8& domain,
Abhinav Aggarwal0c36a942020-06-02 13:47:35 +0100486 const String8& rootpath, const String8& filepath, off64_t* outSize,
Christopher Tate11ae7682015-03-24 18:48:10 -0700487 BackupDataWriter* writer)
Christopher Tate4a627c72011-04-01 14:43:32 -0700488{
489 // In the output stream everything is stored relative to the root
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000490 const char* relstart = filepath.c_str() + rootpath.length();
Christopher Tate4a627c72011-04-01 14:43:32 -0700491 if (*relstart == '/') relstart++; // won't be true when path == rootpath
492 String8 relpath(relstart);
493
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700494 // If relpath is empty, it means this is the top of one of the standard named
495 // domain directories, so we should just skip it
496 if (relpath.length() == 0) {
Christopher Tate11ae7682015-03-24 18:48:10 -0700497 *outSize = 0;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700498 return 0;
499 }
500
Christopher Tate4a627c72011-04-01 14:43:32 -0700501 // Too long a name for the ustar format?
502 // "apps/" + packagename + '/' + domainpath < 155 chars
503 // relpath < 100 chars
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700504 bool needExtended = false;
Christopher Tate4a627c72011-04-01 14:43:32 -0700505 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700506 needExtended = true;
Christopher Tate4a627c72011-04-01 14:43:32 -0700507 }
508
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700509 // Non-7bit-clean path also means needing pax extended format
Christopher Tate75a99702011-05-18 16:28:19 -0700510 if (!needExtended) {
511 for (size_t i = 0; i < filepath.length(); i++) {
Christopher Tate3f6c77b2011-06-07 13:17:17 -0700512 if ((filepath[i] & 0x80) != 0) {
Christopher Tate75a99702011-05-18 16:28:19 -0700513 needExtended = true;
514 break;
515 }
516 }
517 }
518
Christopher Tate4a627c72011-04-01 14:43:32 -0700519 int err = 0;
520 struct stat64 s;
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000521 if (lstat64(filepath.c_str(), &s) != 0) {
Christopher Tate4a627c72011-04-01 14:43:32 -0700522 err = errno;
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000523 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.c_str());
Christopher Tate4a627c72011-04-01 14:43:32 -0700524 return err;
525 }
526
Christopher Tate11ae7682015-03-24 18:48:10 -0700527 // very large files need a pax extended size header
528 if (s.st_size > 077777777777LL) {
529 needExtended = true;
530 }
531
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700532 String8 fullname; // for pax later on
533 String8 prefix;
534
Christopher Tate4a627c72011-04-01 14:43:32 -0700535 const int isdir = S_ISDIR(s.st_mode);
Christopher Tatee9e78ec2011-06-08 20:09:31 -0700536 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
Christopher Tate4a627c72011-04-01 14:43:32 -0700537
Christopher Tate11ae7682015-03-24 18:48:10 -0700538 // Report the size, including a rough tar overhead estimation: 512 bytes for the
539 // overall tar file-block header, plus 2 blocks if using the pax extended format,
540 // plus the raw content size rounded up to a multiple of 512.
541 *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512);
542
543 // Measure case: we've returned the size; now return without moving data
544 if (!writer) return 0;
545
Christopher Tate4a627c72011-04-01 14:43:32 -0700546 // !!! TODO: use mmap when possible to avoid churning the buffer cache
547 // !!! TODO: this will break with symlinks; need to use readlink(2)
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000548 int fd = open(filepath.c_str(), O_RDONLY);
Christopher Tate4a627c72011-04-01 14:43:32 -0700549 if (fd < 0) {
550 err = errno;
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000551 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.c_str());
Christopher Tate4a627c72011-04-01 14:43:32 -0700552 return err;
553 }
554
555 // read/write up to this much at a time.
Piyush Mehrotraa10db392024-01-09 20:15:16 +0000556 const size_t BUFSIZE = backup_flags::enable_max_size_writes_to_pipes() ? (64*1024) : (32*1024);
557
Iliyan Malchev7e1d3952012-02-17 12:15:58 -0800558 char* buf = (char *)calloc(1,BUFSIZE);
George Burgess IVa346f542016-03-02 13:34:44 -0800559 const size_t PAXHEADER_OFFSET = 512;
560 const size_t PAXHEADER_SIZE = 512;
561 const size_t PAXDATA_SIZE = BUFSIZE - (PAXHEADER_SIZE + PAXHEADER_OFFSET);
562 char* const paxHeader = buf + PAXHEADER_OFFSET; // use a different chunk of
563 // it as separate scratch
564 char* const paxData = paxHeader + PAXHEADER_SIZE;
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700565
Christopher Tate4a627c72011-04-01 14:43:32 -0700566 if (buf == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000567 ALOGE("Out of mem allocating transfer buffer");
Christopher Tate4a627c72011-04-01 14:43:32 -0700568 err = ENOMEM;
Christopher Tate294b5122013-02-19 14:08:59 -0800569 goto done;
Christopher Tate4a627c72011-04-01 14:43:32 -0700570 }
571
Christopher Tate4a627c72011-04-01 14:43:32 -0700572 // Magic fields for the ustar file format
573 strcat(buf + 257, "ustar");
574 strcat(buf + 263, "00");
575
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700576 // [ 265 : 32 ] user name, ignored on restore
577 // [ 297 : 32 ] group name, ignored on restore
Christopher Tate4a627c72011-04-01 14:43:32 -0700578
579 // [ 100 : 8 ] file mode
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700580 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
Christopher Tate4a627c72011-04-01 14:43:32 -0700581
582 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
583 // [ 116 : 8 ] gid -- ignored in Android format
Mark Salyzyn00adb862014-03-19 11:00:06 -0700584 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
585 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
Christopher Tate4a627c72011-04-01 14:43:32 -0700586
587 // [ 124 : 12 ] file size in bytes
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700588 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
Christopher Tate4a627c72011-04-01 14:43:32 -0700589
590 // [ 136 : 12 ] last mod time as a UTC time_t
Andreas Gampe25df5fb2014-11-07 22:24:57 -0800591 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
Christopher Tate4a627c72011-04-01 14:43:32 -0700592
Christopher Tate4a627c72011-04-01 14:43:32 -0700593 // [ 156 : 1 ] link/file type
594 uint8_t type;
595 if (isdir) {
596 type = '5'; // tar magic: '5' == directory
597 } else if (S_ISREG(s.st_mode)) {
598 type = '0'; // tar magic: '0' == normal file
599 } else {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000600 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.c_str());
Christopher Tate4a627c72011-04-01 14:43:32 -0700601 goto cleanup;
602 }
603 buf[156] = type;
604
605 // [ 157 : 100 ] name of linked file [not implemented]
606
Christopher Tate4a627c72011-04-01 14:43:32 -0700607 {
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700608 // Prefix and main relative path. Path lengths have been preflighted.
609 if (packageName.length() > 0) {
610 prefix = "apps/";
611 prefix += packageName;
612 }
613 if (domain.length() > 0) {
Tomasz Wasilczyk804e8192023-08-23 02:22:53 +0000614 appendPath(prefix, domain);
Christopher Tate4a627c72011-04-01 14:43:32 -0700615 }
616
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700617 // pax extended means we don't put in a prefix field, and put a different
618 // string in the basic name field. We can also construct the full path name
619 // out of the substrings we've now built.
620 fullname = prefix;
Tomasz Wasilczyk804e8192023-08-23 02:22:53 +0000621 appendPath(fullname, relpath);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700622
623 // ustar:
624 // [ 0 : 100 ]; file name/path
625 // [ 345 : 155 ] filename path prefix
626 // We only use the prefix area if fullname won't fit in the path
627 if (fullname.length() > 100) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000628 strncpy(buf, relpath.c_str(), 100);
629 strncpy(buf + 345, prefix.c_str(), 155);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700630 } else {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000631 strncpy(buf, fullname.c_str(), 100);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700632 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700633 }
634
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700635 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
636
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000637 ALOGI(" Name: %s", fullname.c_str());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700638
639 // If we're using a pax extended header, build & write that here; lengths are
640 // already preflighted
641 if (needExtended) {
Christopher Tatedc92c822011-05-13 15:38:02 -0700642 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
Christopher Tatedc92c822011-05-13 15:38:02 -0700643
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700644 // construct the pax extended header data block
George Burgess IVa346f542016-03-02 13:34:44 -0800645 memset(paxData, 0, PAXDATA_SIZE);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700646
647 // size header -- calc len in digits by actually rendering the number
648 // to a string - brute force but simple
George Burgess IVa346f542016-03-02 13:34:44 -0800649 int paxLen = 0;
Ashok Bhatf5df7002014-03-25 20:51:35 +0000650 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
George Burgess IVa346f542016-03-02 13:34:44 -0800651 paxLen += write_pax_header_entry(paxData, PAXDATA_SIZE, "size", sizeStr);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700652
653 // fullname was generated above with the ustar paths
George Burgess IVa346f542016-03-02 13:34:44 -0800654 paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen,
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000655 "path", fullname.c_str());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700656
657 // Now we know how big the pax data is
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700658
659 // Now build the pax *header* templated on the ustar header
660 memcpy(paxHeader, buf, 512);
661
Tomasz Wasilczyk804e8192023-08-23 02:22:53 +0000662 String8 leaf = getPathLeaf(fullname);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700663 memset(paxHeader, 0, 100); // rewrite the name area
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000664 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700665 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000666 strncpy(paxHeader + 345, prefix.c_str(), 155);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700667
668 paxHeader[156] = 'x'; // mark it as a pax extended header
669
670 // [ 124 : 12 ] size of pax extended header data
671 memset(paxHeader + 124, 0, 12);
George Burgess IVa346f542016-03-02 13:34:44 -0800672 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)paxLen);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700673
674 // Checksum and write the pax block header
George Burgess IVa346f542016-03-02 13:34:44 -0800675 calc_tar_checksum(paxHeader, PAXHEADER_SIZE);
Christopher Tate7926a692011-07-11 11:31:57 -0700676 send_tarfile_chunk(writer, paxHeader, 512);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700677
678 // Now write the pax data itself
679 int paxblocks = (paxLen + 511) / 512;
Christopher Tate7926a692011-07-11 11:31:57 -0700680 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
Christopher Tate83a7cdc52011-05-12 17:47:12 -0700681 }
682
683 // Checksum and write the 512-byte ustar file header block to the output
George Burgess IVa346f542016-03-02 13:34:44 -0800684 calc_tar_checksum(buf, BUFSIZE);
Christopher Tate7926a692011-07-11 11:31:57 -0700685 send_tarfile_chunk(writer, buf, 512);
Christopher Tate4a627c72011-04-01 14:43:32 -0700686
687 // Now write the file data itself, for real files. We honor tar's convention that
688 // only full 512-byte blocks are sent to write().
689 if (!isdir) {
690 off64_t toWrite = s.st_size;
691 while (toWrite > 0) {
Ashok Bhatf5df7002014-03-25 20:51:35 +0000692 size_t toRead = toWrite;
693 if (toRead > BUFSIZE) {
694 toRead = BUFSIZE;
695 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700696 ssize_t nRead = read(fd, buf, toRead);
697 if (nRead < 0) {
698 err = errno;
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000699 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.c_str(),
Christopher Tate4a627c72011-04-01 14:43:32 -0700700 err, strerror(err));
701 break;
702 } else if (nRead == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000703 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000704 filepath.c_str());
Christopher Tate4a627c72011-04-01 14:43:32 -0700705 err = EIO;
706 break;
707 }
708
709 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
710 // depends on the OS guarantee that for ordinary files, read() will never return
711 // less than the number of bytes requested.
712 ssize_t partial = (nRead+512) % 512;
713 if (partial > 0) {
714 ssize_t remainder = 512 - partial;
715 memset(buf + nRead, 0, remainder);
716 nRead += remainder;
717 }
Christopher Tate7926a692011-07-11 11:31:57 -0700718 send_tarfile_chunk(writer, buf, nRead);
Christopher Tate4a627c72011-04-01 14:43:32 -0700719 toWrite -= nRead;
720 }
721 }
722
723cleanup:
You Kim8b2e2c82012-12-17 03:36:10 +0900724 free(buf);
Christopher Tate4a627c72011-04-01 14:43:32 -0700725done:
726 close(fd);
727 return err;
728}
729// end tarfile
730
731
732
Piyush Mehrotraa10db392024-01-09 20:15:16 +0000733const size_t RESTORE_BUF_SIZE = backup_flags::enable_max_size_writes_to_pipes() ? 64*1024 : 8*1024;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700734
735RestoreHelperBase::RestoreHelperBase()
736{
737 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700738 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700739}
740
741RestoreHelperBase::~RestoreHelperBase()
742{
743 free(m_buf);
744}
745
746status_t
747RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
748{
749 ssize_t err;
750 size_t dataSize;
751 String8 key;
752 int fd;
753 void* buf = m_buf;
754 ssize_t amt;
755 int mode;
756 int crc;
757 struct stat st;
758 FileRec r;
759
760 err = in->ReadEntityHeader(&key, &dataSize);
761 if (err != NO_ERROR) {
762 return err;
763 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700764
Christopher Tatefbb92382009-06-23 17:35:11 -0700765 // Get the metadata block off the head of the file entity and use that to
766 // set up the output file
767 file_metadata_v1 metadata;
768 amt = in->ReadEntityData(&metadata, sizeof(metadata));
769 if (amt != sizeof(metadata)) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000770 ALOGW("Could not read metadata for %s -- %ld / %s", filename.c_str(),
Christopher Tatefbb92382009-06-23 17:35:11 -0700771 (long)amt, strerror(errno));
772 return EIO;
773 }
774 metadata.version = fromlel(metadata.version);
775 metadata.mode = fromlel(metadata.mode);
776 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700777 if (!m_loggedUnknownMetadata) {
778 m_loggedUnknownMetadata = true;
Steve Block8564c8d2012-01-05 23:22:43 +0000779 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
Christopher Tate63bcb792009-06-24 13:57:29 -0700780 metadata.version, CURRENT_METADATA_VERSION);
781 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700782 }
783 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700784
785 // Write the file and compute the crc
786 crc = crc32(0L, Z_NULL, 0);
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000787 fd = open(filename.c_str(), O_CREAT|O_RDWR|O_TRUNC, mode);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700788 if (fd == -1) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000789 ALOGW("Could not open file %s -- %s", filename.c_str(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700790 return errno;
791 }
Mark Salyzyn00adb862014-03-19 11:00:06 -0700792
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700793 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
794 err = write(fd, buf, amt);
795 if (err != amt) {
796 close(fd);
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000797 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.c_str());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700798 return errno;
799 }
800 crc = crc32(crc, (Bytef*)buf, amt);
801 }
802
803 close(fd);
804
805 // Record for the snapshot
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000806 err = stat(filename.c_str(), &st);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700807 if (err != 0) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +0000808 ALOGW("Error stating file that we just created %s", filename.c_str());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700809 return errno;
810 }
811
812 r.file = filename;
813 r.deleted = false;
814 r.s.modTime_sec = st.st_mtime;
815 r.s.modTime_nsec = 0; // workaround sim breakage
816 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700817 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700818 r.s.size = st.st_size;
819 r.s.crc32 = crc;
820
821 m_files.add(key, r);
822
823 return NO_ERROR;
824}
825
826status_t
827RestoreHelperBase::WriteSnapshot(int fd)
828{
829 return write_snapshot_file(fd, m_files);;
830}
831
Joe Onorato3ad977b2009-05-05 11:50:51 -0700832#if TEST_BACKUP_HELPERS
833
834#define SCRATCH_DIR "/data/backup_helper_test/"
835
836static int
837write_text_file(const char* path, const char* data)
838{
839 int amt;
840 int fd;
841 int len;
842
843 fd = creat(path, 0666);
844 if (fd == -1) {
845 fprintf(stderr, "creat %s failed\n", path);
846 return errno;
847 }
848
849 len = strlen(data);
850 amt = write(fd, data, len);
851 if (amt != len) {
852 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
853 return errno;
854 }
855
856 close(fd);
857
858 return 0;
859}
860
861static int
862compare_file(const char* path, const unsigned char* data, int len)
863{
864 int fd;
865 int amt;
866
867 fd = open(path, O_RDONLY);
868 if (fd == -1) {
869 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
870 return errno;
871 }
872
873 unsigned char* contents = (unsigned char*)malloc(len);
874 if (contents == NULL) {
875 fprintf(stderr, "malloc(%d) failed\n", len);
876 return ENOMEM;
877 }
878
879 bool sizesMatch = true;
880 amt = lseek(fd, 0, SEEK_END);
881 if (amt != len) {
882 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
883 sizesMatch = false;
884 }
885 lseek(fd, 0, SEEK_SET);
886
887 int readLen = amt < len ? amt : len;
888 amt = read(fd, contents, readLen);
889 if (amt != readLen) {
890 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
891 }
892
893 bool contentsMatch = true;
894 for (int i=0; i<readLen; i++) {
895 if (data[i] != contents[i]) {
896 if (contentsMatch) {
897 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
898 contentsMatch = false;
899 }
900 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
901 }
902 }
903
Christopher Tate63bcb792009-06-24 13:57:29 -0700904 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700905 return contentsMatch && sizesMatch ? 0 : 1;
906}
907
908int
909backup_helper_test_empty()
910{
911 int err;
912 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700913 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700914 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
915
916 system("rm -r " SCRATCH_DIR);
917 mkdir(SCRATCH_DIR, 0777);
918
919 // write
920 fd = creat(filename, 0666);
921 if (fd == -1) {
922 fprintf(stderr, "error creating %s\n", filename);
923 return 1;
924 }
925
926 err = write_snapshot_file(fd, snapshot);
927
928 close(fd);
929
930 if (err != 0) {
931 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
932 return err;
933 }
934
935 static const unsigned char correct_data[] = {
936 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
937 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
938 };
939
940 err = compare_file(filename, correct_data, sizeof(correct_data));
941 if (err != 0) {
942 return err;
943 }
944
945 // read
946 fd = open(filename, O_RDONLY);
947 if (fd == -1) {
948 fprintf(stderr, "error opening for read %s\n", filename);
949 return 1;
950 }
951
952 KeyedVector<String8,FileState> readSnapshot;
953 err = read_snapshot_file(fd, &readSnapshot);
954 if (err != 0) {
955 fprintf(stderr, "read_snapshot_file failed %d\n", err);
956 return err;
957 }
958
959 if (readSnapshot.size() != 0) {
960 fprintf(stderr, "readSnapshot should be length 0\n");
961 return 1;
962 }
963
964 return 0;
965}
966
967int
968backup_helper_test_four()
969{
970 int err;
971 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700972 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700973 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
974
975 system("rm -r " SCRATCH_DIR);
976 mkdir(SCRATCH_DIR, 0777);
977
978 // write
979 fd = creat(filename, 0666);
980 if (fd == -1) {
981 fprintf(stderr, "error opening %s\n", filename);
982 return 1;
983 }
984
985 String8 filenames[4];
986 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700987 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700988 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700989
990 states[0].modTime_sec = 0xfedcba98;
991 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700992 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700993 states[0].size = 0xababbcbc;
994 states[0].crc32 = 0x12345678;
995 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700996 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700997 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700998 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700999
1000 states[1].modTime_sec = 0x93400031;
1001 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001002 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -07001003 states[1].size = 0x88557766;
1004 states[1].crc32 = 0x22334422;
1005 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -07001006 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001007 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -07001008 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001009
1010 states[2].modTime_sec = 0x33221144;
1011 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001012 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -07001013 states[2].size = 0x11223344;
1014 states[2].crc32 = 0x01122334;
1015 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001016 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001017 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -07001018 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001019
1020 states[3].modTime_sec = 0x33221144;
1021 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -07001022 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -07001023 states[3].size = 0x11223344;
1024 states[3].crc32 = 0x01122334;
1025 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -07001026 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -07001027 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -07001028 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001029
1030 err = write_snapshot_file(fd, snapshot);
1031
1032 close(fd);
1033
1034 if (err != 0) {
1035 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1036 return err;
1037 }
1038
1039 static const unsigned char correct_data[] = {
1040 // header
1041 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -07001042 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001043
1044 // bytes_of_padding
1045 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001046 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1047 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1048 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1049 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -07001050
1051 // bytes_of_padding3
1052 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001053 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1054 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1055 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1056 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1057 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001058
Joe Onorato3ad977b2009-05-05 11:50:51 -07001059 // bytes of padding2
1060 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001061 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1062 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1063 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1064 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1065 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001066
Joe Onorato3ad977b2009-05-05 11:50:51 -07001067 // bytes of padding3
1068 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -07001069 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1070 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1071 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1072 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1073 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -07001074 };
1075
1076 err = compare_file(filename, correct_data, sizeof(correct_data));
1077 if (err != 0) {
1078 return err;
1079 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001080
Joe Onorato3ad977b2009-05-05 11:50:51 -07001081 // read
1082 fd = open(filename, O_RDONLY);
1083 if (fd == -1) {
1084 fprintf(stderr, "error opening for read %s\n", filename);
1085 return 1;
1086 }
1087
1088
1089 KeyedVector<String8,FileState> readSnapshot;
1090 err = read_snapshot_file(fd, &readSnapshot);
1091 if (err != 0) {
1092 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1093 return err;
1094 }
1095
1096 if (readSnapshot.size() != 4) {
Kévin PETIT95ece352014-02-13 11:02:27 +00001097 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001098 return 1;
1099 }
1100
1101 bool matched = true;
1102 for (size_t i=0; i<readSnapshot.size(); i++) {
1103 const String8& name = readSnapshot.keyAt(i);
1104 const FileState state = readSnapshot.valueAt(i);
1105
1106 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -07001107 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -07001108 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Ashok Bhatf5df7002014-03-25 20:51:35 +00001109 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
1110 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
Christopher Tate11b15772009-06-23 13:03:00 -07001111 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +00001112 states[i].crc32, name.length(), filenames[i].c_str(),
Christopher Tate11b15772009-06-23 13:03:00 -07001113 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +00001114 state.nameLen, name.c_str());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001115 matched = false;
1116 }
1117 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001118
Joe Onorato3ad977b2009-05-05 11:50:51 -07001119 return matched ? 0 : 1;
1120}
1121
Joe Onorato4535e402009-05-15 09:07:06 -04001122// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1123const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001124 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1125 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1126 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1127 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001128 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1129 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001130 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1131 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001132 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001133 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001134 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1135 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001136 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001137 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1138 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001139 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001140 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1141 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1142 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001143 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1144
Joe Onorato4535e402009-05-15 09:07:06 -04001145};
1146const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1147
1148static int
1149test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1150{
1151 int err;
1152 String8 text(str);
1153
Joe Onorato4535e402009-05-15 09:07:06 -04001154 err = writer.WriteEntityHeader(text, text.length()+1);
1155 if (err != 0) {
1156 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1157 return err;
1158 }
1159
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +00001160 err = writer.WriteEntityData(text.c_str(), text.length()+1);
Joe Onorato4535e402009-05-15 09:07:06 -04001161 if (err != 0) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +00001162 fprintf(stderr, "write failed for data '%s'\n", text.c_str());
Joe Onorato4535e402009-05-15 09:07:06 -04001163 return errno;
1164 }
1165
1166 return err;
1167}
1168
1169int
1170backup_helper_test_data_writer()
1171{
1172 int err;
1173 int fd;
1174 const char* filename = SCRATCH_DIR "data_writer.data";
1175
1176 system("rm -r " SCRATCH_DIR);
1177 mkdir(SCRATCH_DIR, 0777);
1178 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001179
Joe Onorato4535e402009-05-15 09:07:06 -04001180 fd = creat(filename, 0666);
1181 if (fd == -1) {
1182 fprintf(stderr, "error creating: %s\n", strerror(errno));
1183 return errno;
1184 }
1185
1186 BackupDataWriter writer(fd);
1187
1188 err = 0;
1189 err |= test_write_header_and_entity(writer, "no_padding_");
1190 err |= test_write_header_and_entity(writer, "padded_to__3");
1191 err |= test_write_header_and_entity(writer, "padded_to_2__");
1192 err |= test_write_header_and_entity(writer, "padded_to1");
1193
Joe Onorato4535e402009-05-15 09:07:06 -04001194 close(fd);
1195
1196 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1197 if (err != 0) {
1198 return err;
1199 }
1200
1201 return err;
1202}
1203
Joe Onorato2e1da322009-05-15 18:20:19 -04001204int
1205test_read_header_and_entity(BackupDataReader& reader, const char* str)
1206{
1207 int err;
Ashok Bhatf5df7002014-03-25 20:51:35 +00001208 size_t bufSize = strlen(str)+1;
Joe Onorato2e1da322009-05-15 18:20:19 -04001209 char* buf = (char*)malloc(bufSize);
1210 String8 string;
Joe Onorato2e1da322009-05-15 18:20:19 -04001211 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001212 bool done;
1213 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001214 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001215
1216 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1217
Joe Onorato5f15d152009-06-16 16:31:35 -04001218 err = reader.ReadNextHeader(&done, &type);
1219 if (done) {
1220 fprintf(stderr, "should not be done yet\n");
1221 goto finished;
1222 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001223 if (err != 0) {
1224 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001225 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001226 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001227 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001228 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001229 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001230 }
1231
1232 err = reader.ReadEntityHeader(&string, &actualSize);
1233 if (err != 0) {
1234 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001235 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001236 }
1237 if (string != str) {
Tomasz Wasilczykd2a69832023-08-10 23:54:44 +00001238 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.c_str());
Joe Onorato2e1da322009-05-15 18:20:19 -04001239 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001240 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001241 }
Ashok Bhatf5df7002014-03-25 20:51:35 +00001242 if (actualSize != bufSize) {
1243 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1244 bufSize, actualSize);
Joe Onorato2e1da322009-05-15 18:20:19 -04001245 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001246 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001247 }
1248
Christopher Tate11b15772009-06-23 13:03:00 -07001249 nRead = reader.ReadEntityData(buf, bufSize);
1250 if (nRead < 0) {
1251 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001252 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001253 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001254 }
1255
1256 if (0 != memcmp(buf, str, bufSize)) {
1257 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001258 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1259 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001260 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001261 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001262 }
1263
1264 // The next read will confirm whether it got the right amount of data.
1265
Joe Onorato5f15d152009-06-16 16:31:35 -04001266finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001267 if (err != NO_ERROR) {
1268 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1269 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001270 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001271 return err;
1272}
1273
1274int
1275backup_helper_test_data_reader()
1276{
1277 int err;
1278 int fd;
1279 const char* filename = SCRATCH_DIR "data_reader.data";
1280
1281 system("rm -r " SCRATCH_DIR);
1282 mkdir(SCRATCH_DIR, 0777);
1283 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001284
Joe Onorato2e1da322009-05-15 18:20:19 -04001285 fd = creat(filename, 0666);
1286 if (fd == -1) {
1287 fprintf(stderr, "error creating: %s\n", strerror(errno));
1288 return errno;
1289 }
1290
1291 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1292 if (err != DATA_GOLDEN_FILE_SIZE) {
1293 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1294 return errno;
1295 }
1296
1297 close(fd);
1298
1299 fd = open(filename, O_RDONLY);
1300 if (fd == -1) {
1301 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1302 filename);
1303 return errno;
1304 }
1305
1306 {
1307 BackupDataReader reader(fd);
1308
1309 err = 0;
1310
1311 if (err == NO_ERROR) {
1312 err = test_read_header_and_entity(reader, "no_padding_");
1313 }
1314
1315 if (err == NO_ERROR) {
1316 err = test_read_header_and_entity(reader, "padded_to__3");
1317 }
1318
1319 if (err == NO_ERROR) {
1320 err = test_read_header_and_entity(reader, "padded_to_2__");
1321 }
1322
1323 if (err == NO_ERROR) {
1324 err = test_read_header_and_entity(reader, "padded_to1");
1325 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001326 }
1327
1328 close(fd);
1329
1330 return err;
1331}
1332
Joe Onorato3ad977b2009-05-05 11:50:51 -07001333static int
1334get_mod_time(const char* filename, struct timeval times[2])
1335{
1336 int err;
1337 struct stat64 st;
1338 err = stat64(filename, &st);
1339 if (err != 0) {
1340 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1341 return errno;
1342 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001343
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001344 times[0].tv_sec = st.st_atim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001345 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
Elliott Hughes4da9dc52014-11-10 10:48:25 -08001346
1347 times[1].tv_sec = st.st_mtim.tv_sec;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001348 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001349
Joe Onorato3ad977b2009-05-05 11:50:51 -07001350 return 0;
1351}
1352
1353int
1354backup_helper_test_files()
1355{
1356 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001357 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001358 int dataStreamFD;
1359 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001360
1361 system("rm -r " SCRATCH_DIR);
1362 mkdir(SCRATCH_DIR, 0777);
1363 mkdir(SCRATCH_DIR "data", 0777);
1364
1365 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1366 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1367 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1368 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1369 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1370 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1371
1372 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001373 SCRATCH_DIR "data/b",
1374 SCRATCH_DIR "data/c",
1375 SCRATCH_DIR "data/d",
1376 SCRATCH_DIR "data/e",
1377 SCRATCH_DIR "data/f"
1378 };
1379
1380 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001381 "data/b",
1382 "data/c",
1383 "data/d",
1384 "data/e",
1385 "data/f"
1386 };
1387
Joe Onorato4535e402009-05-15 09:07:06 -04001388 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1389 if (dataStreamFD == -1) {
1390 fprintf(stderr, "error creating: %s\n", strerror(errno));
1391 return errno;
1392 }
1393
Joe Onorato3ad977b2009-05-05 11:50:51 -07001394 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1395 if (newSnapshotFD == -1) {
1396 fprintf(stderr, "error creating: %s\n", strerror(errno));
1397 return errno;
1398 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001399
1400 {
1401 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001402
Joe Onorato23ecae32009-06-10 17:07:15 -07001403 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001404 if (err != 0) {
1405 return err;
1406 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001407 }
1408
Joe Onorato4535e402009-05-15 09:07:06 -04001409 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001410 close(newSnapshotFD);
1411
1412 sleep(3);
1413
1414 struct timeval d_times[2];
1415 struct timeval e_times[2];
1416
1417 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1418 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1419 if (err != 0) {
1420 return err;
1421 }
1422
1423 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1424 unlink(SCRATCH_DIR "data/c");
1425 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1426 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1427 utimes(SCRATCH_DIR "data/d", d_times);
1428 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1429 utimes(SCRATCH_DIR "data/e", e_times);
1430 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1431 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001432
Joe Onorato3ad977b2009-05-05 11:50:51 -07001433 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001434 SCRATCH_DIR "data/a", // added
1435 SCRATCH_DIR "data/b", // same
1436 SCRATCH_DIR "data/c", // different mod time
1437 SCRATCH_DIR "data/d", // different size (same mod time)
1438 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1439 SCRATCH_DIR "data/g" // added
1440 };
1441
1442 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001443 "data/a", // added
1444 "data/b", // same
1445 "data/c", // different mod time
1446 "data/d", // different size (same mod time)
1447 "data/e", // different contents (same mod time, same size)
1448 "data/g" // added
1449 };
1450
1451 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1452 if (oldSnapshotFD == -1) {
1453 fprintf(stderr, "error opening: %s\n", strerror(errno));
1454 return errno;
1455 }
1456
Joe Onorato4535e402009-05-15 09:07:06 -04001457 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1458 if (dataStreamFD == -1) {
1459 fprintf(stderr, "error creating: %s\n", strerror(errno));
1460 return errno;
1461 }
1462
Joe Onorato3ad977b2009-05-05 11:50:51 -07001463 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1464 if (newSnapshotFD == -1) {
1465 fprintf(stderr, "error creating: %s\n", strerror(errno));
1466 return errno;
1467 }
1468
Joe Onoratod2110db2009-05-19 13:41:21 -07001469 {
1470 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001471
Joe Onorato23ecae32009-06-10 17:07:15 -07001472 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001473 if (err != 0) {
1474 return err;
1475 }
1476}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001477
1478 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001479 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001480 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001481
Joe Onorato3ad977b2009-05-05 11:50:51 -07001482 return 0;
1483}
1484
Joe Onorato23ecae32009-06-10 17:07:15 -07001485int
1486backup_helper_test_null_base()
1487{
1488 int err;
Joe Onorato23ecae32009-06-10 17:07:15 -07001489 int dataStreamFD;
1490 int newSnapshotFD;
1491
1492 system("rm -r " SCRATCH_DIR);
1493 mkdir(SCRATCH_DIR, 0777);
1494 mkdir(SCRATCH_DIR "data", 0777);
1495
1496 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1497
1498 char const* files[] = {
1499 SCRATCH_DIR "data/a",
1500 };
1501
1502 char const* keys[] = {
1503 "a",
1504 };
1505
1506 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1507 if (dataStreamFD == -1) {
1508 fprintf(stderr, "error creating: %s\n", strerror(errno));
1509 return errno;
1510 }
1511
1512 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1513 if (newSnapshotFD == -1) {
1514 fprintf(stderr, "error creating: %s\n", strerror(errno));
1515 return errno;
1516 }
1517
1518 {
1519 BackupDataWriter dataStream(dataStreamFD);
1520
1521 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1522 if (err != 0) {
1523 return err;
1524 }
1525 }
1526
1527 close(dataStreamFD);
1528 close(newSnapshotFD);
1529
1530 return 0;
1531}
1532
Joe Onoratoce88cb12009-06-11 11:27:16 -07001533int
1534backup_helper_test_missing_file()
1535{
1536 int err;
Joe Onoratoce88cb12009-06-11 11:27:16 -07001537 int dataStreamFD;
1538 int newSnapshotFD;
1539
1540 system("rm -r " SCRATCH_DIR);
1541 mkdir(SCRATCH_DIR, 0777);
1542 mkdir(SCRATCH_DIR "data", 0777);
1543
1544 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1545
1546 char const* files[] = {
1547 SCRATCH_DIR "data/a",
1548 SCRATCH_DIR "data/b",
1549 SCRATCH_DIR "data/c",
1550 };
1551
1552 char const* keys[] = {
1553 "a",
1554 "b",
1555 "c",
1556 };
1557
1558 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1559 if (dataStreamFD == -1) {
1560 fprintf(stderr, "error creating: %s\n", strerror(errno));
1561 return errno;
1562 }
1563
1564 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1565 if (newSnapshotFD == -1) {
1566 fprintf(stderr, "error creating: %s\n", strerror(errno));
1567 return errno;
1568 }
1569
1570 {
1571 BackupDataWriter dataStream(dataStreamFD);
1572
1573 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1574 if (err != 0) {
1575 return err;
1576 }
1577 }
1578
1579 close(dataStreamFD);
1580 close(newSnapshotFD);
1581
1582 return 0;
1583}
1584
Joe Onorato23ecae32009-06-10 17:07:15 -07001585
Joe Onorato3ad977b2009-05-05 11:50:51 -07001586#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001587
1588}