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