1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Libbrasero-media
4  * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5  *
6  * Libbrasero-media is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * The Libbrasero-media authors hereby grant permission for non-GPL compatible
12  * GStreamer plugins to be used and distributed together with GStreamer
13  * and Libbrasero-media. This permission is above and beyond the permissions granted
14  * by the GPL license by which Libbrasero-media is covered. If you modify this code
15  * you may extend this exception to your version of the code, but you are not
16  * obligated to do so. If you do not wish to do so, delete this exception
17  * statement from your version.
18  *
19  * Libbrasero-media is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to:
26  * 	The Free Software Foundation, Inc.,
27  * 	51 Franklin Street, Fifth Floor
28  * 	Boston, MA  02110-1301, USA.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34 
35 #include <errno.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 
39 #include "burn-volume-source.h"
40 #include "burn-iso9660.h"
41 #include "brasero-media.h"
42 #include "brasero-media-private.h"
43 
44 #include "scsi-mmc1.h"
45 #include "scsi-mmc2.h"
46 #include "scsi-sbc.h"
47 
48 static gint64
brasero_volume_source_seek_device_handle(BraseroVolSrc * src,guint block,gint whence,GError ** error)49 brasero_volume_source_seek_device_handle (BraseroVolSrc *src,
50 					  guint block,
51 					  gint whence,
52 					  GError **error)
53 {
54 	gint64 oldpos;
55 
56 	oldpos = src->position;
57 
58 	if (whence == SEEK_CUR)
59 		src->position += block;
60 	else if (whence == SEEK_SET)
61 		src->position = block;
62 
63 	return oldpos;
64 }
65 
66 static gint64
brasero_volume_source_seek_fd(BraseroVolSrc * src,guint block,int whence,GError ** error)67 brasero_volume_source_seek_fd (BraseroVolSrc *src,
68 			       guint block,
69 			       int whence,
70 			       GError **error)
71 {
72 	gint64 oldpos;
73 
74 	oldpos = ftello (src->data);
75 	if (fseeko (src->data, (guint64) (block * ISO9660_BLOCK_SIZE), whence) == -1) {
76 		int errsv = errno;
77 
78 		BRASERO_MEDIA_LOG ("fseeko () failed at block %i (= %lli bytes) (%s)",
79 				   block,
80 				   (guint64) (block * ISO9660_BLOCK_SIZE),
81 				   g_strerror (errsv));
82 		g_set_error (error,
83 			     BRASERO_MEDIA_ERROR,
84 			     BRASERO_MEDIA_ERROR_GENERAL,
85 			     "%s",
86 			     g_strerror (errsv));
87 		return -1;
88 	}
89 
90 	return oldpos / ISO9660_BLOCK_SIZE;
91 }
92 
93 static gboolean
brasero_volume_source_read_fd(BraseroVolSrc * src,gchar * buffer,guint blocks,GError ** error)94 brasero_volume_source_read_fd (BraseroVolSrc *src,
95 			       gchar *buffer,
96 			       guint blocks,
97 			       GError **error)
98 {
99 	guint64 bytes_read;
100 
101 	BRASERO_MEDIA_LOG ("Using fread()");
102 
103 	bytes_read = fread (buffer, 1, ISO9660_BLOCK_SIZE * blocks, src->data);
104 	if (bytes_read != ISO9660_BLOCK_SIZE * blocks) {
105 		int errsv = errno;
106 
107 		BRASERO_MEDIA_LOG ("fread () failed (%s)", g_strerror (errsv));
108 		g_set_error (error,
109 			     BRASERO_MEDIA_ERROR,
110 			     BRASERO_MEDIA_ERROR_GENERAL,
111 			     "%s",
112 			     g_strerror (errsv));
113 		return FALSE;
114 	}
115 
116 	return TRUE;
117 }
118 
119 static gboolean
brasero_volume_source_readcd_device_handle(BraseroVolSrc * src,gchar * buffer,guint blocks,GError ** error)120 brasero_volume_source_readcd_device_handle (BraseroVolSrc *src,
121 					    gchar *buffer,
122 					    guint blocks,
123 					    GError **error)
124 {
125 	BraseroScsiResult result;
126 	BraseroScsiErrCode code;
127 
128 	BRASERO_MEDIA_LOG ("Using READCD. Reading with track mode %i", src->data_mode);
129 	result = brasero_mmc1_read_block (src->data,
130 					  TRUE,
131 					  src->data_mode,
132 					  BRASERO_SCSI_BLOCK_HEADER_NONE,
133 					  BRASERO_SCSI_BLOCK_NO_SUBCHANNEL,
134 					  src->position,
135 					  blocks,
136 					  (unsigned char *) buffer,
137 					  blocks * ISO9660_BLOCK_SIZE,
138 					  &code);
139 	if (result == BRASERO_SCSI_OK) {
140 		src->position += blocks;
141 		return TRUE;
142 	}
143 
144 	/* Give it a last chance if the code is BRASERO_SCSI_INVALID_TRACK_MODE */
145 	if (code == BRASERO_SCSI_INVALID_TRACK_MODE) {
146 		BRASERO_MEDIA_LOG ("Wrong track mode autodetecting mode for block %i",
147 				  src->position);
148 
149 		for (src->data_mode = BRASERO_SCSI_BLOCK_TYPE_CDDA;
150 		     src->data_mode <= BRASERO_SCSI_BLOCK_TYPE_MODE2_FORM2;
151 		     src->data_mode ++) {
152 			BRASERO_MEDIA_LOG ("Re-trying with track mode %i", src->data_mode);
153 			result = brasero_mmc1_read_block (src->data,
154 							  TRUE,
155 							  src->data_mode,
156 							  BRASERO_SCSI_BLOCK_HEADER_NONE,
157 							  BRASERO_SCSI_BLOCK_NO_SUBCHANNEL,
158 							  src->position,
159 							  blocks,
160 							  (unsigned char *) buffer,
161 							  blocks * ISO9660_BLOCK_SIZE,
162 							  &code);
163 
164 			if (result == BRASERO_SCSI_OK) {
165 				src->position += blocks;
166 				return TRUE;
167 			}
168 
169 			if (code != BRASERO_SCSI_INVALID_TRACK_MODE) {
170 				BRASERO_MEDIA_LOG ("Failed with error code %i", code);
171 				src->data_mode = BRASERO_SCSI_BLOCK_TYPE_ANY;
172 				break;
173 			}
174 		}
175 	}
176 
177 	g_set_error (error,
178 		     BRASERO_MEDIA_ERROR,
179 		     BRASERO_MEDIA_ERROR_GENERAL,
180 		     "%s",
181 		     brasero_scsi_strerror (code));
182 
183 	return FALSE;
184 }
185 
186 static gboolean
brasero_volume_source_read10_device_handle(BraseroVolSrc * src,gchar * buffer,guint blocks,GError ** error)187 brasero_volume_source_read10_device_handle (BraseroVolSrc *src,
188 					    gchar *buffer,
189 					    guint blocks,
190 					    GError **error)
191 {
192 	BraseroScsiResult result;
193 	BraseroScsiErrCode code;
194 
195 	BRASERO_MEDIA_LOG ("Using READ10");
196 	result = brasero_sbc_read10_block (src->data,
197 					   src->position,
198 					   blocks,
199 					   (unsigned char *) buffer,
200 					   blocks * ISO9660_BLOCK_SIZE,
201 					   &code);
202 	if (result == BRASERO_SCSI_OK) {
203 		src->position += blocks;
204 		return TRUE;
205 	}
206 
207 	BRASERO_MEDIA_LOG ("READ10 failed %s at %i",
208 			  brasero_scsi_strerror (code),
209 			  src->position);
210 	g_set_error (error,
211 		     BRASERO_MEDIA_ERROR,
212 		     BRASERO_MEDIA_ERROR_GENERAL,
213 		     "%s",
214 		     brasero_scsi_strerror (code));
215 
216 	return FALSE;
217 }
218 
219 void
brasero_volume_source_close(BraseroVolSrc * src)220 brasero_volume_source_close (BraseroVolSrc *src)
221 {
222 	src->ref --;
223 	if (src->ref > 0)
224 		return;
225 
226 	if (src->seek == brasero_volume_source_seek_fd)
227 		fclose (src->data);
228 
229 	g_free (src);
230 }
231 
232 BraseroVolSrc *
brasero_volume_source_open_file(const gchar * path,GError ** error)233 brasero_volume_source_open_file (const gchar *path,
234 				 GError **error)
235 {
236 	BraseroVolSrc *src;
237 	FILE *file;
238 
239 	file = fopen (path, "r");
240 	if (!file) {
241 		int errsv = errno;
242 
243 		BRASERO_MEDIA_LOG ("open () failed (%s)", g_strerror (errsv));
244 		g_set_error (error,
245 			     BRASERO_MEDIA_ERROR,
246 			     BRASERO_MEDIA_ERROR_GENERAL,
247 			     "%s",
248 			     g_strerror (errsv));
249 		return FALSE;
250 	}
251 
252 	src = g_new0 (BraseroVolSrc, 1);
253 	src->ref = 1;
254 	src->data = file;
255 	src->seek = brasero_volume_source_seek_fd;
256 	src->read = brasero_volume_source_read_fd;
257 	return src;
258 }
259 
260 BraseroVolSrc *
brasero_volume_source_open_fd(int fd,GError ** error)261 brasero_volume_source_open_fd (int fd,
262 			       GError **error)
263 {
264 	BraseroVolSrc *src;
265 	int dup_fd;
266 	FILE *file;
267 
268 	dup_fd = dup (fd);
269 	if (dup_fd == -1) {
270 		int errsv = errno;
271 
272 		BRASERO_MEDIA_LOG ("dup () failed (%s)", g_strerror (errsv));
273 		g_set_error (error,
274 			     BRASERO_MEDIA_ERROR,
275 			     BRASERO_MEDIA_ERROR_GENERAL,
276 			     "%s",
277 			     g_strerror (errsv));
278 		return FALSE;
279 	}
280 
281 	file = fdopen (dup_fd, "r");
282 	if (!file) {
283 		int errsv = errno;
284 
285 		close (dup_fd);
286 
287 		BRASERO_MEDIA_LOG ("fdopen () failed (%s)", g_strerror (errsv));
288 		g_set_error (error,
289 			     BRASERO_MEDIA_ERROR,
290 			     BRASERO_MEDIA_ERROR_GENERAL,
291 			     "%s",
292 			     g_strerror (errsv));
293 		return FALSE;
294 	}
295 
296 	src = g_new0 (BraseroVolSrc, 1);
297 	src->ref = 1;
298 	src->data = file;
299 	src->seek = brasero_volume_source_seek_fd;
300 	src->read = brasero_volume_source_read_fd;
301 	return src;
302 }
303 
304 BraseroVolSrc *
brasero_volume_source_open_device_handle(BraseroDeviceHandle * handle,GError ** error)305 brasero_volume_source_open_device_handle (BraseroDeviceHandle *handle,
306 					  GError **error)
307 {
308 	int size;
309 	BraseroVolSrc *src;
310 	BraseroScsiResult result;
311 	BraseroScsiGetConfigHdr *hdr = NULL;
312 
313 	g_return_val_if_fail (handle != NULL, NULL);
314 
315 	src = g_new0 (BraseroVolSrc, 1);
316 	src->ref = 1;
317 	src->data = handle;
318 	src->seek = brasero_volume_source_seek_device_handle;
319 
320 	/* check which read function should be used. */
321 	result = brasero_mmc2_get_configuration_feature (handle,
322 							 BRASERO_SCSI_FEAT_RD_CD,
323 							 &hdr,
324 							 &size,
325 							 NULL);
326 	if (result == BRASERO_SCSI_OK && hdr->desc->current) {
327 		BRASERO_MEDIA_LOG ("READ CD current. Using READCD");
328 		src->read = brasero_volume_source_readcd_device_handle;
329 		g_free (hdr);
330 		return src;
331 	}
332 
333 	/* clean and retry */
334 	g_free (hdr);
335 	hdr = NULL;
336 
337 	result = brasero_mmc2_get_configuration_feature (handle,
338 							 BRASERO_SCSI_FEAT_RD_RANDOM,
339 							 &hdr,
340 							 &size,
341 							 NULL);
342 	if (result == BRASERO_SCSI_OK && hdr->desc->current) {
343 		BRASERO_MEDIA_LOG ("READ DVD current. Using READ10");
344 		src->read = brasero_volume_source_read10_device_handle;
345 		g_free (hdr);
346 	}
347 	else {
348 		BRASERO_MEDIA_LOG ("READ DVD not current. Using READCD.");
349 		src->read = brasero_volume_source_readcd_device_handle;
350 		g_free (hdr);
351 	}
352 
353 	return src;
354 }
355 
356 void
brasero_volume_source_ref(BraseroVolSrc * vol)357 brasero_volume_source_ref (BraseroVolSrc *vol)
358 {
359 	vol->ref ++;
360 }
361 
362