blob: 1fa6a0f02ae9a910ffa897c70c9c304d529c5395 [file] [log] [blame]
Joe Onorato4535e402009-05-15 09:07:06 -04001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joe Onorato3ad977b2009-05-05 11:50:51 -070017#define LOG_TAG "file_backup_helper"
18
19#include <utils/backup_helpers.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 <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
Joe Onoratoc825d3e2009-05-06 12:55:46 -040032#include <utime.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070033#include <fcntl.h>
34#include <zlib.h>
35
36#include <cutils/log.h>
37
Joe Onorato4535e402009-05-15 09:07:06 -040038namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070039
40#define MAGIC0 0x70616e53 // Snap
41#define MAGIC1 0x656c6946 // File
42
Joe Onorato4535e402009-05-15 09:07:06 -040043#if TEST_BACKUP_HELPERS
44#define LOGP(x...) printf(x)
45#else
Joe Onorato290bb012009-05-13 18:57:29 -040046#define LOGP(x...) LOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040047#endif
Joe Onorato290bb012009-05-13 18:57:29 -040048
Joe Onorato3ad977b2009-05-05 11:50:51 -070049struct SnapshotHeader {
50 int magic0;
51 int fileCount;
52 int magic1;
53 int totalSize;
54};
55
56struct FileState {
57 int modTime_sec;
58 int modTime_nsec;
59 int size;
60 int crc32;
61 int nameLen;
62};
63
64const static int ROUND_UP[4] = { 0, 3, 2, 1 };
65
66static inline int
67round_up(int n)
68{
69 return n + ROUND_UP[n % 4];
70}
71
72static int
73read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
74{
75 int bytesRead = 0;
76 int amt;
77 SnapshotHeader header;
78
79 amt = read(fd, &header, sizeof(header));
80 if (amt != sizeof(header)) {
81 return errno;
82 }
83 bytesRead += amt;
84
85 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
86 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
87 return 1;
88 }
89
90 for (int i=0; i<header.fileCount; i++) {
91 FileState file;
92 char filenameBuf[128];
93
94 amt = read(fd, &file, sizeof(file));
95 if (amt != sizeof(file)) {
96 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
97 return 1;
98 }
99 bytesRead += amt;
100
101 // filename is not NULL terminated, but it is padded
102 int nameBufSize = round_up(file.nameLen);
103 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
104 ? filenameBuf
105 : (char*)malloc(nameBufSize);
106 amt = read(fd, filename, nameBufSize);
107 if (amt == nameBufSize) {
108 snapshot->add(String8(filename, file.nameLen), file);
109 }
110 bytesRead += amt;
111 if (filename != filenameBuf) {
112 free(filename);
113 }
114 if (amt != nameBufSize) {
115 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
116 return 1;
117 }
118 }
119
120 if (header.totalSize != bytesRead) {
121 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
122 header.totalSize, bytesRead);
123 return 1;
124 }
125
126 return 0;
127}
128
129static int
130write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
131{
132 int bytesWritten = sizeof(SnapshotHeader);
133 // preflight size
134 const int N = snapshot.size();
135 for (int i=0; i<N; i++) {
136 const String8& name = snapshot.keyAt(i);
137 bytesWritten += sizeof(FileState) + round_up(name.length());
138 }
139
Joe Onorato4535e402009-05-15 09:07:06 -0400140 LOGP("write_snapshot_file fd=%d\n", fd);
141
Joe Onorato3ad977b2009-05-05 11:50:51 -0700142 int amt;
143 SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
144
145 amt = write(fd, &header, sizeof(header));
146 if (amt != sizeof(header)) {
147 LOGW("write_snapshot_file error writing header %s", strerror(errno));
148 return errno;
149 }
150
151 for (int i=0; i<header.fileCount; i++) {
152 const String8& name = snapshot.keyAt(i);
153 FileState file = snapshot.valueAt(i);
154 int nameLen = file.nameLen = name.length();
155
156 amt = write(fd, &file, sizeof(file));
157 if (amt != sizeof(file)) {
158 LOGW("write_snapshot_file error writing header %s", strerror(errno));
159 return 1;
160 }
161
162 // filename is not NULL terminated, but it is padded
163 amt = write(fd, name.string(), nameLen);
164 if (amt != nameLen) {
165 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
166 return 1;
167 }
168 int paddingLen = ROUND_UP[nameLen % 4];
169 if (paddingLen != 0) {
170 int padding = 0xabababab;
171 amt = write(fd, &padding, paddingLen);
172 if (amt != paddingLen) {
173 LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
174 paddingLen, strerror(errno));
175 return 1;
176 }
177 }
178 }
179
180 return 0;
181}
182
183static int
184write_delete_file(const String8& key)
185{
Joe Onorato290bb012009-05-13 18:57:29 -0400186 LOGP("write_delete_file %s\n", key.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700187 return 0;
188}
189
190static int
191write_update_file(const String8& realFilename, const String8& key)
192{
Joe Onorato290bb012009-05-13 18:57:29 -0400193 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700194 return 0;
195}
196
197static int
198compute_crc32(const String8& filename)
199{
200 const int bufsize = 4*1024;
201 int amt;
202
203 int fd = open(filename.string(), O_RDONLY);
204 if (fd == -1) {
205 return -1;
206 }
207
208 char* buf = (char*)malloc(bufsize);
209 int crc = crc32(0L, Z_NULL, 0);
210
211 while ((amt = read(fd, buf, bufsize)) != 0) {
212 crc = crc32(crc, (Bytef*)buf, amt);
213 }
214
215 close(fd);
216 free(buf);
217
218 return crc;
219}
220
221int
Joe Onorato290bb012009-05-13 18:57:29 -0400222back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
Joe Onorato3ad977b2009-05-05 11:50:51 -0700223 char const* fileBase, char const* const* files, int fileCount)
224{
225 int err;
226 const String8 base(fileBase);
227 KeyedVector<String8,FileState> oldSnapshot;
228 KeyedVector<String8,FileState> newSnapshot;
229
230 if (oldSnapshotFD != -1) {
231 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
232 if (err != 0) {
233 // On an error, treat this as a full backup.
234 oldSnapshot.clear();
235 }
236 }
237
238 for (int i=0; i<fileCount; i++) {
239 String8 name(files[i]);
240 FileState s;
241 struct stat st;
242 String8 realFilename(base);
243 realFilename.appendPath(name);
244
245 err = stat(realFilename.string(), &st);
246 if (err != 0) {
247 LOGW("Error stating file %s", realFilename.string());
248 continue;
249 }
250
251 s.modTime_sec = st.st_mtime;
Joe Onoratoc825d3e2009-05-06 12:55:46 -0400252 s.modTime_nsec = 0; // workaround sim breakage
253 //s.modTime_nsec = st.st_mtime_nsec;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700254 s.size = st.st_size;
255 s.crc32 = compute_crc32(realFilename);
256
257 newSnapshot.add(name, s);
258 }
259
260 int n = 0;
261 int N = oldSnapshot.size();
262 int m = 0;
263
264 while (n<N && m<fileCount) {
265 const String8& p = oldSnapshot.keyAt(n);
266 const String8& q = newSnapshot.keyAt(m);
267 int cmp = p.compare(q);
268 if (cmp > 0) {
269 // file added
270 String8 realFilename(base);
271 realFilename.appendPath(q);
Joe Onorato4535e402009-05-15 09:07:06 -0400272 LOGP("file added: %s\n", realFilename.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700273 write_update_file(realFilename, q);
274 m++;
275 }
276 else if (cmp < 0) {
277 // file removed
Joe Onorato4535e402009-05-15 09:07:06 -0400278 LOGP("file removed: %s\n", p.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700279 write_delete_file(p);
280 n++;
281 }
282 else {
283 // both files exist, check them
284 String8 realFilename(base);
285 realFilename.appendPath(q);
286 const FileState& f = oldSnapshot.valueAt(n);
287 const FileState& g = newSnapshot.valueAt(m);
288
Joe Onorato290bb012009-05-13 18:57:29 -0400289 LOGP("%s\n", q.string());
290 LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700291 f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
Joe Onorato290bb012009-05-13 18:57:29 -0400292 LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700293 g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
294 if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
295 || f.size != g.size || f.crc32 != g.crc32) {
296 write_update_file(realFilename, p);
297 }
298 n++;
299 m++;
300 }
301 }
302
303 // these were deleted
304 while (n<N) {
305 write_delete_file(oldSnapshot.keyAt(n));
306 n++;
307 }
308
309 // these were added
310 while (m<fileCount) {
311 const String8& q = newSnapshot.keyAt(m);
312 String8 realFilename(base);
313 realFilename.appendPath(q);
314 write_update_file(realFilename, q);
315 m++;
316 }
317
318 err = write_snapshot_file(newSnapshotFD, newSnapshot);
319
320 return 0;
321}
322
323#if TEST_BACKUP_HELPERS
324
325#define SCRATCH_DIR "/data/backup_helper_test/"
326
327static int
328write_text_file(const char* path, const char* data)
329{
330 int amt;
331 int fd;
332 int len;
333
334 fd = creat(path, 0666);
335 if (fd == -1) {
336 fprintf(stderr, "creat %s failed\n", path);
337 return errno;
338 }
339
340 len = strlen(data);
341 amt = write(fd, data, len);
342 if (amt != len) {
343 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
344 return errno;
345 }
346
347 close(fd);
348
349 return 0;
350}
351
352static int
353compare_file(const char* path, const unsigned char* data, int len)
354{
355 int fd;
356 int amt;
357
358 fd = open(path, O_RDONLY);
359 if (fd == -1) {
360 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
361 return errno;
362 }
363
364 unsigned char* contents = (unsigned char*)malloc(len);
365 if (contents == NULL) {
366 fprintf(stderr, "malloc(%d) failed\n", len);
367 return ENOMEM;
368 }
369
370 bool sizesMatch = true;
371 amt = lseek(fd, 0, SEEK_END);
372 if (amt != len) {
373 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
374 sizesMatch = false;
375 }
376 lseek(fd, 0, SEEK_SET);
377
378 int readLen = amt < len ? amt : len;
379 amt = read(fd, contents, readLen);
380 if (amt != readLen) {
381 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
382 }
383
384 bool contentsMatch = true;
385 for (int i=0; i<readLen; i++) {
386 if (data[i] != contents[i]) {
387 if (contentsMatch) {
388 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
389 contentsMatch = false;
390 }
391 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
392 }
393 }
394
395 return contentsMatch && sizesMatch ? 0 : 1;
396}
397
398int
399backup_helper_test_empty()
400{
401 int err;
402 int fd;
403 KeyedVector<String8,FileState> snapshot;
404 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
405
406 system("rm -r " SCRATCH_DIR);
407 mkdir(SCRATCH_DIR, 0777);
408
409 // write
410 fd = creat(filename, 0666);
411 if (fd == -1) {
412 fprintf(stderr, "error creating %s\n", filename);
413 return 1;
414 }
415
416 err = write_snapshot_file(fd, snapshot);
417
418 close(fd);
419
420 if (err != 0) {
421 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
422 return err;
423 }
424
425 static const unsigned char correct_data[] = {
426 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
427 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
428 };
429
430 err = compare_file(filename, correct_data, sizeof(correct_data));
431 if (err != 0) {
432 return err;
433 }
434
435 // read
436 fd = open(filename, O_RDONLY);
437 if (fd == -1) {
438 fprintf(stderr, "error opening for read %s\n", filename);
439 return 1;
440 }
441
442 KeyedVector<String8,FileState> readSnapshot;
443 err = read_snapshot_file(fd, &readSnapshot);
444 if (err != 0) {
445 fprintf(stderr, "read_snapshot_file failed %d\n", err);
446 return err;
447 }
448
449 if (readSnapshot.size() != 0) {
450 fprintf(stderr, "readSnapshot should be length 0\n");
451 return 1;
452 }
453
454 return 0;
455}
456
457int
458backup_helper_test_four()
459{
460 int err;
461 int fd;
462 KeyedVector<String8,FileState> snapshot;
463 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
464
465 system("rm -r " SCRATCH_DIR);
466 mkdir(SCRATCH_DIR, 0777);
467
468 // write
469 fd = creat(filename, 0666);
470 if (fd == -1) {
471 fprintf(stderr, "error opening %s\n", filename);
472 return 1;
473 }
474
475 String8 filenames[4];
476 FileState states[4];
477
478 states[0].modTime_sec = 0xfedcba98;
479 states[0].modTime_nsec = 0xdeadbeef;
480 states[0].size = 0xababbcbc;
481 states[0].crc32 = 0x12345678;
482 states[0].nameLen = -12;
483 filenames[0] = String8("bytes_of_padding");
484 snapshot.add(filenames[0], states[0]);
485
486 states[1].modTime_sec = 0x93400031;
487 states[1].modTime_nsec = 0xdeadbeef;
488 states[1].size = 0x88557766;
489 states[1].crc32 = 0x22334422;
490 states[1].nameLen = -1;
491 filenames[1] = String8("bytes_of_padding3");
492 snapshot.add(filenames[1], states[1]);
493
494 states[2].modTime_sec = 0x33221144;
495 states[2].modTime_nsec = 0xdeadbeef;
496 states[2].size = 0x11223344;
497 states[2].crc32 = 0x01122334;
498 states[2].nameLen = 0;
499 filenames[2] = String8("bytes_of_padding_2");
500 snapshot.add(filenames[2], states[2]);
501
502 states[3].modTime_sec = 0x33221144;
503 states[3].modTime_nsec = 0xdeadbeef;
504 states[3].size = 0x11223344;
505 states[3].crc32 = 0x01122334;
506 states[3].nameLen = 0;
507 filenames[3] = String8("bytes_of_padding__1");
508 snapshot.add(filenames[3], states[3]);
509
510 err = write_snapshot_file(fd, snapshot);
511
512 close(fd);
513
514 if (err != 0) {
515 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
516 return err;
517 }
518
519 static const unsigned char correct_data[] = {
520 // header
521 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
522 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00,
523
524 // bytes_of_padding
525 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
526 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12,
527 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
528 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
529 0x64, 0x69, 0x6e, 0x67,
530
531 // bytes_of_padding3
532 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
533 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22,
534 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
535 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
536 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab,
537
538 // bytes of padding2
539 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
540 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
541 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
542 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
543 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab,
544
545 // bytes of padding3
546 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
547 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
548 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
549 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
550 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab
551 };
552
553 err = compare_file(filename, correct_data, sizeof(correct_data));
554 if (err != 0) {
555 return err;
556 }
557
558 // read
559 fd = open(filename, O_RDONLY);
560 if (fd == -1) {
561 fprintf(stderr, "error opening for read %s\n", filename);
562 return 1;
563 }
564
565
566 KeyedVector<String8,FileState> readSnapshot;
567 err = read_snapshot_file(fd, &readSnapshot);
568 if (err != 0) {
569 fprintf(stderr, "read_snapshot_file failed %d\n", err);
570 return err;
571 }
572
573 if (readSnapshot.size() != 4) {
574 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
575 return 1;
576 }
577
578 bool matched = true;
579 for (size_t i=0; i<readSnapshot.size(); i++) {
580 const String8& name = readSnapshot.keyAt(i);
581 const FileState state = readSnapshot.valueAt(i);
582
583 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
584 || states[i].modTime_nsec != state.modTime_nsec
585 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
586 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
587 " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
588 states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
589 name.length(), filenames[i].string(),
590 state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
591 name.string());
592 matched = false;
593 }
594 }
595
596 return matched ? 0 : 1;
597}
598
Joe Onorato4535e402009-05-15 09:07:06 -0400599// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
600const unsigned char DATA_GOLDEN_FILE[] = {
601 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
602 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
603 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
604 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
605 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
606 0x6e, 0x67, 0x5f, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
607 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
608 0x41, 0x70, 0x70, 0x31, 0x0c, 0x00, 0x00, 0x00,
609 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
610 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
611 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
612 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
613 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
614 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
615 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
616 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
617 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
618 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
619 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
620 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
621 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
622 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
623 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
624 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
625 0x41, 0x70, 0x70, 0x31, 0x0a, 0x00, 0x00, 0x00,
626 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
627 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
628 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
629 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
630 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
631 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
632 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
633};
634const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
635
636static int
637test_write_header_and_entity(BackupDataWriter& writer, const char* str)
638{
639 int err;
640 String8 text(str);
641
642 err = writer.WriteAppHeader(text);
643 if (err != 0) {
644 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
645 return err;
646 }
647
648 err = writer.WriteEntityHeader(text, text.length()+1);
649 if (err != 0) {
650 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
651 return err;
652 }
653
654 err = writer.WriteEntityData(text.string(), text.length()+1);
655 if (err != 0) {
656 fprintf(stderr, "write failed for data '%s'\n", text.string());
657 return errno;
658 }
659
660 return err;
661}
662
663int
664backup_helper_test_data_writer()
665{
666 int err;
667 int fd;
668 const char* filename = SCRATCH_DIR "data_writer.data";
669
670 system("rm -r " SCRATCH_DIR);
671 mkdir(SCRATCH_DIR, 0777);
672 mkdir(SCRATCH_DIR "data", 0777);
673
674 fd = creat(filename, 0666);
675 if (fd == -1) {
676 fprintf(stderr, "error creating: %s\n", strerror(errno));
677 return errno;
678 }
679
680 BackupDataWriter writer(fd);
681
682 err = 0;
683 err |= test_write_header_and_entity(writer, "no_padding_");
684 err |= test_write_header_and_entity(writer, "padded_to__3");
685 err |= test_write_header_and_entity(writer, "padded_to_2__");
686 err |= test_write_header_and_entity(writer, "padded_to1");
687
688 writer.WriteAppFooter();
689
690 close(fd);
691
692 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
693 if (err != 0) {
694 return err;
695 }
696
697 return err;
698}
699
Joe Onorato3ad977b2009-05-05 11:50:51 -0700700static int
701get_mod_time(const char* filename, struct timeval times[2])
702{
703 int err;
704 struct stat64 st;
705 err = stat64(filename, &st);
706 if (err != 0) {
707 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
708 return errno;
709 }
710 times[0].tv_sec = st.st_atime;
711 times[0].tv_usec = st.st_atime_nsec / 1000;
712 times[1].tv_sec = st.st_mtime;
713 times[1].tv_usec = st.st_mtime_nsec / 1000;
714 return 0;
715}
716
717int
718backup_helper_test_files()
719{
720 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700721 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -0400722 int dataStreamFD;
723 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700724
725 system("rm -r " SCRATCH_DIR);
726 mkdir(SCRATCH_DIR, 0777);
727 mkdir(SCRATCH_DIR "data", 0777);
728
729 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
730 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
731 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
732 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
733 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
734 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
735
736 char const* files_before[] = {
737 "data/b",
738 "data/c",
739 "data/d",
740 "data/e",
741 "data/f"
742 };
743
Joe Onorato4535e402009-05-15 09:07:06 -0400744 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
745 if (dataStreamFD == -1) {
746 fprintf(stderr, "error creating: %s\n", strerror(errno));
747 return errno;
748 }
749
Joe Onorato3ad977b2009-05-05 11:50:51 -0700750 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
751 if (newSnapshotFD == -1) {
752 fprintf(stderr, "error creating: %s\n", strerror(errno));
753 return errno;
754 }
Joe Onorato4535e402009-05-15 09:07:06 -0400755
756 err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700757 if (err != 0) {
758 return err;
759 }
760
Joe Onorato4535e402009-05-15 09:07:06 -0400761 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700762 close(newSnapshotFD);
763
764 sleep(3);
765
766 struct timeval d_times[2];
767 struct timeval e_times[2];
768
769 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
770 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
771 if (err != 0) {
772 return err;
773 }
774
775 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
776 unlink(SCRATCH_DIR "data/c");
777 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
778 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
779 utimes(SCRATCH_DIR "data/d", d_times);
780 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
781 utimes(SCRATCH_DIR "data/e", e_times);
782 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
783 unlink(SCRATCH_DIR "data/f");
784
785 char const* files_after[] = {
786 "data/a", // added
787 "data/b", // same
788 "data/c", // different mod time
789 "data/d", // different size (same mod time)
790 "data/e", // different contents (same mod time, same size)
791 "data/g" // added
792 };
793
794 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
795 if (oldSnapshotFD == -1) {
796 fprintf(stderr, "error opening: %s\n", strerror(errno));
797 return errno;
798 }
799
Joe Onorato4535e402009-05-15 09:07:06 -0400800 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
801 if (dataStreamFD == -1) {
802 fprintf(stderr, "error creating: %s\n", strerror(errno));
803 return errno;
804 }
805
Joe Onorato3ad977b2009-05-05 11:50:51 -0700806 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
807 if (newSnapshotFD == -1) {
808 fprintf(stderr, "error creating: %s\n", strerror(errno));
809 return errno;
810 }
811
Joe Onorato4535e402009-05-15 09:07:06 -0400812 err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700813 if (err != 0) {
814 return err;
815 }
816
817 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -0400818 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700819 close(newSnapshotFD);
820
821 return 0;
822}
823
824#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -0400825
826}