Home | History | Annotate | Line # | Download | only in cd9660
cd9660_write.c revision 1.14
      1  1.14       wiz /*	$NetBSD: cd9660_write.c,v 1.14 2011/01/04 09:48:21 wiz 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.14       wiz __RCSID("$NetBSD: cd9660_write.c,v 1.14 2011/01/04 09:48:21 wiz Exp $");
     41   1.1      fvdl #endif  /* !__lint */
     42   1.1      fvdl 
     43   1.1      fvdl static int cd9660_write_volume_descriptors(FILE *);
     44  1.13  christos static int cd9660_write_path_table(FILE *, off_t, 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.13  christos static int cd9660_write_filedata(FILE *, off_t, const unsigned char *, int);
     48   1.1      fvdl #if 0
     49  1.13  christos static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
     50   1.1      fvdl #endif
     51  1.13  christos static void cd9660_write_rr(FILE *, cd9660node *, off_t, off_t);
     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.13  christos 	char buf[CD9660_SECTOR_SIZE];
     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.13  christos 	memset(buf, 0, CD9660_SECTOR_SIZE);
    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.13  christos 		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.13  christos cd9660_write_path_table(FILE *fd, off_t 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.13  christos 	off_t 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.10     bjh21 	int 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.13  christos 		if (fseeko(fd, working_sector * diskStructure.sectorSize,
    320  1.13  christos 		    SEEK_SET) == -1)
    321  1.13  christos 			err(1, "fseeko");
    322   1.3    dyoung 
    323   1.1      fvdl 		/*
    324   1.1      fvdl 		 * Now loop over children, writing out their directory
    325   1.1      fvdl 		 * records - beware of sector boundaries
    326   1.1      fvdl 	 	 */
    327   1.2    dyoung 		TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
    328   1.1      fvdl 			/*
    329   1.1      fvdl 			 * Copy the temporary record and adjust its size
    330   1.1      fvdl 			 * if necessary
    331   1.1      fvdl 			 */
    332   1.1      fvdl 			memcpy(&temp_record, temp->isoDirRecord,
    333   1.1      fvdl 			    sizeof(iso_directory_record_cd9660));
    334   1.1      fvdl 
    335   1.1      fvdl 			temp_record.length[0] =
    336   1.1      fvdl 			    cd9660_compute_record_size(temp);
    337   1.3    dyoung 
    338   1.1      fvdl 			if (temp_record.length[0] + cur_sector_offset >=
    339   1.1      fvdl 			    diskStructure.sectorSize) {
    340   1.1      fvdl 				cur_sector_offset = 0;
    341   1.1      fvdl 				working_sector++;
    342   1.1      fvdl 
    343   1.1      fvdl 				/* Seek to the next sector. */
    344  1.13  christos 				if (fseeko(fd, working_sector *
    345  1.13  christos 				    diskStructure.sectorSize, SEEK_SET) == -1)
    346  1.13  christos 					err(1, "fseeko");
    347   1.1      fvdl 			}
    348  1.10     bjh21 			/* Write out the basic ISO directory record */
    349  1.10     bjh21 			written = fwrite(&temp_record, 1,
    350  1.10     bjh21 			    temp->isoDirRecord->length[0], fd);
    351   1.1      fvdl 			if (diskStructure.rock_ridge_enabled) {
    352  1.10     bjh21 				cd9660_write_rr(fd, temp,
    353   1.1      fvdl 				    cur_sector_offset, working_sector);
    354   1.1      fvdl 			}
    355  1.13  christos 			if (fseeko(fd, working_sector *
    356  1.13  christos 			    diskStructure.sectorSize + cur_sector_offset +
    357  1.13  christos 			    temp_record.length[0] - temp->su_tail_size,
    358  1.13  christos 			    SEEK_SET) == -1)
    359  1.13  christos 				err(1, "fseeko");
    360  1.10     bjh21 			if (temp->su_tail_size > 0)
    361  1.10     bjh21 				fwrite(temp->su_tail_data, 1,
    362  1.10     bjh21 				    temp->su_tail_size, fd);
    363   1.1      fvdl 			if (ferror(fd)) {
    364   1.4    dyoung 				warnx("%s: write error", __func__);
    365   1.8  christos 				goto out;
    366   1.1      fvdl 			}
    367   1.1      fvdl 			cur_sector_offset += temp_record.length[0];
    368   1.1      fvdl 
    369   1.1      fvdl 		}
    370   1.3    dyoung 
    371   1.1      fvdl 		/*
    372   1.2    dyoung 		 * Recurse on children.
    373   1.1      fvdl 		 */
    374   1.2    dyoung 		TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
    375   1.8  christos 			if ((ret = cd9660_write_file(fd, temp)) == 0)
    376   1.8  christos 				goto out;
    377   1.1      fvdl 		}
    378   1.1      fvdl 	}
    379   1.8  christos 	rv = 1;
    380   1.8  christos out:
    381   1.1      fvdl 	free(temp_file_name);
    382   1.8  christos 	free(buf);
    383   1.8  christos 	return rv;
    384   1.1      fvdl }
    385   1.1      fvdl 
    386   1.1      fvdl /*
    387   1.1      fvdl  * Wrapper function to write a buffer (one sector) to disk.
    388   1.1      fvdl  * Seeks and writes the buffer.
    389   1.1      fvdl  * NOTE: You dont NEED to use this function, but it might make your
    390   1.1      fvdl  * life easier if you have to write things that align to a sector
    391   1.1      fvdl  * (such as volume descriptors).
    392   1.1      fvdl  *
    393   1.1      fvdl  * @param int fd Valid file descriptor
    394   1.1      fvdl  * @param int sector Sector number to write to
    395   1.1      fvdl  * @param const unsigned char* Buffer to write. This should be the
    396   1.1      fvdl  *                             size of a sector, and if only a portion
    397   1.1      fvdl  *                             is written, the rest should be set to 0.
    398   1.1      fvdl  */
    399   1.1      fvdl static int
    400  1.13  christos cd9660_write_filedata(FILE *fd, off_t sector, const unsigned char *buf,
    401   1.1      fvdl 		      int numsecs)
    402   1.1      fvdl {
    403   1.1      fvdl 	off_t curpos;
    404   1.1      fvdl 	size_t success;
    405   1.1      fvdl 
    406   1.1      fvdl 	curpos = ftello(fd);
    407   1.3    dyoung 
    408  1.13  christos 	if (fseeko(fd, sector * diskStructure.sectorSize, SEEK_SET) == -1)
    409  1.13  christos 		err(1, "fseeko");
    410   1.1      fvdl 
    411   1.1      fvdl 	success = fwrite(buf, diskStructure.sectorSize * numsecs, 1, fd);
    412   1.1      fvdl 
    413  1.13  christos 	if (fseeko(fd, curpos, SEEK_SET) == -1)
    414  1.13  christos 		err(1, "fseeko");
    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.13  christos cd9660_write_buffered(FILE *fd, off_t 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.13  christos 	static char buf[CD9660_SECTOR_SIZE];
    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.13  christos cd9660_copy_file(FILE *fd, off_t start_sector, const char *filename)
    435   1.1      fvdl {
    436   1.1      fvdl 	FILE *rf;
    437   1.1      fvdl 	int bytes_read;
    438  1.13  christos 	off_t 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.13  christos 	if (fseeko(fd, start_sector * diskStructure.sectorSize, SEEK_SET) == -1)
    456  1.13  christos 		err(1, "fseeko");
    457   1.3    dyoung 
    458   1.1      fvdl 	while (!feof(rf)) {
    459   1.1      fvdl 		bytes_read = fread(buf,1,buf_size,rf);
    460   1.1      fvdl 		if (ferror(rf)) {
    461   1.4    dyoung 			warn("%s: fread", __func__);
    462   1.7       riz 			free(buf);
    463  1.14       wiz 			(void)fclose(rf);
    464   1.3    dyoung 			return 0;
    465   1.1      fvdl 		}
    466   1.3    dyoung 
    467   1.1      fvdl 		fwrite(buf,1,bytes_read,fd);
    468   1.1      fvdl 		if (ferror(fd)) {
    469   1.4    dyoung 			warn("%s: fwrite", __func__);
    470   1.7       riz 			free(buf);
    471  1.14       wiz 			(void)fclose(rf);
    472   1.3    dyoung 			return 0;
    473   1.1      fvdl 		}
    474   1.1      fvdl 		sector++;
    475   1.1      fvdl 	}
    476   1.3    dyoung 
    477   1.1      fvdl 	fclose(rf);
    478   1.1      fvdl 	free(buf);
    479   1.1      fvdl 	return 1;
    480   1.1      fvdl }
    481   1.1      fvdl 
    482  1.10     bjh21 static void
    483  1.13  christos cd9660_write_rr(FILE *fd, cd9660node *writenode, off_t offset, off_t sector)
    484   1.1      fvdl {
    485   1.1      fvdl 	int in_ca = 0;
    486   1.1      fvdl 	struct ISO_SUSP_ATTRIBUTES *myattr;
    487   1.1      fvdl 
    488   1.1      fvdl 	offset += writenode->isoDirRecord->length[0];
    489  1.13  christos 	if (fseeko(fd, sector * diskStructure.sectorSize + offset, SEEK_SET) ==
    490  1.13  christos 	    -1)
    491  1.13  christos 		err(1, "fseeko");
    492   1.1      fvdl 	/* Offset now points at the end of the record */
    493   1.2    dyoung 	TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
    494   1.1      fvdl 		fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
    495   1.1      fvdl 
    496   1.1      fvdl 		if (!in_ca) {
    497  1.10     bjh21 			offset += CD9660_SUSP_ENTRY_SIZE(myattr);
    498  1.10     bjh21 			if (myattr->last_in_suf) {
    499   1.1      fvdl 				/*
    500   1.1      fvdl 				 * Point the offset to the start of this
    501   1.1      fvdl 				 * record's CE area
    502   1.1      fvdl 				 */
    503  1.13  christos 				if (fseeko(fd, ((off_t)diskStructure.
    504  1.13  christos 				    susp_continuation_area_start_sector *
    505  1.13  christos 				    diskStructure.sectorSize)
    506  1.10     bjh21 				    + writenode->susp_entry_ce_start,
    507  1.13  christos 				    SEEK_SET) == -1)
    508  1.13  christos 					err(1, "fseeko");
    509   1.1      fvdl 				in_ca = 1;
    510   1.1      fvdl 			}
    511   1.1      fvdl 		}
    512   1.1      fvdl 	}
    513   1.1      fvdl 
    514  1.10     bjh21 	/*
    515  1.12   mbalmer 	 * If we had to go to the continuation area, head back to
    516  1.10     bjh21 	 * where we should be.
    517  1.10     bjh21 	 */
    518  1.10     bjh21 	if (in_ca)
    519  1.13  christos 		if (fseeko(fd, sector * diskStructure.sectorSize + offset,
    520  1.13  christos 		    SEEK_SET) == -1)
    521  1.13  christos 			err(1, "fseeko");
    522   1.1      fvdl }
    523