1*ec5d1d82Stsutsui /* $NetBSD: cd9660_write.c,v 1.18 2023/12/28 12:13:56 tsutsui Exp $ */
23550dc98Sfvdl
33550dc98Sfvdl /*
43550dc98Sfvdl * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
53550dc98Sfvdl * Perez-Rathke and Ram Vedam. All rights reserved.
63550dc98Sfvdl *
73550dc98Sfvdl * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
83550dc98Sfvdl * Alan Perez-Rathke and Ram Vedam.
93550dc98Sfvdl *
103550dc98Sfvdl * Redistribution and use in source and binary forms, with or
113550dc98Sfvdl * without modification, are permitted provided that the following
123550dc98Sfvdl * conditions are met:
133550dc98Sfvdl * 1. Redistributions of source code must retain the above copyright
143550dc98Sfvdl * notice, this list of conditions and the following disclaimer.
153550dc98Sfvdl * 2. Redistributions in binary form must reproduce the above
163550dc98Sfvdl * copyright notice, this list of conditions and the following
173550dc98Sfvdl * disclaimer in the documentation and/or other materials provided
183550dc98Sfvdl * with the distribution.
193550dc98Sfvdl *
203550dc98Sfvdl * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
213550dc98Sfvdl * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
223550dc98Sfvdl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
233550dc98Sfvdl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
243550dc98Sfvdl * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
253550dc98Sfvdl * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
263550dc98Sfvdl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
273550dc98Sfvdl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
283550dc98Sfvdl * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
293550dc98Sfvdl * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
303550dc98Sfvdl * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313550dc98Sfvdl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
323550dc98Sfvdl * OF SUCH DAMAGE.
333550dc98Sfvdl */
343550dc98Sfvdl
353550dc98Sfvdl #include "cd9660.h"
363550dc98Sfvdl #include "iso9660_rrip.h"
373550dc98Sfvdl
383550dc98Sfvdl #include <sys/cdefs.h>
393550dc98Sfvdl #if defined(__RCSID) && !defined(__lint)
40*ec5d1d82Stsutsui __RCSID("$NetBSD: cd9660_write.c,v 1.18 2023/12/28 12:13:56 tsutsui Exp $");
413550dc98Sfvdl #endif /* !__lint */
423550dc98Sfvdl
43e4989541Schristos #include <util.h>
44e4989541Schristos
45e4989541Schristos static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *);
46e4989541Schristos static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int);
47e4989541Schristos static int cd9660_write_path_tables(iso9660_disk *, FILE *);
48e4989541Schristos static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *);
49e4989541Schristos static int cd9660_write_filedata(iso9660_disk *, FILE *, off_t,
50e4989541Schristos const unsigned char *, int);
513550dc98Sfvdl #if 0
52203850f0Schristos static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
533550dc98Sfvdl #endif
54e4989541Schristos static void cd9660_write_rr(iso9660_disk *, FILE *, cd9660node *, off_t, off_t);
553550dc98Sfvdl
563550dc98Sfvdl /*
573550dc98Sfvdl * Write the image
583550dc98Sfvdl * Writes the entire image
593550dc98Sfvdl * @param const char* The filename for the image
603550dc98Sfvdl * @returns int 1 on success, 0 on failure
613550dc98Sfvdl */
623550dc98Sfvdl int
cd9660_write_image(iso9660_disk * diskStructure,const char * image)63e4989541Schristos cd9660_write_image(iso9660_disk *diskStructure, const char* image)
643550dc98Sfvdl {
653550dc98Sfvdl FILE *fd;
663550dc98Sfvdl int status;
67203850f0Schristos char buf[CD9660_SECTOR_SIZE];
683550dc98Sfvdl
69f334b70aSdyoung if ((fd = fopen(image, "w+")) == NULL) {
70f334b70aSdyoung err(EXIT_FAILURE, "%s: Can't open `%s' for writing", __func__,
71f334b70aSdyoung image);
72f334b70aSdyoung }
733550dc98Sfvdl
74e4989541Schristos if (diskStructure->verbose_level > 0)
753550dc98Sfvdl printf("Writing image\n");
763550dc98Sfvdl
77e4989541Schristos if (diskStructure->has_generic_bootimage) {
78e4989541Schristos status = cd9660_copy_file(diskStructure, fd, 0,
79e4989541Schristos diskStructure->generic_bootimage);
80989d6357Sskrll if (status == 0) {
81989d6357Sskrll warnx("%s: Error writing generic boot image",
82989d6357Sskrll __func__);
83989d6357Sskrll goto cleanup_bad_image;
84989d6357Sskrll }
85989d6357Sskrll }
86989d6357Sskrll
873550dc98Sfvdl /* Write the volume descriptors */
88e4989541Schristos status = cd9660_write_volume_descriptors(diskStructure, fd);
893550dc98Sfvdl if (status == 0) {
90f334b70aSdyoung warnx("%s: Error writing volume descriptors to image",
91f334b70aSdyoung __func__);
923550dc98Sfvdl goto cleanup_bad_image;
933550dc98Sfvdl }
943550dc98Sfvdl
95e4989541Schristos if (diskStructure->verbose_level > 0)
963550dc98Sfvdl printf("Volume descriptors written\n");
973550dc98Sfvdl
983550dc98Sfvdl /*
993550dc98Sfvdl * Write the path tables: there are actually four, but right
1003550dc98Sfvdl * now we are only concearned with two.
1013550dc98Sfvdl */
102e4989541Schristos status = cd9660_write_path_tables(diskStructure, fd);
1033550dc98Sfvdl if (status == 0) {
104f334b70aSdyoung warnx("%s: Error writing path tables to image", __func__);
1053550dc98Sfvdl goto cleanup_bad_image;
1063550dc98Sfvdl }
1073550dc98Sfvdl
108e4989541Schristos if (diskStructure->verbose_level > 0)
1093550dc98Sfvdl printf("Path tables written\n");
1103550dc98Sfvdl
1113550dc98Sfvdl /* Write the directories and files */
112e4989541Schristos status = cd9660_write_file(diskStructure, fd, diskStructure->rootNode);
1133550dc98Sfvdl if (status == 0) {
114f334b70aSdyoung warnx("%s: Error writing files to image", __func__);
1153550dc98Sfvdl goto cleanup_bad_image;
1163550dc98Sfvdl }
1173550dc98Sfvdl
118e4989541Schristos if (diskStructure->is_bootable) {
119e4989541Schristos cd9660_write_boot(diskStructure, fd);
1203550dc98Sfvdl }
1213550dc98Sfvdl
1223550dc98Sfvdl /* Write padding bits. This is temporary */
123203850f0Schristos memset(buf, 0, CD9660_SECTOR_SIZE);
124e4989541Schristos cd9660_write_filedata(diskStructure, fd,
125e4989541Schristos diskStructure->totalSectors - 1, buf, 1);
1263550dc98Sfvdl
127e4989541Schristos if (diskStructure->verbose_level > 0)
1283550dc98Sfvdl printf("Files written\n");
1293550dc98Sfvdl fclose(fd);
1303550dc98Sfvdl
131e4989541Schristos if (diskStructure->verbose_level > 0)
1323550dc98Sfvdl printf("Image closed\n");
1333550dc98Sfvdl return 1;
1343550dc98Sfvdl
1353550dc98Sfvdl cleanup_bad_image:
1363550dc98Sfvdl fclose(fd);
137e4989541Schristos if (!diskStructure->keep_bad_images)
1383550dc98Sfvdl unlink(image);
139e4989541Schristos if (diskStructure->verbose_level > 0)
1403550dc98Sfvdl printf("Bad image cleaned up\n");
1413550dc98Sfvdl return 0;
1423550dc98Sfvdl }
1433550dc98Sfvdl
1443550dc98Sfvdl static int
cd9660_write_volume_descriptors(iso9660_disk * diskStructure,FILE * fd)145e4989541Schristos cd9660_write_volume_descriptors(iso9660_disk *diskStructure, FILE *fd)
1463550dc98Sfvdl {
147e4989541Schristos volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor;
1483550dc98Sfvdl while (vd_temp != NULL) {
149e4989541Schristos cd9660_write_filedata(diskStructure, fd, vd_temp->sector,
1503550dc98Sfvdl vd_temp->volumeDescriptorData, 1);
1513550dc98Sfvdl vd_temp = vd_temp->next;
1523550dc98Sfvdl }
1533550dc98Sfvdl return 1;
1543550dc98Sfvdl }
1553550dc98Sfvdl
1563550dc98Sfvdl /*
1573550dc98Sfvdl * Write out an individual path table
1583550dc98Sfvdl * Used just to keep redundant code to a minimum
1593550dc98Sfvdl * @param FILE *fd Valid file pointer
1603550dc98Sfvdl * @param int Sector to start writing path table to
1613550dc98Sfvdl * @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
1623550dc98Sfvdl * @returns int 1 on success, 0 on failure
1633550dc98Sfvdl */
1643550dc98Sfvdl static int
cd9660_write_path_table(iso9660_disk * diskStructure,FILE * fd,off_t sector,int mode)165e4989541Schristos cd9660_write_path_table(iso9660_disk *diskStructure, FILE *fd, off_t sector,
166e4989541Schristos int mode)
1673550dc98Sfvdl {
168e4989541Schristos int path_table_sectors = CD9660_BLOCKS(diskStructure->sectorSize,
169e4989541Schristos diskStructure->pathTableLength);
1703550dc98Sfvdl unsigned char *buffer;
1713550dc98Sfvdl unsigned char *buffer_head;
1723550dc98Sfvdl int len;
1733550dc98Sfvdl path_table_entry temp_entry;
1743550dc98Sfvdl cd9660node *ptcur;
1753550dc98Sfvdl
176e4989541Schristos buffer = ecalloc(path_table_sectors, diskStructure->sectorSize);
1773550dc98Sfvdl buffer_head = buffer;
1783550dc98Sfvdl
179e4989541Schristos ptcur = diskStructure->rootNode;
1803550dc98Sfvdl
1813550dc98Sfvdl while (ptcur != NULL) {
1823550dc98Sfvdl memset(&temp_entry, 0, sizeof(path_table_entry));
1833550dc98Sfvdl temp_entry.length[0] = ptcur->isoDirRecord->name_len[0];
1843550dc98Sfvdl temp_entry.extended_attribute_length[0] =
1853550dc98Sfvdl ptcur->isoDirRecord->ext_attr_length[0];
1863550dc98Sfvdl memcpy(temp_entry.name, ptcur->isoDirRecord->name,
1873550dc98Sfvdl temp_entry.length[0] + 1);
1883550dc98Sfvdl
1893550dc98Sfvdl /* round up */
1903550dc98Sfvdl len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01);
1913550dc98Sfvdl
1923550dc98Sfvdl /* todo: function pointers instead */
1933550dc98Sfvdl if (mode == LITTLE_ENDIAN) {
1943550dc98Sfvdl cd9660_731(ptcur->fileDataSector,
1953550dc98Sfvdl temp_entry.first_sector);
1963550dc98Sfvdl cd9660_721((ptcur->parent == NULL ?
1973550dc98Sfvdl 1 : ptcur->parent->ptnumber),
1983550dc98Sfvdl temp_entry.parent_number);
1993550dc98Sfvdl } else {
2003550dc98Sfvdl cd9660_732(ptcur->fileDataSector,
2013550dc98Sfvdl temp_entry.first_sector);
2023550dc98Sfvdl cd9660_722((ptcur->parent == NULL ?
2033550dc98Sfvdl 1 : ptcur->parent->ptnumber),
2043550dc98Sfvdl temp_entry.parent_number);
2053550dc98Sfvdl }
2063550dc98Sfvdl
2073550dc98Sfvdl
2083550dc98Sfvdl memcpy(buffer, &temp_entry, len);
2093550dc98Sfvdl buffer += len;
2103550dc98Sfvdl
2113550dc98Sfvdl ptcur = ptcur->ptnext;
2123550dc98Sfvdl }
2133550dc98Sfvdl
214e4989541Schristos return cd9660_write_filedata(diskStructure, fd, sector, buffer_head,
2153550dc98Sfvdl path_table_sectors);
2163550dc98Sfvdl }
2173550dc98Sfvdl
2183550dc98Sfvdl
2193550dc98Sfvdl /*
2203550dc98Sfvdl * Write out the path tables to disk
2213550dc98Sfvdl * Each file descriptor should be pointed to by the PVD, so we know which
2223550dc98Sfvdl * sector to copy them to. One thing to watch out for: the only path tables
2233550dc98Sfvdl * stored are in the endian mode that the application is compiled for. So,
2243550dc98Sfvdl * the first thing to do is write out that path table, then to write the one
2253550dc98Sfvdl * in the other endian mode requires to convert the endianness of each entry
2263550dc98Sfvdl * in the table. The best way to do this would be to create a temporary
2273550dc98Sfvdl * path_table_entry structure, then for each path table entry, copy it to
2283550dc98Sfvdl * the temporary entry, translate, then copy that to disk.
2293550dc98Sfvdl *
2303550dc98Sfvdl * @param FILE* Valid file descriptor
2313550dc98Sfvdl * @returns int 0 on failure, 1 on success
2323550dc98Sfvdl */
2333550dc98Sfvdl static int
cd9660_write_path_tables(iso9660_disk * diskStructure,FILE * fd)234e4989541Schristos cd9660_write_path_tables(iso9660_disk *diskStructure, FILE *fd)
2353550dc98Sfvdl {
236e4989541Schristos if (cd9660_write_path_table(diskStructure, fd,
237e4989541Schristos diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0)
2383550dc98Sfvdl return 0;
2393550dc98Sfvdl
240e4989541Schristos if (cd9660_write_path_table(diskStructure, fd,
241e4989541Schristos diskStructure->primaryBigEndianTableSector, BIG_ENDIAN) == 0)
2423550dc98Sfvdl return 0;
2433550dc98Sfvdl
2443550dc98Sfvdl /* @TODO: handle remaining two path tables */
2453550dc98Sfvdl return 1;
2463550dc98Sfvdl }
2473550dc98Sfvdl
2483550dc98Sfvdl /*
2493550dc98Sfvdl * Write a file to disk
2503550dc98Sfvdl * Writes a file, its directory record, and its data to disk
2513550dc98Sfvdl * This file is designed to be called RECURSIVELY, so initially call it
2523550dc98Sfvdl * with the root node. All of the records should store what sector the
2533550dc98Sfvdl * file goes in, so no computation should be necessary.
2543550dc98Sfvdl *
2553550dc98Sfvdl * @param int fd Valid file descriptor
2563550dc98Sfvdl * @param struct cd9660node* writenode Pointer to the file to be written
2573550dc98Sfvdl * @returns int 0 on failure, 1 on success
2583550dc98Sfvdl */
2593550dc98Sfvdl static int
cd9660_write_file(iso9660_disk * diskStructure,FILE * fd,cd9660node * writenode)260e4989541Schristos cd9660_write_file(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode)
2613550dc98Sfvdl {
2623550dc98Sfvdl char *buf;
2633550dc98Sfvdl char *temp_file_name;
2643550dc98Sfvdl int ret;
265203850f0Schristos off_t working_sector;
2663550dc98Sfvdl int cur_sector_offset;
2673550dc98Sfvdl iso_directory_record_cd9660 temp_record;
2683550dc98Sfvdl cd9660node *temp;
269f8474b32Sbjh21 int rv = 0;
2703550dc98Sfvdl
2713550dc98Sfvdl /* Todo : clean up variables */
2723550dc98Sfvdl
273e4989541Schristos temp_file_name = ecalloc(CD9660MAXPATH + 1, 1);
274e4989541Schristos buf = emalloc(diskStructure->sectorSize);
2753550dc98Sfvdl if ((writenode->level != 0) &&
2763550dc98Sfvdl !(writenode->node->type & S_IFDIR)) {
2771da54664Sdyoung fsinode *inode = writenode->node->inode;
2781da54664Sdyoung /* Only attempt to write unwritten files that have length. */
2791da54664Sdyoung if ((inode->flags & FI_WRITTEN) != 0) {
2801da54664Sdyoung INODE_WARNX(("%s: skipping written inode %d", __func__,
2811da54664Sdyoung (int)inode->st.st_ino));
2821da54664Sdyoung } else if (writenode->fileDataLength > 0) {
2832fa0e02bSdyoung INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
2842fa0e02bSdyoung __func__, (int)inode->st.st_ino, inode->ino));
2851da54664Sdyoung inode->flags |= FI_WRITTEN;
2863550dc98Sfvdl cd9660_compute_full_filename(writenode,
287f1cc0951Schristos temp_file_name);
288e4989541Schristos ret = cd9660_copy_file(diskStructure, fd,
289e4989541Schristos writenode->fileDataSector, temp_file_name);
290be722641Schristos if (ret == 0)
291be722641Schristos goto out;
2923550dc98Sfvdl }
2933550dc98Sfvdl } else {
2943550dc98Sfvdl /*
2953550dc98Sfvdl * Here is a new revelation that ECMA didnt explain
2963550dc98Sfvdl * (at least not well).
2973550dc98Sfvdl * ALL . and .. records store the name "\0" and "\1"
2983550dc98Sfvdl * resepctively. So, for each directory, we have to
2993550dc98Sfvdl * make a new node.
3003550dc98Sfvdl *
3013550dc98Sfvdl * This is where it gets kinda messy, since we have to
3023550dc98Sfvdl * be careful of sector boundaries
3033550dc98Sfvdl */
3043550dc98Sfvdl cur_sector_offset = 0;
3053550dc98Sfvdl working_sector = writenode->fileDataSector;
306e4989541Schristos if (fseeko(fd, working_sector * diskStructure->sectorSize,
307203850f0Schristos SEEK_SET) == -1)
308*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
3093550dc98Sfvdl
3103550dc98Sfvdl /*
3113550dc98Sfvdl * Now loop over children, writing out their directory
3123550dc98Sfvdl * records - beware of sector boundaries
3133550dc98Sfvdl */
314689c61f6Sdyoung TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
3153550dc98Sfvdl /*
3163550dc98Sfvdl * Copy the temporary record and adjust its size
3173550dc98Sfvdl * if necessary
3183550dc98Sfvdl */
3193550dc98Sfvdl memcpy(&temp_record, temp->isoDirRecord,
3203550dc98Sfvdl sizeof(iso_directory_record_cd9660));
3213550dc98Sfvdl
3223550dc98Sfvdl temp_record.length[0] =
323e4989541Schristos cd9660_compute_record_size(diskStructure, temp);
3243550dc98Sfvdl
3253550dc98Sfvdl if (temp_record.length[0] + cur_sector_offset >=
326e4989541Schristos diskStructure->sectorSize) {
3273550dc98Sfvdl cur_sector_offset = 0;
3283550dc98Sfvdl working_sector++;
3293550dc98Sfvdl
3303550dc98Sfvdl /* Seek to the next sector. */
331203850f0Schristos if (fseeko(fd, working_sector *
332e4989541Schristos diskStructure->sectorSize, SEEK_SET) == -1)
333*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
3343550dc98Sfvdl }
335f8474b32Sbjh21 /* Write out the basic ISO directory record */
3360a77b69aSchristos (void)fwrite(&temp_record, 1,
337f8474b32Sbjh21 temp->isoDirRecord->length[0], fd);
338e4989541Schristos if (diskStructure->rock_ridge_enabled) {
339e4989541Schristos cd9660_write_rr(diskStructure, fd, temp,
3403550dc98Sfvdl cur_sector_offset, working_sector);
3413550dc98Sfvdl }
342203850f0Schristos if (fseeko(fd, working_sector *
343e4989541Schristos diskStructure->sectorSize + cur_sector_offset +
344203850f0Schristos temp_record.length[0] - temp->su_tail_size,
345203850f0Schristos SEEK_SET) == -1)
346*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
347f8474b32Sbjh21 if (temp->su_tail_size > 0)
348f8474b32Sbjh21 fwrite(temp->su_tail_data, 1,
349f8474b32Sbjh21 temp->su_tail_size, fd);
3503550dc98Sfvdl if (ferror(fd)) {
351f334b70aSdyoung warnx("%s: write error", __func__);
352be722641Schristos goto out;
3533550dc98Sfvdl }
3543550dc98Sfvdl cur_sector_offset += temp_record.length[0];
3553550dc98Sfvdl
3563550dc98Sfvdl }
3573550dc98Sfvdl
3583550dc98Sfvdl /*
359689c61f6Sdyoung * Recurse on children.
3603550dc98Sfvdl */
361689c61f6Sdyoung TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
362e4989541Schristos if ((ret = cd9660_write_file(diskStructure, fd, temp))
363e4989541Schristos == 0)
364be722641Schristos goto out;
365be722641Schristos }
366be722641Schristos }
367be722641Schristos rv = 1;
368be722641Schristos out:
3693550dc98Sfvdl free(temp_file_name);
370be722641Schristos free(buf);
371be722641Schristos return rv;
3723550dc98Sfvdl }
3733550dc98Sfvdl
3743550dc98Sfvdl /*
3753550dc98Sfvdl * Wrapper function to write a buffer (one sector) to disk.
3763550dc98Sfvdl * Seeks and writes the buffer.
3773550dc98Sfvdl * NOTE: You dont NEED to use this function, but it might make your
3783550dc98Sfvdl * life easier if you have to write things that align to a sector
3793550dc98Sfvdl * (such as volume descriptors).
3803550dc98Sfvdl *
3813550dc98Sfvdl * @param int fd Valid file descriptor
3823550dc98Sfvdl * @param int sector Sector number to write to
3833550dc98Sfvdl * @param const unsigned char* Buffer to write. This should be the
3843550dc98Sfvdl * size of a sector, and if only a portion
3853550dc98Sfvdl * is written, the rest should be set to 0.
3863550dc98Sfvdl */
3873550dc98Sfvdl static int
cd9660_write_filedata(iso9660_disk * diskStructure,FILE * fd,off_t sector,const unsigned char * buf,int numsecs)388e4989541Schristos cd9660_write_filedata(iso9660_disk *diskStructure, FILE *fd, off_t sector,
389e4989541Schristos const unsigned char *buf, int numsecs)
3903550dc98Sfvdl {
3913550dc98Sfvdl off_t curpos;
3923550dc98Sfvdl size_t success;
3933550dc98Sfvdl
3943550dc98Sfvdl curpos = ftello(fd);
3953550dc98Sfvdl
396e4989541Schristos if (fseeko(fd, sector * diskStructure->sectorSize, SEEK_SET) == -1)
397*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
3983550dc98Sfvdl
399e4989541Schristos success = fwrite(buf, diskStructure->sectorSize * numsecs, 1, fd);
4003550dc98Sfvdl
401203850f0Schristos if (fseeko(fd, curpos, SEEK_SET) == -1)
402*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
4033550dc98Sfvdl
4043550dc98Sfvdl if (success == 1)
405e4989541Schristos success = diskStructure->sectorSize * numsecs;
4063550dc98Sfvdl return success;
4073550dc98Sfvdl }
4083550dc98Sfvdl
4093550dc98Sfvdl #if 0
4103550dc98Sfvdl static int
411203850f0Schristos cd9660_write_buffered(FILE *fd, off_t offset, int buff_len,
4123550dc98Sfvdl const unsigned char* buffer)
4133550dc98Sfvdl {
4143550dc98Sfvdl static int working_sector = -1;
415203850f0Schristos static char buf[CD9660_SECTOR_SIZE];
4163550dc98Sfvdl
4173550dc98Sfvdl return 0;
4183550dc98Sfvdl }
4193550dc98Sfvdl #endif
4203550dc98Sfvdl
4213550dc98Sfvdl int
cd9660_copy_file(iso9660_disk * diskStructure,FILE * fd,off_t start_sector,const char * filename)422e4989541Schristos cd9660_copy_file(iso9660_disk *diskStructure, FILE *fd, off_t start_sector,
423e4989541Schristos const char *filename)
4243550dc98Sfvdl {
4253550dc98Sfvdl FILE *rf;
4263550dc98Sfvdl int bytes_read;
427203850f0Schristos off_t sector = start_sector;
428e4989541Schristos int buf_size = diskStructure->sectorSize;
4293550dc98Sfvdl char *buf;
4303550dc98Sfvdl
431e4989541Schristos buf = emalloc(buf_size);
4323550dc98Sfvdl if ((rf = fopen(filename, "rb")) == NULL) {
433f334b70aSdyoung warn("%s: cannot open %s", __func__, filename);
434a27001b7Sriz free(buf);
4353550dc98Sfvdl return 0;
4363550dc98Sfvdl }
4373550dc98Sfvdl
438e4989541Schristos if (diskStructure->verbose_level > 1)
4393550dc98Sfvdl printf("Writing file: %s\n",filename);
4403550dc98Sfvdl
441e4989541Schristos if (fseeko(fd, start_sector * diskStructure->sectorSize, SEEK_SET) == -1)
442*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
4433550dc98Sfvdl
4443550dc98Sfvdl while (!feof(rf)) {
4453550dc98Sfvdl bytes_read = fread(buf,1,buf_size,rf);
4463550dc98Sfvdl if (ferror(rf)) {
447f334b70aSdyoung warn("%s: fread", __func__);
448a27001b7Sriz free(buf);
449613c2821Swiz (void)fclose(rf);
4503550dc98Sfvdl return 0;
4513550dc98Sfvdl }
4523550dc98Sfvdl
4533550dc98Sfvdl fwrite(buf,1,bytes_read,fd);
4543550dc98Sfvdl if (ferror(fd)) {
455f334b70aSdyoung warn("%s: fwrite", __func__);
456a27001b7Sriz free(buf);
457613c2821Swiz (void)fclose(rf);
4583550dc98Sfvdl return 0;
4593550dc98Sfvdl }
4603550dc98Sfvdl sector++;
4613550dc98Sfvdl }
4623550dc98Sfvdl
4633550dc98Sfvdl fclose(rf);
4643550dc98Sfvdl free(buf);
4653550dc98Sfvdl return 1;
4663550dc98Sfvdl }
4673550dc98Sfvdl
468f8474b32Sbjh21 static void
cd9660_write_rr(iso9660_disk * diskStructure,FILE * fd,cd9660node * writenode,off_t offset,off_t sector)469e4989541Schristos cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode,
470e4989541Schristos off_t offset, off_t sector)
4713550dc98Sfvdl {
4723550dc98Sfvdl int in_ca = 0;
4733550dc98Sfvdl struct ISO_SUSP_ATTRIBUTES *myattr;
4743550dc98Sfvdl
4753550dc98Sfvdl offset += writenode->isoDirRecord->length[0];
476e4989541Schristos if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) ==
477203850f0Schristos -1)
478*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
4793550dc98Sfvdl /* Offset now points at the end of the record */
480689c61f6Sdyoung TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
4813550dc98Sfvdl fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
4823550dc98Sfvdl
4833550dc98Sfvdl if (!in_ca) {
484f8474b32Sbjh21 offset += CD9660_SUSP_ENTRY_SIZE(myattr);
485f8474b32Sbjh21 if (myattr->last_in_suf) {
4863550dc98Sfvdl /*
4873550dc98Sfvdl * Point the offset to the start of this
4883550dc98Sfvdl * record's CE area
4893550dc98Sfvdl */
490e4989541Schristos if (fseeko(fd, ((off_t)diskStructure->
4913550dc98Sfvdl susp_continuation_area_start_sector *
492e4989541Schristos diskStructure->sectorSize)
493f8474b32Sbjh21 + writenode->susp_entry_ce_start,
494203850f0Schristos SEEK_SET) == -1)
495*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
4963550dc98Sfvdl in_ca = 1;
4973550dc98Sfvdl }
4983550dc98Sfvdl }
4993550dc98Sfvdl }
5003550dc98Sfvdl
501f8474b32Sbjh21 /*
502f0a888eeSmbalmer * If we had to go to the continuation area, head back to
503f8474b32Sbjh21 * where we should be.
504f8474b32Sbjh21 */
505f8474b32Sbjh21 if (in_ca)
506e4989541Schristos if (fseeko(fd, sector * diskStructure->sectorSize + offset,
507203850f0Schristos SEEK_SET) == -1)
508*ec5d1d82Stsutsui err(EXIT_FAILURE, "fseeko");
5093550dc98Sfvdl }
510