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

📄 transport.hxx

📁 linux平台下的dvd刻录软件
💻 HXX
📖 第 1 页 / 共 3 页
字号:
	    req.ds_senselen = sizeof(_sense);	    req.ds_flags    = DSRQ_SENSE;	    req.ds_time     = 60*1000;	}	req.ds_cmdlen = i+1;	return cdb[i];    }    unsigned char &operator()(size_t i)	{ return _sense[i]; }    unsigned char *sense()		{ return _sense;    }    void timeout(int i)			{ req.ds_time=i*1000; }    size_t residue()			{ return req.ds_datalen-req.ds_datasent; }    int transport(Direction dir=NONE,void *buf=NULL,size_t sz=0)    { int ret=0,retries=3;	req.ds_databuf = (caddr_t)buf;	req.ds_datalen = sz;	req.ds_flags  |= dir;	// I personally don't understand why do we need to loop, but 	// /usr/share/src/irix/examples/scsi/lib/src/dslib.c is looping...	while (retries--)	{   if (ioctl(fd,DS_ENTER,&req) < 0)	return -1;	    if (req.ds_status==STA_GOOD)	return 0;	    if (req.ds_ret==DSRT_NOSEL)		continue;	    if (req.ds_status==STA_BUSY || req.ds_status==STA_RESERV)	    {	poll(NULL,0,500); continue;   }	    break;	}	errno=EIO; ret=-1;	if (req.ds_status==STA_CHECK && req.ds_sensesent>=14) 	{   ret = ERRCODE(_sense);	    if (ret==0)	ret=-1;	    else	CREAM_ON_ERRNO(_sense);	}	return ret;    }    // mimics umount(2), therefore inconsistent return values    int umount(int f=-1)    { struct stat    fsb,msb;      struct mntent *mb;      FILE          *fp;      pid_t          pid,rpid;      int            ret=0,rval;      char           hw_path[MAXPATHLEN];      int            hw_len=sizeof(hw_path)-1;	if (f==-1) f=fd;	if (fstat (f,&fsb) < 0)	return -1;	if (!getenv("MEDIAD_GOT_EXCLUSIVEUSE"))	{   if (attr_getf (f,"_devname",hw_path,&hw_len,0))	return -1;	    if (hw_len>=sizeof(hw_path)) hw_len=sizeof(hw_path)-1;// paranoia	    hw_path[hw_len]='\0';	    // mediad even unmounts removable volumes. However! The	    // locks are "granted" even for unmanaged devices, so	    // it's not possible to tell if device is ignored through	    // /etc/config/mediad.config or actually managed. Therefore	    // I have to pass through own unmount code in either case...	    mediad_get_exclusiveuse(hw_path,"dvd+rw-tools");	    switch (mediad_last_error())	    {	case RMED_NOERROR:	break;		case RMED_EACCESS:		case RMED_ECANTUMOUNT:	errno=EBUSY; return -1;		case RMED_ENOMEDIAD:	break;		case -1:	if(errno==ECONNREFUSED)	break;	// no mediad...				else			return -1;		default:	errno=ENOTTY; return -1;	    }	}	if ((fp=setmntent (MOUNTED,"r"))==NULL)	return -1;	while ((mb=getmntent (fp))!=NULL)	{   if (stat (mb->mnt_fsname,&msb) < 0)	continue; // corrupted line?	    // Following effectively catches only /dev/rdsk/dksXdYvol,	    // which is sufficient for iso9660 volumes, but not for e.g.	    // EFS formatted media. I mean code might have to be more	    // versatile... Wait for feedback...	    if (msb.st_rdev == fsb.st_rdev)	    {	ret = -1;		if ((pid = fork()) == (pid_t)-1)	break;		if (pid == 0) execl ("/sbin/umount","umount",mb->mnt_dir,NULL);		while (1)		{   rpid = waitpid (pid,&rval,0);		    if (rpid == (pid_t)-1)		    {	if (errno==EINTR)	continue;			else			break;		    }		    else if (rpid != pid)		    {	errno = ECHILD;			break;		    }		    if (WIFEXITED(rval))		    {	if (WEXITSTATUS(rval) == 0)	ret=0;			else				errno=EBUSY; // most likely			break;		    }		    else if (WIFSTOPPED(rval) || WIFCONTINUED(rval))			continue;		    else		    {	errno = ENOLINK;	// some phony errno			break;		    }		}		break;	    }	}	endmntent (fp);	return ret;    }#if 0	// for now just an idea to test...#define RELOAD_NEVER_NEEDED    int is_reload_needed ()    {  return 0;   }#else    int is_reload_needed ()    {	return 1;   }#endif};#elif defined(_WIN32)#if defined(__MINGW32__)#include <ddk/ntddscsi.h>#else#include <devioctl.h>#include <ntddscsi.h>#endiftypedef enum {	NONE=SCSI_IOCTL_DATA_UNSPECIFIED,		READ=SCSI_IOCTL_DATA_IN,		WRITE=SCSI_IOCTL_DATA_OUT	     } Direction;typedef struct {    SCSI_PASS_THROUGH_DIRECT	spt;    unsigned char		sense[18];} SPKG;class Scsi_Command {private:    HANDLE fd;    SPKG   p;public:    Scsi_Command()	{ fd=INVALID_HANDLE_VALUE; }    ~Scsi_Command()	{ if (fd!=INVALID_HANDLE_VALUE) CloseHandle (fd); }    int associate (const char *file)    { char dev[32];	sprintf(dev,"\\\\.\\%.*s",sizeof(dev)-5,file);	fd=CreateFile (dev,GENERIC_WRITE|GENERIC_READ,			   FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);	return fd!=INVALID_HANDLE_VALUE;    }    unsigned char &operator[] (size_t i)    {	if (i==0)	{   memset(&p,0,sizeof(p));	    p.spt.Length = sizeof(p.spt);	    p.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;	    p.spt.TimeOutValue = 30;	    p.spt.SenseInfoLength = sizeof(p.sense);	    p.spt.SenseInfoOffset = offsetof(SPKG,sense);	}	p.spt.CdbLength = i+1;	return p.spt.Cdb[i];    }    unsigned char &operator()(size_t i)	{ return p.sense[i]; }    unsigned char *sense()		{ return p.sense;    }    void timeout(int i)			{ p.spt.TimeOutValue=i; }    size_t residue()			{ return 0; } // bogus    int transport(Direction dir=NONE,void *buf=NULL,size_t sz=0)    { DWORD bytes;      int   ret=0;	p.spt.DataBuffer = buf;	p.spt.DataTransferLength = sz;	p.spt.DataIn = dir;	if (DeviceIoControl (fd,IOCTL_SCSI_PASS_THROUGH_DIRECT,				&p,sizeof(p.spt),				&p,sizeof(p),				&bytes,FALSE) == 0) return -1;	if (p.sense[0]&0x70)	{   SetLastError (ERROR_GEN_FAILURE);	    ret = ERRCODE(p.sense);	    if (ret==0) ret=-1;	    else	CREAM_ON_ERRNO(p.sense);	}	return ret;    }    int umount ()		{   return 0;   }	// bogus    int is_reload_needed ()	{   return 0;   }	// bogus};#else#error "Unsupported OS"#endif#define DUMP_EVENTS 0static int handle_events (Scsi_Command &cmd){ unsigned char  event[8];  unsigned short profile=0,started=0;  int err,ret=0;  unsigned int descr;  static unsigned char events=0xFF;	// "All events"    while (events)    {	cmd[0] = 0x4A;		// GET EVENT	cmd[1] = 1;		// "Polled"	cmd[4] = events;	cmd[8] = sizeof(event);	cmd[9] = 0;	if ((err=cmd.transport(READ,event,sizeof(event))))	{   events=0;	    sperror ("GET EVENT",err);	    return ret;	}	events = event[3];	if ((event[2]&7) == 0			||	    (event[0]<<8|event[1]) == 2	|| 	    (event[4]&0xF) == 0			)	// No Changes	    return ret;	descr  = event[4]<<24|event[5]<<16|event[6]<<8|event[7];#if DUMP_EVENTS	fprintf(stderr,"< %d[%08x],%x >\n",event[2],descr,events);#endif	switch(event[2]&7)	{   case 0: return ret;			// No [supported] events	    case 1: ret |= 1<<1;		// Operational Change		if ((descr&0xFFFF) < 3)		    goto read_profile;	    start_unit:	    	if (!started)		{   cmd[0]=0x1B;	// START STOP UNIT		    cmd[4]=1;		// "Start"		    cmd[5]=0;		    if ((err=cmd.transport()) && err!=0x62800)			sperror ("START UNIT",err);		    started=1, profile=0;		}	    read_profile:		if (!profile)		{   cmd[0] = 0x46;	// GET CONFIGURATION		    cmd[8] = sizeof(event);		    cmd[9] = 0;		    if (!cmd.transport(READ,event,sizeof(event)))			profile=event[6]<<8|event[7];		}		break;	    case 2: ret |= 1<<2;		// Power Management		if (event[5]>1)		// State is other than Active		    goto start_unit;		break;	    case 3: ret |= 1<<3; break;		// External Request	    case 4: ret |= 1<<4;		// Media		if (event[5]&2)		// Media in		    goto  start_unit;		break;	    case 5: ret |= 1<<5; break;		// Multiple Initiators	    case 6:				// Device Busy		if ((event[4]&0xF)==1)	// Timeout occured		{   poll(NULL,0,(descr&0xFFFF)*100+100);		    cmd[0] = 0;		// TEST UNIT READY		    cmd[5] = 0;		    if ((err=cmd.transport()))			sperror("TEST UNIT READY",err);		    ret |= 1<<6;		}		break;	    case 7: ret |= 1<<7; break;		// Reserved	}    }  return ret;}#undef DUMP_EVENTSstatic int wait_for_unit (Scsi_Command &cmd,volatile int *progress=NULL){ unsigned char *sense=cmd.sense(),sensebuf[18];  int  err;  long msecs=1000;    while (1)    {	if (msecs > 0) poll(NULL,0,msecs);	msecs = getmsecs();	cmd[0] = 0;	// TEST UNIT READY	cmd[5] = 0;	if (!(err=cmd.transport ())) break;	// I wish I could test just for sense.valid, but (at least)	// hp dvd100i returns 0 in valid bit at this point:-( So I	// check for all bits...	if ((sense[0]&0x70)==0)	{   perror (":-( unable to TEST UNIT READY");	    return -1;	}	else if (sense[12]==0x3A) // doesn't get any further than "no media"	    return err;	while (progress)	{   if (sense[15]&0x80)	    {	*progress = sense[16]<<8|sense[17];		break;	    }	    // MMC-3 (draft) specification says that the unit should	    // return progress indicator in key specific bytes even	    // in reply to TEST UNIT READY. I.e. as above! But (at	    // least) hp dvd100i doesn't do that and I have to fetch	    // it separately:-(	    cmd[0] = 0x03;	// REQUEST SENSE	    cmd[4] = sizeof(sensebuf);	    cmd[5] = 0;	    if ((err=cmd.transport (READ,sensebuf,sizeof(sensebuf))))	    {   sperror ("REQUEST SENSE",err);		return err;	    }	    if (sensebuf[15]&0x80)		*progress = sensebuf[16]<<8|sensebuf[17];	    break;	}	msecs = 1000 - (getmsecs() - msecs);    }  return 0;}#define FEATURE21_BROKEN 1static void page05_setup (Scsi_Command &cmd, unsigned short profile=0,	unsigned char p32=0xC0)	// 5 least significant bits of p32 go to p[2], Test Write&Write Type	// 2 most significant bits go to p[3], Multi-session field	// 0xC0 means "Multi-session, no Test Write, Incremental"{ unsigned int   len,bdlen;  unsigned char  header[12],track[32],*p;#if !FEATURE21_BROKEN  unsigned char  feature21[24];#endif  int            err;  class autofree page05;    if (profile==0)    { unsigned char prof[8];	cmd[0] = 0x46;	// GET CONFIGURATION	cmd[8] = sizeof(prof);	cmd[9] = 0;	if ((err=cmd.transport(READ,prof,sizeof(prof))))	    sperror ("GET CONFIGURATION",err), exit(FATAL_START(errno));	profile = prof[6]<<8|prof[7];    }#if !FEATURE21_BROKEN    if (profile==0x11 || profile==0x14)    {	cmd[0] = 0x46;	// GET CONFIGURATION	cmd[1] = 2;	// ask for the only feature...	cmd[3] = 0x21;	// the "Incremental Streaming Writable" one	cmd[8] = 8;	// read the header only to start with	cmd[9] = 0;	if ((err=cmd.transport(READ,feature21,8)))	    sperror ("GET CONFIGURATION",err), exit(FATAL_START(errno));	len = feature21[0]<<24|feature21[1]<<16|feature21[2]<<8|feature21[3];	len += 4;	if (len>sizeof(feature21))	    len = sizeof(feature21);	else if (len<(8+8))	    fprintf (stderr,":-( READ FEATURE DESCRIPTOR 0021h: insane length\n"),	    exit(FATAL_START(EINVAL));	cmd[0] = 0x46;	// GET CONFIGURATION	cmd[1] = 2;	// ask for the only feature...	cmd[3] = 0x21;	// the "Incremental Streaming Writable" one	cmd[8] = len;	// this time with real length	cmd[9] = 0;	if ((err=cmd.transport(READ,feature21,len)))	    sperror ("READ FEATURE DESCRIPTOR 0021h",err),	    exit(FATAL_START(errno));	if ((feature21[8+2]&1)==0)	    fprintf (stderr,":-( FEATURE 0021h is not in effect\n"),	    exit(FATAL_START(EMEDIUMTYPE));    }    else	feature21[8+2]=0;#endif    cmd[0] = 0x52;	// READ TRACK INFORMATION    cmd[1] = 1;		// TRACK INFORMATION    cmd[5] = 1;		// track#1, in DVD context it's safe to assume    			//          that all tracks are in the same mode    cmd[8] = sizeof(track);    cmd[9] = 0;    if ((err=cmd.transport(READ,track,sizeof(track))))	sperror ("READ TRACK INFORMATION",err), exit(FATAL_START(errno));    // WRITE PAGE SETUP //    cmd[0] = 0x5A;		// MODE SENSE    cmd[1] = 0x08;		// "Disable Block Descriptors"    cmd[2] = 0x05;		// "Write Page"    cmd[8] = sizeof(header);	// header only to start with    cmd[9] = 0;    if ((err=cmd.transport(READ,header,sizeof(header))))	sperror ("MODE SENSE",err), exit(FATAL_START(errno));    len   = (header[0]<<8|header[1])+2;    bdlen = header[6]<<8|header[7];    if (bdlen)	// should never happen as we set "DBD" above    {	if (len <= (8+bdlen+14))	    fprintf (stderr,":-( LUN is impossible to bear with...\n"),	    exit(FATAL_START(EINVAL));    }    else if (len < (8+2+(unsigned int)header[9]))// SANYO does this.	len = 8+2+header[9];    page05 = (unsigned char *)malloc(len);    if (page05 == NULL)	fprintf (stderr,":-( memory exhausted\n"),	exit(FATAL_START(ENOMEM));    cmd[0] = 0x5A;		// MODE SENSE    cmd[1] = 0x08;		// "Disable Block Descriptors"    cmd[2] = 0x05;		// "Write Page"    cmd[7] = len>>8;    cmd[8] = len;		// real length this time    cmd[9] = 0;    if ((err=cmd.transport(READ,page05,len)))	sperror("MODE SENSE",err), exit(FATAL_START(errno));    len -= 2;    if (len < ((unsigned int)page05[0]<<8|page05[1]))	// paranoia:-)	page05[0] = len>>8, page05[1] = len;    len   = (page05[0]<<8|page05[1])+2;    bdlen = page05[6]<<8|page05[7];    len  -= bdlen;    if (len < (8+14))	fprintf (stderr,":-( LUN is impossible to bear with...\n"),	exit(FATAL_START(EINVAL));    p = page05 + 8 + bdlen;    memset (p-8,0,8);    p[0] &= 0x7F;    // copy "Test Write" and "Write Type" from p32    p[2] &= ~0x1F, p[2] |= p32&0x1F;	    p[2] |= 0x40;	// insist on BUFE on    // setup Preferred Link Size#if !FEATURE21_BROKEN    if (feature21[8+2]&1)    {	if (feature21[8+7])	p[2] |= 0x20,  p[5] = feature21[8+8];	else			p[2] &= ~0x20, p[5] = 0;    }#else	// At least Pioneer DVR-104 returns some bogus data in	// Preferred Link Size...    if (profile==0x11 || profile==0x14)	// Sequential recordings...	p[2] |= 0x20, p[5] = 0x10;#endif    else	p[2] &= ~0x20, p[5] = 0;    // copy Track Mode from TRACK INFORMATION    // [some DVD-R units (most notably Panasonic LF-D310), insist    // on Track Mode 5, even though it's effectively ignored]    p[3] &= ~0x0F, p[3] |= profile==0x11?5:(track[5]&0x0F);    // copy "Multi-session" bits from p32    p[3] &= ~0xC0, p[3] |= p32&0xC0;    if (profile == 0x13)	// DVD-RW Restricted Overwrite    	p[3] &= 0x3F;		// always Single-session?    // setup Data Block Type    if ((track[6]&0x0F)==1)	p[4] = 8;    else	fprintf (stderr,":-( none Mode 1 track\n"),		exit(FATAL_START(EMEDIUMTYPE));    // setup Packet Size    // [some DVD-R units (most notably Panasonic LF-D310), insist    // on fixed Packet Size of 16 blocks, even though it's effectively    // ignored]    p[3] |= 0x20, memset (p+10,0,4), p[13] = 0x10;    if (track[6]&0x10)	memcpy (p+10,track+20,4);	// Fixed    else if (profile != 0x11)	p[3] &= ~0x20, p[13] = 0;	// Variable    switch (profile)    {	case 0x13:	// DVD-RW Restricted Overwrite	    if (!(track[6]&0x10))		fprintf (stderr,":-( track is not formatted for fixed packet size\n"),		exit(FATAL_START(EMEDIUMTYPE));	    break;	case 0x14:	// DVD-RW Sequential Recording	case 0x11:	// DVD-R  Sequential Recording	    if (track[6]&0x10)		fprintf (stderr,":-( track is formatted for fixed packet size\n"),		exit(FATAL_START(EMEDIUMTYPE));	    break;	default:#if 0	    fprintf (stderr,":-( invalid profile %04xh\n",profile);	    exit(FATAL_START(EMEDIUMTYPE));#endif	    break;    }    p[8] = 0;		// "Session Format" should be ignored, but			// I reset it just in case...    cmd[0] = 0x55;	// MODE SELECT    cmd[1] = 0x10;	// conformant    cmd[7] = len>>8;    cmd[8] = len;    cmd[9] = 0;    if ((err=cmd.transport(WRITE,p-8,len)))	sperror ("MODE SELECT",err), exit(FATAL_START(errno));    // END OF WRITE PAGE SETUP //}#undef FEATURE21_BROKEN#undef ERRCODE#undef CREAM_ON_ERRNO#undef CREAM_ON_ERRNO_NAKED

⌨️ 快捷键说明

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