📄 cdrwtool.c
字号:
/* * cdrwtool - perform all sort of actions on a CD-R, CD-RW, and DVD-R drive. * * Copyright (c) 1999,2000 Jens Axboe <axboe@suse.de> * Copyright (c) 2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <getopt.h>#include <signal.h>#include <sys/ioctl.h>#include <asm/param.h>#include <linux/cdrom.h>#include "cdrwtool.h"#include "../mkudffs/mkudffs.h"static int progress;int msf_to_lba(int m, int s, int f){ return (((m * 60) + s) * 75) + f;}void hexdump(const void *buffer, int size){ unsigned char *ptr = (unsigned char *) buffer; int i; for (i = 0; i < size; i++) printf("%02x ", ptr[i]); printf("\n");}void dump_sense(unsigned char *cdb, struct request_sense *sense){ int i; printf("Command failed: "); for (i=0; i<12; i++) printf("%02x ", cdb[i]); if (sense) { printf("- sense %02x.%02x.%02x\n", sense->sense_key, sense->asc, sense->ascq); } else { printf(", no sense\n"); }}int wait_cmd(int fd, struct cdrom_generic_command *cgc, unsigned char *buf, int dir, int timeout){ struct request_sense sense; int ret; if (cgc->timeout <= 0) cgc->timeout = 500; memset(&sense, 0, sizeof(sense)); cgc->buffer = buf; cgc->data_direction = dir; cgc->sense = &sense; cgc->timeout = timeout; ret = ioctl(fd, CDROM_SEND_PACKET, cgc); if (ret) { perror("wait_cmd"); dump_sense(cgc->cmd, cgc->sense); } return ret;}int sigfd;void sig_progress(int sig){ struct cdrom_generic_command cgc; struct request_sense sense; static int did = 0; int ret; memset(&cgc, 0, sizeof(cgc)); memset(&sense, 0, sizeof(sense)); cgc.sense = &sense; ret = wait_cmd(sigfd, &cgc, NULL, CGC_DATA_NONE, WAIT_PC); if (!(sense.sks[0] & 0x80) && !did) { printf("Progress indicator not implemented on this drive\n"); printf("Don't access drive until operation has completed\n"); progress = 101; return; } progress = ((sense.sks[1] << 8 | sense.sks[2]) * 100) / 0xffff; did = 1; printf("%02d%% complete\n", progress); if (progress == 99) { progress = 101; return; } alarm(2);}void print_completion_info(int fd){ sigfd = fd; /* we can only poll sense for non-blocking commands */#if USE_IMMED == 0 return;#else progress = 0; signal(SIGALRM, sig_progress); alarm(5); while (progress < 100) sleep(1);#endif}/* buffer must already have been filled by mode_sense */int mode_select(int fd, unsigned char *buffer, int len){ struct cdrom_generic_command cgc; memset(&cgc, 0, sizeof(cgc)); memset(buffer, 0, 3); cgc.cmd[0] = GPCMD_MODE_SELECT_10; cgc.cmd[1] = 1 << 4; cgc.cmd[8] = cgc.buflen = len; return wait_cmd(fd, &cgc, buffer, CGC_DATA_WRITE, WAIT_PC);}int mode_sense(int fd, unsigned char *buffer, int page, char pc, int size){ struct cdrom_generic_command cgc; memset(&cgc, 0, sizeof(cgc)); cgc.cmd[0] = GPCMD_MODE_SENSE_10;// cgc.cmd[1] = 1 << 4; cgc.cmd[2] = page | pc << 6; cgc.cmd[8] = cgc.buflen = size; return wait_cmd(fd, &cgc, buffer, CGC_DATA_READ, WAIT_PC);}int set_write_mode(int fd, write_params_t *w){ unsigned char header[0x10]; unsigned char *buffer; int ret, len, offset; memset(header, 0x00, sizeof(header)); len = 0x10; if ((ret = mode_sense(fd, header, GPMODE_WRITE_PARMS_PAGE, PAGE_DEFAULT, len)) < 0) { perror("mode_sense_write"); return ret; } len = 2 + (((header[0] & 0xff) << 8) | (header[1] & 0xff)); offset = 8 + (((header[6] & 0xff) << 8) | (header[7] & 0xff)); buffer = calloc(len, sizeof(unsigned char)); if ((ret = mode_sense(fd, buffer, GPMODE_WRITE_PARMS_PAGE, PAGE_DEFAULT, len)) < 0) { perror("mode_sense_write"); return ret; } buffer[offset+2] = w->ls_v << 5; buffer[offset+3] = w->track_mode | w->fpacket << 5 | w->border << 6; buffer[offset+4] = w->data_block & 0xf; buffer[offset+5] = w->link_size; buffer[offset+8] = w->session_format & 0xff; buffer[offset+10] = (w->packet_size >> 24) & 0xff; buffer[offset+11] = (w->packet_size >> 16) & 0xff; buffer[offset+12] = (w->packet_size >> 8) & 0xff; buffer[offset+13] = w->packet_size & 0xff; /* sub-header is only a mode-2 thing */ if (w->data_block == 10) { buffer[offset+48] = 0x00; buffer[offset+49] = 0x00; buffer[offset+50] = 0x08; buffer[offset+51] = 0x00; } if ((ret = mode_select(fd, buffer, len)) < 0) { hexdump(buffer, len); free(buffer); perror("mode_select"); return ret; } free(buffer); return 0;} int get_write_mode(int fd, write_params_t *w){ unsigned char header[0x10]; unsigned char *buffer; int ret, len, offset; memset(header, 0x00, sizeof(header)); len = 0x10; if ((ret = mode_sense(fd, header, GPMODE_WRITE_PARMS_PAGE, PAGE_CURRENT, len)) < 0) { perror("mode_sense_write"); return ret; } len = 2 + (((header[0] & 0xff) << 8) | (header[1] & 0xff)); offset = 8 + (((header[6] & 0xff) << 8) | (header[7] & 0xff)); buffer = calloc(len, sizeof(unsigned char)); if ((ret = mode_sense(fd, buffer, GPMODE_WRITE_PARMS_PAGE, PAGE_CURRENT, len)) < 0) { perror("mode_sense_write"); return ret; } w->ls_v = (buffer[offset+2] >> 5) & 1; w->border = (buffer[offset+3] >> 6) & 3; w->fpacket = (buffer[offset+3] >> 5) & 1; w->track_mode = buffer[offset+3] & 0xf; w->data_block = buffer[offset+4] & 0xf; w->link_size = buffer[offset+5]; w->session_format = buffer[offset+8]; w->packet_size = buffer[offset+13]; free(buffer); return 0;}int sync_cache(int fd){ struct cdrom_generic_command cgc; memset(&cgc, 0, sizeof(cgc)); cgc.cmd[0] = 0x35; cgc.cmd[1] = 2; return wait_cmd(fd, &cgc, NULL, CGC_DATA_NONE, WAIT_SYNC);}int write_blocks(int fd, char *buffer, int lba, int blocks){ struct cdrom_generic_command cgc; memset(&cgc, 0, sizeof(cgc)); cgc.cmd[0] = GPCMD_WRITE_10;#if 0 cgc.cmd[1] = 1 << 3;#endif cgc.cmd[2] = (lba >> 24) & 0xff; cgc.cmd[3] = (lba >> 16) & 0xff; cgc.cmd[4] = (lba >> 8) & 0xff; cgc.cmd[5] = lba & 0xff; cgc.cmd[7] = (blocks >> 8) & 0xff; cgc.cmd[8] = blocks & 0xff; cgc.buflen = blocks * CDROM_BLOCK; return wait_cmd(fd, &cgc, buffer, CGC_DATA_WRITE, WAIT_SYNC);}int write_file(int fd, struct cdrw_disc *disc){ int file, lba, size, blocks; char *buf = NULL; int ret = 0, go_on = 1; if ((file = open(disc->filename, O_RDONLY)) < 0) { fprintf(stderr, "can't open %s\n", disc->filename); return 1; } /* for fixed packets, the write size is set. variable packets, * we write a little less than the buffer capacity. the drive * probably uses some of this for internal housekeeping, and * we want to completely eliminate buffer underruns. */ size = disc->fpacket ? disc->packet_size * CDROM_BLOCK : 63 * CDROM_BLOCK; lba = disc->offset; buf = (char *) malloc(size+1); if (buf == NULL) return 1; while (!ret && go_on) { blocks = disc->fpacket ? disc->packet_size : size / CDROM_BLOCK; ret = read(file, buf, size); if (ret == -1) { perror("read from file"); break; } else if (ret < size) { /* not enough data to complete the packet. fill * the rest of the data block with zeros. we must * write out complete packets every time with * fixed packets. for variable packets we just * write what we have left. */ if (disc->fpacket) { memset(&buf[ret], 0, size - ret - 1); } else { blocks = (ret + CDROM_BLOCK - 1) / CDROM_BLOCK; } /* regardless of type, this is the last write */ go_on = 0; } fprintf(stdout, "writing at lba = %d, blocks = %d\n", lba, blocks); if ((ret = write_blocks(fd, buf, lba, blocks))) break; /* sync to indicate that one packet has been sent */// sync_cache(fd); /* for fixed packets, the run-in/run-out blocks are * contained within the packet size. variable packets * don't count them as part of the written size. */ lba += blocks;// lba += disc->fpacket ? 0 : 7; } sync_cache(fd); close(file); free(buf); return ret;}int blank_disc(int fd, int type){ struct cdrom_generic_command cgc; int ret; memset(&cgc, 0, sizeof(cgc)); cgc.cmd[0] = GPCMD_BLANK; cgc.cmd[1] = (type == BLANK_FULL ? 0 : 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -