• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3  * Licensed under the Mulan PSL v2.
4  * You can use this software according to the terms and conditions of the Mulan PSL v2.
5  * You may obtain a copy of Mulan PSL v2 at:
6  *     http://license.coscl.org.cn/MulanPSL2
7  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8  * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9  * PURPOSE.
10  * See the Mulan PSL v2 for more details.
11  */
12 
13 #include <chcore/cpio.h>
14 
15 #include <stdio.h>
16 #include <chcore/bug.h>
17 #include <chcore/defs.h>
18 #include <malloc.h>
19 #include <errno.h>
20 #include <chcore/error.h>
21 #include <string.h>
22 
23 #define kwarn               printf
24 #define cpio_info(fmt, ...) printf(fmt, ##__VA_ARGS__)
25 #define cpio_zalloc(sz)     calloc(1, sz)
26 #define cpio_free(obj)      free(obj)
27 
28 struct {
29     struct cpio_file head;
30     struct cpio_file *tail;
31 } g_files;
32 
hex8_u64(const char s[8])33 static u64 hex8_u64(const char s[8])
34 {
35     u64 u = 0;
36     for (int i = 0; i < 8; ++i) {
37         u <<= 4;
38         if (s[i] >= 'A' && s[i] <= 'F')
39             u += s[i] - 'A' + 10;
40         else
41             u += s[i] - '0';
42     }
43     return u;
44 }
45 
cpio_parse_header(const void * addr,struct cpio_header * header)46 static int cpio_parse_header(const void *addr, struct cpio_header *header)
47 {
48     const struct cpio_newc_header *newc = addr;
49 
50     // cpio_info("print in text: %s\n", addr);
51     /* headers other than newc are not supported */
52     BUG_ON(strncmp(newc->c_magic, "070701", 6));
53 
54     header->c_ino = hex8_u64(newc->c_ino);
55     header->c_mode = hex8_u64(newc->c_mode);
56     header->c_uid = hex8_u64(newc->c_uid);
57     header->c_gid = hex8_u64(newc->c_gid);
58     header->c_nlink = hex8_u64(newc->c_nlink);
59     header->c_mtime = hex8_u64(newc->c_mtime);
60     header->c_filesize = hex8_u64(newc->c_filesize);
61     header->c_devmajor = hex8_u64(newc->c_devmajor);
62     header->c_devminor = hex8_u64(newc->c_devminor);
63     header->c_rdevmajor = hex8_u64(newc->c_rdevmajor);
64     header->c_rdevminor = hex8_u64(newc->c_rdevminor);
65     header->c_namesize = hex8_u64(newc->c_namesize);
66     header->c_check = hex8_u64(newc->c_check);
67 
68     // cpio_info("header address is 0x%lx\n", (u64) header);
69     return 0;
70 }
71 
cpio_extract_file(const void * addr,const char * dirat)72 int cpio_extract_file(const void *addr, const char *dirat)
73 {
74     return 0;
75 }
76 
cpio_init_g_files(void)77 void cpio_init_g_files(void)
78 {
79     g_files.head.next = NULL;
80     g_files.tail = &g_files.head;
81 }
82 
cpio_alloc_file(void)83 static struct cpio_file *cpio_alloc_file(void)
84 {
85     return cpio_zalloc(sizeof(struct cpio_file));
86 }
87 
cpio_add_file(struct cpio_file * f)88 static void cpio_add_file(struct cpio_file *f)
89 {
90     f->next = NULL;
91     g_files.tail->next = f;
92     g_files.tail = f;
93 }
94 
cpio_free_g_files(void)95 void cpio_free_g_files(void)
96 {
97         struct cpio_file *f, *next;
98 
99         f = g_files.head.next;
100         if (f) {
101             next = f->next;
102         } else {
103             return;
104         }
105 
106         for (;;) {
107             free(f);
108             f = next;
109             if (next) {
110                 next = next->next;
111             }
112 
113             if (!f) {
114                 break;
115             }
116         }
117 
118         // to keep the list head represented by g_files
119         // consistent
120         cpio_init_g_files();
121 }
122 
cpio_extract(const void * addr,const char * dirat)123 void cpio_extract(const void *addr, const char *dirat)
124 {
125     const char *p = addr;
126     struct cpio_file *f;
127     int err;
128 
129     for (;;) {
130         f = cpio_alloc_file();
131         // printf("cpio_alloc_file returns %p\n", f);
132         if (f == NULL) {
133             kwarn("cpio_alloc_file fails due to lack of memory.\n");
134             return;
135         }
136 
137         BUG_ON(!f);
138 
139         err = cpio_parse_header(p, &f->header);
140         BUG_ON(err);
141         p += sizeof(struct cpio_newc_header);
142 
143         if (0 == strcmp(p, "TRAILER!!!")) {
144             cpio_free(f);
145             break;
146         }
147 
148         f->name = p;
149         p += f->header.c_namesize;
150         p = (void *)ALIGN4_UP(p);
151 
152         f->data = p;
153         p += f->header.c_filesize;
154         p = (void *)ALIGN4_UP(p);
155 
156         cpio_add_file(f);
157     }
158 }
159 
cpio_extract_single(const void * addr,const char * target,int (* cpio_single_file_filler)(const void * start,size_t size,void * data),void * data)160 int cpio_extract_single(const void *addr, const char *target,
161                         int (*cpio_single_file_filler)(const void *start,
162                                                        size_t size, void *data),
163                         void *data)
164 {
165     const char *p = addr;
166     struct cpio_header header;
167     const char *filename;
168 
169     /* Skip leading '/' */
170     target = target + 1;
171 
172     for (;;) {
173         int err;
174 
175         err = cpio_parse_header(p, &header);
176         BUG_ON(err);
177         p += sizeof(struct cpio_newc_header);
178 
179         if (0 == strcmp(p, "TRAILER!!!"))
180             break;
181 
182         filename = p;
183         p += header.c_namesize;
184         p = (void *)ALIGN4_UP(p);
185 
186         if (0 == strcmp(filename, target)) {
187             return cpio_single_file_filler(p, header.c_filesize, data);
188         }
189 
190         p += header.c_filesize;
191         p = (void *)ALIGN4_UP(p);
192     }
193     return -ENOENT;
194 }
195