1 /* $NetBSD$ */
2 
3 /*
4  * File "udf_discinfo.c" is part of the UDFclient toolkit.
5  * File $Id: udf_discop.c,v 1.81 2017/01/16 14:33:06 reinoud Exp $ $Name:  $
6  *
7  * Copyright (c) 2003, 2004, 2005, 2006, 2011
8  * 	Reinoud Zandijk <reinoud@netbsd.org>
9  * All rights reserved.
10  *
11  * The UDFclient toolkit is distributed under the Clarified Artistic Licence.
12  * A copy of the licence is included in the distribution as
13  * `LICENCE.clearified.artistic' and a copy of the licence can also be
14  * requested at the GNU foundantion's website.
15  *
16  * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30 
31 
32 /* XXX strip this XXX */
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40 #include <unistd.h>
41 #include <assert.h>
42 #include <dirent.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <limits.h>
46 
47 #include "uscsilib.h"
48 
49 
50 /* for locals */
51 #include "uscsilib.h"
52 #include "udf_discop.h"
53 
54 
55 #ifndef MAX
56 #	define MAX(a,b) ((a)>(b)?(a):(b))
57 #	define MIN(a,b) ((a)<(b)?(a):(b))
58 #endif
59 
60 
61 /* #define DEBUG(a) { a; } */
62 #define DEBUG(a) if (0) { a; }
63 
64 
65 /* globals */
66 
67 
68 /******************************************************************************************
69  *
70  * Tables and helper functions section
71  *
72  ******************************************************************************************/
73 
read_cd_hex2(int val)74 int read_cd_hex2(int val) {
75 	int nl, nh;
76 
77 	nl = val & 15;
78 	nh = val >> 4;
79 	if (nl >= 'A') nl -= 'A' + 10;
80 	if (nh >= 'A') nh -= 'A' + 10;
81 
82 	return (nh*16) + nl;
83 }
84 
85 
read_cd_bcd(int val)86 int read_cd_bcd(int val) {
87 	int nl, nh;
88 
89 	nl = (val & 15) - '0';
90 	nh = (val >> 4) - '0';
91 	if ((nl < 0 || nl > 9) || (nh < 0 || nh > 9)) return val;
92 
93 	return nh*10 + nl;
94 }
95 
96 
cd_msf2lba(int h,int m,int s,int f)97 int32_t cd_msf2lba(int h, int m, int s, int f) {
98 	return 270000*h + 4500*m + 75*s + f - 150;
99 }
100 
101 
102 /******************************************************************************************
103  *
104  * Disc level operations
105  *
106  ******************************************************************************************/
107 
udf_discinfo_is_cd_or_dvd(struct udf_discinfo * disc)108 int udf_discinfo_is_cd_or_dvd(struct udf_discinfo *disc) {
109 	/* check device type */
110 	switch (disc->devdrv_class & UDF_DEVDRV_CLASS) {
111 		case UDF_DEVDRV_CLASS_FILE :
112 		case UDF_DEVDRV_CLASS_DISC :
113 			/* not nessisary */
114 			return 0;
115 		case UDF_DEVDRV_CLASS_CD   :
116 		case UDF_DEVDRV_CLASS_DVD  :
117 			/* it really is */
118 			return 1;
119 		default :
120 			break;
121 	}
122 	return ENODEV;
123 }
124 
125 
udf_discinfo_check_disc_ready(struct udf_discinfo * disc)126 int udf_discinfo_check_disc_ready(struct udf_discinfo *disc) {
127 	scsicmd cmd;
128 	uint8_t buf[36];
129 	int error;
130 
131 	if (!udf_discinfo_is_cd_or_dvd(disc)) return 1;
132 
133 	bzero(cmd, SCSI_CMD_LEN);
134 	cmd[0] = 0;				/* test unit ready */
135 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 6, buf, 0, 30000, NULL);
136 
137 	return (error == 0);
138 }
139 
140 
141 #define blk_len 10000
udf_discinfo_set_recording_parameters(struct udf_discinfo * discinfo,int testwriting)142 int udf_discinfo_set_recording_parameters(struct udf_discinfo *discinfo, int testwriting) {
143 	scsicmd  cmd;
144 	uint8_t  res[blk_len];
145 	uint8_t *pos;
146 	uint32_t blockingnr;
147 	int      val_len, packet;
148 	int      error;
149 
150 	if (!udf_discinfo_is_cd_or_dvd(discinfo)) return 0;
151 
152 	/* Set up CD/DVD recording parameters */
153 	if (!discinfo->recordable) return 0;
154 
155 	blockingnr = discinfo->blockingnr;
156 
157 	DEBUG(printf("Setting device's recording parameters\n"));
158 	packet = discinfo->packet;
159 
160 	val_len = 0x32+2+8;
161 	bzero(res, val_len);
162 
163 	pos = res + 8;
164 
165 	bzero(cmd, SCSI_CMD_LEN);
166 	if (!packet) {
167 		pos[ 0] = 0x05;			/* page code 5 : cd writing					*/
168 		pos[ 1] = 0x32;			/* length in bytes						*/
169 		pos[ 2] = 64 + 0;		/* BUFE + write type 1 : track at once				*/
170 		if (testwriting) pos[ 2] += 16;
171 		pos[ 3] = (3<<6) | 5;		/* next session OK, data packet, rec. incr. var packets		*/
172 		pos[ 4] = 8;			/* ISO mode 1							*/
173 		pos[ 8] = 0;			/* normal CD-DA/CD-ROM or data disc				*/
174 		DEBUG(printf("\tsetting up for sequential writing\n"));
175 	} else {
176 		pos[ 0] = 0x05;			/* page code 5 : cd writing					*/
177 		pos[ 1] = 0x32;			/* length in bytes						*/
178 		pos[ 2] = 0;			/* write type 0 : packet/incremental				*/
179 		if (testwriting) pos[ 2] += 16;
180 		pos[ 3] = (3<<6) | 32 | 5;	/* next session OK, data packet, rec. incr. fixed packets	*/
181 		pos[ 4] = 10;			/* ISO mode 2; XA form 1					*/
182 		pos[ 8] = 0x20;			/* CD-ROM XA disc or DDCD disc */
183 		pos[10] = (blockingnr >> 24) & 0xff;	/* MSB packet size 		*/
184 		pos[11] = (blockingnr >> 16) & 0xff;
185 		pos[12] = (blockingnr >>  8) & 0xff;
186 		pos[13] = (blockingnr      ) & 0xff;	/* LSB packet size in SECTORS	*/
187 		DEBUG(printf("\tsetting up for packet writing with packet size %d\n", blockingnr));
188 	}
189 
190 	bzero(cmd, SCSI_CMD_LEN);
191 	cmd[0] = 0x55;			/* MODE SELECT (10)		*/
192 	cmd[1] = 16;			/* PF format			*/
193 	cmd[7] = val_len >> 8;		/* length of blob		*/
194 	cmd[8] = val_len & 0xff;
195 	cmd[9] = 0;			/* control			*/
196 
197 	error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, res, val_len, 3000, NULL);
198 	if (error) {
199 		perror("While WRTITING parameter page 5");
200 		return error;
201 	}
202 
203 #if 0
204 	/* Set CD/DVD speed to 'optimal' for it doesnt seem to do it automatically */
205 	bzero(cmd, SCSI_CMD_LEN);
206 	cmd[ 0] = 0xBB;				/* Set CD speed */
207 	cmd[ 1] = 1;				/* select CAV (1) or CLV (0) recording */
208 	cmd[ 2] = 0xff;
209 	cmd[ 3] = 0xff;				/* max read performance speed */
210 	cmd[ 4] = 0xff;
211 	cmd[ 5] = 0xff;				/* max write performance speed; applic? */
212 	cmd[11] = 0;				/* control */
213 	error = scsi_call(SCSI_WRITECMD, discinfo, cmd, 12, NULL, 0, NULL);
214 	if (error) {
215 		/* CAV not possible? then go for CLV */
216 		cmd[ 1] = 0;				/* select CAV (1) or CLV (0) recording */
217 		error = scsi_call(SCSI_WRITECMD, discinfo, cmd, 12, NULL, 0, NULL);
218 		if (error) {
219 			perror("While setting speed");
220 			return error;
221 		}
222 	}
223 #endif
224 
225 	/* flag OK */
226 	return 0;
227 }
228 #undef blk_len
229 
230 
udf_discinfo_synchronise_caches(struct udf_discinfo * discinfo)231 int udf_discinfo_synchronise_caches(struct udf_discinfo *discinfo) {
232 	scsicmd cmd;
233 	int	error;
234 
235 	/* bail out when we're in sequential emulation */
236 	if (!udf_discinfo_is_cd_or_dvd(discinfo))
237 		return 0;
238 
239 	bzero(cmd, SCSI_CMD_LEN);
240 	cmd[ 0] = 0x35;				/* Synchronise cache	*/
241 	cmd[ 9] = 0;				/* control		*/
242 	error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
243 	if (error) {
244 		perror("While synchronising write cache");
245 	}
246 
247 	return error;
248 }
249 
250 
251 /*
252  * important: it must be called after write operations before read operations
253  * are allowed again. When its allready finished with writing this call has no
254  * effect and can be called at start to make sure the device knows that we're
255  * going to read.
256  */
udf_discinfo_finish_writing(struct udf_discinfo * discinfo)257 int udf_discinfo_finish_writing(struct udf_discinfo *discinfo) {
258 	int error;
259 
260 	if (!udf_discinfo_is_cd_or_dvd(discinfo))
261 		return 0;
262 
263 	error = udf_discinfo_synchronise_caches(discinfo);
264 	return error;
265 }
266 
267 
udf_discinfo_reserve_track_in_logic_units(struct udf_discinfo * discinfo,uint32_t logic_units)268 int udf_discinfo_reserve_track_in_logic_units(struct udf_discinfo *discinfo, uint32_t logic_units) {
269 	scsicmd cmd;
270 	int	error;
271 
272 	if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
273 
274 	bzero(cmd, SCSI_CMD_LEN);
275 	cmd[ 0] = 0x53;				/* reserve track	*/
276 	cmd[ 5] = (logic_units  >> 24) & 0xff;	/* size MSB		*/
277 	cmd[ 6] = (logic_units  >> 16) & 0xff;
278 	cmd[ 7] = (logic_units  >>  8) & 0xff;
279 	cmd[ 8] = (logic_units       ) & 0xff;	/* size LSB		*/
280 	cmd[ 9] = 0;				/* control		*/
281 	error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
282 
283 	return error;
284 }
285 
286 
udf_discinfo_close_track(struct udf_discinfo * discinfo,uint16_t trackno)287 int udf_discinfo_close_track(struct udf_discinfo *discinfo, uint16_t trackno) {
288 	scsicmd cmd;
289 	int	error;
290 
291 	if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
292 
293 	bzero(cmd, SCSI_CMD_LEN);
294 	cmd[ 0] = 0x5B;				/* close session/track	*/
295 	cmd[ 2] = 1;				/* track 		*/
296 	cmd[ 4] = (trackno      >>  8) & 0xff;	/* specify trackno MSB	*/
297 	cmd[ 5] = (trackno           ) & 0xff;	/*         trackno LSB	*/
298 	cmd[ 9] = 0;				/* control		*/
299 	error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
300 
301 	return error;
302 }
303 
304 
305 /* can only close last session */
udf_discinfo_close_session(struct udf_discinfo * discinfo)306 int udf_discinfo_close_session(struct udf_discinfo *discinfo) {
307 	scsicmd cmd;
308 	int error;
309 
310 	if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
311 
312 	bzero(cmd, SCSI_CMD_LEN);
313 	cmd[ 0] = 0x5B;				/* close session/track	*/
314 	cmd[ 2] = 2;				/* session 		*/
315 	cmd[ 9] = 0;				/* control		*/
316 	error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
317 
318 	return error;
319 }
320 
321 
322 /*
323  * Repair a damaged track when suspected. It'll try to make it writable again.
324  * A track can be broken when sudden stops are made and the track end is left
325  * in a inconsistent state in the ATIP/PMA/TOC.
326  */
udf_discinfo_repair_track(struct udf_discinfo * discinfo,uint16_t trackno)327 int udf_discinfo_repair_track(struct udf_discinfo *discinfo, uint16_t trackno) {
328 	scsicmd cmd;
329 	int	error;
330 
331 	if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV;
332 
333 	bzero(cmd, SCSI_CMD_LEN);
334 	cmd[ 0] = 0x58;				/* repair track		*/
335 	cmd[ 4] = (trackno      >>  8) & 0xff;	/* specify trackno MSB	*/
336 	cmd[ 5] = (trackno           ) & 0xff;	/*         trackno LSB	*/
337 	cmd[ 9] = 0;				/* control		*/
338 	error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL);
339 
340 	return error;
341 }
342 
343 
344 /*
345  * This routine 'get disc type' tries to get operational information from the
346  * disc/drive combination and its capabilities.  Fills in devdrv_class, MMC
347  * profile and the various flags; no track info.
348  */
349 
udf_discinfo_get_disc_type(struct udf_discinfo * disc)350 int udf_discinfo_get_disc_type(struct udf_discinfo *disc) {
351 	struct stat stat;
352 	scsicmd	    cmd;
353 	uint8_t	    buf[256];
354 	uint8_t	    features[1024+100], *rpos, *fpos;
355 	uint32_t    pos, features_len, feat_tbl_len, val_len;
356 	uint32_t    feature, last_feature;
357 	uint32_t    feature_ver, feature_pers, feature_cur, feature_len;
358 	int         error;
359 
360 	/* assume generic CD-ROM with no known MMC profile */
361 	disc->devdrv_class = UDF_DEVDRV_CLASS_CD;
362 	disc->mmc_profile  = 0;
363 
364 	/* check if its a regular file */
365 	fstat(disc->dev->fhandle, &stat);
366 	if (S_ISREG(stat.st_mode)) {
367 		UDF_VERBOSE(printf("UDF device %s is a regular file\n", disc->dev->dev_name));
368 		disc->devdrv_class     = UDF_DEVDRV_CLASS_FILE;
369 		disc->sequential       = 0;	/* full r/w		*/
370 		disc->recordable       = 1;	/* assuming rw access	*/
371 		disc->blankable        = 0;	/* not applicable       */
372 		disc->rewritable       = 1;
373 		disc->packet           = 0;
374 		disc->blockingnr       = 1;
375 		disc->strict_overwrite = 0;
376 		disc->sector_size      = DISC_SECTOR_SIZE;
377 		return 0;
378 	}
379 
380 	/* check if its a ATIPI/SCSI device */
381 	error = uscsi_check_for_scsi(disc->dev);
382 	if (error) {
383 		/* obviously no ATIPI/SCSI device -> has to be IDE disc or other but no file either */
384 		disc->devdrv_class     = UDF_DEVDRV_CLASS_DISC;
385 		disc->sequential       = 0;	/* full r/w		*/
386 		disc->recordable       = 1;	/* assuming rw access	*/
387 		disc->blankable        = 0;	/* not applicable       */
388 		disc->rewritable       = 1;
389 		disc->packet           = 0;
390 		disc->blockingnr       = 1;
391 		disc->strict_overwrite = 0;
392 		disc->sector_size      = DISC_SECTOR_SIZE;
393 		UDF_VERBOSE(printf("Got error executing SCSI command, assuming IDE disc\n"));
394 		return 0;
395 	}
396 
397 	/* check if its a SCSI disc -> if so, do NOT issue mmc profile check */
398 	bzero(cmd, SCSI_CMD_LEN);
399 	cmd[0] = 0x12;	/* INQUIRY */
400 	cmd[1] = 0;	/* basic inquiry */
401 	cmd[2] = 0;	/* no page or operation code */
402 	cmd[3] = 0;	/* reserved/MSB result */
403 	cmd[4] = 96;	/* all but vendor specific */
404 	cmd[5] = 0;	/* control */
405 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 6, buf, 96, 30000, NULL);
406 	if (error) {
407 		fprintf(stderr, "Device claims to be SCSI but does NOT respond to inquiry!\n");
408 		return ENOENT;
409 	}
410 	disc->scsi_device_type = buf[0] & 0x1f;
411 
412 	switch (disc->scsi_device_type) {
413 		case 0x05 : break; /* MMC */
414 		case 0x00 : /* Direct access device */
415 		case 0x0E : /* Simplified direct access device */
416 			/* read-write possible */
417 			disc->devdrv_class     = UDF_DEVDRV_CLASS_DISC;
418 			disc->sequential       = 0;	/* full r/w		*/
419 			disc->recordable       = 1;	/* assuming rw access	*/
420 			disc->blankable        = 0;	/* not applicable       */
421 			disc->rewritable       = 1;
422 			disc->packet           = 0;
423 			disc->blockingnr       = 1;
424 			disc->strict_overwrite = 0;
425 			disc->sector_size      = DISC_SECTOR_SIZE;
426 			return 0;
427 		case 0x04 :
428 		case 0x07 :
429 			/* Non MMC read only optical media */
430 			disc->devdrv_class     = UDF_DEVDRV_CLASS_DISC;
431 			disc->sequential       = 0;	/* 			*/
432 			disc->recordable       = 0;	/* assuming ro access	*/
433 			disc->blankable        = 0;	/* not applicable       */
434 			disc->rewritable       = 0;
435 			disc->packet           = 0;
436 			disc->blockingnr       = 1;
437 			disc->strict_overwrite = 0;
438 			disc->sector_size      = DISC_SECTOR_SIZE;
439 			return 0;
440 		default:
441 			fprintf(stderr, "Device type 0x%02x not suitable for mass storage\n", disc->scsi_device_type);
442 			return ENOENT;
443 	}
444 
445 	/* get MMC profile */
446 	bzero(cmd, SCSI_CMD_LEN);
447 	cmd[ 0] = 0x46;				/* Get configuration */
448 	cmd[ 8] = 32;				/* just a small buffer size */
449 	cmd[ 9] = 0;				/* control */
450 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, buf, 32, 30000, NULL);
451 	if (!error) {
452 		disc->mmc_profile = buf[7] | (buf[6] << 8);
453 	} else {
454 		disc->mmc_profile = 0;	/* mark unknown MMC profile */
455 	}
456 	UDF_VERBOSE_MAX(printf("Device has MMC profile 0x%02x\n", disc->mmc_profile));
457 
458 	/* determine CD sector size */
459 	bzero(buf, 8);
460 	bzero(cmd, SCSI_CMD_LEN);
461 	cmd[0] = 0x25;		/* CD READ RECORDED CAPACITY */
462 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, buf, 8, 30000, NULL);
463 	if (error) {
464 		fprintf(stderr, "Can't read CD recorded capacity; assuming sector size %d : %s", CD_SECTOR_SIZE, strerror(error));
465 		disc->sector_size = CD_SECTOR_SIZE;
466 	} else {
467 		disc->sector_size = buf[7] | (buf[6]<<8) | (buf[5]<<16) | (buf[4]<<24);
468 		/* packet size is recorded for each track seperately */
469 	}
470 
471 	/*
472 	 * Read in features to determine device flags. First take some initial
473 	 * values.
474 	 */
475 	disc->sequential       = 0;
476 	disc->recordable       = 0;
477 	disc->erasable         = 0;
478 	disc->blankable        = 0;
479 	disc->formattable      = 0;
480 	disc->rewritable       = 0;
481 	disc->mrw              = 0;
482 	disc->packet           = 0;
483 	disc->strict_overwrite = 0;
484 	disc->blockingnr       = 1;	/* not relevant if non packet write */
485 
486 	feat_tbl_len = 1024;
487 	last_feature = feature = 0;
488 	do {
489 		bzero(cmd, SCSI_CMD_LEN);
490 		cmd[0] = 0x46;			/* Get configuration */
491 		cmd[1] = 0;			/* RT=0 -> all independent of current setting */
492 		cmd[2] = (last_feature) >> 8;	/* MSB feature number */
493 		cmd[3] = (last_feature) & 0xff;	/* LSB feature number */
494 		cmd[7] = (feat_tbl_len) >> 8;	/* MSB buffersize */
495 		cmd[8] = (feat_tbl_len) & 0xff;	/* LSB buffersize */
496 		cmd[9] = 0;			/* control */
497 		error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, features, feat_tbl_len, 30000, NULL);
498 		if (error) {
499 			fprintf(stderr, "While reading feature table : %s\n", strerror(error));
500 			return EIO;
501 		}
502 
503 		features_len      = features[3] | (features[2]<<8) | (features[1]<<16) | (features[0]<<24);
504 		disc->mmc_profile = features[7] | (features[6]<<8);
505 
506 		pos = 8;
507 		while (pos < features_len) {
508 			fpos = &features[pos];
509 
510 			feature     =  fpos[1] | (fpos[0] << 8);
511 			feature_ver = (fpos[2] >> 2) & 15;
512 			feature_cur = (fpos[2] & 1);
513 			feature_pers= (fpos[2] & 2);
514 			feature_len =  fpos[3];
515 
516 			if (feature_cur == 1) {
517 				rpos = &fpos[4];
518 				switch (feature) {
519 					case 0x0010 :	/* random readable feature */
520 						disc->sector_size = rpos[3] | (rpos[2] << 8) | (rpos[1] << 16) | (rpos[0] << 24);
521 						disc->blockingnr  = rpos[5] | (rpos[4] << 8);
522 						/* RW error page */
523 						break;
524 					case 0x0020 :	/* random writable feature */
525 						disc->recordable = 1;
526 						disc->rewritable = 1;
527 						break;
528 					case 0x0021 :	/* incremental streaming write feature */
529 						disc->recordable = 1;
530 						disc->sequential = 1;
531 						disc->link_size  = rpos[7];
532 						if (rpos[6] & 1)
533 							disc->link_size = 0;
534 						break;
535 					case 0x0022 : 	/* (obsolete) erase support feature */
536 						disc->recordable = 1;
537 						disc->erasable = 1;
538 						break;
539 					case 0x0023 :	/* formatting media support feature */
540 						disc->recordable = 1;
541 						disc->formattable = 1;
542 						break;
543 					case 0x0024 :	/* hardware assisted defect management feature */
544 						/* XXX set mrw ? */
545 						break;
546 					case 0x0025 :	/* write once */
547 						disc->recordable = 1;
548 						break;
549 					case 0x0026 :	/* restricted overwrite feature */
550 						disc->recordable = 1;
551 						disc->rewritable = 1;
552 						disc->strict_overwrite = 1;
553 						break;
554 					case 0x0028 :	/* MRW formatted media support feature */
555 						disc->mrw = 1;
556 						break;
557 					case 0x002b :	/* read/write DVD+R formatted media */
558 						disc->sequential = 1;
559 						if (rpos[0] & 1) /* write support */
560 							disc->recordable = 1;
561 						break;
562 					case 0x002c :	/* regid restricted overwrite feature */
563 						disc->recordable = 1;
564 						disc->rewritable = 1;
565 						disc->strict_overwrite = 1;
566 						if (rpos[0] & 1) /* blank bit */
567 							disc->blankable = 1;
568 						break;
569 					case 0x002d :	/* track at once recording feature */
570 						disc->recordable = 1;
571 						disc->sequential = 1;
572 						break;
573 					case 0x002f :	/* DVD-R/-RW write feature */
574 						disc->recordable = 1;
575 						if (rpos[0] & 2) /* DVD-RW bit */
576 							disc->blankable = 1;
577 						break;
578 					case 0x0038 :	/* pseuro overwritable */
579 						break;
580 					default :
581 						/* ignore */
582 						break;
583 				}
584 			}
585 
586 			last_feature = MAX(last_feature, feature);
587 			if (feature_len & 3) {
588 				UDF_VERBOSE(printf("Drive returned feature %d %swith bad length %d\n",
589 					feature, (feature_cur == 1?  "(current) ":""), feature_len));
590 				feature_len = (feature_len + 3) & ~3;
591 			}
592 			pos += 4 + feature_len;
593 		}
594 	} while (features_len >= 0xffff);
595 
596        /*
597 	* fixup DVD and CD-RW drives that are on crack.
598 	*/
599         if (disc->mmc_profile == 0x0a) {
600 		/* some forget to mention strict overwrite when not sequential and forget the blocking size */
601 		if (!disc->sequential) {
602 			disc->strict_overwrite = 1;
603 			disc->blockingnr = 32;		/* fixed for CD-RW */
604 		}
605 		/* some say they are strict overwrite but also sequential */
606 		if (disc->strict_overwrite)
607 			disc->sequential = 0;
608 		/* some forget that if they are mrw they can't the be other */
609 		if (disc->mrw) {
610 			disc->sequential = 0;
611 			disc->strict_overwrite = 0;
612 		}
613 	}
614 	/* some think a CD-R is rewritable */
615 	if (disc->mmc_profile == 0x09) {
616 		disc->rewritable = 0;
617 	}
618 
619 	/* derivatives */
620 	if (disc->blockingnr > 1)
621 		disc->packet = 1;
622 
623 	switch (disc->mmc_profile) {
624 		case 0x01 :
625 		case 0x02 :
626 			/* SCSI discs class; treat like normal discs */
627 			disc->devdrv_class   = UDF_DEVDRV_CLASS_DISC;
628 			UDF_VERBOSE(printf("SCSI disc detected; treating like normal disc device\n"));
629 			return 0;
630 		case 0x03 :	/* Magneto Optical with sector erase */
631 		case 0x04 :	/* Magneto Optical write once */
632 		case 0x05 :	/* Advance Storage Magneto Optical */
633 			disc->devdrv_class   = UDF_DEVDRV_CLASS_MO;
634 			break;
635 		/* 0x00, 0x08, 0x09, 0x0a : different types of CD-ROM devices like CD-R/RW etc. */
636 		case 0x00 :
637 			disc->devdrv_class   = UDF_DEVDRV_CLASS_CD;	/* not allways clear */
638 			break;
639 		case 0x08 :	/* CD-ROM */
640 		case 0x09 :	/* CD-R */
641 		case 0x0a :	/* CD-RW */
642 			disc->devdrv_class   = UDF_DEVDRV_CLASS_CD;
643 			break;
644 		/* 0x10...0x14 DVD-ROM and DVD- devices */
645 		case 0x10 :	/* DVD-ROM */
646 		case 0x11 :	/* DVD-R   */
647 		case 0x12 :	/* DVD-RAM */
648 		case 0x13 :	/* DVD-RW (restricted overwrite) */
649 		case 0x14 :	/* DVD-RW (sequential)           */
650 		/* 0x1a..0x1b DVD+ devices */
651 		case 0x1a :	/* DVD+RW */
652 		case 0x1b :	/* DVD+R */
653 		case 0x2b :	/* DVD+R double layer */
654 			disc->devdrv_class   = UDF_DEVDRV_CLASS_DVD;
655 			break;
656 		case 0x40 :	/* BD-ROM */
657 		case 0x41 :	/* BD-R Sequential Recording (SRM) */
658 		case 0x42 :	/* BD-R Random Recording (RRM) */
659 		case 0x43 :	/* BD-RE */
660 			disc->devdrv_class   = UDF_DEVDRV_CLASS_BD;
661 			break;
662 		default :
663 			fprintf(stderr, "Not recognized MMC profile %d encountered, marking readonly\n", disc->mmc_profile);
664 			disc->devdrv_class   = UDF_DEVDRV_CLASS_CD;	/* go for the `dummy' */
665 			break;
666 	}
667 
668 	/*
669 	 * ok, if we're on an CD-MRW or DVD+MRW, we ought to have switched
670 	 * automatically to DMA space. However, this drive at times just
671 	 * refuses with all messy things around.
672 	 */
673 
674 
675 	/* Select `Defect managed area' LBA space */
676 	if (!disc->mrw)
677 		return 0;
678 
679 	DEBUG(printf("Setting DMA LBA space"));
680 
681 	val_len = 6   + 8 + 2;			/* 2 for 4 byte alignment	*/
682 	rpos    = buf + 8;
683 	bzero(buf, val_len);
684 
685 	rpos[ 0] = 0x03;			/* GAA/DMA space select		*/
686 	rpos[ 1] = 6;				/* page length         		*/
687 	rpos[ 3] = 0;				/* select GAA bit in bit 0	*/
688 
689 	bzero(cmd, SCSI_CMD_LEN);
690 	cmd[0] = 0x55;			/* MODE SELECT (10)		*/
691 	cmd[1] = 16;			/* PF format			*/
692 	cmd[7] = val_len >> 8;		/* length of blob		*/
693 	cmd[8] = val_len & 0xff;
694 	cmd[9] = 0;			/* control			*/
695 
696 	error = uscsi_command(SCSI_WRITECMD, disc->dev, cmd, 10, buf, val_len, 30000, NULL);
697 	if (error) {
698 		perror("While WRTITING parameter page 3");
699 		return error;
700 	}
701 
702 	/* shutup gcc */
703 	feature_pers = feature_pers; feature_ver = feature_ver;
704 
705 	return 0;
706 }
707 
708 #if defined(__NetBSD__) || defined(__OpenBSD__)
709 #include <sys/ioctl.h>
710 #include <sys/disklabel.h>
711 #include <sys/dkio.h>
712 
udf_get_partition_info(struct udf_discinfo * disc)713 int udf_get_partition_info(struct udf_discinfo *disc) {
714 	struct disklabel  disklab;
715 	struct partition *dp;
716 	struct stat st;
717 	int partnr;
718 
719 	/* read disklabel partition */
720 	if (ioctl(disc->dev->fhandle, DIOCGDINFO, &disklab) == -1) {
721 		/* failed to get disclabel! */
722 		perror("disklabel");
723 		return errno;
724 	}
725 
726         /* get disk partition it refers to */
727 	fstat(disc->dev->fhandle, &st);
728 	partnr = DISKPART(st.st_rdev);
729 	dp = &disklab.d_partitions[partnr];
730 
731 	if (dp->p_size == 0) {
732 		perror("faulty disklabel partition returned, check label\n");
733 		return EIO;
734 	}
735 
736 	disc->sector_size        = disklab.d_secsize;
737 	disc->session_start [0]  = 0;
738 	disc->session_end   [0]  = dp->p_size - 1;
739 
740 	return 0;
741 }
742 
743 #elif defined(__linux__)
744 #include <linux/fs.h>
745 
udf_get_partition_info(struct udf_discinfo * disc)746 int udf_get_partition_info(struct udf_discinfo *disc) {
747 	long p_size, p_size512;
748 	int  secsize;
749 
750 	/* get device length and sector size */
751 	if (ioctl(disc->dev->fhandle, BLKSSZGET, &secsize) == -1) {
752 		perror("Can't read my sector size\n");
753 		return errno;
754 	}
755 	if (ioctl(disc->dev->fhandle, BLKGETSIZE, &p_size512) == -1) {
756 		perror("Can't read my partition size\n");
757 		return errno;
758 	}
759 
760 	p_size = p_size512 * (secsize / 512);
761 
762 	disc->sector_size        = secsize;
763 	disc->session_start [0]  = 0;
764 	disc->session_end   [0]  = p_size - 1;
765 
766 	return 0;
767 }
768 
769 #else
770 
udf_get_partition_info(struct udf_discinfo * disc)771 int udf_get_partition_info(struct udf_discinfo *disc) {
772 	perror(" UDF: no explicit support for disc devices yet for this operating system.\n");
773 	perror("Trying readonly access...\n");
774 
775 	disc->recordable = disc->rewritable = 0;
776 
777 	return 0;
778 }
779 
780 #endif
781 
782 
783 /* 10000 is arbitrary */
784 /* TODO split up one day for its updating values unnessisarily */
785 #define res_len 10000
udf_get_disc_info(struct udf_discinfo * disc)786 int udf_get_disc_info(struct udf_discinfo *disc) {
787 	scsicmd		 cmd;
788 	struct stat	 stat;
789 	uint32_t	 val_len;
790 	uint32_t	 first_track, last_track;
791 	uint32_t	 first_session, last_session;
792 	uint32_t	 next_writable_addr, packet_size;
793 	uint32_t	 cntrl, addr, tno, point, min, sec, frame, pmin, psec, pframe;
794 	uint32_t	 data_length, pos;
795 	uint8_t		 res[res_len];
796 	int		 first_track_last_session, last_track_last_session;
797 	int		 track, session, sector_size;
798 	int		 nwa_valid;
799 	off_t		 track_start, track_end, track_size, disc_size, free_blocks;
800 	int		 error;
801 
802 	if (disc->devdrv_class == UDF_DEVDRV_CLASS_FILE) {
803 		sector_size = disc->alt_sector_size ? disc->alt_sector_size : disc->sector_size;
804 		fstat(disc->dev->fhandle, &stat);
805 		disc->link_size		 = 0;					/* no link lossage	*/
806 		disc->disc_state         = DISC_STATE_NOT_SERIAL;
807 		disc->last_session_state = SESSION_STATE_INCOMPLETE;
808 		disc->num_sessions       = 1;
809 		disc->session_start [0]  = 0;
810 		disc->session_end   [0]  = (stat.st_size    / sector_size);	/* inclusive */
811 		disc->next_writable [0]  = (stat.st_size    / sector_size) + 1;
812 		disc->packet_size   [0]  =  stat.st_blksize / sector_size;
813 		return 0;
814 	}
815 
816 	if (disc->devdrv_class == UDF_DEVDRV_CLASS_DISC) {
817 		disc->link_size		 = 0;					/* no link lossage	*/
818 		disc->disc_state         = DISC_STATE_NOT_SERIAL;
819 		disc->last_session_state = SESSION_STATE_COMPLETE;
820 		disc->num_sessions       = 1;
821 
822 		disc->session_start [0]  = 0;
823 		disc->session_end   [0]  = 0;
824 
825 		error = udf_get_partition_info(disc);
826 		if (error)
827 			return error;
828 
829 		fprintf(stderr, "UDF: warning... reading/writing on 'disc' device\n");
830 		return 0;
831 	}
832 
833 	/* classes CD and DVD remain; we can be on a DVD/CD recordable or on a legacy CD-ROM */
834 
835 	/* Get track information */
836 	val_len = 12;
837 	bzero(res, val_len);
838 	bzero(cmd, SCSI_CMD_LEN);
839 
840 	cmd[0] = 0x51;				/* Read disc information */
841 	cmd[7] = val_len >> 8;			/* MSB allocation length */
842 	cmd[8] = val_len & 0xff;		/* LSB allocation length */
843 	cmd[9] = 0;				/* control */
844 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
845 
846 	if (!error) {
847 		/* we are a MMC3+ device! */
848 		disc->disc_state		 =  res[2]       &  3;		/* just 'happends' to be the same as we use */
849 		disc->last_session_state	 = (res[2] >> 2) &  3;		/* ditto */
850 		disc->blankable			 =  res[2]       & 16;		/* blankable -> update possibility */
851 		disc->num_sessions		 =  res[4] | (res[ 9] << 8);
852 		first_track			 =  res[3];
853 		first_track_last_session	 =  res[5] | (res[10] << 8);	/* to build up the last 'session' */
854 		last_track_last_session  	 =  res[6] | (res[11] << 8);
855 
856 		/* Initialise the sessions to be taken as overspanning tracks */
857 		for (session = 0; session < disc->num_sessions; session++) {
858 			disc->session_start[session] = INT_MAX;
859 			disc->session_end  [session] = 0;
860 		}
861 
862 		for (track = first_track; track <= last_track_last_session; track++) {
863 			/* each track record is 36 bytes long */
864 			val_len = 36;
865 			bzero(res, val_len);
866 
867 			bzero(cmd, SCSI_CMD_LEN);
868 			cmd[0] = 0x52;				/* Read track information */
869 			cmd[1] = 1;				/* indexed on track       */
870 			cmd[4] = track >> 8;			/* track number 0-0xff ?  */
871 			cmd[5] = track & 0xff;
872 			cmd[7] = val_len >> 8;			/* MSB length resultbuf	  */
873 			cmd[8] = val_len & 0xff;		/* LSB ,,		  */
874 			cmd[9] = 0;
875 			error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
876 			if (error) {
877 				perror("While reading track info");
878 				break;
879 			}
880 #if 0
881 			data_length		= res[1] | (res[0]  << 8);
882 			// track_number		= res[2] | (res[32] << 8);	  /* why? */
883 			session			= res[3] | (res[33] << 8);
884 			// is_track_mode	= res[5] & 15;
885 			// is_copy		= res[5] & 16;
886 			// is_damage		= res[5] & 32;
887 			// is_fixed_packet	= res[6] & 16;
888 			// is_packet_or_inc	= res[6] & 32;
889 			// is_blank		= res[6] & 64;
890 			// is_reserved		= res[6] & 128;
891 			// is_data_mode		= res[6] & 15;
892 			nwa_valid		= res[7] & 1;
893 			// lra_valid		= res[7] & 2;
894 #endif
895 			data_length		= res[1] | (res[0]  << 8);
896 			session			= res[3] | (res[33] << 8);
897 			nwa_valid		= res[7] & 1;
898 
899 			track_start		= res[11] | (res[10]<<8) | (res[ 9]<<16) | (res[ 8]<<24);
900 			next_writable_addr	= res[15] | (res[14]<<8) | (res[13]<<16) | (res[12]<<24);
901 			free_blocks		= res[19] | (res[18]<<8) | (res[17]<<16) | (res[16]<<24);
902 			packet_size		= res[23] | (res[22]<<8) | (res[21]<<16) | (res[20]<<24);
903 			track_size		= res[27] | (res[26]<<8) | (res[25]<<16) | (res[24]<<24);
904 			/* last_recorded_addr	= res[32] | (res[30]<<8) | (res[29]<<16) | (res[28]<<24); */
905 			track_end = track_start + track_size;
906 
907 			if (data_length <= 30) session &= 0xff;
908 
909 			disc->session_start[session-1] = MIN(disc->session_start[session-1], track_start);
910 			disc->session_end  [session-1] = MAX(disc->session_end  [session-1], track_end);
911 			disc->free_blocks  [session-1] = free_blocks;
912 			disc->packet_size  [session-1] = packet_size;
913 			if (nwa_valid) disc->next_writable[session-1] = next_writable_addr;
914 		}
915 		if (disc->session_start[disc->num_sessions-1] == INT_MAX) {
916 			if (disc->disc_state == DISC_STATE_FULL) {
917 				if (disc->last_session_state == SESSION_STATE_COMPLETE) disc->num_sessions--;
918 			}
919 		}
920 
921 		/* XXX
922 		 * initialise default link size to zero; only set DEFAULT
923 		 * link lossage for CD-R we are using `Burn Free' for writing
924 		 * but if it fails its good to know the penalty for recovery
925 		 * XXX
926 		 */
927 		disc->link_size = 0;
928 		if (disc->mmc_profile == 0x09) {
929 			disc->link_size = 7;
930 		}
931 
932 		return 0;
933 	}
934 
935 	/* Start with legacy CD-ROM .... trying to get as much info from it as possible */
936 	disc->sequential	 = 0;
937 	disc->recordable	 = 0;
938 	disc->blankable		 = 0;
939 	disc->packet		 = 0;
940 	disc->blockingnr	 = 32;
941 	disc->strict_overwrite	 = 0;
942 	disc->disc_state         = DISC_STATE_FULL;
943 	disc->last_session_state = SESSION_STATE_COMPLETE;
944 	disc->link_size          = 7;	/* DEFAULT link lossage for CDs */
945 
946 
947 	/* Read session range */
948 	val_len = 4;			/* only head */
949 	bzero(res, val_len);
950 	bzero(cmd, SCSI_CMD_LEN);
951 	cmd[0] = 0x43;			/* READ TOC/PMA/ATIP INFO	*/
952 	cmd[1] = 2;			/* no LBA's are defined         */
953 	cmd[2] = 2;			/* format 2 also this time	*/
954 	cmd[6] = 0;			/* obligatory zero		*/
955 	cmd[7] = val_len >> 8;
956 	cmd[8] = val_len & 0xff;
957 	cmd[9] = 0;
958 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
959 	if (error) {
960 		perror("TOC reading of sessions failed");
961 		return error;
962 	}
963 	first_session = read_cd_hex2(res[2]);
964 	last_session  = read_cd_hex2(res[3]);
965 
966 	disc->num_sessions = last_session - first_session + 1;
967 
968 	/* Initialise the sessions to be taken as overspanning tracks */
969 	for(session = 0; session <= disc->num_sessions; session++) {
970 		disc->session_start[session] = INT_MAX;
971 		disc->session_end  [session] = 0;
972 	}
973 
974 	/* calculate how big the result buffer ought to be to get the whole TOC */
975 	/* NOTE: don't count the 2 length bytes */
976 	val_len = res[1] + (res[0] << 8);
977 
978 	/* fix length for ATAPI drives */
979 	if (val_len & 1)
980 		val_len++;
981 
982 	assert(val_len < res_len);
983 
984 	/* Read the complete TOC and extract information */
985 	bzero(res, val_len);
986 	bzero(cmd, SCSI_CMD_LEN);
987 	cmd[0] = 0x43;			/* READ TOC/PMA/ATIP INFO	*/
988 	cmd[1] = 2;			/* LBA's are not defined 	*/
989 	cmd[2] = 2;			/* format 2; full TOC		*/
990 	cmd[6] = first_session;		/* start at first session	*/
991 	cmd[7] = val_len >> 8;
992 	cmd[8] = val_len & 0xff;
993 	cmd[9] = 0;
994 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL);
995 	if (error) {
996 		perror("TOC reading of full TOC failed");
997 		return error;
998 	}
999 
1000 	data_length =res[1] | (res[0] << 8);
1001 	if (data_length != val_len) {
1002 		fprintf(stderr, "Warning: device didn't return all data requested when reading full TOC\nn");
1003 		fprintf(stderr, "\treturned %d bytes instead of %d\n", data_length, val_len);
1004 	}
1005 	pos = 4;
1006 	track_start = INT_MAX; track_end = 0;
1007 
1008 	while (pos < data_length + 2) {
1009 		session = read_cd_bcd(res[pos+ 0]);
1010 		cntrl   = res[pos+1] & 15;
1011 		addr    = res[pos+1] >> 4;
1012 		tno     = read_cd_bcd(res[pos+ 2]);
1013 		point   = read_cd_bcd(res[pos+ 3]);
1014 		min     = read_cd_bcd(res[pos+ 4]);
1015 		sec     = read_cd_bcd(res[pos+ 5]);
1016 		frame   = read_cd_bcd(res[pos+ 6]);
1017 		pmin    = read_cd_bcd(res[pos+ 8]);
1018 		psec    = read_cd_bcd(res[pos+ 9]);
1019 		pframe  = read_cd_bcd(res[pos+10]);
1020 
1021 		/* extract information; explicit writeout. See SCSI docs */
1022 		if (tno == 0 && session && addr == 1) {
1023 			switch (point) {
1024 				case 0xa0 : first_track = pmin; break;
1025 				case 0xa1 : last_track  = pmin; break;
1026 				case 0xa2 :
1027 					track_end   = cd_msf2lba(0, pmin, psec, pframe);
1028 					disc->session_end  [session-1] = MAX(disc->session_end  [session-1], track_end);
1029 					break;
1030 				default   :
1031 					track_start = cd_msf2lba(0, pmin, psec, pframe);
1032 					disc->session_start[session-1] = MIN(disc->session_start[session-1], track_start);
1033 					break;
1034 			}
1035 		}
1036 		if (tno == 0 && session && addr == 5) {
1037 			if (point == 0xb0) {
1038 				next_writable_addr = cd_msf2lba(0, min, sec, frame);
1039 				disc_size = cd_msf2lba(0, pmin, psec, pframe);
1040 				/* TODO use nwa & size */
1041 				printf("UDF: ignoring B0 Q channel : next writable address; pre MMC3 device; fix me\n");
1042 			}
1043 
1044 		}
1045 		pos += 11;
1046 	}
1047 
1048 	/* Last session information is notoriously flawed in TOC format so update it */
1049 	bzero(res, 8);
1050 	bzero(cmd, SCSI_CMD_LEN);
1051 	cmd[0] = 0x25;		/* CD READ RECORDED CAPACITY */
1052 	error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, 8, 30000, NULL);
1053 	if (error) {
1054 		fprintf(stderr, "Can't read CD recorded capacity, last session end might not be OK : %s\n", strerror(error));
1055 		return 0;
1056 	}
1057 
1058 	session = disc->num_sessions-1;
1059 	disc->session_end[session] = res[3] | (res[2]<<8) | (res[1]<<16) | (res[0]<<24);
1060 
1061 	/* shut up gcc */
1062 	disc_size = disc_size; first_track_last_session = first_track_last_session;
1063 	cntrl = cntrl; last_track = last_track;
1064 
1065 	return 0;
1066 }
1067 #undef res_len
1068 
1069 
udf_open_disc(char * dev_name,int discop_flags,struct udf_discinfo ** discptr)1070 int udf_open_disc(char *dev_name, int discop_flags, struct udf_discinfo **discptr) {
1071 	struct udf_discinfo *disc;
1072 
1073 	if (!discptr) return EINVAL;
1074 	*discptr = NULL;
1075 
1076 	/* determine what kind of file/device we are dealing with */
1077 	disc = calloc(1, sizeof(struct udf_discinfo));
1078 	if (!disc) return ENOMEM;
1079 
1080 	disc->dev = calloc(1, sizeof(struct uscsi_dev));
1081 	if (!disc->dev) {
1082 		free(disc);
1083 		return ENOMEM;
1084 	}
1085 
1086 	/* fill in the name */
1087 	disc->dev->dev_name = strdup(dev_name);
1088 
1089 	if (uscsi_open(disc->dev) != 0) {
1090 		perror("Failure to open device or file");
1091 		free(disc->dev);
1092 		free(disc);
1093 		return ENODEV;
1094 	}
1095 
1096 	/* determine disc type */
1097 	if (udf_discinfo_get_disc_type(disc)) {
1098 		perror("Error during classification of disc; skipping disc\n");
1099 		uscsi_close(disc->dev);
1100 		free(disc->dev);
1101 		free(disc);
1102 		return ENODEV;
1103 	}
1104 
1105 	/* get disc info */
1106 	if (udf_get_disc_info(disc)) {
1107 		fprintf(stderr, "Can't get disc info");
1108 		uscsi_close(disc->dev);
1109 		free(disc->dev);
1110 		free(disc);
1111 		return ENODEV;
1112 	}
1113 
1114 	/* process discop_flags */
1115 	if (discop_flags & UDF_DISCOP_BSWAP)
1116 		disc->bswap_sectors = 1;
1117 
1118 	/* return the pointer */
1119 	*discptr = disc;
1120 
1121 	/* set recording parameters */
1122 	udf_discinfo_set_recording_parameters(disc, 0);	/* no testwrite */
1123 
1124 	return 0;
1125 }
1126 
1127 
udf_close_disc(struct udf_discinfo * disc)1128 int udf_close_disc(struct udf_discinfo *disc) {
1129 	if (!disc) return 0;
1130 
1131 /*	udf_stop_disc_thread(disc); */
1132 	uscsi_close(disc->dev);
1133 
1134 	printf("Disc access statistics\n");
1135 	printf("\tsector reads   %8"PRIu64"  (%"PRIu64" Kbyte)\n", disc->sectors_read,    ((uint64_t) (disc->sectors_read)    * disc->sector_size) / 1024);
1136 	printf("\tsector written %8"PRIu64"  (%"PRIu64" Kbyte)\n", disc->sectors_written, ((uint64_t) (disc->sectors_written) * disc->sector_size) / 1024);
1137 	printf("\tswitches       %8d\n", disc->switchings);
1138 
1139 	return 0;
1140 }
1141 
1142 
1143 
udf_discinfo_alter_perception(struct udf_discinfo * disc,uint32_t sec_size,uint32_t num_sectors)1144 int udf_discinfo_alter_perception(struct udf_discinfo *disc, uint32_t sec_size, uint32_t num_sectors) {
1145 	struct stat stat;
1146 
1147 	assert(disc);
1148 	if ((disc->devdrv_class & UDF_DEVDRV_CLASS) != UDF_DEVDRV_CLASS_FILE) {
1149 		return EINVAL;
1150 	}
1151 
1152 	fstat(disc->dev->fhandle, &stat);
1153 	if (sec_size == 0)    sec_size    = disc->sector_size;
1154 	if (num_sectors == 0) num_sectors = stat.st_size / sec_size;
1155 
1156 	if (((sec_size % 512) != 0) || (sec_size == 0)) {
1157 		fprintf(stderr, "Size of blocks need to be a multiple of 512\n");
1158 		return EINVAL;
1159 	}
1160 
1161 	if (stat.st_size / sec_size >= (uint32_t) -1)
1162 	{
1163 		fprintf(stderr, "Disc needs to many logical sectors, please increase blocksize\n");
1164 		return EINVAL;
1165 	}
1166 
1167 	if (num_sectors < 300) {
1168 		fprintf(stderr, "Disc size too small to put an UDF filingsystem on\n");
1169 		return EINVAL;
1170 	}
1171 
1172 	if (stat.st_size != (off_t) sec_size * num_sectors) {
1173 		fprintf(stderr, "Size of image file is not equal to specified size parameters\n");
1174 		return EINVAL;
1175 	}
1176 
1177 	disc->sequential         = 0;					/* full r/w		*/
1178 	disc->recordable         = 1;					/* assuming rw access	*/
1179 	disc->rewritable         = 1;
1180 	disc->sector_size	 = sec_size;
1181 	disc->alt_sector_size	 = sec_size;				/* altered value	*/
1182 	disc->link_size		 = 0;					/* no link lossage	*/
1183 	disc->disc_state         = DISC_STATE_NOT_SERIAL;
1184 	disc->last_session_state = SESSION_STATE_INCOMPLETE;
1185 	disc->num_sessions       = 1;
1186 	disc->session_start [0]  = 0;
1187 	disc->session_end   [0]  = num_sectors;
1188 	disc->next_writable [0]  = num_sectors + 1;
1189 	disc->packet_size   [0]  = stat.st_blksize / sec_size;		/* best blocking size	*/
1190 
1191 	return 0;
1192 }
1193 
1194 
1195 /******************************************************************************************
1196  *
1197  * Sector readers and writers
1198  *
1199  ******************************************************************************************/
1200 
1201 
1202 /* read an extent of sectors in the `result' buffer */
udf_read_physical_sectors(struct udf_discinfo * disc,off_t sector,uint32_t num_sectors,char * what,uint8_t * result)1203 int udf_read_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *result) {
1204 	struct uscsi_sense sense;
1205 	scsicmd		cmd;
1206 	int		size, size_read, chunk;
1207 	uint32_t	session, skipped, sector_size;
1208 	int		pos, lb, hb, error;
1209 
1210 	/* protect us */
1211 	if (((long) result) & 3) {
1212 		printf("Unaligned read of sector : possible panic() on some systems avoided\n");
1213 		return EIO;
1214 	}
1215 
1216 	sector_size = disc->sector_size;
1217 
1218 	/* read one UDF sector at a physical address specified in UDF_SECTOR size units */
1219 	size = num_sectors * disc->sector_size;
1220 	size_read = 0;
1221 	bzero(result, size);	/* just in case */		/* has to go? */
1222 
1223 	assert(sector_size);
1224 	assert(num_sectors <= 0xffff);
1225 
1226 	/* statistics and cache control */
1227 	if (disc->am_writing) {
1228 		disc->switchings++;
1229 		/* XXX how about pseudo-overwrite? is this nessisary then too ? XXX */
1230 		if (disc->sequential) {
1231 			/*
1232 			 * we need to synchronise the write caches before we
1233 			 * are allowed to read from the disc again.
1234 			 */
1235 			error = udf_discinfo_synchronise_caches(disc);
1236 			while (error) {
1237 				printf("udf_discinfo: failed to sync caches, retrying\n");
1238 				error = udf_discinfo_synchronise_caches(disc);
1239 			}
1240 			/* we need to update our NWA's after the sync on sequentials */
1241 			udf_get_disc_info(disc);
1242 		}
1243 		/* mark reading access only */
1244 		disc->am_writing = 0;
1245 	}
1246 
1247 	error = 0;
1248 	DEBUG(printf("\r%08d : %s; read %d bytes\n", (int) sector, what, size));
1249 	while (num_sectors) {
1250 		switch (disc->devdrv_class & UDF_DEVDRV_CLASS) {
1251 			case UDF_DEVDRV_CLASS_CD  :
1252 			case UDF_DEVDRV_CLASS_DVD :
1253 				/*
1254 				 * Use a SCSI command to read it so we can go past the last session;
1255 				 * allthough READ (12) is available, some older CD-ROM
1256 				 * devices only want to do READ (10).
1257 				 */
1258 
1259 				/* limited by MAXPHYS, taking 64kb as limitation */
1260 				chunk     = MIN(64*1024 / sector_size, num_sectors);
1261 				size_read = chunk * sector_size;		/* definition */
1262 				skipped = session = 0;
1263 
1264 				bzero(cmd, SCSI_CMD_LEN);
1265 				cmd[0] = 0x28;				/* READ (10) command		*/
1266 				cmd[1] = 0;				/* normal access		*/
1267 				cmd[2] = (sector >> 24) & 0xff;
1268 				cmd[3] = (sector >> 16) & 0xff;
1269 				cmd[4] = (sector >>  8) & 0xff;
1270 				cmd[5] = (sector      ) & 0xff;
1271 				cmd[6] = 0;				/* reserved */
1272 				cmd[7] = (chunk >>  8) & 0xff;		/* MSB transfer */
1273 				cmd[8] = (chunk      ) & 0xff;		/* number of logical block(s) */
1274 				cmd[9] = 0;				/* control */
1275 				do {
1276 					error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, result, size_read - skipped, 30000, &sense);
1277 					/* TODO: if busy, ask drive how long it'll take to be available again and wait */
1278 					if (sense.asc == 4)
1279 						usleep(5000);
1280 				} while (sense.asc == 4);
1281 
1282 				if (error) return ENOENT;
1283 				break;
1284 			default :
1285 				/* XXX first and only reference to {p}read() XXX */
1286 				if (sector>=0)
1287 					size_read = pread(disc->dev->fhandle, result, (uint64_t) num_sectors * sector_size, sector * sector_size);
1288 				break;
1289 		}
1290 		/* statistics */
1291 		disc->sectors_read += size_read / sector_size;
1292 
1293 		/* swap space if requested */
1294 		if (disc->bswap_sectors) {
1295 			for (pos = 0; pos < size_read;) {
1296 				lb = result[pos  ];
1297 				hb = result[pos+1];
1298 				result[pos  ] = hb;
1299 				result[pos+1] = lb;
1300 				pos += 2;
1301 			}
1302 		}
1303 
1304 		/* advance */
1305 		num_sectors -= size_read / sector_size;
1306 		sector      += size_read / sector_size;
1307 		result      += size_read;
1308 		if (size_read <= 0) {
1309 			UDF_VERBOSE_MAX(
1310 				if (what) {
1311 					printf("Can't read sectors %d+%d for %s\n", (int) sector, num_sectors, what);
1312 				}
1313 			);
1314 			if (size_read == 0) return ENOENT;
1315 			return error;
1316 		}
1317 	}
1318 
1319 	return 0; /* flag ok */
1320 }
1321 
1322 
1323 /* write an extent of sectors to disc */
udf_write_physical_sectors(struct udf_discinfo * disc,off_t sector,uint32_t num_sectors,char * what,uint8_t * source)1324 int udf_write_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *source) {
1325 	struct uscsi_sense sense;
1326 	scsicmd    cmd;
1327 	int        trans_length, size, size_written, chunk;
1328 	uint32_t   sector_size;
1329 	uint8_t   *buffer;
1330 	int        lb, hb, pos, error;
1331 
1332 /*	if (!disc->udf_recording) return ENODEV; */
1333 
1334 	/* protect us */
1335 	if (((long) source) & 3) {
1336 		printf("Unaligned write of sector : possible panic() on some systems avoided\n");
1337 		return EIO;
1338 	}
1339 
1340 	sector_size = disc->sector_size;
1341 
1342 	/* XXX clean up XXX */
1343 	assert(sector_size);
1344 	assert(num_sectors <= 0xffff);					/* compatible with WRITE (10)? */
1345 
1346 	DEBUG(printf("\r%08d : %s ;WRITE %d bytes\n", (int) sector, what, num_sectors * sector_size));
1347 
1348 	/* swap space if requested */
1349 	buffer = source;
1350 	if (disc->bswap_sectors) {
1351 		size = num_sectors * sector_size;
1352 		buffer = malloc(num_sectors * sector_size);
1353 		for (pos = 0; pos < size;) {
1354 			lb = source[pos  ];
1355 			hb = source[pos+1];
1356 			buffer[pos  ] = hb;
1357 			buffer[pos+1] = lb;
1358 			pos += 2;
1359 		}
1360 	}
1361 
1362 	error = 0;
1363 	while (num_sectors) {
1364                 size_written = 0;
1365 
1366 		switch (disc->devdrv_class & UDF_DEVDRV_CLASS) {
1367 			case UDF_DEVDRV_CLASS_CD  :
1368 			case UDF_DEVDRV_CLASS_DVD :
1369 				/*
1370 				 * Use WRITE (12) command to write to the disc; we
1371 				 * might have to downgrade later to using WRITE (10)
1372 				 * on older discs though :-/
1373 				 */
1374 
1375 				/* limited by MAXPHYS, taking 64kb as limitation */
1376 				chunk        = MIN(64*1024 / sector_size, num_sectors);		/* in sectors */
1377 				trans_length = chunk;						/* in sectors */
1378 				bzero(cmd, SCSI_CMD_LEN);
1379 				cmd[ 0] = 0xAA;				/* WRITE (12)	*/
1380 				cmd[ 1] = 0;				/* no force unit access */
1381 				cmd[ 2] = (sector       >> 24) & 0xff;
1382 				cmd[ 3] = (sector       >> 16) & 0xff;
1383 				cmd[ 4] = (sector       >>  8) & 0xff;
1384 				cmd[ 5] = (sector            ) & 0xff;
1385 				cmd[ 6] = (trans_length >> 24) & 0xff;	/* MSB */
1386 				cmd[ 7] = (trans_length >> 16) & 0xff;
1387 				cmd[ 8] = (trans_length >>  8) & 0xff;
1388 				cmd[ 9] = (trans_length      ) & 0xff;	/* LSB  */
1389 				cmd[10] = 0;				/* no streaming */
1390 				cmd[11] = 0;				/* control */
1391 				do {
1392 					error = uscsi_command(SCSI_WRITECMD, disc->dev, cmd, 12, buffer, trans_length * sector_size, 30000, &sense);
1393 					/* TODO: if busy, ask drive how long it'll take to be available again and wait */
1394 					if (sense.asc == 4)
1395 						usleep(5000);
1396 				} while (sense.asc == 4);
1397 
1398 		                /* write one UDF sector at a physical address specified in UDF_SECTOR size units */
1399                 		size = trans_length * sector_size;
1400 				size_written = error ? 0 : size;
1401 				break;
1402 			default :
1403 				/* XXX first and only reference to {p}write() XXX */
1404 				DEBUG(printf("udf_discop: pwrite %"PRIu64" + %d\n", (uint64_t) sector * sector_size, (int) num_sectors * sector_size));
1405 		                /* write one UDF sector at a physical address specified in UDF_SECTOR size units */
1406                 		size = num_sectors * sector_size;
1407 				size_written = pwrite(disc->dev->fhandle, buffer, (uint64_t) num_sectors * sector_size, sector * sector_size);
1408 				if (size_written < 0)
1409 					size_written = 0;
1410 				break;
1411 		}
1412 
1413 		/* free our copy if we created one */
1414 		if (buffer != source)
1415 			free(buffer);
1416 
1417 		/* statistics */
1418 		disc->sectors_written += size_written / sector_size;
1419 		if (!disc->am_writing) disc->switchings++;
1420 		disc->am_writing = 1;
1421 
1422 		num_sectors -= size_written / sector_size;
1423 		sector      += size_written / sector_size;
1424 		buffer      += size_written;
1425 		if ((size_written < size) || error) {
1426 			DEBUG(if (error) printf("Writing %s at sectors %d+%d failed\n", what, (int) sector, num_sectors));
1427 			return EIO;
1428 		}
1429 	}
1430 
1431 	return 0;
1432 }
1433 
1434 
1435 /* End of udf_discinfo.c */
1436 
1437