1 /***************************************************************************
2 * Copyright (C) 2007 by Arep *
3 * Support is provided through the forums at *
4 * http://www.console-tribe.com *
6 * This program 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. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20 ***************************************************************************/
25 #include <multihash.h>
26 #include "constants.h"
32 #include <sys/types.h>
38 u_int32_t start_sector_raw
;
41 u_int32_t start_sector_iso
;
43 u_int32_t start_sector
;
50 progress_func progress
;
56 * Tries to open the output file for writing and to find out if it contains valid data so that the dump can continue.
59 * @param[out] fp The file pointer to write to.
60 * @param[out] start_sector The sector to start reading from.
61 * @return true if the dumping can start/continue, false otherwise (for instance if outfile cannot be written to).
63 bool dumper_set_raw_output_file (dumper
*dmp
, char *outfile_raw
, bool resume
) {
69 /* Raw output disabled */
71 dmp
-> start_sector_raw
= -1;
72 my_free (dmp
-> outfile_raw
);
73 dmp
-> outfile_raw
= NULL
;
74 } else if (dmp
-> outfile_raw
) {
75 error ("Raw output file already defined");
77 } else if (!(fp
= fopen (outfile_raw
, "rb"))) { /** @todo Maybe we could not open file for permission problems */
78 /* Raw output file does not exist, start from scratch */
80 dmp
-> start_sector_raw
= 0;
81 my_strdup (dmp
-> outfile_raw
, outfile_raw
);
83 /* Raw output file exists and resume was requested, so see how many dumped sectors it contains */
84 my_fseek (fp
, 0, SEEK_END
);
85 filesize
= my_ftell (fp
);
88 dmp
-> start_sector_raw
= (u_int32_t
) (filesize
/ RAW_SECTOR_SIZE
/ SECTORS_PER_BLOCK
) * SECTORS_PER_BLOCK
;
89 debug ("Raw output can restart from sector %u", dmp
-> start_sector_raw
);
90 my_strdup (dmp
-> outfile_raw
, outfile_raw
);
92 /* Raw output file exists but resume was not requested, error */
94 error ("Raw output file exists, but resume was not requested.");
96 dmp
-> start_sector_raw
= -1;
97 my_free (dmp
-> outfile_raw
);
98 dmp
-> outfile_raw
= NULL
;
105 bool dumper_set_iso_output_file (dumper
*dmp
, char *outfile_iso
, bool resume
) {
111 /* Raw output disabled */
113 dmp
-> start_sector_iso
= -1;
114 my_free (dmp
-> outfile_iso
);
115 dmp
-> outfile_iso
= NULL
;
116 } else if (dmp
-> outfile_iso
) {
117 error ("ISO output file already defined");
119 } else if (!(fp
= fopen (outfile_iso
, "rb"))) { /** @todo Maybe we could not open file for permission problems */
120 /* Raw output file does not exist, start from scratch */
122 dmp
-> start_sector_iso
= 0;
123 my_strdup (dmp
-> outfile_iso
, outfile_iso
);
125 /* Raw output file exists and resume was requested, so see how many dumped sectors it contains */
126 my_fseek (fp
, 0, SEEK_END
);
127 filesize
= my_ftell (fp
);
130 dmp
-> start_sector_iso
= (u_int32_t
) (filesize
/ SECTOR_SIZE
/ SECTORS_PER_BLOCK
) * SECTORS_PER_BLOCK
;
131 debug ("ISO output can restart from sector %u", dmp
-> start_sector_iso
);
132 my_strdup (dmp
-> outfile_iso
, outfile_iso
);
134 /* Raw output file exists but resume was not requested, error */
136 error ("ISO output file exists, but resume was not requested.");
138 dmp
-> start_sector_iso
= -1;
139 my_free (dmp
-> outfile_iso
);
140 dmp
-> outfile_iso
= NULL
;
147 bool dumper_prepare (dumper
*dmp
) {
149 u_int8_t buf
[RAW_SECTOR_SIZE
];
153 /* Outputting to both files, resume must start from the file with the least sectors. Hopefully they will have the same number of sectors, anyway... */
154 if (dmp
-> outfile_raw
&& dmp
-> outfile_iso
&& dmp
-> start_sector_raw
!= dmp
-> start_sector_iso
) {
155 if (dmp
-> start_sector_raw
< dmp
-> start_sector_iso
)
156 dmp
-> start_sector
= dmp
-> start_sector_raw
;
158 dmp
-> start_sector
= dmp
-> start_sector_iso
;
159 } else if (dmp
-> outfile_raw
) {
160 dmp
-> start_sector
= dmp
-> start_sector_raw
;
161 } else if (dmp
-> outfile_iso
) {
162 dmp
-> start_sector
= dmp
-> start_sector_iso
;
168 if (dmp
-> hashing
) {
169 multihash_init (&(dmp
-> hash_raw
));
170 multihash_init (&(dmp
-> hash_iso
));
173 /* Setup raw output file */
174 if (dmp
-> outfile_raw
) {
175 dmp
-> fp_raw
= fopen (dmp
-> outfile_raw
, "a+b");
177 if (dmp
-> hashing
) {
178 debug ("Calculating hashes for pre-existing raw dump data");
179 if (dmp
-> start_sector
> 0) {
180 for (i
= 0; i
< dmp
-> start_sector
&& (r
= fread (buf
, RAW_SECTOR_SIZE
, 1, dmp
-> fp_raw
)) > 0; i
++)
181 multihash_update (&(dmp
-> hash_raw
), buf
, RAW_SECTOR_SIZE
);
186 /* Now call fseek as file will only be written, from now on */
187 if (my_fseek (dmp
-> fp_raw
, dmp
-> start_sector
* RAW_SECTOR_SIZE
, SEEK_SET
) == 0 &&
188 ftruncate (fileno (dmp
-> fp_raw
), dmp
-> start_sector
* RAW_SECTOR_SIZE
) == 0) {
190 debug ("Writing to file \"%s\" in raw format (fseeked() to %lld)", dmp
-> outfile_raw
, my_ftell (dmp
-> fp_raw
));
193 fclose (dmp
-> fp_raw
);
194 dmp
-> fp_raw
= NULL
;
197 dmp
-> fp_raw
= NULL
;
200 /* Setup ISO output file */
201 if (dmp
-> outfile_iso
) {
202 dmp
-> fp_iso
= fopen (dmp
-> outfile_iso
, "a+b");
204 if (dmp
-> hashing
) {
205 debug ("Calculating hashes for pre-existing ISO dump data");
206 if (dmp
-> start_sector
> 0) {
207 for (i
= 0; i
< dmp
-> start_sector
&& (r
= fread (buf
, SECTOR_SIZE
, 1, dmp
-> fp_iso
)) > 0; i
++)
208 multihash_update (&(dmp
-> hash_iso
), buf
, SECTOR_SIZE
);
213 if (my_fseek (dmp
-> fp_iso
, dmp
-> start_sector
* SECTOR_SIZE
, SEEK_SET
) == 0 &&
214 ftruncate (fileno (dmp
-> fp_iso
), dmp
-> start_sector
* SECTOR_SIZE
) == 0) {
216 debug ("Writing to file \"%s\" in ISO format (fseeked() to %lld)", dmp
-> outfile_iso
, my_ftell (dmp
-> fp_iso
));
219 fclose (dmp
-> fp_iso
);
220 dmp
-> fp_iso
= NULL
;
223 dmp
-> fp_iso
= NULL
;
230 int dumper_dump (dumper
*dmp
) {
232 u_int8_t
*rawbuf
, *isobuf
;
233 u_int32_t i
, sectors_no
;
235 bool no_unscrambling
;
239 no_unscrambling
= dd
-> no_unscrambling
;
240 if (fp_iso
&& no_unscrambling
) {
241 warning ("Output to ISO format requested, ignoring no_unscrambling!");
242 no_unscrambling
= false;
246 sectors_no
= disc_get_sectors_no (dmp
-> dsk
);
248 if (dd
-> start_sector
!= -1) {
249 if (dd
-> start_sector
>= sectors_no
) {
250 error ("Cannot start dumping from sector %u as the inserted disc only has %u sectors\n", dd
-> start_sector
, sectors_no
);
253 warning ("Start sector forced to %u\n", dd
-> start_sector
);
254 ss
= dd
-> start_sector
;
257 fseek (fp_iso
, ss
* 2048, SEEK_SET
);
259 fseek (fp_raw
, ss
* 2064, SEEK_SET
);
265 debug ("Starting dump process from sector %u...\n", dmp
-> start_sector
);
267 /* First call to progress function */
269 dmp
-> progress (true, dmp
-> start_sector
, sectors_no
, dmp
-> progress_data
);
271 for (i
= dmp
-> start_sector
, out
= true; i
< sectors_no
&& out
; i
++) {
272 disc_read_sector (dmp
-> dsk
, i
, &isobuf
, &rawbuf
);
275 clearerr (dmp
-> fp_raw
);
276 fwrite (rawbuf
, RAW_SECTOR_SIZE
, 1, dmp
-> fp_raw
);
277 if (ferror (dmp
-> fp_raw
)) {
278 error ("fwrite() to raw output file failed");
283 fflush (dmp
-> fp_raw
);
286 multihash_update (&(dmp
-> hash_raw
), rawbuf
, RAW_SECTOR_SIZE
);
290 clearerr (dmp
-> fp_iso
);
291 fwrite (isobuf
, SECTOR_SIZE
, 1, dmp
-> fp_iso
);
292 if (ferror (dmp
-> fp_iso
)) {
293 error ("fwrite() to ISO output file failed");
298 fflush (dmp
-> fp_iso
);
301 multihash_update (&(dmp
-> hash_iso
), isobuf
, SECTOR_SIZE
);
305 dmp
-> progress (false, i
+ 1, sectors_no
, dmp
-> progress_data
); /* i + 1 'cause sectors range from 0 to N */
308 if (dmp
-> hashing
) {
309 multihash_finish (&(dmp
-> hash_raw
));
310 multihash_finish (&(dmp
-> hash_iso
));
314 fclose (dmp
-> fp_raw
);
316 fclose (dmp
-> fp_iso
);
327 dumper
*dumper_new (disc
*d
) {
330 dmp
= (dumper
*) malloc (sizeof (dumper
));
331 memset (dmp
, 0, sizeof (dumper
));
333 dumper_set_hashing (dmp
, true);
334 dumper_set_flushing (dmp
, true);
340 void dumper_set_progress_callback (dumper
*dmp
, progress_func progress
, void *progress_data
) {
341 dmp
-> progress
= progress
;
342 dmp
-> progress_data
= progress_data
;
348 void dumper_set_hashing (dumper
*dmp
, bool h
) {
350 debug ("Hashing %s", h
? "enabled" : "disabled");
356 void dumper_set_flushing (dumper
*dmp
, bool f
) {
358 debug ("Flushing %s", f
? "enabled" : "disabled");
363 void *dumper_destroy (dumper
*dmp
) {
364 my_free (dmp
-> outfile_raw
);
365 my_free (dmp
-> outfile_iso
);
372 char *dumper_get_iso_crc32 (dumper
*dmp
) {
373 return ((dmp
-> hash_iso
).crc32_s
);
377 char *dumper_get_raw_crc32 (dumper
*dmp
) {
378 return ((dmp
-> hash_raw
).crc32_s
);
382 char *dumper_get_iso_md4 (dumper
*dmp
) {
383 return ((dmp
-> hash_iso
).md4_s
);
387 char *dumper_get_raw_md4 (dumper
*dmp
) {
388 return ((dmp
-> hash_raw
).md4_s
);
392 char *dumper_get_iso_md5 (dumper
*dmp
) {
393 return ((dmp
-> hash_iso
).md5_s
);
397 char *dumper_get_raw_md5 (dumper
*dmp
) {
398 return ((dmp
-> hash_raw
).md5_s
);
402 char *dumper_get_iso_ed2k (dumper
*dmp
) {
403 return ((dmp
-> hash_iso
).ed2k_s
);
407 char *dumper_get_raw_ed2k (dumper
*dmp
) {
408 return ((dmp
-> hash_raw
).ed2k_s
);
412 char *dumper_get_iso_sha1 (dumper
*dmp
) {
413 return ((dmp
-> hash_iso
).sha1_s
);
417 char *dumper_get_raw_sha1 (dumper
*dmp
) {
418 return ((dmp
-> hash_raw
).sha1_s
);