Home | History | Annotate | Line # | Download | only in cd9660
      1  1.18   tsutsui /*	$NetBSD: cd9660_write.c,v 1.18 2023/12/28 12:13:56 tsutsui Exp $	*/
      2   1.1      fvdl 
      3   1.1      fvdl /*
      4   1.1      fvdl  * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
      5   1.1      fvdl  * Perez-Rathke and Ram Vedam.  All rights reserved.
      6   1.1      fvdl  *
      7   1.1      fvdl  * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
      8   1.1      fvdl  * Alan Perez-Rathke and Ram Vedam.
      9   1.1      fvdl  *
     10   1.1      fvdl  * Redistribution and use in source and binary forms, with or
     11   1.1      fvdl  * without modification, are permitted provided that the following
     12   1.1      fvdl  * conditions are met:
     13   1.1      fvdl  * 1. Redistributions of source code must retain the above copyright
     14   1.1      fvdl  *    notice, this list of conditions and the following disclaimer.
     15   1.1      fvdl  * 2. Redistributions in binary form must reproduce the above
     16   1.1      fvdl  *    copyright notice, this list of conditions and the following
     17   1.1      fvdl  *    disclaimer in the documentation and/or other materials provided
     18   1.1      fvdl  *    with the distribution.
     19   1.1      fvdl  *
     20   1.1      fvdl  * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
     21   1.1      fvdl  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
     22   1.1      fvdl  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23   1.3    dyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     24   1.1      fvdl  * DISCLAIMED.  IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
     25   1.1      fvdl  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
     26   1.1      fvdl  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27   1.1      fvdl  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
     28   1.1      fvdl  * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     29   1.1      fvdl  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     30   1.1      fvdl  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1      fvdl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     32   1.1      fvdl  * OF SUCH DAMAGE.
     33   1.1      fvdl  */
     34   1.1      fvdl 
     35   1.1      fvdl #include "cd9660.h"
     36   1.1      fvdl #include "iso9660_rrip.h"
     37   1.1      fvdl 
     38   1.1      fvdl #include <sys/cdefs.h>
     39   1.1      fvdl #if defined(__RCSID) && !defined(__lint)
     40  1.18   tsutsui __RCSID("$NetBSD: cd9660_write.c,v 1.18 2023/12/28 12:13:56 tsutsui Exp $");
     41   1.1      fvdl #endif  /* !__lint */
     42   1.1      fvdl 
     43  1.16  christos #include <util.h>
     44  1.16  christos 
     45  1.16  christos static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *);
     46  1.16  christos static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int);
     47  1.16  christos static int cd9660_write_path_tables(iso9660_disk *, FILE *);
     48  1.16  christos static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *);
     49  1.16  christos static int cd9660_write_filedata(iso9660_disk *, FILE *, off_t,
     50  1.16  christos     const unsigned char *, int);
     51   1.1      fvdl #if 0
     52  1.13  christos static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
     53   1.1      fvdl #endif
     54  1.16  christos static void cd9660_write_rr(iso9660_disk *, FILE *, cd9660node *, off_t, off_t);
     55   1.1      fvdl 
     56   1.1      fvdl /*
     57   1.1      fvdl  * Write the image
     58   1.1      fvdl  * Writes the entire image
     59   1.1      fvdl  * @param const char* The filename for the image
     60   1.1      fvdl  * @returns int 1 on success, 0 on failure
     61   1.1      fvdl  */
     62   1.3    dyoung int
     63  1.16  christos cd9660_write_image(iso9660_disk *diskStructure, const char* image)
     64   1.1      fvdl {
     65   1.1      fvdl 	FILE *fd;
     66   1.1      fvdl 	int status;
     67  1.13  christos 	char buf[CD9660_SECTOR_SIZE];
     68   1.3    dyoung 
     69   1.4    dyoung 	if ((fd = fopen(image, "w+")) == NULL) {
     70   1.4    dyoung 		err(EXIT_FAILURE, "%s: Can't open `%s' for writing", __func__,
     71   1.4    dyoung 		    image);
     72   1.4    dyoung 	}
     73   1.1      fvdl 
     74  1.16  christos 	if (diskStructure->verbose_level > 0)
     75   1.1      fvdl 		printf("Writing image\n");
     76   1.1      fvdl 
     77  1.16  christos 	if (diskStructure->has_generic_bootimage) {
     78  1.16  christos 		status = cd9660_copy_file(diskStructure, fd, 0,
     79  1.16  christos 		    diskStructure->generic_bootimage);
     80   1.9     skrll 		if (status == 0) {
     81   1.9     skrll 			warnx("%s: Error writing generic boot image",
     82   1.9     skrll 			    __func__);
     83   1.9     skrll 			goto cleanup_bad_image;
     84   1.9     skrll 		}
     85   1.9     skrll 	}
     86   1.9     skrll 
     87   1.1      fvdl 	/* Write the volume descriptors */
     88  1.16  christos 	status = cd9660_write_volume_descriptors(diskStructure, fd);
     89   1.1      fvdl 	if (status == 0) {
     90   1.4    dyoung 		warnx("%s: Error writing volume descriptors to image",
     91   1.4    dyoung 		    __func__);
     92   1.1      fvdl 		goto cleanup_bad_image;
     93   1.1      fvdl 	}
     94   1.3    dyoung 
     95  1.16  christos 	if (diskStructure->verbose_level > 0)
     96   1.1      fvdl 		printf("Volume descriptors written\n");
     97   1.3    dyoung 
     98   1.1      fvdl 	/*
     99   1.1      fvdl 	 * Write the path tables: there are actually four, but right
    100   1.1      fvdl 	 * now we are only concearned with two.
    101   1.1      fvdl 	 */
    102  1.16  christos 	status = cd9660_write_path_tables(diskStructure, fd);
    103   1.1      fvdl 	if (status == 0) {
    104   1.4    dyoung 		warnx("%s: Error writing path tables to image", __func__);
    105   1.1      fvdl 		goto cleanup_bad_image;
    106   1.1      fvdl 	}
    107   1.3    dyoung 
    108  1.16  christos 	if (diskStructure->verbose_level > 0)
    109   1.1      fvdl 		printf("Path tables written\n");
    110   1.3    dyoung 
    111   1.1      fvdl 	/* Write the directories and files */
    112  1.16  christos 	status = cd9660_write_file(diskStructure, fd, diskStructure->rootNode);
    113   1.1      fvdl 	if (status == 0) {
    114   1.4    dyoung 		warnx("%s: Error writing files to image", __func__);
    115   1.1      fvdl 		goto cleanup_bad_image;
    116   1.1      fvdl 	}
    117   1.1      fvdl 
    118  1.16  christos 	if (diskStructure->is_bootable) {
    119  1.16  christos 		cd9660_write_boot(diskStructure, fd);
    120   1.1      fvdl 	}
    121   1.1      fvdl 
    122   1.1      fvdl 	/* Write padding bits. This is temporary */
    123  1.13  christos 	memset(buf, 0, CD9660_SECTOR_SIZE);
    124  1.16  christos 	cd9660_write_filedata(diskStructure, fd,
    125  1.16  christos 	    diskStructure->totalSectors - 1, buf, 1);
    126   1.3    dyoung 
    127  1.16  christos 	if (diskStructure->verbose_level > 0)
    128   1.1      fvdl 		printf("Files written\n");
    129   1.1      fvdl 	fclose(fd);
    130   1.3    dyoung 
    131  1.16  christos 	if (diskStructure->verbose_level > 0)
    132   1.1      fvdl 		printf("Image closed\n");
    133   1.1      fvdl 	return 1;
    134   1.1      fvdl 
    135   1.1      fvdl cleanup_bad_image:
    136   1.1      fvdl 	fclose(fd);
    137  1.16  christos 	if (!diskStructure->keep_bad_images)
    138   1.1      fvdl 		unlink(image);
    139  1.16  christos 	if (diskStructure->verbose_level > 0)
    140   1.1      fvdl 		printf("Bad image cleaned up\n");
    141   1.1      fvdl 	return 0;
    142   1.1      fvdl }
    143   1.1      fvdl 
    144   1.1      fvdl static int
    145  1.16  christos cd9660_write_volume_descriptors(iso9660_disk *diskStructure, FILE *fd)
    146   1.1      fvdl {
    147  1.16  christos 	volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor;
    148   1.1      fvdl 	while (vd_temp != NULL) {
    149  1.16  christos 		cd9660_write_filedata(diskStructure, fd, vd_temp->sector,
    150   1.1      fvdl 		    vd_temp->volumeDescriptorData, 1);
    151   1.1      fvdl 		vd_temp = vd_temp->next;
    152   1.1      fvdl 	}
    153   1.1      fvdl 	return 1;
    154   1.1      fvdl }
    155   1.1      fvdl 
    156   1.1      fvdl /*
    157   1.1      fvdl  * Write out an individual path table
    158   1.1      fvdl  * Used just to keep redundant code to a minimum
    159   1.1      fvdl  * @param FILE *fd Valid file pointer
    160   1.1      fvdl  * @param int Sector to start writing path table to
    161   1.1      fvdl  * @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
    162   1.1      fvdl  * @returns int 1 on success, 0 on failure
    163   1.1      fvdl  */
    164   1.1      fvdl static int
    165  1.16  christos cd9660_write_path_table(iso9660_disk *diskStructure, FILE *fd, off_t sector,
    166  1.16  christos     int mode)
    167   1.1      fvdl {
    168  1.16  christos 	int path_table_sectors = CD9660_BLOCKS(diskStructure->sectorSize,
    169  1.16  christos 	    diskStructure->pathTableLength);
    170   1.1      fvdl 	unsigned char *buffer;
    171   1.1      fvdl 	unsigned char *buffer_head;
    172   1.1      fvdl 	int len;
    173   1.1      fvdl 	path_table_entry temp_entry;
    174   1.1      fvdl 	cd9660node *ptcur;
    175   1.1      fvdl 
    176  1.16  christos 	buffer = ecalloc(path_table_sectors, diskStructure->sectorSize);
    177   1.1      fvdl 	buffer_head = buffer;
    178   1.1      fvdl 
    179  1.16  christos 	ptcur = diskStructure->rootNode;
    180   1.3    dyoung 
    181   1.1      fvdl 	while (ptcur != NULL) {
    182   1.1      fvdl 		memset(&temp_entry, 0, sizeof(path_table_entry));
    183   1.1      fvdl 		temp_entry.length[0] = ptcur->isoDirRecord->name_len[0];
    184   1.1      fvdl 		temp_entry.extended_attribute_length[0] =
    185   1.1      fvdl 		    ptcur->isoDirRecord->ext_attr_length[0];
    186   1.1      fvdl 		memcpy(temp_entry.name, ptcur->isoDirRecord->name,
    187   1.1      fvdl 		    temp_entry.length[0] + 1);
    188   1.1      fvdl 
    189   1.1      fvdl 		/* round up */
    190   1.1      fvdl 		len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01);
    191   1.1      fvdl 
    192   1.1      fvdl                 /* todo: function pointers instead */
    193   1.1      fvdl 		if (mode == LITTLE_ENDIAN) {
    194   1.1      fvdl 			cd9660_731(ptcur->fileDataSector,
    195   1.1      fvdl 			    temp_entry.first_sector);
    196   1.1      fvdl 			cd9660_721((ptcur->parent == NULL ?
    197   1.1      fvdl 				1 : ptcur->parent->ptnumber),
    198   1.1      fvdl 			    temp_entry.parent_number);
    199   1.1      fvdl 		} else {
    200   1.1      fvdl 			cd9660_732(ptcur->fileDataSector,
    201   1.1      fvdl 			    temp_entry.first_sector);
    202   1.1      fvdl 			cd9660_722((ptcur->parent == NULL ?
    203   1.1      fvdl 				1 : ptcur->parent->ptnumber),
    204   1.1      fvdl 			    temp_entry.parent_number);
    205   1.1      fvdl 		}
    206   1.3    dyoung 
    207   1.1      fvdl 
    208   1.1      fvdl 		memcpy(buffer, &temp_entry, len);
    209   1.1      fvdl 		buffer += len;
    210   1.3    dyoung 
    211   1.1      fvdl 		ptcur = ptcur->ptnext;
    212   1.1      fvdl 	}
    213   1.3    dyoung 
    214  1.16  christos 	return cd9660_write_filedata(diskStructure, fd, sector, buffer_head,
    215   1.1      fvdl 	    path_table_sectors);
    216   1.1      fvdl }
    217   1.1      fvdl 
    218   1.1      fvdl 
    219   1.1      fvdl /*
    220   1.1      fvdl  * Write out the path tables to disk
    221   1.1      fvdl  * Each file descriptor should be pointed to by the PVD, so we know which
    222   1.1      fvdl  * sector to copy them to. One thing to watch out for: the only path tables
    223   1.1      fvdl  * stored are in the endian mode that the application is compiled for. So,
    224   1.1      fvdl  * the first thing to do is write out that path table, then to write the one
    225   1.1      fvdl  * in the other endian mode requires to convert the endianness of each entry
    226   1.1      fvdl  * in the table. The best way to do this would be to create a temporary
    227   1.1      fvdl  * path_table_entry structure, then for each path table entry, copy it to
    228   1.1      fvdl  * the temporary entry, translate, then copy that to disk.
    229   1.1      fvdl  *
    230   1.1      fvdl  * @param FILE* Valid file descriptor
    231   1.1      fvdl  * @returns int 0 on failure, 1 on success
    232   1.1      fvdl  */
    233   1.1      fvdl static int
    234  1.16  christos cd9660_write_path_tables(iso9660_disk *diskStructure, FILE *fd)
    235   1.1      fvdl {
    236  1.16  christos 	if (cd9660_write_path_table(diskStructure, fd,
    237  1.16  christos 	    diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0)
    238   1.1      fvdl 		return 0;
    239   1.1      fvdl 
    240  1.16  christos 	if (cd9660_write_path_table(diskStructure, fd,
    241  1.16  christos 	    diskStructure->primaryBigEndianTableSector, BIG_ENDIAN) == 0)
    242   1.1      fvdl 		return 0;
    243   1.1      fvdl 
    244   1.1      fvdl 	/* @TODO: handle remaining two path tables */
    245   1.1      fvdl 	return 1;
    246   1.1      fvdl }
    247   1.1      fvdl 
    248   1.1      fvdl /*
    249   1.1      fvdl  * Write a file to disk
    250   1.1      fvdl  * Writes a file, its directory record, and its data to disk
    251   1.1      fvdl  * This file is designed to be called RECURSIVELY, so initially call it
    252   1.1      fvdl  * with the root node. All of the records should store what sector the
    253   1.1      fvdl  * file goes in, so no computation should be  necessary.
    254   1.1      fvdl  *
    255   1.1      fvdl  * @param int fd Valid file descriptor
    256   1.1      fvdl  * @param struct cd9660node* writenode Pointer to the file to be written
    257   1.1      fvdl  * @returns int 0 on failure, 1 on success
    258   1.1      fvdl  */
    259   1.1      fvdl static int
    260  1.16  christos cd9660_write_file(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode)
    261   1.1      fvdl {
    262   1.1      fvdl 	char *buf;
    263   1.1      fvdl 	char *temp_file_name;
    264   1.1      fvdl 	int ret;
    265  1.13  christos 	off_t working_sector;
    266   1.1      fvdl 	int cur_sector_offset;
    267   1.1      fvdl 	iso_directory_record_cd9660 temp_record;
    268   1.1      fvdl 	cd9660node *temp;
    269  1.10     bjh21 	int rv = 0;
    270   1.1      fvdl 
    271   1.1      fvdl 	/* Todo : clean up variables */
    272   1.3    dyoung 
    273  1.16  christos 	temp_file_name = ecalloc(CD9660MAXPATH + 1, 1);
    274  1.16  christos 	buf = emalloc(diskStructure->sectorSize);
    275   1.1      fvdl 	if ((writenode->level != 0) &&
    276   1.1      fvdl 	    !(writenode->node->type & S_IFDIR)) {
    277   1.5    dyoung 		fsinode *inode = writenode->node->inode;
    278   1.5    dyoung 		/* Only attempt to write unwritten files that have length. */
    279   1.5    dyoung 		if ((inode->flags & FI_WRITTEN) != 0) {
    280   1.5    dyoung 			INODE_WARNX(("%s: skipping written inode %d", __func__,
    281   1.5    dyoung 			    (int)inode->st.st_ino));
    282   1.5    dyoung 		} else if (writenode->fileDataLength > 0) {
    283   1.6    dyoung 			INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
    284   1.6    dyoung 			    __func__, (int)inode->st.st_ino, inode->ino));
    285   1.5    dyoung 			inode->flags |= FI_WRITTEN;
    286   1.1      fvdl 			cd9660_compute_full_filename(writenode,
    287  1.15  christos 			    temp_file_name);
    288  1.16  christos 			ret = cd9660_copy_file(diskStructure, fd,
    289  1.16  christos 			    writenode->fileDataSector, temp_file_name);
    290   1.8  christos 			if (ret == 0)
    291   1.8  christos 				goto out;
    292   1.1      fvdl 		}
    293   1.1      fvdl 	} else {
    294   1.1      fvdl 		/*
    295   1.1      fvdl 		 * Here is a new revelation that ECMA didnt explain
    296   1.1      fvdl 		 * (at least not well).
    297   1.1      fvdl 		 * ALL . and .. records store the name "\0" and "\1"
    298   1.1      fvdl 		 * resepctively. So, for each directory, we have to
    299   1.1      fvdl 		 * make a new node.
    300   1.1      fvdl 		 *
    301   1.1      fvdl 		 * This is where it gets kinda messy, since we have to
    302   1.1      fvdl 		 * be careful of sector boundaries
    303   1.1      fvdl 		 */
    304   1.1      fvdl 		cur_sector_offset = 0;
    305   1.1      fvdl 		working_sector = writenode->fileDataSector;
    306  1.16  christos 		if (fseeko(fd, working_sector * diskStructure->sectorSize,
    307  1.13  christos 		    SEEK_SET) == -1)
    308  1.18   tsutsui 			err(EXIT_FAILURE, "fseeko");
    309   1.3    dyoung 
    310   1.1      fvdl 		/*
    311   1.1      fvdl 		 * Now loop over children, writing out their directory
    312   1.1      fvdl 		 * records - beware of sector boundaries
    313   1.1      fvdl 	 	 */
    314   1.2    dyoung 		TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
    315   1.1      fvdl 			/*
    316   1.1      fvdl 			 * Copy the temporary record and adjust its size
    317   1.1      fvdl 			 * if necessary
    318   1.1      fvdl 			 */
    319   1.1      fvdl 			memcpy(&temp_record, temp->isoDirRecord,
    320   1.1      fvdl 			    sizeof(iso_directory_record_cd9660));
    321   1.1      fvdl 
    322   1.1      fvdl 			temp_record.length[0] =
    323  1.16  christos 			    cd9660_compute_record_size(diskStructure, temp);
    324   1.3    dyoung 
    325   1.1      fvdl 			if (temp_record.length[0] + cur_sector_offset >=
    326  1.16  christos 			    diskStructure->sectorSize) {
    327   1.1      fvdl 				cur_sector_offset = 0;
    328   1.1      fvdl 				working_sector++;
    329   1.1      fvdl 
    330   1.1      fvdl 				/* Seek to the next sector. */
    331  1.13  christos 				if (fseeko(fd, working_sector *
    332  1.16  christos 				    diskStructure->sectorSize, SEEK_SET) == -1)
    333  1.18   tsutsui 					err(EXIT_FAILURE, "fseeko");
    334   1.1      fvdl 			}
    335  1.10     bjh21 			/* Write out the basic ISO directory record */
    336  1.17  christos 			(void)fwrite(&temp_record, 1,
    337  1.10     bjh21 			    temp->isoDirRecord->length[0], fd);
    338  1.16  christos 			if (diskStructure->rock_ridge_enabled) {
    339  1.16  christos 				cd9660_write_rr(diskStructure, fd, temp,
    340   1.1      fvdl 				    cur_sector_offset, working_sector);
    341   1.1      fvdl 			}
    342  1.13  christos 			if (fseeko(fd, working_sector *
    343  1.16  christos 			    diskStructure->sectorSize + cur_sector_offset +
    344  1.13  christos 			    temp_record.length[0] - temp->su_tail_size,
    345  1.13  christos 			    SEEK_SET) == -1)
    346  1.18   tsutsui 				err(EXIT_FAILURE, "fseeko");
    347  1.10     bjh21 			if (temp->su_tail_size > 0)
    348  1.10     bjh21 				fwrite(temp->su_tail_data, 1,
    349  1.10     bjh21 				    temp->su_tail_size, fd);
    350   1.1      fvdl 			if (ferror(fd)) {
    351   1.4    dyoung 				warnx("%s: write error", __func__);
    352   1.8  christos 				goto out;
    353   1.1      fvdl 			}
    354   1.1      fvdl 			cur_sector_offset += temp_record.length[0];
    355   1.1      fvdl 
    356   1.1      fvdl 		}
    357   1.3    dyoung 
    358   1.1      fvdl 		/*
    359   1.2    dyoung 		 * Recurse on children.
    360   1.1      fvdl 		 */
    361   1.2    dyoung 		TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
    362  1.16  christos 			if ((ret = cd9660_write_file(diskStructure, fd, temp))
    363  1.16  christos 			    == 0)
    364   1.8  christos 				goto out;
    365   1.1      fvdl 		}
    366   1.1      fvdl 	}
    367   1.8  christos 	rv = 1;
    368   1.8  christos out:
    369   1.1      fvdl 	free(temp_file_name);
    370   1.8  christos 	free(buf);
    371   1.8  christos 	return rv;
    372   1.1      fvdl }
    373   1.1      fvdl 
    374   1.1      fvdl /*
    375   1.1      fvdl  * Wrapper function to write a buffer (one sector) to disk.
    376   1.1      fvdl  * Seeks and writes the buffer.
    377   1.1      fvdl  * NOTE: You dont NEED to use this function, but it might make your
    378   1.1      fvdl  * life easier if you have to write things that align to a sector
    379   1.1      fvdl  * (such as volume descriptors).
    380   1.1      fvdl  *
    381   1.1      fvdl  * @param int fd Valid file descriptor
    382   1.1      fvdl  * @param int sector Sector number to write to
    383   1.1      fvdl  * @param const unsigned char* Buffer to write. This should be the
    384   1.1      fvdl  *                             size of a sector, and if only a portion
    385   1.1      fvdl  *                             is written, the rest should be set to 0.
    386   1.1      fvdl  */
    387   1.1      fvdl static int
    388  1.16  christos cd9660_write_filedata(iso9660_disk *diskStructure, FILE *fd, off_t sector,
    389  1.16  christos     const unsigned char *buf, int numsecs)
    390   1.1      fvdl {
    391   1.1      fvdl 	off_t curpos;
    392   1.1      fvdl 	size_t success;
    393   1.1      fvdl 
    394   1.1      fvdl 	curpos = ftello(fd);
    395   1.3    dyoung 
    396  1.16  christos 	if (fseeko(fd, sector * diskStructure->sectorSize, SEEK_SET) == -1)
    397  1.18   tsutsui 		err(EXIT_FAILURE, "fseeko");
    398   1.1      fvdl 
    399  1.16  christos 	success = fwrite(buf, diskStructure->sectorSize * numsecs, 1, fd);
    400   1.1      fvdl 
    401  1.13  christos 	if (fseeko(fd, curpos, SEEK_SET) == -1)
    402  1.18   tsutsui 		err(EXIT_FAILURE, "fseeko");
    403   1.1      fvdl 
    404   1.1      fvdl 	if (success == 1)
    405  1.16  christos 		success = diskStructure->sectorSize * numsecs;
    406   1.1      fvdl 	return success;
    407   1.1      fvdl }
    408   1.1      fvdl 
    409   1.1      fvdl #if 0
    410   1.1      fvdl static int
    411  1.13  christos cd9660_write_buffered(FILE *fd, off_t offset, int buff_len,
    412   1.1      fvdl 		      const unsigned char* buffer)
    413   1.1      fvdl {
    414   1.1      fvdl 	static int working_sector = -1;
    415  1.13  christos 	static char buf[CD9660_SECTOR_SIZE];
    416   1.3    dyoung 
    417   1.1      fvdl 	return 0;
    418   1.1      fvdl }
    419   1.1      fvdl #endif
    420   1.1      fvdl 
    421   1.1      fvdl int
    422  1.16  christos cd9660_copy_file(iso9660_disk *diskStructure, FILE *fd, off_t start_sector,
    423  1.16  christos     const char *filename)
    424   1.1      fvdl {
    425   1.1      fvdl 	FILE *rf;
    426   1.1      fvdl 	int bytes_read;
    427  1.13  christos 	off_t sector = start_sector;
    428  1.16  christos 	int buf_size = diskStructure->sectorSize;
    429   1.1      fvdl 	char *buf;
    430   1.1      fvdl 
    431  1.16  christos 	buf = emalloc(buf_size);
    432   1.1      fvdl 	if ((rf = fopen(filename, "rb")) == NULL) {
    433   1.4    dyoung 		warn("%s: cannot open %s", __func__, filename);
    434   1.7       riz 		free(buf);
    435   1.3    dyoung 		return 0;
    436   1.1      fvdl 	}
    437   1.1      fvdl 
    438  1.16  christos 	if (diskStructure->verbose_level > 1)
    439   1.1      fvdl 		printf("Writing file: %s\n",filename);
    440   1.3    dyoung 
    441  1.16  christos 	if (fseeko(fd, start_sector * diskStructure->sectorSize, SEEK_SET) == -1)
    442  1.18   tsutsui 		err(EXIT_FAILURE, "fseeko");
    443   1.3    dyoung 
    444   1.1      fvdl 	while (!feof(rf)) {
    445   1.1      fvdl 		bytes_read = fread(buf,1,buf_size,rf);
    446   1.1      fvdl 		if (ferror(rf)) {
    447   1.4    dyoung 			warn("%s: fread", __func__);
    448   1.7       riz 			free(buf);
    449  1.14       wiz 			(void)fclose(rf);
    450   1.3    dyoung 			return 0;
    451   1.1      fvdl 		}
    452   1.3    dyoung 
    453   1.1      fvdl 		fwrite(buf,1,bytes_read,fd);
    454   1.1      fvdl 		if (ferror(fd)) {
    455   1.4    dyoung 			warn("%s: fwrite", __func__);
    456   1.7       riz 			free(buf);
    457  1.14       wiz 			(void)fclose(rf);
    458   1.3    dyoung 			return 0;
    459   1.1      fvdl 		}
    460   1.1      fvdl 		sector++;
    461   1.1      fvdl 	}
    462   1.3    dyoung 
    463   1.1      fvdl 	fclose(rf);
    464   1.1      fvdl 	free(buf);
    465   1.1      fvdl 	return 1;
    466   1.1      fvdl }
    467   1.1      fvdl 
    468  1.10     bjh21 static void
    469  1.16  christos cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode,
    470  1.16  christos     off_t offset, off_t sector)
    471   1.1      fvdl {
    472   1.1      fvdl 	int in_ca = 0;
    473   1.1      fvdl 	struct ISO_SUSP_ATTRIBUTES *myattr;
    474   1.1      fvdl 
    475   1.1      fvdl 	offset += writenode->isoDirRecord->length[0];
    476  1.16  christos 	if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) ==
    477  1.13  christos 	    -1)
    478  1.18   tsutsui 		err(EXIT_FAILURE, "fseeko");
    479   1.1      fvdl 	/* Offset now points at the end of the record */
    480   1.2    dyoung 	TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
    481   1.1      fvdl 		fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
    482   1.1      fvdl 
    483   1.1      fvdl 		if (!in_ca) {
    484  1.10     bjh21 			offset += CD9660_SUSP_ENTRY_SIZE(myattr);
    485  1.10     bjh21 			if (myattr->last_in_suf) {
    486   1.1      fvdl 				/*
    487   1.1      fvdl 				 * Point the offset to the start of this
    488   1.1      fvdl 				 * record's CE area
    489   1.1      fvdl 				 */
    490  1.16  christos 				if (fseeko(fd, ((off_t)diskStructure->
    491  1.13  christos 				    susp_continuation_area_start_sector *
    492  1.16  christos 				    diskStructure->sectorSize)
    493  1.10     bjh21 				    + writenode->susp_entry_ce_start,
    494  1.13  christos 				    SEEK_SET) == -1)
    495  1.18   tsutsui 					err(EXIT_FAILURE, "fseeko");
    496   1.1      fvdl 				in_ca = 1;
    497   1.1      fvdl 			}
    498   1.1      fvdl 		}
    499   1.1      fvdl 	}
    500   1.1      fvdl 
    501  1.10     bjh21 	/*
    502  1.12   mbalmer 	 * If we had to go to the continuation area, head back to
    503  1.10     bjh21 	 * where we should be.
    504  1.10     bjh21 	 */
    505  1.10     bjh21 	if (in_ca)
    506  1.16  christos 		if (fseeko(fd, sector * diskStructure->sectorSize + offset,
    507  1.13  christos 		    SEEK_SET) == -1)
    508  1.18   tsutsui 			err(EXIT_FAILURE, "fseeko");
    509   1.1      fvdl }
    510