⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 growisofs_mmc.cpp

📁 linux平台下的dvd刻录软件
💻 CPP
📖 第 1 页 / 共 4 页
字号:
#ifndef _LARGEFILE_SOURCE#define _LARGEFILE_SOURCE#endif#ifndef _LARGEFILE64_SOURCE#define _LARGEFILE64_SOURCE#endif#ifndef _FILE_OFFSET_BITS#define _FILE_OFFSET_BITS 64#endif#if defined(__linux)/* ... and "engage" glibc large file support */#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#endif#include "transport.hxx"#include <time.h>#include <sys/types.h>#include <signal.h>#define sigs_mask(how)	do {	\    sigset_t mask;		\				\    sigemptyset (&mask);	\    sigaddset (&mask,SIGHUP),	sigaddset (&mask,SIGINT),	\    sigaddset (&mask,SIGTERM),	sigaddset (&mask,SIGPIPE);	\					\    sigprocmask (how,&mask,NULL);	\} while (0)#define	ONEX 1352	// 1385 * 1000 / 1024static int           media_written=0,next_track=1,velocity=0,		     is_dao=0,quickgrown=0,do_reload=1;static void         *ioctl_handle=(void *)-1;#ifndef ioctl_fd#define ioctl_fd ((long)ioctl_handle)#endifstatic unsigned int  next_wr_addr=1;	// it starts as booleanstatic unsigned int  buf_size=256;	// measured in 1KBsstatic unsigned char formats[260],disc_info[32];extern int	dvd_compat,test_write,no_reload,mmc_profile,_argc,wrvfy;extern double	speed_factor;extern char	*ioctl_device,**_argv;extern "C"int fumount (int fd){ Scsi_Command cmd;  return cmd.umount(fd);}extern "C"int media_reload (char *name=NULL,struct stat *sb=NULL){   if (name==NULL)    {	Scsi_Command cmd(ioctl_handle);	while (1)	// Pioneer DVR-x06 needs this...	{   cmd[0] = 0x1B;	// START/STOP UNIT	    cmd[1] = 0x1;	// "IMMED"	    cmd[4] = 0;		// "Stop"	    cmd[5] = 0;	    if (cmd.transport() == 0x20407)	// "OP IN PROGRESS"	    {	poll (NULL,0,333);		continue;	    }	    break;	}#if defined(RELOAD_NEVER_NEEDED)#undef RELOAD_NEVER_NEEDED#define RELOAD_NEVER_NEEDED 1#else#define RELOAD_NEVER_NEEDED 0#endif	if (RELOAD_NEVER_NEEDED || no_reload>0)	{   cmd[0] = 0x1E;	// ALLOW MEDIA REMOVAL	    cmd[5] = 0;	    cmd.transport ();	    return (errno=0);	}#if !RELOAD_NEVER_NEEDED	char str[12];	int n;		if ((n=fcntl (ioctl_fd,F_GETFD))<0) n=0;	fcntl (ioctl_fd,F_SETFD,n&~FD_CLOEXEC);	sprintf (str,"%d",ioctl_fd);	execlp(_argv[0],"-reload",str,ioctl_device,NULL);    }    else    {	{ Scsi_Command cmd;	    if (!cmd.associate (name,sb)) return 1;	    if (cmd.is_reload_needed())	    {	fprintf (stderr,"%s: reloading tray\n",name);		cmd[0] = 0x1E;		// ALLOW MEDIA REMOVAL		cmd[5] = 0;		if (cmd.transport ()) return 1;		while (1)	// Pioneer DVR-x05 needs this...		{   cmd[0] = 0x1B;	// START/STOP UNIT		    cmd[1] = 0x1;	// "IMMED"		    cmd[4] = 0x2;	// "Eject"		    cmd[5] = 0;		    if (cmd.transport() == 0x20407) // "OP IN PROGRESS"		    {	poll (NULL,0,333);			continue;		    }		    break;		}		// yes, once again, non-"IMMED"...		cmd[0] = 0x1B;		// START/STOP UNIT		cmd[4] = 0x2;		// "Eject"		cmd[5] = 0;		if (cmd.transport()) return 1;	    }#if defined(__sun) || defined(sun)	    else if (volmgt_running())	    {	setuid(getuid());		execl("/usr/bin/volrmmount","volrmmount","-i",name,NULL);		return 0;	// not normally reached	    }#endif	    else return 0;	// m-m-m-m! patched kernel:-)	}	if (no_reload>=0)	{ Scsi_Command cmd;	    if (cmd.associate (name,sb))	    {	cmd[0] = 0x1B;		// START/STOP UNIT		cmd[1] = 0x1;		// "IMMED"		cmd[4] = 0x3;		// "Load"		cmd[5] = 0;		cmd.transport ();	    }	    errno=0;	// ignore all errors on load	}	return 0;#endif    }  return 1;}extern "C"int get_mmc_profile (void *fd){ Scsi_Command cmd(fd);  unsigned char buf[8],inq[128];  int profile=0,once=1,blank=0,err;  unsigned int len;    // INQUIRY is considered to be "non-intrusive" in a sense that    // it won't interfere with any other operation nor clear sense    // data, which might be important to retain for security reasons.    cmd[0] = 0x12;	// INQUIRY    cmd[4] = 36;    cmd[5] = 0;    if ((err=cmd.transport(READ,inq,36)))	sperror ("INQUIRY",err),	exit (FATAL_START(errno));    // make sure we're talking to MMC unit, for security reasons...    if ((inq[0]&0x1F) != 5)	fprintf (stderr,":-( not an MMC unit!\n"),	exit (FATAL_START(EINVAL));    do {	cmd[0] = 0x46;	cmd[8] = sizeof(buf);	cmd[9] = 0;	if ((err=cmd.transport(READ,buf,sizeof(buf))))	    sperror ("GET CONFIGURATION",err),	    fprintf (stderr,":-( non-MMC unit?\n"),	    exit (FATAL_START(errno));        if ((profile = buf[6]<<8|buf[7]) || !once) break;	// no media?	cmd[0] = 0;	// TEST UNIT READY	cmd[5] = 0;	if ((cmd.transport()&0xFFF00) != 0x23A00) break;	// try to load tray...	cmd[0] = 0x1B;	// START/STOP UNIT	cmd[4] = 0x3;	// "Load"	cmd[5] = 0;	if ((err=cmd.transport ()))	    sperror ("LOAD TRAY",err),	    exit (FATAL_START(errno));#if 1	wait_for_unit (cmd);#else	// consume sense data, most likely "MEDIA MAY HAVE CHANGED"	cmd[0] = 0;	// TEST UNIT READY	cmd[5] = 0;	if ((err=cmd.transport ()) == -1)	    sperror ("TEST UNIT READY",err),	    exit (FATAL_START(errno));#endif    } while (once--);    if (profile==0 || (profile&0x30)==0)	// no or non-DVD media...	return profile;    cmd[0] = 0x51;	// READ DISC INFORMATION    cmd[8] = sizeof(disc_info);    cmd[9] = 0;    if ((err=cmd.transport (READ,disc_info,sizeof(disc_info))))	sperror ("READ DISC INFORMATION",err),	exit (FATAL_START(errno));    // see if it's blank media    if ((disc_info[2]&3) == 0)	blank=0x10000;    if (profile != 0x1A && profile != 0x13 && profile != 0x12)	return blank|profile;    cmd[0] = 0x23;	// READ FORMAT CAPACITIES    cmd[8] = 12;    cmd[9] = 0;    if ((err=cmd.transport (READ,formats,12)))	sperror ("READ FORMAT CAPACITIES",err),	exit (FATAL_START(errno));    len = formats[3];    if (len&7 || len<16)	fprintf (stderr,":-( FORMAT allocaion length isn't sane"),	exit (FATAL_START(EINVAL));    cmd[0] = 0x23;	// READ FORMAT CAPACITIES    cmd[7] = (4+len)>>8;    cmd[8] = (4+len)&0xFF;    cmd[9] = 0;    if ((err=cmd.transport (READ,formats,4+len)))	sperror ("READ FORMAT CAPACITIES",err),	exit (FATAL_START(errno));    if (len != formats[3])	fprintf (stderr,":-( parameter length inconsistency\n"),	exit(FATAL_START(EINVAL));    // see if it's not formatted    if ((formats[8]&3) != 2) blank = 0x10000;  return blank|profile;}static unsigned int get_2k_capacity (Scsi_Command &cmd){ unsigned char	buf[32];  unsigned int	ret=0;  unsigned int	nwa,free_blocks;  int		i,obligatory,len,err;    obligatory=0x00;    switch (mmc_profile&0xFFFF)    {	case 0x1A:		// DVD+RW	    obligatory=0x26;	case 0x13:		// DVD-RW Restricted Overwrite	    for (i=8,len=formats[3];i<len;i+=8)		if ((formats [4+i+4]>>2) == obligatory) break;	    if (i==len)	    {	fprintf (stderr,":-( can't locate obligatory format descriptor\n");		return 0;	    }	    ret  = formats[4+i+0]<<24;	    ret |= formats[4+i+1]<<16;	    ret |= formats[4+i+2]<<8;	    ret |= formats[4+i+3];	    nwa = formats[4+5]<<16|formats[4+6]<<8|formats[4+7];	    if (nwa>2048)	ret *= nwa/2048;	    else if (nwa<2048)	ret /= 2048/nwa;	    break;	case 0x12:		// DVD-RAM	    // As for the moment of this writing I don't format DVD-RAM.	    // Therefore I just pull formatted capacity for now...	    ret  = formats[4+0]<<24;	    ret |= formats[4+1]<<16;	    ret |= formats[4+2]<<8;	    ret |= formats[4+3];	    nwa = formats[4+5]<<16|formats[4+6]<<8|formats[4+7];	    if (nwa>2048)	ret *= nwa/2048;	    else if (nwa<2048)	ret /= 2048/nwa;	    break;	case 0x11:		// DVD-R	case 0x14:		// DVD-RW Sequential	case 0x1B:		// DVD+R	case 0x2B:		// DVD+R Double Layer	    cmd[0] = 0x52;	// READ TRACK INFORMATION	    cmd[1] = 1;	    cmd[4] = next_track>>8;	    cmd[5] = next_track&0xFF;	// last track, set up earlier	    cmd[8] = sizeof(buf);	    cmd[9] = 0;	    if ((err=cmd.transport (READ,buf,sizeof(buf))))	    {	sperror ("READ TRACK INFORMATION",err);		return 0;	    }	    nwa = 0;	    if (buf[7]&1)	// NWA_V	    {	nwa  = buf[12]<<24;		nwa |= buf[13]<<16;		nwa |= buf[14]<<8;		nwa |= buf[15];	    }	    free_blocks  = buf[16]<<24;	    free_blocks |= buf[17]<<16;	    free_blocks |= buf[18]<<8;	    free_blocks |= buf[19];	    ret = nwa + free_blocks;	    break;	default:	    break;    }  return ret;}extern "C"off64_t get_capacity (void *fd){ Scsi_Command	cmd(fd);  return (off64_t)get_2k_capacity(cmd)*2048;}ssize_t poor_mans_pwrite64 (int fd,const void *_buff,size_t size,off64_t foff){ Scsi_Command		cmd(ioctl_handle);	/* screw first argument */  unsigned char		bcap[12];  const unsigned char  *buff=(const unsigned char *)_buff;  unsigned int		lba,nbl,bsize,bfree;  int			retries=0,errcode;  static int		dao_toggle=-1;    if (foff&0x7FFF || size&0x7FFF)	// 32K block size	return (errno=EINVAL,-1);    lba = foff>>11;    nbl = size>>11;    if (!media_written && next_wr_addr)    {	if ((lba+nbl) <= next_wr_addr)	    return size;	else if (next_wr_addr > lba)	    nbl  -= (next_wr_addr-lba),	    size -= (next_wr_addr-lba)<<11,	    buff += (next_wr_addr-lba)<<11,	    lba   = next_wr_addr;    }#if defined(__sun) || defined(sun)    else    next_wr_addr = lba;#endif    if (dao_toggle<0) dao_toggle=is_dao;    { static unsigned int first_wr_addr=0;	if (!media_written)	{   sigs_mask (SIG_BLOCK); first_wr_addr = lba;	}	else if (lba >= (first_wr_addr+buf_size/2)) // measured in 2KBs!	{   sigs_mask (SIG_UNBLOCK);			}    }    while (1)    {	cmd[0] = wrvfy?0x2E:0x2A;	// WRITE [AND VERIFY] (10)	cmd[2] = (lba>>24)&0xff;	// Logical Block Addrss	cmd[3] = (lba>>16)&0xff;	cmd[4] = (lba>>8)&0xff;	cmd[5] = lba&0xff;	cmd[7] = (nbl>>8)&0xff;	cmd[8] = nbl&0xff;	cmd[9] = 0;#if 0	cmd[0] = 0xAA;			// WRITE(12)	cmd[2] = (lba>>24)&0xff;	// Logical Block Addrss	cmd[3] = (lba>>16)&0xff;	cmd[4] = (lba>>8)&0xff;	cmd[5] = lba&0xff;	cmd[8] = (nbl>>8)&0xff;	cmd[9] = nbl&0xff;	cmd[10] = 0x80;			// "Streaming"	cmd[11] = 0;#endif	//	// First writes can be long, especially in DAO mode...	// I wish I could complement this with "if (lba==0),"	// but some units might choose to fill the buffer before	// they take the first nap...	//	cmd.timeout(dao_toggle?180:60);	//	// It should also be noted that under Linux these values	// (if actually respected by kernel!) can turn out bogus.	// The problem is that I scale them to milliseconds as	// documentation requires/implies, while kernel treats	// them as "jiffies." I could/should have used HZ macro	// (or sysconf(_SC_CLK_TCK)), but recent kernels maintain	// own higher HZ value and disrespects the user-land one.	// Sending them down as milliseconds is just safer...	//	if (!(errcode=cmd.transport (WRITE,(void *)buff,size)))	    break;	//--- WRITE failed ---//#if defined(__sun) || defined(sun)	//	// Solaris can slice USB WRITEs to multiple ones. Here I try	// to find out which slice has failed. I expect we get here	// only when we re-enter the loop...	//	if (lba==next_wr_addr &&	    errcode==0x52102)		// "INVALID ADDRESS FOR WRITE"	{ unsigned char track[32];	    cmd[0] = 0x52;		// READ TRACK INFORMATION	    cmd[1] = 1;	    cmd[4] = next_track>>8;	    cmd[5] = next_track&0xFF;	    cmd[8] = sizeof(track);	    cmd[9] = 0;	    if (!cmd.transport (READ,track,sizeof(track)))	    {	if (track[7]&1)	// NWA_V		{   next_wr_addr  = track[12]<<24;		    next_wr_addr |= track[13]<<16;		    next_wr_addr |= track[14]<<8;		    next_wr_addr |= track[15];		    if (lba<next_wr_addr && (lba+nbl)>next_wr_addr)		    {	nbl  -= next_wr_addr-lba,			size -= (next_wr_addr-lba)<<11,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -