1 /* @(#)stream.c	1.17 15/12/08 Copyright 2002-2015 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)stream.c	1.17 15/12/08 Copyright 2002-2015 J. Schilling";
6 #endif
7 /*
8  *	ISO-9660 stream (pipe) file module for mkisofs
9  *
10  *	Copyright (c) 2002-2015 J. Schilling
11  *	Implemented after an idea from M.H. Voase
12  */
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2
16  * as published by the Free Software Foundation.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along with
24  * this program; see the file COPYING.  If not, write to the Free Software
25  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  */
27 
28 #include "mkisofs.h"
29 #include "iso9660.h"
30 #include <schily/schily.h>
31 
32 LOCAL int	size_str_file	__PR((UInt32_t starting_extent));
33 LOCAL int	size_str_dir	__PR((UInt32_t starting_extent));
34 LOCAL int	size_str_path	__PR((UInt32_t starting_extent));
35 
36 LOCAL int	gen_str_path	__PR((void));
37 
38 LOCAL int	write_str_file	__PR((FILE *outfile));
39 LOCAL int	write_str_dir	__PR((FILE *outfile));
40 LOCAL int	write_str_path	__PR((FILE *outfile));
41 
42 extern int		stream_media_size;
43 extern char		*stream_filename;
44 extern time_t		begun;
45 
46 LOCAL unsigned int	avail_extent;
47 LOCAL unsigned int	stream_extent;
48 LOCAL unsigned int	stream_size;
49 LOCAL unsigned int	stream_pad;
50 LOCAL char		*l_path;
51 LOCAL char		*m_path;
52 LOCAL struct iso_directory_record s_dir;
53 LOCAL int		stream_finished = 0;
54 
55 /*
56  * Compute the size of the file
57  */
58 LOCAL int
size_str_file(starting_extent)59 size_str_file(starting_extent)
60 	UInt32_t	starting_extent;
61 {
62 	int	n;
63 extern	int	dopad;
64 
65 	stream_extent = last_extent;	/* Start of stream file content */
66 
67 	avail_extent = stream_media_size;
68 	n = last_extent;		/* Room for FS blocks before file */
69 	n += 1;				/* Room for the directory block */
70 	stream_pad = 0;
71 	if (n < 50) {
72 		stream_pad = 50 - n;
73 		n = 50;			/* Make net. size easy to compute */
74 	}
75 	if (dopad)
76 		n += 150;		/* Room for final padding */
77 
78 	if (n >= avail_extent) {
79 		comerrno(EX_BAD,
80 			_("-stream-media-size %d but must be at least %d\n"),
81 			avail_extent, n+2);
82 	}
83 	avail_extent -= n;
84 
85 	last_extent += avail_extent + stream_pad;
86 
87 	return (0);
88 }
89 
90 /*
91  * The size of the directory record - one sector
92  */
93 LOCAL int
size_str_dir(starting_extent)94 size_str_dir(starting_extent)
95 	UInt32_t	starting_extent;
96 {
97 	root->extent = last_extent;
98 	last_extent += 1;
99 	return (0);
100 }
101 
102 /*
103  * The size of the path tables - two sectors
104  */
105 LOCAL int
size_str_path(starting_extent)106 size_str_path(starting_extent)
107 	UInt32_t	starting_extent;
108 {
109 	path_table[0] = starting_extent;
110 	path_table[1] = 0;
111 	path_table[2] = path_table[0] + 1;
112 	path_table[3] = 0;
113 	last_extent += 2 * 1;
114 	return (0);
115 }
116 
117 /*
118  * Generate the path table data
119  */
120 LOCAL int
gen_str_path()121 gen_str_path()
122 {
123 	/*
124 	 * Basically add the root directory entry
125 	 */
126 	l_path = (char *)e_malloc(SECTOR_SIZE);
127 	m_path = (char *)e_malloc(SECTOR_SIZE);
128 	memset(l_path, 0, SECTOR_SIZE);
129 	memset(m_path, 0, SECTOR_SIZE);
130 	l_path[0] = 1;
131 	m_path[0] = 1;
132 	set_731(l_path + 2, root->extent);
133 	set_732(m_path + 2, root->extent);
134 	set_721(l_path + 6, 1);
135 	set_722(m_path + 6, 1);
136 	l_path[8] = '\0'; l_path[9] = '\0';
137 	m_path[8] = '\0'; m_path[9] = '\0';
138 	return (0);
139 }
140 
141 /*
142  * Write the file content
143  */
144 LOCAL int
write_str_file(outfile)145 write_str_file(outfile)
146 	FILE	*outfile;
147 {
148 	unsigned int	idx = 0;
149 	unsigned int	iso_blocks;
150 	int		count;
151 	char		*buf;
152 
153 	buf = e_malloc(SECTOR_SIZE);
154 	stream_size = 0;
155 	while ((idx + SECTOR_SIZE) < (avail_extent * SECTOR_SIZE)) {
156 		memset(buf, 0, SECTOR_SIZE);
157 		count = fread(buf, 1, SECTOR_SIZE, stdin);
158 		if (count <= 0) {
159 			stream_finished = 1;
160 			break;
161 		}
162 		idx += count;
163 		xfwrite(buf, count, 1, outfile, 0, FALSE);
164 	}
165 
166 	stream_size = idx;
167 	iso_blocks = ISO_BLOCKS(idx);
168 	memset(buf, 0, SECTOR_SIZE);
169 	if (SECTOR_SIZE * iso_blocks - idx)
170 		xfwrite(buf, SECTOR_SIZE * iso_blocks - idx, 1, outfile, 0, FALSE);
171 	/*
172 	 * If we didn't fill the available area, pad to directory block
173 	 */
174 	for (count = 0; count < (avail_extent - iso_blocks); count++)
175 		xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
176 
177 	for (count = 0; count < stream_pad; count++)
178 		xfwrite(buf, SECTOR_SIZE, 1, outfile, 0, FALSE);
179 
180 	last_extent_written += avail_extent + stream_pad;
181 	free(buf);
182 	return (0);
183 }
184 
185 /*
186  * Generate and write the directory record data
187  */
188 LOCAL int
write_str_dir(outfile)189 write_str_dir(outfile)
190 	FILE	*outfile;
191 {
192 	int	reclen;
193 	char	*buf;
194 
195 	buf = e_malloc(SECTOR_SIZE); memset(buf, 0, SECTOR_SIZE);
196 	memset(&s_dir, 0, sizeof (struct iso_directory_record));
197 	s_dir.length[0] = 34;			/* BAD: Hardcoded - Will fix, MHV */
198 	s_dir.ext_attr_length[0] = 0;
199 	set_733((char *)s_dir.extent, root->extent);
200 	set_733((char *)s_dir.size, SECTOR_SIZE);
201 	iso9660_date(s_dir.date, begun);
202 	s_dir.flags[0] = ISO_DIRECTORY;
203 	s_dir.file_unit_size[0] = 0;
204 	s_dir.interleave[0] = 0;
205 	set_723((char *)s_dir.volume_sequence_number, volume_sequence_number);
206 	s_dir.name_len[0] = 1;
207 	s_dir.name[0] = 0;	/* "." */
208 	xfwrite(&s_dir, offsetof(struct iso_directory_record, name[0]) + 1, 1, outfile, 0, FALSE);
209 	s_dir.name[0] = 1;	/* ".." */
210 	xfwrite(&s_dir, offsetof(struct iso_directory_record, name[0]) + 1, 1, outfile, 0, FALSE);
211 	memset(&s_dir, 0, sizeof (struct iso_directory_record));
212 	reclen = offsetof(struct iso_directory_record, name[0]) +
213 				strlen(stream_filename);
214 	if (reclen & 1)
215 		reclen++;
216 	s_dir.length[0] = reclen;
217 	s_dir.ext_attr_length[0] = 0;
218 	set_733((char *)s_dir.extent, stream_extent);
219 	set_733((char *)s_dir.size, stream_size);
220 	iso9660_date(s_dir.date, begun);
221 	s_dir.flags[0] = 0;
222 	s_dir.file_unit_size[0] = 0;
223 	set_723((char *)s_dir.volume_sequence_number, volume_sequence_number);
224 	s_dir.name_len[0] = strlen(stream_filename);
225 	memcpy(s_dir.name, stream_filename, s_dir.name_len[0]);
226 	xfwrite(&s_dir, reclen, 1, outfile, 0, FALSE);
227 
228 	/*
229 	 * This calc is: 2 single char directory entries (34) + an additional entry
230 	 * with filename length stream_filename + round up for even lenght count
231 	 */
232 	xfwrite(buf, SECTOR_SIZE - ((2 * 34) + reclen), 1, outfile, 0, FALSE);
233 	free(buf);
234 	last_extent_written++;
235 	return (0);
236 }
237 
238 /*
239  * Generate the path table data
240  */
241 LOCAL int
write_str_path(outfile)242 write_str_path(outfile)
243 	FILE	*outfile;
244 {
245 	xfwrite(l_path, SECTOR_SIZE, 1, outfile, 0, FALSE);
246 	xfwrite(m_path, SECTOR_SIZE, 1, outfile, 0, FALSE);
247 	last_extent_written += 2;
248 	free(l_path);
249 	free(m_path);
250 	path_table_l = NULL;
251 	path_table_m = NULL;
252 	return (0);
253 }
254 
255 struct output_fragment strfile_desc  = { NULL, size_str_file, NULL,	   write_str_file, "Stream File" };
256 struct output_fragment strdir_desc  = { NULL, size_str_dir,  NULL,	   write_str_dir,  "Stream File Directory"  };
257 struct output_fragment strpath_desc = { NULL, size_str_path, gen_str_path, write_str_path, "Stream File Path table" };
258