├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── debian
├── changelog
├── compat
├── control
├── copyright
├── docs
├── rules
└── source
│ └── format
├── ebiso.c
├── include
├── CE.h
├── SL.h
├── ebiso.h
├── el_torito.h
├── filename.h
├── globals.h
├── iso9660.h
├── list.h
└── write_files.h
├── lib
├── CE.c
├── SL.c
├── el_torito.c
├── filename.c
├── globals.c
├── iso9660.c
├── list.c
└── write_files.c
├── man
└── man1
│ └── ebiso.1.gz
└── packaging
└── ebiso.spec
/.gitignore:
--------------------------------------------------------------------------------
1 | ebiso
2 | *.o
3 | *.a
4 | .d/
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # add .h files to dependencies: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine
2 | # FLAGS=-g3 -O3 -m64 -std=gnu9x -Wall -Wshadow -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes
3 | # $(info $$OBJ is [${OBJ}])
4 |
5 | CC ?= gcc
6 | LIBDIR=lib
7 | INCLUDEDIR=./include
8 | DESTDIR=
9 | INSTDIR=/usr/bin
10 | PROGNAME=ebiso
11 |
12 | BASE_DEPDIR=.d
13 | DEPDIR=.d/${LIBDIR}
14 | $(shell mkdir -p $(DEPDIR) >/dev/null)
15 | DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
16 | POSTCOMPILE=mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
17 |
18 | LIBS=-L${LIBDIR} -lmain -lm
19 | MAIN_LIB=${LIBDIR}/libmain.a
20 | MANDIR=/usr/share/man
21 |
22 | #FLAGS=-fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -I${INCLUDEDIR}
23 | CFLAGS=-fcommon
24 | FLAGS=$(CFLAGS) -g3 -std=gnu9x -Wall -Wshadow -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -I${INCLUDEDIR}
25 | VERSION=$(shell grep "\#define EBISO_VERSION" ${INCLUDEDIR}/${PROGNAME}.h | awk '{ print $$NF }' | sed s/\"//g)
26 |
27 | SRC=$(sort $(wildcard ${LIBDIR}/*.c))
28 | HEADERS=$(wildcard ${INCLUDEDIR}/*.h)
29 | OBJ=$(addprefix ${LIBDIR}/,$(notdir $(SRC:.c=.o)))
30 |
31 | # some variables for building RPMs
32 | bindir = $(INSTDIR)
33 | specfile = packaging/$(PROGNAME).spec
34 | distversion = $(VERSION)
35 | rpmrelease = %nil
36 | obsproject = home:gdha
37 | obspackage = $(PROGNAME)-$(distversion)
38 | # end of some variables for building RPMs
39 |
40 | all: ${MAIN_LIB} ${PROGNAME}
41 |
42 | ${LIBDIR}/%.o: ${LIBDIR}/%.c $(DEPDIR)/%.d
43 | ${CC} ${FLAGS} ${DEPFLAGS} -c -o $@ $<
44 | $(POSTCOMPILE)
45 |
46 | $(DEPDIR)/%.d: ;
47 |
48 | ${MAIN_LIB}: ${OBJ} ${HEADERS}
49 | ar rcs $@ ${OBJ}
50 |
51 | ${PROGNAME}: ${OBJ} ${PROGNAME}.c ${HEADERS}
52 | ${CC} ${FLAGS} -o ${PROGNAME} ${PROGNAME}.c ${LIBS}
53 |
54 | .PHONY: dist
55 | dist: clean rewrite $(PROGNAME)-$(distversion).tar.gz restore
56 |
57 | .PHONY: $(PROGNAME)-$(distversion).tar.gz
58 | $(PROGNAME)-$(distversion).tar.gz:
59 | @echo -e "\033[1m== Creating tar archive $(PROGNAME)-$(distversion).tar.gz ==\033[0;0m"
60 | tar czf ../$(PROGNAME)-$(distversion).tar.gz \
61 | --exclude=.git \
62 | --exclude=.gitignore \
63 | --exclude=README.md \
64 | --transform='s,^\.,ebiso-$(distversion),S' .
65 | @mv ../$(PROGNAME)-$(distversion).tar.gz ./
66 |
67 | .PHONY: clean
68 | clean:
69 | @echo -e "\033[1m== Cleaning up ==\033[0;0m"
70 | rm -f ${LIBDIR}/*.o ${LIBDIR}/*.a
71 | rm -f $(PROGNAME)
72 | rm -f $(PROGNAME)*.tar.gz
73 | rm -f $(PROGNAME)*.rpm
74 | rm -rf ${BASE_DEPDIR}
75 |
76 | .PHONY: rewrite
77 | rewrite:
78 | @echo -e "\033[1m== Rewriting $(specfile) (updating version) ==\033[0;0m"
79 | sed -i.orig -e 's#^Version:.*#Version:\t\t$(distversion)#' $(specfile)
80 |
81 | .PHONY: restore
82 | restore:
83 | @echo -e "\033[1m== Restore original $(specfile) ==\033[0;0m"
84 | mv -f $(specfile).orig $(specfile)
85 |
86 | .PHONY: rpm
87 | rpm: dist $(specfile)
88 | @echo -e "\033[1m== Building RPM package $(PROGNAME)-$(distversion) ==\033[0;0m"
89 | rpmbuild -v --clean \
90 | --define "_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \
91 | --define "debug_package %{nil}" \
92 | --define "_rpmdir %(pwd)" \
93 | -tb $(PROGNAME)-$(distversion).tar.gz
94 |
95 | .PHONY: install
96 | install: ${PROGNAME}
97 | @echo -e "\033[1m== Installing $(PROGNAME)-$(distversion) ==\033[0;0m"
98 | if [ ! -d $(DESTDIR)$(INSTDIR) ]; then mkdir -m 755 -p $(DESTDIR)$(INSTDIR); fi
99 | install -m 0755 ${PROGNAME} $(DESTDIR)$(INSTDIR)
100 | if [ ! -d $(DESTDIR)${MANDIR}/man1 ]; then mkdir -m 755 -p $(DESTDIR)${MANDIR}/man1; fi
101 | install -m 0644 man/man1/$(PROGNAME).1.gz $(DESTDIR)${MANDIR}/man1/
102 | strip $(DESTDIR)$(INSTDIR)/$(PROGNAME)
103 |
104 | .PHONY: uninstall
105 | uninstall:
106 | -rm $(DESTDIR)$(INSTDIR)/${PROGNAME}
107 | -rm $(DESTDIR)${MANDIR}/man1/$(PROGNAME).1.gz
108 |
109 | -include $(patsubst %,$(BASE_DEPDIR)/%.d,$(basename $(SRC)))
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ebiso
2 | UEFI bootable ISO image creator
3 |
4 | Primary intention of ebiso was to create simple bootable UEFI ISO image for [ReaR](https://github.com/rear/rear) on SLES11. It should however work on other Linux based distributions as well.
5 |
6 | - no additional dependencies
7 | - released under GPL
8 | - supports 8.3 and long file names (up to 255 characters) formats
9 | - more info can be found in [ebiso wiki](https://gitlab.com/gozora/ebiso/wikis/home)
10 | - tested with rear on SLES11 SP3 and Centos 6.7
11 | - basic [usage](https://gitlab.com/gozora/ebiso/wikis/Usage)
12 | - [features](https://gitlab.com/gozora/ebiso/wikis/Features-in-progress-(limitations)) that can be expected
13 | - [packages](https://gitlab.com/gozora/ebiso/wikis/Packages)
14 |
--------------------------------------------------------------------------------
/debian/changelog:
--------------------------------------------------------------------------------
1 | ebiso (0.2.3-1) unstable; urgency=low
2 |
3 | * Initial release
4 |
5 | -- Michael Ablassmeier Thu, 09 Jun 2016 10:08:29 +0200
6 |
--------------------------------------------------------------------------------
/debian/compat:
--------------------------------------------------------------------------------
1 | 9
2 |
--------------------------------------------------------------------------------
/debian/control:
--------------------------------------------------------------------------------
1 | Source: ebiso
2 | Section: otherosfs
3 | Priority: optional
4 | Maintainer: Vladimir (sodoma) Gozora
5 | Build-Depends: debhelper (>= 9)
6 | Standards-Version: 3.9.5
7 | Homepage: https://github.com/gozora/ebiso/wiki
8 | Vcs-Git: git://github.com/gozora/ebiso
9 | Vcs-Browser: https://github.com/gozora/ebiso
10 |
11 | Package: ebiso
12 | Architecture: any
13 | Depends: ${shlibs:Depends}, ${misc:Depends}
14 | Description: create UEFI bootable ISO images
15 | Ebiso is a small program written in C, that creates UEFI bootable ISO image
16 | no additional dependencies.
17 |
--------------------------------------------------------------------------------
/debian/copyright:
--------------------------------------------------------------------------------
1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: ebiso
3 | Source: https://github.com/gozora/ebiso/
4 |
5 | Files: *
6 | Copyright: 2015 Vladimir (sodoma) Gozora
7 | License: GPL-2
8 | This package is free software; you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation; either version 2 of the License, or
11 | (at your option) any later version.
12 | .
13 | This package is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 | .
18 | You should have received a copy of the GNU General Public License
19 | along with this program. If not, see
20 | .
21 | On Debian systems, the complete text of the GNU General
22 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
23 |
--------------------------------------------------------------------------------
/debian/docs:
--------------------------------------------------------------------------------
1 | README.md
2 |
--------------------------------------------------------------------------------
/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # See debhelper(7) (uncomment to enable)
3 | # output every command that modifies files on the build system.
4 | #DH_VERBOSE = 1
5 |
6 | # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
7 | DPKG_EXPORT_BUILDFLAGS = 1
8 | include /usr/share/dpkg/default.mk
9 |
10 | # see FEATURE AREAS in dpkg-buildflags(1)
11 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
12 |
13 | # see ENVIRONMENT in dpkg-buildflags(1)
14 | # package maintainers to append CFLAGS
15 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
16 | # package maintainers to append LDFLAGS
17 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
18 |
19 |
20 | # main packaging script based on dh7 syntax
21 | %:
22 | dh $@
23 |
24 | # debmake generated override targets
25 | # This is example for Cmake (See http://bugs.debian.org/641051 )
26 | #override_dh_auto_configure:
27 | # dh_auto_configure -- \
28 | # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (quilt)
2 |
--------------------------------------------------------------------------------
/ebiso.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ebiso.c
3 | *
4 | * Version: 0.2.2
5 | *
6 | * Release date: 2.4.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "ebiso.h"
29 |
30 | int main(int argc, char *argv[]) {
31 | struct file_list_t *list = (struct file_list_t*) malloc(sizeof(struct file_list_t));
32 | struct file_list_t *rr_list = list;
33 | struct ISO_data_t ISO_data;
34 | FILE *fp = NULL;
35 | FILE *boot_catalog = NULL;
36 | void *boot_descriptor = (void *) malloc(BLOCK_SIZE);
37 | void *header = NULL;
38 | void *terminator = NULL;
39 | void *path_table_LSB = NULL;
40 | void *path_table_MSB = NULL;
41 | int option = 0;
42 | int e_flag = 0;
43 | int o_flag = 0;
44 | int rv = 0;
45 |
46 | memset(list, 0, sizeof(struct file_list_t));
47 | memset(boot_descriptor, 0, BLOCK_SIZE);
48 | memset(&ISO_data, 0, sizeof(struct ISO_data_t));
49 |
50 | static struct option longOptions[] = {
51 | {"efi-boot", required_argument, 0, 'e'},
52 | {"output", required_argument, 0, 'o'},
53 | {"rock-ridge", no_argument, 0, 'R'},
54 | {"help", no_argument, 0, 'h'},
55 | {"version", no_argument, 0, 'v'},
56 | {0, 0, 0, 0}
57 | };
58 |
59 | while ((option = getopt_long(argc, argv, "e:ho:Rv", longOptions, NULL)) != -1) {
60 | switch(option) {
61 | case 'h':
62 | help_msg(MSG_USAGE);
63 | goto cleanup;
64 | break;
65 | case 'v':
66 | help_msg(MSG_VERSION);
67 | goto cleanup;
68 | break;
69 | case 'e':
70 | if (*optarg == '-') {
71 | printf("Error: %s is invalid argument for option -e\n", optarg);
72 | rv = E_BADSYNTAX;
73 | err_msg(rv);
74 | goto cleanup;
75 | }
76 | else {
77 | strncpy(ISO_data.efi_boot_file, optarg, sizeof(ISO_data.efi_boot_file));
78 | e_flag++;
79 | }
80 | break;
81 | case 'o':
82 | if (*optarg == '-') {
83 | printf("Error: %s is invalid argument for option -o\n", optarg);
84 | rv = E_BADSYNTAX;
85 | err_msg(rv);
86 | goto cleanup;
87 | }
88 | else {
89 | strncpy(ISO_data.iso_file, optarg, sizeof(ISO_data.iso_file));
90 | o_flag++;
91 | ISO_data.options |= (1 << OPT_o);
92 | }
93 | break;
94 | case 'R':
95 | if ((rv = set_option(&ISO_data.options, OPT_R)) != E_OK) {
96 | err_msg(rv);
97 | goto cleanup;
98 | }
99 | break;
100 | default:
101 | rv = E_BADSYNTAX;
102 | goto cleanup;
103 | break;
104 | }
105 | }
106 |
107 | /* First syntax check */
108 | if (e_flag != 1 || o_flag != 1 || argc < 6) {
109 | rv = E_BADSYNTAX;
110 | err_msg(rv);
111 | goto cleanup;
112 | }
113 |
114 | /* Working dir will be the last argument */
115 | strncpy(ISO_data.work_dir, argv[argc-1], MAX_DIR_STR_LEN);
116 |
117 | /* Yes, BOOT.CAT file will stay in (/) root of ISO file */
118 | snprintf(ISO_data.boot_cat_file, MAX_DIR_STR_LEN, "%s/%s", ISO_data.work_dir, "BOOT.CAT");
119 | snprintf(ISO_data.efi_boot_file_full, MAX_DIR_STR_LEN, "%s/%s", ISO_data.work_dir, ISO_data.efi_boot_file);
120 |
121 | /* Check if we can read working dir & add some stat info for ABS root directory */
122 | if ((rv = check_availability(ISO_data.work_dir, TYPE_DIR, MODE_READ, list)) != 0)
123 | goto cleanup;
124 |
125 | /* Fill some additional info about ABS root directory */
126 | strncpy(list->name_path, ".", 1);
127 | list->name_short_len = 1;
128 | list->name_conv_len = 1;
129 | list->dir_id = 1;
130 | list->parent_id = 1;
131 | list->next = (struct file_list_t*) malloc(sizeof(struct file_list_t));
132 | ISO_data.dir_count = 1;
133 | rr_list = list->next;
134 | memset(rr_list, 0, sizeof(struct file_list_t));
135 |
136 | /* Check if we can read UEFI boot image */
137 | if ((rv = check_availability(ISO_data.efi_boot_file_full, TYPE_FILE, MODE_READ, NULL)) != 0)
138 | goto cleanup;
139 |
140 | /*
141 | * Check if destination directory is writeable.
142 | * This will as well truncate existing file (if any) to zero
143 | */
144 | if ((fp = fopen(ISO_data.iso_file, "w")) == NULL) {
145 | printf("Error: Failed to create output file [%s]: %s\n", ISO_data.iso_file, strerror(errno));
146 | goto cleanup;
147 | }
148 | else
149 | fclose(fp);
150 |
151 | /* Delete dest iso file (if any) */
152 | unlink(ISO_data.iso_file);
153 |
154 | /* Create boot calalog (only as placeholder) */
155 | if ((boot_catalog = fopen(ISO_data.boot_cat_file, "w")) != NULL) {
156 | fwrite(boot_descriptor, 1, BLOCK_SIZE, boot_catalog);
157 | fclose(boot_catalog);
158 | }
159 | else {
160 | printf("Error: Failed to open [%s] for writing: %s\n", ISO_data.work_dir, strerror(errno));
161 | rv = E_WRFAIL;
162 | goto cleanup;
163 | }
164 |
165 | /* Create initial file structure */
166 | if ((rv = list_create(ISO_data.work_dir, &rr_list, &ISO_data)) != E_OK)
167 | goto cleanup;
168 |
169 | /* Remove possible duplicates */
170 | filename_rename_duplicates(list);
171 |
172 | /* Calculate path table offset, so LBAs can be offsetted in future */
173 | ISO_data.path_table_offset = get_path_table_offset(list);
174 |
175 | /* Assign future LBAs to created file list */
176 | if ((rv = iso9660_assign_LBA(list, &ISO_data)) != E_OK)
177 | goto cleanup;
178 |
179 | /* Write data to boot catalog */
180 | if ((rv = et_boot_catalog(ISO_data)) != E_OK)
181 | goto cleanup;
182 |
183 | /*
184 | * Create path table and assamble header
185 | * ISO_data in iso9660_path_table() is used to store path table size
186 | */
187 | if ((rv = iso9660_path_table(list, &path_table_LSB, LSB, &ISO_data)) != E_OK)
188 | goto cleanup;
189 | else {
190 | iso9660_path_table(list, &path_table_MSB, MSB, NULL);
191 | iso9660_header(&header, *list, ISO_data);
192 | }
193 |
194 | /* Assamble terminator */
195 | iso9660_terminator(&terminator);
196 |
197 | /* Assamble boot descriptor */
198 | et_boot_record_descr(&boot_descriptor, ISO_data);
199 |
200 | /* Write meta data to file */
201 | fp = fopen(ISO_data.iso_file, "w");
202 | fseek(fp, 0x8000, SEEK_SET); // Starting block in file
203 | fwrite(header, BLOCK_SIZE, 1, fp); // 0x8000 - LBA 0x10 - Static
204 | fwrite(boot_descriptor, BLOCK_SIZE, 1, fp); // 0x8800 - LBA 0x11 - Static
205 | fwrite(terminator, BLOCK_SIZE, 1, fp); // 0x9000 - LBA 0x12 - Static
206 | fseek(fp, BLOCK_SIZE, SEEK_CUR); // 0x9800 - LBA 0x13 - Static
207 |
208 | fwrite(path_table_LSB, (ISO_data.path_table_offset + 1) * BLOCK_SIZE, 1, fp); // (0xA000 - LBA 0x14) - Dynamic
209 | fseek(fp, BLOCK_SIZE, SEEK_CUR); // (0xA800 - LBA 0x15)
210 | fwrite(path_table_MSB, (ISO_data.path_table_offset + 1) * BLOCK_SIZE, 1, fp); // (0xB000 - LBA 0x16)
211 | fseek(fp, BLOCK_SIZE, SEEK_CUR); // (0xB800 - LBA 0x17)
212 |
213 | /* If write of files failed, get rid of output iso file */
214 | if ((rv = iso9660_directory_record(list, fp, &ISO_data)) != E_OK) // 0xC000
215 | unlink(ISO_data.iso_file);
216 | else {
217 | fseek(fp, 0, SEEK_END);
218 | fseek(fp, BLOCK_SIZE - 1, SEEK_CUR);
219 | fwrite(&zero, 1, 1, fp); // Write one empty block at the end
220 | }
221 |
222 | fclose(fp);
223 |
224 | #if (DEBUG == 1)
225 | printf("DEBUG: %s(): Number of directories: [%d]\n", __func__, ISO_data.dir_count);
226 | int i = 0;
227 | printf("DEBUG: %s(): MAIN STRUCTURE DUMP:\n", __func__);
228 | printf("%-5s %-4s %-55s %-11s %-3s %-9s %-5s %-7s %-12s %-5s %-11s %-6s %-8s %-7s\n", \
229 | "Level", "PID", "Name", "Size", "ID", "LBA", "Flag", "Blocks", "conf_name", \
230 | "Len", "ISO9660_len", "CE_LBA", "Full_len", "CE_off");
231 | for (i = 0; i <= 128; i++)
232 | disp_level(list, i);
233 | #endif
234 |
235 | cleanup:
236 |
237 | list_clean(list);
238 | if (terminator != NULL)
239 | free(terminator);
240 | if (path_table_LSB != NULL)
241 | free(path_table_LSB);
242 | if (path_table_MSB != NULL)
243 | free(path_table_MSB);
244 | if (header != NULL)
245 | free(header);
246 | if (boot_descriptor != NULL)
247 | free(boot_descriptor);
248 |
249 | return rv;
250 | }
251 |
252 | #if (DEBUG == 1)
253 | static void disp_level(struct file_list_t *list_to_display, int level) {
254 | char flag = 0;
255 | struct tm *ts;
256 | char buff[80];
257 |
258 | while(list_to_display->next != NULL) {
259 | if (list_to_display->level == level) {
260 | if (S_ISDIR(list_to_display->st_mode))
261 | flag = 'D';
262 | else
263 | flag = 'F';
264 |
265 | if (S_ISLNK(list_to_display->st_mode))
266 | flag = 'L';
267 |
268 | ts = localtime(&list_to_display->mtime);
269 | strftime(buff, sizeof(buff), "%a %Y-%m-%d %H:%M:%S %Z", ts);
270 |
271 | printf("%-5d %-4d %-55s 0x%-9x %-3d 0x%-7x %-5c %-7d %-12s %-5d 0x%-9x 0x%-4x 0x%-6x 0x%-5x\n", \
272 | level, list_to_display->parent_id, list_to_display->name_path, list_to_display->size, \
273 | list_to_display->dir_id, list_to_display->LBA, flag, list_to_display->blocks, \
274 | list_to_display->name_conv, list_to_display->name_conv_len, list_to_display->ISO9660_len, \
275 | list_to_display->CE_LBA, list_to_display->full_len, list_to_display->CE_offset);
276 | }
277 |
278 | list_to_display = list_to_display->next;
279 | }
280 | }
281 | #endif
282 |
283 | static int set_option(uint32_t *opt2set, enum opt_l option) {
284 | if ((*opt2set & (1 << option)) != 0)
285 | return E_BADSYNTAX;
286 | else
287 | *opt2set |= (1 << option);
288 |
289 | return E_OK;
290 | }
291 |
292 | int option_on_off(uint32_t option2check, enum opt_l option) {
293 | if ((option2check & (1 << option)) != 0)
294 | return E_OK;
295 | else
296 | return E_NOTSET;
297 | }
298 |
299 | static int check_availability(char *filename, enum check_type_l type, enum check_mode_l mode, struct file_list_t *file_list) {
300 | struct stat rr_stat;
301 | int rv = E_OK;
302 |
303 | memset(&rr_stat, 0, sizeof(struct stat));
304 |
305 | if (stat(filename, &rr_stat) != 0) {
306 | printf("Error: check_availability(): Failed to stat [%s]: %s\n", filename, strerror(errno));
307 | rv = E_STATFAIL;
308 | }
309 |
310 | if (mode == MODE_READ && rv == 0) {
311 | if (access(filename, R_OK) != 0) {
312 | printf("Error: check_availability(): Failed to read [%s]: %s\n", filename, strerror(errno));
313 | rv = E_READFAIL;
314 | }
315 | }
316 | else if (mode == MODE_WRITE && rv == 0) {
317 | if (access(filename, W_OK) != 0) {
318 | printf("Error: check_availability(): Failed to write [%s]: %s\n", filename, strerror(errno));
319 | rv = E_WRFAIL;
320 | }
321 | }
322 |
323 | if (type == TYPE_FILE && rv == 0) {
324 | if (!S_ISREG(rr_stat.st_mode)) {
325 | printf("Error: check_availability(): Not a regular file [%s]\n", filename);
326 | rv = E_NOTREG;
327 | }
328 | }
329 |
330 | if (type == TYPE_DIR && rv == 0) {
331 | if (!S_ISDIR(rr_stat.st_mode)) {
332 | printf("Error: check_availability(): Not a directory [%s]\n", filename);
333 | rv = E_NOTDIR;
334 | }
335 | }
336 |
337 | if (file_list != NULL) {
338 | file_list->size = rr_stat.st_size;
339 | file_list->st_mode = rr_stat.st_mode;
340 | file_list->st_uid = rr_stat.st_uid;
341 | file_list->st_gid = rr_stat.st_gid;
342 | file_list->st_nlink = rr_stat.st_nlink;
343 | file_list->st_ino = rr_stat.st_ino;
344 | file_list->mtime = rr_stat.st_mtime;
345 | file_list->atime = rr_stat.st_atime;
346 | file_list->ctime = rr_stat.st_ctime;
347 | }
348 |
349 |
350 | return rv;
351 | }
352 |
353 | static void help_msg(enum msg_l id) {
354 | if (id == MSG_USAGE) {
355 | printf("\
356 | Usage: \n\
357 | %s -e FILE -o FILE [-R] WORK_DIR\n\
358 | %s -h\n\
359 | %s -v\n\
360 | \n\
361 | Create UEFI bootable ISO image.\n\
362 | \n\
363 | Arguments:\n\
364 | -e, --efi-boot=FILE Bootable image location.\n\
365 | WARNING: Path must be relative to WORK_DIR!\n\
366 | -o, --output=FILE Output file location. File will be overwritten, if exists.\n\
367 | -R, --rock-ridge Use Rock Ridge Interchange Protocol (RRIP).\n\
368 | -h, --help This screen.\n\
369 | -v, --version Display version.\n", PROGNAME, PROGNAME, PROGNAME);
370 | }
371 | else if (id == MSG_VERSION)
372 | printf("%s\n", EBISO_VERSION);
373 | }
374 |
375 | static void err_msg(enum errors_l error) {
376 | if (error == E_BADSYNTAX) {
377 | printf("%s: Bad syntax\n", PROGNAME);
378 | printf("Try '%s --help' for more information.\n", PROGNAME);
379 | }
380 | }
381 |
382 | static uint32_t get_path_table_offset(struct file_list_t *file_list) {
383 | uint8_t pad_len = 0;
384 | uint32_t path_table_size = 0;
385 |
386 | while(file_list->next != NULL ) {
387 | if (S_ISDIR(file_list->st_mode)) {
388 | pad_len = do_pad(file_list->name_conv_len, PAD_ODD);
389 |
390 | path_table_size += PT_RECORD_LEN + pad_len;
391 | }
392 |
393 | file_list = file_list->next;
394 | }
395 |
396 | return path_table_size / (BLOCK_SIZE + 1);
397 |
398 | }
399 |
--------------------------------------------------------------------------------
/include/CE.h:
--------------------------------------------------------------------------------
1 | /*
2 | * CE.h
3 | *
4 | * Version: 0.2.0
5 | *
6 | * Release date: 20.10.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 | #include
30 | #include
31 |
32 | /* iso9660.c */
33 | int CE_assign_LBA(struct CE_list_t *CE_list, struct file_list_t *file_list, uint32_t *LBA);
34 | void CEarr_destroy_list(struct CE_list_t *CE_list);
35 | int CEarr_init_list(struct CE_list_t *CE_list, int arr_prealloc);
36 |
37 | static int realloc_CE_list(struct CE_list_t *CE_list);
38 | static int compar(const void *a, const void *b);
39 |
--------------------------------------------------------------------------------
/include/SL.h:
--------------------------------------------------------------------------------
1 | /*
2 | * SL.h
3 | *
4 | * Version: 0.2.1
5 | *
6 | * Release date: 13.12.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 |
30 | #include
31 | #include
32 | #include
33 |
34 | #define ROOT 1 << 3
35 | #define PARENT 1 << 2
36 | #define CURRENT 1 << 1
37 | #define SL_HEADER_SIZE 5
38 | #define SL_PREALLOC 128 // Size of memory chunk for unsplited SL record
39 |
40 | /*
41 | * At what length will SL record split.
42 | * Must be minimum SL_HEADER_SIZE + 5 (5 = 2*(flag + length) + (at least) one component character)
43 | */
44 | #define SL_MAX_LEN 250
45 |
46 | struct buffer_data_t {
47 | unsigned char *poutput_start;
48 | unsigned char *pbuff;
49 | unsigned char *pcomponent_len;
50 | unsigned char *pSL_len;
51 | unsigned char *pflags;
52 | int total_len;
53 | int blocks_allocated;
54 | uint16_t component_len;
55 | } buffer_data_t;
56 |
57 | struct save_data_t {
58 | unsigned char *start;
59 | unsigned char *SLlen_save;
60 | unsigned char *SLflag_save;
61 | unsigned char *component_flag_save;
62 | unsigned char *component_len_save;
63 | int mem_free;
64 | int blocks_allocated;
65 | size_t inital_alloc;
66 | } save_data_t;
67 |
68 | /* iso9660.c */
69 | int SL_create(char*, unsigned char**, int*);
70 |
71 | static int split_SL_record(unsigned char*, int, unsigned char**, int*);
72 | static unsigned char *write_data(char, unsigned char**, int*);
73 | static void write_SL_header(unsigned char**, struct save_data_t*);
74 | static int check_realloc_main(struct buffer_data_t*, int);
75 | static int check_realloc_part(struct save_data_t*, int, unsigned char**);
76 |
--------------------------------------------------------------------------------
/include/ebiso.h:
--------------------------------------------------------------------------------
1 | /*
2 | * ebiso.h
3 | *
4 | * Version: 0.2.3
5 | *
6 | * Release date: 2.4.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #define PROGNAME "ebiso"
36 | #define EBISO_VERSION "0.2.7"
37 |
38 | #if (DEBUG == 1)
39 | static void disp_level(struct file_list_t *list_to_display, int level);
40 | #endif
41 |
42 | enum check_type_l {
43 | TYPE_FILE,
44 | TYPE_DIR
45 | } check_type_l;
46 |
47 | enum check_mode_l {
48 | MODE_READ,
49 | MODE_WRITE
50 | } check_mode_l;
51 |
52 | enum msg_l {
53 | MSG_USAGE,
54 | MSG_VERSION,
55 | MSG_SYNTAX
56 | } msg_l;
57 |
58 | extern void filename_rename_duplicates(struct file_list_t *list);
59 |
60 | extern int list_create(const char *dirname, struct file_list_t **flist, struct ISO_data_t *ISO_data);
61 | extern void list_clean(struct file_list_t *list_to_clean);
62 |
63 | extern uint32_t iso9660_header(void **header, struct file_list_t file_list, struct ISO_data_t ISO_data);
64 | extern uint32_t iso9660_terminator(void **terminator);
65 | extern int iso9660_path_table(struct file_list_t *file_list, void **path_table, enum endianity_l endianity, struct ISO_data_t *ISO_data);
66 | extern int iso9660_assign_LBA(struct file_list_t *file_list, struct ISO_data_t *ISO_data);
67 | extern int iso9660_directory_record(struct file_list_t *file_list, FILE *dest, struct ISO_data_t *ISO_data);
68 | extern int do_pad(int len, enum pad_list_t type);
69 |
70 | extern void et_boot_record_descr(void **boot_record_descriptor, struct ISO_data_t ISO_data);
71 | extern int et_boot_catalog(struct ISO_data_t LBA_data);
72 |
73 | /* iso9660.c list.c */
74 | int option_on_off(uint32_t option2check, enum opt_l option);
75 |
76 | static int set_option(uint32_t *opt2set, enum opt_l option);
77 | static int check_availability(char *filename, enum check_type_l type, enum check_mode_l mode, struct file_list_t *file_list);
78 | static void help_msg(enum msg_l id);
79 | static void err_msg(enum errors_l error);
80 | static uint32_t get_path_table_offset(struct file_list_t *file_list);
81 |
--------------------------------------------------------------------------------
/include/el_torito.h:
--------------------------------------------------------------------------------
1 | /*
2 | * el_torito.h
3 | *
4 | * Version: 0.0.3-alfa
5 | *
6 | * Release date: 17.09.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 | #include
30 |
31 | extern void iso9660_cp2heap(void **dest, const void *source, long int size, uint32_t *dest_size);
32 |
33 | /* ebiso.c */
34 | void et_boot_record_descr(void **boot_record_descriptor, struct ISO_data_t ISO_data);
35 | int et_boot_catalog(struct ISO_data_t ISO_data);
36 |
37 | static uint16_t create_checksum(void *data, uint32_t data_size);
38 |
--------------------------------------------------------------------------------
/include/filename.h:
--------------------------------------------------------------------------------
1 | /*
2 | * filename.c
3 | *
4 | * Version: 0.1.1
5 | *
6 | * Release date: 20.09.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 | #include
30 |
31 | /* list.c */
32 | uint8_t filename_convert_name(char *input, char *output, enum conv_type_l type);
33 | /* ebiso.c */
34 | void filename_rename_duplicates(struct file_list_t *list);
35 |
36 | static void filename_explode(char *input, char **oname, char **oext, enum conv_type_l type);
37 | static size_t conv_rules(char *input, int max_len);
38 | static char *add_duplicate_couter(char *input, int counter, uint8_t *input_len);
39 |
--------------------------------------------------------------------------------
/include/globals.h:
--------------------------------------------------------------------------------
1 | /*
2 | * globals.h
3 | *
4 | * Version: 0.6.0
5 | *
6 | * Release date: 13.12.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #define DEBUG 0
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #if (DEBUG == 1)
38 | #include
39 | #endif
40 |
41 | #define ISO9660_ID "CD001"
42 | #define SYSTEM_ID "LINUX"
43 | #define VOLUME_ID "CDROM"
44 | #define VERSION 1
45 | #define MAX_DIR_STR_LEN 512
46 | #define BLOCK_SIZE 2048
47 | #define LBA_ROOT 0x18
48 | #define DIR_RECORD_LEN 0x21
49 | #define PT_RECORD_LEN 0x8
50 |
51 | /* Which fields should be used in RRIP */
52 | #define RRIP_INIT_FIELDS rrip_RR | rrip_PX | rrip_TF | rrip_NM
53 |
54 | /* Examples */
55 | //#define RRIP_INIT_FIELDS rrip_TF | rrip_PX
56 | //#define RRIP_INIT_FIELDS rrip_RR
57 | //#define RRIP_INIT_FIELDS rrip_NM
58 |
59 | #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
60 |
61 | static const uint8_t zero = 0;
62 | static const uint8_t one = 1;
63 |
64 | /* Global types */
65 | enum errors_l {
66 | E_OK,
67 | E_STATFAIL,
68 | E_READFAIL,
69 | E_WRFAIL,
70 | E_NOTREG,
71 | E_NOTDIR,
72 | E_BADSYNTAX,
73 | E_FILELIMIT,
74 | E_NOTFOUND,
75 | E_IO,
76 | E_CONV,
77 | E_MALLOC,
78 | E_NOTSET,
79 | E_LNKFAIL
80 | } errors_l;
81 |
82 | enum endianity_l {
83 | LSB,
84 | MSB
85 | } endianity_l;
86 |
87 | enum conv_type_l {
88 | CONV_ISO9660
89 | };
90 |
91 | enum pad_list_t {
92 | PAD_EVEN,
93 | PAD_ODD
94 | } pad_list_t;
95 |
96 | enum opt_l {
97 | OPT_e = 1,
98 | OPT_o,
99 | OPT_R
100 | };
101 |
102 | typedef enum bool_t {
103 | FALSE,
104 | TRUE
105 | } bool_t;
106 |
107 | struct CE_list_t {
108 | unsigned int *pid;
109 | unsigned int *lba;
110 | unsigned int *CE_used;
111 | size_t members;
112 | size_t arr_size;
113 | const int arr_prealloc;
114 | } CE_list_t;
115 |
116 | struct file_list_t {
117 | char name_path[MAX_DIR_STR_LEN];
118 | char name_short[MAX_DIR_STR_LEN];
119 | char name_conv[MAX_DIR_STR_LEN];
120 | struct file_list_t *next;
121 | time_t mtime;
122 | time_t atime;
123 | time_t ctime;
124 | mode_t st_mode;
125 | nlink_t st_nlink;
126 | uid_t st_uid;
127 | gid_t st_gid;
128 | ino_t st_ino;
129 | int size;
130 | int dir_id;
131 | int level;
132 | int blocks;
133 | int full_len; // ISO9660_len + sizeof(CE entry)
134 | int CE_offset;
135 | uint32_t LBA;
136 | uint32_t CE_LBA;
137 | uint16_t parent_id;
138 | uint8_t ISO9660_len;
139 | uint8_t name_conv_len;
140 | uint8_t name_short_len;
141 | } file_list_t;
142 |
143 | struct ISO_data_t {
144 | char efi_boot_file[MAX_DIR_STR_LEN];
145 | char efi_boot_file_full[MAX_DIR_STR_LEN];
146 | char boot_cat_file[MAX_DIR_STR_LEN];
147 | char work_dir[MAX_DIR_STR_LEN];
148 | char iso_file[MAX_DIR_STR_LEN];
149 | int dir_count;
150 | int LBA_last;
151 | int largest_cont_block;
152 | uint32_t boot_cat_LBA;
153 | uint32_t path_table_size;
154 | uint32_t path_table_offset;
155 | uint32_t options;
156 | } ISO_data_t;
157 |
158 | /* Global functions */
159 | enum errors_l Gdisplay_message(enum errors_l, const char *);
160 |
--------------------------------------------------------------------------------
/include/iso9660.h:
--------------------------------------------------------------------------------
1 | /*
2 | * iso9660.h
3 | *
4 | * Version: 0.4.0
5 | *
6 | * Release date: 13.12.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 | #include
30 |
31 | #define CE_LIST_PREALLOC 32
32 | #define NM_HEADER_SIZE 5
33 |
34 | enum segment_list_t {
35 | ISO9660_ROOT,
36 | ISO9660,
37 | ROOT_HEADER,
38 | RRIP_ABS_ROOT,
39 | RRIP_ABS_ROOT_CE,
40 | RRIP_ROOT,
41 | RRIP
42 | } segment_list_t;
43 |
44 | enum rrip_fields_t {
45 | rrip_RR = 1 << 1,
46 | rrip_TF = 1 << 2,
47 | rrip_PX = 1 << 3,
48 | rrip_NM = 1 << 4
49 | } rrip_fields_t;
50 |
51 | struct iso9660_data_t {
52 | char mdate_time[7];
53 | uint64_t LBA;
54 | uint64_t data_len;
55 | uint32_t volume_seq_number;
56 | uint8_t flags;
57 | uint8_t name_len;
58 | uint8_t ext_attr_record;
59 | } iso9660_data_t;
60 |
61 | extern int option_on_off(uint32_t option2check, enum opt_l option);
62 | extern int write_files(struct file_list_t *file_list, FILE *dest);
63 | extern struct file_list_t *list_search_name(struct file_list_t *file_list, char *needle);
64 | extern int CE_assign_LBA(struct CE_list_t *CE_list, struct file_list_t *file_list, uint32_t *LBA);
65 | extern int CEarr_init_list(struct CE_list_t *CE_list, int arr_prealloc);
66 | extern void CEarr_destroy_list(struct CE_list_t *CE_list);
67 | extern int SL_create(char *input, unsigned char **output, int *output_len);
68 |
69 | /* ebiso.c */
70 | uint32_t iso9660_terminator(void **terminator);
71 | uint32_t iso9660_header(void **header, struct file_list_t file_list, struct ISO_data_t ISO_data);
72 | int iso9660_path_table(struct file_list_t *file_list, void **path_table, enum endianity_l endianity, struct ISO_data_t *ISO_data);
73 | int iso9660_assign_LBA(struct file_list_t *file_list, struct ISO_data_t *ISO_data);
74 | int iso9660_directory_record(struct file_list_t *file_list, FILE *dest, struct ISO_data_t *ISO_data);
75 | int do_pad(int len, enum pad_list_t type);
76 |
77 | /* el_torito.c */
78 | void iso9660_cp2heap(void **dest, const void *source, long int size, uint32_t *dest_size);
79 |
80 | static uint32_t construct_dir_record(struct file_list_t *file_list, struct file_list_t **parent_index, void **directory_table_output, enum segment_list_t type);
81 | static int construct_iso9660_record(void **output, struct iso9660_data_t data, uint32_t *size);
82 | static uint64_t get_int32_LSB_MSB(uint64_t input);
83 | static uint32_t get_int16_LSB_MSB(uint32_t input);
84 | static int blocks_count(int size);
85 | static int int2str(uint16_t input, char **output);
86 | static int format_header_date(time_t time_now, char *output);
87 | static void str_var_prepare(char *input, char fill_char, size_t input_size);
88 | static int init_RRIP(void);
89 | static void shift_mem(void *var, int offset, int ammount);
90 | static uint8_t set_terminator_len(mode_t mode);
91 |
--------------------------------------------------------------------------------
/include/list.h:
--------------------------------------------------------------------------------
1 | /*
2 | * list.h
3 | *
4 | * Version: 0.2.0
5 | *
6 | * Release date: 15.11.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 | #include "unistd.h"
30 |
31 | extern uint8_t filename_convert_name(char *input, char *output, enum conv_type_l type);
32 | extern int option_on_off(uint32_t option2check, enum opt_l option);
33 |
34 | /* ebiso.c */
35 | int list_create(const char *dirname, struct file_list_t **flist, struct ISO_data_t *ISO_data);
36 | void list_clean(struct file_list_t *list_to_clean);
37 |
38 | /* iso9660.c */
39 | struct file_list_t *list_search_name(struct file_list_t *file_list, char *needle);
40 |
--------------------------------------------------------------------------------
/include/write_files.h:
--------------------------------------------------------------------------------
1 | /*
2 | * write_files.h
3 | *
4 | * Version: 0.0.3
5 | *
6 | * Release date: 10.10.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "globals.h"
29 |
30 | int write_files(struct file_list_t *file_list, FILE *dest);
31 |
--------------------------------------------------------------------------------
/lib/CE.c:
--------------------------------------------------------------------------------
1 | /*
2 | * CE.c
3 | *
4 | * Version: 0.2.1
5 | *
6 | * Release date: 13.12.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "CE.h"
29 |
30 | int CE_assign_LBA(struct CE_list_t *CE_list, struct file_list_t *file_list, uint32_t *LBA) {
31 | void *found = NULL;
32 | int parent_id = file_list->parent_id;
33 | int element = -1;
34 | int CE_len = file_list->full_len - file_list->ISO9660_len;
35 |
36 | if (realloc_CE_list(CE_list) == E_MALLOC)
37 | return E_MALLOC;
38 |
39 | if ((found = lfind(&parent_id, CE_list->pid, &(CE_list)->members, sizeof(int), compar)) == NULL) {
40 | #if (DEBUG == 1)
41 | printf("DEBUG: %s(): PID: [%d] not found, inserting LBA: 0x%x\n", __func__, parent_id, *LBA);
42 | #endif
43 |
44 | /*
45 | * ABS root will always have separate CE record and
46 | * will not be recorded in CE_data structure
47 | */
48 | if (strncmp(file_list->name_path, ".", 2) != 0) {
49 | CE_list->pid[CE_list->members] = parent_id;
50 | CE_list->lba[CE_list->members] = *LBA;
51 | CE_list->CE_used[CE_list->members] += CE_len;
52 | CE_list->members++;
53 | }
54 |
55 | file_list->CE_LBA = *LBA;
56 | (*LBA)++;
57 |
58 | }
59 | else {
60 | #if (DEBUG == 1)
61 | printf("DEBUG: %s(): PID: [%d] found.\n", __func__, parent_id);
62 | #endif
63 | element = (int*) found - (int*) CE_list->pid;
64 | file_list->CE_LBA = CE_list->lba[element];
65 | /* Test */
66 | file_list->CE_offset = CE_list->CE_used[element];
67 | /* Test END*/
68 |
69 | CE_list->CE_used[element] += CE_len;
70 |
71 |
72 | /* CE have reached BLOCK_SIZE, allocate new LBA */
73 | if (CE_list->CE_used[element] > BLOCK_SIZE) {
74 | #if (DEBUG == 1)
75 | printf("DEBUG: %s(): CE record for pid [%d] is longer than BLOCK_SIZE, assigning new LBA [0x%x]\n", __func__, CE_list->pid[element], *LBA);
76 | #endif
77 | CE_list->CE_used[element] = CE_len;
78 | CE_list->lba[element] = *LBA;
79 | file_list->CE_LBA = *LBA;
80 | file_list->CE_offset = 0;
81 | (*LBA)++;
82 | }
83 | }
84 |
85 | return E_OK;
86 | }
87 |
88 | void CEarr_destroy_list(struct CE_list_t *CE_list) {
89 | if (CE_list->pid != NULL)
90 | free(CE_list->pid);
91 |
92 | if (CE_list->lba != NULL)
93 | free(CE_list->lba);
94 |
95 | if (CE_list->CE_used != NULL)
96 | free(CE_list->CE_used);
97 | }
98 |
99 | static int realloc_CE_list(struct CE_list_t *CE_list) {
100 | unsigned int *rr = NULL;
101 | unsigned int new_size = 0;
102 | unsigned int curr_size = CE_list->arr_size;
103 | unsigned int resize_by = CE_list->arr_prealloc * sizeof(int);
104 | int rv = E_OK;
105 |
106 | if (CE_list->members * sizeof(int) >= CE_list->arr_size) {
107 | new_size = curr_size + resize_by;
108 |
109 | if ((rr = realloc(CE_list->pid, new_size)) == NULL) {
110 | rv = E_MALLOC;
111 | }
112 | else {
113 | CE_list->pid = rr;
114 | memset((CE_list)->pid + CE_list->members, 0, resize_by);
115 |
116 | if ((rr = realloc(CE_list->lba, new_size)) == NULL) {
117 | rv = E_MALLOC;
118 | }
119 | else {
120 | CE_list->lba = rr;
121 | memset((CE_list)->lba + CE_list->members, 0, resize_by);
122 |
123 | if ((rr = realloc(CE_list->CE_used, new_size)) == NULL) {
124 | rv = E_MALLOC;
125 | }
126 | else {
127 | #if (DEBUG == 1)
128 | printf("DEBUG: %s(): New space allocation success.\n", __func__);
129 | #endif
130 | CE_list->CE_used = rr;
131 | memset((CE_list)->CE_used + CE_list->members, 0, resize_by);
132 | CE_list->arr_size += CE_list->arr_prealloc * sizeof(int);
133 | }
134 | }
135 | }
136 | }
137 |
138 | if (rv == E_MALLOC)
139 | Gdisplay_message(E_MALLOC, __func__);
140 |
141 | return rv;
142 | }
143 |
144 | static int compar(const void *a, const void *b) {
145 | return (*(const int *)a == *(const int *)b) ? 0 : 1;
146 | }
147 |
148 | #if GCC_VERSION >= 40600
149 | #pragma GCC diagnostic push // Available only sice gcc 4.6
150 | #endif
151 |
152 | #pragma GCC diagnostic ignored "-Wcast-qual"
153 | int CEarr_init_list(struct CE_list_t *CE_list, int arr_prealloc) {
154 | int rv = E_OK;
155 |
156 | *(int*) &CE_list->arr_prealloc = arr_prealloc; // Intentional const discard
157 | CE_list->pid = NULL;
158 | CE_list->lba = NULL;
159 | CE_list->CE_used = NULL;
160 | CE_list->members = 0;
161 | CE_list->arr_size = arr_prealloc * sizeof(int);
162 |
163 | #if (DEBUG == 1)
164 | printf("DEBUG: %s(): Allocating new space: %zu bytes.\n", __func__, CE_list->arr_size);
165 | #endif
166 |
167 | if ((CE_list->pid = (unsigned int *) malloc(CE_list->arr_size)) == NULL) {
168 | rv = E_MALLOC;
169 | }
170 | else {
171 | if ((CE_list->lba = (unsigned int *) malloc(CE_list->arr_size)) == NULL) {
172 | rv = E_MALLOC;
173 | }
174 | else {
175 | if ((CE_list->CE_used = (unsigned int *) malloc(CE_list->arr_size)) == NULL) {
176 | rv = E_MALLOC;
177 | }
178 | else {
179 | memset(CE_list->pid, 0, CE_list->arr_size);
180 | memset(CE_list->lba, 0, CE_list->arr_size);
181 | memset(CE_list->CE_used, 0, CE_list->arr_size);
182 | }
183 | }
184 | }
185 |
186 | if (rv == E_MALLOC)
187 | Gdisplay_message(E_MALLOC, __func__);
188 |
189 | return rv;
190 | }
191 |
192 | #if GCC_VERSION >= 40600
193 | #pragma GCC diagnostic pop // Available only sice gcc 4.6
194 | #endif
195 |
--------------------------------------------------------------------------------
/lib/SL.c:
--------------------------------------------------------------------------------
1 | /*
2 | * SL.c
3 | *
4 | * Version: 0.2.0
5 | *
6 | * Release date: 13.12.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "SL.h"
29 |
30 | int SL_create(char *input, unsigned char **output, int *output_len) {
31 | struct buffer_data_t buff;
32 | unsigned char *split_record = NULL; // Used only during split record
33 | int split_record_len = 0; // Used only during split record
34 | int rv = E_OK;
35 |
36 | memset(&buff, 0, sizeof(struct buffer_data_t));
37 |
38 | #if (DEBUG == 1)
39 | printf("DEBUG: %s(): Allocating new space: %d bytes.\n", __func__, SL_PREALLOC);
40 | #endif
41 |
42 | if ((buff.poutput_start = (unsigned char *) malloc(SL_PREALLOC)) == NULL) {
43 | return Gdisplay_message(E_MALLOC, __func__);
44 | }
45 | else
46 | memset(buff.poutput_start, 0, SL_PREALLOC);
47 |
48 | /* Insert known data to entry header */
49 | buff.poutput_start[0] = 'S';
50 | buff.poutput_start[1] = 'L';
51 | buff.poutput_start[3] = 0x01;
52 |
53 | buff.total_len = SL_HEADER_SIZE;
54 | buff.pbuff = buff.poutput_start + buff.total_len; // Move pointer behind system use entry header
55 | buff.pSL_len = buff.poutput_start + 2; // Position of SL record length
56 | buff.pflags = buff.poutput_start + 4; // Position of SL record flag
57 | buff.pcomponent_len = buff.poutput_start + 6; // Position of component record len
58 | buff.blocks_allocated = 1;
59 |
60 | /* Check for type of first component record */
61 | if (*input == '/') {
62 | *(buff).pbuff++ = ROOT; // Flag
63 | buff.pbuff++; // Length
64 | }
65 | else if (*input == '.' && *(input + 1) == '.' && *(input + 2) == '/') {
66 | *(buff).pbuff++ = PARENT; // Flag
67 | buff.pbuff++; // Length
68 | input += 2; // move pointer to first '/' in the stream
69 | }
70 | else if (*input == '.' && *(input + 1) == '/') {
71 | *(buff).pbuff++ = CURRENT; // Flag
72 | buff.pbuff++; // Length
73 | input += 1; // move pointer to first '/' in the stream
74 | }
75 | else {
76 | buff.pbuff++; // Flag
77 | buff.pbuff++; // Length
78 | }
79 |
80 | buff.total_len += 2; // Allign total length
81 |
82 | /* Process input string until 0 is found */
83 | while(*input) {
84 | if (*input == '/') {
85 |
86 | /* Dont add any more bytes when end is near */
87 | if (*(input + 1) == 0)
88 | break;
89 |
90 | input++;
91 |
92 | /* There are multiple '/' in a row, create entry for them */
93 | if (*input == '/') {
94 |
95 | if ((rv = check_realloc_main(&buff, 2)) != E_OK)
96 | goto cleanup;
97 |
98 | *(buff).pbuff++ = ROOT; // Flag
99 | *(buff).pbuff++ = 0x00; // Lenth, have hardcoded zero
100 |
101 | continue;
102 | }
103 |
104 | /* Link to parent directory */
105 | if (*input == '.' && *(input + 1) == '.' && (*(input + 2) == '/' || *(input + 2) == 0)) {
106 | input += 2;
107 |
108 | if ((rv = check_realloc_main(&buff, 2)) != E_OK)
109 | goto cleanup;
110 |
111 | *(buff).pbuff++ = PARENT;
112 | *(buff).pbuff++ = 0x00;
113 |
114 | continue;
115 | }
116 |
117 | /* Link to current directory */
118 | if (*input == '.' && (*(input + 1) == '/' || *(input + 1) == 0)) {
119 | input += 1;
120 |
121 | if ((rv = check_realloc_main(&buff, 2)) != E_OK)
122 | goto cleanup;
123 |
124 | *(buff).pbuff++ = CURRENT;
125 | *(buff).pbuff++ = 0x00;
126 |
127 | continue;
128 | }
129 |
130 | if ((rv = check_realloc_main(&buff, 2)) != E_OK)
131 | goto cleanup;
132 |
133 | *(buff).pbuff++ = 0x00; // Flag, can be updated with split_SL_record() if needed
134 |
135 | *(buff).pcomponent_len = buff.component_len; // Write length of previous component
136 |
137 | buff.pcomponent_len = buff.pbuff; // Save position of component length
138 |
139 | *(buff).pbuff++ = 0x00; // Length placeholder
140 |
141 | buff.component_len = 0;
142 | }
143 |
144 | if ((rv = check_realloc_main(&buff, 1)) != E_OK)
145 | goto cleanup;
146 |
147 | buff.component_len++;
148 |
149 | /* Single contious compont can't be longer than 256 bytes */
150 | if (buff.component_len > 255) {
151 | printf("Error: %s(): Invalid symlink\n", __func__);
152 | rv = E_LNKFAIL;
153 | goto cleanup;
154 | }
155 |
156 | *(buff).pbuff++ = *input++; // Assign char to output buffer
157 | }
158 |
159 | /* Write length of last valid link component */
160 | *(buff).pcomponent_len = buff.component_len;
161 | *(buff).pSL_len = buff.total_len;
162 |
163 | /* Split SL record to smaller chunks if necessary */
164 | if (buff.total_len > SL_MAX_LEN) {
165 |
166 | if ((rv = split_SL_record(buff.poutput_start, buff.total_len, &split_record, &split_record_len)) != E_OK) {
167 | goto cleanup;
168 | }
169 | else {
170 | *output = split_record;
171 | *output_len = split_record_len;
172 | free(buff.poutput_start);
173 | }
174 | }
175 | else {
176 | /* Set output pointer to correct value if needed */
177 | *output = buff.poutput_start;
178 | *output_len = buff.total_len;
179 | }
180 |
181 | #if (DEBUG == 1)
182 | printf("DEBUG: %s(): Original len: %d bytes\n", __func__, buff.total_len);
183 | printf("DEBUG: %s(): Split len: %d bytes\n", __func__, split_record_len);
184 | #endif
185 |
186 | cleanup:
187 | if (rv != E_OK) {
188 | if (buff.poutput_start != NULL)
189 | free(buff.poutput_start);
190 | }
191 |
192 | return rv;
193 | }
194 |
195 | static int split_SL_record(unsigned char *input, int input_len, unsigned char **output, int *output_len) {
196 | struct save_data_t save_data; // Structure to save pointers
197 | unsigned char *rr_output = NULL;
198 | int rv = E_OK;
199 | int SL_len = 0;
200 | int part_component_len = 0; // Follows component length in case of split
201 | int len2split_remain = SL_MAX_LEN; // Controls if and when should be component split
202 | int total_len = 0; // Total lenght of splited SL record
203 | int rr = 0;
204 | uint8_t component_len = 0; // Original component length
205 | uint8_t component_flag = 0;
206 | uint8_t add = 0;
207 |
208 | memset(&save_data, 0, sizeof(save_data));
209 | save_data.inital_alloc = (input_len * 2); // Just a rough guess
210 | save_data.mem_free = save_data.inital_alloc - SL_HEADER_SIZE; // At least SL_HEADER_SIZE will be used
211 | save_data.blocks_allocated = 1;
212 |
213 | #if (DEBUG == 1)
214 | printf("DEBUG: %s(): Allocating new space: %zu bytes.\n", __func__, save_data.inital_alloc);
215 | #endif
216 |
217 | if ((save_data.start = (unsigned char *) malloc(save_data.inital_alloc)) == NULL) {
218 | return Gdisplay_message(E_MALLOC, __func__);
219 | }
220 | else {
221 | rr_output = save_data.start;
222 | memset(rr_output, 0, save_data.inital_alloc);
223 | memcpy((void *) rr_output, (void *) input, SL_HEADER_SIZE); // Copy SL header
224 |
225 | save_data.SLlen_save = rr_output + 2; // Save position of SL record lenght
226 | save_data.SLflag_save = rr_output + 4; // Save position of SL record flags
227 |
228 | /* Update pointer and sizes due previous memcpy() */
229 | input += SL_HEADER_SIZE;
230 | rr_output += SL_HEADER_SIZE;
231 | input_len -= SL_HEADER_SIZE;
232 | len2split_remain -= SL_HEADER_SIZE;
233 | SL_len += SL_HEADER_SIZE;
234 | total_len += SL_HEADER_SIZE;
235 |
236 | while(input_len > 0) {
237 | component_flag = *(input++); // Store flag value
238 | component_len = *(input++); // Store length value
239 | input_len -= 2;
240 |
241 | /* Component name can't be separated from its flags and length */
242 | add = (component_len > 0) ? 1 : 0;
243 |
244 | /* Split record */
245 | if (len2split_remain - (2 + add) < 0) {
246 | *save_data.SLflag_save = 1;
247 | *save_data.SLlen_save = SL_len;
248 | *save_data.component_len_save = part_component_len;
249 |
250 | if ((rv = check_realloc_part(&save_data, 5, &rr_output)) != E_OK)
251 | goto cleanup;
252 |
253 | write_SL_header(&rr_output, &save_data);
254 |
255 | /*
256 | * Following section insures that '/' (0x08 0x00) is inserted in front
257 | * of start of every component record name,
258 | * but only if new SL record is created.
259 | * it is not very clear what RRIP standard says about this, but some clients had
260 | * problem to correctly interpret symlink without it.
261 | */
262 | if (component_len > 0) {
263 | if ((rv = check_realloc_part(&save_data, 2, &rr_output)) != E_OK)
264 | goto cleanup;
265 |
266 | write_data(ROOT, &rr_output, &len2split_remain); // Write root record
267 | rr_output++; // Insert length
268 |
269 | rr = 2;
270 | }
271 |
272 | len2split_remain = SL_MAX_LEN - SL_HEADER_SIZE - rr;
273 | SL_len = SL_HEADER_SIZE + rr;
274 | total_len += (SL_HEADER_SIZE + rr);
275 |
276 | rr = 0;
277 | }
278 |
279 | if ((rv = check_realloc_part(&save_data, 2, &rr_output)) != E_OK)
280 | goto cleanup;
281 |
282 | /* Record component flags and lenght */
283 | save_data.component_flag_save = write_data(component_flag, &rr_output, &len2split_remain);
284 | save_data.component_len_save = write_data(component_len, &rr_output, &len2split_remain);
285 |
286 | SL_len += 2;
287 | total_len += 2;
288 |
289 | part_component_len = 0;
290 |
291 | /* Record component data (name) */
292 | while(component_len--) {
293 |
294 | if (len2split_remain == 0) {
295 | *save_data.SLflag_save = 1;
296 | *save_data.SLlen_save = SL_len;
297 | *save_data.component_len_save = part_component_len;
298 | *save_data.component_flag_save = 1;
299 |
300 | if ((rv = check_realloc_part(&save_data, 7, &rr_output)) != E_OK)
301 | goto cleanup;
302 |
303 | write_SL_header(&rr_output, &save_data);
304 |
305 | save_data.component_flag_save = rr_output++;
306 | save_data.component_len_save = rr_output++;
307 |
308 | /* +/- 2 to allign with component_flag_save & component_len_save */
309 | SL_len = (SL_HEADER_SIZE + 2);
310 | len2split_remain = (SL_MAX_LEN - SL_HEADER_SIZE - 2);
311 | total_len += (SL_HEADER_SIZE + 2);
312 |
313 | part_component_len = 0;
314 | }
315 |
316 | if ((rv = check_realloc_part(&save_data, 1, &rr_output)) != E_OK)
317 | goto cleanup;
318 |
319 | write_data(*(input++), &rr_output, &len2split_remain);
320 |
321 | input_len--;
322 | SL_len++;
323 | part_component_len++;
324 | total_len++;
325 | }
326 |
327 | *save_data.component_len_save = part_component_len;
328 | *save_data.SLlen_save = SL_len;
329 | }
330 |
331 | *output = save_data.start;
332 | *output_len = total_len;
333 | }
334 |
335 | cleanup:
336 | if (rv != E_OK) {
337 | if (save_data.start != NULL)
338 | free(save_data.start);
339 | }
340 |
341 | return rv;
342 | }
343 |
344 | static unsigned char *write_data(char source, unsigned char **dest, int *remain) {
345 | **dest = source;
346 |
347 | (*remain)--;
348 | (*dest)++;
349 | return (*dest) - 1;
350 | }
351 |
352 | static void write_SL_header(unsigned char **head, struct save_data_t *mem_save_data) {
353 | unsigned char *rr_head = *head;
354 |
355 | *rr_head++ = 'S';
356 | *rr_head++ = 'L';
357 | mem_save_data->SLlen_save = rr_head;
358 | *rr_head++ = 0; // Length
359 | *rr_head++ = VERSION;
360 | mem_save_data->SLflag_save = rr_head;
361 | *rr_head++ = 0; // Flag
362 |
363 | *head = rr_head;
364 | }
365 |
366 | static int check_realloc_main(struct buffer_data_t *buff, int increment_by) {
367 | int rr_total_len = buff->total_len; // Make things a bit obscure ...
368 | int rv = E_OK;
369 | unsigned long int pcomponent_len_off = 0;
370 | unsigned long int pSL_len_off = 0;
371 |
372 | rr_total_len += increment_by;
373 |
374 | /* Check if we need to allocate additional memory chunk */
375 | if (rr_total_len > buff->blocks_allocated * SL_PREALLOC) {
376 | unsigned char *rr = NULL;
377 |
378 | pcomponent_len_off = buff->pcomponent_len - buff->poutput_start;
379 | pSL_len_off = buff->pSL_len - buff->poutput_start;
380 |
381 | #if (DEBUG == 1)
382 | printf("DEBUG: %s(): Allocating additional space: %d bytes\n", __func__, (buff->blocks_allocated + 1) * SL_PREALLOC);
383 | #endif
384 |
385 | if ((rr = realloc(buff->poutput_start, ++buff->blocks_allocated * SL_PREALLOC)) == NULL) {
386 | return Gdisplay_message(E_MALLOC, "check_realloc");
387 | }
388 | else {
389 | memset(rr + buff->total_len, 0, (buff->blocks_allocated * SL_PREALLOC) - buff->total_len);
390 |
391 | /* Update pointers with new memory address */
392 | buff->poutput_start = rr;
393 | buff->pSL_len = rr + pSL_len_off;
394 | buff->pbuff = rr + buff->total_len;
395 | buff->pcomponent_len = rr + pcomponent_len_off;
396 | buff->pflags = buff->pSL_len + 2;
397 | }
398 | }
399 |
400 | buff->total_len = rr_total_len;
401 |
402 | return rv;
403 | }
404 |
405 | static int check_realloc_part(struct save_data_t *save_data, int ammount, unsigned char **head) {
406 | unsigned char *rr = NULL;
407 | int rv = E_OK;
408 | unsigned long int SLflag_off = 0;
409 | unsigned long int SLlen_off = 0;
410 | unsigned long int component_flag_off = 0;
411 | unsigned long int component_len_off = 0;
412 | unsigned long int head_off = 0;
413 |
414 | save_data->mem_free -= ammount;
415 |
416 | if (save_data->mem_free < 0) {
417 |
418 | /*
419 | * Save absolute memory position of save_data members
420 | * for later pointer restore after realloc()
421 | */
422 | head_off = *head - save_data->start;
423 | SLflag_off = save_data->SLflag_save - save_data->start;
424 | SLlen_off = save_data->SLlen_save - save_data->start;
425 |
426 | if (save_data->component_flag_save != NULL)
427 | component_flag_off = save_data->component_flag_save - save_data->start;
428 |
429 | if (save_data->component_len_save != NULL)
430 | component_len_off = save_data->component_len_save - save_data->start;
431 |
432 | #if (DEBUG == 1)
433 | printf("DEBUG: %s(): Allocating additional space %zu bytes\n", __func__, (save_data->blocks_allocated + 1) * save_data->inital_alloc);
434 | #endif
435 |
436 | /* Try to reallocate memory */
437 | if ((rr = realloc(save_data->start, ++save_data->blocks_allocated * save_data->inital_alloc)) == NULL) {
438 | return Gdisplay_message(E_MALLOC, __func__);
439 | }
440 | else {
441 | memset(rr + ((save_data->blocks_allocated - 1) * save_data->inital_alloc), 0, save_data->inital_alloc);
442 | save_data->start = rr;
443 |
444 | /* Restore previous location of pointers */
445 | *head = save_data->start + head_off;
446 | save_data->SLflag_save = save_data->start + SLflag_off;
447 | save_data->SLlen_save = save_data->start + SLlen_off;
448 |
449 | /* Component flag and length were not set */
450 | if (component_flag_off == 0)
451 | save_data->component_flag_save = NULL;
452 | else
453 | save_data->component_flag_save = save_data->start + component_flag_off;
454 |
455 | if (component_len_off == 0)
456 | save_data->component_len_save = NULL;
457 | else
458 | save_data->component_len_save = save_data->start + component_len_off;
459 |
460 | save_data->mem_free += save_data->inital_alloc;
461 | }
462 | }
463 |
464 | return rv;
465 | }
466 |
--------------------------------------------------------------------------------
/lib/el_torito.c:
--------------------------------------------------------------------------------
1 | /*
2 | * el_torito.c
3 | *
4 | * Version: 0.0.2-alfa
5 | *
6 | * Release date: 11.09.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "el_torito.h"
29 |
30 | void et_boot_record_descr(void **boot_record_descriptor, struct ISO_data_t ISO_data) {
31 | void *rr_boot_descriptor = *boot_record_descriptor;
32 | void *rr_boot_descriptor_start = rr_boot_descriptor;
33 | uint32_t desc_size = 0;
34 | char et_id[32];
35 | char unused[32];
36 |
37 | memset(et_id, 0, sizeof(et_id));
38 | memset(unused, 0, sizeof(unused));
39 | strcpy(et_id, "EL TORITO SPECIFICATION");
40 |
41 | iso9660_cp2heap(&rr_boot_descriptor, &zero, sizeof(uint8_t), &desc_size); // Boot Record Indicator, always 0x00
42 | iso9660_cp2heap(&rr_boot_descriptor, ISO9660_ID, strlen(ISO9660_ID), &desc_size); // ISO9660 identifier, always "CD001"
43 | iso9660_cp2heap(&rr_boot_descriptor, &one, sizeof(uint8_t), &desc_size); // Version of this descriptor, always 0x01
44 | iso9660_cp2heap(&rr_boot_descriptor, et_id, sizeof(et_id), &desc_size); // El-torito boot system ID
45 | iso9660_cp2heap(&rr_boot_descriptor, unused, sizeof(unused), &desc_size); // Unused
46 | iso9660_cp2heap(&rr_boot_descriptor, &ISO_data.boot_cat_LBA, sizeof(uint32_t), &desc_size); // Boot catalog LBA
47 |
48 | *boot_record_descriptor = rr_boot_descriptor_start;
49 | }
50 |
51 | int et_boot_catalog(struct ISO_data_t ISO_data) {
52 | struct stat EFI_boot_file_stat;
53 | void *boot_cat_data = (void *) malloc(BLOCK_SIZE);
54 | void *boot_cat_start = boot_cat_data;
55 | void *rr = NULL;
56 | int rv = 0;
57 |
58 | char id_string[24];
59 | FILE *boot_catalog = NULL;
60 | uint32_t boot_cat_size = 0;
61 | uint16_t unused = 0;
62 | uint16_t checksum = 0x0000;
63 | uint16_t signature = 0xAA55;
64 | uint8_t header_id = 0x01; // Always 0x01
65 | uint8_t platform_id = 0x00; // x86
66 |
67 | uint16_t load_segment = 0x00;
68 | uint16_t sector_count = 0x00;
69 | uint8_t boot_indicator = 0x88; // Bootable
70 | uint8_t media_type = 0x00; // No emulation
71 | uint8_t system_type = 0x00;
72 |
73 | memset(&EFI_boot_file_stat, 0, sizeof(struct stat));
74 | memset(id_string, 0, sizeof(id_string));
75 | memset(boot_cat_start, 0, BLOCK_SIZE);
76 |
77 | /* Move to LBA of UEFI boot image */
78 | (ISO_data.boot_cat_LBA)++;
79 |
80 | stat(ISO_data.efi_boot_file_full, &EFI_boot_file_stat);
81 | sector_count = EFI_boot_file_stat.st_size / 512;
82 |
83 | iso9660_cp2heap(&boot_cat_data, &header_id, sizeof(uint8_t), &boot_cat_size);
84 | iso9660_cp2heap(&boot_cat_data, &platform_id, sizeof(uint8_t), &boot_cat_size);
85 | iso9660_cp2heap(&boot_cat_data, &unused, sizeof(uint16_t), &boot_cat_size);
86 | iso9660_cp2heap(&boot_cat_data, &id_string, sizeof(id_string), &boot_cat_size);
87 | iso9660_cp2heap(&boot_cat_data, &checksum, sizeof(uint16_t), &boot_cat_size);
88 | iso9660_cp2heap(&boot_cat_data, &signature, sizeof(uint16_t), &boot_cat_size);
89 |
90 | /* Calculate checksum of words so far written */
91 | checksum = create_checksum(boot_cat_start, boot_cat_size);
92 | rr = boot_cat_data - 4; // Return back 4 bytes and write checksum
93 | boot_cat_size -= sizeof(uint16_t); // This will be counted back in next step
94 | iso9660_cp2heap(&rr, &checksum, sizeof(uint16_t), &boot_cat_size);
95 |
96 | iso9660_cp2heap(&boot_cat_data, &boot_indicator, sizeof(uint8_t), &boot_cat_size);
97 | iso9660_cp2heap(&boot_cat_data, &media_type, sizeof(uint8_t), &boot_cat_size);
98 | iso9660_cp2heap(&boot_cat_data, &load_segment, sizeof(uint16_t), &boot_cat_size);
99 | iso9660_cp2heap(&boot_cat_data, &system_type, sizeof(uint8_t), &boot_cat_size);
100 | iso9660_cp2heap(&boot_cat_data, &unused, sizeof(uint8_t), &boot_cat_size);
101 | iso9660_cp2heap(&boot_cat_data, §or_count, sizeof(uint16_t), &boot_cat_size); // Size of UEFI boot image (this will overflow because of size)
102 | iso9660_cp2heap(&boot_cat_data, &ISO_data.boot_cat_LBA, sizeof(uint32_t), &boot_cat_size); // LBA of UEFI boot image (virtual disk)
103 |
104 | boot_catalog = fopen(ISO_data.boot_cat_file, "w");
105 | if (fwrite(boot_cat_start, 1, BLOCK_SIZE, boot_catalog) != BLOCK_SIZE) {
106 | perror("Error: et_boot_catalog()");
107 | rv = E_IO;
108 | }
109 |
110 | fclose(boot_catalog);
111 | free(boot_cat_start);
112 |
113 | return rv;
114 | }
115 |
116 | static uint16_t create_checksum(void *data, uint32_t data_size) {
117 | uint16_t *rr_val = data;
118 | uint16_t sum = 0;
119 | int size = data_size / sizeof(uint16_t);
120 |
121 | while(size--)
122 | sum += *(rr_val++);
123 |
124 | return 0xFFFF - sum + 1;
125 | }
126 |
--------------------------------------------------------------------------------
/lib/filename.c:
--------------------------------------------------------------------------------
1 | /*
2 | * filename.c
3 | *
4 | * Version: 0.1.2
5 | *
6 | * Release date: 07.04.2016
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "filename.h"
29 |
30 | void filename_rename_duplicates(struct file_list_t *list) {
31 | struct file_list_t *rr_list = list;
32 | struct file_list_t *rr2_list = list;
33 | int dup_counter = 0;
34 |
35 | while(rr_list->next != NULL) {
36 | dup_counter = 0;
37 |
38 | while(rr2_list->next != NULL) {
39 | if (strncmp(rr_list->name_conv, rr2_list->name_conv, rr_list->name_conv_len + 1) == 0 && \
40 | /* Avoid comapration with file it self */
41 | strncmp(rr_list->name_short, rr2_list->name_short, rr_list->name_short_len) != 0 && \
42 | rr_list->parent_id == rr2_list->parent_id) {
43 |
44 | printf("Info: Duplicate: %s and %s -> %s\n", rr_list->name_path, rr2_list->name_path, \
45 | add_duplicate_couter(rr2_list->name_conv, dup_counter, &rr2_list->name_conv_len));
46 |
47 | dup_counter++;
48 | }
49 |
50 | rr2_list = rr2_list->next;
51 | }
52 | rr2_list = list;
53 |
54 | rr_list = rr_list->next;
55 | }
56 | }
57 |
58 | static char *add_duplicate_couter(char *input, int counter, uint8_t *input_len) {
59 | char *name = NULL;
60 | char *ext = NULL;
61 | char *offset = NULL;
62 | char prepad_nulls[3];
63 | char str_counter[4];
64 | char save_ext[4];
65 | size_t name_len = 0;
66 | int counter_digits = 0;
67 |
68 | memset(prepad_nulls, 0, sizeof(prepad_nulls));
69 | memset(str_counter, 0, sizeof(str_counter));
70 | memset(save_ext, 0, sizeof(save_ext));
71 |
72 | /* Can't be done with memset. Valgrind doesn't like it */
73 | strncpy(prepad_nulls, "000", 3);
74 |
75 | /* Get pointers to name and extension */
76 | filename_explode(input, &name, &ext, CONV_ISO9660);
77 | name_len = strlen(name);
78 |
79 | /*
80 | * Save extension to stack.
81 | * Otherwise it would be overwritten if filename is shorter than
82 | * 4 bytes (this number is just a guess ;-) ), by:
83 | * snprintf(offset, 5, "_%s", str_counter);
84 | */
85 | if (ext != NULL)
86 | strncpy(save_ext, ext, sizeof(save_ext)-1);
87 |
88 | if (counter > 999)
89 | printf("Warning: Duplicity counter too large, file might be unreadable on target ISO\n");
90 |
91 | /* log(0) is undefined */
92 | if (counter == 0)
93 | counter_digits = 1;
94 | else {
95 | /* For padding purposes, how many '0' chars should be prepadded */
96 | counter_digits = log10(counter) + 1;
97 | }
98 |
99 | /* Create counter string (e.g. 001, 066, 123 ...)*/
100 | snprintf(str_counter, sizeof(str_counter), "%.*s%d", (int) (sizeof(prepad_nulls) - counter_digits), prepad_nulls, counter);
101 |
102 | /*
103 | * Everything after 4th (including) will be replaced by couter string.
104 | * This space is needed to accomodate counter string.
105 | */
106 | if (name_len >= 4)
107 | offset = name + 4;
108 | else
109 | offset = name + name_len;
110 |
111 | /*
112 | * Put couter string directly into file_list structure
113 | * snprintf() outputs '\0' as last character
114 | */
115 | snprintf(offset, 5, "_%s", str_counter);
116 |
117 | /* If there was a filename extension, add it back to filename */
118 | if (ext != NULL)
119 | snprintf(offset + sizeof(str_counter), 1 + strlen(save_ext) + 1, ".%s", save_ext);
120 |
121 | *input_len = strlen(name);
122 |
123 | return name;
124 | }
125 |
126 | uint8_t filename_convert_name(char *input, char *output, enum conv_type_l type) {
127 | char *name = NULL;
128 | char *ext = NULL;
129 | char rr_input[MAX_DIR_STR_LEN];
130 | int name_len = 0;
131 | int ext_len = 0;
132 |
133 | memset(rr_input, 0, sizeof(rr_input));
134 | strncpy(rr_input, input, sizeof(rr_input));
135 |
136 | filename_explode(rr_input, &name, &ext, type);
137 |
138 | name_len = conv_rules(name, 8);
139 | ext_len = conv_rules(ext, 3);
140 |
141 | /*
142 | * WARNING:
143 | * *output must be large enough
144 | * otherwise SEGFAULT is inevitable
145 | */
146 | strncat(output, name, name_len);
147 |
148 | if (ext != NULL)
149 | snprintf(output + name_len, ext_len + 2, ".%s", ext);
150 |
151 | return strlen(output);
152 | }
153 |
154 | static void filename_explode(char *input, char **oname, char **oext, enum conv_type_l type) {
155 | int input_len = strlen(input);
156 | int i = 0;
157 |
158 | /* When 8.3 filenames are in use, filename can't start with '.' */
159 | if (*input == '.' && type == CONV_ISO9660)
160 | *input = '_';
161 |
162 | /* Set pointer to last character in the string */
163 | input += input_len - 1;
164 |
165 | /* Check if we have dot (.) separataor present */
166 | for (i = 0; i < input_len; i++) {
167 | if (*input == '.') {
168 | *oext = input + 1; // Extension will be set one byte behind first separator from the end
169 | *oname = input - (input_len - i) + 1; // File name is set here
170 | *input = '\0'; // Replace separator with '\0'
171 | break; // No need to look further
172 | }
173 |
174 | input--; // Move to next character
175 | }
176 |
177 | /* No separator was found, file name will equal to input and extension will be NULL */
178 | if (*oname == NULL)
179 | *oname = input + 1;
180 | }
181 |
182 | static size_t conv_rules(char *input, int max_len) {
183 | size_t input_len = 0;
184 | size_t i = 0;
185 |
186 | /* Mostly because filename extension might be missing */
187 | if (input != NULL) {
188 | input_len = strlen(input);
189 |
190 | if (input_len > max_len)
191 | input_len = max_len;
192 |
193 | for (i = 0; i < input_len; i++) {
194 | if (*input >= 97 && *input <= 122)
195 | *input -= 32; // Convert lower case characters to upper case
196 | else if ((*input >= 65 && *input <= 90) || (*input >= 48 && *input <= 57)) {
197 | // Do not convert this character set
198 | }
199 | else
200 | *input = '_'; // Everything else will become '_'
201 |
202 | input++;
203 | }
204 |
205 | *input = '\0';
206 | }
207 |
208 | return input_len;
209 | }
210 |
--------------------------------------------------------------------------------
/lib/globals.c:
--------------------------------------------------------------------------------
1 | /*
2 | * globals.c
3 | *
4 | * Version: 0.1.0
5 | *
6 | * Release date: 13.12.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include
29 |
30 | enum errors_l Gdisplay_message(enum errors_l error, const char *calling_function_name) {
31 | char msg[256];
32 |
33 | memset(msg, 0, sizeof(msg));
34 |
35 | switch(error) {
36 | case E_MALLOC:
37 | strncpy(msg, "Memory allocation problem.", sizeof(msg));
38 | break;
39 |
40 | default:
41 | strncpy(msg, "I don't know what to say.", sizeof(msg));
42 | break;
43 | }
44 |
45 | printf("Error: %s(): %s\n", calling_function_name, msg);
46 |
47 | return error;
48 | }
49 |
--------------------------------------------------------------------------------
/lib/iso9660.c:
--------------------------------------------------------------------------------
1 | /*
2 | * iso9660.c
3 | *
4 | * Version: 0.4.1
5 | *
6 | * Release date: 07.04.2016
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "iso9660.h"
29 |
30 | /* Rockridge */
31 | unsigned char CE[28];
32 | unsigned char ER[238];
33 | unsigned char SP[7];
34 | unsigned char RR[5];
35 | unsigned char PX[44]; // 1<<0
36 | unsigned char TF[26]; // 1<<7
37 | unsigned char *SL; // 1<<2
38 | unsigned char *NM; // 1<<3
39 | const enum rrip_fields_t init_fields = RRIP_INIT_FIELDS;
40 |
41 | void iso9660_cp2heap(void **dest, const void *source, long int size, uint32_t *dest_size) {
42 | memcpy(*dest, source, size);
43 |
44 | if (dest_size != NULL) {
45 | *dest_size += size;
46 | *dest += size;
47 | }
48 | }
49 |
50 | uint32_t iso9660_terminator(void **terminator) {
51 | void *rr_terminator = (void *) malloc(BLOCK_SIZE);
52 | void *terminator_start = rr_terminator;
53 | uint32_t terminator_size = 0;
54 |
55 | uint8_t type = 0xff;
56 | char identifier[5] = ISO9660_ID;
57 | uint8_t version = 0x01;
58 |
59 | memset(rr_terminator, 0, BLOCK_SIZE);
60 |
61 | iso9660_cp2heap(&rr_terminator, &type, sizeof(uint8_t), &terminator_size);
62 | iso9660_cp2heap(&rr_terminator, identifier, sizeof(identifier), &terminator_size);
63 | iso9660_cp2heap(&rr_terminator, &version, sizeof(uint8_t), &terminator_size);
64 |
65 | *terminator = terminator_start;
66 | return terminator_size;
67 | }
68 |
69 | uint32_t iso9660_header(void **header, struct file_list_t file_list, struct ISO_data_t ISO_data) {
70 | void *rr_header = (void *) malloc(BLOCK_SIZE);
71 | void *header_start = rr_header;
72 | int offset = ISO_data.path_table_size / (BLOCK_SIZE + 1);
73 | uint32_t header_size = 0;
74 | time_t time_now = time(NULL);
75 |
76 | char system_identifier[32] = SYSTEM_ID; // "LINUX"
77 | char volume_identifier[32] = VOLUME_ID; // "CDROM"
78 | uint64_t volume_space_size = get_int32_LSB_MSB(ISO_data.LBA_last + 1); // Size of whole ISO image in blocks ( * BLOCK_SIZE = ISO size [B]) + 1 empty block at the end
79 | uint32_t volume_set_size = get_int16_LSB_MSB(one);
80 | uint32_t volume_sequence_number = get_int16_LSB_MSB(one);
81 | uint32_t logical_block_size = get_int16_LSB_MSB(BLOCK_SIZE);
82 | uint64_t path_table_size = get_int32_LSB_MSB(ISO_data.path_table_size); // Path table size
83 | uint32_t path_table_LBA = 0x14; // LBA of type-L path table (little endian)
84 | uint32_t opath_table_LBA = 0x00; // LBA of type-L optional path table (little endian)
85 | uint32_t path_table_LBA_BE = __bswap_32(0x16 + offset); // LBA of type-M path table (big endian)
86 | uint32_t opath_table_LBA_BE = 0x00; // LBA of type-M optional path table (big endian)
87 |
88 | /* Might be used more in future ... */
89 | char volume_set_id[128];
90 | char publisher_id[128];
91 | char data_preparer_id[128];
92 | char application_id[128] = "EBISO UEFI BOOTABLE ISO CREATOR (C) 2015 V. (SODOMA) GOZORA";
93 | char copyright_file_id[38];
94 | char abstract_file_id[36];
95 | char biblio_file_id[37];
96 |
97 | /* Date/times */
98 | char date_time[17];
99 | char expiration_date_time[17];
100 |
101 | memset(rr_header, 0, BLOCK_SIZE);
102 |
103 | /*
104 | * According to ISO9660 unused space should be filled
105 | * with (0x20) ASCII spaces ' '
106 | */
107 | str_var_prepare(system_identifier, 0x20, sizeof(system_identifier));
108 | str_var_prepare(volume_identifier, 0x20, sizeof(volume_identifier));
109 | str_var_prepare(application_id, 0x20, sizeof(application_id));
110 |
111 | memset(volume_set_id, 0x20, sizeof(volume_set_id));
112 | memset(publisher_id, 0x20, sizeof(publisher_id));
113 | memset(data_preparer_id, 0x20, sizeof(data_preparer_id));
114 | memset(copyright_file_id, 0x20, sizeof(copyright_file_id));
115 | memset(abstract_file_id, 0x20, sizeof(abstract_file_id));
116 | memset(biblio_file_id, 0x20, sizeof(biblio_file_id));
117 |
118 | memset(expiration_date_time, '0', sizeof(expiration_date_time));
119 |
120 | iso9660_cp2heap(&rr_header, &one, sizeof(uint8_t), &header_size); // Type code of primary volume descirptor 0x01
121 | iso9660_cp2heap(&rr_header, ISO9660_ID, strlen(ISO9660_ID), &header_size); // Standard Identifier 'CD001'
122 | iso9660_cp2heap(&rr_header, &one, sizeof(uint8_t), &header_size); // Version always 0x01
123 | rr_header += 1, header_size += 1; // Unused
124 | iso9660_cp2heap(&rr_header, system_identifier, sizeof(system_identifier), &header_size); // "LINUX"
125 | iso9660_cp2heap(&rr_header, volume_identifier, sizeof(volume_identifier), &header_size); // "CDROM"
126 | rr_header += 8, header_size += 8; // Unused
127 | iso9660_cp2heap(&rr_header, &volume_space_size, sizeof(uint64_t), &header_size); // Size of whole ISO image in blocks ( * BLOCK_SIZE = ISO size [B])
128 | rr_header += 32, header_size += 32; // Unused
129 | iso9660_cp2heap(&rr_header, &volume_set_size, sizeof(uint32_t), &header_size); // 0x01
130 | iso9660_cp2heap(&rr_header, &volume_sequence_number, sizeof(uint32_t), &header_size); // 0x01
131 | iso9660_cp2heap(&rr_header, &logical_block_size, sizeof(uint32_t), &header_size); // ISO file block size (BLOCK_SIZE)
132 | iso9660_cp2heap(&rr_header, &path_table_size, sizeof(uint64_t), &header_size); // Size of path table
133 | iso9660_cp2heap(&rr_header, &path_table_LBA, sizeof(uint32_t), &header_size); // Path table will always start on block 0x14 (hopefully)
134 | iso9660_cp2heap(&rr_header, &opath_table_LBA, sizeof(uint32_t), &header_size); // Location of optional path table
135 | iso9660_cp2heap(&rr_header, &path_table_LBA_BE, sizeof(uint32_t), &header_size); // type-M path table (big endian)
136 | iso9660_cp2heap(&rr_header, &opath_table_LBA_BE, sizeof(uint32_t), &header_size); // LBA of type-M optional path table (big endian)
137 |
138 | /* Create root directory record for header */
139 | construct_dir_record(&file_list, NULL, &rr_header, ROOT_HEADER);
140 |
141 | iso9660_cp2heap(&rr_header, volume_set_id, sizeof(volume_set_id), &header_size);
142 | iso9660_cp2heap(&rr_header, publisher_id, sizeof(publisher_id), &header_size);
143 | iso9660_cp2heap(&rr_header, data_preparer_id, sizeof(data_preparer_id), &header_size);
144 | iso9660_cp2heap(&rr_header, application_id, sizeof(application_id), &header_size); // So far, only this one is in use
145 | iso9660_cp2heap(&rr_header, copyright_file_id, sizeof(copyright_file_id), &header_size);
146 | iso9660_cp2heap(&rr_header, abstract_file_id, sizeof(abstract_file_id), &header_size);
147 | iso9660_cp2heap(&rr_header, biblio_file_id, sizeof(biblio_file_id), &header_size);
148 |
149 | /* If conversion fails, use default values ('0') */
150 | if (format_header_date(time_now, date_time) != E_OK) {
151 | printf("Warning: iso9660_header(): Failed to convert creation date/time\n");
152 | memset(date_time, '0', sizeof(date_time));
153 | }
154 |
155 | iso9660_cp2heap(&rr_header, date_time, sizeof(date_time), &header_size); // Creation date/time
156 | iso9660_cp2heap(&rr_header, date_time, sizeof(date_time), &header_size); // Modification date/time
157 | iso9660_cp2heap(&rr_header, expiration_date_time, sizeof(expiration_date_time), &header_size); // Expiration date/tim
158 | iso9660_cp2heap(&rr_header, date_time, sizeof(date_time), &header_size); // Effective date/time
159 |
160 | iso9660_cp2heap(&rr_header, &one, sizeof(uint8_t), &header_size); // File structure version
161 | iso9660_cp2heap(&rr_header, &zero, sizeof(uint8_t), &header_size); // Unused
162 |
163 | *header = header_start;
164 | return header_size;
165 | }
166 |
167 | int iso9660_path_table(struct file_list_t *file_list, void **path_table, enum endianity_l endianity, struct ISO_data_t *ISO_data) {
168 | struct file_list_t *rr_file_list = file_list;
169 | void *rr_path_table = (void *) malloc(BLOCK_SIZE);
170 | void *path_table_start = rr_path_table;
171 | void *tmp_realloc = NULL;
172 | int entry_len = 0;
173 | int count = 1;
174 | int mem_free = BLOCK_SIZE;
175 | int rv = 0;
176 | uint32_t path_table_size = 0;
177 | uint32_t LBA = 0;
178 | uint16_t parent_id = 0;
179 | uint8_t pad_len = 0;
180 |
181 | memset(rr_path_table, 0, BLOCK_SIZE);
182 |
183 | while(rr_file_list->next != NULL ) {
184 | if (S_ISDIR(rr_file_list->st_mode)) {
185 | pad_len = do_pad(rr_file_list->name_conv_len, PAD_ODD);
186 |
187 | /* Switch endianity for selected parematers */
188 | LBA = rr_file_list->LBA;
189 | parent_id = rr_file_list->parent_id;
190 | if (endianity == MSB) {
191 | LBA = __bswap_32(LBA);
192 | parent_id = __bswap_16(parent_id);
193 | }
194 |
195 | /* Dynamic memory allocation BEGIN */
196 | entry_len = PT_RECORD_LEN + pad_len;
197 |
198 | mem_free -= entry_len;
199 |
200 | if (mem_free < 0) {
201 | count++;
202 |
203 | if ((tmp_realloc = realloc(path_table_start, count * BLOCK_SIZE)) != NULL) {
204 | path_table_start = tmp_realloc;
205 | mem_free = BLOCK_SIZE + mem_free;
206 | memset(path_table_start + (count * BLOCK_SIZE) - BLOCK_SIZE, 0, BLOCK_SIZE);
207 | rr_path_table = path_table_start + path_table_size;
208 | }
209 | else {
210 | rv = Gdisplay_message(E_MALLOC, __func__);
211 | break;
212 | }
213 | }
214 | /* Dynamic memory allocation END */
215 |
216 | iso9660_cp2heap(&rr_path_table, &rr_file_list->name_conv_len, sizeof(uint8_t), &path_table_size); // Len of dir name
217 | iso9660_cp2heap(&rr_path_table, &zero, sizeof(uint8_t), &path_table_size); // Extended attr record
218 | iso9660_cp2heap(&rr_path_table, &LBA, sizeof(uint32_t), &path_table_size); // LBA
219 | iso9660_cp2heap(&rr_path_table, &parent_id, sizeof(uint16_t), &path_table_size); // Parent dir ID
220 | iso9660_cp2heap(&rr_path_table, rr_file_list->name_conv, pad_len, &path_table_size); // Dir name
221 | }
222 |
223 | rr_file_list = rr_file_list->next;
224 | }
225 |
226 | if (ISO_data != NULL)
227 | ISO_data->path_table_size = path_table_size;
228 |
229 | *path_table = path_table_start;
230 |
231 | return rv;
232 | }
233 |
234 | int iso9660_assign_LBA(struct file_list_t *file_list, struct ISO_data_t *ISO_data) {
235 | struct file_list_t *rr_file_list = file_list;
236 | struct file_list_t *tmp_file_list = NULL;
237 | struct file_list_t *search_result = NULL;
238 | struct CE_list_t CE_list;
239 | int total_len = 0;
240 | int dir_rec_len = 0;
241 | int counter = 1;
242 | int additional_bytes = 0;
243 | int rock_ridge_header_size = 0;
244 | int SL_len = 0;
245 | int rv = E_OK;
246 | uint32_t LBA = LBA_ROOT + (2 * ISO_data->path_table_offset); // Move first LBA if path tables are larger that BLOCK_SIZE
247 | uint8_t terminator_len = 0;
248 | bool_t rock_ridge_on = FALSE;
249 | int current_len = 0;
250 | int parent_len = 0;
251 | int empty_dir_len = 0;
252 |
253 | memset(&CE_list, 0, sizeof(CE_list));
254 |
255 | if (option_on_off(ISO_data->options, OPT_R) == E_OK) {
256 | rock_ridge_header_size = init_RRIP();
257 |
258 | rock_ridge_on = TRUE;
259 | }
260 |
261 | /* Initialize CE_list for directory records */
262 | if (rock_ridge_on == TRUE && (rv = CEarr_init_list(&CE_list, CE_LIST_PREALLOC)) != E_OK) {
263 | CEarr_destroy_list(&CE_list);
264 | return rv;
265 | }
266 |
267 | /* Assign LBAs to directories first */
268 | while(rr_file_list->next != NULL) {
269 | if (S_ISDIR(rr_file_list->st_mode)) {
270 | total_len = 0;
271 | counter = 1;
272 | tmp_file_list = file_list;
273 | empty_dir_len = do_pad((DIR_RECORD_LEN + 1) + rock_ridge_header_size, PAD_ODD);
274 | dir_rec_len = 2 * empty_dir_len; // Min directory record will contain at least '.' and '..'
275 |
276 | /* Absolute root directory will have SP & CE on top */
277 | if (strncmp(rr_file_list->name_path, ".", 2) == 0 && rock_ridge_on == TRUE) {
278 | current_len = do_pad(DIR_RECORD_LEN + 1 + rock_ridge_header_size + (sizeof(SP) + sizeof(CE)), PAD_ODD);
279 | parent_len = do_pad(DIR_RECORD_LEN + 1 + rock_ridge_header_size, PAD_ODD);
280 |
281 | dir_rec_len = current_len + parent_len;
282 |
283 | /* Calculate and allign absolute root entry length */
284 | rr_file_list->ISO9660_len = current_len;
285 |
286 | /* CE entry should always exist for absolute root */
287 | rr_file_list->CE_LBA = 1;
288 |
289 | rr_file_list->full_len = rr_file_list->ISO9660_len + sizeof(ER);
290 | }
291 |
292 | /* Calculate how much blocks will parent directory occupy */
293 | while(tmp_file_list->next != NULL) {
294 |
295 | /* Skip absolute root direcstory */
296 | if (strncmp(tmp_file_list->name_path, ".", 2) == 0) {
297 | tmp_file_list = tmp_file_list->next;
298 | continue;
299 | }
300 | else if (tmp_file_list->parent_id == rr_file_list->dir_id) {
301 | int rr_len = 0; // Represent individual len of each record
302 |
303 | terminator_len = set_terminator_len(tmp_file_list->st_mode);
304 |
305 | /* Size of basic iso9660 directory record */
306 | rr_len = do_pad(DIR_RECORD_LEN + tmp_file_list->name_conv_len + terminator_len, PAD_ODD);
307 | dir_rec_len += rr_len;
308 |
309 | if (rock_ridge_on == TRUE) {
310 | if ((init_fields & rrip_NM) != 0)
311 | additional_bytes = tmp_file_list->name_short_len + NM_HEADER_SIZE;
312 | else
313 | additional_bytes = 0;
314 |
315 | /* Add potentional length of symlink (SL) record */
316 | if (S_ISLNK(tmp_file_list->st_mode)) {
317 | #if (DEBUG == 1)
318 | printf("DEBUG: %s(): Symlink name: [%s]\n", __func__, tmp_file_list->name_short);
319 | #endif
320 | if ((rv = SL_create(tmp_file_list->name_path, &SL, &SL_len)) != E_OK) {
321 | if (rv == E_LNKFAIL)
322 | printf("Error: %s(): Working with symlink [%s] failed.\n", __func__, tmp_file_list->name_short);
323 |
324 | CEarr_destroy_list(&CE_list);
325 | free(NM);
326 | return rv;
327 | }
328 | else {
329 | additional_bytes += (SL_len);
330 | free(SL);
331 | }
332 | }
333 |
334 | dir_rec_len += rock_ridge_header_size + additional_bytes;
335 | rr_len += rock_ridge_header_size + additional_bytes;
336 |
337 | /*
338 | * Set flag for CE creation if entry is longer than 255 bytes.
339 | * tmp_file_list->full_len is used only if CE record is in use,
340 | * otherwise tmp_file_list->ISO9660 is sufficient.
341 | */
342 | if (rr_len >= 0xFF) {
343 | tmp_file_list->CE_LBA = 1;
344 | tmp_file_list->ISO9660_len = do_pad(DIR_RECORD_LEN + tmp_file_list->name_conv_len + terminator_len + sizeof(CE), PAD_ODD);
345 |
346 | dir_rec_len -= rock_ridge_header_size + additional_bytes;
347 | dir_rec_len += sizeof(CE);
348 |
349 | tmp_file_list->full_len = rr_len + sizeof(CE);
350 |
351 | /*
352 | * Create another NM entry if needed
353 | * 250 is max len of payload for uint8 togeather with NM entry header.
354 | * Without this NM entry len could overfow.
355 | */
356 | if (tmp_file_list->name_short_len >= 250)
357 | tmp_file_list->full_len += NM_HEADER_SIZE;
358 |
359 | /* Allign to even bytes count in the end */
360 | tmp_file_list->full_len = do_pad(tmp_file_list->full_len, PAD_ODD);
361 | }
362 | else {
363 | tmp_file_list->ISO9660_len = do_pad(rr_len, PAD_ODD);
364 | }
365 |
366 | /* Allign to even bytes count in the end */
367 | dir_rec_len = do_pad(dir_rec_len, PAD_ODD);
368 | }
369 |
370 | /* Allign entry at the end of the block */
371 | if (total_len + dir_rec_len <= counter * BLOCK_SIZE)
372 | total_len += dir_rec_len;
373 | else {
374 | total_len = counter * BLOCK_SIZE;
375 | total_len += dir_rec_len;
376 | counter++;
377 | }
378 |
379 | dir_rec_len = 0;
380 | }
381 |
382 | tmp_file_list = tmp_file_list->next;
383 | }
384 |
385 | if (total_len == 0)
386 | total_len = 2 * empty_dir_len;
387 |
388 | rr_file_list->size = total_len;
389 | rr_file_list->blocks = blocks_count(total_len);
390 |
391 | /*
392 | * Save largest continous directory block.
393 | * This will be used for memory allocation later in iso9660_directory_record().
394 | */
395 | if (rr_file_list->blocks > ISO_data->largest_cont_block)
396 | ISO_data->largest_cont_block = rr_file_list->blocks;
397 |
398 | rr_file_list->LBA = LBA;
399 | LBA += rr_file_list->blocks;
400 |
401 | /*
402 | * Assign LBA to CE directory records.
403 | * Warning: This function increments LBA.
404 | */
405 | if (rr_file_list->CE_LBA == 1) {
406 | if ((rv = CE_assign_LBA(&CE_list, rr_file_list, &LBA)) != E_OK) {
407 | CEarr_destroy_list(&CE_list);
408 | return rv;
409 | }
410 | }
411 |
412 | }
413 |
414 | rr_file_list = rr_file_list->next;
415 | }
416 | if (rock_ridge_on == TRUE)
417 | CEarr_destroy_list(&CE_list);
418 |
419 | /* Initialize CE_list for non-directory records */
420 | if (rock_ridge_on == TRUE && (rv = CEarr_init_list(&CE_list, CE_LIST_PREALLOC)) != E_OK) {
421 | CEarr_destroy_list(&CE_list);
422 | return rv;
423 | }
424 |
425 | /* Assign CE LBAs to non-directory records */
426 | rr_file_list = file_list;
427 | while(rr_file_list->next != NULL) {
428 | if (rr_file_list->CE_LBA == 1) {
429 |
430 | /*
431 | * Assign LBA to CE file records.
432 | * Warning: This function increments LBA.
433 | */
434 | if ((rv = CE_assign_LBA(&CE_list, rr_file_list, &LBA)) != E_OK) {
435 | CEarr_destroy_list(&CE_list);
436 | return rv;
437 | }
438 | }
439 |
440 | rr_file_list = rr_file_list->next;
441 | }
442 |
443 | if (rock_ridge_on == TRUE)
444 | CEarr_destroy_list(&CE_list);
445 |
446 | /* Assign first 2 file LBAs for BOOT.CAT and UEFI boot image (virtual image) */
447 | search_result = list_search_name(file_list, ISO_data->boot_cat_file);
448 | search_result->LBA = LBA;
449 | ISO_data->boot_cat_LBA = LBA;
450 | LBA += blocks_count(search_result->size);
451 |
452 | search_result = list_search_name(file_list, ISO_data->efi_boot_file_full);
453 | search_result->LBA = LBA;
454 | search_result->blocks = blocks_count(search_result->size);
455 | LBA += search_result->blocks;
456 |
457 | /* Assign LBA to files */
458 | rr_file_list = file_list;
459 | while(rr_file_list->next != NULL) {
460 | if (!S_ISDIR(rr_file_list->st_mode) && strncmp(rr_file_list->name_short, "BOOT.CAT", 8) \
461 | && strncmp(rr_file_list->name_path, ISO_data->efi_boot_file_full, strlen(ISO_data->efi_boot_file_full)) ) {
462 |
463 | rr_file_list->LBA = LBA;
464 |
465 | /*
466 | * Dont increment LBA for symlink as they dont bear no real content
467 | * Symlink can point to arbitrary LBA
468 | */
469 | if (!S_ISLNK(rr_file_list->st_mode)) {
470 | rr_file_list->LBA = LBA;
471 | rr_file_list->blocks = blocks_count(rr_file_list->size);
472 | LBA = LBA + rr_file_list->blocks;
473 | }
474 | }
475 | rr_file_list = rr_file_list->next;
476 | }
477 |
478 | ISO_data->LBA_last = LBA;
479 |
480 | return E_OK;
481 | }
482 |
483 | int iso9660_directory_record(struct file_list_t *file_list, FILE *dest, struct ISO_data_t *ISO_data) {
484 | void *directory_table = NULL;
485 | void *directory_table_start = NULL;
486 | void *rr_save_ptr = NULL;
487 | struct file_list_t *rr_file_list = file_list;
488 | struct file_list_t *tmp_file_list = NULL;
489 | struct file_list_t **parent_index = NULL;
490 | int directory_table_size = BLOCK_SIZE * ISO_data->largest_cont_block;
491 | int parent_index_size = sizeof(struct file_list_t *) * ISO_data->dir_count;
492 | int rv = E_OK;
493 | int entry_len = 0;
494 | int bytes_written = 0;
495 | int offset = 0;
496 | uint8_t rock_ridge_on = FALSE;
497 | enum segment_list_t type = 0;
498 |
499 | if (option_on_off(ISO_data->options, OPT_R) == E_OK)
500 | rock_ridge_on = TRUE;
501 |
502 | if ((directory_table_start = (void *) malloc(directory_table_size)) == NULL) {
503 | rv = Gdisplay_message(E_MALLOC, __func__);
504 | goto cleanup;
505 | }
506 |
507 | if ((parent_index = (struct file_list_t **) malloc(parent_index_size)) == NULL ) {
508 | rv = Gdisplay_message(E_MALLOC, __func__);
509 | goto cleanup;
510 | }
511 | else
512 | memset(parent_index, 0, parent_index_size);
513 |
514 | while(rr_file_list->next != NULL) {
515 |
516 | /* Skip files */
517 | if (!S_ISDIR(rr_file_list->st_mode)) {
518 | rr_file_list = rr_file_list->next;
519 | continue;
520 | }
521 |
522 | directory_table = directory_table_start;
523 | memset(directory_table_start, 0, directory_table_size);
524 |
525 | /*
526 | * Entry for ABS root will be a bit different
527 | * Create records for '.' & '..'
528 | */
529 | if (strncmp(rr_file_list->name_path, ".", 2) == 0)
530 | type = (rock_ridge_on == TRUE) ? RRIP_ABS_ROOT : ISO9660_ROOT;
531 | else
532 | type = (rock_ridge_on == TRUE) ? RRIP_ROOT : ISO9660_ROOT;
533 |
534 | /* Create index of parent directory data */
535 | if (parent_index[rr_file_list->dir_id - 1] == NULL)
536 | parent_index[rr_file_list->dir_id - 1] = rr_file_list;
537 |
538 | bytes_written = construct_dir_record(rr_file_list, parent_index, &directory_table, type);
539 |
540 | /*
541 | * Search whole file list from beginning
542 | * Search for all elements (dirs, files, ...), with matching parent ID
543 | */
544 | tmp_file_list = file_list;
545 | int CE_offset = 0;
546 | while(tmp_file_list->next != NULL) {
547 |
548 | /*
549 | * Root entry in list was artificially created.
550 | * Following condition will skip it
551 | */
552 | if (tmp_file_list->parent_id == rr_file_list->dir_id && *tmp_file_list->name_short != 0 ) {
553 |
554 | /* Save pointer for later shift operations */
555 | rr_save_ptr = directory_table;
556 |
557 | type = (rock_ridge_on == TRUE) ? RRIP : ISO9660;
558 |
559 | entry_len = construct_dir_record(tmp_file_list, NULL, &directory_table, type);
560 |
561 | bytes_written += entry_len;
562 |
563 | /* Create CE record if needed */
564 | if (tmp_file_list->CE_LBA != 0) {
565 | void *rr_CE = CE + 4;
566 | void *CE_start = NULL;
567 | int basic_iso9660_len = 0;
568 | uint64_t CE_len = 0;
569 | uint64_t CE_LBA = 0;
570 | uint64_t CE_offset_LSB_MSB = 0;
571 | uint32_t rr_write = 0;
572 | uint8_t pad_len = 0;
573 | uint8_t terminator_len = 0;
574 |
575 | CE_offset = tmp_file_list->CE_offset;
576 |
577 | terminator_len = set_terminator_len(tmp_file_list->st_mode);
578 | pad_len = do_pad(tmp_file_list->name_conv_len, PAD_EVEN); // Dir record must start on EVEN byte
579 | basic_iso9660_len = DIR_RECORD_LEN + pad_len + terminator_len; // Length of basic dir record (without SUSP or RRIP)
580 | CE_LBA = get_int32_LSB_MSB(tmp_file_list->CE_LBA);
581 | CE_len = get_int32_LSB_MSB(entry_len - basic_iso9660_len);
582 | CE_offset_LSB_MSB = get_int32_LSB_MSB(CE_offset);
583 |
584 | fseek(dest, (tmp_file_list->CE_LBA * BLOCK_SIZE) + CE_offset, SEEK_SET);
585 | fwrite(rr_save_ptr + basic_iso9660_len, 1, entry_len - basic_iso9660_len, dest); // Write everything after standard dir record
586 |
587 | memset(rr_CE, 0, sizeof(CE) - 4);
588 | iso9660_cp2heap(&rr_CE, &CE_LBA, sizeof(CE_LBA), &rr_write); // rr_write is here only to ensure move of pointer
589 | iso9660_cp2heap(&rr_CE, &CE_offset_LSB_MSB, sizeof(CE_offset_LSB_MSB), &rr_write);
590 | iso9660_cp2heap(&rr_CE, &CE_len, sizeof(CE_len), &rr_write);
591 |
592 | /* Modify directory_table entry */
593 | CE_start = rr_save_ptr + basic_iso9660_len;
594 | iso9660_cp2heap(&CE_start, CE, sizeof(CE), &rr_write);
595 | iso9660_cp2heap(&rr_save_ptr, &(tmp_file_list)->ISO9660_len, sizeof(uint8_t), NULL);
596 |
597 | /* Clean bytes and correct counter value */
598 | memset(rr_save_ptr + tmp_file_list->ISO9660_len, 0, entry_len - tmp_file_list->ISO9660_len);
599 | directory_table -= entry_len;
600 | bytes_written -= entry_len;
601 | directory_table += tmp_file_list->ISO9660_len;
602 | bytes_written += tmp_file_list->ISO9660_len;
603 | entry_len = tmp_file_list->ISO9660_len;
604 | }
605 |
606 | /* Allign directory entry to BLOCK_SIZE */
607 | if (bytes_written > BLOCK_SIZE) {
608 | offset = entry_len + (BLOCK_SIZE - bytes_written);
609 | bytes_written = entry_len;
610 |
611 | /* Move bytes to new block */
612 | shift_mem(rr_save_ptr, offset, entry_len);
613 | directory_table += offset;
614 | }
615 | }
616 |
617 | tmp_file_list = tmp_file_list->next;
618 | }
619 |
620 | fseek(dest, rr_file_list->LBA * BLOCK_SIZE, SEEK_SET);
621 | fwrite(directory_table_start, 1, rr_file_list->blocks * BLOCK_SIZE, dest);
622 |
623 | rr_file_list = rr_file_list->next;
624 | }
625 |
626 | /* Write ER entry of ABS root directory */
627 | rr_file_list = file_list;
628 | fseek(dest, rr_file_list->CE_LBA * BLOCK_SIZE, SEEK_SET);
629 | fwrite(ER, 1, sizeof(ER), dest);
630 |
631 | /* Write files */
632 | rv = write_files(file_list, dest);
633 |
634 | cleanup:
635 | if (directory_table_start != NULL)
636 | free(directory_table_start);
637 | if (NM != NULL)
638 | free(NM);
639 | if (parent_index != NULL)
640 | free(parent_index);
641 |
642 | return rv;
643 | }
644 |
645 | int do_pad(int len, enum pad_list_t type) {
646 |
647 | if ((type == PAD_EVEN && len % 2 == 0) || (type == PAD_ODD && len % 2 != 0))
648 | len++;
649 |
650 | return len;
651 | }
652 |
653 | static uint32_t construct_dir_record(struct file_list_t *file_list, struct file_list_t **parent_index, void **directory_table_output, enum segment_list_t type) {
654 | struct file_list_t *rr_file_list = file_list;
655 | struct file_list_t *parent = NULL;
656 | struct tm *ts = NULL;
657 | struct iso9660_data_t iso9660_data;
658 | void *rr_directory_table = *directory_table_output;
659 | void *rr_directory_table_start = rr_directory_table;
660 | void *rr_save_ptr = NULL;
661 | char *file_terminator = ";1";
662 | char mdate_time[7];
663 | char adate_time[7];
664 | char cdate_time[7];
665 | int terminator_len = 0;
666 | int rr_save_size = 0;
667 | int SL_len = 0;
668 | uint64_t mode = get_int32_LSB_MSB(rr_file_list->st_mode);
669 | uint64_t nlinks = get_int32_LSB_MSB(rr_file_list->st_nlink);
670 | uint64_t uid = get_int32_LSB_MSB(rr_file_list->st_uid);
671 | uint64_t gid = get_int32_LSB_MSB(rr_file_list->st_gid);
672 | uint64_t ino = get_int32_LSB_MSB(rr_file_list->st_ino);
673 | uint32_t directory_table_size = 0;
674 | uint8_t pad_len = 0;
675 |
676 | memset(mdate_time, 0, sizeof(mdate_time));
677 | memset(adate_time, 0, sizeof(adate_time));
678 | memset(cdate_time, 0, sizeof(cdate_time));
679 | memset(&iso9660_data, 0, sizeof(iso9660_data_t));
680 |
681 | iso9660_data.volume_seq_number = get_int16_LSB_MSB(one);
682 | iso9660_data.ext_attr_record = 0;
683 |
684 | /* Assign modify date/time values */
685 | ts = localtime(&file_list->mtime);
686 | mdate_time[0] = ts->tm_year;
687 | mdate_time[1] = ts->tm_mon + 1;
688 | mdate_time[2] = ts->tm_mday;
689 | mdate_time[3] = ts->tm_hour;
690 | mdate_time[4] = ts->tm_min;
691 | mdate_time[5] = ts->tm_sec;
692 | mdate_time[6] = ts->tm_gmtoff / 60 / 15;
693 |
694 | /* Assign access date/time values */
695 | ts = localtime(&file_list->atime);
696 | adate_time[0] = ts->tm_year;
697 | adate_time[1] = ts->tm_mon + 1;
698 | adate_time[2] = ts->tm_mday;
699 | adate_time[3] = ts->tm_hour;
700 | adate_time[4] = ts->tm_min;
701 | adate_time[5] = ts->tm_sec;
702 | adate_time[6] = ts->tm_gmtoff / 60 / 15;
703 |
704 | /* Assign status change date/time values */
705 | ts = localtime(&file_list->ctime);
706 | cdate_time[0] = ts->tm_year;
707 | cdate_time[1] = ts->tm_mon + 1;
708 | cdate_time[2] = ts->tm_mday;
709 | cdate_time[3] = ts->tm_hour;
710 | cdate_time[4] = ts->tm_min;
711 | cdate_time[5] = ts->tm_sec;
712 | cdate_time[6] = ts->tm_gmtoff / 60 / 15;
713 |
714 | iso9660_data.LBA = get_int32_LSB_MSB(rr_file_list->LBA);
715 | strncpy(iso9660_data.mdate_time, mdate_time, sizeof(iso9660_data.mdate_time));
716 | pad_len = (rr_file_list->name_conv_len % 2 == 0) ? 1 : 0; // Do padding of EVEN lengths
717 |
718 | if (S_ISDIR(rr_file_list->st_mode)) {
719 | terminator_len = 0;
720 | iso9660_data.data_len = get_int32_LSB_MSB(rr_file_list->blocks * BLOCK_SIZE);
721 | iso9660_data.flags = 0x02;
722 | }
723 | else {
724 | terminator_len = 2;
725 | iso9660_data.data_len = get_int32_LSB_MSB(rr_file_list->size);
726 | iso9660_data.flags = 0x00;
727 | }
728 |
729 | if (type == ISO9660_ROOT || type == ROOT_HEADER || type == RRIP_ROOT) {
730 | pad_len = 0;
731 | iso9660_data.name_len = 1; // Lenght of roor dir name is always 1
732 | }
733 | else {
734 | iso9660_data.name_len = rr_file_list->name_conv_len + terminator_len;
735 | }
736 |
737 | /* Create basic ISO9660 structure */
738 | construct_iso9660_record(&rr_directory_table, iso9660_data, &directory_table_size);
739 |
740 | /* Add file name */
741 | if (type == ISO9660_ROOT || type == ROOT_HEADER || type == RRIP_ROOT)
742 | iso9660_cp2heap(&rr_directory_table, &zero, iso9660_data.name_len, &directory_table_size);
743 | else
744 | iso9660_cp2heap(&rr_directory_table, rr_file_list->name_conv, rr_file_list->name_conv_len, &directory_table_size);
745 |
746 | /* If entry is file, add file terminator */
747 | if (!S_ISDIR(rr_file_list->st_mode))
748 | iso9660_cp2heap(&rr_directory_table, file_terminator, terminator_len, &directory_table_size);
749 |
750 | /* Do padding of even len file names */
751 | if (pad_len == 1)
752 | iso9660_cp2heap(&rr_directory_table, &zero, pad_len, &directory_table_size);
753 |
754 | /* This one is called only during header creation */
755 | if (type == ROOT_HEADER) {
756 | iso9660_cp2heap(&rr_directory_table_start, &directory_table_size, sizeof(uint8_t), NULL);
757 | }
758 | /* Add record for directory '..' */
759 | else if (type == ISO9660_ROOT) {
760 | parent = parent_index[rr_file_list->parent_id - 1];
761 |
762 | iso9660_cp2heap(&rr_directory_table_start, &directory_table_size, sizeof(uint8_t), NULL); // Write size of '.'
763 | rr_save_ptr = rr_directory_table;
764 | rr_save_size = directory_table_size;
765 |
766 | /* Assign modify date/time values */
767 | ts = localtime(&parent->mtime);
768 | mdate_time[0] = ts->tm_year;
769 | mdate_time[1] = ts->tm_mon + 1;
770 | mdate_time[2] = ts->tm_mday;
771 | mdate_time[3] = ts->tm_hour;
772 | mdate_time[4] = ts->tm_min;
773 | mdate_time[5] = ts->tm_sec;
774 | mdate_time[6] = ts->tm_gmtoff / 60 / 15;
775 |
776 | iso9660_data.LBA = get_int32_LSB_MSB(parent->LBA);
777 | iso9660_data.data_len = get_int32_LSB_MSB(parent->blocks * BLOCK_SIZE);
778 | strncpy(iso9660_data.mdate_time, mdate_time, sizeof(iso9660_data.mdate_time));
779 |
780 | construct_iso9660_record(&rr_directory_table, iso9660_data, &directory_table_size);
781 | iso9660_cp2heap(&rr_directory_table, &one, iso9660_data.name_len, &directory_table_size);
782 |
783 | rr_save_size = directory_table_size - rr_save_size;
784 | iso9660_cp2heap(&rr_save_ptr, &rr_save_size, sizeof(uint8_t), NULL);
785 | }
786 | /* Only add size of entry if RockRidge is not used */
787 | else if (type == ISO9660) {
788 | iso9660_cp2heap(&rr_directory_table_start, &directory_table_size, sizeof(uint8_t), NULL);
789 | }
790 | /* Add SUSP and RRIP data */
791 | else if (type == RRIP_ABS_ROOT || type == RRIP_ROOT) {
792 | RR[4] = 0;
793 |
794 | if ((init_fields & rrip_PX) != 0)
795 | RR[4] |= 1 << 0; // PX record in use
796 | if ((init_fields & rrip_TF) != 0)
797 | RR[4] |= 1 << 7; // TF record in use
798 |
799 | /* Record directory '.' */
800 | if (type == RRIP_ABS_ROOT) {
801 | void *rr_CE = CE + 4;
802 | uint64_t CE_size = get_int32_LSB_MSB(rr_file_list->CE_LBA);
803 |
804 | iso9660_cp2heap(&rr_CE, &CE_size, sizeof(uint64_t), NULL);
805 | rr_CE += 16;
806 | CE_size = get_int32_LSB_MSB(0xED);
807 | iso9660_cp2heap(&rr_CE, &CE_size, sizeof(uint64_t), NULL);
808 |
809 | iso9660_cp2heap(&rr_directory_table, SP, sizeof(SP), &directory_table_size);
810 | iso9660_cp2heap(&rr_directory_table, CE, sizeof(CE), &directory_table_size);
811 | }
812 |
813 | /* Add RR record*/
814 | if ((init_fields & rrip_RR) != 0)
815 | iso9660_cp2heap(&rr_directory_table, RR, sizeof(RR), &directory_table_size);
816 |
817 | /* Add PX record */
818 | if ((init_fields & rrip_PX) != 0) {
819 | iso9660_cp2heap(&rr_directory_table, PX, 4, &directory_table_size);
820 | iso9660_cp2heap(&rr_directory_table, &mode, sizeof(mode), &directory_table_size);
821 | iso9660_cp2heap(&rr_directory_table, &nlinks, sizeof(nlinks), &directory_table_size);
822 | iso9660_cp2heap(&rr_directory_table, &uid, sizeof(uid), &directory_table_size);
823 | iso9660_cp2heap(&rr_directory_table, &gid, sizeof(gid), &directory_table_size);
824 | iso9660_cp2heap(&rr_directory_table, &ino, sizeof(ino), &directory_table_size);
825 | }
826 |
827 | /* Add TF record */
828 | if ((init_fields & rrip_TF) != 0) {
829 | iso9660_cp2heap(&rr_directory_table, TF, 5, &directory_table_size);
830 | iso9660_cp2heap(&rr_directory_table, mdate_time, sizeof(mdate_time), &directory_table_size); // Modify date/time
831 | iso9660_cp2heap(&rr_directory_table, adate_time, sizeof(adate_time), &directory_table_size); // Access date/time
832 | iso9660_cp2heap(&rr_directory_table, cdate_time, sizeof(cdate_time), &directory_table_size); // status change date/time
833 | }
834 |
835 | /* End of record, do padding if needed */
836 | if (directory_table_size % 2 == 1)
837 | iso9660_cp2heap(&rr_directory_table, &zero, 1, &directory_table_size);
838 |
839 | /* Write size of first record */
840 | iso9660_cp2heap(&rr_directory_table_start, &directory_table_size, sizeof(uint8_t), NULL);
841 |
842 | rr_save_size = directory_table_size;
843 | rr_save_ptr = rr_directory_table;
844 |
845 | /* Add record for directory '..' */
846 | parent = parent_index[rr_file_list->parent_id - 1];
847 |
848 | /* Assign modify date/time values */
849 | ts = localtime(&parent->mtime);
850 | mdate_time[0] = ts->tm_year;
851 | mdate_time[1] = ts->tm_mon + 1;
852 | mdate_time[2] = ts->tm_mday;
853 | mdate_time[3] = ts->tm_hour;
854 | mdate_time[4] = ts->tm_min;
855 | mdate_time[5] = ts->tm_sec;
856 | mdate_time[6] = ts->tm_gmtoff / 60 / 15;
857 |
858 | /* Assign access date/time values */
859 | ts = localtime(&parent->atime);
860 | adate_time[0] = ts->tm_year;
861 | adate_time[1] = ts->tm_mon + 1;
862 | adate_time[2] = ts->tm_mday;
863 | adate_time[3] = ts->tm_hour;
864 | adate_time[4] = ts->tm_min;
865 | adate_time[5] = ts->tm_sec;
866 | adate_time[6] = ts->tm_gmtoff / 60 / 15;
867 |
868 | /* Assign status change date/time values */
869 | ts = localtime(&parent->ctime);
870 | cdate_time[0] = ts->tm_year;
871 | cdate_time[1] = ts->tm_mon + 1;
872 | cdate_time[2] = ts->tm_mday;
873 | cdate_time[3] = ts->tm_hour;
874 | cdate_time[4] = ts->tm_min;
875 | cdate_time[5] = ts->tm_sec;
876 | cdate_time[6] = ts->tm_gmtoff / 60 / 15;
877 |
878 | iso9660_data.LBA = get_int32_LSB_MSB(parent->LBA);
879 | iso9660_data.data_len = get_int32_LSB_MSB(parent->blocks * BLOCK_SIZE);
880 | strncpy(iso9660_data.mdate_time, mdate_time, sizeof(iso9660_data.mdate_time));
881 |
882 | construct_iso9660_record(&rr_directory_table, iso9660_data, &directory_table_size);
883 | iso9660_cp2heap(&rr_directory_table, &one, iso9660_data.name_len, &directory_table_size); // File name len
884 |
885 | /* Add RR record */
886 | if ((init_fields & rrip_RR) != 0)
887 | iso9660_cp2heap(&rr_directory_table, RR, sizeof(RR), &directory_table_size);
888 |
889 | /* Add PX record */
890 | if ((init_fields & rrip_PX) != 0) {
891 | mode = get_int32_LSB_MSB(parent->st_mode);
892 | nlinks = get_int32_LSB_MSB(parent->st_nlink);
893 | uid = get_int32_LSB_MSB(parent->st_uid);
894 | gid = get_int32_LSB_MSB(parent->st_gid);
895 | ino = get_int32_LSB_MSB(parent->st_ino);
896 |
897 | iso9660_cp2heap(&rr_directory_table, PX, 4, &directory_table_size);
898 | iso9660_cp2heap(&rr_directory_table, &mode, sizeof(mode), &directory_table_size);
899 | iso9660_cp2heap(&rr_directory_table, &nlinks, sizeof(nlinks), &directory_table_size);
900 | iso9660_cp2heap(&rr_directory_table, &uid, sizeof(uid), &directory_table_size);
901 | iso9660_cp2heap(&rr_directory_table, &gid, sizeof(gid), &directory_table_size);
902 | iso9660_cp2heap(&rr_directory_table, &ino, sizeof(ino), &directory_table_size);
903 | }
904 |
905 | /* Add TF record */
906 | if ((init_fields & rrip_TF) != 0) {
907 | iso9660_cp2heap(&rr_directory_table, TF, 5, &directory_table_size);
908 | iso9660_cp2heap(&rr_directory_table, mdate_time, sizeof(mdate_time), &directory_table_size); // Modify date/time
909 | iso9660_cp2heap(&rr_directory_table, adate_time, sizeof(adate_time), &directory_table_size); // Access date/time
910 | iso9660_cp2heap(&rr_directory_table, cdate_time, sizeof(cdate_time), &directory_table_size); // status change date/time
911 | }
912 |
913 | /* Do padding if needed */
914 | if (directory_table_size % 2 == 1)
915 | iso9660_cp2heap(&rr_directory_table, &zero, 1, &directory_table_size);
916 |
917 | /* Write size of second record */
918 | rr_save_size = directory_table_size - rr_save_size;
919 | iso9660_cp2heap(&rr_save_ptr, &rr_save_size, sizeof(uint8_t), NULL);
920 | }
921 | /* Add SUSP and RRIP data for regular entry */
922 | else if (type == RRIP) {
923 | uint8_t rest = 0;
924 | RR[4] = 0;
925 |
926 | if (S_ISLNK(rr_file_list->st_mode))
927 | RR[4] |= 1 << 2;
928 | if ((init_fields & rrip_PX) != 0)
929 | RR[4] |= 1 << 0; // PX record in use
930 | if ((init_fields & rrip_TF) != 0)
931 | RR[4] |= 1 << 7; // TF record in use
932 | if ((init_fields & rrip_NM) != 0) {
933 | RR[4] |= 1 << 3; // NM record in use
934 |
935 | memset(NM + NM_HEADER_SIZE, 0, BLOCK_SIZE - NM_HEADER_SIZE);
936 |
937 | /* Prepare for another possible NM entry */
938 | if (rr_file_list->name_short_len >= 250) {
939 | rest = rr_file_list->name_short_len - 250;
940 | rr_file_list->name_short_len = 250;
941 | }
942 |
943 | NM[2] = NM_HEADER_SIZE + rr_file_list->name_short_len;
944 | strncpy((char *)NM + NM_HEADER_SIZE, rr_file_list->name_short, rr_file_list->name_short_len);
945 | }
946 |
947 | if ((init_fields & rrip_RR) != 0)
948 | iso9660_cp2heap(&rr_directory_table, RR, sizeof(RR), &directory_table_size);
949 |
950 | /* Set flag that NM entry will continue at next NM entry */
951 | if ((init_fields & rrip_NM) != 0) {
952 | if (rest != 0)
953 | NM[4] = 1;
954 |
955 | iso9660_cp2heap(&rr_directory_table, NM, rr_file_list->name_short_len + NM_HEADER_SIZE, &directory_table_size);
956 |
957 | /* Add second NM entry if needed */
958 | if (rest != 0) {
959 | memset(NM + 4, 0, BLOCK_SIZE - 4);
960 | NM[2] = NM_HEADER_SIZE + rest;
961 |
962 | strncpy((char *)NM + 5, rr_file_list->name_short + rr_file_list->name_short_len, rest);
963 |
964 | iso9660_cp2heap(&rr_directory_table, NM, rest + NM_HEADER_SIZE, &directory_table_size);
965 | }
966 | }
967 |
968 | /* Write PX record */
969 | if ((init_fields & rrip_PX) != 0) {
970 | iso9660_cp2heap(&rr_directory_table, PX, 4, &directory_table_size);
971 | iso9660_cp2heap(&rr_directory_table, &mode, sizeof(mode), &directory_table_size);
972 | iso9660_cp2heap(&rr_directory_table, &nlinks, sizeof(nlinks), &directory_table_size);
973 | iso9660_cp2heap(&rr_directory_table, &uid, sizeof(uid), &directory_table_size);
974 | iso9660_cp2heap(&rr_directory_table, &gid, sizeof(gid), &directory_table_size);
975 | iso9660_cp2heap(&rr_directory_table, &ino, sizeof(ino), &directory_table_size);
976 | }
977 |
978 | /* Write SL record */
979 | if (S_ISLNK(rr_file_list->st_mode)) {
980 | SL_create(rr_file_list->name_path, &SL, &SL_len);
981 |
982 | iso9660_cp2heap(&rr_directory_table, SL, SL_len, &directory_table_size);
983 |
984 | free(SL);
985 | }
986 |
987 | /* Write TF record */
988 | if ((init_fields & rrip_TF) != 0) {
989 | iso9660_cp2heap(&rr_directory_table, TF, 5, &directory_table_size);
990 | iso9660_cp2heap(&rr_directory_table, mdate_time, sizeof(mdate_time), &directory_table_size); // Modify date/time
991 | iso9660_cp2heap(&rr_directory_table, adate_time, sizeof(adate_time), &directory_table_size); // Access date/time
992 | iso9660_cp2heap(&rr_directory_table, cdate_time, sizeof(cdate_time), &directory_table_size); // status change date/time
993 | }
994 |
995 | if (directory_table_size % 2 != 0)
996 | iso9660_cp2heap(&rr_directory_table, &zero, 1, &directory_table_size);
997 |
998 | iso9660_cp2heap(&rr_directory_table_start, &directory_table_size, sizeof(uint8_t), NULL);
999 | }
1000 |
1001 | *directory_table_output = rr_directory_table;
1002 |
1003 | return directory_table_size;
1004 | }
1005 |
1006 | static int construct_iso9660_record(void **output, struct iso9660_data_t data, uint32_t *size) {
1007 |
1008 | iso9660_cp2heap(output, &zero, sizeof(uint8_t), size); // Lenght of whole entry will be added at the end
1009 | iso9660_cp2heap(output, &data.ext_attr_record, sizeof(uint8_t), size); // Ext. attr. record
1010 | iso9660_cp2heap(output, &data.LBA, sizeof(uint64_t), size); // LBA
1011 | iso9660_cp2heap(output, &data.data_len, sizeof(uint64_t), size); // Size of file/dir
1012 | iso9660_cp2heap(output, &data.mdate_time, sizeof(data.mdate_time), size); // Recording date/time
1013 | iso9660_cp2heap(output, &data.flags, sizeof(uint8_t), size); // Flags
1014 | iso9660_cp2heap(output, &zero, sizeof(uint8_t), size); // Interleaving
1015 | iso9660_cp2heap(output, &zero, sizeof(uint8_t), size); // Interleaving
1016 | iso9660_cp2heap(output, &data.volume_seq_number, sizeof(uint32_t), size); // Volume sequence number
1017 | iso9660_cp2heap(output, &data.name_len, sizeof(uint8_t), size); // File name len
1018 |
1019 | return E_OK;
1020 | }
1021 |
1022 | static int blocks_count(int size) {
1023 | int blocks = 0;
1024 |
1025 | if (size % BLOCK_SIZE == 0)
1026 | blocks = size / BLOCK_SIZE;
1027 | else
1028 | blocks = (size / BLOCK_SIZE) + 1;
1029 |
1030 | if (blocks == 0)
1031 | blocks = 1;
1032 |
1033 | return blocks;
1034 | }
1035 |
1036 | static uint64_t get_int32_LSB_MSB(uint64_t input) {
1037 | return input + __bswap_64(input);
1038 | }
1039 |
1040 | static uint32_t get_int16_LSB_MSB(uint32_t input) {
1041 | return input + __bswap_32(input);
1042 | }
1043 |
1044 | static int int2str(uint16_t input, char **output) {
1045 | char *rr_output = *output;
1046 | uint8_t result = 0;
1047 | uint16_t i = 0;
1048 | const uint8_t offset = 0x30;
1049 | const uint8_t divide = 10;
1050 | uint16_t max_val;
1051 |
1052 | if (input < 100)
1053 | max_val = 99;
1054 | else
1055 | max_val = 9999;
1056 |
1057 | if (input > max_val || input < 0)
1058 | return -1;
1059 |
1060 | for (i = (max_val + 1) / divide ; i != 1; i /= divide) {
1061 | result = (input / i) + offset;
1062 | *rr_output++ = result;
1063 |
1064 | input -= (i * (result - offset));
1065 | }
1066 |
1067 | *rr_output = (input % divide) + offset;
1068 |
1069 | *output = rr_output + 1;
1070 | return 0;
1071 | }
1072 |
1073 | static int format_header_date(time_t time_now, char *output) {
1074 | char *rr_output = output;
1075 | struct tm *ts = NULL;
1076 | ts = localtime(&time_now);
1077 |
1078 | if (int2str(ts->tm_year + 1900, &rr_output) != E_OK) // 4 bytes - Year
1079 | return E_CONV;
1080 |
1081 | if (int2str(ts->tm_mon + 1, &rr_output) != E_OK) // 2 bytes - Month
1082 | return E_CONV;
1083 |
1084 | if (int2str(ts->tm_mday, &rr_output) != E_OK) // 2 bytes - Day
1085 | return E_CONV;
1086 |
1087 | if (int2str(ts->tm_hour, &rr_output) != E_OK) // 2 bytes - Hour
1088 | return E_CONV;
1089 |
1090 | if (int2str(ts->tm_min, &rr_output) != E_OK) // 2 bytes - Min
1091 | return E_CONV;
1092 |
1093 | if (int2str(ts->tm_sec, &rr_output) != E_OK) // 2 bytes - Sec
1094 | return E_CONV;
1095 |
1096 | if (int2str(00, &rr_output) != E_OK) // 2 bytes - Hundredths of a second from 0 to 99
1097 | return E_CONV;
1098 |
1099 | *rr_output = ts->tm_gmtoff / 60 / 15; // 1 byte - Timezone offset from GMT in 15 minute intervals
1100 |
1101 | return E_OK;
1102 | }
1103 |
1104 | static void str_var_prepare(char *input, char fill_char, size_t input_size) {
1105 | size_t input_len = strlen(input);
1106 |
1107 | input += input_len;
1108 | memset(input, fill_char, input_size - input_len);
1109 | }
1110 |
1111 | static int init_RRIP(void) {
1112 | size_t rr_size = 0;
1113 | int header_size = 0;
1114 | char ER_text[] = "RRIP_1991ATHE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM \
1115 | SEMANTICSPLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY \
1116 | VOLUME DESCRIPTOR FOR CONTACT INFORMATION.";
1117 |
1118 | rr_size = sizeof(SP);
1119 | memset(SP, 0, rr_size);
1120 | SP[0] = 'S';
1121 | SP[1] = 'P';
1122 | SP[2] = rr_size;
1123 | SP[3] = 1; // SUSP Version
1124 | SP[4] = 0xBE; // Check byte
1125 | SP[5] = 0xEF; // Check byte
1126 | SP[6] = 0; // Len skip
1127 |
1128 | rr_size = sizeof(CE);
1129 | memset(CE, 0, rr_size);
1130 | CE[0] = 'C';
1131 | CE[1] = 'E';
1132 | CE[2] = rr_size;
1133 | CE[3] = 1; // SUSP Version
1134 |
1135 | rr_size = sizeof(ER);
1136 | memset(ER, 0, rr_size);
1137 | ER[0] = 'E';
1138 | ER[1] = 'R';
1139 | ER[2] = rr_size; // Size
1140 | ER[3] = 1; // SUSP Version
1141 | ER[4] = 0x0A; // Len ID
1142 | ER[5] = 0x54; // Len descriptor
1143 | ER[6] = 0x87; // Len source
1144 | ER[7] = 0x01; // Extension version
1145 |
1146 | strcat((char *)ER, ER_text);
1147 |
1148 | if ((init_fields & rrip_RR) != 0) {
1149 | rr_size = sizeof(RR);
1150 | memset(RR, 0, rr_size);
1151 | RR[0] = 'R';
1152 | RR[1] = 'R';
1153 | RR[2] = rr_size;
1154 | RR[3] = 1;
1155 | RR[4] = 0;
1156 | header_size += rr_size;
1157 | }
1158 |
1159 | if ((init_fields & rrip_PX) != 0) {
1160 | rr_size = sizeof(PX);
1161 | memset(PX, 0, rr_size);
1162 | PX[0] = 'P';
1163 | PX[1] = 'X';
1164 | PX[2] = rr_size;
1165 | PX[3] = 1;
1166 | header_size += rr_size;
1167 | }
1168 |
1169 | if ((init_fields & rrip_TF) != 0) {
1170 | rr_size = sizeof(TF);
1171 | memset(TF, 0, rr_size);
1172 | TF[0] = 'T';
1173 | TF[1] = 'F';
1174 | TF[2] = rr_size;
1175 | TF[3] = 1;
1176 | TF[4] = 0x0E; // Record MODIFY, ACCESS and CREATION
1177 | header_size += rr_size;
1178 | }
1179 |
1180 | if ((init_fields & rrip_NM) != 0) {
1181 | rr_size = BLOCK_SIZE;
1182 | NM = (unsigned char*) malloc(rr_size);
1183 | memset(NM, 0, rr_size);
1184 | NM[0] = 'N';
1185 | NM[1] = 'M';
1186 | NM[2] = 0;
1187 | NM[3] = 1;
1188 | NM[4] = 0;
1189 | }
1190 |
1191 | return header_size;
1192 | }
1193 |
1194 | static void shift_mem(void *var, int offset, int ammount) {
1195 | memmove(var + offset, var, ammount);
1196 | memset(var, 0, offset);
1197 | }
1198 |
1199 | static uint8_t set_terminator_len(mode_t mode) {
1200 | return (S_ISDIR(mode)) ? 0 : 2;
1201 | }
1202 |
--------------------------------------------------------------------------------
/lib/list.c:
--------------------------------------------------------------------------------
1 | /*
2 | * list.c
3 | *
4 | * Version: 0.2.2
5 | *
6 | * Release date: 28.2.2017
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "list.h"
29 | #include
30 | #include
31 |
32 | int list_create(const char *dirname, struct file_list_t **flist, struct ISO_data_t *ISO_data) {
33 | FILE *read_test = NULL;
34 | DIR *cur_dir = NULL;
35 | struct dirent *dir_content = NULL;
36 | struct stat dir_cont_stat;
37 | char path[MAX_DIR_STR_LEN];
38 | static int parent_id = 1;
39 | static int dir_id = 1;
40 | static int level = 0;
41 | int rr_dir = 0;
42 | int path_len = 0;
43 | int rv = E_OK;
44 | bool_t rock_ridge_on = FALSE;
45 |
46 | if (option_on_off(ISO_data->options, OPT_R) == E_OK)
47 | rock_ridge_on = TRUE;
48 |
49 | /* Record/increase current directory level */
50 | level++;
51 |
52 | /* Fail if some (sub) directory is unreadable */
53 | if ( (cur_dir = opendir(dirname)) == NULL ) {
54 | printf("Error: list_create(): Opening directory [%s] failed: %s\n", dirname, strerror(errno));
55 | rv = E_READFAIL;
56 | goto cleanup;
57 | }
58 |
59 | /* Read whole directory content */
60 | while ( (dir_content = readdir(cur_dir)) != NULL && (rv == 0) ) {
61 | if ( (strcmp(dir_content->d_name, "..") == 0) || (strcmp(dir_content->d_name, ".") == 0) )
62 | continue;
63 |
64 | /* Stop if number of characters in path reaches the limit */
65 | if ( (path_len = snprintf(path, MAX_DIR_STR_LEN, "%s/%s", dirname, dir_content->d_name)) > MAX_DIR_STR_LEN ) {
66 | printf("Error: list_create(): Max path lenght limit[%d] reached [%s/%s]\n", MAX_DIR_STR_LEN, dirname, dir_content->d_name);
67 | rv = E_FILELIMIT;
68 | }
69 |
70 | /* Fill structure with directory data */
71 | else {
72 | strncpy((*flist)->name_path, path, path_len + 1); // Copy trailing null
73 | strncpy((*flist)->name_short, dir_content->d_name, MAX_DIR_STR_LEN - 1);
74 |
75 | /* convert filename to 8.3 format */
76 | (*flist)->name_conv_len = filename_convert_name((*flist)->name_short, (*flist)->name_conv, CONV_ISO9660);
77 |
78 | lstat(path, &dir_cont_stat);
79 |
80 | /* Don't do read test on symlinks as they don't need to have any real valid content */
81 | if (S_ISLNK(dir_cont_stat.st_mode) && rock_ridge_on == TRUE) {
82 | memset((*flist)->name_path, 0, MAX_DIR_STR_LEN);
83 | if (readlink(path, (*flist)->name_path, MAX_DIR_STR_LEN - 1) == -1) {
84 | printf("Error: list_create(): Failed to read link [%s]: %s\n", path, strerror(errno));
85 | goto cleanup;
86 | }
87 | }
88 | /* Symlinks will be ignored if RRIP is not in use */
89 | else if (S_ISLNK(dir_cont_stat.st_mode) && rock_ridge_on == FALSE) {
90 | printf("Warning: list_create(): Symlink will be ignored: [%s]\n", path);
91 | memset(*flist, 0, sizeof(struct file_list_t));
92 | continue;
93 | }
94 | /* Do a read test on files and dirs */
95 | else {
96 | stat(path, &dir_cont_stat);
97 | if ((read_test = fopen(path, "r")) == NULL) {
98 | printf("Error: list_create(): Failed to open [%s]: %s\n", path, strerror(errno));
99 | rv = E_READFAIL;
100 | goto cleanup;
101 | }
102 | else
103 | fclose(read_test);
104 | }
105 |
106 | if (S_ISDIR(dir_cont_stat.st_mode))
107 | dir_id++;
108 |
109 | (*flist)->name_short_len = strlen((*flist)->name_short);
110 | (*flist)->size = dir_cont_stat.st_size;
111 | (*flist)->st_mode = dir_cont_stat.st_mode;
112 | (*flist)->st_nlink = dir_cont_stat.st_nlink;
113 | (*flist)->st_uid = dir_cont_stat.st_uid;
114 | (*flist)->st_gid = dir_cont_stat.st_gid;
115 | (*flist)->st_ino = dir_cont_stat.st_ino;
116 | (*flist)->mtime = dir_cont_stat.st_mtime;
117 | (*flist)->atime = dir_cont_stat.st_atime;
118 | (*flist)->ctime = dir_cont_stat.st_ctime;
119 | (*flist)->dir_id = dir_id;
120 | (*flist)->parent_id = parent_id;
121 | (*flist)->level = level;
122 | (*flist)->next = (struct file_list_t*) malloc(sizeof(struct file_list_t));
123 | (*flist) = (*flist)->next;
124 |
125 | memset(*flist, 0, sizeof(struct file_list_t));
126 | }
127 |
128 | /* Recursion to child directory */
129 | if ( S_ISDIR(dir_cont_stat.st_mode) && (rv == E_OK) ) {
130 | rr_dir = parent_id;
131 | parent_id = dir_id;
132 |
133 | rv = list_create(path, flist, ISO_data);
134 |
135 | parent_id = rr_dir;
136 | ISO_data->dir_count++;
137 | }
138 | }
139 |
140 | cleanup:
141 | closedir(cur_dir);
142 | level--;
143 |
144 | return rv;
145 | }
146 |
147 | void list_clean(struct file_list_t *list_to_clean) {
148 | struct file_list_t *curr = NULL;
149 | struct file_list_t *head = NULL;
150 |
151 | curr = list_to_clean->next;
152 |
153 | while (curr != NULL) {
154 | head = curr->next;
155 | free(curr);
156 | curr = head;
157 | }
158 |
159 | free(list_to_clean);
160 | }
161 |
162 | struct file_list_t *list_search_name(struct file_list_t *file_list, char *needle) {
163 | struct file_list_t *rv = NULL;
164 | size_t needle_len = strlen(needle);
165 |
166 | while(file_list->next != NULL) {
167 | if (S_ISDIR(file_list->st_mode)) {
168 | file_list = file_list->next;
169 | continue;
170 | }
171 | else {
172 | if (strncmp(file_list->name_path, needle, needle_len) == 0) {
173 | rv = file_list;
174 | break;
175 | }
176 | else
177 | file_list = file_list->next;
178 | }
179 | }
180 |
181 | return rv;
182 | }
183 |
--------------------------------------------------------------------------------
/lib/write_files.c:
--------------------------------------------------------------------------------
1 | /*
2 | * write_files.c
3 | *
4 | * Version: 0.2.0
5 | *
6 | * Release date: 13.11.2015
7 | *
8 | * Copyright 2015 Vladimir (sodoma) Gozora
9 | *
10 | * This program is free software; you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation; either version 2 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with this program; if not, write to the Free Software
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 | * MA 02110-1301, USA.
24 | *
25 | *
26 | */
27 |
28 | #include "write_files.h"
29 |
30 | int write_files(struct file_list_t *file_list, FILE *dest) {
31 | struct file_list_t *rr_file_list = file_list;
32 | FILE *source_file = NULL;
33 | char buffer[BLOCK_SIZE];
34 | size_t bytes_read = 0;
35 | int mod = 0;
36 | memset(buffer, 0, sizeof(buffer));
37 |
38 | while(rr_file_list->next != NULL) {
39 | /* Skip directories and symlinks */
40 | if (S_ISDIR(rr_file_list->st_mode) || S_ISLNK(rr_file_list->st_mode)) {
41 | rr_file_list = rr_file_list->next;
42 | continue;
43 | }
44 |
45 | fseek(dest, rr_file_list->LBA * BLOCK_SIZE, SEEK_SET);
46 |
47 | source_file = fopen(rr_file_list->name_path, "r");
48 | while(feof(source_file) == 0) {
49 | bytes_read = fread(buffer, 1, sizeof(buffer), source_file);
50 | if (fwrite(buffer, 1, bytes_read, dest) != bytes_read) {
51 | perror("Error: write_files()");
52 | fclose(source_file);
53 | return E_IO;
54 | }
55 | }
56 |
57 | memset(buffer, 0, sizeof(buffer));
58 | /* Pad rest of the block */
59 | if ((mod = rr_file_list->size % BLOCK_SIZE) != 0) {
60 | if (fwrite(buffer, 1, BLOCK_SIZE - mod, dest) != BLOCK_SIZE - mod) {
61 | perror("Error: pad()");
62 | return E_IO;
63 | }
64 | }
65 |
66 | /* If file is zero size write BLOCK_SIZE of zeros */
67 | if (rr_file_list->size == 0)
68 | if (fwrite(buffer, 1, BLOCK_SIZE, dest) != BLOCK_SIZE) {
69 | perror("Error: pad()");
70 | return E_IO;
71 | }
72 |
73 | fflush(dest);
74 |
75 | fclose(source_file);
76 |
77 | rr_file_list = rr_file_list->next;
78 | }
79 |
80 | return E_OK;
81 | }
82 |
--------------------------------------------------------------------------------
/man/man1/ebiso.1.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gozora/ebiso/ebd99d277820aeab9d6a2e8bac3978a1b6440ce1/man/man1/ebiso.1.gz
--------------------------------------------------------------------------------
/packaging/ebiso.spec:
--------------------------------------------------------------------------------
1 | #
2 | # spec file for package ebiso
3 | #
4 | # Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
5 | #
6 | # All modifications and additions to the file contributed by third parties
7 | # remain the property of their copyright owners, unless otherwise agreed
8 | # upon. The license for this file, and modifications and additions to the
9 | # file, is the same license as for the pristine package itself (unless the
10 | # license for the pristine package is not an Open Source License, in which
11 | # case the license is the MIT License). An "Open Source License" is a
12 | # license that conforms to the Open Source Definition (Version 1.9)
13 | # published by the Open Source Initiative.
14 |
15 | # Please submit bugfixes or comments via http://bugs.opensuse.org/
16 | #
17 |
18 | Name: ebiso
19 | Version: 0.2.7
20 | Release: 0
21 | Summary: UEFI bootable ISO image creator for Relax-and-Recover
22 | License: GPL-3.0
23 | Group: Productivity/Archiving/Backup
24 | # Refer to http://license.opensuse.org/
25 | # for the list of known licences and their exact spelling:
26 | # ebiso is only used by rear to make UEFI bootable ISO images
27 | # accordingly ebiso is in the same RPM group as rear:
28 | Url: https://gitlab.com/gozora/ebiso
29 | Source0: https://gitlab.com/gozora/ebiso/-/archive/%{version}/ebiso-%{version}.tar.gz#/%{name}-%{version}.tar.gz
30 | # Supplements is a reverse "Recommends" which means
31 | # (cf. https://tr.opensuse.org/Libzypp/Dependencies):
32 | # ebiso should be be installed if rear is is provided by an installed package.
33 | # In particular ebiso should be be installed if rear is (to be) installed.
34 | # The dependency resolver will do a best-try approach to install ebiso.
35 | # If ebiso cannot be installed, installing ebiso is silently skipped.
36 | # Also uninstalling ebiso is (silently) accepted.
37 | # The reverse "Recommends" is used because ebiso is only available on x86_64
38 | # so that a "Recommends: ebiso" in rear.spec could be often uninstallable.
39 | # In contrast "Supplements: rear" in ebiso.spec can be usually fulfilled:
40 | %if 0%{?centos} != 6 && 0%{?centos} != 7
41 | Supplements: rear
42 | %endif
43 | BuildRoot: %{_tmppath}/%{name}-%{version}-build
44 | # Enable building only on architectures which support UEFI
45 | ExclusiveArch: x86_64
46 |
47 | %description
48 | ebiso is needed by Relax-and-Recover (abbreviated ReaR)
49 | to create bootable ISO images with enabled UEFI boot
50 | on 64-bit x86_64 architecture.
51 |
52 | ebiso only works for systems with UEFI boot.
53 | ebiso cannot create legacy bootable ISOs.
54 |
55 | See project pages at https://gitlab.com/gozora/ebiso
56 |
57 | %prep
58 | %setup -q
59 |
60 | %build
61 | # Setting our preferred architecture-specific flags for the compiler and linker:
62 | export CFLAGS="%{optflags}"
63 | # Do not strip installed binaries as this would prevent -debuginfo package
64 | # from being created
65 | sed -i "s|strip|/bin/true|g" Makefile
66 | make %{?_smp_mflags}
67 |
68 | %install
69 | make %{?_smp_mflags} DESTDIR=%{buildroot} install
70 |
71 | %files
72 | %defattr(-,root,root)
73 | %{_bindir}/ebiso
74 | %{_mandir}/man1/ebiso.1%{ext_man}
75 |
76 | %changelog
77 | * Wed Jun 10 2020 Vladimir Gozora - 0.2.7-%{release}
78 | Workaround for building with gcc-10
79 | * Tue Feb 28 2017 Vladimir Gozora - 0.2.5-%{release}
80 | Corrected segfault wiht XFS ftype=0
81 | * Sun Dec 13 2015 Vladimir Gozora - 0.2.1-%{release}
82 | Full symbolic link support
83 | * Tue Oct 27 2015 Vladimir Gozora - 0.1.4-%{release}
84 | Added man pages to package
85 | * Wed Oct 21 2015 Gratien D'haese - 0.1.1-%{release}
86 | Rewrote original spec file from Vladimir
87 |
--------------------------------------------------------------------------------