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 <string.h>
37 #include <stdio.h>
38 #include <unistd.h>
39
40 #include <glib.h>
41 #include <glib/gi18n-lib.h>
42
43 #include "burn-volume-source.h"
44 #include "burn-volume.h"
45 #include "burn-iso9660.h"
46 #include "brasero-media.h"
47 #include "brasero-media-private.h"
48 #include "brasero-units.h"
49
50 struct _BraseroTagDesc {
51 guint16 id;
52 guint16 version;
53 guchar checksum;
54 guchar reserved;
55 guint16 serial;
56 guint16 crc;
57 guint16 crc_len;
58 guint32 location;
59 };
60 typedef struct _BraseroTagDesc BraseroTagDesc;
61
62 struct _BraseroAnchorDesc {
63 BraseroTagDesc tag;
64
65 guchar main_extent [8];
66 guchar reserve_extent [8];
67 };
68 typedef struct _BraseroAnchorDesc BraseroAnchorDesc;
69
70 #define SYSTEM_AREA_SECTORS 16
71 #define ANCHOR_AREA_SECTORS 256
72
73
74 void
brasero_volume_file_free(BraseroVolFile * file)75 brasero_volume_file_free (BraseroVolFile *file)
76 {
77 if (!file)
78 return;
79
80 if (file->isdir) {
81 GList *iter;
82
83 if (file->isdir_loaded) {
84 for (iter = file->specific.dir.children; iter; iter = iter->next)
85 brasero_volume_file_free (iter->data);
86
87 g_list_free (file->specific.dir.children);
88 }
89 }
90 else {
91 g_slist_foreach (file->specific.file.extents,
92 (GFunc) g_free,
93 NULL);
94 g_slist_free (file->specific.file.extents);
95 }
96
97 g_free (file->rr_name);
98 g_free (file->name);
99 g_free (file);
100 }
101
102 static gboolean
brasero_volume_get_primary_from_file(BraseroVolSrc * vol,gchar * primary_vol,GError ** error)103 brasero_volume_get_primary_from_file (BraseroVolSrc *vol,
104 gchar *primary_vol,
105 GError **error)
106 {
107 BraseroVolDesc *desc;
108
109 /* skip the first 16 blocks */
110 if (BRASERO_VOL_SRC_SEEK (vol, SYSTEM_AREA_SECTORS, SEEK_CUR, error) == -1)
111 return FALSE;
112
113 if (!BRASERO_VOL_SRC_READ (vol, primary_vol, 1, error))
114 return FALSE;
115
116 /* make a few checks to ensure this is an ECMA volume */
117 desc = (BraseroVolDesc *) primary_vol;
118 if (memcmp (desc->id, "CD001", 5)
119 && memcmp (desc->id, "BEA01", 5)
120 && memcmp (desc->id, "BOOT2", 5)
121 && memcmp (desc->id, "CDW02", 5)
122 && memcmp (desc->id, "NSR02", 5) /* usually UDF */
123 && memcmp (desc->id, "NSR03", 5) /* usually UDF */
124 && memcmp (desc->id, "TEA01", 5)) {
125 g_set_error (error,
126 BRASERO_MEDIA_ERROR,
127 BRASERO_MEDIA_ERROR_IMAGE_INVALID,
128 _("It does not appear to be a valid ISO image"));
129 BRASERO_MEDIA_LOG ("Wrong volume descriptor, got %.5s", desc->id);
130 return FALSE;
131 }
132
133 return TRUE;
134 }
135
136 gboolean
brasero_volume_get_size(BraseroVolSrc * vol,gint64 block,gint64 * nb_blocks,GError ** error)137 brasero_volume_get_size (BraseroVolSrc *vol,
138 gint64 block,
139 gint64 *nb_blocks,
140 GError **error)
141 {
142 gboolean result;
143 gchar buffer [ISO9660_BLOCK_SIZE];
144
145 if (block && BRASERO_VOL_SRC_SEEK (vol, block, SEEK_SET, error) == -1)
146 return FALSE;
147
148 result = brasero_volume_get_primary_from_file (vol, buffer, error);
149 if (!result)
150 return FALSE;
151
152 if (!brasero_iso9660_is_primary_descriptor (buffer, error))
153 return FALSE;
154
155 return brasero_iso9660_get_size (buffer, nb_blocks, error);
156 }
157
158 BraseroVolFile *
brasero_volume_get_files(BraseroVolSrc * vol,gint64 block,gchar ** label,gint64 * nb_blocks,gint64 * data_blocks,GError ** error)159 brasero_volume_get_files (BraseroVolSrc *vol,
160 gint64 block,
161 gchar **label,
162 gint64 *nb_blocks,
163 gint64 *data_blocks,
164 GError **error)
165 {
166 gchar buffer [ISO9660_BLOCK_SIZE];
167
168 if (BRASERO_VOL_SRC_SEEK (vol, block, SEEK_SET, error) == -1)
169 return FALSE;
170
171 if (!brasero_volume_get_primary_from_file (vol, buffer, error))
172 return NULL;
173
174 if (!brasero_iso9660_is_primary_descriptor (buffer, error))
175 return NULL;
176
177 if (label
178 && !brasero_iso9660_get_label (buffer, label, error))
179 return NULL;
180
181 if (nb_blocks
182 && !brasero_iso9660_get_size (buffer, nb_blocks, error))
183 return NULL;
184
185 return brasero_iso9660_get_contents (vol,
186 buffer,
187 data_blocks,
188 error);
189 }
190
191 GList *
brasero_volume_load_directory_contents(BraseroVolSrc * vol,gint64 session_block,gint64 block,GError ** error)192 brasero_volume_load_directory_contents (BraseroVolSrc *vol,
193 gint64 session_block,
194 gint64 block,
195 GError **error)
196 {
197 gchar buffer [ISO9660_BLOCK_SIZE];
198
199 if (BRASERO_VOL_SRC_SEEK (vol, session_block, SEEK_SET, error) == -1)
200 return FALSE;
201
202 if (!brasero_volume_get_primary_from_file (vol, buffer, error))
203 return NULL;
204
205 if (!brasero_iso9660_is_primary_descriptor (buffer, error))
206 return NULL;
207
208 return brasero_iso9660_get_directory_contents (vol,
209 buffer,
210 block,
211 error);
212 }
213
214 BraseroVolFile *
brasero_volume_get_file(BraseroVolSrc * vol,const gchar * path,gint64 volume_start_block,GError ** error)215 brasero_volume_get_file (BraseroVolSrc *vol,
216 const gchar *path,
217 gint64 volume_start_block,
218 GError **error)
219 {
220 gchar buffer [ISO9660_BLOCK_SIZE];
221
222 if (BRASERO_VOL_SRC_SEEK (vol, volume_start_block, SEEK_SET, error) == -1)
223 return NULL;
224
225 if (!brasero_volume_get_primary_from_file (vol, buffer, error))
226 return NULL;
227
228 if (!brasero_iso9660_is_primary_descriptor (buffer, error))
229 return NULL;
230
231 return brasero_iso9660_get_file (vol, path, buffer, error);
232 }
233
234 gchar *
brasero_volume_file_to_path(BraseroVolFile * file)235 brasero_volume_file_to_path (BraseroVolFile *file)
236 {
237 GString *path;
238 BraseroVolFile *parent;
239 GSList *components = NULL, *iter, *next;
240
241 if (!file)
242 return NULL;
243
244 /* make a list of all the components of the path by going up to root */
245 parent = file->parent;
246 while (parent && parent->name) {
247 components = g_slist_prepend (components, BRASERO_VOLUME_FILE_NAME (parent));
248 parent = parent->parent;
249 }
250
251 if (!components)
252 return NULL;
253
254 path = g_string_new (NULL);
255 for (iter = components; iter; iter = next) {
256 gchar *name;
257
258 name = iter->data;
259 next = iter->next;
260 components = g_slist_remove (components, name);
261
262 g_string_append_c (path, G_DIR_SEPARATOR);
263 g_string_append (path, name);
264 }
265
266 g_slist_free (components);
267 return g_string_free (path, FALSE);
268 }
269
270 BraseroVolFile *
brasero_volume_file_from_path(const gchar * ptr,BraseroVolFile * parent)271 brasero_volume_file_from_path (const gchar *ptr,
272 BraseroVolFile *parent)
273 {
274 GList *iter;
275 gchar *next;
276 gint len;
277
278 /* first determine the name of the directory / file to look for */
279 if (!ptr || ptr [0] != '/' || !parent)
280 return NULL;
281
282 ptr ++;
283 next = g_utf8_strchr (ptr, -1, G_DIR_SEPARATOR);
284 if (!next)
285 len = strlen (ptr);
286 else
287 len = next - ptr;
288
289 for (iter = parent->specific.dir.children; iter; iter = iter->next) {
290 BraseroVolFile *file;
291
292 file = iter->data;
293 if (!strncmp (ptr, BRASERO_VOLUME_FILE_NAME (file), len)) {
294 /* we've found it seek for the next if any */
295 if (!next)
296 return file;
297
298 ptr = next;
299 return brasero_volume_file_from_path (ptr, file);
300 }
301 }
302
303 return NULL;
304 }
305
306 gint64
brasero_volume_file_size(BraseroVolFile * file)307 brasero_volume_file_size (BraseroVolFile *file)
308 {
309 GList *iter;
310 gint64 size = 0;
311
312 if (!file->isdir) {
313 GSList *extents;
314
315 for (extents = file->specific.file.extents; extents; extents = extents->next) {
316 BraseroVolFileExtent *extent;
317
318 extent = extents->data;
319 size += extent->size;
320 }
321 return BRASERO_BYTES_TO_SECTORS (size, 2048);
322 }
323
324 for (iter = file->specific.dir.children; iter; iter = iter->next) {
325 file = iter->data;
326
327 if (file->isdir)
328 size += brasero_volume_file_size (file);
329 else
330 size += BRASERO_BYTES_TO_SECTORS (file->specific.file.size_bytes, 2048);
331 }
332
333 return size;
334 }
335
336 BraseroVolFile *
brasero_volume_file_merge(BraseroVolFile * file1,BraseroVolFile * file2)337 brasero_volume_file_merge (BraseroVolFile *file1,
338 BraseroVolFile *file2)
339 {
340 file1->specific.file.size_bytes += file2->specific.file.size_bytes;
341 file1->specific.file.extents = g_slist_concat (file1->specific.file.extents,
342 file2->specific.file.extents);
343
344 file2->specific.file.extents = NULL;
345 brasero_volume_file_free (file2);
346
347 return file1;
348 }
349
350