diff options
Diffstat (limited to 'utils/ypr0tools')
21 files changed, 2939 insertions, 0 deletions
diff --git a/utils/ypr0tools/Makefile b/utils/ypr0tools/Makefile new file mode 100644 index 0000000000..efc1de63f2 --- /dev/null +++ b/utils/ypr0tools/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | |||
2 | .PHONY: all clean | ||
3 | PROGS = extract_section | ||
4 | CC = gcc | ||
5 | CFLAGS = -O1 -g -W -Wall | ||
6 | |||
7 | |||
8 | all: $(PROGS) | ||
9 | $(MAKE) -C cramfs-1.1 | ||
10 | |||
11 | clean: | ||
12 | $(MAKE) -C cramfs-1.1 clean | ||
13 | rm -f extract_section | ||
diff --git a/utils/ypr0tools/MuonEncrypt b/utils/ypr0tools/MuonEncrypt new file mode 100755 index 0000000000..b1bc124523 --- /dev/null +++ b/utils/ypr0tools/MuonEncrypt | |||
Binary files differ | |||
diff --git a/utils/ypr0tools/README b/utils/ypr0tools/README new file mode 100644 index 0000000000..45777dd8c5 --- /dev/null +++ b/utils/ypr0tools/README | |||
@@ -0,0 +1,12 @@ | |||
1 | |||
2 | To generate a firmware, run (paths may differ): | ||
3 | |||
4 | $ make | ||
5 | $ ./unpack-firmware.sh R0.ROM /tmp/romfiles | ||
6 | $ sudo ./patch-firmware.sh files /tmp/romfiles # needs sudo | ||
7 | $ ./pack-firmware.sh R0.ROM /tmp/romfiles | ||
8 | |||
9 | After that, R0.ROM is patched and can load Rockbox. | ||
10 | |||
11 | rockbox.sh is a script to put into rockbox.zip. It's a small loader script | ||
12 | that sets stuff up. | ||
diff --git a/utils/ypr0tools/cramfs-1.1/COPYING b/utils/ypr0tools/cramfs-1.1/COPYING new file mode 100644 index 0000000000..5b6e7c66c2 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/COPYING | |||
@@ -0,0 +1,340 @@ | |||
1 | GNU GENERAL PUBLIC LICENSE | ||
2 | Version 2, June 1991 | ||
3 | |||
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||
5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
6 | Everyone is permitted to copy and distribute verbatim copies | ||
7 | of this license document, but changing it is not allowed. | ||
8 | |||
9 | Preamble | ||
10 | |||
11 | The licenses for most software are designed to take away your | ||
12 | freedom to share and change it. By contrast, the GNU General Public | ||
13 | License is intended to guarantee your freedom to share and change free | ||
14 | software--to make sure the software is free for all its users. This | ||
15 | General Public License applies to most of the Free Software | ||
16 | Foundation's software and to any other program whose authors commit to | ||
17 | using it. (Some other Free Software Foundation software is covered by | ||
18 | the GNU Library General Public License instead.) You can apply it to | ||
19 | your programs, too. | ||
20 | |||
21 | When we speak of free software, we are referring to freedom, not | ||
22 | price. Our General Public Licenses are designed to make sure that you | ||
23 | have the freedom to distribute copies of free software (and charge for | ||
24 | this service if you wish), that you receive source code or can get it | ||
25 | if you want it, that you can change the software or use pieces of it | ||
26 | in new free programs; and that you know you can do these things. | ||
27 | |||
28 | To protect your rights, we need to make restrictions that forbid | ||
29 | anyone to deny you these rights or to ask you to surrender the rights. | ||
30 | These restrictions translate to certain responsibilities for you if you | ||
31 | distribute copies of the software, or if you modify it. | ||
32 | |||
33 | For example, if you distribute copies of such a program, whether | ||
34 | gratis or for a fee, you must give the recipients all the rights that | ||
35 | you have. You must make sure that they, too, receive or can get the | ||
36 | source code. And you must show them these terms so they know their | ||
37 | rights. | ||
38 | |||
39 | We protect your rights with two steps: (1) copyright the software, and | ||
40 | (2) offer you this license which gives you legal permission to copy, | ||
41 | distribute and/or modify the software. | ||
42 | |||
43 | Also, for each author's protection and ours, we want to make certain | ||
44 | that everyone understands that there is no warranty for this free | ||
45 | software. If the software is modified by someone else and passed on, we | ||
46 | want its recipients to know that what they have is not the original, so | ||
47 | that any problems introduced by others will not reflect on the original | ||
48 | authors' reputations. | ||
49 | |||
50 | Finally, any free program is threatened constantly by software | ||
51 | patents. We wish to avoid the danger that redistributors of a free | ||
52 | program will individually obtain patent licenses, in effect making the | ||
53 | program proprietary. To prevent this, we have made it clear that any | ||
54 | patent must be licensed for everyone's free use or not licensed at all. | ||
55 | |||
56 | The precise terms and conditions for copying, distribution and | ||
57 | modification follow. | ||
58 | |||
59 | GNU GENERAL PUBLIC LICENSE | ||
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||
61 | |||
62 | 0. This License applies to any program or other work which contains | ||
63 | a notice placed by the copyright holder saying it may be distributed | ||
64 | under the terms of this General Public License. The "Program", below, | ||
65 | refers to any such program or work, and a "work based on the Program" | ||
66 | means either the Program or any derivative work under copyright law: | ||
67 | that is to say, a work containing the Program or a portion of it, | ||
68 | either verbatim or with modifications and/or translated into another | ||
69 | language. (Hereinafter, translation is included without limitation in | ||
70 | the term "modification".) Each licensee is addressed as "you". | ||
71 | |||
72 | Activities other than copying, distribution and modification are not | ||
73 | covered by this License; they are outside its scope. The act of | ||
74 | running the Program is not restricted, and the output from the Program | ||
75 | is covered only if its contents constitute a work based on the | ||
76 | Program (independent of having been made by running the Program). | ||
77 | Whether that is true depends on what the Program does. | ||
78 | |||
79 | 1. You may copy and distribute verbatim copies of the Program's | ||
80 | source code as you receive it, in any medium, provided that you | ||
81 | conspicuously and appropriately publish on each copy an appropriate | ||
82 | copyright notice and disclaimer of warranty; keep intact all the | ||
83 | notices that refer to this License and to the absence of any warranty; | ||
84 | and give any other recipients of the Program a copy of this License | ||
85 | along with the Program. | ||
86 | |||
87 | You may charge a fee for the physical act of transferring a copy, and | ||
88 | you may at your option offer warranty protection in exchange for a fee. | ||
89 | |||
90 | 2. You may modify your copy or copies of the Program or any portion | ||
91 | of it, thus forming a work based on the Program, and copy and | ||
92 | distribute such modifications or work under the terms of Section 1 | ||
93 | above, provided that you also meet all of these conditions: | ||
94 | |||
95 | a) You must cause the modified files to carry prominent notices | ||
96 | stating that you changed the files and the date of any change. | ||
97 | |||
98 | b) You must cause any work that you distribute or publish, that in | ||
99 | whole or in part contains or is derived from the Program or any | ||
100 | part thereof, to be licensed as a whole at no charge to all third | ||
101 | parties under the terms of this License. | ||
102 | |||
103 | c) If the modified program normally reads commands interactively | ||
104 | when run, you must cause it, when started running for such | ||
105 | interactive use in the most ordinary way, to print or display an | ||
106 | announcement including an appropriate copyright notice and a | ||
107 | notice that there is no warranty (or else, saying that you provide | ||
108 | a warranty) and that users may redistribute the program under | ||
109 | these conditions, and telling the user how to view a copy of this | ||
110 | License. (Exception: if the Program itself is interactive but | ||
111 | does not normally print such an announcement, your work based on | ||
112 | the Program is not required to print an announcement.) | ||
113 | |||
114 | These requirements apply to the modified work as a whole. If | ||
115 | identifiable sections of that work are not derived from the Program, | ||
116 | and can be reasonably considered independent and separate works in | ||
117 | themselves, then this License, and its terms, do not apply to those | ||
118 | sections when you distribute them as separate works. But when you | ||
119 | distribute the same sections as part of a whole which is a work based | ||
120 | on the Program, the distribution of the whole must be on the terms of | ||
121 | this License, whose permissions for other licensees extend to the | ||
122 | entire whole, and thus to each and every part regardless of who wrote it. | ||
123 | |||
124 | Thus, it is not the intent of this section to claim rights or contest | ||
125 | your rights to work written entirely by you; rather, the intent is to | ||
126 | exercise the right to control the distribution of derivative or | ||
127 | collective works based on the Program. | ||
128 | |||
129 | In addition, mere aggregation of another work not based on the Program | ||
130 | with the Program (or with a work based on the Program) on a volume of | ||
131 | a storage or distribution medium does not bring the other work under | ||
132 | the scope of this License. | ||
133 | |||
134 | 3. You may copy and distribute the Program (or a work based on it, | ||
135 | under Section 2) in object code or executable form under the terms of | ||
136 | Sections 1 and 2 above provided that you also do one of the following: | ||
137 | |||
138 | a) Accompany it with the complete corresponding machine-readable | ||
139 | source code, which must be distributed under the terms of Sections | ||
140 | 1 and 2 above on a medium customarily used for software interchange; or, | ||
141 | |||
142 | b) Accompany it with a written offer, valid for at least three | ||
143 | years, to give any third party, for a charge no more than your | ||
144 | cost of physically performing source distribution, a complete | ||
145 | machine-readable copy of the corresponding source code, to be | ||
146 | distributed under the terms of Sections 1 and 2 above on a medium | ||
147 | customarily used for software interchange; or, | ||
148 | |||
149 | c) Accompany it with the information you received as to the offer | ||
150 | to distribute corresponding source code. (This alternative is | ||
151 | allowed only for noncommercial distribution and only if you | ||
152 | received the program in object code or executable form with such | ||
153 | an offer, in accord with Subsection b above.) | ||
154 | |||
155 | The source code for a work means the preferred form of the work for | ||
156 | making modifications to it. For an executable work, complete source | ||
157 | code means all the source code for all modules it contains, plus any | ||
158 | associated interface definition files, plus the scripts used to | ||
159 | control compilation and installation of the executable. However, as a | ||
160 | special exception, the source code distributed need not include | ||
161 | anything that is normally distributed (in either source or binary | ||
162 | form) with the major components (compiler, kernel, and so on) of the | ||
163 | operating system on which the executable runs, unless that component | ||
164 | itself accompanies the executable. | ||
165 | |||
166 | If distribution of executable or object code is made by offering | ||
167 | access to copy from a designated place, then offering equivalent | ||
168 | access to copy the source code from the same place counts as | ||
169 | distribution of the source code, even though third parties are not | ||
170 | compelled to copy the source along with the object code. | ||
171 | |||
172 | 4. You may not copy, modify, sublicense, or distribute the Program | ||
173 | except as expressly provided under this License. Any attempt | ||
174 | otherwise to copy, modify, sublicense or distribute the Program is | ||
175 | void, and will automatically terminate your rights under this License. | ||
176 | However, parties who have received copies, or rights, from you under | ||
177 | this License will not have their licenses terminated so long as such | ||
178 | parties remain in full compliance. | ||
179 | |||
180 | 5. You are not required to accept this License, since you have not | ||
181 | signed it. However, nothing else grants you permission to modify or | ||
182 | distribute the Program or its derivative works. These actions are | ||
183 | prohibited by law if you do not accept this License. Therefore, by | ||
184 | modifying or distributing the Program (or any work based on the | ||
185 | Program), you indicate your acceptance of this License to do so, and | ||
186 | all its terms and conditions for copying, distributing or modifying | ||
187 | the Program or works based on it. | ||
188 | |||
189 | 6. Each time you redistribute the Program (or any work based on the | ||
190 | Program), the recipient automatically receives a license from the | ||
191 | original licensor to copy, distribute or modify the Program subject to | ||
192 | these terms and conditions. You may not impose any further | ||
193 | restrictions on the recipients' exercise of the rights granted herein. | ||
194 | You are not responsible for enforcing compliance by third parties to | ||
195 | this License. | ||
196 | |||
197 | 7. If, as a consequence of a court judgment or allegation of patent | ||
198 | infringement or for any other reason (not limited to patent issues), | ||
199 | conditions are imposed on you (whether by court order, agreement or | ||
200 | otherwise) that contradict the conditions of this License, they do not | ||
201 | excuse you from the conditions of this License. If you cannot | ||
202 | distribute so as to satisfy simultaneously your obligations under this | ||
203 | License and any other pertinent obligations, then as a consequence you | ||
204 | may not distribute the Program at all. For example, if a patent | ||
205 | license would not permit royalty-free redistribution of the Program by | ||
206 | all those who receive copies directly or indirectly through you, then | ||
207 | the only way you could satisfy both it and this License would be to | ||
208 | refrain entirely from distribution of the Program. | ||
209 | |||
210 | If any portion of this section is held invalid or unenforceable under | ||
211 | any particular circumstance, the balance of the section is intended to | ||
212 | apply and the section as a whole is intended to apply in other | ||
213 | circumstances. | ||
214 | |||
215 | It is not the purpose of this section to induce you to infringe any | ||
216 | patents or other property right claims or to contest validity of any | ||
217 | such claims; this section has the sole purpose of protecting the | ||
218 | integrity of the free software distribution system, which is | ||
219 | implemented by public license practices. Many people have made | ||
220 | generous contributions to the wide range of software distributed | ||
221 | through that system in reliance on consistent application of that | ||
222 | system; it is up to the author/donor to decide if he or she is willing | ||
223 | to distribute software through any other system and a licensee cannot | ||
224 | impose that choice. | ||
225 | |||
226 | This section is intended to make thoroughly clear what is believed to | ||
227 | be a consequence of the rest of this License. | ||
228 | |||
229 | 8. If the distribution and/or use of the Program is restricted in | ||
230 | certain countries either by patents or by copyrighted interfaces, the | ||
231 | original copyright holder who places the Program under this License | ||
232 | may add an explicit geographical distribution limitation excluding | ||
233 | those countries, so that distribution is permitted only in or among | ||
234 | countries not thus excluded. In such case, this License incorporates | ||
235 | the limitation as if written in the body of this License. | ||
236 | |||
237 | 9. The Free Software Foundation may publish revised and/or new versions | ||
238 | of the General Public License from time to time. Such new versions will | ||
239 | be similar in spirit to the present version, but may differ in detail to | ||
240 | address new problems or concerns. | ||
241 | |||
242 | Each version is given a distinguishing version number. If the Program | ||
243 | specifies a version number of this License which applies to it and "any | ||
244 | later version", you have the option of following the terms and conditions | ||
245 | either of that version or of any later version published by the Free | ||
246 | Software Foundation. If the Program does not specify a version number of | ||
247 | this License, you may choose any version ever published by the Free Software | ||
248 | Foundation. | ||
249 | |||
250 | 10. If you wish to incorporate parts of the Program into other free | ||
251 | programs whose distribution conditions are different, write to the author | ||
252 | to ask for permission. For software which is copyrighted by the Free | ||
253 | Software Foundation, write to the Free Software Foundation; we sometimes | ||
254 | make exceptions for this. Our decision will be guided by the two goals | ||
255 | of preserving the free status of all derivatives of our free software and | ||
256 | of promoting the sharing and reuse of software generally. | ||
257 | |||
258 | NO WARRANTY | ||
259 | |||
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | ||
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | ||
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | ||
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||
268 | REPAIR OR CORRECTION. | ||
269 | |||
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||
278 | POSSIBILITY OF SUCH DAMAGES. | ||
279 | |||
280 | END OF TERMS AND CONDITIONS | ||
281 | |||
282 | How to Apply These Terms to Your New Programs | ||
283 | |||
284 | If you develop a new program, and you want it to be of the greatest | ||
285 | possible use to the public, the best way to achieve this is to make it | ||
286 | free software which everyone can redistribute and change under these terms. | ||
287 | |||
288 | To do so, attach the following notices to the program. It is safest | ||
289 | to attach them to the start of each source file to most effectively | ||
290 | convey the exclusion of warranty; and each file should have at least | ||
291 | the "copyright" line and a pointer to where the full notice is found. | ||
292 | |||
293 | <one line to give the program's name and a brief idea of what it does.> | ||
294 | Copyright (C) <year> <name of author> | ||
295 | |||
296 | This program is free software; you can redistribute it and/or modify | ||
297 | it under the terms of the GNU General Public License as published by | ||
298 | the Free Software Foundation; either version 2 of the License, or | ||
299 | (at your option) any later version. | ||
300 | |||
301 | This program is distributed in the hope that it will be useful, | ||
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
304 | GNU General Public License for more details. | ||
305 | |||
306 | You should have received a copy of the GNU General Public License | ||
307 | along with this program; if not, write to the Free Software | ||
308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
309 | |||
310 | |||
311 | Also add information on how to contact you by electronic and paper mail. | ||
312 | |||
313 | If the program is interactive, make it output a short notice like this | ||
314 | when it starts in an interactive mode: | ||
315 | |||
316 | Gnomovision version 69, Copyright (C) year name of author | ||
317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||
318 | This is free software, and you are welcome to redistribute it | ||
319 | under certain conditions; type `show c' for details. | ||
320 | |||
321 | The hypothetical commands `show w' and `show c' should show the appropriate | ||
322 | parts of the General Public License. Of course, the commands you use may | ||
323 | be called something other than `show w' and `show c'; they could even be | ||
324 | mouse-clicks or menu items--whatever suits your program. | ||
325 | |||
326 | You should also get your employer (if you work as a programmer) or your | ||
327 | school, if any, to sign a "copyright disclaimer" for the program, if | ||
328 | necessary. Here is a sample; alter the names: | ||
329 | |||
330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||
331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||
332 | |||
333 | <signature of Ty Coon>, 1 April 1989 | ||
334 | Ty Coon, President of Vice | ||
335 | |||
336 | This General Public License does not permit incorporating your program into | ||
337 | proprietary programs. If your program is a subroutine library, you may | ||
338 | consider it more useful to permit linking proprietary applications with the | ||
339 | library. If this is what you want to do, use the GNU Library General | ||
340 | Public License instead of this License. | ||
diff --git a/utils/ypr0tools/cramfs-1.1/GNUmakefile b/utils/ypr0tools/cramfs-1.1/GNUmakefile new file mode 100644 index 0000000000..e15fb22f01 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/GNUmakefile | |||
@@ -0,0 +1,12 @@ | |||
1 | CC = gcc | ||
2 | CFLAGS = -W -Wall -O2 -g -Wno-pointer-sign | ||
3 | CPPFLAGS = -I. | ||
4 | LDLIBS = -lz | ||
5 | PROGS = mkcramfs cramfsck | ||
6 | |||
7 | all: $(PROGS) | ||
8 | |||
9 | distclean clean: | ||
10 | rm -f $(PROGS) | ||
11 | |||
12 | .PHONY: all clean | ||
diff --git a/utils/ypr0tools/cramfs-1.1/NOTES b/utils/ypr0tools/cramfs-1.1/NOTES new file mode 100644 index 0000000000..445d1c2d76 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/NOTES | |||
@@ -0,0 +1,168 @@ | |||
1 | Notes on Filesystem Layout | ||
2 | -------------------------- | ||
3 | |||
4 | These notes describe what mkcramfs generates. Kernel requirements are | ||
5 | a bit looser, e.g. it doesn't care if the <file_data> items are | ||
6 | swapped around (though it does care that directory entries (inodes) in | ||
7 | a given directory are contiguous, as this is used by readdir). | ||
8 | |||
9 | All data is currently in host-endian format; neither mkcramfs nor the | ||
10 | kernel ever do swabbing. (See section `Block Size' below.) | ||
11 | |||
12 | <filesystem>: | ||
13 | <superblock> | ||
14 | <directory_structure> | ||
15 | <data> | ||
16 | |||
17 | <superblock>: struct cramfs_super (see cramfs_fs.h). | ||
18 | |||
19 | <directory_structure>: | ||
20 | For each file: | ||
21 | struct cramfs_inode (see cramfs_fs.h). | ||
22 | Filename. Not generally null-terminated, but it is | ||
23 | null-padded to a multiple of 4 bytes. | ||
24 | |||
25 | The order of inode traversal is described as "width-first" (not to be | ||
26 | confused with breadth-first); i.e. like depth-first but listing all of | ||
27 | a directory's entries before recursing down its subdirectories: the | ||
28 | same order as `ls -AUR' (but without the /^\..*:$/ directory header | ||
29 | lines); put another way, the same order as `find -type d -exec | ||
30 | ls -AU1 {} \;'. | ||
31 | |||
32 | Beginning in 2.4.7, directory entries are sorted. This optimization | ||
33 | allows cramfs_lookup to return more quickly when a filename does not | ||
34 | exist, speeds up user-space directory sorts, etc. | ||
35 | |||
36 | <data>: | ||
37 | One <file_data> for each file that's either a symlink or a | ||
38 | regular file of non-zero st_size. | ||
39 | |||
40 | <file_data>: | ||
41 | nblocks * <block_pointer> | ||
42 | (where nblocks = (st_size - 1) / blksize + 1) | ||
43 | nblocks * <block> | ||
44 | padding to multiple of 4 bytes | ||
45 | |||
46 | The i'th <block_pointer> for a file stores the byte offset of the | ||
47 | *end* of the i'th <block> (i.e. one past the last byte, which is the | ||
48 | same as the start of the (i+1)'th <block> if there is one). The first | ||
49 | <block> immediately follows the last <block_pointer> for the file. | ||
50 | <block_pointer>s are each 32 bits long. | ||
51 | |||
52 | The order of <file_data>'s is a depth-first descent of the directory | ||
53 | tree, i.e. the same order as `find -size +0 \( -type f -o -type l \) | ||
54 | -print'. | ||
55 | |||
56 | |||
57 | <block>: The i'th <block> is the output of zlib's compress function | ||
58 | applied to the i'th blksize-sized chunk of the input data. | ||
59 | (For the last <block> of the file, the input may of course be smaller.) | ||
60 | Each <block> may be a different size. (See <block_pointer> above.) | ||
61 | <block>s are merely byte-aligned, not generally u32-aligned. | ||
62 | |||
63 | |||
64 | Holes | ||
65 | ----- | ||
66 | |||
67 | This kernel supports cramfs holes (i.e. [efficient representation of] | ||
68 | blocks in uncompressed data consisting entirely of NUL bytes), but by | ||
69 | default mkcramfs doesn't test for & create holes, since cramfs in | ||
70 | kernels up to at least 2.3.39 didn't support holes. Run mkcramfs | ||
71 | with -z if you want it to create files that can have holes in them. | ||
72 | |||
73 | |||
74 | Tools | ||
75 | ----- | ||
76 | |||
77 | The cramfs user-space tools, including mkcramfs and cramfsck, are | ||
78 | located at <http://sourceforge.net/projects/cramfs/>. | ||
79 | |||
80 | |||
81 | Future Development | ||
82 | ================== | ||
83 | |||
84 | Block Size | ||
85 | ---------- | ||
86 | |||
87 | (Block size in cramfs refers to the size of input data that is | ||
88 | compressed at a time. It's intended to be somewhere around | ||
89 | PAGE_CACHE_SIZE for cramfs_readpage's convenience.) | ||
90 | |||
91 | The superblock ought to indicate the block size that the fs was | ||
92 | written for, since comments in <linux/pagemap.h> indicate that | ||
93 | PAGE_CACHE_SIZE may grow in future (if I interpret the comment | ||
94 | correctly). | ||
95 | |||
96 | Currently, mkcramfs #define's PAGE_CACHE_SIZE as 4096 and uses that | ||
97 | for blksize, whereas Linux-2.3.39 uses its PAGE_CACHE_SIZE, which in | ||
98 | turn is defined as PAGE_SIZE (which can be as large as 32KB on arm). | ||
99 | This discrepancy is a bug, though it's not clear which should be | ||
100 | changed. | ||
101 | |||
102 | One option is to change mkcramfs to take its PAGE_CACHE_SIZE from | ||
103 | <asm/page.h>. Personally I don't like this option, but it does | ||
104 | require the least amount of change: just change `#define | ||
105 | PAGE_CACHE_SIZE (4096)' to `#include <asm/page.h>'. The disadvantage | ||
106 | is that the generated cramfs cannot always be shared between different | ||
107 | kernels, not even necessarily kernels of the same architecture if | ||
108 | PAGE_CACHE_SIZE is subject to change between kernel versions | ||
109 | (currently possible with arm and ia64). | ||
110 | |||
111 | The remaining options try to make cramfs more sharable. | ||
112 | |||
113 | One part of that is addressing endianness. The two options here are | ||
114 | `always use little-endian' (like ext2fs) or `writer chooses | ||
115 | endianness; kernel adapts at runtime'. Little-endian wins because of | ||
116 | code simplicity and little CPU overhead even on big-endian machines. | ||
117 | |||
118 | The cost of swabbing is changing the code to use the le32_to_cpu | ||
119 | etc. macros as used by ext2fs. We don't need to swab the compressed | ||
120 | data, only the superblock, inodes and block pointers. | ||
121 | |||
122 | |||
123 | The other part of making cramfs more sharable is choosing a block | ||
124 | size. The options are: | ||
125 | |||
126 | 1. Always 4096 bytes. | ||
127 | |||
128 | 2. Writer chooses blocksize; kernel adapts but rejects blocksize > | ||
129 | PAGE_CACHE_SIZE. | ||
130 | |||
131 | 3. Writer chooses blocksize; kernel adapts even to blocksize > | ||
132 | PAGE_CACHE_SIZE. | ||
133 | |||
134 | It's easy enough to change the kernel to use a smaller value than | ||
135 | PAGE_CACHE_SIZE: just make cramfs_readpage read multiple blocks. | ||
136 | |||
137 | The cost of option 1 is that kernels with a larger PAGE_CACHE_SIZE | ||
138 | value don't get as good compression as they can. | ||
139 | |||
140 | The cost of option 2 relative to option 1 is that the code uses | ||
141 | variables instead of #define'd constants. The gain is that people | ||
142 | with kernels having larger PAGE_CACHE_SIZE can make use of that if | ||
143 | they don't mind their cramfs being inaccessible to kernels with | ||
144 | smaller PAGE_CACHE_SIZE values. | ||
145 | |||
146 | Option 3 is easy to implement if we don't mind being CPU-inefficient: | ||
147 | e.g. get readpage to decompress to a buffer of size MAX_BLKSIZE (which | ||
148 | must be no larger than 32KB) and discard what it doesn't need. | ||
149 | Getting readpage to read into all the covered pages is harder. | ||
150 | |||
151 | The main advantage of option 3 over 1, 2, is better compression. The | ||
152 | cost is greater complexity. Probably not worth it, but I hope someone | ||
153 | will disagree. (If it is implemented, then I'll re-use that code in | ||
154 | e2compr.) | ||
155 | |||
156 | |||
157 | Another cost of 2 and 3 over 1 is making mkcramfs use a different | ||
158 | block size, but that just means adding and parsing a -b option. | ||
159 | |||
160 | |||
161 | Inode Size | ||
162 | ---------- | ||
163 | |||
164 | Given that cramfs will probably be used for CDs etc. as well as just | ||
165 | silicon ROMs, it might make sense to expand the inode a little from | ||
166 | its current 12 bytes. Inodes other than the root inode are followed | ||
167 | by filename, so the expansion doesn't even have to be a multiple of 4 | ||
168 | bytes. | ||
diff --git a/utils/ypr0tools/cramfs-1.1/README b/utils/ypr0tools/cramfs-1.1/README new file mode 100644 index 0000000000..31f53f0ab9 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/README | |||
@@ -0,0 +1,76 @@ | |||
1 | |||
2 | Cramfs - cram a filesystem onto a small ROM | ||
3 | |||
4 | cramfs is designed to be simple and small, and to compress things well. | ||
5 | |||
6 | It uses the zlib routines to compress a file one page at a time, and | ||
7 | allows random page access. The meta-data is not compressed, but is | ||
8 | expressed in a very terse representation to make it use much less | ||
9 | diskspace than traditional filesystems. | ||
10 | |||
11 | You can't write to a cramfs filesystem (making it compressible and | ||
12 | compact also makes it _very_ hard to update on-the-fly), so you have to | ||
13 | create the disk image with the "mkcramfs" utility. | ||
14 | |||
15 | |||
16 | Usage Notes | ||
17 | ----------- | ||
18 | |||
19 | File sizes are limited to less than 16MB. | ||
20 | |||
21 | Maximum filesystem size is a little over 256MB. (The last file on the | ||
22 | filesystem is allowed to extend past 256MB.) | ||
23 | |||
24 | Only the low 8 bits of gid are stored. The current version of | ||
25 | mkcramfs simply truncates to 8 bits, which is a potential security | ||
26 | issue. | ||
27 | |||
28 | Hard links are supported, but hard linked files | ||
29 | will still have a link count of 1 in the cramfs image. | ||
30 | |||
31 | Cramfs directories have no `.' or `..' entries. Directories (like | ||
32 | every other file on cramfs) always have a link count of 1. (There's | ||
33 | no need to use -noleaf in `find', btw.) | ||
34 | |||
35 | No timestamps are stored in a cramfs, so these default to the epoch | ||
36 | (1970 GMT). Recently-accessed files may have updated timestamps, but | ||
37 | the update lasts only as long as the inode is cached in memory, after | ||
38 | which the timestamp reverts to 1970, i.e. moves backwards in time. | ||
39 | |||
40 | Currently, cramfs must be written and read with architectures of the | ||
41 | same endianness, and can be read only by kernels with PAGE_CACHE_SIZE | ||
42 | == 4096. At least the latter of these is a bug, but it hasn't been | ||
43 | decided what the best fix is. For the moment if you have larger pages | ||
44 | you can just change the #define in mkcramfs.c, so long as you don't | ||
45 | mind the filesystem becoming unreadable to future kernels. | ||
46 | |||
47 | |||
48 | For /usr/share/magic | ||
49 | -------------------- | ||
50 | |||
51 | 0 ulelong 0x28cd3d45 Linux cramfs offset 0 | ||
52 | >4 ulelong x size %d | ||
53 | >8 ulelong x flags 0x%x | ||
54 | >12 ulelong x future 0x%x | ||
55 | >16 string >\0 signature "%.16s" | ||
56 | >32 ulelong x fsid.crc 0x%x | ||
57 | >36 ulelong x fsid.edition %d | ||
58 | >40 ulelong x fsid.blocks %d | ||
59 | >44 ulelong x fsid.files %d | ||
60 | >48 string >\0 name "%.16s" | ||
61 | 512 ulelong 0x28cd3d45 Linux cramfs offset 512 | ||
62 | >516 ulelong x size %d | ||
63 | >520 ulelong x flags 0x%x | ||
64 | >524 ulelong x future 0x%x | ||
65 | >528 string >\0 signature "%.16s" | ||
66 | >544 ulelong x fsid.crc 0x%x | ||
67 | >548 ulelong x fsid.edition %d | ||
68 | >552 ulelong x fsid.blocks %d | ||
69 | >556 ulelong x fsid.files %d | ||
70 | >560 string >\0 name "%.16s" | ||
71 | |||
72 | |||
73 | Hacker Notes | ||
74 | ------------ | ||
75 | |||
76 | See fs/cramfs/README for filesystem layout and implementation notes. | ||
diff --git a/utils/ypr0tools/cramfs-1.1/cramfsck.c b/utils/ypr0tools/cramfs-1.1/cramfsck.c new file mode 100644 index 0000000000..aef017a4b4 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/cramfsck.c | |||
@@ -0,0 +1,716 @@ | |||
1 | /* | ||
2 | * cramfsck - check a cramfs file system | ||
3 | * | ||
4 | * Copyright (C) 2000-2002 Transmeta Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | * 1999/12/03: Linus Torvalds (cramfs tester and unarchive program) | ||
21 | * 2000/06/03: Daniel Quinlan (CRC and length checking program) | ||
22 | * 2000/06/04: Daniel Quinlan (merged programs, added options, support | ||
23 | * for special files, preserve permissions and | ||
24 | * ownership, cramfs superblock v2, bogus mode | ||
25 | * test, pathname length test, etc.) | ||
26 | * 2000/06/06: Daniel Quinlan (support for holes, pretty-printing, | ||
27 | * symlink size test) | ||
28 | * 2000/07/11: Daniel Quinlan (file length tests, start at offset 0 or 512, | ||
29 | * fsck-compatible exit codes) | ||
30 | * 2000/07/15: Daniel Quinlan (initial support for block devices) | ||
31 | * 2002/01/10: Daniel Quinlan (additional checks, test more return codes, | ||
32 | * use read if mmap fails, standardize messages) | ||
33 | */ | ||
34 | |||
35 | /* compile-time options */ | ||
36 | #define INCLUDE_FS_TESTS /* include cramfs checking and extraction */ | ||
37 | |||
38 | #define _GNU_SOURCE | ||
39 | #include <sys/types.h> | ||
40 | #include <stdio.h> | ||
41 | #include <stdarg.h> | ||
42 | #include <sys/stat.h> | ||
43 | #include <unistd.h> | ||
44 | #include <sys/mman.h> | ||
45 | #include <fcntl.h> | ||
46 | #include <dirent.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <errno.h> | ||
49 | #include <string.h> | ||
50 | #include <sys/sysmacros.h> | ||
51 | #include <utime.h> | ||
52 | #include <sys/ioctl.h> | ||
53 | #define _LINUX_STRING_H_ | ||
54 | #include <linux/fs.h> | ||
55 | #include <linux/cramfs_fs.h> | ||
56 | #include <zlib.h> | ||
57 | |||
58 | /* Exit codes used by fsck-type programs */ | ||
59 | #define FSCK_OK 0 /* No errors */ | ||
60 | #define FSCK_NONDESTRUCT 1 /* File system errors corrected */ | ||
61 | #define FSCK_REBOOT 2 /* System should be rebooted */ | ||
62 | #define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */ | ||
63 | #define FSCK_ERROR 8 /* Operational error */ | ||
64 | #define FSCK_USAGE 16 /* Usage or syntax error */ | ||
65 | #define FSCK_LIBRARY 128 /* Shared library error */ | ||
66 | |||
67 | #define PAD_SIZE 512 | ||
68 | |||
69 | #define PAGE_CACHE_SIZE page_size | ||
70 | |||
71 | static const char *progname = "cramfsck"; | ||
72 | |||
73 | static int fd; /* ROM image file descriptor */ | ||
74 | static char *filename; /* ROM image filename */ | ||
75 | struct cramfs_super super; /* just find the cramfs superblock once */ | ||
76 | static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */ | ||
77 | #ifdef INCLUDE_FS_TESTS | ||
78 | static int opt_extract = 0; /* extract cramfs (-x) */ | ||
79 | static char *extract_dir = "root"; /* extraction directory (-x) */ | ||
80 | static uid_t euid; /* effective UID */ | ||
81 | |||
82 | /* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */ | ||
83 | static unsigned long start_dir = ~0UL; /* start of first non-root inode */ | ||
84 | static unsigned long end_dir = 0; /* end of the directory structure */ | ||
85 | static unsigned long start_data = ~0UL; /* start of the data (256 MB = max) */ | ||
86 | static unsigned long end_data = 0; /* end of the data */ | ||
87 | |||
88 | /* Guarantee access to at least 8kB at a time */ | ||
89 | #define ROMBUFFER_BITS 13 | ||
90 | #define ROMBUFFERSIZE (1 << ROMBUFFER_BITS) | ||
91 | #define ROMBUFFERMASK (ROMBUFFERSIZE-1) | ||
92 | static char read_buffer[ROMBUFFERSIZE * 2]; | ||
93 | static unsigned long read_buffer_block = ~0UL; | ||
94 | |||
95 | /* Uncompressing data structures... */ | ||
96 | static char *outbuffer; | ||
97 | static z_stream stream; | ||
98 | |||
99 | static size_t page_size; | ||
100 | |||
101 | /* Prototypes */ | ||
102 | static void expand_fs(char *, struct cramfs_inode *); | ||
103 | #endif /* INCLUDE_FS_TESTS */ | ||
104 | |||
105 | /* Input status of 0 to print help and exit without an error. */ | ||
106 | static void usage(int status) | ||
107 | { | ||
108 | FILE *stream = status ? stderr : stdout; | ||
109 | |||
110 | fprintf(stream, "usage: %s [-hv] [-x dir] file\n" | ||
111 | " -h print this help\n" | ||
112 | " -x dir extract into dir\n" | ||
113 | " -v be more verbose\n" | ||
114 | " file file to test\n", progname); | ||
115 | |||
116 | exit(status); | ||
117 | } | ||
118 | |||
119 | static void die(int status, int syserr, const char *fmt, ...) | ||
120 | { | ||
121 | va_list arg_ptr; | ||
122 | int save = errno; | ||
123 | |||
124 | fflush(0); | ||
125 | va_start(arg_ptr, fmt); | ||
126 | fprintf(stderr, "%s: ", progname); | ||
127 | vfprintf(stderr, fmt, arg_ptr); | ||
128 | if (syserr) { | ||
129 | fprintf(stderr, ": %s", strerror(save)); | ||
130 | } | ||
131 | fprintf(stderr, "\n"); | ||
132 | va_end(arg_ptr); | ||
133 | exit(status); | ||
134 | } | ||
135 | |||
136 | static void test_super(int *start, size_t *length) { | ||
137 | struct stat st; | ||
138 | |||
139 | /* find the physical size of the file or block device */ | ||
140 | if (stat(filename, &st) < 0) { | ||
141 | die(FSCK_ERROR, 1, "stat failed: %s", filename); | ||
142 | } | ||
143 | fd = open(filename, O_RDONLY); | ||
144 | if (fd < 0) { | ||
145 | die(FSCK_ERROR, 1, "open failed: %s", filename); | ||
146 | } | ||
147 | if (S_ISBLK(st.st_mode)) { | ||
148 | if (ioctl(fd, BLKGETSIZE, length) < 0) { | ||
149 | die(FSCK_ERROR, 1, "ioctl failed: unable to determine device size: %s", filename); | ||
150 | } | ||
151 | *length = *length * 512; | ||
152 | } | ||
153 | else if (S_ISREG(st.st_mode)) { | ||
154 | *length = st.st_size; | ||
155 | } | ||
156 | else { | ||
157 | die(FSCK_ERROR, 0, "not a block device or file: %s", filename); | ||
158 | } | ||
159 | |||
160 | if (*length < sizeof(struct cramfs_super)) { | ||
161 | die(FSCK_UNCORRECTED, 0, "file length too short"); | ||
162 | } | ||
163 | |||
164 | /* find superblock */ | ||
165 | if (read(fd, &super, sizeof(super)) != sizeof(super)) { | ||
166 | die(FSCK_ERROR, 1, "read failed: %s", filename); | ||
167 | } | ||
168 | if (super.magic == CRAMFS_MAGIC) { | ||
169 | *start = 0; | ||
170 | } | ||
171 | else if (*length >= (PAD_SIZE + sizeof(super))) { | ||
172 | lseek(fd, PAD_SIZE, SEEK_SET); | ||
173 | if (read(fd, &super, sizeof(super)) != sizeof(super)) { | ||
174 | die(FSCK_ERROR, 1, "read failed: %s", filename); | ||
175 | } | ||
176 | if (super.magic == CRAMFS_MAGIC) { | ||
177 | *start = PAD_SIZE; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /* superblock tests */ | ||
182 | if (super.magic != CRAMFS_MAGIC) { | ||
183 | die(FSCK_UNCORRECTED, 0, "superblock magic not found"); | ||
184 | } | ||
185 | if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { | ||
186 | die(FSCK_ERROR, 0, "unsupported filesystem features"); | ||
187 | } | ||
188 | if (super.size < PAGE_CACHE_SIZE) { | ||
189 | die(FSCK_UNCORRECTED, 0, "superblock size (%d) too small", super.size); | ||
190 | } | ||
191 | if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { | ||
192 | if (super.fsid.files == 0) { | ||
193 | die(FSCK_UNCORRECTED, 0, "zero file count"); | ||
194 | } | ||
195 | if (*length < super.size) { | ||
196 | die(FSCK_UNCORRECTED, 0, "file length too short"); | ||
197 | } | ||
198 | else if (*length > super.size) { | ||
199 | fprintf(stderr, "warning: file extends past end of filesystem\n"); | ||
200 | } | ||
201 | } | ||
202 | else { | ||
203 | fprintf(stderr, "warning: old cramfs format\n"); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | static void test_crc(int start) | ||
208 | { | ||
209 | void *buf; | ||
210 | u32 crc; | ||
211 | |||
212 | if (!(super.flags & CRAMFS_FLAG_FSID_VERSION_2)) { | ||
213 | #ifdef INCLUDE_FS_TESTS | ||
214 | return; | ||
215 | #else /* not INCLUDE_FS_TESTS */ | ||
216 | die(FSCK_USAGE, 0, "unable to test CRC: old cramfs format"); | ||
217 | #endif /* not INCLUDE_FS_TESTS */ | ||
218 | } | ||
219 | |||
220 | crc = crc32(0L, Z_NULL, 0); | ||
221 | |||
222 | buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | ||
223 | if (buf == MAP_FAILED) { | ||
224 | buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
225 | if (buf != MAP_FAILED) { | ||
226 | lseek(fd, 0, SEEK_SET); | ||
227 | read(fd, buf, super.size); | ||
228 | } | ||
229 | } | ||
230 | if (buf != MAP_FAILED) { | ||
231 | ((struct cramfs_super *) (buf+start))->fsid.crc = crc32(0L, Z_NULL, 0); | ||
232 | crc = crc32(crc, buf+start, super.size-start); | ||
233 | munmap(buf, super.size); | ||
234 | } | ||
235 | else { | ||
236 | int retval; | ||
237 | size_t length = 0; | ||
238 | |||
239 | buf = malloc(4096); | ||
240 | if (!buf) { | ||
241 | die(FSCK_ERROR, 1, "malloc failed"); | ||
242 | } | ||
243 | lseek(fd, start, SEEK_SET); | ||
244 | for (;;) { | ||
245 | retval = read(fd, buf, 4096); | ||
246 | if (retval < 0) { | ||
247 | die(FSCK_ERROR, 1, "read failed: %s", filename); | ||
248 | } | ||
249 | else if (retval == 0) { | ||
250 | break; | ||
251 | } | ||
252 | if (length == 0) { | ||
253 | ((struct cramfs_super *) buf)->fsid.crc = crc32(0L, Z_NULL, 0); | ||
254 | } | ||
255 | length += retval; | ||
256 | if (length > (super.size-start)) { | ||
257 | crc = crc32(crc, buf, retval - (length - (super.size-start))); | ||
258 | break; | ||
259 | } | ||
260 | crc = crc32(crc, buf, retval); | ||
261 | } | ||
262 | free(buf); | ||
263 | } | ||
264 | |||
265 | if (crc != super.fsid.crc) { | ||
266 | die(FSCK_UNCORRECTED, 0, "crc error"); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | #ifdef INCLUDE_FS_TESTS | ||
271 | static void print_node(char type, struct cramfs_inode *i, char *name) | ||
272 | { | ||
273 | char info[10]; | ||
274 | |||
275 | if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) { | ||
276 | /* major/minor numbers can be as high as 2^12 or 4096 */ | ||
277 | snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size)); | ||
278 | } | ||
279 | else { | ||
280 | /* size be as high as 2^24 or 16777216 */ | ||
281 | snprintf(info, 10, "%9d", i->size); | ||
282 | } | ||
283 | |||
284 | printf("%c %04o %s %5d:%-3d %s\n", | ||
285 | type, i->mode & ~S_IFMT, info, i->uid, i->gid, name); | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * Create a fake "blocked" access | ||
290 | */ | ||
291 | static void *romfs_read(unsigned long offset) | ||
292 | { | ||
293 | unsigned int block = offset >> ROMBUFFER_BITS; | ||
294 | if (block != read_buffer_block) { | ||
295 | read_buffer_block = block; | ||
296 | lseek(fd, block << ROMBUFFER_BITS, SEEK_SET); | ||
297 | read(fd, read_buffer, ROMBUFFERSIZE * 2); | ||
298 | } | ||
299 | return read_buffer + (offset & ROMBUFFERMASK); | ||
300 | } | ||
301 | |||
302 | static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i) | ||
303 | { | ||
304 | struct cramfs_inode *inode = malloc(sizeof(struct cramfs_inode)); | ||
305 | |||
306 | if (!inode) { | ||
307 | die(FSCK_ERROR, 1, "malloc failed"); | ||
308 | } | ||
309 | *inode = *i; | ||
310 | return inode; | ||
311 | } | ||
312 | |||
313 | static struct cramfs_inode *iget(unsigned int ino) | ||
314 | { | ||
315 | return cramfs_iget(romfs_read(ino)); | ||
316 | } | ||
317 | |||
318 | static void iput(struct cramfs_inode *inode) | ||
319 | { | ||
320 | free(inode); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * Return the offset of the root directory | ||
325 | */ | ||
326 | static struct cramfs_inode *read_super(void) | ||
327 | { | ||
328 | unsigned long offset = super.root.offset << 2; | ||
329 | |||
330 | if (!S_ISDIR(super.root.mode)) | ||
331 | die(FSCK_UNCORRECTED, 0, "root inode is not directory"); | ||
332 | if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && | ||
333 | ((offset != sizeof(struct cramfs_super)) && | ||
334 | (offset != PAD_SIZE + sizeof(struct cramfs_super)))) | ||
335 | { | ||
336 | die(FSCK_UNCORRECTED, 0, "bad root offset (%lu)", offset); | ||
337 | } | ||
338 | return cramfs_iget(&super.root); | ||
339 | } | ||
340 | |||
341 | static int uncompress_block(void *src, int len) | ||
342 | { | ||
343 | int err; | ||
344 | |||
345 | stream.next_in = src; | ||
346 | stream.avail_in = len; | ||
347 | |||
348 | stream.next_out = (unsigned char *) outbuffer; | ||
349 | stream.avail_out = PAGE_CACHE_SIZE*2; | ||
350 | |||
351 | inflateReset(&stream); | ||
352 | |||
353 | if (len > PAGE_CACHE_SIZE*2) { | ||
354 | die(FSCK_UNCORRECTED, 0, "data block too large"); | ||
355 | } | ||
356 | err = inflate(&stream, Z_FINISH); | ||
357 | if (err != Z_STREAM_END) { | ||
358 | die(FSCK_UNCORRECTED, 0, "decompression error %p(%d): %s", | ||
359 | zError(err), src, len); | ||
360 | } | ||
361 | return stream.total_out; | ||
362 | } | ||
363 | |||
364 | static void do_uncompress(char *path, int fd, unsigned long offset, unsigned long size) | ||
365 | { | ||
366 | unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE); | ||
367 | |||
368 | do { | ||
369 | unsigned long out = PAGE_CACHE_SIZE; | ||
370 | unsigned long next = *(u32 *) romfs_read(offset); | ||
371 | |||
372 | if (next > end_data) { | ||
373 | end_data = next; | ||
374 | } | ||
375 | |||
376 | offset += 4; | ||
377 | if (curr == next) { | ||
378 | if (opt_verbose > 1) { | ||
379 | printf(" hole at %ld (%d)\n", curr, PAGE_CACHE_SIZE); | ||
380 | } | ||
381 | if (size < PAGE_CACHE_SIZE) | ||
382 | out = size; | ||
383 | memset(outbuffer, 0x00, out); | ||
384 | } | ||
385 | else { | ||
386 | if (opt_verbose > 1) { | ||
387 | printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); | ||
388 | } | ||
389 | out = uncompress_block(romfs_read(curr), next - curr); | ||
390 | } | ||
391 | if (size >= PAGE_CACHE_SIZE) { | ||
392 | if (out != PAGE_CACHE_SIZE) { | ||
393 | die(FSCK_UNCORRECTED, 0, "non-block (%ld) bytes", out); | ||
394 | } | ||
395 | } else { | ||
396 | if (out != size) { | ||
397 | die(FSCK_UNCORRECTED, 0, "non-size (%ld vs %ld) bytes", out, size); | ||
398 | } | ||
399 | } | ||
400 | size -= out; | ||
401 | if (opt_extract) { | ||
402 | if (write(fd, outbuffer, out) < 0) { | ||
403 | die(FSCK_ERROR, 1, "write failed: %s", path); | ||
404 | } | ||
405 | } | ||
406 | curr = next; | ||
407 | } while (size); | ||
408 | } | ||
409 | |||
410 | static void change_file_status(char *path, struct cramfs_inode *i) | ||
411 | { | ||
412 | struct utimbuf epoch = { 0, 0 }; | ||
413 | |||
414 | if (euid == 0) { | ||
415 | if (lchown(path, i->uid, i->gid) < 0) { | ||
416 | die(FSCK_ERROR, 1, "lchown failed: %s", path); | ||
417 | } | ||
418 | if (S_ISLNK(i->mode)) | ||
419 | return; | ||
420 | if ((S_ISUID | S_ISGID) & i->mode) { | ||
421 | if (chmod(path, i->mode) < 0) { | ||
422 | die(FSCK_ERROR, 1, "chown failed: %s", path); | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | if (S_ISLNK(i->mode)) | ||
427 | return; | ||
428 | if (utime(path, &epoch) < 0) { | ||
429 | die(FSCK_ERROR, 1, "utime failed: %s", path); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | static void do_directory(char *path, struct cramfs_inode *i) | ||
434 | { | ||
435 | int pathlen = strlen(path); | ||
436 | int count = i->size; | ||
437 | unsigned long offset = i->offset << 2; | ||
438 | char *newpath = malloc(pathlen + 256); | ||
439 | |||
440 | if (!newpath) { | ||
441 | die(FSCK_ERROR, 1, "malloc failed"); | ||
442 | } | ||
443 | if (offset == 0 && count != 0) { | ||
444 | die(FSCK_UNCORRECTED, 0, "directory inode has zero offset and non-zero size: %s", path); | ||
445 | } | ||
446 | if (offset != 0 && offset < start_dir) { | ||
447 | start_dir = offset; | ||
448 | } | ||
449 | /* TODO: Do we need to check end_dir for empty case? */ | ||
450 | memcpy(newpath, path, pathlen); | ||
451 | newpath[pathlen] = '/'; | ||
452 | pathlen++; | ||
453 | if (opt_verbose) { | ||
454 | print_node('d', i, path); | ||
455 | } | ||
456 | if (opt_extract) { | ||
457 | if (mkdir(path, i->mode) < 0) { | ||
458 | die(FSCK_ERROR, 1, "mkdir failed: %s", path); | ||
459 | } | ||
460 | change_file_status(path, i); | ||
461 | } | ||
462 | while (count > 0) { | ||
463 | struct cramfs_inode *child = iget(offset); | ||
464 | int size; | ||
465 | int newlen = child->namelen << 2; | ||
466 | |||
467 | size = sizeof(struct cramfs_inode) + newlen; | ||
468 | count -= size; | ||
469 | |||
470 | offset += sizeof(struct cramfs_inode); | ||
471 | |||
472 | memcpy(newpath + pathlen, romfs_read(offset), newlen); | ||
473 | newpath[pathlen + newlen] = 0; | ||
474 | if (newlen == 0) { | ||
475 | die(FSCK_UNCORRECTED, 0, "filename length is zero"); | ||
476 | } | ||
477 | if ((pathlen + newlen) - strlen(newpath) > 3) { | ||
478 | die(FSCK_UNCORRECTED, 0, "bad filename length"); | ||
479 | } | ||
480 | expand_fs(newpath, child); | ||
481 | |||
482 | offset += newlen; | ||
483 | |||
484 | if (offset <= start_dir) { | ||
485 | die(FSCK_UNCORRECTED, 0, "bad inode offset"); | ||
486 | } | ||
487 | if (offset > end_dir) { | ||
488 | end_dir = offset; | ||
489 | } | ||
490 | iput(child); /* free(child) */ | ||
491 | } | ||
492 | free(newpath); | ||
493 | } | ||
494 | |||
495 | static void do_file(char *path, struct cramfs_inode *i) | ||
496 | { | ||
497 | unsigned long offset = i->offset << 2; | ||
498 | int fd = 0; | ||
499 | |||
500 | if (offset == 0 && i->size != 0) { | ||
501 | die(FSCK_UNCORRECTED, 0, "file inode has zero offset and non-zero size"); | ||
502 | } | ||
503 | if (i->size == 0 && offset != 0) { | ||
504 | die(FSCK_UNCORRECTED, 0, "file inode has zero size and non-zero offset"); | ||
505 | } | ||
506 | if (offset != 0 && offset < start_data) { | ||
507 | start_data = offset; | ||
508 | } | ||
509 | if (opt_verbose) { | ||
510 | print_node('f', i, path); | ||
511 | } | ||
512 | if (opt_extract) { | ||
513 | fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, i->mode); | ||
514 | if (fd < 0) { | ||
515 | die(FSCK_ERROR, 1, "open failed: %s", path); | ||
516 | } | ||
517 | } | ||
518 | if (i->size) { | ||
519 | do_uncompress(path, fd, offset, i->size); | ||
520 | } | ||
521 | if (opt_extract) { | ||
522 | close(fd); | ||
523 | change_file_status(path, i); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | static void do_symlink(char *path, struct cramfs_inode *i) | ||
528 | { | ||
529 | unsigned long offset = i->offset << 2; | ||
530 | unsigned long curr = offset + 4; | ||
531 | unsigned long next = *(u32 *) romfs_read(offset); | ||
532 | unsigned long size; | ||
533 | |||
534 | if (offset == 0) { | ||
535 | die(FSCK_UNCORRECTED, 0, "symbolic link has zero offset"); | ||
536 | } | ||
537 | if (i->size == 0) { | ||
538 | die(FSCK_UNCORRECTED, 0, "symbolic link has zero size"); | ||
539 | } | ||
540 | |||
541 | if (offset < start_data) { | ||
542 | start_data = offset; | ||
543 | } | ||
544 | if (next > end_data) { | ||
545 | end_data = next; | ||
546 | } | ||
547 | |||
548 | size = uncompress_block(romfs_read(curr), next - curr); | ||
549 | if (size != i->size) { | ||
550 | die(FSCK_UNCORRECTED, 0, "size error in symlink: %s", path); | ||
551 | } | ||
552 | outbuffer[size] = 0; | ||
553 | if (opt_verbose) { | ||
554 | char *str; | ||
555 | |||
556 | asprintf(&str, "%s -> %s", path, outbuffer); | ||
557 | print_node('l', i, str); | ||
558 | if (opt_verbose > 1) { | ||
559 | printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); | ||
560 | } | ||
561 | free(str); | ||
562 | } | ||
563 | if (opt_extract) { | ||
564 | if (symlink(outbuffer, path) < 0) { | ||
565 | die(FSCK_ERROR, 1, "symlink failed: %s", path); | ||
566 | } | ||
567 | change_file_status(path, i); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | static void do_special_inode(char *path, struct cramfs_inode *i) | ||
572 | { | ||
573 | dev_t devtype = 0; | ||
574 | char type; | ||
575 | |||
576 | if (i->offset) { /* no need to shift offset */ | ||
577 | die(FSCK_UNCORRECTED, 0, "special file has non-zero offset: %s", path); | ||
578 | } | ||
579 | if (S_ISCHR(i->mode)) { | ||
580 | devtype = i->size; | ||
581 | type = 'c'; | ||
582 | } | ||
583 | else if (S_ISBLK(i->mode)) { | ||
584 | devtype = i->size; | ||
585 | type = 'b'; | ||
586 | } | ||
587 | else if (S_ISFIFO(i->mode)) { | ||
588 | if (i->size != 0) { | ||
589 | die(FSCK_UNCORRECTED, 0, "fifo has non-zero size: %s", path); | ||
590 | } | ||
591 | type = 'p'; | ||
592 | } | ||
593 | else if (S_ISSOCK(i->mode)) { | ||
594 | if (i->size != 0) { | ||
595 | die(FSCK_UNCORRECTED, 0, "socket has non-zero size: %s", path); | ||
596 | } | ||
597 | type = 's'; | ||
598 | } | ||
599 | else { | ||
600 | die(FSCK_UNCORRECTED, 0, "bogus mode: %s (%o)", path, i->mode); | ||
601 | return; /* not reached */ | ||
602 | } | ||
603 | |||
604 | if (opt_verbose) { | ||
605 | print_node(type, i, path); | ||
606 | } | ||
607 | |||
608 | if (opt_extract) { | ||
609 | if (mknod(path, i->mode, devtype) < 0) { | ||
610 | die(FSCK_ERROR, 1, "mknod failed: %s", path); | ||
611 | } | ||
612 | change_file_status(path, i); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | static void expand_fs(char *path, struct cramfs_inode *inode) | ||
617 | { | ||
618 | if (S_ISDIR(inode->mode)) { | ||
619 | do_directory(path, inode); | ||
620 | } | ||
621 | else if (S_ISREG(inode->mode)) { | ||
622 | do_file(path, inode); | ||
623 | } | ||
624 | else if (S_ISLNK(inode->mode)) { | ||
625 | do_symlink(path, inode); | ||
626 | } | ||
627 | else { | ||
628 | do_special_inode(path, inode); | ||
629 | } | ||
630 | } | ||
631 | |||
632 | static void test_fs(int start) | ||
633 | { | ||
634 | struct cramfs_inode *root; | ||
635 | |||
636 | root = read_super(); | ||
637 | umask(0); | ||
638 | euid = geteuid(); | ||
639 | stream.next_in = NULL; | ||
640 | stream.avail_in = 0; | ||
641 | inflateInit(&stream); | ||
642 | expand_fs(extract_dir, root); | ||
643 | inflateEnd(&stream); | ||
644 | if (start_data != ~0UL) { | ||
645 | if (start_data < (sizeof(struct cramfs_super) + start)) { | ||
646 | die(FSCK_UNCORRECTED, 0, "directory data start (%ld) < sizeof(struct cramfs_super) + start (%ld)", start_data, sizeof(struct cramfs_super) + start); | ||
647 | } | ||
648 | if (end_dir != start_data) { | ||
649 | die(FSCK_UNCORRECTED, 0, "directory data end (%ld) != file data start (%ld)", end_dir, start_data); | ||
650 | } | ||
651 | } | ||
652 | if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { | ||
653 | if (end_data > super.size) { | ||
654 | die(FSCK_UNCORRECTED, 0, "invalid file data offset"); | ||
655 | } | ||
656 | } | ||
657 | iput(root); /* free(root) */ | ||
658 | } | ||
659 | #endif /* INCLUDE_FS_TESTS */ | ||
660 | |||
661 | int main(int argc, char **argv) | ||
662 | { | ||
663 | int c; /* for getopt */ | ||
664 | int start = 0; | ||
665 | size_t length; | ||
666 | |||
667 | page_size = sysconf(_SC_PAGESIZE); | ||
668 | |||
669 | if (argc) | ||
670 | progname = argv[0]; | ||
671 | |||
672 | outbuffer = malloc(page_size * 2); | ||
673 | if (!outbuffer) | ||
674 | die(FSCK_ERROR, 1, "failed to allocate outbuffer"); | ||
675 | |||
676 | /* command line options */ | ||
677 | while ((c = getopt(argc, argv, "hx:v")) != EOF) { | ||
678 | switch (c) { | ||
679 | case 'h': | ||
680 | usage(FSCK_OK); | ||
681 | case 'x': | ||
682 | #ifdef INCLUDE_FS_TESTS | ||
683 | opt_extract = 1; | ||
684 | extract_dir = optarg; | ||
685 | break; | ||
686 | #else /* not INCLUDE_FS_TESTS */ | ||
687 | die(FSCK_USAGE, 0, "compiled without -x support"); | ||
688 | #endif /* not INCLUDE_FS_TESTS */ | ||
689 | case 'v': | ||
690 | opt_verbose++; | ||
691 | break; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | if ((argc - optind) != 1) | ||
696 | usage(FSCK_USAGE); | ||
697 | filename = argv[optind]; | ||
698 | |||
699 | test_super(&start, &length); | ||
700 | test_crc(start); | ||
701 | #ifdef INCLUDE_FS_TESTS | ||
702 | test_fs(start); | ||
703 | #endif /* INCLUDE_FS_TESTS */ | ||
704 | |||
705 | if (opt_verbose) { | ||
706 | printf("%s: OK\n", filename); | ||
707 | } | ||
708 | |||
709 | exit(FSCK_OK); | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * Local variables: | ||
714 | * c-file-style: "linux" | ||
715 | * End: | ||
716 | */ | ||
diff --git a/utils/ypr0tools/cramfs-1.1/linux/cramfs_fs.h b/utils/ypr0tools/cramfs-1.1/linux/cramfs_fs.h new file mode 100644 index 0000000000..a8948f34b7 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/linux/cramfs_fs.h | |||
@@ -0,0 +1,98 @@ | |||
1 | #ifndef __CRAMFS_H | ||
2 | #define __CRAMFS_H | ||
3 | |||
4 | #ifndef __KERNEL__ | ||
5 | |||
6 | typedef unsigned char u8; | ||
7 | typedef unsigned short u16; | ||
8 | typedef unsigned int u32; | ||
9 | |||
10 | #endif | ||
11 | |||
12 | #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ | ||
13 | #define CRAMFS_SIGNATURE "Compressed ROMFS" | ||
14 | |||
15 | /* | ||
16 | * Width of various bitfields in struct cramfs_inode. | ||
17 | * Primarily used to generate warnings in mkcramfs. | ||
18 | */ | ||
19 | #define CRAMFS_MODE_WIDTH 16 | ||
20 | #define CRAMFS_UID_WIDTH 16 | ||
21 | #define CRAMFS_SIZE_WIDTH 24 | ||
22 | #define CRAMFS_GID_WIDTH 8 | ||
23 | #define CRAMFS_NAMELEN_WIDTH 6 | ||
24 | #define CRAMFS_OFFSET_WIDTH 26 | ||
25 | |||
26 | /* | ||
27 | * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs | ||
28 | * path length is 63 << 2 = 252. | ||
29 | */ | ||
30 | #define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2) | ||
31 | |||
32 | /* | ||
33 | * Reasonably terse representation of the inode data. | ||
34 | */ | ||
35 | struct cramfs_inode { | ||
36 | u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH; | ||
37 | /* SIZE for device files is i_rdev */ | ||
38 | u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH; | ||
39 | /* NAMELEN is the length of the file name, divided by 4 and | ||
40 | rounded up. (cramfs doesn't support hard links.) */ | ||
41 | /* OFFSET: For symlinks and non-empty regular files, this | ||
42 | contains the offset (divided by 4) of the file data in | ||
43 | compressed form (starting with an array of block pointers; | ||
44 | see README). For non-empty directories it is the offset | ||
45 | (divided by 4) of the inode of the first file in that | ||
46 | directory. For anything else, offset is zero. */ | ||
47 | u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; | ||
48 | }; | ||
49 | |||
50 | struct cramfs_info { | ||
51 | u32 crc; | ||
52 | u32 edition; | ||
53 | u32 blocks; | ||
54 | u32 files; | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * Superblock information at the beginning of the FS. | ||
59 | */ | ||
60 | struct cramfs_super { | ||
61 | u32 magic; /* 0x28cd3d45 - random number */ | ||
62 | u32 size; /* length in bytes */ | ||
63 | u32 flags; /* feature flags */ | ||
64 | u32 future; /* reserved for future use */ | ||
65 | u8 signature[16]; /* "Compressed ROMFS" */ | ||
66 | struct cramfs_info fsid; /* unique filesystem info */ | ||
67 | u8 name[16]; /* user-defined name */ | ||
68 | struct cramfs_inode root; /* root inode data */ | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * Feature flags | ||
73 | * | ||
74 | * 0x00000000 - 0x000000ff: features that work for all past kernels | ||
75 | * 0x00000100 - 0xffffffff: features that don't work for past kernels | ||
76 | */ | ||
77 | #define CRAMFS_FLAG_FSID_VERSION_2 0x00000001 /* fsid version #2 */ | ||
78 | #define CRAMFS_FLAG_SORTED_DIRS 0x00000002 /* sorted dirs */ | ||
79 | #define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */ | ||
80 | #define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */ | ||
81 | #define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */ | ||
82 | |||
83 | /* | ||
84 | * Valid values in super.flags. Currently we refuse to mount | ||
85 | * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be | ||
86 | * changed to test super.future instead. | ||
87 | */ | ||
88 | #define CRAMFS_SUPPORTED_FLAGS ( 0x000000ff \ | ||
89 | | CRAMFS_FLAG_HOLES \ | ||
90 | | CRAMFS_FLAG_WRONG_SIGNATURE \ | ||
91 | | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET ) | ||
92 | |||
93 | /* Uncompression interfaces to the underlying zlib */ | ||
94 | int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); | ||
95 | int cramfs_uncompress_init(void); | ||
96 | int cramfs_uncompress_exit(void); | ||
97 | |||
98 | #endif | ||
diff --git a/utils/ypr0tools/cramfs-1.1/linux/cramfs_fs_sb.h b/utils/ypr0tools/cramfs-1.1/linux/cramfs_fs_sb.h new file mode 100644 index 0000000000..afea368796 --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/linux/cramfs_fs_sb.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef _CRAMFS_FS_SB | ||
2 | #define _CRAMFS_FS_SB | ||
3 | |||
4 | /* | ||
5 | * cramfs super-block data in memory | ||
6 | */ | ||
7 | struct cramfs_sb_info { | ||
8 | unsigned long magic; | ||
9 | unsigned long size; | ||
10 | unsigned long blocks; | ||
11 | unsigned long files; | ||
12 | unsigned long flags; | ||
13 | }; | ||
14 | |||
15 | #endif | ||
diff --git a/utils/ypr0tools/cramfs-1.1/mkcramfs.c b/utils/ypr0tools/cramfs-1.1/mkcramfs.c new file mode 100644 index 0000000000..2eccb733be --- /dev/null +++ b/utils/ypr0tools/cramfs-1.1/mkcramfs.c | |||
@@ -0,0 +1,889 @@ | |||
1 | /* | ||
2 | * mkcramfs - make a cramfs file system | ||
3 | * | ||
4 | * Copyright (C) 1999-2002 Transmeta Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * If you change the disk format of cramfs, please update fs/cramfs/README. | ||
23 | */ | ||
24 | |||
25 | #include <sys/types.h> | ||
26 | #include <stdio.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <unistd.h> | ||
29 | #include <sys/mman.h> | ||
30 | #include <fcntl.h> | ||
31 | #include <dirent.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <errno.h> | ||
34 | #include <string.h> | ||
35 | #include <stdarg.h> | ||
36 | #include <linux/cramfs_fs.h> | ||
37 | #include <zlib.h> | ||
38 | #include <stdint.h> | ||
39 | |||
40 | /* Exit codes used by mkfs-type programs */ | ||
41 | #define MKFS_OK 0 /* No errors */ | ||
42 | #define MKFS_ERROR 8 /* Operational error */ | ||
43 | #define MKFS_USAGE 16 /* Usage or syntax error */ | ||
44 | |||
45 | /* The kernel only supports PAD_SIZE of 0 and 512. */ | ||
46 | #define PAD_SIZE 512 | ||
47 | |||
48 | /* | ||
49 | * The longest filename component to allow for in the input directory tree. | ||
50 | * ext2fs (and many others) allow up to 255 bytes. A couple of filesystems | ||
51 | * allow longer (e.g. smbfs 1024), but there isn't much use in supporting | ||
52 | * >255-byte names in the input directory tree given that such names get | ||
53 | * truncated to CRAMFS_MAXPATHLEN (252 bytes) when written to cramfs. | ||
54 | * | ||
55 | * Old versions of mkcramfs generated corrupted filesystems if any input | ||
56 | * filenames exceeded CRAMFS_MAXPATHLEN (252 bytes), however old | ||
57 | * versions of cramfsck seem to have been able to detect the corruption. | ||
58 | */ | ||
59 | #define MAX_INPUT_NAMELEN 255 | ||
60 | |||
61 | /* | ||
62 | * Maximum size fs you can create is roughly 256MB. (The last file's | ||
63 | * data must begin within 256MB boundary but can extend beyond that.) | ||
64 | * | ||
65 | * Note that if you want it to fit in a ROM then you're limited to what the | ||
66 | * hardware and kernel can support. | ||
67 | */ | ||
68 | #define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \ | ||
69 | + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \ | ||
70 | + (1 << CRAMFS_SIZE_WIDTH) * 4 / blksize /* block pointers */ ) | ||
71 | |||
72 | static const char *progname = "mkcramfs"; | ||
73 | static unsigned int blksize; | ||
74 | static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ | ||
75 | static int image_length = 0; | ||
76 | |||
77 | /* | ||
78 | * If opt_holes is set, then mkcramfs can create explicit holes in the | ||
79 | * data, which saves 26 bytes per hole (which is a lot smaller a | ||
80 | * saving than most most filesystems). | ||
81 | * | ||
82 | * Note that kernels up to at least 2.3.39 don't support cramfs holes, | ||
83 | * which is why this is turned off by default. | ||
84 | * | ||
85 | * If opt_verbose is 1, be verbose. If it is higher, be even more verbose. | ||
86 | */ | ||
87 | static u32 opt_edition = 0; | ||
88 | static int opt_errors = 0; | ||
89 | static int opt_holes = 0; | ||
90 | static int opt_pad = 0; | ||
91 | static int opt_verbose = 0; | ||
92 | static char *opt_image = NULL; | ||
93 | static char *opt_name = NULL; | ||
94 | |||
95 | static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid; | ||
96 | |||
97 | /* In-core version of inode / directory entry. */ | ||
98 | struct entry { | ||
99 | /* stats */ | ||
100 | unsigned char *name; | ||
101 | unsigned int mode, size, uid, gid; | ||
102 | |||
103 | /* these are only used for non-empty files */ | ||
104 | char *path; /* always null except non-empty files */ | ||
105 | int fd; /* temporarily open files while mmapped */ | ||
106 | |||
107 | /* FS data */ | ||
108 | void *uncompressed; | ||
109 | /* points to other identical file */ | ||
110 | struct entry *same; | ||
111 | unsigned int offset; /* pointer to compressed data in archive */ | ||
112 | unsigned int dir_offset; /* Where in the archive is the directory entry? */ | ||
113 | |||
114 | /* organization */ | ||
115 | struct entry *child; /* null for non-directories and empty directories */ | ||
116 | struct entry *next; | ||
117 | }; | ||
118 | |||
119 | /* Input status of 0 to print help and exit without an error. */ | ||
120 | static void usage(int status) | ||
121 | { | ||
122 | FILE *stream = status ? stderr : stdout; | ||
123 | |||
124 | fprintf(stream, "usage: %s [-h] [-b blksize] [-e edition] [-i file] [-n name] dirname outfile\n" | ||
125 | " -h print this help\n" | ||
126 | " -E make all warnings errors (non-zero exit status)\n" | ||
127 | " -b blksize blocksize to use\n" | ||
128 | " -e edition set edition number (part of fsid)\n" | ||
129 | " -i file insert a file image into the filesystem (requires >= 2.4.0)\n" | ||
130 | " -n name set name of cramfs filesystem\n" | ||
131 | " -p pad by %d bytes for boot code\n" | ||
132 | " -s sort directory entries (old option, ignored)\n" | ||
133 | " -v be more verbose\n" | ||
134 | " -z make explicit holes (requires >= 2.3.39)\n" | ||
135 | " dirname root of the directory tree to be compressed\n" | ||
136 | " outfile output file\n", progname, PAD_SIZE); | ||
137 | |||
138 | exit(status); | ||
139 | } | ||
140 | |||
141 | static void die(int status, int syserr, const char *fmt, ...) | ||
142 | { | ||
143 | va_list arg_ptr; | ||
144 | int save = errno; | ||
145 | |||
146 | fflush(0); | ||
147 | va_start(arg_ptr, fmt); | ||
148 | fprintf(stderr, "%s: ", progname); | ||
149 | vfprintf(stderr, fmt, arg_ptr); | ||
150 | if (syserr) { | ||
151 | fprintf(stderr, ": %s", strerror(save)); | ||
152 | } | ||
153 | fprintf(stderr, "\n"); | ||
154 | va_end(arg_ptr); | ||
155 | exit(status); | ||
156 | } | ||
157 | |||
158 | static void map_entry(struct entry *entry) | ||
159 | { | ||
160 | if (entry->path) { | ||
161 | entry->fd = open(entry->path, O_RDONLY); | ||
162 | if (entry->fd < 0) { | ||
163 | die(MKFS_ERROR, 1, "open failed: %s", entry->path); | ||
164 | } | ||
165 | entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, entry->fd, 0); | ||
166 | if (entry->uncompressed == MAP_FAILED) { | ||
167 | die(MKFS_ERROR, 1, "mmap failed: %s", entry->path); | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static void unmap_entry(struct entry *entry) | ||
173 | { | ||
174 | if (entry->path) { | ||
175 | if (munmap(entry->uncompressed, entry->size) < 0) { | ||
176 | die(MKFS_ERROR, 1, "munmap failed: %s", entry->path); | ||
177 | } | ||
178 | close(entry->fd); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | static int find_identical_file(struct entry *orig, struct entry *newfile) | ||
183 | { | ||
184 | if (orig == newfile) | ||
185 | return 1; | ||
186 | if (!orig) | ||
187 | return 0; | ||
188 | if (orig->size == newfile->size && (orig->path || orig->uncompressed)) | ||
189 | { | ||
190 | map_entry(orig); | ||
191 | map_entry(newfile); | ||
192 | if (!memcmp(orig->uncompressed, newfile->uncompressed, orig->size)) | ||
193 | { | ||
194 | newfile->same = orig; | ||
195 | unmap_entry(newfile); | ||
196 | unmap_entry(orig); | ||
197 | return 1; | ||
198 | } | ||
199 | unmap_entry(newfile); | ||
200 | unmap_entry(orig); | ||
201 | } | ||
202 | return (find_identical_file(orig->child, newfile) || | ||
203 | find_identical_file(orig->next, newfile)); | ||
204 | } | ||
205 | |||
206 | static void eliminate_doubles(struct entry *root, struct entry *orig) { | ||
207 | if (orig) { | ||
208 | if (orig->size && (orig->path || orig->uncompressed)) | ||
209 | find_identical_file(root, orig); | ||
210 | eliminate_doubles(root, orig->child); | ||
211 | eliminate_doubles(root, orig->next); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * We define our own sorting function instead of using alphasort which | ||
217 | * uses strcoll and changes ordering based on locale information. | ||
218 | */ | ||
219 | static int cramsort (const void *a, const void *b) | ||
220 | { | ||
221 | return strcmp ((*(const struct dirent **) a)->d_name, | ||
222 | (*(const struct dirent **) b)->d_name); | ||
223 | } | ||
224 | |||
225 | static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub) | ||
226 | { | ||
227 | struct dirent **dirlist; | ||
228 | int totalsize = 0, dircount, dirindex; | ||
229 | char *path, *endpath; | ||
230 | size_t len = strlen(name); | ||
231 | |||
232 | /* Set up the path. */ | ||
233 | /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */ | ||
234 | path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1); | ||
235 | if (!path) { | ||
236 | die(MKFS_ERROR, 1, "malloc failed"); | ||
237 | } | ||
238 | memcpy(path, name, len); | ||
239 | endpath = path + len; | ||
240 | *endpath = '/'; | ||
241 | endpath++; | ||
242 | |||
243 | /* read in the directory and sort */ | ||
244 | dircount = scandir(name, &dirlist, 0, cramsort); | ||
245 | |||
246 | if (dircount < 0) { | ||
247 | die(MKFS_ERROR, 1, "scandir failed: %s", name); | ||
248 | } | ||
249 | |||
250 | /* process directory */ | ||
251 | for (dirindex = 0; dirindex < dircount; dirindex++) { | ||
252 | struct dirent *dirent; | ||
253 | struct entry *entry; | ||
254 | struct stat st; | ||
255 | int size; | ||
256 | size_t namelen; | ||
257 | |||
258 | dirent = dirlist[dirindex]; | ||
259 | |||
260 | /* Ignore "." and ".." - we won't be adding them to the archive */ | ||
261 | if (dirent->d_name[0] == '.') { | ||
262 | if (dirent->d_name[1] == '\0') | ||
263 | continue; | ||
264 | if (dirent->d_name[1] == '.') { | ||
265 | if (dirent->d_name[2] == '\0') | ||
266 | continue; | ||
267 | } | ||
268 | } | ||
269 | namelen = strlen(dirent->d_name); | ||
270 | if (namelen > MAX_INPUT_NAMELEN) { | ||
271 | die(MKFS_ERROR, 0, | ||
272 | "very long (%u bytes) filename found: %s\n" | ||
273 | "please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile", | ||
274 | namelen, dirent->d_name); | ||
275 | } | ||
276 | memcpy(endpath, dirent->d_name, namelen + 1); | ||
277 | |||
278 | if (lstat(path, &st) < 0) { | ||
279 | warn_skip = 1; | ||
280 | continue; | ||
281 | } | ||
282 | entry = calloc(1, sizeof(struct entry)); | ||
283 | if (!entry) { | ||
284 | die(MKFS_ERROR, 1, "calloc failed"); | ||
285 | } | ||
286 | entry->name = strdup(dirent->d_name); | ||
287 | if (!entry->name) { | ||
288 | die(MKFS_ERROR, 1, "strdup failed"); | ||
289 | } | ||
290 | /* truncate multi-byte UTF-8 filenames on character boundary */ | ||
291 | if (namelen > CRAMFS_MAXPATHLEN) { | ||
292 | namelen = CRAMFS_MAXPATHLEN; | ||
293 | warn_namelen = 1; | ||
294 | /* the first lost byte must not be a trail byte */ | ||
295 | while ((entry->name[namelen] & 0xc0) == 0x80) { | ||
296 | namelen--; | ||
297 | /* are we reasonably certain it was UTF-8 ? */ | ||
298 | if (entry->name[namelen] < 0x80 || !namelen) { | ||
299 | die(MKFS_ERROR, 0, "cannot truncate filenames not encoded in UTF-8"); | ||
300 | } | ||
301 | } | ||
302 | entry->name[namelen] = '\0'; | ||
303 | } | ||
304 | entry->mode = st.st_mode; | ||
305 | entry->size = st.st_size; | ||
306 | entry->uid = st.st_uid; | ||
307 | if (entry->uid >= 1 << CRAMFS_UID_WIDTH) | ||
308 | warn_uid = 1; | ||
309 | entry->gid = st.st_gid; | ||
310 | if (entry->gid >= 1 << CRAMFS_GID_WIDTH) | ||
311 | /* TODO: We ought to replace with a default | ||
312 | gid instead of truncating; otherwise there | ||
313 | are security problems. Maybe mode should | ||
314 | be &= ~070. Same goes for uid once Linux | ||
315 | supports >16-bit uids. */ | ||
316 | warn_gid = 1; | ||
317 | size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3); | ||
318 | *fslen_ub += size; | ||
319 | if (S_ISDIR(st.st_mode)) { | ||
320 | entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub); | ||
321 | } else if (S_ISREG(st.st_mode)) { | ||
322 | if (entry->size) { | ||
323 | if (access(path, R_OK) < 0) { | ||
324 | warn_skip = 1; | ||
325 | continue; | ||
326 | } | ||
327 | entry->path = strdup(path); | ||
328 | if (!entry->path) { | ||
329 | die(MKFS_ERROR, 1, "strdup failed"); | ||
330 | } | ||
331 | if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) { | ||
332 | warn_size = 1; | ||
333 | entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1; | ||
334 | } | ||
335 | } | ||
336 | } else if (S_ISLNK(st.st_mode)) { | ||
337 | int len; | ||
338 | entry->uncompressed = malloc(entry->size); | ||
339 | if (!entry->uncompressed) { | ||
340 | die(MKFS_ERROR, 1, "malloc failed"); | ||
341 | } | ||
342 | len = readlink(path, entry->uncompressed, entry->size); | ||
343 | if (len < 0) { | ||
344 | warn_skip = 1; | ||
345 | continue; | ||
346 | } | ||
347 | entry->size = len; | ||
348 | } else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { | ||
349 | /* maybe we should skip sockets */ | ||
350 | entry->size = 0; | ||
351 | } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { | ||
352 | entry->size = st.st_rdev; | ||
353 | if (entry->size & -(1<<CRAMFS_SIZE_WIDTH)) | ||
354 | warn_dev = 1; | ||
355 | } else { | ||
356 | die(MKFS_ERROR, 0, "bogus file type: %s", entry->name); | ||
357 | } | ||
358 | |||
359 | if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { | ||
360 | int blocks = ((entry->size - 1) / blksize + 1); | ||
361 | |||
362 | /* block pointers & data expansion allowance + data */ | ||
363 | if (entry->size) | ||
364 | *fslen_ub += (4+26)*blocks + entry->size + 3; | ||
365 | } | ||
366 | |||
367 | /* Link it into the list */ | ||
368 | *prev = entry; | ||
369 | prev = &entry->next; | ||
370 | totalsize += size; | ||
371 | } | ||
372 | free(path); | ||
373 | free(dirlist); /* allocated by scandir() with malloc() */ | ||
374 | return totalsize; | ||
375 | } | ||
376 | |||
377 | /* Returns sizeof(struct cramfs_super), which includes the root inode. */ | ||
378 | static unsigned int write_superblock(struct entry *root, char *base, int size) | ||
379 | { | ||
380 | struct cramfs_super *super = (struct cramfs_super *) base; | ||
381 | unsigned int offset = sizeof(struct cramfs_super) + image_length; | ||
382 | |||
383 | offset += opt_pad; /* 0 if no padding */ | ||
384 | |||
385 | super->magic = CRAMFS_MAGIC; | ||
386 | super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS; | ||
387 | if (opt_holes) | ||
388 | super->flags |= CRAMFS_FLAG_HOLES; | ||
389 | if (image_length > 0) | ||
390 | super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET; | ||
391 | super->size = size; | ||
392 | memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)); | ||
393 | |||
394 | super->fsid.crc = crc32(0L, Z_NULL, 0); | ||
395 | super->fsid.edition = opt_edition; | ||
396 | super->fsid.blocks = total_blocks; | ||
397 | super->fsid.files = total_nodes; | ||
398 | |||
399 | memset(super->name, 0x00, sizeof(super->name)); | ||
400 | if (opt_name) | ||
401 | strncpy(super->name, opt_name, sizeof(super->name)); | ||
402 | else | ||
403 | strncpy(super->name, "Compressed", sizeof(super->name)); | ||
404 | |||
405 | super->root.mode = root->mode; | ||
406 | super->root.uid = root->uid; | ||
407 | super->root.gid = root->gid; | ||
408 | super->root.size = root->size; | ||
409 | super->root.offset = offset >> 2; | ||
410 | |||
411 | return offset; | ||
412 | } | ||
413 | |||
414 | static void set_data_offset(struct entry *entry, char *base, unsigned long offset) | ||
415 | { | ||
416 | struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset); | ||
417 | |||
418 | if ((offset & 3) != 0) { | ||
419 | die(MKFS_ERROR, 0, "illegal offset of %lu bytes", offset); | ||
420 | } | ||
421 | if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) { | ||
422 | die(MKFS_ERROR, 0, "filesystem too big"); | ||
423 | } | ||
424 | inode->offset = (offset >> 2); | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * TODO: Does this work for chars >= 0x80? Most filesystems use UTF-8 | ||
429 | * encoding for filenames, whereas the console is a single-byte | ||
430 | * character set like iso-latin-1. | ||
431 | */ | ||
432 | static void print_node(struct entry *e) | ||
433 | { | ||
434 | char info[10]; | ||
435 | char type = '?'; | ||
436 | |||
437 | if (S_ISREG(e->mode)) type = 'f'; | ||
438 | else if (S_ISDIR(e->mode)) type = 'd'; | ||
439 | else if (S_ISLNK(e->mode)) type = 'l'; | ||
440 | else if (S_ISCHR(e->mode)) type = 'c'; | ||
441 | else if (S_ISBLK(e->mode)) type = 'b'; | ||
442 | else if (S_ISFIFO(e->mode)) type = 'p'; | ||
443 | else if (S_ISSOCK(e->mode)) type = 's'; | ||
444 | |||
445 | if (S_ISCHR(e->mode) || (S_ISBLK(e->mode))) { | ||
446 | /* major/minor numbers can be as high as 2^12 or 4096 */ | ||
447 | snprintf(info, 10, "%4d,%4d", major(e->size), minor(e->size)); | ||
448 | } | ||
449 | else { | ||
450 | /* size be as high as 2^24 or 16777216 */ | ||
451 | snprintf(info, 10, "%9d", e->size); | ||
452 | } | ||
453 | |||
454 | printf("%c %04o %s %5d:%-3d %s\n", | ||
455 | type, e->mode & ~S_IFMT, info, e->uid, e->gid, e->name); | ||
456 | } | ||
457 | |||
458 | /* | ||
459 | * We do a width-first printout of the directory | ||
460 | * entries, using a stack to remember the directories | ||
461 | * we've seen. | ||
462 | */ | ||
463 | static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset) | ||
464 | { | ||
465 | int stack_entries = 0; | ||
466 | int stack_size = 64; | ||
467 | struct entry **entry_stack; | ||
468 | |||
469 | entry_stack = malloc(stack_size * sizeof(struct entry *)); | ||
470 | if (!entry_stack) { | ||
471 | die(MKFS_ERROR, 1, "malloc failed"); | ||
472 | } | ||
473 | |||
474 | if (opt_verbose) { | ||
475 | printf("root:\n"); | ||
476 | } | ||
477 | |||
478 | for (;;) { | ||
479 | int dir_start = stack_entries; | ||
480 | while (entry) { | ||
481 | struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset); | ||
482 | size_t len = strlen(entry->name); | ||
483 | |||
484 | entry->dir_offset = offset; | ||
485 | |||
486 | inode->mode = entry->mode; | ||
487 | inode->uid = entry->uid; | ||
488 | inode->gid = entry->gid; | ||
489 | inode->size = entry->size; | ||
490 | inode->offset = 0; | ||
491 | /* Non-empty directories, regfiles and symlinks will | ||
492 | write over inode->offset later. */ | ||
493 | |||
494 | offset += sizeof(struct cramfs_inode); | ||
495 | total_nodes++; /* another node */ | ||
496 | memcpy(base + offset, entry->name, len); | ||
497 | /* Pad up the name to a 4-byte boundary */ | ||
498 | while (len & 3) { | ||
499 | *(base + offset + len) = '\0'; | ||
500 | len++; | ||
501 | } | ||
502 | inode->namelen = len >> 2; | ||
503 | offset += len; | ||
504 | |||
505 | if (opt_verbose) | ||
506 | print_node(entry); | ||
507 | |||
508 | if (entry->child) { | ||
509 | if (stack_entries >= stack_size) { | ||
510 | stack_size *= 2; | ||
511 | entry_stack = realloc(entry_stack, stack_size * sizeof(struct entry *)); | ||
512 | if (!entry_stack) { | ||
513 | die(MKFS_ERROR, 1, "realloc failed"); | ||
514 | } | ||
515 | } | ||
516 | entry_stack[stack_entries] = entry; | ||
517 | stack_entries++; | ||
518 | } | ||
519 | entry = entry->next; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Reverse the order the stack entries pushed during | ||
524 | * this directory, for a small optimization of disk | ||
525 | * access in the created fs. This change makes things | ||
526 | * `ls -UR' order. | ||
527 | */ | ||
528 | { | ||
529 | struct entry **lo = entry_stack + dir_start; | ||
530 | struct entry **hi = entry_stack + stack_entries; | ||
531 | struct entry *tmp; | ||
532 | |||
533 | while (lo < --hi) { | ||
534 | tmp = *lo; | ||
535 | *lo++ = *hi; | ||
536 | *hi = tmp; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | /* Pop a subdirectory entry from the stack, and recurse. */ | ||
541 | if (!stack_entries) | ||
542 | break; | ||
543 | stack_entries--; | ||
544 | entry = entry_stack[stack_entries]; | ||
545 | |||
546 | set_data_offset(entry, base, offset); | ||
547 | if (opt_verbose) { | ||
548 | printf("%s:\n", entry->name); | ||
549 | } | ||
550 | entry = entry->child; | ||
551 | } | ||
552 | free(entry_stack); | ||
553 | return offset; | ||
554 | } | ||
555 | |||
556 | static int is_zero(char const *begin, unsigned len) | ||
557 | { | ||
558 | /* Returns non-zero iff the first LEN bytes from BEGIN are all NULs. */ | ||
559 | return (len-- == 0 || | ||
560 | (begin[0] == '\0' && | ||
561 | (len-- == 0 || | ||
562 | (begin[1] == '\0' && | ||
563 | (len-- == 0 || | ||
564 | (begin[2] == '\0' && | ||
565 | (len-- == 0 || | ||
566 | (begin[3] == '\0' && | ||
567 | memcmp(begin, begin + 4, len) == 0)))))))); | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * One 4-byte pointer per block and then the actual blocked | ||
572 | * output. The first block does not need an offset pointer, | ||
573 | * as it will start immediately after the pointer block; | ||
574 | * so the i'th pointer points to the end of the i'th block | ||
575 | * (i.e. the start of the (i+1)'th block or past EOF). | ||
576 | * | ||
577 | * Note that size > 0, as a zero-sized file wouldn't ever | ||
578 | * have gotten here in the first place. | ||
579 | */ | ||
580 | static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size) | ||
581 | { | ||
582 | unsigned long original_size = size; | ||
583 | unsigned long original_offset = offset; | ||
584 | unsigned long new_size; | ||
585 | unsigned long blocks = (size - 1) / blksize + 1; | ||
586 | unsigned long curr = offset + 4 * blocks; | ||
587 | int change; | ||
588 | |||
589 | total_blocks += blocks; | ||
590 | |||
591 | do { | ||
592 | unsigned long len = 2 * blksize; | ||
593 | unsigned int input = size; | ||
594 | int err; | ||
595 | |||
596 | if (input > blksize) | ||
597 | input = blksize; | ||
598 | size -= input; | ||
599 | if (!(opt_holes && is_zero (uncompressed, input))) { | ||
600 | err = compress2(base + curr, &len, uncompressed, input, Z_BEST_COMPRESSION); | ||
601 | if (err != Z_OK) { | ||
602 | die(MKFS_ERROR, 0, "compression error: %s", zError(err)); | ||
603 | } | ||
604 | curr += len; | ||
605 | } | ||
606 | uncompressed += input; | ||
607 | |||
608 | if (len > blksize*2) { | ||
609 | /* (I don't think this can happen with zlib.) */ | ||
610 | die(MKFS_ERROR, 0, "AIEEE: block \"compressed\" to > 2*blocklength (%ld)", len); | ||
611 | } | ||
612 | |||
613 | *(u32 *) (base + offset) = curr; | ||
614 | offset += 4; | ||
615 | } while (size); | ||
616 | |||
617 | curr = (curr + 3) & ~3; | ||
618 | new_size = curr - original_offset; | ||
619 | /* TODO: Arguably, original_size in these 2 lines should be | ||
620 | st_blocks * 512. But if you say that then perhaps | ||
621 | administrative data should also be included in both. */ | ||
622 | change = new_size - original_size; | ||
623 | if (opt_verbose > 1) { | ||
624 | printf("%6.2f%% (%+d bytes)\t%s\n", | ||
625 | (change * 100) / (double) original_size, change, name); | ||
626 | } | ||
627 | |||
628 | return curr; | ||
629 | } | ||
630 | |||
631 | |||
632 | /* | ||
633 | * Traverse the entry tree, writing data for every item that has | ||
634 | * non-null entry->path (i.e. every non-empty regfile) and non-null | ||
635 | * entry->uncompressed (i.e. every symlink). | ||
636 | */ | ||
637 | static unsigned int write_data(struct entry *entry, char *base, unsigned int offset) | ||
638 | { | ||
639 | do { | ||
640 | if (entry->path || entry->uncompressed) { | ||
641 | if (entry->same) { | ||
642 | set_data_offset(entry, base, entry->same->offset); | ||
643 | entry->offset = entry->same->offset; | ||
644 | } | ||
645 | else { | ||
646 | set_data_offset(entry, base, offset); | ||
647 | entry->offset = offset; | ||
648 | map_entry(entry); | ||
649 | offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size); | ||
650 | unmap_entry(entry); | ||
651 | } | ||
652 | } | ||
653 | else if (entry->child) | ||
654 | offset = write_data(entry->child, base, offset); | ||
655 | entry=entry->next; | ||
656 | } while (entry); | ||
657 | return offset; | ||
658 | } | ||
659 | |||
660 | static unsigned int write_file(char *file, char *base, unsigned int offset) | ||
661 | { | ||
662 | int fd; | ||
663 | char *buf; | ||
664 | |||
665 | fd = open(file, O_RDONLY); | ||
666 | if (fd < 0) { | ||
667 | die(MKFS_ERROR, 1, "open failed: %s", file); | ||
668 | } | ||
669 | buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0); | ||
670 | if (buf == MAP_FAILED) { | ||
671 | die(MKFS_ERROR, 1, "mmap failed"); | ||
672 | } | ||
673 | memcpy(base + offset, buf, image_length); | ||
674 | munmap(buf, image_length); | ||
675 | close (fd); | ||
676 | /* Pad up the image_length to a 4-byte boundary */ | ||
677 | while (image_length & 3) { | ||
678 | *(base + offset + image_length) = '\0'; | ||
679 | image_length++; | ||
680 | } | ||
681 | return (offset + image_length); | ||
682 | } | ||
683 | |||
684 | int main(int argc, char **argv) | ||
685 | { | ||
686 | struct stat st; /* used twice... */ | ||
687 | struct entry *root_entry; | ||
688 | char *rom_image; | ||
689 | ssize_t offset, written; | ||
690 | int fd; | ||
691 | /* initial guess (upper-bound) of required filesystem size */ | ||
692 | loff_t fslen_ub = sizeof(struct cramfs_super); | ||
693 | char const *dirname, *outfile; | ||
694 | u32 crc; | ||
695 | int c; /* for getopt */ | ||
696 | char *ep; /* for strtoul */ | ||
697 | |||
698 | blksize = sysconf(_SC_PAGESIZE); | ||
699 | total_blocks = 0; | ||
700 | |||
701 | if (argc) | ||
702 | progname = argv[0]; | ||
703 | |||
704 | /* command line options */ | ||
705 | while ((c = getopt(argc, argv, "hEb:e:i:n:psvz")) != EOF) { | ||
706 | switch (c) { | ||
707 | case 'h': | ||
708 | usage(MKFS_OK); | ||
709 | case 'E': | ||
710 | opt_errors = 1; | ||
711 | break; | ||
712 | case 'b': | ||
713 | errno = 0; | ||
714 | blksize = strtoul(optarg, &ep, 10); | ||
715 | if (errno || optarg[0] == '\0' || *ep != '\0') | ||
716 | usage(MKFS_USAGE); | ||
717 | if (blksize < 512 || (blksize & (blksize - 1))) | ||
718 | die(MKFS_ERROR, 0, "invalid blocksize: %u", blksize); | ||
719 | break; | ||
720 | case 'e': | ||
721 | errno = 0; | ||
722 | opt_edition = strtoul(optarg, &ep, 10); | ||
723 | if (errno || optarg[0] == '\0' || *ep != '\0') | ||
724 | usage(MKFS_USAGE); | ||
725 | break; | ||
726 | case 'i': | ||
727 | opt_image = optarg; | ||
728 | if (lstat(opt_image, &st) < 0) { | ||
729 | die(MKFS_ERROR, 1, "lstat failed: %s", opt_image); | ||
730 | } | ||
731 | image_length = st.st_size; /* may be padded later */ | ||
732 | fslen_ub += (image_length + 3); /* 3 is for padding */ | ||
733 | break; | ||
734 | case 'n': | ||
735 | opt_name = optarg; | ||
736 | break; | ||
737 | case 'p': | ||
738 | opt_pad = PAD_SIZE; | ||
739 | fslen_ub += PAD_SIZE; | ||
740 | break; | ||
741 | case 's': | ||
742 | /* old option, ignored */ | ||
743 | break; | ||
744 | case 'v': | ||
745 | opt_verbose++; | ||
746 | break; | ||
747 | case 'z': | ||
748 | opt_holes = 1; | ||
749 | break; | ||
750 | } | ||
751 | } | ||
752 | |||
753 | if ((argc - optind) != 2) | ||
754 | usage(MKFS_USAGE); | ||
755 | dirname = argv[optind]; | ||
756 | outfile = argv[optind + 1]; | ||
757 | |||
758 | if (stat(dirname, &st) < 0) { | ||
759 | die(MKFS_USAGE, 1, "stat failed: %s", dirname); | ||
760 | } | ||
761 | fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); | ||
762 | if (fd < 0) { | ||
763 | die(MKFS_USAGE, 1, "open failed: %s", outfile); | ||
764 | } | ||
765 | |||
766 | root_entry = calloc(1, sizeof(struct entry)); | ||
767 | if (!root_entry) { | ||
768 | die(MKFS_ERROR, 1, "calloc failed"); | ||
769 | } | ||
770 | root_entry->mode = st.st_mode; | ||
771 | root_entry->uid = st.st_uid; | ||
772 | root_entry->gid = st.st_gid; | ||
773 | |||
774 | root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub); | ||
775 | |||
776 | /* always allocate a multiple of blksize bytes because that's | ||
777 | what we're going to write later on */ | ||
778 | fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1; | ||
779 | |||
780 | if (fslen_ub > MAXFSLEN) { | ||
781 | fprintf(stderr, | ||
782 | "warning: estimate of required size (upper bound) is %jdMB, but maximum image size is %uMB, we might die prematurely\n", | ||
783 | (intmax_t) (fslen_ub >> 20), | ||
784 | MAXFSLEN >> 20); | ||
785 | fslen_ub = MAXFSLEN; | ||
786 | } | ||
787 | |||
788 | /* find duplicate files. TODO: uses the most inefficient algorithm | ||
789 | possible. */ | ||
790 | eliminate_doubles(root_entry, root_entry); | ||
791 | |||
792 | /* TODO: Why do we use a private/anonymous mapping here | ||
793 | followed by a write below, instead of just a shared mapping | ||
794 | and a couple of ftruncate calls? Is it just to save us | ||
795 | having to deal with removing the file afterwards? If we | ||
796 | really need this huge anonymous mapping, we ought to mmap | ||
797 | in smaller chunks, so that the user doesn't need nn MB of | ||
798 | RAM free. If the reason is to be able to write to | ||
799 | un-mmappable block devices, then we could try shared mmap | ||
800 | and revert to anonymous mmap if the shared mmap fails. */ | ||
801 | rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
802 | |||
803 | if (rom_image == MAP_FAILED) { | ||
804 | die(MKFS_ERROR, 1, "mmap failed"); | ||
805 | } | ||
806 | |||
807 | /* Skip the first opt_pad bytes for boot loader code */ | ||
808 | offset = opt_pad; | ||
809 | memset(rom_image, 0x00, opt_pad); | ||
810 | |||
811 | /* Skip the superblock and come back to write it later. */ | ||
812 | offset += sizeof(struct cramfs_super); | ||
813 | |||
814 | /* Insert a file image. */ | ||
815 | if (opt_image) { | ||
816 | printf("Including: %s\n", opt_image); | ||
817 | offset = write_file(opt_image, rom_image, offset); | ||
818 | } | ||
819 | |||
820 | offset = write_directory_structure(root_entry->child, rom_image, offset); | ||
821 | printf("Directory data: %zd bytes\n", offset); | ||
822 | |||
823 | offset = write_data(root_entry, rom_image, offset); | ||
824 | |||
825 | /* We always write a multiple of blksize bytes, so that | ||
826 | losetup works. */ | ||
827 | offset = ((offset - 1) | (blksize - 1)) + 1; | ||
828 | printf("Everything: %zd kilobytes\n", offset >> 10); | ||
829 | |||
830 | /* Write the superblock now that we can fill in all of the fields. */ | ||
831 | write_superblock(root_entry, rom_image+opt_pad, offset); | ||
832 | printf("Super block: %zd bytes\n", sizeof(struct cramfs_super)); | ||
833 | |||
834 | /* Put the checksum in. */ | ||
835 | crc = crc32(0L, Z_NULL, 0); | ||
836 | crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad)); | ||
837 | ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc; | ||
838 | printf("CRC: %x\n", crc); | ||
839 | |||
840 | /* Check to make sure we allocated enough space. */ | ||
841 | if (fslen_ub < offset) { | ||
842 | die(MKFS_ERROR, 0, "not enough space allocated for ROM image (%Ld allocated, %d used)", fslen_ub, offset); | ||
843 | } | ||
844 | |||
845 | written = write(fd, rom_image, offset); | ||
846 | if (written < 0) { | ||
847 | die(MKFS_ERROR, 1, "write failed"); | ||
848 | } | ||
849 | if (offset != written) { | ||
850 | die(MKFS_ERROR, 0, "ROM image write failed (wrote %d of %d bytes): No space left on device?", written, offset); | ||
851 | } | ||
852 | |||
853 | /* (These warnings used to come at the start, but they scroll off the | ||
854 | screen too quickly.) */ | ||
855 | if (warn_namelen) | ||
856 | fprintf(stderr, /* bytes, not chars: think UTF-8. */ | ||
857 | "warning: filenames truncated to %d bytes (possibly less if multi-byte UTF-8)\n", | ||
858 | CRAMFS_MAXPATHLEN); | ||
859 | if (warn_skip) | ||
860 | fprintf(stderr, "warning: files were skipped due to errors\n"); | ||
861 | if (warn_size) | ||
862 | fprintf(stderr, | ||
863 | "warning: file sizes truncated to %luMB (minus 1 byte)\n", | ||
864 | 1L << (CRAMFS_SIZE_WIDTH - 20)); | ||
865 | if (warn_uid) /* (not possible with current Linux versions) */ | ||
866 | fprintf(stderr, | ||
867 | "warning: uids truncated to %u bits (this may be a security concern)\n", | ||
868 | CRAMFS_UID_WIDTH); | ||
869 | if (warn_gid) | ||
870 | fprintf(stderr, | ||
871 | "warning: gids truncated to %u bits (this may be a security concern)\n", | ||
872 | CRAMFS_GID_WIDTH); | ||
873 | if (warn_dev) | ||
874 | fprintf(stderr, | ||
875 | "WARNING: device numbers truncated to %u bits (this almost certainly means\n" | ||
876 | "that some device files will be wrong)\n", | ||
877 | CRAMFS_OFFSET_WIDTH); | ||
878 | if (opt_errors && | ||
879 | (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev)) | ||
880 | exit(MKFS_ERROR); | ||
881 | |||
882 | exit(MKFS_OK); | ||
883 | } | ||
884 | |||
885 | /* | ||
886 | * Local variables: | ||
887 | * c-file-style: "linux" | ||
888 | * End: | ||
889 | */ | ||
diff --git a/utils/ypr0tools/extract_section.c b/utils/ypr0tools/extract_section.c new file mode 100644 index 0000000000..8ad12bc7df --- /dev/null +++ b/utils/ypr0tools/extract_section.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Thomas Martitz | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <unistd.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <stdarg.h> | ||
29 | |||
30 | /* A simple replacement program for ( | ||
31 | * dd if=$file1 of=$file2 bs=1 skip=$offset count=$size | ||
32 | * | ||
33 | * Written because byte-size operations with dd are unbearably slow. | ||
34 | */ | ||
35 | |||
36 | void usage(void) | ||
37 | { | ||
38 | fprintf(stderr, "Usage: extract_section <romfile> <outfile> <offset> <byte count>\n"); | ||
39 | exit(1); | ||
40 | } | ||
41 | |||
42 | void die(const char* fmt, ...) | ||
43 | { | ||
44 | va_list ap; | ||
45 | va_start(ap, fmt); | ||
46 | vfprintf(stderr, fmt, ap); | ||
47 | va_end(ap); | ||
48 | exit(1); | ||
49 | } | ||
50 | |||
51 | int main(int argc, const char* argv[]) | ||
52 | { | ||
53 | if (argc != 5) | ||
54 | usage(); | ||
55 | |||
56 | int ifd, ofd; | ||
57 | ssize_t size = atol(argv[4]); | ||
58 | long skip = atol(argv[3]); | ||
59 | |||
60 | if (!size) | ||
61 | die("invalid byte count\n"); | ||
62 | |||
63 | ifd = open(argv[1], O_RDONLY); | ||
64 | if (ifd < 0) | ||
65 | die("Could not open %s for reading!\n", argv[1]); | ||
66 | |||
67 | ofd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666); | ||
68 | if (ofd < 0) | ||
69 | die("Could not create %s\n", argv[2]); | ||
70 | |||
71 | void *buf = malloc(size); | ||
72 | if (!buf) die("OOM\n"); | ||
73 | |||
74 | lseek(ifd, skip, SEEK_SET); | ||
75 | lseek(ofd, 0, SEEK_SET); | ||
76 | if (read(ifd, buf, size) != size) | ||
77 | die("Read failed\n"); | ||
78 | if (write(ofd, buf, size) != size) | ||
79 | die("write failed\n"); | ||
80 | |||
81 | close(ifd); | ||
82 | close(ofd); | ||
83 | |||
84 | exit(EXIT_SUCCESS); | ||
85 | } | ||
diff --git a/utils/ypr0tools/files/.rockbox/README b/utils/ypr0tools/files/.rockbox/README new file mode 100644 index 0000000000..f0e306e196 --- /dev/null +++ b/utils/ypr0tools/files/.rockbox/README | |||
@@ -0,0 +1 @@ | |||
This directory is empty and acts as mount point. | |||
diff --git a/utils/ypr0tools/files/Playlists/README b/utils/ypr0tools/files/Playlists/README new file mode 100644 index 0000000000..f0e306e196 --- /dev/null +++ b/utils/ypr0tools/files/Playlists/README | |||
@@ -0,0 +1 @@ | |||
This directory is empty and acts as mount point. | |||
diff --git a/utils/ypr0tools/files/etc/mods/safe_mode.raw b/utils/ypr0tools/files/etc/mods/safe_mode.raw new file mode 100644 index 0000000000..1c1aa61dd1 --- /dev/null +++ b/utils/ypr0tools/files/etc/mods/safe_mode.raw | |||
Binary files differ | |||
diff --git a/utils/ypr0tools/files/etc/mods/safe_mode.sh b/utils/ypr0tools/files/etc/mods/safe_mode.sh new file mode 100755 index 0000000000..122b2eabfe --- /dev/null +++ b/utils/ypr0tools/files/etc/mods/safe_mode.sh | |||
@@ -0,0 +1,111 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # YP-R0 Safe Mode!! | ||
4 | # - Part of the "Device Rescue Kit", modded ROM v2.20 and onwards | ||
5 | # Version: v0.3 | ||
6 | # v0.2 - initial version | ||
7 | # v0.3 - USB cable check implemented | ||
8 | # by lorenzo92 aka Memory | ||
9 | # memoryS60@gmail.com | ||
10 | |||
11 | CustomIMG="/mnt/media1/safe_mode.raw" | ||
12 | DefIMG="/etc/mods/safe_mode.raw" | ||
13 | |||
14 | timer=0 | ||
15 | # Seconds before turning the device OFF | ||
16 | timeout=2 | ||
17 | |||
18 | shutdown () { | ||
19 | sync | ||
20 | reboot | ||
21 | } | ||
22 | |||
23 | cableDaemon () { | ||
24 | cd /usr/local/bin | ||
25 | while [ 1 ] | ||
26 | do | ||
27 | if [ $timer -gt $timeout ] | ||
28 | then | ||
29 | shutdown | ||
30 | fi | ||
31 | |||
32 | if ./minird 0x0a | grep -q 0x00 | ||
33 | then | ||
34 | timer=$(($timer+1)) | ||
35 | else | ||
36 | timer=0 | ||
37 | fi | ||
38 | sleep 1 | ||
39 | done | ||
40 | } | ||
41 | |||
42 | # Back button is a \x08\x00\x00\x00 string... | ||
43 | # ...since bash removes null bytes for us, we must only care the single byte | ||
44 | var=$(dd if=/dev/r0Btn bs=4 count=1) | ||
45 | # Here a workaround to detect \x08 byte :S | ||
46 | var2=$(echo -e -n "\x08") | ||
47 | if [[ "$var" = "$var2" ]] | ||
48 | then | ||
49 | echo "Safe mode (USB) activated..." | ||
50 | # Put the backlight at the minimum level: no energy waste, please ;) | ||
51 | # Using low level interface | ||
52 | |||
53 | cd /usr/local/bin | ||
54 | ./afewr 0x1b 0x3 0x8 | ||
55 | |||
56 | # Long press reset time 5 secs | ||
57 | [ -e /etc/mods/reset_time_mod.sh ] && /bin/sh /etc/mods/reset_time_mod.sh | ||
58 | |||
59 | # Clear the screen and show a nice picture :D | ||
60 | |||
61 | echo -n "1" > /sys/class/graphics/fb0/blank | ||
62 | echo -n "0" >> /sys/class/graphics/fb0/blank | ||
63 | # echo -n "1" > /sys/class/graphics/fb2/blank | ||
64 | # echo -n "0" >> /sys/class/graphics/fb2/blank | ||
65 | if [ -e $CustomIMG ] | ||
66 | then | ||
67 | cat $CustomIMG > "/dev/fb0" | ||
68 | else | ||
69 | cat $DefIMG > "/dev/fb0" | ||
70 | fi | ||
71 | |||
72 | # Here the real USB connection stuff | ||
73 | # This is slightly modified by me; it was contained in the cramfs shipped with | ||
74 | # YP-R0 opensource package... | ||
75 | |||
76 | lsmod | grep g_file_storage | ||
77 | if [ $? == 0 ] | ||
78 | then | ||
79 | umount /mnt/media1/dev/gadget | ||
80 | fi | ||
81 | #if [ -d /mnt/media0 ] | ||
82 | #then | ||
83 | umount /mnt/media1 | ||
84 | umount /mnt/media0 | ||
85 | #umount /mnt/mmc | ||
86 | #fi | ||
87 | lsmod | grep rfs | ||
88 | if [ $? == 0 ] | ||
89 | then | ||
90 | rmmod rfs | ||
91 | fi | ||
92 | lsmod | grep g_file_storage | ||
93 | if [ $? == 0 ] | ||
94 | then | ||
95 | rmmod gadgetfs | ||
96 | rmmod g_file_storage | ||
97 | rmmod arcotg_udc | ||
98 | fi | ||
99 | lsmod | grep g_file_storage | ||
100 | if [ $? != 0 ] | ||
101 | then | ||
102 | modprobe g-file-storage file=/dev/stl3,/dev/stl2,/dev/mmcblk0 removable=1 | ||
103 | fi | ||
104 | |||
105 | # Let's implement the check if usb cable is still inserted or not... | ||
106 | cableDaemon | ||
107 | |||
108 | return 1 | ||
109 | else | ||
110 | return 0 | ||
111 | fi | ||
diff --git a/utils/ypr0tools/files/etc/profile b/utils/ypr0tools/files/etc/profile new file mode 100755 index 0000000000..4ba61d7535 --- /dev/null +++ b/utils/ypr0tools/files/etc/profile | |||
@@ -0,0 +1,66 @@ | |||
1 | export PS1='\u@\h \w$ ' | ||
2 | export PS2='> ' | ||
3 | export PS3='? ' | ||
4 | export PS4='[$LINENO]+' | ||
5 | |||
6 | export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin | ||
7 | export LD_LIBRARY_PATH=/mnt/media1/Lib:/mnt/media1/Lib/ExtraLib:/usr/lib | ||
8 | export FSL_OMX_COMPONENT_REGISTRY="/Sysdata/OpenMaxIL/ComponentRegistry.txt" | ||
9 | export FSL_OMX_MAX_INDEX_SIZE=1048576 | ||
10 | export MALLOC_CHECK_=0 | ||
11 | |||
12 | ulimit -s unlimited | ||
13 | hwclock -s | ||
14 | |||
15 | alias ls='ls --color=auto' | ||
16 | alias ll='ls -l --color=auto' | ||
17 | |||
18 | # Start with lorenzo92's safe mode | ||
19 | SCRIPT="/etc/mods/safe_mode.sh" | ||
20 | if [ -f $SCRIPT ] | ||
21 | then | ||
22 | /bin/sh $SCRIPT | ||
23 | # it returns 1 if usb was connected | ||
24 | if [ "$?" = "1" ] | ||
25 | then | ||
26 | sync | ||
27 | sleep 1 | ||
28 | reboot | ||
29 | fi | ||
30 | fi | ||
31 | |||
32 | if [ -e "/mnt/media1/r0" ] | ||
33 | then | ||
34 | MAINFILE="/mnt/media1/r0" | ||
35 | elif [ -f "/mnt/media0/r0" ] | ||
36 | then | ||
37 | # copy to media1 since USB wouldn't work | ||
38 | cp /mnt/media0/r0 /mnt/media1/r0_media0 | ||
39 | if [ "$?" = "0" ] | ||
40 | then # perhaps cp failed due to insufficient storage or so | ||
41 | MAINFILE="/mnt/media1/r0_media0" | ||
42 | else | ||
43 | MAINFILE="/usr/local/bin/r0" | ||
44 | fi | ||
45 | else | ||
46 | MAINFILE="/usr/local/bin/r0" | ||
47 | fi | ||
48 | |||
49 | # source the rockbox loader script | ||
50 | SOURCE="/mnt/media0/.rockbox/rockbox.sh" | ||
51 | [ -f $SOURCE ] && . $SOURCE | ||
52 | |||
53 | # source user script if available | ||
54 | SOURCE="/mnt/media0/rc.user" | ||
55 | [ -f $SOURCE ] && . $SOURCE | ||
56 | |||
57 | # finally call the entry point | ||
58 | if [ -e $MAINFILE ] | ||
59 | then | ||
60 | chmod 777 $MAINFILE | ||
61 | $MAINFILE Application AppMain | ||
62 | rm -f /mnt/media1/r0_media0 | ||
63 | sync | ||
64 | # sleep 5 | ||
65 | reboot | ||
66 | fi | ||
diff --git a/utils/ypr0tools/pack-firmware.sh b/utils/ypr0tools/pack-firmware.sh new file mode 100755 index 0000000000..f3b55548d9 --- /dev/null +++ b/utils/ypr0tools/pack-firmware.sh | |||
@@ -0,0 +1,132 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | ###################################################################### | ||
4 | # __________ __ ___. | ||
5 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
6 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
7 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
8 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
9 | # \/ \/ \/ \/ \/ | ||
10 | # | ||
11 | # * Script to generate a Samsung YP-R0 firmware file (R0.ROM) */ | ||
12 | ###################################################################### | ||
13 | # | ||
14 | # This file was oringally called NewPack.sh, its origin is the R0 open source | ||
15 | # package from Samsung. | ||
16 | # | ||
17 | # Muon Platform | ||
18 | # Copyright (c) 2004-2009 Samsung Electronics, Inc. | ||
19 | # All rights reserved. | ||
20 | # | ||
21 | # Rom Packaging Script | ||
22 | # It needs sudoer privilege of rm, mkdir, cp, mkcramfs. | ||
23 | # You can configure it in the /etc/sudoer file. | ||
24 | # This script is very dangerous. Be careful to use. | ||
25 | # | ||
26 | # SangMan Sim<sangman.sim@samsung.com> | ||
27 | |||
28 | # bail out early | ||
29 | set -e | ||
30 | |||
31 | DIR=${2:-"."} | ||
32 | DIR=${DIR%/} | ||
33 | REVISION="$DIR/RevisionInfo.txt" | ||
34 | CRAMFS="$DIR/cramfs-fsl.rom" | ||
35 | SYSDATA="$DIR/SYSDATA.bin" | ||
36 | MBOOT="$DIR/MBoot.bin" | ||
37 | MBOOT_TMP="${TMP_DIR:-$DIR}/MBoot.tmp" | ||
38 | LINUX="$DIR/zImage" | ||
39 | R0ROM=$1 | ||
40 | |||
41 | # some sanity checks | ||
42 | if [ $# -lt 1 ] || [ $# -gt 2 ]; then | ||
43 | echo "Usage $0 <rom file> [path to image files]" | ||
44 | exit 1 | ||
45 | fi | ||
46 | |||
47 | if [ ! -f ./MuonEncrypt ]; then | ||
48 | echo "Couldn't find MuonEncrypt binary (try 'make')" | ||
49 | exit 1 | ||
50 | fi | ||
51 | |||
52 | if [ ! -e $REVISION ]; then | ||
53 | cat >$REVISION <<EOF | ||
54 | Version : V2.30 | ||
55 | Target : KR | ||
56 | EOF | ||
57 | fi | ||
58 | |||
59 | |||
60 | function WriteImage { | ||
61 | echo "Adding $1 to $R0ROM" | ||
62 | #HEAD_STR=[`stat -c%s $1`/`md5sum $1 | cut -d " " -f 1`] | ||
63 | #HEAD_SIZE=`echo $HEAD_STR | wc -c` | ||
64 | #PACK_SIZE=`expr 44 - $HEAD_SIZE` | ||
65 | |||
66 | #while [ $PACK_SIZE -gt 0 ] | ||
67 | #do | ||
68 | #PACK_SIZE=`expr $PACK_SIZE - 1` | ||
69 | #echo -n 0 | ||
70 | #done | ||
71 | |||
72 | ./MuonEncrypt $1 >> $R0ROM | ||
73 | #cat $MBOOT >> $R0ROM | ||
74 | } | ||
75 | |||
76 | function Pack4Byte { | ||
77 | FILE_SIZE=`stat -c%s $R0ROM` | ||
78 | PACK_SIZE=`expr 4 - $FILE_SIZE % 4` | ||
79 | |||
80 | if [ $PACK_SIZE != 4 ] | ||
81 | then | ||
82 | while [ $PACK_SIZE -gt 0 ] | ||
83 | do | ||
84 | PACK_SIZE=`expr $PACK_SIZE - 1` || true | ||
85 | echo -en $1 >> $R0ROM | ||
86 | done | ||
87 | fi | ||
88 | |||
89 | } | ||
90 | |||
91 | echo Make $R0ROM | ||
92 | |||
93 | cat $REVISION > $R0ROM | ||
94 | echo User : $USER >> $R0ROM | ||
95 | echo Dir : $PWD >> $R0ROM | ||
96 | echo BuildTime : `date "+%y/%m/%d %H:%M:%S"` >> $R0ROM | ||
97 | echo MBoot : size\(`stat -c%s $MBOOT`\),checksum\(`md5sum $MBOOT | cut -d " " -f 1`\) >> $R0ROM | ||
98 | echo Linux : size\(`stat -c%s $LINUX`\),checksum\(`md5sum $LINUX | cut -d " " -f 1`\) >> $R0ROM | ||
99 | echo RootFS : size\(`stat -c%s $CRAMFS`\),checksum\(`md5sum $CRAMFS | cut -d " " -f 1`\) >> $R0ROM | ||
100 | echo Sysdata : size\(`stat -c%s $SYSDATA`\),checksum\(`md5sum $SYSDATA | cut -d " " -f 1`\) >> $R0ROM | ||
101 | |||
102 | Pack4Byte "\\n" | ||
103 | |||
104 | |||
105 | dd if=$MBOOT of=$MBOOT_TMP bs=96 count=1 2> /dev/null | ||
106 | |||
107 | echo `stat -c%s $MBOOT`:`md5sum $MBOOT | cut -d " " -f 1` >> $MBOOT_TMP | ||
108 | echo `stat -c%s $LINUX`:`md5sum $LINUX | cut -d " " -f 1` >> $MBOOT_TMP | ||
109 | echo `stat -c%s $CRAMFS`:`md5sum $CRAMFS | cut -d " " -f 1` >> $MBOOT_TMP | ||
110 | echo `stat -c%s $SYSDATA`:`md5sum $SYSDATA | cut -d " " -f 1` >> $MBOOT_TMP | ||
111 | |||
112 | dd if=$MBOOT of=$MBOOT_TMP bs=1088 skip=1 seek=1 2> /dev/null | ||
113 | WriteImage $MBOOT_TMP | ||
114 | |||
115 | #rm $MBOOT_TMP | ||
116 | |||
117 | Pack4Byte "0" | ||
118 | |||
119 | WriteImage $LINUX | ||
120 | |||
121 | Pack4Byte "0" | ||
122 | |||
123 | WriteImage $CRAMFS | ||
124 | |||
125 | Pack4Byte "0" | ||
126 | |||
127 | WriteImage $SYSDATA | ||
128 | |||
129 | echo $R0ROM : `stat -c%s $R0ROM`, `md5sum $R0ROM | cut -d " " -f 1` | ||
130 | #head -9 $R0ROM | ||
131 | |||
132 | echo "Done" | ||
diff --git a/utils/ypr0tools/patch-firmware.sh b/utils/ypr0tools/patch-firmware.sh new file mode 100755 index 0000000000..879b3f879d --- /dev/null +++ b/utils/ypr0tools/patch-firmware.sh | |||
@@ -0,0 +1,67 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | |||
4 | ###################################################################### | ||
5 | # __________ __ ___. | ||
6 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
7 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
8 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
9 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
10 | # \/ \/ \/ \/ \/ | ||
11 | # | ||
12 | # * Script to patch an unpacked Samsung YP-R0 firmware file */ | ||
13 | # Copyright (C) 2011 Thomas Martitz | ||
14 | ###################################################################### | ||
15 | # bail out early | ||
16 | set -e | ||
17 | |||
18 | if [ $# -lt 1 ] || [ $# -gt 2 ]; then | ||
19 | echo "Usage: $0 <files path> [path to unpacked rom]" | ||
20 | echo "\t<files path> is expected to have a rootfs layout and to contain" | ||
21 | echo "\tonly the files to overwrite (plain cp -r is used)" | ||
22 | exit 1 | ||
23 | fi | ||
24 | |||
25 | FILES=${1%/} | ||
26 | FILES=${FILES:-"/"} | ||
27 | DIR=${2:-"."} | ||
28 | DIR=${DIR%/} | ||
29 | ROOTFS=$DIR/rootfs | ||
30 | CRAMFS=$DIR/cramfs-fsl.rom | ||
31 | |||
32 | # sanity checks | ||
33 | |||
34 | # this needs to be run as root! | ||
35 | if [ $(whoami) != "root" ] | ||
36 | then | ||
37 | echo "This needs to be run as root" | ||
38 | exit 1 | ||
39 | fi | ||
40 | |||
41 | if [ ! -e $1 ] || [ ! -e $2 ]; then | ||
42 | echo "$1 or $2 does not exist" | ||
43 | exit 1 | ||
44 | fi | ||
45 | |||
46 | if [ -z $ROOTFS ] || [ -z $FILES ]; then | ||
47 | echo "Invalid input directories" | ||
48 | exit 1 | ||
49 | fi | ||
50 | |||
51 | if [ ! -e $CRAMFS ]; then | ||
52 | echo "Cramfs image not found (did you extract the firmware?)" | ||
53 | exit 1 | ||
54 | fi | ||
55 | |||
56 | echo "Extracting cramfs image" | ||
57 | |||
58 | [ ! -e $ROOTFS ] || rmdir -p $ROOTFS | ||
59 | cramfs-1.1/cramfsck -x $ROOTFS $CRAMFS | ||
60 | |||
61 | echo "Patching rootfs" | ||
62 | echo "cp -r $FILES/* $ROOTFS/" | ||
63 | cp -r $FILES/.rockbox $ROOTFS/ | ||
64 | cp -r $FILES/* $ROOTFS/ | ||
65 | |||
66 | echo "Packing new cramfs image" | ||
67 | cramfs-1.1/mkcramfs $ROOTFS $CRAMFS | ||
diff --git a/utils/ypr0tools/rockbox.sh b/utils/ypr0tools/rockbox.sh new file mode 100755 index 0000000000..cbe54fd223 --- /dev/null +++ b/utils/ypr0tools/rockbox.sh | |||
@@ -0,0 +1,47 @@ | |||
1 | #!/bin/sh | ||
2 | ###################################################################### | ||
3 | # __________ __ ___. | ||
4 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
5 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
6 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
7 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
8 | # \/ \/ \/ \/ \/ | ||
9 | # | ||
10 | # * Samsung YP-R0 Rockbox as an application loader * | ||
11 | # Lorenzo Miori (C) 2011 | ||
12 | ###################################################################### | ||
13 | |||
14 | # This is expected to be sourced by the shell, which is then | ||
15 | # expected to run $MAINFILE | ||
16 | |||
17 | # Check for menu button being pressed. Return immediately to launch the OF | ||
18 | var=$(dd if=/dev/r0Btn bs=4 count=1) | ||
19 | # Here a workaround to detect the byte | ||
20 | var2=$(echo -e -n "\x07") | ||
21 | |||
22 | if [[ "$var" = "$var2" ]] | ||
23 | then | ||
24 | return | ||
25 | fi | ||
26 | |||
27 | |||
28 | # Blank-Unblank video to get rid of Samsung BootLogo, but turn off backlight before to hide these things :) | ||
29 | echo -n "0" > /sys/devices/platform/afe.0/bli | ||
30 | echo -n "1" > /sys/class/graphics/fb0/blank | ||
31 | echo -n "0" >> /sys/class/graphics/fb0/blank | ||
32 | |||
33 | amixer sset 'Soft Mute' 0 | ||
34 | amixer sset 'Master' 85% | ||
35 | |||
36 | # We set-up various settings for the cpu governor: default are | ||
37 | # Every 1,5 s the kernel evaluates if it's the case to down/up clocking the cpu | ||
38 | echo "ondemand" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor | ||
39 | echo "1" > /sys/devices/system/cpu/cpu0/cpufreq/ondemand/ignore_nice_load | ||
40 | echo "150000" > /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate | ||
41 | echo "95" > /sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold | ||
42 | |||
43 | # bind these two to the root so that they're writable | ||
44 | mount --bind /mnt/media0/.rockbox /.rockbox | ||
45 | mount --bind /mnt/media0/Playlists /Playlists | ||
46 | |||
47 | MAINFILE="/mnt/media0/.rockbox/rockbox" | ||
diff --git a/utils/ypr0tools/unpack-firmware.sh b/utils/ypr0tools/unpack-firmware.sh new file mode 100755 index 0000000000..ab80670c79 --- /dev/null +++ b/utils/ypr0tools/unpack-firmware.sh | |||
@@ -0,0 +1,90 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | ###################################################################### | ||
4 | # __________ __ ___. | ||
5 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
6 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
7 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
8 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
9 | # \/ \/ \/ \/ \/ | ||
10 | # | ||
11 | # * Script to unpack a Samsung YP-R0 firmware file (R0.ROM) */ | ||
12 | ###################################################################### | ||
13 | |||
14 | # The file was originally called MuonDecrypt.sh | ||
15 | # | ||
16 | # I'm not sure about the original author of this file, as it wasn't included in Samsung package. | ||
17 | # But I guess it was done by JeanLouis, an Italian user of the Hardware Upgrade Forum. If needed, we should search throug old posts for that... | ||
18 | # | ||
19 | |||
20 | |||
21 | # bail out early | ||
22 | set -e | ||
23 | |||
24 | # some sanity checks | ||
25 | if [ $# -lt 1 ] || [ $# -gt 2 ]; then | ||
26 | echo "Usage $0 <rom file> [out dir]" | ||
27 | exit 1 | ||
28 | fi | ||
29 | |||
30 | |||
31 | ROM=$1 | ||
32 | DIR=${2:-"."} | ||
33 | DIR=${DIR%/} | ||
34 | MBOOT="$DIR/MBoot.bin" | ||
35 | MBOOT_TMP="${TMP_DIR:-$DIR}/MBoot.tmp" | ||
36 | LINUX="$DIR/zImage" | ||
37 | CRAMFS="$DIR/cramfs-fsl.rom" | ||
38 | SYSDATA="$DIR/SYSDATA.bin" | ||
39 | MD5SUMS="$DIR/MD5SUMS" | ||
40 | TMP="${TMP_DIR:-$DIR}/_$$.tmp" | ||
41 | |||
42 | |||
43 | if [ ! -f ./extract_section ]; then | ||
44 | echo "Couldn't find extract_section binary (try 'make')" | ||
45 | exit 1 | ||
46 | fi | ||
47 | |||
48 | if [ ! -f ./MuonEncrypt ]; then | ||
49 | echo "Couldn't find MuonEncrypt binary (try 'make')" | ||
50 | exit 1 | ||
51 | fi | ||
52 | |||
53 | mkdir -p $DIR | ||
54 | |||
55 | if [ ! -w $DIR ]; then | ||
56 | echo "Target dir not writable" | ||
57 | exit 1 | ||
58 | fi | ||
59 | |||
60 | ExtractAndDecrypt() { | ||
61 | START=$(expr $START - $2) | ||
62 | echo "Extracting $1..." | ||
63 | ./extract_section $ROM $TMP $START $2 | ||
64 | echo "Decrypt $1..." | ||
65 | ./MuonEncrypt $TMP > $1 | ||
66 | } | ||
67 | |||
68 | size=( `head -n 9 $ROM | tail -n 4 | while read LINE; do echo $LINE | cut -d\( -f 2 | cut -d\) -f 1; done`) | ||
69 | checksum=( `head -n 9 $ROM | tail -n 4 | while read LINE; do echo $LINE | cut -d\( -f 3 | cut -d\) -f 1; done`) | ||
70 | |||
71 | echo "${checksum[0]} $MBOOT" > $MD5SUMS | ||
72 | echo "${checksum[1]} $LINUX" >> $MD5SUMS | ||
73 | echo "${checksum[2]} $CRAMFS" >> $MD5SUMS | ||
74 | echo "${checksum[3]} $SYSDATA" >> $MD5SUMS | ||
75 | |||
76 | START=`stat -c%s $ROM` | ||
77 | |||
78 | ExtractAndDecrypt $SYSDATA ${size[3]} | ||
79 | ExtractAndDecrypt $CRAMFS ${size[2]} | ||
80 | ExtractAndDecrypt $LINUX ${size[1]} | ||
81 | ExtractAndDecrypt $MBOOT_TMP ${size[0]} | ||
82 | |||
83 | rm $TMP | ||
84 | echo "Create $MBOOT..." | ||
85 | dd if=$MBOOT_TMP of=$MBOOT bs=96 count=1 2>/dev/null | ||
86 | dd if=$MBOOT_TMP of=$MBOOT bs=1088 skip=1 seek=1 2>/dev/null | ||
87 | rm $MBOOT_TMP | ||
88 | |||
89 | echo "Check integrity:" | ||
90 | md5sum -c $MD5SUMS | ||