1 /*
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
17 #define LOG_TAG "file_backup_helper"
18
19 #include <androidfw/BackupHelpers.h>
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/time.h> // for utimes
28 #include <sys/uio.h>
29 #include <unistd.h>
30 #include <utime.h>
31 #include <zlib.h>
32
33 #include <androidfw/PathUtils.h>
34 #include <log/log.h>
35 #include <utils/ByteOrder.h>
36 #include <utils/KeyedVector.h>
37 #include <utils/String8.h>
38
39 #include <com_android_server_backup.h>
40 namespace backup_flags = com::android::server::backup;
41
42 namespace android {
43
44 #define MAGIC0 0x70616e53 // Snap
45 #define MAGIC1 0x656c6946 // File
46
47 /*
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
65 struct file_metadata_v1 {
66 int version;
67 int mode;
68 int undefined_1;
69 int undefined_2;
70 };
71
72 const static int CURRENT_METADATA_VERSION = 1;
73
74 static const bool kIsDebug = false;
75 #if TEST_BACKUP_HELPERS
76 #define LOGP(f, x...) if (kIsDebug) printf(f "\n", x)
77 #else
78 #define LOGP(x...) if (kIsDebug) ALOGD(x)
79 #endif
80
81 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
82
83 static inline int
round_up(int n)84 round_up(int n)
85 {
86 return n + ROUND_UP[n % 4];
87 }
88
89 static int
read_snapshot_file(int fd,KeyedVector<String8,FileState> * snapshot)90 read_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) {
103 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
104 return 1;
105 }
106
107 for (int i=0; i<header.fileCount; i++) {
108 FileState file;
109 char filenameBuf[128];
110
111 amt = read(fd, &file, sizeof(FileState));
112 if (amt != sizeof(FileState)) {
113 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
114 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) {
132 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
133 return 1;
134 }
135 }
136
137 if (header.totalSize != bytesRead) {
138 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
139 header.totalSize, bytesRead);
140 return 1;
141 }
142
143 return 0;
144 }
145
146 static int
write_snapshot_file(int fd,const KeyedVector<String8,FileRec> & snapshot)147 write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
148 {
149 int fileCount = 0;
150 int bytesWritten = sizeof(SnapshotHeader);
151 // preflight size
152 const int N = snapshot.size();
153 for (int i=0; i<N; i++) {
154 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 }
160 }
161
162 LOGP("write_snapshot_file fd=%d\n", fd);
163
164 int amt;
165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
166
167 amt = write(fd, &header, sizeof(header));
168 if (amt != sizeof(header)) {
169 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
170 return errno;
171 }
172
173 for (int i=0; i<N; i++) {
174 FileRec r = snapshot.valueAt(i);
175 if (!r.deleted) {
176 const String8& name = snapshot.keyAt(i);
177 int nameLen = r.s.nameLen = name.length();
178
179 amt = write(fd, &r.s, sizeof(FileState));
180 if (amt != sizeof(FileState)) {
181 ALOGW("write_snapshot_file error writing header %s", strerror(errno));
182 return 1;
183 }
184
185 // filename is not NULL terminated, but it is padded
186 amt = write(fd, name.c_str(), nameLen);
187 if (amt != nameLen) {
188 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
189 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) {
196 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s",
197 paddingLen, strerror(errno));
198 return 1;
199 }
200 }
201 }
202 }
203
204 return 0;
205 }
206
207 static int
write_delete_file(BackupDataWriter * dataStream,const String8 & key)208 write_delete_file(BackupDataWriter* dataStream, const String8& key)
209 {
210 LOGP("write_delete_file %s\n", key.c_str());
211 return dataStream->WriteEntityHeader(key, -1);
212 }
213
214 static int
write_update_file(BackupDataWriter * dataStream,int fd,int mode,const String8 & key,char const * realFilename)215 write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
216 char const* realFilename)
217 {
218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.c_str(), mode);
219
220 const int bufsize = backup_flags::enable_max_size_writes_to_pipes() ? (64*1024) : (4*1024);
221 int err;
222 int amt;
223 int fileSize;
224 int bytesLeft;
225 file_metadata_v1 metadata;
226
227 char* buf = (char*)malloc(bufsize);
228
229 fileSize = lseek(fd, 0, SEEK_END);
230 lseek(fd, 0, SEEK_SET);
231
232 if (sizeof(metadata) != 16) {
233 ALOGE("ERROR: metadata block is the wrong size!");
234 }
235
236 bytesLeft = fileSize + sizeof(metadata);
237 err = dataStream->WriteEntityHeader(key, bytesLeft);
238 if (err != 0) {
239 free(buf);
240 return err;
241 }
242
243 // 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) {
249 free(buf);
250 return err;
251 }
252 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
253
254 // now store the file content
255 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) {
262 free(buf);
263 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) {
276 free(buf);
277 return err;
278 }
279 }
280 }
281 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
282 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
283 }
284
285 free(buf);
286 return NO_ERROR;
287 }
288
289 static int
write_update_file(BackupDataWriter * dataStream,const String8 & key,char const * realFilename)290 write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
291 {
292 int err;
293 struct stat st;
294
295 err = stat(realFilename, &st);
296 if (err < 0) {
297 return errno;
298 }
299
300 int fd = open(realFilename, O_RDONLY);
301 if (fd == -1) {
302 return errno;
303 }
304
305 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
306 close(fd);
307 return err;
308 }
309
310 static int
compute_crc32(const char * file,FileRec * out)311 compute_crc32(const char* file, FileRec* out) {
312 int fd = open(file, O_RDONLY);
313 if (fd < 0) {
314 return -1;
315 }
316
317 const int bufsize = 4*1024;
318 int amt;
319
320 char* buf = (char*)malloc(bufsize);
321 int crc = crc32(0L, Z_NULL, 0);
322
323 lseek(fd, 0, SEEK_SET);
324
325 while ((amt = read(fd, buf, bufsize)) != 0) {
326 crc = crc32(crc, (Bytef*)buf, amt);
327 }
328
329 close(fd);
330 free(buf);
331
332 out->s.crc32 = crc;
333 return NO_ERROR;
334 }
335
336 int
back_up_files(int oldSnapshotFD,BackupDataWriter * dataStream,int newSnapshotFD,char const * const * files,char const * const * keys,int fileCount)337 back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
338 char const* const* files, char const* const* keys, int fileCount)
339 {
340 int err;
341 KeyedVector<String8,FileState> oldSnapshot;
342 KeyedVector<String8,FileRec> newSnapshot;
343
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++) {
353 String8 key(keys[i]);
354 FileRec r;
355 char const* file = files[i];
356 r.file = file;
357 struct stat st;
358
359 err = stat(file, &st);
360 if (err != 0) {
361 // not found => treat as deleted
362 continue;
363 } 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;
368 r.s.mode = st.st_mode;
369 r.s.size = st.st_size;
370
371 if (newSnapshot.indexOfKey(key) >= 0) {
372 LOGP("back_up_files key already in use '%s'", key.c_str());
373 return -1;
374 }
375
376 // compute the CRC
377 if (compute_crc32(file, &r) != NO_ERROR) {
378 ALOGW("Unable to open file %s", file);
379 continue;
380 }
381 }
382 newSnapshot.add(key, r);
383 }
384
385 int n = 0;
386 int N = oldSnapshot.size();
387 int m = 0;
388 int M = newSnapshot.size();
389
390 while (n<N && m<M) {
391 const String8& p = oldSnapshot.keyAt(n);
392 const String8& q = newSnapshot.keyAt(m);
393 FileRec& g = newSnapshot.editValueAt(m);
394 int cmp = p.compare(q);
395 if (cmp < 0) {
396 // file present in oldSnapshot, but not present in newSnapshot
397 LOGP("file removed: %s", p.c_str());
398 write_delete_file(dataStream, p);
399 n++;
400 } else if (cmp > 0) {
401 // file added
402 LOGP("file added: %s crc=0x%08x", g.file.c_str(), g.s.crc32);
403 write_update_file(dataStream, q, g.file.c_str());
404 m++;
405 } else {
406 // same file exists in both old and new; check whether to update
407 const FileState& f = oldSnapshot.valueAt(n);
408
409 LOGP("%s", q.c_str());
410 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
411 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
412 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
413 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
416 int fd = open(g.file.c_str(), O_RDONLY);
417 if (fd < 0) {
418 ALOGE("Unable to read file for backup: %s", g.file.c_str());
419 } else {
420 write_update_file(dataStream, fd, g.s.mode, p, g.file.c_str());
421 close(fd);
422 }
423 }
424 n++;
425 m++;
426 }
427 }
428
429 // these were deleted
430 while (n<N) {
431 write_delete_file(dataStream, oldSnapshot.keyAt(n));
432 n++;
433 }
434
435 // these were added
436 while (m<M) {
437 const String8& q = newSnapshot.keyAt(m);
438 FileRec& g = newSnapshot.editValueAt(m);
439 write_update_file(dataStream, q, g.file.c_str());
440 m++;
441 }
442
443 err = write_snapshot_file(newSnapshotFD, newSnapshot);
444
445 return 0;
446 }
447
calc_tar_checksum(char * buf,size_t buf_size)448 static void calc_tar_checksum(char* buf, size_t buf_size) {
449 // [ 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
459 snprintf(buf + 148, buf_size - 148, "%06o", sum); // the trailing space is
460 // already in place
461 }
462
463 // Returns number of bytes written
write_pax_header_entry(char * buf,size_t buf_size,const char * key,const char * value)464 static int write_pax_header_entry(char* buf, size_t buf_size,
465 const char* key, const char* value) {
466 // 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
474 return snprintf(buf, buf_size, "%d %s=%s\n", len, key, value);
475 }
476
477 // 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.
send_tarfile_chunk(BackupDataWriter * writer,const char * buffer,size_t size)479 void 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
write_tarfile(const String8 & packageName,const String8 & domain,const String8 & rootpath,const String8 & filepath,off64_t * outSize,BackupDataWriter * writer)485 int write_tarfile(const String8& packageName, const String8& domain,
486 const String8& rootpath, const String8& filepath, off64_t* outSize,
487 BackupDataWriter* writer)
488 {
489 // In the output stream everything is stored relative to the root
490 const char* relstart = filepath.c_str() + rootpath.length();
491 if (*relstart == '/') relstart++; // won't be true when path == rootpath
492 String8 relpath(relstart);
493
494 // 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) {
497 *outSize = 0;
498 return 0;
499 }
500
501 // Too long a name for the ustar format?
502 // "apps/" + packagename + '/' + domainpath < 155 chars
503 // relpath < 100 chars
504 bool needExtended = false;
505 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
506 needExtended = true;
507 }
508
509 // Non-7bit-clean path also means needing pax extended format
510 if (!needExtended) {
511 for (size_t i = 0; i < filepath.length(); i++) {
512 if ((filepath[i] & 0x80) != 0) {
513 needExtended = true;
514 break;
515 }
516 }
517 }
518
519 int err = 0;
520 struct stat64 s;
521 if (lstat64(filepath.c_str(), &s) != 0) {
522 err = errno;
523 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.c_str());
524 return err;
525 }
526
527 // very large files need a pax extended size header
528 if (s.st_size > 077777777777LL) {
529 needExtended = true;
530 }
531
532 String8 fullname; // for pax later on
533 String8 prefix;
534
535 const int isdir = S_ISDIR(s.st_mode);
536 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream
537
538 // 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
546 // !!! TODO: use mmap when possible to avoid churning the buffer cache
547 // !!! TODO: this will break with symlinks; need to use readlink(2)
548 int fd = open(filepath.c_str(), O_RDONLY);
549 if (fd < 0) {
550 err = errno;
551 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.c_str());
552 return err;
553 }
554
555 // read/write up to this much at a time.
556 const size_t BUFSIZE = backup_flags::enable_max_size_writes_to_pipes() ? (64*1024) : (32*1024);
557
558 char* buf = (char *)calloc(1,BUFSIZE);
559 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;
565
566 if (buf == NULL) {
567 ALOGE("Out of mem allocating transfer buffer");
568 err = ENOMEM;
569 goto done;
570 }
571
572 // Magic fields for the ustar file format
573 strcat(buf + 257, "ustar");
574 strcat(buf + 263, "00");
575
576 // [ 265 : 32 ] user name, ignored on restore
577 // [ 297 : 32 ] group name, ignored on restore
578
579 // [ 100 : 8 ] file mode
580 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
581
582 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
583 // [ 116 : 8 ] gid -- ignored in Android format
584 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid);
585 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid);
586
587 // [ 124 : 12 ] file size in bytes
588 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
589
590 // [ 136 : 12 ] last mod time as a UTC time_t
591 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
592
593 // [ 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 {
600 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.c_str());
601 goto cleanup;
602 }
603 buf[156] = type;
604
605 // [ 157 : 100 ] name of linked file [not implemented]
606
607 {
608 // 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) {
614 appendPath(prefix, domain);
615 }
616
617 // 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;
621 appendPath(fullname, relpath);
622
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) {
628 strncpy(buf, relpath.c_str(), 100);
629 strncpy(buf + 345, prefix.c_str(), 155);
630 } else {
631 strncpy(buf, fullname.c_str(), 100);
632 }
633 }
634
635 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
636
637 ALOGI(" Name: %s", fullname.c_str());
638
639 // If we're using a pax extended header, build & write that here; lengths are
640 // already preflighted
641 if (needExtended) {
642 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
643
644 // construct the pax extended header data block
645 memset(paxData, 0, PAXDATA_SIZE);
646
647 // size header -- calc len in digits by actually rendering the number
648 // to a string - brute force but simple
649 int paxLen = 0;
650 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size);
651 paxLen += write_pax_header_entry(paxData, PAXDATA_SIZE, "size", sizeStr);
652
653 // fullname was generated above with the ustar paths
654 paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen,
655 "path", fullname.c_str());
656
657 // Now we know how big the pax data is
658
659 // Now build the pax *header* templated on the ustar header
660 memcpy(paxHeader, buf, 512);
661
662 String8 leaf = getPathLeaf(fullname);
663 memset(paxHeader, 0, 100); // rewrite the name area
664 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
665 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
666 strncpy(paxHeader + 345, prefix.c_str(), 155);
667
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);
672 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)paxLen);
673
674 // Checksum and write the pax block header
675 calc_tar_checksum(paxHeader, PAXHEADER_SIZE);
676 send_tarfile_chunk(writer, paxHeader, 512);
677
678 // Now write the pax data itself
679 int paxblocks = (paxLen + 511) / 512;
680 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
681 }
682
683 // Checksum and write the 512-byte ustar file header block to the output
684 calc_tar_checksum(buf, BUFSIZE);
685 send_tarfile_chunk(writer, buf, 512);
686
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) {
692 size_t toRead = toWrite;
693 if (toRead > BUFSIZE) {
694 toRead = BUFSIZE;
695 }
696 ssize_t nRead = read(fd, buf, toRead);
697 if (nRead < 0) {
698 err = errno;
699 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.c_str(),
700 err, strerror(err));
701 break;
702 } else if (nRead == 0) {
703 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
704 filepath.c_str());
705 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 }
718 send_tarfile_chunk(writer, buf, nRead);
719 toWrite -= nRead;
720 }
721 }
722
723 cleanup:
724 free(buf);
725 done:
726 close(fd);
727 return err;
728 }
729 // end tarfile
730
731
732
733 const size_t RESTORE_BUF_SIZE = backup_flags::enable_max_size_writes_to_pipes() ? 64*1024 : 8*1024;
734
RestoreHelperBase()735 RestoreHelperBase::RestoreHelperBase()
736 {
737 m_buf = malloc(RESTORE_BUF_SIZE);
738 m_loggedUnknownMetadata = false;
739 }
740
~RestoreHelperBase()741 RestoreHelperBase::~RestoreHelperBase()
742 {
743 free(m_buf);
744 }
745
746 status_t
WriteFile(const String8 & filename,BackupDataReader * in)747 RestoreHelperBase::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 }
764
765 // 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)) {
770 ALOGW("Could not read metadata for %s -- %ld / %s", filename.c_str(),
771 (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) {
777 if (!m_loggedUnknownMetadata) {
778 m_loggedUnknownMetadata = true;
779 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
780 metadata.version, CURRENT_METADATA_VERSION);
781 }
782 }
783 mode = metadata.mode;
784
785 // Write the file and compute the crc
786 crc = crc32(0L, Z_NULL, 0);
787 fd = open(filename.c_str(), O_CREAT|O_RDWR|O_TRUNC, mode);
788 if (fd == -1) {
789 ALOGW("Could not open file %s -- %s", filename.c_str(), strerror(errno));
790 return errno;
791 }
792
793 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
794 err = write(fd, buf, amt);
795 if (err != amt) {
796 close(fd);
797 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.c_str());
798 return errno;
799 }
800 crc = crc32(crc, (Bytef*)buf, amt);
801 }
802
803 close(fd);
804
805 // Record for the snapshot
806 err = stat(filename.c_str(), &st);
807 if (err != 0) {
808 ALOGW("Error stating file that we just created %s", filename.c_str());
809 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;
817 r.s.mode = st.st_mode;
818 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
826 status_t
WriteSnapshot(int fd)827 RestoreHelperBase::WriteSnapshot(int fd)
828 {
829 return write_snapshot_file(fd, m_files);;
830 }
831
832 #if TEST_BACKUP_HELPERS
833
834 #define SCRATCH_DIR "/data/backup_helper_test/"
835
836 static int
write_text_file(const char * path,const char * data)837 write_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
861 static int
compare_file(const char * path,const unsigned char * data,int len)862 compare_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
904 free(contents);
905 return contentsMatch && sizesMatch ? 0 : 1;
906 }
907
908 int
backup_helper_test_empty()909 backup_helper_test_empty()
910 {
911 int err;
912 int fd;
913 KeyedVector<String8,FileRec> snapshot;
914 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
967 int
backup_helper_test_four()968 backup_helper_test_four()
969 {
970 int err;
971 int fd;
972 KeyedVector<String8,FileRec> snapshot;
973 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];
987 FileRec r;
988 r.deleted = false;
989
990 states[0].modTime_sec = 0xfedcba98;
991 states[0].modTime_nsec = 0xdeadbeef;
992 states[0].mode = 0777; // decimal 511, hex 0x000001ff
993 states[0].size = 0xababbcbc;
994 states[0].crc32 = 0x12345678;
995 states[0].nameLen = -12;
996 r.s = states[0];
997 filenames[0] = String8("bytes_of_padding");
998 snapshot.add(filenames[0], r);
999
1000 states[1].modTime_sec = 0x93400031;
1001 states[1].modTime_nsec = 0xdeadbeef;
1002 states[1].mode = 0666; // decimal 438, hex 0x000001b6
1003 states[1].size = 0x88557766;
1004 states[1].crc32 = 0x22334422;
1005 states[1].nameLen = -1;
1006 r.s = states[1];
1007 filenames[1] = String8("bytes_of_padding3");
1008 snapshot.add(filenames[1], r);
1009
1010 states[2].modTime_sec = 0x33221144;
1011 states[2].modTime_nsec = 0xdeadbeef;
1012 states[2].mode = 0744; // decimal 484, hex 0x000001e4
1013 states[2].size = 0x11223344;
1014 states[2].crc32 = 0x01122334;
1015 states[2].nameLen = 0;
1016 r.s = states[2];
1017 filenames[2] = String8("bytes_of_padding_2");
1018 snapshot.add(filenames[2], r);
1019
1020 states[3].modTime_sec = 0x33221144;
1021 states[3].modTime_nsec = 0xdeadbeef;
1022 states[3].mode = 0755; // decimal 493, hex 0x000001ed
1023 states[3].size = 0x11223344;
1024 states[3].crc32 = 0x01122334;
1025 states[3].nameLen = 0;
1026 r.s = states[3];
1027 filenames[3] = String8("bytes_of_padding__1");
1028 snapshot.add(filenames[3], r);
1029
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,
1042 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
1043
1044 // bytes_of_padding
1045 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
1046 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,
1050
1051 // bytes_of_padding3
1052 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
1053 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,
1058
1059 // bytes of padding2
1060 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
1061 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,
1066
1067 // bytes of padding3
1068 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
1069 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
1074 };
1075
1076 err = compare_file(filename, correct_data, sizeof(correct_data));
1077 if (err != 0) {
1078 return err;
1079 }
1080
1081 // 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) {
1097 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
1098 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
1107 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
1108 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
1109 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,
1111 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1112 states[i].crc32, name.length(), filenames[i].c_str(),
1113 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1114 state.nameLen, name.c_str());
1115 matched = false;
1116 }
1117 }
1118
1119 return matched ? 0 : 1;
1120 }
1121
1122 // hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1123 const unsigned char DATA_GOLDEN_FILE[] = {
1124 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,
1128 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1129 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
1130 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1131 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
1132 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1133 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
1134 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1135 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
1136 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
1137 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1138 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
1139 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
1140 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,
1143 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1144
1145 };
1146 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1147
1148 static int
test_write_header_and_entity(BackupDataWriter & writer,const char * str)1149 test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1150 {
1151 int err;
1152 String8 text(str);
1153
1154 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
1160 err = writer.WriteEntityData(text.c_str(), text.length()+1);
1161 if (err != 0) {
1162 fprintf(stderr, "write failed for data '%s'\n", text.c_str());
1163 return errno;
1164 }
1165
1166 return err;
1167 }
1168
1169 int
backup_helper_test_data_writer()1170 backup_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);
1179
1180 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
1194 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
1204 int
test_read_header_and_entity(BackupDataReader & reader,const char * str)1205 test_read_header_and_entity(BackupDataReader& reader, const char* str)
1206 {
1207 int err;
1208 size_t bufSize = strlen(str)+1;
1209 char* buf = (char*)malloc(bufSize);
1210 String8 string;
1211 size_t actualSize;
1212 bool done;
1213 int type;
1214 ssize_t nRead;
1215
1216 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1217
1218 err = reader.ReadNextHeader(&done, &type);
1219 if (done) {
1220 fprintf(stderr, "should not be done yet\n");
1221 goto finished;
1222 }
1223 if (err != 0) {
1224 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
1225 goto finished;
1226 }
1227 if (type != BACKUP_HEADER_ENTITY_V1) {
1228 err = EINVAL;
1229 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
1230 }
1231
1232 err = reader.ReadEntityHeader(&string, &actualSize);
1233 if (err != 0) {
1234 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
1235 goto finished;
1236 }
1237 if (string != str) {
1238 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.c_str());
1239 err = EINVAL;
1240 goto finished;
1241 }
1242 if (actualSize != bufSize) {
1243 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n",
1244 bufSize, actualSize);
1245 err = EINVAL;
1246 goto finished;
1247 }
1248
1249 nRead = reader.ReadEntityData(buf, bufSize);
1250 if (nRead < 0) {
1251 err = reader.Status();
1252 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
1253 goto finished;
1254 }
1255
1256 if (0 != memcmp(buf, str, bufSize)) {
1257 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
1258 "%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]);
1260 err = EINVAL;
1261 goto finished;
1262 }
1263
1264 // The next read will confirm whether it got the right amount of data.
1265
1266 finished:
1267 if (err != NO_ERROR) {
1268 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1269 }
1270 free(buf);
1271 return err;
1272 }
1273
1274 int
backup_helper_test_data_reader()1275 backup_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);
1284
1285 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 }
1326 }
1327
1328 close(fd);
1329
1330 return err;
1331 }
1332
1333 static int
get_mod_time(const char * filename,struct timeval times[2])1334 get_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 }
1343
1344 times[0].tv_sec = st.st_atim.tv_sec;
1345 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1346
1347 times[1].tv_sec = st.st_mtim.tv_sec;
1348 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1349
1350 return 0;
1351 }
1352
1353 int
backup_helper_test_files()1354 backup_helper_test_files()
1355 {
1356 int err;
1357 int oldSnapshotFD;
1358 int dataStreamFD;
1359 int newSnapshotFD;
1360
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[] = {
1373 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[] = {
1381 "data/b",
1382 "data/c",
1383 "data/d",
1384 "data/e",
1385 "data/f"
1386 };
1387
1388 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
1394 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1395 if (newSnapshotFD == -1) {
1396 fprintf(stderr, "error creating: %s\n", strerror(errno));
1397 return errno;
1398 }
1399
1400 {
1401 BackupDataWriter dataStream(dataStreamFD);
1402
1403 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
1404 if (err != 0) {
1405 return err;
1406 }
1407 }
1408
1409 close(dataStreamFD);
1410 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");
1432
1433 char const* files_after[] = {
1434 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[] = {
1443 "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
1457 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
1463 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
1469 {
1470 BackupDataWriter dataStream(dataStreamFD);
1471
1472 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
1473 if (err != 0) {
1474 return err;
1475 }
1476 }
1477
1478 close(oldSnapshotFD);
1479 close(dataStreamFD);
1480 close(newSnapshotFD);
1481
1482 return 0;
1483 }
1484
1485 int
backup_helper_test_null_base()1486 backup_helper_test_null_base()
1487 {
1488 int err;
1489 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
1533 int
backup_helper_test_missing_file()1534 backup_helper_test_missing_file()
1535 {
1536 int err;
1537 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
1585
1586 #endif // TEST_BACKUP_HELPERS
1587
1588 }
1589