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 <utils/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...) LOGD(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 LOGW("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 LOGW("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 LOGW("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 LOGW("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 LOGW("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 LOGW("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 LOGW("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 LOGW("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 LOGE("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 LOGE("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 LOGE("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 LOGE("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 = new char[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 LOGE("Out of mem allocating transfer buffer");
555 err = ENOMEM;
556 goto cleanup;
557 }
558
559 // Good to go -- first construct the standard tar header at the start of the buffer
560 memset(buf, 0, BUFSIZE);
561
562 // Magic fields for the ustar file format
563 strcat(buf + 257, "ustar");
564 strcat(buf + 263, "00");
565
566 // [ 265 : 32 ] user name, ignored on restore
567 // [ 297 : 32 ] group name, ignored on restore
568
569 // [ 100 : 8 ] file mode
570 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
571
572 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
573 // [ 116 : 8 ] gid -- ignored in Android format
574 snprintf(buf + 108, 8, "0%lo", s.st_uid);
575 snprintf(buf + 116, 8, "0%lo", s.st_gid);
576
577 // [ 124 : 12 ] file size in bytes
578 if (s.st_size > 077777777777LL) {
579 // very large files need a pax extended size header
580 needExtended = true;
581 }
582 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
583
584 // [ 136 : 12 ] last mod time as a UTC time_t
585 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
586
587 // [ 156 : 1 ] link/file type
588 uint8_t type;
589 if (isdir) {
590 type = '5'; // tar magic: '5' == directory
591 } else if (S_ISREG(s.st_mode)) {
592 type = '0'; // tar magic: '0' == normal file
593 } else {
594 LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
595 goto cleanup;
596 }
597 buf[156] = type;
598
599 // [ 157 : 100 ] name of linked file [not implemented]
600
601 {
602 // Prefix and main relative path. Path lengths have been preflighted.
603 if (packageName.length() > 0) {
604 prefix = "apps/";
605 prefix += packageName;
606 }
607 if (domain.length() > 0) {
608 prefix.appendPath(domain);
609 }
610
611 // pax extended means we don't put in a prefix field, and put a different
612 // string in the basic name field. We can also construct the full path name
613 // out of the substrings we've now built.
614 fullname = prefix;
615 fullname.appendPath(relpath);
616
617 // ustar:
618 // [ 0 : 100 ]; file name/path
619 // [ 345 : 155 ] filename path prefix
620 // We only use the prefix area if fullname won't fit in the path
621 if (fullname.length() > 100) {
622 strncpy(buf, relpath.string(), 100);
623 strncpy(buf + 345, prefix.string(), 155);
624 } else {
625 strncpy(buf, fullname.string(), 100);
626 }
627 }
628
629 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
630
631 LOGI(" Name: %s", fullname.string());
632
633 // If we're using a pax extended header, build & write that here; lengths are
634 // already preflighted
635 if (needExtended) {
636 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal
637 char* p = paxData;
638
639 // construct the pax extended header data block
640 memset(paxData, 0, BUFSIZE - (paxData - buf));
641 int len;
642
643 // size header -- calc len in digits by actually rendering the number
644 // to a string - brute force but simple
645 snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size);
646 p += write_pax_header_entry(p, "size", sizeStr);
647
648 // fullname was generated above with the ustar paths
649 p += write_pax_header_entry(p, "path", fullname.string());
650
651 // Now we know how big the pax data is
652 int paxLen = p - paxData;
653
654 // Now build the pax *header* templated on the ustar header
655 memcpy(paxHeader, buf, 512);
656
657 String8 leaf = fullname.getPathLeaf();
658 memset(paxHeader, 0, 100); // rewrite the name area
659 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
660 memset(paxHeader + 345, 0, 155); // rewrite the prefix area
661 strncpy(paxHeader + 345, prefix.string(), 155);
662
663 paxHeader[156] = 'x'; // mark it as a pax extended header
664
665 // [ 124 : 12 ] size of pax extended header data
666 memset(paxHeader + 124, 0, 12);
667 snprintf(paxHeader + 124, 12, "%011o", p - paxData);
668
669 // Checksum and write the pax block header
670 calc_tar_checksum(paxHeader);
671 send_tarfile_chunk(writer, paxHeader, 512);
672
673 // Now write the pax data itself
674 int paxblocks = (paxLen + 511) / 512;
675 send_tarfile_chunk(writer, paxData, 512 * paxblocks);
676 }
677
678 // Checksum and write the 512-byte ustar file header block to the output
679 calc_tar_checksum(buf);
680 send_tarfile_chunk(writer, buf, 512);
681
682 // Now write the file data itself, for real files. We honor tar's convention that
683 // only full 512-byte blocks are sent to write().
684 if (!isdir) {
685 off64_t toWrite = s.st_size;
686 while (toWrite > 0) {
687 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
688 ssize_t nRead = read(fd, buf, toRead);
689 if (nRead < 0) {
690 err = errno;
691 LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
692 err, strerror(err));
693 break;
694 } else if (nRead == 0) {
695 LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
696 filepath.string());
697 err = EIO;
698 break;
699 }
700
701 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
702 // depends on the OS guarantee that for ordinary files, read() will never return
703 // less than the number of bytes requested.
704 ssize_t partial = (nRead+512) % 512;
705 if (partial > 0) {
706 ssize_t remainder = 512 - partial;
707 memset(buf + nRead, 0, remainder);
708 nRead += remainder;
709 }
710 send_tarfile_chunk(writer, buf, nRead);
711 toWrite -= nRead;
712 }
713 }
714
715 cleanup:
716 delete [] buf;
717 done:
718 close(fd);
719 return err;
720 }
721 // end tarfile
722
723
724
725 #define RESTORE_BUF_SIZE (8*1024)
726
RestoreHelperBase()727 RestoreHelperBase::RestoreHelperBase()
728 {
729 m_buf = malloc(RESTORE_BUF_SIZE);
730 m_loggedUnknownMetadata = false;
731 }
732
~RestoreHelperBase()733 RestoreHelperBase::~RestoreHelperBase()
734 {
735 free(m_buf);
736 }
737
738 status_t
WriteFile(const String8 & filename,BackupDataReader * in)739 RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
740 {
741 ssize_t err;
742 size_t dataSize;
743 String8 key;
744 int fd;
745 void* buf = m_buf;
746 ssize_t amt;
747 int mode;
748 int crc;
749 struct stat st;
750 FileRec r;
751
752 err = in->ReadEntityHeader(&key, &dataSize);
753 if (err != NO_ERROR) {
754 return err;
755 }
756
757 // Get the metadata block off the head of the file entity and use that to
758 // set up the output file
759 file_metadata_v1 metadata;
760 amt = in->ReadEntityData(&metadata, sizeof(metadata));
761 if (amt != sizeof(metadata)) {
762 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
763 (long)amt, strerror(errno));
764 return EIO;
765 }
766 metadata.version = fromlel(metadata.version);
767 metadata.mode = fromlel(metadata.mode);
768 if (metadata.version > CURRENT_METADATA_VERSION) {
769 if (!m_loggedUnknownMetadata) {
770 m_loggedUnknownMetadata = true;
771 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
772 metadata.version, CURRENT_METADATA_VERSION);
773 }
774 }
775 mode = metadata.mode;
776
777 // Write the file and compute the crc
778 crc = crc32(0L, Z_NULL, 0);
779 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
780 if (fd == -1) {
781 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
782 return errno;
783 }
784
785 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
786 err = write(fd, buf, amt);
787 if (err != amt) {
788 close(fd);
789 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
790 return errno;
791 }
792 crc = crc32(crc, (Bytef*)buf, amt);
793 }
794
795 close(fd);
796
797 // Record for the snapshot
798 err = stat(filename.string(), &st);
799 if (err != 0) {
800 LOGW("Error stating file that we just created %s", filename.string());
801 return errno;
802 }
803
804 r.file = filename;
805 r.deleted = false;
806 r.s.modTime_sec = st.st_mtime;
807 r.s.modTime_nsec = 0; // workaround sim breakage
808 //r.s.modTime_nsec = st.st_mtime_nsec;
809 r.s.mode = st.st_mode;
810 r.s.size = st.st_size;
811 r.s.crc32 = crc;
812
813 m_files.add(key, r);
814
815 return NO_ERROR;
816 }
817
818 status_t
WriteSnapshot(int fd)819 RestoreHelperBase::WriteSnapshot(int fd)
820 {
821 return write_snapshot_file(fd, m_files);;
822 }
823
824 #if TEST_BACKUP_HELPERS
825
826 #define SCRATCH_DIR "/data/backup_helper_test/"
827
828 static int
write_text_file(const char * path,const char * data)829 write_text_file(const char* path, const char* data)
830 {
831 int amt;
832 int fd;
833 int len;
834
835 fd = creat(path, 0666);
836 if (fd == -1) {
837 fprintf(stderr, "creat %s failed\n", path);
838 return errno;
839 }
840
841 len = strlen(data);
842 amt = write(fd, data, len);
843 if (amt != len) {
844 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
845 return errno;
846 }
847
848 close(fd);
849
850 return 0;
851 }
852
853 static int
compare_file(const char * path,const unsigned char * data,int len)854 compare_file(const char* path, const unsigned char* data, int len)
855 {
856 int fd;
857 int amt;
858
859 fd = open(path, O_RDONLY);
860 if (fd == -1) {
861 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
862 return errno;
863 }
864
865 unsigned char* contents = (unsigned char*)malloc(len);
866 if (contents == NULL) {
867 fprintf(stderr, "malloc(%d) failed\n", len);
868 return ENOMEM;
869 }
870
871 bool sizesMatch = true;
872 amt = lseek(fd, 0, SEEK_END);
873 if (amt != len) {
874 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
875 sizesMatch = false;
876 }
877 lseek(fd, 0, SEEK_SET);
878
879 int readLen = amt < len ? amt : len;
880 amt = read(fd, contents, readLen);
881 if (amt != readLen) {
882 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
883 }
884
885 bool contentsMatch = true;
886 for (int i=0; i<readLen; i++) {
887 if (data[i] != contents[i]) {
888 if (contentsMatch) {
889 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
890 contentsMatch = false;
891 }
892 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
893 }
894 }
895
896 free(contents);
897 return contentsMatch && sizesMatch ? 0 : 1;
898 }
899
900 int
backup_helper_test_empty()901 backup_helper_test_empty()
902 {
903 int err;
904 int fd;
905 KeyedVector<String8,FileRec> snapshot;
906 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
907
908 system("rm -r " SCRATCH_DIR);
909 mkdir(SCRATCH_DIR, 0777);
910
911 // write
912 fd = creat(filename, 0666);
913 if (fd == -1) {
914 fprintf(stderr, "error creating %s\n", filename);
915 return 1;
916 }
917
918 err = write_snapshot_file(fd, snapshot);
919
920 close(fd);
921
922 if (err != 0) {
923 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
924 return err;
925 }
926
927 static const unsigned char correct_data[] = {
928 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
929 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
930 };
931
932 err = compare_file(filename, correct_data, sizeof(correct_data));
933 if (err != 0) {
934 return err;
935 }
936
937 // read
938 fd = open(filename, O_RDONLY);
939 if (fd == -1) {
940 fprintf(stderr, "error opening for read %s\n", filename);
941 return 1;
942 }
943
944 KeyedVector<String8,FileState> readSnapshot;
945 err = read_snapshot_file(fd, &readSnapshot);
946 if (err != 0) {
947 fprintf(stderr, "read_snapshot_file failed %d\n", err);
948 return err;
949 }
950
951 if (readSnapshot.size() != 0) {
952 fprintf(stderr, "readSnapshot should be length 0\n");
953 return 1;
954 }
955
956 return 0;
957 }
958
959 int
backup_helper_test_four()960 backup_helper_test_four()
961 {
962 int err;
963 int fd;
964 KeyedVector<String8,FileRec> snapshot;
965 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
966
967 system("rm -r " SCRATCH_DIR);
968 mkdir(SCRATCH_DIR, 0777);
969
970 // write
971 fd = creat(filename, 0666);
972 if (fd == -1) {
973 fprintf(stderr, "error opening %s\n", filename);
974 return 1;
975 }
976
977 String8 filenames[4];
978 FileState states[4];
979 FileRec r;
980 r.deleted = false;
981
982 states[0].modTime_sec = 0xfedcba98;
983 states[0].modTime_nsec = 0xdeadbeef;
984 states[0].mode = 0777; // decimal 511, hex 0x000001ff
985 states[0].size = 0xababbcbc;
986 states[0].crc32 = 0x12345678;
987 states[0].nameLen = -12;
988 r.s = states[0];
989 filenames[0] = String8("bytes_of_padding");
990 snapshot.add(filenames[0], r);
991
992 states[1].modTime_sec = 0x93400031;
993 states[1].modTime_nsec = 0xdeadbeef;
994 states[1].mode = 0666; // decimal 438, hex 0x000001b6
995 states[1].size = 0x88557766;
996 states[1].crc32 = 0x22334422;
997 states[1].nameLen = -1;
998 r.s = states[1];
999 filenames[1] = String8("bytes_of_padding3");
1000 snapshot.add(filenames[1], r);
1001
1002 states[2].modTime_sec = 0x33221144;
1003 states[2].modTime_nsec = 0xdeadbeef;
1004 states[2].mode = 0744; // decimal 484, hex 0x000001e4
1005 states[2].size = 0x11223344;
1006 states[2].crc32 = 0x01122334;
1007 states[2].nameLen = 0;
1008 r.s = states[2];
1009 filenames[2] = String8("bytes_of_padding_2");
1010 snapshot.add(filenames[2], r);
1011
1012 states[3].modTime_sec = 0x33221144;
1013 states[3].modTime_nsec = 0xdeadbeef;
1014 states[3].mode = 0755; // decimal 493, hex 0x000001ed
1015 states[3].size = 0x11223344;
1016 states[3].crc32 = 0x01122334;
1017 states[3].nameLen = 0;
1018 r.s = states[3];
1019 filenames[3] = String8("bytes_of_padding__1");
1020 snapshot.add(filenames[3], r);
1021
1022 err = write_snapshot_file(fd, snapshot);
1023
1024 close(fd);
1025
1026 if (err != 0) {
1027 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
1028 return err;
1029 }
1030
1031 static const unsigned char correct_data[] = {
1032 // header
1033 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
1034 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
1035
1036 // bytes_of_padding
1037 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
1038 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
1039 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
1040 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1041 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1042
1043 // bytes_of_padding3
1044 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
1045 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
1046 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
1047 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1048 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1049 0x33, 0xab, 0xab, 0xab,
1050
1051 // bytes of padding2
1052 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
1053 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1054 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
1055 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1056 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1057 0x5f, 0x32, 0xab, 0xab,
1058
1059 // bytes of padding3
1060 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
1061 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
1062 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
1063 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
1064 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
1065 0x5f, 0x5f, 0x31, 0xab
1066 };
1067
1068 err = compare_file(filename, correct_data, sizeof(correct_data));
1069 if (err != 0) {
1070 return err;
1071 }
1072
1073 // read
1074 fd = open(filename, O_RDONLY);
1075 if (fd == -1) {
1076 fprintf(stderr, "error opening for read %s\n", filename);
1077 return 1;
1078 }
1079
1080
1081 KeyedVector<String8,FileState> readSnapshot;
1082 err = read_snapshot_file(fd, &readSnapshot);
1083 if (err != 0) {
1084 fprintf(stderr, "read_snapshot_file failed %d\n", err);
1085 return err;
1086 }
1087
1088 if (readSnapshot.size() != 4) {
1089 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
1090 return 1;
1091 }
1092
1093 bool matched = true;
1094 for (size_t i=0; i<readSnapshot.size(); i++) {
1095 const String8& name = readSnapshot.keyAt(i);
1096 const FileState state = readSnapshot.valueAt(i);
1097
1098 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
1099 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
1100 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
1101 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1102 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1103 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1104 states[i].crc32, name.length(), filenames[i].string(),
1105 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1106 state.nameLen, name.string());
1107 matched = false;
1108 }
1109 }
1110
1111 return matched ? 0 : 1;
1112 }
1113
1114 // hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1115 const unsigned char DATA_GOLDEN_FILE[] = {
1116 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1117 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1118 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1119 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
1120 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1121 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
1122 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1123 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
1124 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1125 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
1126 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1127 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
1128 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
1129 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1130 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
1131 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
1132 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1133 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1134 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
1135 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1136
1137 };
1138 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1139
1140 static int
test_write_header_and_entity(BackupDataWriter & writer,const char * str)1141 test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1142 {
1143 int err;
1144 String8 text(str);
1145
1146 err = writer.WriteEntityHeader(text, text.length()+1);
1147 if (err != 0) {
1148 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1149 return err;
1150 }
1151
1152 err = writer.WriteEntityData(text.string(), text.length()+1);
1153 if (err != 0) {
1154 fprintf(stderr, "write failed for data '%s'\n", text.string());
1155 return errno;
1156 }
1157
1158 return err;
1159 }
1160
1161 int
backup_helper_test_data_writer()1162 backup_helper_test_data_writer()
1163 {
1164 int err;
1165 int fd;
1166 const char* filename = SCRATCH_DIR "data_writer.data";
1167
1168 system("rm -r " SCRATCH_DIR);
1169 mkdir(SCRATCH_DIR, 0777);
1170 mkdir(SCRATCH_DIR "data", 0777);
1171
1172 fd = creat(filename, 0666);
1173 if (fd == -1) {
1174 fprintf(stderr, "error creating: %s\n", strerror(errno));
1175 return errno;
1176 }
1177
1178 BackupDataWriter writer(fd);
1179
1180 err = 0;
1181 err |= test_write_header_and_entity(writer, "no_padding_");
1182 err |= test_write_header_and_entity(writer, "padded_to__3");
1183 err |= test_write_header_and_entity(writer, "padded_to_2__");
1184 err |= test_write_header_and_entity(writer, "padded_to1");
1185
1186 close(fd);
1187
1188 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1189 if (err != 0) {
1190 return err;
1191 }
1192
1193 return err;
1194 }
1195
1196 int
test_read_header_and_entity(BackupDataReader & reader,const char * str)1197 test_read_header_and_entity(BackupDataReader& reader, const char* str)
1198 {
1199 int err;
1200 int bufSize = strlen(str)+1;
1201 char* buf = (char*)malloc(bufSize);
1202 String8 string;
1203 int cookie = 0x11111111;
1204 size_t actualSize;
1205 bool done;
1206 int type;
1207 ssize_t nRead;
1208
1209 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1210
1211 err = reader.ReadNextHeader(&done, &type);
1212 if (done) {
1213 fprintf(stderr, "should not be done yet\n");
1214 goto finished;
1215 }
1216 if (err != 0) {
1217 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
1218 goto finished;
1219 }
1220 if (type != BACKUP_HEADER_ENTITY_V1) {
1221 err = EINVAL;
1222 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
1223 }
1224
1225 err = reader.ReadEntityHeader(&string, &actualSize);
1226 if (err != 0) {
1227 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
1228 goto finished;
1229 }
1230 if (string != str) {
1231 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1232 err = EINVAL;
1233 goto finished;
1234 }
1235 if ((int)actualSize != bufSize) {
1236 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1237 actualSize);
1238 err = EINVAL;
1239 goto finished;
1240 }
1241
1242 nRead = reader.ReadEntityData(buf, bufSize);
1243 if (nRead < 0) {
1244 err = reader.Status();
1245 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
1246 goto finished;
1247 }
1248
1249 if (0 != memcmp(buf, str, bufSize)) {
1250 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
1251 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1252 buf[0], buf[1], buf[2], buf[3]);
1253 err = EINVAL;
1254 goto finished;
1255 }
1256
1257 // The next read will confirm whether it got the right amount of data.
1258
1259 finished:
1260 if (err != NO_ERROR) {
1261 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1262 }
1263 free(buf);
1264 return err;
1265 }
1266
1267 int
backup_helper_test_data_reader()1268 backup_helper_test_data_reader()
1269 {
1270 int err;
1271 int fd;
1272 const char* filename = SCRATCH_DIR "data_reader.data";
1273
1274 system("rm -r " SCRATCH_DIR);
1275 mkdir(SCRATCH_DIR, 0777);
1276 mkdir(SCRATCH_DIR "data", 0777);
1277
1278 fd = creat(filename, 0666);
1279 if (fd == -1) {
1280 fprintf(stderr, "error creating: %s\n", strerror(errno));
1281 return errno;
1282 }
1283
1284 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1285 if (err != DATA_GOLDEN_FILE_SIZE) {
1286 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1287 return errno;
1288 }
1289
1290 close(fd);
1291
1292 fd = open(filename, O_RDONLY);
1293 if (fd == -1) {
1294 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1295 filename);
1296 return errno;
1297 }
1298
1299 {
1300 BackupDataReader reader(fd);
1301
1302 err = 0;
1303
1304 if (err == NO_ERROR) {
1305 err = test_read_header_and_entity(reader, "no_padding_");
1306 }
1307
1308 if (err == NO_ERROR) {
1309 err = test_read_header_and_entity(reader, "padded_to__3");
1310 }
1311
1312 if (err == NO_ERROR) {
1313 err = test_read_header_and_entity(reader, "padded_to_2__");
1314 }
1315
1316 if (err == NO_ERROR) {
1317 err = test_read_header_and_entity(reader, "padded_to1");
1318 }
1319 }
1320
1321 close(fd);
1322
1323 return err;
1324 }
1325
1326 static int
get_mod_time(const char * filename,struct timeval times[2])1327 get_mod_time(const char* filename, struct timeval times[2])
1328 {
1329 int err;
1330 struct stat64 st;
1331 err = stat64(filename, &st);
1332 if (err != 0) {
1333 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1334 return errno;
1335 }
1336 times[0].tv_sec = st.st_atime;
1337 times[1].tv_sec = st.st_mtime;
1338
1339 // If st_atime is a macro then struct stat64 uses struct timespec
1340 // to store the access and modif time values and typically
1341 // st_*time_nsec is not defined. In glibc, this is controlled by
1342 // __USE_MISC.
1343 #ifdef __USE_MISC
1344 #if !defined(st_atime) || defined(st_atime_nsec)
1345 #error "Check if this __USE_MISC conditional is still needed."
1346 #endif
1347 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1348 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1349 #else
1350 times[0].tv_usec = st.st_atime_nsec / 1000;
1351 times[1].tv_usec = st.st_mtime_nsec / 1000;
1352 #endif
1353
1354 return 0;
1355 }
1356
1357 int
backup_helper_test_files()1358 backup_helper_test_files()
1359 {
1360 int err;
1361 int oldSnapshotFD;
1362 int dataStreamFD;
1363 int newSnapshotFD;
1364
1365 system("rm -r " SCRATCH_DIR);
1366 mkdir(SCRATCH_DIR, 0777);
1367 mkdir(SCRATCH_DIR "data", 0777);
1368
1369 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1370 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1371 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1372 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1373 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1374 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1375
1376 char const* files_before[] = {
1377 SCRATCH_DIR "data/b",
1378 SCRATCH_DIR "data/c",
1379 SCRATCH_DIR "data/d",
1380 SCRATCH_DIR "data/e",
1381 SCRATCH_DIR "data/f"
1382 };
1383
1384 char const* keys_before[] = {
1385 "data/b",
1386 "data/c",
1387 "data/d",
1388 "data/e",
1389 "data/f"
1390 };
1391
1392 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1393 if (dataStreamFD == -1) {
1394 fprintf(stderr, "error creating: %s\n", strerror(errno));
1395 return errno;
1396 }
1397
1398 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1399 if (newSnapshotFD == -1) {
1400 fprintf(stderr, "error creating: %s\n", strerror(errno));
1401 return errno;
1402 }
1403
1404 {
1405 BackupDataWriter dataStream(dataStreamFD);
1406
1407 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
1408 if (err != 0) {
1409 return err;
1410 }
1411 }
1412
1413 close(dataStreamFD);
1414 close(newSnapshotFD);
1415
1416 sleep(3);
1417
1418 struct timeval d_times[2];
1419 struct timeval e_times[2];
1420
1421 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1422 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1423 if (err != 0) {
1424 return err;
1425 }
1426
1427 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1428 unlink(SCRATCH_DIR "data/c");
1429 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1430 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1431 utimes(SCRATCH_DIR "data/d", d_times);
1432 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1433 utimes(SCRATCH_DIR "data/e", e_times);
1434 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1435 unlink(SCRATCH_DIR "data/f");
1436
1437 char const* files_after[] = {
1438 SCRATCH_DIR "data/a", // added
1439 SCRATCH_DIR "data/b", // same
1440 SCRATCH_DIR "data/c", // different mod time
1441 SCRATCH_DIR "data/d", // different size (same mod time)
1442 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1443 SCRATCH_DIR "data/g" // added
1444 };
1445
1446 char const* keys_after[] = {
1447 "data/a", // added
1448 "data/b", // same
1449 "data/c", // different mod time
1450 "data/d", // different size (same mod time)
1451 "data/e", // different contents (same mod time, same size)
1452 "data/g" // added
1453 };
1454
1455 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1456 if (oldSnapshotFD == -1) {
1457 fprintf(stderr, "error opening: %s\n", strerror(errno));
1458 return errno;
1459 }
1460
1461 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1462 if (dataStreamFD == -1) {
1463 fprintf(stderr, "error creating: %s\n", strerror(errno));
1464 return errno;
1465 }
1466
1467 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1468 if (newSnapshotFD == -1) {
1469 fprintf(stderr, "error creating: %s\n", strerror(errno));
1470 return errno;
1471 }
1472
1473 {
1474 BackupDataWriter dataStream(dataStreamFD);
1475
1476 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
1477 if (err != 0) {
1478 return err;
1479 }
1480 }
1481
1482 close(oldSnapshotFD);
1483 close(dataStreamFD);
1484 close(newSnapshotFD);
1485
1486 return 0;
1487 }
1488
1489 int
backup_helper_test_null_base()1490 backup_helper_test_null_base()
1491 {
1492 int err;
1493 int oldSnapshotFD;
1494 int dataStreamFD;
1495 int newSnapshotFD;
1496
1497 system("rm -r " SCRATCH_DIR);
1498 mkdir(SCRATCH_DIR, 0777);
1499 mkdir(SCRATCH_DIR "data", 0777);
1500
1501 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1502
1503 char const* files[] = {
1504 SCRATCH_DIR "data/a",
1505 };
1506
1507 char const* keys[] = {
1508 "a",
1509 };
1510
1511 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1512 if (dataStreamFD == -1) {
1513 fprintf(stderr, "error creating: %s\n", strerror(errno));
1514 return errno;
1515 }
1516
1517 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1518 if (newSnapshotFD == -1) {
1519 fprintf(stderr, "error creating: %s\n", strerror(errno));
1520 return errno;
1521 }
1522
1523 {
1524 BackupDataWriter dataStream(dataStreamFD);
1525
1526 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1527 if (err != 0) {
1528 return err;
1529 }
1530 }
1531
1532 close(dataStreamFD);
1533 close(newSnapshotFD);
1534
1535 return 0;
1536 }
1537
1538 int
backup_helper_test_missing_file()1539 backup_helper_test_missing_file()
1540 {
1541 int err;
1542 int oldSnapshotFD;
1543 int dataStreamFD;
1544 int newSnapshotFD;
1545
1546 system("rm -r " SCRATCH_DIR);
1547 mkdir(SCRATCH_DIR, 0777);
1548 mkdir(SCRATCH_DIR "data", 0777);
1549
1550 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1551
1552 char const* files[] = {
1553 SCRATCH_DIR "data/a",
1554 SCRATCH_DIR "data/b",
1555 SCRATCH_DIR "data/c",
1556 };
1557
1558 char const* keys[] = {
1559 "a",
1560 "b",
1561 "c",
1562 };
1563
1564 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1565 if (dataStreamFD == -1) {
1566 fprintf(stderr, "error creating: %s\n", strerror(errno));
1567 return errno;
1568 }
1569
1570 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1571 if (newSnapshotFD == -1) {
1572 fprintf(stderr, "error creating: %s\n", strerror(errno));
1573 return errno;
1574 }
1575
1576 {
1577 BackupDataWriter dataStream(dataStreamFD);
1578
1579 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1580 if (err != 0) {
1581 return err;
1582 }
1583 }
1584
1585 close(dataStreamFD);
1586 close(newSnapshotFD);
1587
1588 return 0;
1589 }
1590
1591
1592 #endif // TEST_BACKUP_HELPERS
1593
1594 }
1595