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 <utils/KeyedVector.h>
22 #include <utils/ByteOrder.h>
23 #include <utils/String8.h>
24
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <sys/stat.h>
29 #include <sys/time.h> // for utimes
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <utime.h>
34 #include <fcntl.h>
35 #include <zlib.h>
36
37 #include <cutils/log.h>
38
39 namespace android {
40
41 #define MAGIC0 0x70616e53 // Snap
42 #define MAGIC1 0x656c6946 // File
43
44 /*
45 * File entity data format (v1):
46 *
47 * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
48 * - 12 bytes of metadata
49 * - the file data itself
50 *
51 * i.e. a 16-byte metadata header followed by the raw file data. If the
52 * restore code does not recognize the metadata version, it can still
53 * interpret the file data itself correctly.
54 *
55 * file_metadata_v1:
56 *
57 * - 4 byte version number === 0x00000001 (little endian)
58 * - 4-byte access mode (little-endian)
59 * - undefined (8 bytes)
60 */
61
62 struct file_metadata_v1 {
63 int version;
64 int mode;
65 int undefined_1;
66 int undefined_2;
67 };
68
69 const static int CURRENT_METADATA_VERSION = 1;
70
71 #if 1
72 #define LOGP(f, x...)
73 #else
74 #if TEST_BACKUP_HELPERS
75 #define LOGP(f, x...) printf(f "\n", x)
76 #else
77 #define LOGP(x...) ALOGD(x)
78 #endif
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.string(), 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.string());
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.string(), mode);
219
220 const int bufsize = 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 int crc = crc32(0L, Z_NULL, 0);
229
230
231 fileSize = lseek(fd, 0, SEEK_END);
232 lseek(fd, 0, SEEK_SET);
233
234 if (sizeof(metadata) != 16) {
235 ALOGE("ERROR: metadata block is the wrong size!");
236 }
237
238 bytesLeft = fileSize + sizeof(metadata);
239 err = dataStream->WriteEntityHeader(key, bytesLeft);
240 if (err != 0) {
241 free(buf);
242 return err;
243 }
244
245 // store the file metadata first
246 metadata.version = tolel(CURRENT_METADATA_VERSION);
247 metadata.mode = tolel(mode);
248 metadata.undefined_1 = metadata.undefined_2 = 0;
249 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
250 if (err != 0) {
251 free(buf);
252 return err;
253 }
254 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
255
256 // now store the file content
257 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
258 bytesLeft -= amt;
259 if (bytesLeft < 0) {
260 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
261 }
262 err = dataStream->WriteEntityData(buf, amt);
263 if (err != 0) {
264 free(buf);
265 return err;
266 }
267 }
268 if (bytesLeft != 0) {
269 if (bytesLeft > 0) {
270 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
271 // even though the data we're sending is probably bad.
272 memset(buf, 0, bufsize);
273 while (bytesLeft > 0) {
274 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
275 bytesLeft -= amt;
276 err = dataStream->WriteEntityData(buf, amt);
277 if (err != 0) {
278 free(buf);
279 return err;
280 }
281 }
282 }
283 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
284 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
285 }
286
287 free(buf);
288 return NO_ERROR;
289 }
290
291 static int
write_update_file(BackupDataWriter * dataStream,const String8 & key,char const * realFilename)292 write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
293 {
294 int err;
295 struct stat st;
296
297 err = stat(realFilename, &st);
298 if (err < 0) {
299 return errno;
300 }
301
302 int fd = open(realFilename, O_RDONLY);
303 if (fd == -1) {
304 return errno;
305 }
306
307 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
308 close(fd);
309 return err;
310 }
311
312 static int
compute_crc32(int fd)313 compute_crc32(int fd)
314 {
315 const int bufsize = 4*1024;
316 int amt;
317
318 char* buf = (char*)malloc(bufsize);
319 int crc = crc32(0L, Z_NULL, 0);
320
321 lseek(fd, 0, SEEK_SET);
322
323 while ((amt = read(fd, buf, bufsize)) != 0) {
324 crc = crc32(crc, (Bytef*)buf, amt);
325 }
326
327 free(buf);
328 return crc;
329 }
330
331 int
back_up_files(int oldSnapshotFD,BackupDataWriter * dataStream,int newSnapshotFD,char const * const * files,char const * const * keys,int fileCount)332 back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
333 char const* const* files, char const* const* keys, int fileCount)
334 {
335 int err;
336 KeyedVector<String8,FileState> oldSnapshot;
337 KeyedVector<String8,FileRec> newSnapshot;
338
339 if (oldSnapshotFD != -1) {
340 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
341 if (err != 0) {
342 // On an error, treat this as a full backup.
343 oldSnapshot.clear();
344 }
345 }
346
347 for (int i=0; i<fileCount; i++) {
348 String8 key(keys[i]);
349 FileRec r;
350 char const* file = files[i];
351 r.file = file;
352 struct stat st;
353
354 err = stat(file, &st);
355 if (err != 0) {
356 r.deleted = true;
357 } else {
358 r.deleted = false;
359 r.s.modTime_sec = st.st_mtime;
360 r.s.modTime_nsec = 0; // workaround sim breakage
361 //r.s.modTime_nsec = st.st_mtime_nsec;
362 r.s.mode = st.st_mode;
363 r.s.size = st.st_size;
364 // we compute the crc32 later down below, when we already have the file open.
365
366 if (newSnapshot.indexOfKey(key) >= 0) {
367 LOGP("back_up_files key already in use '%s'", key.string());
368 return -1;
369 }
370 }
371 newSnapshot.add(key, r);
372 }
373
374 int n = 0;
375 int N = oldSnapshot.size();
376 int m = 0;
377
378 while (n<N && m<fileCount) {
379 const String8& p = oldSnapshot.keyAt(n);
380 const String8& q = newSnapshot.keyAt(m);
381 FileRec& g = newSnapshot.editValueAt(m);
382 int cmp = p.compare(q);
383 if (g.deleted || cmp < 0) {
384 // file removed
385 LOGP("file removed: %s", p.string());
386 g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
387 dataStream->WriteEntityHeader(p, -1);
388 n++;
389 }
390 else if (cmp > 0) {
391 // file added
392 LOGP("file added: %s", g.file.string());
393 write_update_file(dataStream, q, g.file.string());
394 m++;
395 }
396 else {
397 // both files exist, check them
398 const FileState& f = oldSnapshot.valueAt(n);
399
400 int fd = open(g.file.string(), O_RDONLY);
401 if (fd < 0) {
402 // We can't open the file. Don't report it as a delete either. Let the
403 // server keep the old version. Maybe they'll be able to deal with it
404 // on restore.
405 LOGP("Unable to open file %s - skipping", g.file.string());
406 } else {
407 g.s.crc32 = compute_crc32(fd);
408
409 LOGP("%s", q.string());
410 LOGP(" new: 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(" old: 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 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
417 }
418
419 close(fd);
420 }
421 n++;
422 m++;
423 }
424 }
425
426 // these were deleted
427 while (n<N) {
428 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
429 n++;
430 }
431
432 // these were added
433 while (m<fileCount) {
434 const String8& q = newSnapshot.keyAt(m);
435 FileRec& g = newSnapshot.editValueAt(m);
436 write_update_file(dataStream, q, g.file.string());
437 m++;
438 }
439
440 err = write_snapshot_file(newSnapshotFD, newSnapshot);
441
442 return 0;
443 }
444
445 // Utility function, equivalent to stpcpy(): perform a strcpy, but instead of
446 // returning the initial dest, return a pointer to the trailing NUL.
strcpy_ptr(char * dest,const char * str)447 static char* strcpy_ptr(char* dest, const char* str) {
448 if (dest && str) {
449 while ((*dest = *str) != 0) {
450 dest++;
451 str++;
452 }
453 }
454 return dest;
455 }
456
calc_tar_checksum(char * buf)457 static void calc_tar_checksum(char* buf) {
458 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
459 memset(buf + 148, ' ', 8);
460
461 uint16_t sum = 0;
462 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
463 sum += *p;
464 }
465
466 // Now write the real checksum value:
467 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
468 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
469 }
470
471 // Returns number of bytes written
write_pax_header_entry(char * buf,const char * key,const char * value)472 static int write_pax_header_entry(char* buf, const char* key, const char* value) {
473 // start with the size of "1 key=value\n"
474 int len = strlen(key) + strlen(value) + 4;
475 if (len > 9) len++;
476 if (len > 99) len++;
477 if (len > 999) len++;
478 // since PATH_MAX is 4096 we don't expect to have to generate any single
479 // header entry longer than 9999 characters
480
481 return sprintf(buf, "%d %s=%s\n", len, key, value);
482 }
483
484 // Wire format to the backup manager service is chunked: each chunk is prefixed by
485 // 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)486 void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
487 uint32_t chunk_size_no = htonl(size);
488 writer->WriteEntityData(&chunk_size_no, 4);
489 if (size != 0) writer->WriteEntityData(buffer, size);
490 }
491
write_tarfile(const String8 & packageName,const String8 & domain,const String8 & rootpath,const String8 & filepath,BackupDataWriter * writer)492 int write_tarfile(const String8& packageName, const String8& domain,
493 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
494 {
495 // In the output stream everything is stored relative to the root
496 const char* relstart = filepath.string() + rootpath.length();
497 if (*relstart == '/') relstart++; // won't be true when path == rootpath
498 String8 relpath(relstart);
499
500 // If relpath is empty, it means this is the top of one of the standard named
501 // domain directories, so we should just skip it
502 if (relpath.length() == 0) {
503 return 0;
504 }
505
506 // Too long a name for the ustar format?
507 // "apps/" + packagename + '/' + domainpath < 155 chars
508 // relpath < 100 chars
509 bool needExtended = false;
510 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
511 needExtended = true;
512 }
513
514 // Non-7bit-clean path also means needing pax extended format
515 if (!needExtended) {
516 for (size_t i = 0; i < filepath.length(); i++) {
517 if ((filepath[i] & 0x80) != 0) {
518 needExtended = true;
519 break;
520 }
521 }
522 }
523
524 int err = 0;
525 struct stat64 s;
526 if (lstat64(filepath.string(), &s) != 0) {
527 err = errno;
528 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
529 return err;
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 // !!! TODO: use mmap when possible to avoid churning the buffer cache
539 // !!! TODO: this will break with symlinks; need to use readlink(2)
540 int fd = open(filepath.string(), O_RDONLY);
541 if (fd < 0) {
542 err = errno;
543 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
544 return err;
545 }
546
547 // read/write up to this much at a time.
548 const size_t BUFSIZE = 32 * 1024;
549 char* buf = (char *)calloc(1,BUFSIZE);
550 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch
551 char* paxData = buf + 1024;
552
553 if (buf == NULL) {
554 ALOGE("Out of mem allocating transfer buffer");
555 err = ENOMEM;
556 goto done;
557 }
558
559 // Magic fields for the ustar file format
560 strcat(buf + 257, "ustar");
561 strcat(buf + 263, "00");
562
563 // [ 265 : 32 ] user name, ignored on restore
564 // [ 297 : 32 ] group name, ignored on restore
565
566 // [ 100 : 8 ] file mode
567 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
568
569 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
570 // [ 116 : 8 ] gid -- ignored in Android format
571 snprintf(buf + 108, 8, "0%lo", s.st_uid);
572 snprintf(buf + 116, 8, "0%lo", s.st_gid);
573
574 // [ 124 : 12 ] file size in bytes
575 if (s.st_size > 077777777777LL) {
576 // very large files need a pax extended size header
577 needExtended = true;
578 }
579 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
580
581 // [ 136 : 12 ] last mod time as a UTC time_t
582 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
583
584 // [ 156 : 1 ] link/file type
585 uint8_t type;
586 if (isdir) {
587 type = '5'; // tar magic: '5' == directory
588 } else if (S_ISREG(s.st_mode)) {
589 type = '0'; // tar magic: '0' == normal file
590 } else {
591 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
592 goto cleanup;
593 }
594 buf[156] = type;
595
596 // [ 157 : 100 ] name of linked file [not implemented]
597
598 {
599 // Prefix and main relative path. Path lengths have been preflighted.
600 if (packageName.length() > 0) {
601 prefix = "apps/";
602 prefix += packageName;
603 }
604 if (domain.length() > 0) {
605 prefix.appendPath(domain);
606 }
607
608 // pax extended means we don't put in a prefix field, and put a different
609 // string in the basic name field. We can also construct the full path name
610 // out of the substrings we've now built.
611 fullname = prefix;
612 fullname.appendPath(relpath);
613
614 // ustar:
615 // [ 0 : 100 ]; file name/path
616 // [ 345 : 155 ] filename path prefix
617 // We only use the prefix area if fullname won't fit in the path
618 if (fullname.length() > 100) {
619 strncpy(buf, relpath.string(), 100);
620 strncpy(buf + 345, prefix.string(), 155);
621 } else {
622 strncpy(buf, fullname.string(), 100);
623 }
624 }
625
626 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
627
628 ALOGI(" Name: %s", fullname.string());
629
630 // If we're using a pax extended header, build & write that here; lengths are
631 // already preflighted
632 if (needExtended) {
633 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
634 char* p = paxData;
635
636 // construct the pax extended header data block
637 memset(paxData, 0, BUFSIZE - (paxData - buf));
638 int len;
639
640 // size header -- calc len in digits by actually rendering the number
641 // to a string - brute force but simple
642 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
643 p += write_pax_header_entry(p, "size", sizeStr);
644
645 // fullname was generated above with the ustar paths
646 p += write_pax_header_entry(p, "path", fullname.string());
647
648 // Now we know how big the pax data is
649 int paxLen = p - paxData;
650
651 // Now build the pax *header* templated on the ustar header
652 memcpy(paxHeader, buf, 512);
653
654 String8 leaf = fullname.getPathLeaf();
655 memset(paxHeader, 0, 100); // rewrite the name area
656 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
657 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
658 strncpy(paxHeader + 345, prefix.string(), 155);
659
660 paxHeader[156] = 'x'; // mark it as a pax extended header
661
662 // [ 124 : 12 ] size of pax extended header data
663 memset(paxHeader + 124, 0, 12);
664 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
665
666 // Checksum and write the pax block header
667 calc_tar_checksum(paxHeader);
668 send_tarfile_chunk(writer, paxHeader, 512);
669
670 // Now write the pax data itself
671 int paxblocks = (paxLen + 511) / 512;
672 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
673 }
674
675 // Checksum and write the 512-byte ustar file header block to the output
676 calc_tar_checksum(buf);
677 send_tarfile_chunk(writer, buf, 512);
678
679 // Now write the file data itself, for real files. We honor tar's convention that
680 // only full 512-byte blocks are sent to write().
681 if (!isdir) {
682 off64_t toWrite = s.st_size;
683 while (toWrite > 0) {
684 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
685 ssize_t nRead = read(fd, buf, toRead);
686 if (nRead < 0) {
687 err = errno;
688 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
689 err, strerror(err));
690 break;
691 } else if (nRead == 0) {
692 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
693 filepath.string());
694 err = EIO;
695 break;
696 }
697
698 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
699 // depends on the OS guarantee that for ordinary files, read() will never return
700 // less than the number of bytes requested.
701 ssize_t partial = (nRead+512) % 512;
702 if (partial > 0) {
703 ssize_t remainder = 512 - partial;
704 memset(buf + nRead, 0, remainder);
705 nRead += remainder;
706 }
707 send_tarfile_chunk(writer, buf, nRead);
708 toWrite -= nRead;
709 }
710 }
711
712 cleanup:
713 free(buf);
714 done:
715 close(fd);
716 return err;
717 }
718 // end tarfile
719
720
721
722 #define RESTORE_BUF_SIZE (8*1024)
723
RestoreHelperBase()724 RestoreHelperBase::RestoreHelperBase()
725 {
726 m_buf = malloc(RESTORE_BUF_SIZE);
727 m_loggedUnknownMetadata = false;
728 }
729
~RestoreHelperBase()730 RestoreHelperBase::~RestoreHelperBase()
731 {
732 free(m_buf);
733 }
734
735 status_t
WriteFile(const String8 & filename,BackupDataReader * in)736 RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
737 {
738 ssize_t err;
739 size_t dataSize;
740 String8 key;
741 int fd;
742 void* buf = m_buf;
743 ssize_t amt;
744 int mode;
745 int crc;
746 struct stat st;
747 FileRec r;
748
749 err = in->ReadEntityHeader(&key, &dataSize);
750 if (err != NO_ERROR) {
751 return err;
752 }
753
754 // Get the metadata block off the head of the file entity and use that to
755 // set up the output file
756 file_metadata_v1 metadata;
757 amt = in->ReadEntityData(&metadata, sizeof(metadata));
758 if (amt != sizeof(metadata)) {
759 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
760 (long)amt, strerror(errno));
761 return EIO;
762 }
763 metadata.version = fromlel(metadata.version);
764 metadata.mode = fromlel(metadata.mode);
765 if (metadata.version > CURRENT_METADATA_VERSION) {
766 if (!m_loggedUnknownMetadata) {
767 m_loggedUnknownMetadata = true;
768 ALOGW("Restoring file with unsupported metadata version %d (currently %d)",
769 metadata.version, CURRENT_METADATA_VERSION);
770 }
771 }
772 mode = metadata.mode;
773
774 // Write the file and compute the crc
775 crc = crc32(0L, Z_NULL, 0);
776 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
777 if (fd == -1) {
778 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
779 return errno;
780 }
781
782 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
783 err = write(fd, buf, amt);
784 if (err != amt) {
785 close(fd);
786 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
787 return errno;
788 }
789 crc = crc32(crc, (Bytef*)buf, amt);
790 }
791
792 close(fd);
793
794 // Record for the snapshot
795 err = stat(filename.string(), &st);
796 if (err != 0) {
797 ALOGW("Error stating file that we just created %s", filename.string());
798 return errno;
799 }
800
801 r.file = filename;
802 r.deleted = false;
803 r.s.modTime_sec = st.st_mtime;
804 r.s.modTime_nsec = 0; // workaround sim breakage
805 //r.s.modTime_nsec = st.st_mtime_nsec;
806 r.s.mode = st.st_mode;
807 r.s.size = st.st_size;
808 r.s.crc32 = crc;
809
810 m_files.add(key, r);
811
812 return NO_ERROR;
813 }
814
815 status_t
WriteSnapshot(int fd)816 RestoreHelperBase::WriteSnapshot(int fd)
817 {
818 return write_snapshot_file(fd, m_files);;
819 }
820
821 #if TEST_BACKUP_HELPERS
822
823 #define SCRATCH_DIR "/data/backup_helper_test/"
824
825 static int
write_text_file(const char * path,const char * data)826 write_text_file(const char* path, const char* data)
827 {
828 int amt;
829 int fd;
830 int len;
831
832 fd = creat(path, 0666);
833 if (fd == -1) {
834 fprintf(stderr, "creat %s failed\n", path);
835 return errno;
836 }
837
838 len = strlen(data);
839 amt = write(fd, data, len);
840 if (amt != len) {
841 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
842 return errno;
843 }
844
845 close(fd);
846
847 return 0;
848 }
849
850 static int
compare_file(const char * path,const unsigned char * data,int len)851 compare_file(const char* path, const unsigned char* data, int len)
852 {
853 int fd;
854 int amt;
855
856 fd = open(path, O_RDONLY);
857 if (fd == -1) {
858 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
859 return errno;
860 }
861
862 unsigned char* contents = (unsigned char*)malloc(len);
863 if (contents == NULL) {
864 fprintf(stderr, "malloc(%d) failed\n", len);
865 return ENOMEM;
866 }
867
868 bool sizesMatch = true;
869 amt = lseek(fd, 0, SEEK_END);
870 if (amt != len) {
871 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
872 sizesMatch = false;
873 }
874 lseek(fd, 0, SEEK_SET);
875
876 int readLen = amt < len ? amt : len;
877 amt = read(fd, contents, readLen);
878 if (amt != readLen) {
879 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
880 }
881
882 bool contentsMatch = true;
883 for (int i=0; i<readLen; i++) {
884 if (data[i] != contents[i]) {
885 if (contentsMatch) {
886 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
887 contentsMatch = false;
888 }
889 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
890 }
891 }
892
893 free(contents);
894 return contentsMatch && sizesMatch ? 0 : 1;
895 }
896
897 int
backup_helper_test_empty()898 backup_helper_test_empty()
899 {
900 int err;
901 int fd;
902 KeyedVector<String8,FileRec> snapshot;
903 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
904
905 system("rm -r " SCRATCH_DIR);
906 mkdir(SCRATCH_DIR, 0777);
907
908 // write
909 fd = creat(filename, 0666);
910 if (fd == -1) {
911 fprintf(stderr, "error creating %s\n", filename);
912 return 1;
913 }
914
915 err = write_snapshot_file(fd, snapshot);
916
917 close(fd);
918
919 if (err != 0) {
920 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
921 return err;
922 }
923
924 static const unsigned char correct_data[] = {
925 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
926 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
927 };
928
929 err = compare_file(filename, correct_data, sizeof(correct_data));
930 if (err != 0) {
931 return err;
932 }
933
934 // read
935 fd = open(filename, O_RDONLY);
936 if (fd == -1) {
937 fprintf(stderr, "error opening for read %s\n", filename);
938 return 1;
939 }
940
941 KeyedVector<String8,FileState> readSnapshot;
942 err = read_snapshot_file(fd, &readSnapshot);
943 if (err != 0) {
944 fprintf(stderr, "read_snapshot_file failed %d\n", err);
945 return err;
946 }
947
948 if (readSnapshot.size() != 0) {
949 fprintf(stderr, "readSnapshot should be length 0\n");
950 return 1;
951 }
952
953 return 0;
954 }
955
956 int
backup_helper_test_four()957 backup_helper_test_four()
958 {
959 int err;
960 int fd;
961 KeyedVector<String8,FileRec> snapshot;
962 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
963
964 system("rm -r " SCRATCH_DIR);
965 mkdir(SCRATCH_DIR, 0777);
966
967 // write
968 fd = creat(filename, 0666);
969 if (fd == -1) {
970 fprintf(stderr, "error opening %s\n", filename);
971 return 1;
972 }
973
974 String8 filenames[4];
975 FileState states[4];
976 FileRec r;
977 r.deleted = false;
978
979 states[0].modTime_sec = 0xfedcba98;
980 states[0].modTime_nsec = 0xdeadbeef;
981 states[0].mode = 0777; // decimal 511, hex 0x000001ff
982 states[0].size = 0xababbcbc;
983 states[0].crc32 = 0x12345678;
984 states[0].nameLen = -12;
985 r.s = states[0];
986 filenames[0] = String8("bytes_of_padding");
987 snapshot.add(filenames[0], r);
988
989 states[1].modTime_sec = 0x93400031;
990 states[1].modTime_nsec = 0xdeadbeef;
991 states[1].mode = 0666; // decimal 438, hex 0x000001b6
992 states[1].size = 0x88557766;
993 states[1].crc32 = 0x22334422;
994 states[1].nameLen = -1;
995 r.s = states[1];
996 filenames[1] = String8("bytes_of_padding3");
997 snapshot.add(filenames[1], r);
998
999 states[2].modTime_sec = 0x33221144;
1000 states[2].modTime_nsec = 0xdeadbeef;
1001 states[2].mode = 0744; // decimal 484, hex 0x000001e4
1002 states[2].size = 0x11223344;
1003 states[2].crc32 = 0x01122334;
1004 states[2].nameLen = 0;
1005 r.s = states[2];
1006 filenames[2] = String8("bytes_of_padding_2");
1007 snapshot.add(filenames[2], r);
1008
1009 states[3].modTime_sec = 0x33221144;
1010 states[3].modTime_nsec = 0xdeadbeef;
1011 states[3].mode = 0755; // decimal 493, hex 0x000001ed
1012 states[3].size = 0x11223344;
1013 states[3].crc32 = 0x01122334;
1014 states[3].nameLen = 0;
1015 r.s = states[3];
1016 filenames[3] = String8("bytes_of_padding__1");
1017 snapshot.add(filenames[3], r);
1018
1019 err = write_snapshot_file(fd, snapshot);
1020
1021 close(fd);
1022
1023 if (err != 0) {
1024 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1025 return err;
1026 }
1027
1028 static const unsigned char correct_data[] = {
1029 // header
1030 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
1031 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
1032
1033 // bytes_of_padding
1034 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
1035 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1036 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1037 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1038 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1039
1040 // bytes_of_padding3
1041 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
1042 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1043 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1044 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1045 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1046 0x33, 0xab, 0xab, 0xab,
1047
1048 // bytes of padding2
1049 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
1050 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1051 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1052 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1053 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1054 0x5f, 0x32, 0xab, 0xab,
1055
1056 // bytes of padding3
1057 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
1058 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1059 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1060 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1061 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1062 0x5f, 0x5f, 0x31, 0xab
1063 };
1064
1065 err = compare_file(filename, correct_data, sizeof(correct_data));
1066 if (err != 0) {
1067 return err;
1068 }
1069
1070 // read
1071 fd = open(filename, O_RDONLY);
1072 if (fd == -1) {
1073 fprintf(stderr, "error opening for read %s\n", filename);
1074 return 1;
1075 }
1076
1077
1078 KeyedVector<String8,FileState> readSnapshot;
1079 err = read_snapshot_file(fd, &readSnapshot);
1080 if (err != 0) {
1081 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1082 return err;
1083 }
1084
1085 if (readSnapshot.size() != 4) {
1086 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1087 return 1;
1088 }
1089
1090 bool matched = true;
1091 for (size_t i=0; i<readSnapshot.size(); i++) {
1092 const String8& name = readSnapshot.keyAt(i);
1093 const FileState state = readSnapshot.valueAt(i);
1094
1095 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
1096 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
1097 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
1098 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1099 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1100 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1101 states[i].crc32, name.length(), filenames[i].string(),
1102 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1103 state.nameLen, name.string());
1104 matched = false;
1105 }
1106 }
1107
1108 return matched ? 0 : 1;
1109 }
1110
1111 // hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1112 const unsigned char DATA_GOLDEN_FILE[] = {
1113 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1114 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1115 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1116 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
1117 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1118 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
1119 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1120 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
1121 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1122 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
1123 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1124 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
1125 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
1126 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1127 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
1128 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
1129 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1130 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1131 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
1132 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1133
1134 };
1135 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1136
1137 static int
test_write_header_and_entity(BackupDataWriter & writer,const char * str)1138 test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1139 {
1140 int err;
1141 String8 text(str);
1142
1143 err = writer.WriteEntityHeader(text, text.length()+1);
1144 if (err != 0) {
1145 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1146 return err;
1147 }
1148
1149 err = writer.WriteEntityData(text.string(), text.length()+1);
1150 if (err != 0) {
1151 fprintf(stderr, "write failed for data '%s'\n", text.string());
1152 return errno;
1153 }
1154
1155 return err;
1156 }
1157
1158 int
backup_helper_test_data_writer()1159 backup_helper_test_data_writer()
1160 {
1161 int err;
1162 int fd;
1163 const char* filename = SCRATCH_DIR "data_writer.data";
1164
1165 system("rm -r " SCRATCH_DIR);
1166 mkdir(SCRATCH_DIR, 0777);
1167 mkdir(SCRATCH_DIR "data", 0777);
1168
1169 fd = creat(filename, 0666);
1170 if (fd == -1) {
1171 fprintf(stderr, "error creating: %s\n", strerror(errno));
1172 return errno;
1173 }
1174
1175 BackupDataWriter writer(fd);
1176
1177 err = 0;
1178 err |= test_write_header_and_entity(writer, "no_padding_");
1179 err |= test_write_header_and_entity(writer, "padded_to__3");
1180 err |= test_write_header_and_entity(writer, "padded_to_2__");
1181 err |= test_write_header_and_entity(writer, "padded_to1");
1182
1183 close(fd);
1184
1185 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1186 if (err != 0) {
1187 return err;
1188 }
1189
1190 return err;
1191 }
1192
1193 int
test_read_header_and_entity(BackupDataReader & reader,const char * str)1194 test_read_header_and_entity(BackupDataReader& reader, const char* str)
1195 {
1196 int err;
1197 int bufSize = strlen(str)+1;
1198 char* buf = (char*)malloc(bufSize);
1199 String8 string;
1200 int cookie = 0x11111111;
1201 size_t actualSize;
1202 bool done;
1203 int type;
1204 ssize_t nRead;
1205
1206 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1207
1208 err = reader.ReadNextHeader(&done, &type);
1209 if (done) {
1210 fprintf(stderr, "should not be done yet\n");
1211 goto finished;
1212 }
1213 if (err != 0) {
1214 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
1215 goto finished;
1216 }
1217 if (type != BACKUP_HEADER_ENTITY_V1) {
1218 err = EINVAL;
1219 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
1220 }
1221
1222 err = reader.ReadEntityHeader(&string, &actualSize);
1223 if (err != 0) {
1224 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
1225 goto finished;
1226 }
1227 if (string != str) {
1228 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1229 err = EINVAL;
1230 goto finished;
1231 }
1232 if ((int)actualSize != bufSize) {
1233 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1234 actualSize);
1235 err = EINVAL;
1236 goto finished;
1237 }
1238
1239 nRead = reader.ReadEntityData(buf, bufSize);
1240 if (nRead < 0) {
1241 err = reader.Status();
1242 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
1243 goto finished;
1244 }
1245
1246 if (0 != memcmp(buf, str, bufSize)) {
1247 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
1248 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1249 buf[0], buf[1], buf[2], buf[3]);
1250 err = EINVAL;
1251 goto finished;
1252 }
1253
1254 // The next read will confirm whether it got the right amount of data.
1255
1256 finished:
1257 if (err != NO_ERROR) {
1258 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1259 }
1260 free(buf);
1261 return err;
1262 }
1263
1264 int
backup_helper_test_data_reader()1265 backup_helper_test_data_reader()
1266 {
1267 int err;
1268 int fd;
1269 const char* filename = SCRATCH_DIR "data_reader.data";
1270
1271 system("rm -r " SCRATCH_DIR);
1272 mkdir(SCRATCH_DIR, 0777);
1273 mkdir(SCRATCH_DIR "data", 0777);
1274
1275 fd = creat(filename, 0666);
1276 if (fd == -1) {
1277 fprintf(stderr, "error creating: %s\n", strerror(errno));
1278 return errno;
1279 }
1280
1281 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1282 if (err != DATA_GOLDEN_FILE_SIZE) {
1283 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1284 return errno;
1285 }
1286
1287 close(fd);
1288
1289 fd = open(filename, O_RDONLY);
1290 if (fd == -1) {
1291 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1292 filename);
1293 return errno;
1294 }
1295
1296 {
1297 BackupDataReader reader(fd);
1298
1299 err = 0;
1300
1301 if (err == NO_ERROR) {
1302 err = test_read_header_and_entity(reader, "no_padding_");
1303 }
1304
1305 if (err == NO_ERROR) {
1306 err = test_read_header_and_entity(reader, "padded_to__3");
1307 }
1308
1309 if (err == NO_ERROR) {
1310 err = test_read_header_and_entity(reader, "padded_to_2__");
1311 }
1312
1313 if (err == NO_ERROR) {
1314 err = test_read_header_and_entity(reader, "padded_to1");
1315 }
1316 }
1317
1318 close(fd);
1319
1320 return err;
1321 }
1322
1323 static int
get_mod_time(const char * filename,struct timeval times[2])1324 get_mod_time(const char* filename, struct timeval times[2])
1325 {
1326 int err;
1327 struct stat64 st;
1328 err = stat64(filename, &st);
1329 if (err != 0) {
1330 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1331 return errno;
1332 }
1333 times[0].tv_sec = st.st_atime;
1334 times[1].tv_sec = st.st_mtime;
1335
1336 // If st_atime is a macro then struct stat64 uses struct timespec
1337 // to store the access and modif time values and typically
1338 // st_*time_nsec is not defined. In glibc, this is controlled by
1339 // __USE_MISC.
1340 #ifdef __USE_MISC
1341 #if !defined(st_atime) || defined(st_atime_nsec)
1342 #error "Check if this __USE_MISC conditional is still needed."
1343 #endif
1344 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1345 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1346 #else
1347 times[0].tv_usec = st.st_atime_nsec / 1000;
1348 times[1].tv_usec = st.st_mtime_nsec / 1000;
1349 #endif
1350
1351 return 0;
1352 }
1353
1354 int
backup_helper_test_files()1355 backup_helper_test_files()
1356 {
1357 int err;
1358 int oldSnapshotFD;
1359 int dataStreamFD;
1360 int newSnapshotFD;
1361
1362 system("rm -r " SCRATCH_DIR);
1363 mkdir(SCRATCH_DIR, 0777);
1364 mkdir(SCRATCH_DIR "data", 0777);
1365
1366 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1367 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1368 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1369 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1370 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1371 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1372
1373 char const* files_before[] = {
1374 SCRATCH_DIR "data/b",
1375 SCRATCH_DIR "data/c",
1376 SCRATCH_DIR "data/d",
1377 SCRATCH_DIR "data/e",
1378 SCRATCH_DIR "data/f"
1379 };
1380
1381 char const* keys_before[] = {
1382 "data/b",
1383 "data/c",
1384 "data/d",
1385 "data/e",
1386 "data/f"
1387 };
1388
1389 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1390 if (dataStreamFD == -1) {
1391 fprintf(stderr, "error creating: %s\n", strerror(errno));
1392 return errno;
1393 }
1394
1395 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1396 if (newSnapshotFD == -1) {
1397 fprintf(stderr, "error creating: %s\n", strerror(errno));
1398 return errno;
1399 }
1400
1401 {
1402 BackupDataWriter dataStream(dataStreamFD);
1403
1404 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
1405 if (err != 0) {
1406 return err;
1407 }
1408 }
1409
1410 close(dataStreamFD);
1411 close(newSnapshotFD);
1412
1413 sleep(3);
1414
1415 struct timeval d_times[2];
1416 struct timeval e_times[2];
1417
1418 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1419 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1420 if (err != 0) {
1421 return err;
1422 }
1423
1424 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1425 unlink(SCRATCH_DIR "data/c");
1426 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1427 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1428 utimes(SCRATCH_DIR "data/d", d_times);
1429 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1430 utimes(SCRATCH_DIR "data/e", e_times);
1431 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1432 unlink(SCRATCH_DIR "data/f");
1433
1434 char const* files_after[] = {
1435 SCRATCH_DIR "data/a", // added
1436 SCRATCH_DIR "data/b", // same
1437 SCRATCH_DIR "data/c", // different mod time
1438 SCRATCH_DIR "data/d", // different size (same mod time)
1439 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1440 SCRATCH_DIR "data/g" // added
1441 };
1442
1443 char const* keys_after[] = {
1444 "data/a", // added
1445 "data/b", // same
1446 "data/c", // different mod time
1447 "data/d", // different size (same mod time)
1448 "data/e", // different contents (same mod time, same size)
1449 "data/g" // added
1450 };
1451
1452 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1453 if (oldSnapshotFD == -1) {
1454 fprintf(stderr, "error opening: %s\n", strerror(errno));
1455 return errno;
1456 }
1457
1458 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1459 if (dataStreamFD == -1) {
1460 fprintf(stderr, "error creating: %s\n", strerror(errno));
1461 return errno;
1462 }
1463
1464 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1465 if (newSnapshotFD == -1) {
1466 fprintf(stderr, "error creating: %s\n", strerror(errno));
1467 return errno;
1468 }
1469
1470 {
1471 BackupDataWriter dataStream(dataStreamFD);
1472
1473 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
1474 if (err != 0) {
1475 return err;
1476 }
1477 }
1478
1479 close(oldSnapshotFD);
1480 close(dataStreamFD);
1481 close(newSnapshotFD);
1482
1483 return 0;
1484 }
1485
1486 int
backup_helper_test_null_base()1487 backup_helper_test_null_base()
1488 {
1489 int err;
1490 int oldSnapshotFD;
1491 int dataStreamFD;
1492 int newSnapshotFD;
1493
1494 system("rm -r " SCRATCH_DIR);
1495 mkdir(SCRATCH_DIR, 0777);
1496 mkdir(SCRATCH_DIR "data", 0777);
1497
1498 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1499
1500 char const* files[] = {
1501 SCRATCH_DIR "data/a",
1502 };
1503
1504 char const* keys[] = {
1505 "a",
1506 };
1507
1508 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1509 if (dataStreamFD == -1) {
1510 fprintf(stderr, "error creating: %s\n", strerror(errno));
1511 return errno;
1512 }
1513
1514 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1515 if (newSnapshotFD == -1) {
1516 fprintf(stderr, "error creating: %s\n", strerror(errno));
1517 return errno;
1518 }
1519
1520 {
1521 BackupDataWriter dataStream(dataStreamFD);
1522
1523 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1524 if (err != 0) {
1525 return err;
1526 }
1527 }
1528
1529 close(dataStreamFD);
1530 close(newSnapshotFD);
1531
1532 return 0;
1533 }
1534
1535 int
backup_helper_test_missing_file()1536 backup_helper_test_missing_file()
1537 {
1538 int err;
1539 int oldSnapshotFD;
1540 int dataStreamFD;
1541 int newSnapshotFD;
1542
1543 system("rm -r " SCRATCH_DIR);
1544 mkdir(SCRATCH_DIR, 0777);
1545 mkdir(SCRATCH_DIR "data", 0777);
1546
1547 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1548
1549 char const* files[] = {
1550 SCRATCH_DIR "data/a",
1551 SCRATCH_DIR "data/b",
1552 SCRATCH_DIR "data/c",
1553 };
1554
1555 char const* keys[] = {
1556 "a",
1557 "b",
1558 "c",
1559 };
1560
1561 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1562 if (dataStreamFD == -1) {
1563 fprintf(stderr, "error creating: %s\n", strerror(errno));
1564 return errno;
1565 }
1566
1567 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1568 if (newSnapshotFD == -1) {
1569 fprintf(stderr, "error creating: %s\n", strerror(errno));
1570 return errno;
1571 }
1572
1573 {
1574 BackupDataWriter dataStream(dataStreamFD);
1575
1576 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1577 if (err != 0) {
1578 return err;
1579 }
1580 }
1581
1582 close(dataStreamFD);
1583 close(newSnapshotFD);
1584
1585 return 0;
1586 }
1587
1588
1589 #endif // TEST_BACKUP_HELPERS
1590
1591 }
1592