1de807f2ed8af63a75174933c13705a7529a82914Geremy Condra/*
2de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * Copyright (C) 2013 The Android Open Source Project
3de807f2ed8af63a75174933c13705a7529a82914Geremy Condra *
4de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * Licensed under the Apache License, Version 2.0 (the "License");
5de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * you may not use this file except in compliance with the License.
6de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * You may obtain a copy of the License at
7de807f2ed8af63a75174933c13705a7529a82914Geremy Condra *
8de807f2ed8af63a75174933c13705a7529a82914Geremy Condra *      http://www.apache.org/licenses/LICENSE-2.0
9de807f2ed8af63a75174933c13705a7529a82914Geremy Condra *
10de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * Unless required by applicable law or agreed to in writing, software
11de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * distributed under the License is distributed on an "AS IS" BASIS,
12de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * See the License for the specific language governing permissions and
14de807f2ed8af63a75174933c13705a7529a82914Geremy Condra * limitations under the License.
15de807f2ed8af63a75174933c13705a7529a82914Geremy Condra */
16de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
17de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#define _FILE_OFFSET_BITS 64
18de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#define _LARGEFILE64_SOURCE 1
190e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross#define _GNU_SOURCE
20de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
21de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <errno.h>
22de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <fcntl.h>
23de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <stdio.h>
24de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <stdlib.h>
25de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <string.h>
26de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <unistd.h>
27de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
28de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include <sparse/sparse.h>
29de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include "sparse_file.h"
30de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#include "backed_block.h"
31de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
32de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#ifndef O_BINARY
33de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#define O_BINARY 0
34de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#endif
35de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
36de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#if defined(__APPLE__) && defined(__MACH__)
37de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#define lseek64 lseek
38de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#endif
39de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#if defined(__APPLE__) && defined(__MACH__)
40de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#define lseek64 lseek
41de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#define off64_t off_t
42de807f2ed8af63a75174933c13705a7529a82914Geremy Condra#endif
43de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
44de807f2ed8af63a75174933c13705a7529a82914Geremy Condravoid usage()
45de807f2ed8af63a75174933c13705a7529a82914Geremy Condra{
46de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    fprintf(stderr, "Usage: append2simg <output> <input>\n");
47de807f2ed8af63a75174933c13705a7529a82914Geremy Condra}
48de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
49de807f2ed8af63a75174933c13705a7529a82914Geremy Condraint main(int argc, char *argv[])
50de807f2ed8af63a75174933c13705a7529a82914Geremy Condra{
51de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    int output;
52de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    int output_block;
53de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    char *output_path;
54de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    struct sparse_file *sparse_output;
55de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
56de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    int input;
57de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    char *input_path;
58de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    off64_t input_len;
59de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
600e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    int tmp_fd;
610e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    char *tmp_path;
620e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
630e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    int ret;
640e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
65de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    if (argc == 3) {
66de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        output_path = argv[1];
67de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        input_path = argv[2];
68de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    } else {
69de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        usage();
70de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
71de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
72de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
730e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    ret = asprintf(&tmp_path, "%s.append2simg", output_path);
740e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    if (ret < 0) {
750e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross        fprintf(stderr, "Couldn't allocate filename\n");
760e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross        exit(-1);
770e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    }
780e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
79de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    output = open(output_path, O_RDWR | O_BINARY);
80de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    if (output < 0) {
81de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
82de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
83de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
84de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
85de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    sparse_output = sparse_file_import_auto(output, true);
86de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    if (!sparse_output) {
87de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Couldn't import output file\n");
88de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
89de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
90de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
91de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    input = open(input_path, O_RDONLY | O_BINARY);
92de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    if (input < 0) {
93de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
94de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
95de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
96de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
97de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    input_len = lseek64(input, 0, SEEK_END);
98de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    if (input_len < 0) {
99de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
100de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
101de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    } else if (input_len % sparse_output->block_size) {
102de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Input file is not a multiple of the output file's block size");
103de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
104de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
105de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    lseek64(input, 0, SEEK_SET);
106de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
107de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    output_block = sparse_output->len / sparse_output->block_size;
108de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
109de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Couldn't add input file\n");
110de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
111de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
112de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    sparse_output->len += input_len;
113de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
1140e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
1150e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    if (tmp_fd < 0) {
1160e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross        fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
1170e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross        exit(-1);
1180e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    }
1190e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
120de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    lseek64(output, 0, SEEK_SET);
1210e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
122de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        fprintf(stderr, "Failed to write sparse file\n");
123de807f2ed8af63a75174933c13705a7529a82914Geremy Condra        exit(-1);
124de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    }
125de807f2ed8af63a75174933c13705a7529a82914Geremy Condra
126de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    sparse_file_destroy(sparse_output);
1270e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    close(tmp_fd);
128de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    close(output);
129de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    close(input);
1300e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
1310e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    ret = rename(tmp_path, output_path);
1320e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    if (ret < 0) {
1330e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross        fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
1340e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross        exit(-1);
1350e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    }
1360e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
1370e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross    free(tmp_path);
1380e3f47e4827a067b9b9795a3ae7297b51c9f0776Colin Cross
139de807f2ed8af63a75174933c13705a7529a82914Geremy Condra    exit(0);
140de807f2ed8af63a75174933c13705a7529a82914Geremy Condra}
141