v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.git] / tools / firmware-utils / src / mkdlinkfw-lib.c
1 /*
2  * mkdlinkfw
3  *
4  * Copyright (C) 2018 PaweÅ‚ Dembicki <paweldembicki@gmail.com>
5  *
6  * This tool is based on mktplinkfw.
7  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
8  * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <unistd.h>             /* for unlink() */
21 #include <libgen.h>
22 #include <getopt.h>             /* for getopt() */
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <endian.h>
26 #include <errno.h>
27 #include <time.h>
28 #include <sys/stat.h>
29 #include <zlib.h>               /*for crc32 */
30
31 #include "mkdlinkfw-lib.h"
32
33 extern char *progname;
34
35 static unsigned char jffs2_eof_mark[4] = { 0xde, 0xad, 0xc0, 0xde };
36
37 uint32_t jboot_timestamp(void)
38 {
39         time_t rawtime;
40         time(&rawtime);
41         return (((uint32_t) rawtime) - TIMESTAMP_MAGIC) >> 2;
42 }
43
44 uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size)
45 {
46         uint32_t counter = start_val;
47         uint16_t *ptr = data;
48
49         while (size > 1) {
50                 counter += *ptr;
51                 ++ptr;
52                 while (counter >> 16)
53                         counter = (uint16_t) counter + (counter >> 16);
54                 size -= 2;
55         }
56         if (size > 0) {
57                 counter += *(uint8_t *) ptr;
58                 counter -= 0xFF;
59         }
60         while (counter >> 16)
61                 counter = (uint16_t) counter + (counter >> 16);
62         return counter;
63 }
64
65 int get_file_stat(struct file_info *fdata)
66 {
67         struct stat st;
68         int res;
69
70         if (fdata->file_name == NULL)
71                 return 0;
72
73         res = stat(fdata->file_name, &st);
74         if (res) {
75                 ERRS("stat failed on %s", fdata->file_name);
76                 return res;
77         }
78
79         fdata->file_size = st.st_size;
80         return 0;
81 }
82
83 int read_to_buf(const struct file_info *fdata, char *buf)
84 {
85         FILE *f;
86         int ret = EXIT_FAILURE;
87
88         f = fopen(fdata->file_name, "r");
89         if (f == NULL) {
90                 ERRS("could not open \"%s\" for reading", fdata->file_name);
91                 goto out;
92         }
93
94         errno = 0;
95         fread(buf, fdata->file_size, 1, f);
96         if (errno != 0) {
97                 ERRS("unable to read from file \"%s\"", fdata->file_name);
98                 goto out_close;
99         }
100
101         ret = EXIT_SUCCESS;
102
103  out_close:
104         fclose(f);
105  out:
106         return ret;
107 }
108
109 int pad_jffs2(char *buf, int currlen, int maxlen)
110 {
111         int len;
112         uint32_t pad_mask;
113
114         len = currlen;
115         pad_mask = (4 * 1024) | (64 * 1024);    /* EOF at 4KB and at 64KB */
116         while ((len < maxlen) && (pad_mask != 0)) {
117                 uint32_t mask;
118                 int i;
119
120                 for (i = 10; i < 32; i++) {
121                         mask = 1 << i;
122                         if (pad_mask & mask)
123                                 break;
124                 }
125
126                 len = ALIGN(len, mask);
127
128                 for (i = 10; i < 32; i++) {
129                         mask = 1 << i;
130                         if ((len & (mask - 1)) == 0)
131                                 pad_mask &= ~mask;
132                 }
133
134                 for (i = 0; i < sizeof(jffs2_eof_mark); i++)
135                         buf[len + i] = jffs2_eof_mark[i];
136
137                 len += sizeof(jffs2_eof_mark);
138         }
139
140         return len;
141 }
142
143 int write_fw(const char *ofname, const char *data, int len)
144 {
145         FILE *f;
146         int ret = EXIT_FAILURE;
147
148         f = fopen(ofname, "w");
149         if (f == NULL) {
150                 ERRS("could not open \"%s\" for writing", ofname);
151                 goto out;
152         }
153
154         errno = 0;
155         fwrite(data, len, 1, f);
156         if (errno) {
157                 ERRS("unable to write output file");
158                 goto out_flush;
159         }
160
161         DBG("firmware file \"%s\" completed", ofname);
162
163         ret = EXIT_SUCCESS;
164
165  out_flush:
166         fflush(f);
167         fclose(f);
168         if (ret != EXIT_SUCCESS)
169                 unlink(ofname);
170  out:
171         return ret;
172 }