LINUX.ORG.RU

Считывание секторов с DVD дисков


0

1

Приветствую.
Я разрабатываю приложение для работы с CD\DVD дисками. Одна из задач - считывание сырых секторов с дисков (достаточно считывать только user data). Реализовано все через SCSI драйвер. С CD дисками разобрался, считываю секторы командой READ CD (код 0xBE), все нормально (использовал материалы из этого и этого документов). Но когда начал работать с DVD дисками, считать секторы тем же методом не удалось. В документах, которые я указал выше вроде бы не упоминается, что для работы с DVD нужно что-то особенное. Подскажите как быть, куда копать? Заранее спасибо.


Ответ на: комментарий от darkenshvein

dd не подходит в моем случае, к сожалению

sliff
() автор топика

Если тебе не нужны специфичные для оптических дисков данные (всякие там субканалы и коды коррекции) используй обычный SCSI READ 10 (0x28). У меня работало и для CD и для DVD (правда под виндой).

Если ты пытаешься читать DVD-видео, то нужно что-то делать с CSS - смотри libdvdread и libdvdcss.

anonymous
()
Ответ на: комментарий от anonymous

Да, спец данные не нужны. DVD-видео тоже не нужно. Можно попросить примеры командного пакета и\или функции отправки команды? Вроде делаю функцию для READ 10 по той же схеме что и для READ CD. Вторая работает, первая - нет, выдает 4 08 00 LOGICAL UNIT COMMUNICATION FAILURE.

Еще вопрос в догонку: какой командой узнать объем записаной информации на двд?

sliff
() автор топика
Ответ на: комментарий от sliff

Примеры для винды:

#define SCSI_READ10    0x28
#define SEC_SIZE 2048
#define MAX_COUNT 32

BOOL ReadCDROM(UNI_ADDR *addr, unsigned LBA, unsigned count, void *buf)
    {
    UNI_SRB usrb;
    BOOL ret;
    unsigned read_now;
    void *batch;
    
    usrb.Addr=*addr;
    batch=SCSIBatchBegin(&usrb);
    if(batch==NULL)
        {
        SCSILastError=usrb.Err;
        return FALSE;
        }

    while(count>0)
        {
        if(count>MAX_COUNT)
            read_now=MAX_COUNT;
        else
            read_now=count;
        ZeroMemory(&usrb, sizeof(usrb));
        usrb.Addr=*addr;
        usrb.CDBLen=10;
        usrb.CDB[0]=SCSI_READ10;
        usrb.CDB[2]=(unsigned char)(LBA>>24);
        usrb.CDB[3]=(unsigned char)(LBA>>16);
        usrb.CDB[4]=(unsigned char)(LBA>>8);
        usrb.CDB[5]=(unsigned char)LBA;
        usrb.CDB[7]=(unsigned char)(read_now>>8);
        usrb.CDB[8]=(unsigned char)read_now;
        usrb.DataLen=read_now*SEC_SIZE;
        usrb.DataBuffer=buf;
        usrb.DataOut=0;
        usrb.SenseLen=sizeof(usrb.SenseBuffer);

        ret=SCSIBatchCmd(&usrb, batch);

        if(!ret)
            {
            SCSILastError=usrb.Err;
            break;
            }

        count-=read_now;
        LBA+=read_now;
        buf=read_now*SEC_SIZE+(unsigned char *)buf;
        }

    SCSIBatchEnd(batch);

    return ret;
    }

#define SCSI_READCDCAP    0x25

unsigned ReadCDROMCapacity(UNI_ADDR *addr)
    {
    UNI_SRB usrb;
    unsigned char buf[16];
    BOOL ret;
    unsigned LBA;
        
    ZeroMemory(&usrb, sizeof(usrb));
    usrb.Addr=*addr;
    usrb.CDBLen=10;
    usrb.CDB[0]=SCSI_READCDCAP;
    usrb.DataLen=sizeof(buf);
    usrb.DataBuffer=buf;
    usrb.DataOut=0;
    usrb.SenseLen=sizeof(usrb.SenseBuffer);

    ret=SCSICmd(&usrb);
            
    if(ret)
        LBA=(buf[0]<<24)|(buf[1]<<16)|
            (buf[2]<<8)|buf[3];
    else
        LBA=0;

    return LBA;
    }

Не помню, почему чтение по 32 сектора, но какая-то причина наверное была :)

cdslow ★★
()
Ответ на: комментарий от cdslow

спасибо большое! будем копать...

sliff
() автор топика
Ответ на: комментарий от cdslow

У меня интересная ситуация возникает. Судя по всему, команда READ читает какой-то буфер. При первом чтении показывает мусор. А если сначала выполнить READ CD, а потом READ, то последний вернет тоже самое, что и первый. Кто-нибудь сталкивался с подобной ситуацией?

sliff
() автор топика
Ответ на: комментарий от sliff

У меня работает для CD и для DVD:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
#include <inttypes.h>

int read_capacity(int fd);
int read_sectors(int fd, int LBA, int count, void *buf);

int main(int argc, char *argv[])
    {
    int fd;
    int capacity;
    unsigned char buf[CD_FRAMESIZE * 1];

    if(argc != 2)
        {
        fprintf(stderr, "Call: readcd /dev/cdrom\n");
        return EXIT_FAILURE;
        }

    fd = open(argv[1], O_RDONLY | O_NONBLOCK);
    if(fd < 0)
        {
        perror(argv[1]);
        return EXIT_FAILURE;
        }

    capacity = read_capacity(fd);

    if(capacity == 0)
        return EXIT_FAILURE;

    printf("Capacity: %d sectors (%" PRIuMAX " bytes)\n", capacity, (uintmax_t)capacity * CD_FRAMESIZE);

    if(read_sectors(fd, 16, 1, buf) != 0)
        return EXIT_FAILURE;

    close(fd);

    fd = creat("sectors.dat", 0666);
    if(fd < 0)
        {
        perror("sectors.dat");
        return EXIT_FAILURE;
        }

    write(fd, buf, sizeof(buf));

    close(fd);

    printf("Volume: '%.32s'\n", buf + 0x28);

    return EXIT_SUCCESS;
    }

int read_capacity(int fd)
    {
    struct cdrom_generic_command cgc;
    struct request_sense sense;
    unsigned char buf[16];
    int LBA;

    memset(&sense, 0, sizeof(sense));

    memset(&cgc, 0, sizeof(cgc));
    cgc.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
    cgc.buffer = buf;
    cgc.buflen = sizeof(buf);
    cgc.sense = &sense;
    cgc.data_direction = CGC_DATA_READ;

    if(ioctl(fd, CDROM_SEND_PACKET, &cgc) != 0)
        {
        perror("GPCMD_READ_CDVD_CAPACITY");
        return 0;
        }

    LBA = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];

    return LBA;
    }

int read_sectors(int fd, int LBA, int count, void *buf)
    {
    struct cdrom_generic_command cgc;
    struct request_sense sense;
    int ret;

    memset(&sense, 0, sizeof(sense));

    memset(&cgc, 0, sizeof(cgc));
    cgc.cmd[0] = GPCMD_READ_10;
    cgc.cmd[2] = (unsigned char)(LBA >> 24);
    cgc.cmd[3] = (unsigned char)(LBA >> 16);
    cgc.cmd[4] = (unsigned char)(LBA >> 8);
    cgc.cmd[5] = (unsigned char)LBA;
    cgc.cmd[7] = (unsigned char)(count >> 8);
    cgc.cmd[8] = (unsigned char)count;
    cgc.buffer = buf;
    cgc.buflen = count * CD_FRAMESIZE;
    cgc.sense = &sense;
    cgc.data_direction = CGC_DATA_READ;

    ret = ioctl(fd, CDROM_SEND_PACKET, &cgc);

    if(ret != 0)
        perror("GPCMD_READ_10");

    return ret;
    }

cdslow ★★
()
Ответ на: комментарий от cdslow

еще интересно почему нельзя считать больше 30 секторов за раз

sliff
() автор топика
Ответ на: комментарий от sliff

если кому интересно, моя ошибка была лишь в том, что для «переворачивания» полей командного пакета я использовал функции __swab32() и __swab16(). После замены их на «ручную» перестановку как в примере все заработало.

sliff
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.