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