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