Fix memleak
[appimagekit/gsi.git] / src / appimagetool_shared.c
blob6b74ef26d90dade0d52ae6b83fff1bc5c981a9c4
1 #include <glib.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 #include "appimage/appimage.h"
7 #include "getsection.h"
9 /* Check if a file is an AppImage. Returns the image type if it is, or -1 if it isn't */
10 int appimage_get_type(const char* path, bool verbose)
12 FILE *f = fopen(path, "rt");
13 if (f != NULL)
15 char buffer[3] = {0};
17 /* Check magic bytes at offset 8 */
18 fseek(f, 8, SEEK_SET);
19 fread(buffer, 1, 3, f);
20 fclose(f);
21 if((buffer[0] == 0x41) && (buffer[1] == 0x49) && (buffer[2] == 0x01)){
22 #ifdef STANDALONE
23 fprintf(stderr, "_________________________\n");
24 #endif
25 if(verbose){
26 fprintf(stderr, "AppImage type 1\n");
28 return 1;
29 } else if((buffer[0] == 0x41) && (buffer[1] == 0x49) && (buffer[2] == 0x02)){
30 #ifdef STANDALONE
31 fprintf(stderr, "_________________________\n");
32 #endif
33 if(verbose){
34 fprintf(stderr, "AppImage type 2\n");
36 return 2;
37 } else {
38 if((g_str_has_suffix(path,".AppImage")) || (g_str_has_suffix(path,".appimage"))) {
39 #ifdef STANDALONE
40 fprintf(stderr, "_________________________\n");
41 #endif
42 if (verbose) {
43 fprintf(stderr, "Blindly assuming AppImage type 1\n");
44 fprintf(stderr, "The author of this AppImage should embed the magic bytes, see https://github.com/AppImage/AppImageSpec\n");
46 return 1;
47 } else {
48 #ifdef STANDALONE
49 fprintf(stderr, "_________________________\n");
50 #endif
51 if(verbose){
52 fprintf(stderr, "Unrecognized file '%s'\n", path);
54 return -1;
58 return -1;
61 bool appimage_type2_digest_md5(const char* path, char* digest) {
62 // skip digest, signature and key sections in digest calculation
63 unsigned long digest_md5_offset = 0, digest_md5_length = 0;
64 if (!appimage_get_elf_section_offset_and_length(path, ".digest_md5", &digest_md5_offset, &digest_md5_length))
65 return false;
67 unsigned long signature_offset = 0, signature_length = 0;
68 if (!appimage_get_elf_section_offset_and_length(path, ".sha256_sig", &signature_offset, &signature_length))
69 return false;
71 unsigned long sig_key_offset = 0, sig_key_length = 0;
72 if (!appimage_get_elf_section_offset_and_length(path, ".sig_key", &sig_key_offset, &sig_key_length))
73 return false;
75 GChecksum *checksum = g_checksum_new(G_CHECKSUM_MD5);
77 // read file in chunks
78 static const int chunk_size = 4096;
80 FILE *fp = fopen(path, "r");
82 // determine file size
83 fseek(fp, 0L, SEEK_END);
84 const long file_size = ftell(fp);
85 rewind(fp);
87 long bytes_left = file_size;
89 // if a section spans over more than a single chunk, we need emulate null bytes in the following chunks
90 ssize_t bytes_skip_following_chunks = 0;
92 while (bytes_left > 0) {
93 char buffer[chunk_size];
95 long current_position = ftell(fp);
97 ssize_t bytes_left_this_chunk = chunk_size;
99 // first, check whether there's bytes left that need to be skipped
100 if (bytes_skip_following_chunks > 0) {
101 ssize_t bytes_skip_this_chunk = (bytes_skip_following_chunks % chunk_size == 0) ? chunk_size : (bytes_skip_following_chunks % chunk_size);
102 bytes_left_this_chunk -= bytes_skip_this_chunk;
104 // we could just set it to 0 here, but it makes more sense to use -= for debugging
105 bytes_skip_following_chunks -= bytes_skip_this_chunk;
107 // make sure to skip these bytes in the file
108 fseek(fp, bytes_skip_this_chunk, SEEK_CUR);
111 // check whether there's a section in this chunk that we need to skip
112 if (digest_md5_offset != 0 && digest_md5_length != 0 && digest_md5_offset - current_position > 0 && digest_md5_offset - current_position < chunk_size) {
113 ssize_t begin_of_section = (digest_md5_offset - current_position) % chunk_size;
114 // read chunk before section
115 fread(buffer, sizeof(char), (size_t) begin_of_section, fp);
117 bytes_left_this_chunk -= begin_of_section;
118 bytes_left_this_chunk -= digest_md5_length;
120 // if bytes_left is now < 0, the section exceeds the current chunk
121 // this amount of bytes needs to be skipped in the future sections
122 if (bytes_left_this_chunk < 0) {
123 bytes_skip_following_chunks = (size_t) (-1 * bytes_left_this_chunk);
124 bytes_left_this_chunk = 0;
127 // if there's bytes left to read, we need to seek the difference between chunk's end and bytes_left
128 fseek(fp, (chunk_size - bytes_left_this_chunk - begin_of_section), SEEK_CUR);
131 // check whether there's a section in this chunk that we need to skip
132 if (signature_offset != 0 && signature_length != 0 && signature_offset - current_position > 0 && signature_offset - current_position < chunk_size) {
133 ssize_t begin_of_section = (signature_offset - current_position) % chunk_size;
134 // read chunk before section
135 fread(buffer, sizeof(char), (size_t) begin_of_section, fp);
137 bytes_left_this_chunk -= begin_of_section;
138 bytes_left_this_chunk -= signature_length;
140 // if bytes_left is now < 0, the section exceeds the current chunk
141 // this amount of bytes needs to be skipped in the future sections
142 if (bytes_left_this_chunk < 0) {
143 bytes_skip_following_chunks = (size_t) (-1 * bytes_left_this_chunk);
144 bytes_left_this_chunk = 0;
147 // if there's bytes left to read, we need to seek the difference between chunk's end and bytes_left
148 fseek(fp, (chunk_size - bytes_left_this_chunk - begin_of_section), SEEK_CUR);
151 // check whether there's a section in this chunk that we need to skip
152 if (sig_key_offset != 0 && sig_key_length != 0 && sig_key_offset - current_position > 0 && sig_key_offset - current_position < chunk_size) {
153 ssize_t begin_of_section = (sig_key_offset - current_position) % chunk_size;
154 // read chunk before section
155 fread(buffer, sizeof(char), (size_t) begin_of_section, fp);
157 bytes_left_this_chunk -= begin_of_section;
158 bytes_left_this_chunk -= sig_key_length;
160 // if bytes_left is now < 0, the section exceeds the current chunk
161 // this amount of bytes needs to be skipped in the future sections
162 if (bytes_left_this_chunk < 0) {
163 bytes_skip_following_chunks = (size_t) (-1 * bytes_left_this_chunk);
164 bytes_left_this_chunk = 0;
167 // if there's bytes left to read, we need to seek the difference between chunk's end and bytes_left
168 fseek(fp, (chunk_size - bytes_left_this_chunk - begin_of_section), SEEK_CUR);
171 // check whether we're done already
172 if (bytes_left_this_chunk > 0) {
173 // read data from file into buffer with the correct offset in case bytes have to be skipped
174 fread(buffer + (chunk_size - bytes_left_this_chunk), sizeof(char), (size_t) bytes_left_this_chunk, fp);
177 // feed buffer into checksum calculation
178 g_checksum_update(checksum, (const guchar*) buffer, chunk_size);
180 bytes_left -= chunk_size;
183 gsize digest_len = 16;
184 g_checksum_get_digest(checksum, (guint8*) digest, &digest_len);
186 fclose(fp);
188 return true;
191 char* appimage_hexlify(const char* bytes, const size_t numBytes) {
192 // first of all, allocate the new string
193 // a hexadecimal representation works like "every byte will be represented by two chars"
194 // additionally, we need to null-terminate the string
195 char* hexlified = (char*) calloc((2 * numBytes + 1), sizeof(char));
197 for (size_t i = 0; i < numBytes; i++) {
198 char buffer[3];
199 sprintf(buffer, "%02x", (unsigned char) bytes[i]);
200 strcat(hexlified, buffer);
203 return hexlified;