1 /* $NetBSD: cd9660_write.c,v 1.17 2013/10/19 17:16:37 christos Exp $ */
4 * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
5 * Perez-Rathke and Ram Vedam. All rights reserved.
7 * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
8 * Alan Perez-Rathke and Ram Vedam.
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
21 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
25 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 #include "iso9660_rrip.h"
38 #include <sys/cdefs.h>
39 #if defined(__RCSID) && !defined(__lint)
40 __RCSID("$NetBSD: cd9660_write.c,v 1.17 2013/10/19 17:16:37 christos Exp $");
45 static int cd9660_write_volume_descriptors(iso9660_disk
*, FILE *);
46 static int cd9660_write_path_table(iso9660_disk
*, FILE *, off_t
, int);
47 static int cd9660_write_path_tables(iso9660_disk
*, FILE *);
48 static int cd9660_write_file(iso9660_disk
*, FILE *, cd9660node
*);
49 static int cd9660_write_filedata(iso9660_disk
*, FILE *, off_t
,
50 const unsigned char *, int);
52 static int cd9660_write_buffered(FILE *, off_t
, int, const unsigned char *);
54 static void cd9660_write_rr(iso9660_disk
*, FILE *, cd9660node
*, off_t
, off_t
);
58 * Writes the entire image
59 * @param const char* The filename for the image
60 * @returns int 1 on success, 0 on failure
63 cd9660_write_image(iso9660_disk
*diskStructure
, const char* image
)
67 char buf
[CD9660_SECTOR_SIZE
];
69 if ((fd
= fopen(image
, "w+")) == NULL
) {
70 err(EXIT_FAILURE
, "%s: Can't open `%s' for writing", __func__
,
74 if (diskStructure
->verbose_level
> 0)
75 printf("Writing image\n");
77 if (diskStructure
->has_generic_bootimage
) {
78 status
= cd9660_copy_file(diskStructure
, fd
, 0,
79 diskStructure
->generic_bootimage
);
81 warnx("%s: Error writing generic boot image",
83 goto cleanup_bad_image
;
87 /* Write the volume descriptors */
88 status
= cd9660_write_volume_descriptors(diskStructure
, fd
);
90 warnx("%s: Error writing volume descriptors to image",
92 goto cleanup_bad_image
;
95 if (diskStructure
->verbose_level
> 0)
96 printf("Volume descriptors written\n");
99 * Write the path tables: there are actually four, but right
100 * now we are only concearned with two.
102 status
= cd9660_write_path_tables(diskStructure
, fd
);
104 warnx("%s: Error writing path tables to image", __func__
);
105 goto cleanup_bad_image
;
108 if (diskStructure
->verbose_level
> 0)
109 printf("Path tables written\n");
111 /* Write the directories and files */
112 status
= cd9660_write_file(diskStructure
, fd
, diskStructure
->rootNode
);
114 warnx("%s: Error writing files to image", __func__
);
115 goto cleanup_bad_image
;
118 if (diskStructure
->is_bootable
) {
119 cd9660_write_boot(diskStructure
, fd
);
122 /* Write padding bits. This is temporary */
123 memset(buf
, 0, CD9660_SECTOR_SIZE
);
124 cd9660_write_filedata(diskStructure
, fd
,
125 diskStructure
->totalSectors
- 1, buf
, 1);
127 if (diskStructure
->verbose_level
> 0)
128 printf("Files written\n");
131 if (diskStructure
->verbose_level
> 0)
132 printf("Image closed\n");
137 if (!diskStructure
->keep_bad_images
)
139 if (diskStructure
->verbose_level
> 0)
140 printf("Bad image cleaned up\n");
145 cd9660_write_volume_descriptors(iso9660_disk
*diskStructure
, FILE *fd
)
147 volume_descriptor
*vd_temp
= diskStructure
->firstVolumeDescriptor
;
148 while (vd_temp
!= NULL
) {
149 cd9660_write_filedata(diskStructure
, fd
, vd_temp
->sector
,
150 vd_temp
->volumeDescriptorData
, 1);
151 vd_temp
= vd_temp
->next
;
157 * Write out an individual path table
158 * Used just to keep redundant code to a minimum
159 * @param FILE *fd Valid file pointer
160 * @param int Sector to start writing path table to
161 * @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
162 * @returns int 1 on success, 0 on failure
165 cd9660_write_path_table(iso9660_disk
*diskStructure
, FILE *fd
, off_t sector
,
168 int path_table_sectors
= CD9660_BLOCKS(diskStructure
->sectorSize
,
169 diskStructure
->pathTableLength
);
170 unsigned char *buffer
;
171 unsigned char *buffer_head
;
173 path_table_entry temp_entry
;
176 buffer
= ecalloc(path_table_sectors
, diskStructure
->sectorSize
);
177 buffer_head
= buffer
;
179 ptcur
= diskStructure
->rootNode
;
181 while (ptcur
!= NULL
) {
182 memset(&temp_entry
, 0, sizeof(path_table_entry
));
183 temp_entry
.length
[0] = ptcur
->isoDirRecord
->name_len
[0];
184 temp_entry
.extended_attribute_length
[0] =
185 ptcur
->isoDirRecord
->ext_attr_length
[0];
186 memcpy(temp_entry
.name
, ptcur
->isoDirRecord
->name
,
187 temp_entry
.length
[0] + 1);
190 len
= temp_entry
.length
[0] + 8 + (temp_entry
.length
[0] & 0x01);
192 /* todo: function pointers instead */
193 if (mode
== LITTLE_ENDIAN
) {
194 cd9660_731(ptcur
->fileDataSector
,
195 temp_entry
.first_sector
);
196 cd9660_721((ptcur
->parent
== NULL
?
197 1 : ptcur
->parent
->ptnumber
),
198 temp_entry
.parent_number
);
200 cd9660_732(ptcur
->fileDataSector
,
201 temp_entry
.first_sector
);
202 cd9660_722((ptcur
->parent
== NULL
?
203 1 : ptcur
->parent
->ptnumber
),
204 temp_entry
.parent_number
);
208 memcpy(buffer
, &temp_entry
, len
);
211 ptcur
= ptcur
->ptnext
;
214 return cd9660_write_filedata(diskStructure
, fd
, sector
, buffer_head
,
220 * Write out the path tables to disk
221 * Each file descriptor should be pointed to by the PVD, so we know which
222 * sector to copy them to. One thing to watch out for: the only path tables
223 * stored are in the endian mode that the application is compiled for. So,
224 * the first thing to do is write out that path table, then to write the one
225 * in the other endian mode requires to convert the endianness of each entry
226 * in the table. The best way to do this would be to create a temporary
227 * path_table_entry structure, then for each path table entry, copy it to
228 * the temporary entry, translate, then copy that to disk.
230 * @param FILE* Valid file descriptor
231 * @returns int 0 on failure, 1 on success
234 cd9660_write_path_tables(iso9660_disk
*diskStructure
, FILE *fd
)
236 if (cd9660_write_path_table(diskStructure
, fd
,
237 diskStructure
->primaryLittleEndianTableSector
, LITTLE_ENDIAN
) == 0)
240 if (cd9660_write_path_table(diskStructure
, fd
,
241 diskStructure
->primaryBigEndianTableSector
, BIG_ENDIAN
) == 0)
244 /* @TODO: handle remaining two path tables */
249 * Write a file to disk
250 * Writes a file, its directory record, and its data to disk
251 * This file is designed to be called RECURSIVELY, so initially call it
252 * with the root node. All of the records should store what sector the
253 * file goes in, so no computation should be necessary.
255 * @param int fd Valid file descriptor
256 * @param struct cd9660node* writenode Pointer to the file to be written
257 * @returns int 0 on failure, 1 on success
260 cd9660_write_file(iso9660_disk
*diskStructure
, FILE *fd
, cd9660node
*writenode
)
263 char *temp_file_name
;
265 off_t working_sector
;
266 int cur_sector_offset
;
267 iso_directory_record_cd9660 temp_record
;
271 /* Todo : clean up variables */
273 temp_file_name
= ecalloc(CD9660MAXPATH
+ 1, 1);
274 buf
= emalloc(diskStructure
->sectorSize
);
275 if ((writenode
->level
!= 0) &&
276 !(writenode
->node
->type
& S_IFDIR
)) {
277 fsinode
*inode
= writenode
->node
->inode
;
278 /* Only attempt to write unwritten files that have length. */
279 if ((inode
->flags
& FI_WRITTEN
) != 0) {
280 INODE_WARNX(("%s: skipping written inode %d", __func__
,
281 (int)inode
->st
.st_ino
));
282 } else if (writenode
->fileDataLength
> 0) {
283 INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32
,
284 __func__
, (int)inode
->st
.st_ino
, inode
->ino
));
285 inode
->flags
|= FI_WRITTEN
;
286 cd9660_compute_full_filename(writenode
,
288 ret
= cd9660_copy_file(diskStructure
, fd
,
289 writenode
->fileDataSector
, temp_file_name
);
295 * Here is a new revelation that ECMA didnt explain
296 * (at least not well).
297 * ALL . and .. records store the name "\0" and "\1"
298 * resepctively. So, for each directory, we have to
301 * This is where it gets kinda messy, since we have to
302 * be careful of sector boundaries
304 cur_sector_offset
= 0;
305 working_sector
= writenode
->fileDataSector
;
306 if (fseeko(fd
, working_sector
* diskStructure
->sectorSize
,
311 * Now loop over children, writing out their directory
312 * records - beware of sector boundaries
314 TAILQ_FOREACH(temp
, &writenode
->cn_children
, cn_next_child
) {
316 * Copy the temporary record and adjust its size
319 memcpy(&temp_record
, temp
->isoDirRecord
,
320 sizeof(iso_directory_record_cd9660
));
322 temp_record
.length
[0] =
323 cd9660_compute_record_size(diskStructure
, temp
);
325 if (temp_record
.length
[0] + cur_sector_offset
>=
326 diskStructure
->sectorSize
) {
327 cur_sector_offset
= 0;
330 /* Seek to the next sector. */
331 if (fseeko(fd
, working_sector
*
332 diskStructure
->sectorSize
, SEEK_SET
) == -1)
335 /* Write out the basic ISO directory record */
336 (void)fwrite(&temp_record
, 1,
337 temp
->isoDirRecord
->length
[0], fd
);
338 if (diskStructure
->rock_ridge_enabled
) {
339 cd9660_write_rr(diskStructure
, fd
, temp
,
340 cur_sector_offset
, working_sector
);
342 if (fseeko(fd
, working_sector
*
343 diskStructure
->sectorSize
+ cur_sector_offset
+
344 temp_record
.length
[0] - temp
->su_tail_size
,
347 if (temp
->su_tail_size
> 0)
348 fwrite(temp
->su_tail_data
, 1,
349 temp
->su_tail_size
, fd
);
351 warnx("%s: write error", __func__
);
354 cur_sector_offset
+= temp_record
.length
[0];
359 * Recurse on children.
361 TAILQ_FOREACH(temp
, &writenode
->cn_children
, cn_next_child
) {
362 if ((ret
= cd9660_write_file(diskStructure
, fd
, temp
))
369 free(temp_file_name
);
375 * Wrapper function to write a buffer (one sector) to disk.
376 * Seeks and writes the buffer.
377 * NOTE: You dont NEED to use this function, but it might make your
378 * life easier if you have to write things that align to a sector
379 * (such as volume descriptors).
381 * @param int fd Valid file descriptor
382 * @param int sector Sector number to write to
383 * @param const unsigned char* Buffer to write. This should be the
384 * size of a sector, and if only a portion
385 * is written, the rest should be set to 0.
388 cd9660_write_filedata(iso9660_disk
*diskStructure
, FILE *fd
, off_t sector
,
389 const unsigned char *buf
, int numsecs
)
396 if (fseeko(fd
, sector
* diskStructure
->sectorSize
, SEEK_SET
) == -1)
399 success
= fwrite(buf
, diskStructure
->sectorSize
* numsecs
, 1, fd
);
401 if (fseeko(fd
, curpos
, SEEK_SET
) == -1)
405 success
= diskStructure
->sectorSize
* numsecs
;
411 cd9660_write_buffered(FILE *fd
, off_t offset
, int buff_len
,
412 const unsigned char* buffer
)
414 static int working_sector
= -1;
415 static char buf
[CD9660_SECTOR_SIZE
];
422 cd9660_copy_file(iso9660_disk
*diskStructure
, FILE *fd
, off_t start_sector
,
423 const char *filename
)
427 off_t sector
= start_sector
;
428 int buf_size
= diskStructure
->sectorSize
;
431 buf
= emalloc(buf_size
);
432 if ((rf
= fopen(filename
, "rb")) == NULL
) {
433 warn("%s: cannot open %s", __func__
, filename
);
438 if (diskStructure
->verbose_level
> 1)
439 printf("Writing file: %s\n",filename
);
441 if (fseeko(fd
, start_sector
* diskStructure
->sectorSize
, SEEK_SET
) == -1)
445 bytes_read
= fread(buf
,1,buf_size
,rf
);
447 warn("%s: fread", __func__
);
453 fwrite(buf
,1,bytes_read
,fd
);
455 warn("%s: fwrite", __func__
);
469 cd9660_write_rr(iso9660_disk
*diskStructure
, FILE *fd
, cd9660node
*writenode
,
470 off_t offset
, off_t sector
)
473 struct ISO_SUSP_ATTRIBUTES
*myattr
;
475 offset
+= writenode
->isoDirRecord
->length
[0];
476 if (fseeko(fd
, sector
* diskStructure
->sectorSize
+ offset
, SEEK_SET
) ==
479 /* Offset now points at the end of the record */
480 TAILQ_FOREACH(myattr
, &writenode
->head
, rr_ll
) {
481 fwrite(&(myattr
->attr
), CD9660_SUSP_ENTRY_SIZE(myattr
), 1, fd
);
484 offset
+= CD9660_SUSP_ENTRY_SIZE(myattr
);
485 if (myattr
->last_in_suf
) {
487 * Point the offset to the start of this
490 if (fseeko(fd
, ((off_t
)diskStructure
->
491 susp_continuation_area_start_sector
*
492 diskStructure
->sectorSize
)
493 + writenode
->susp_entry_ce_start
,
502 * If we had to go to the continuation area, head back to
503 * where we should be.
506 if (fseeko(fd
, sector
* diskStructure
->sectorSize
+ offset
,