static struct dentry * cdfs_lookup(struct inode *dir, struct dentry *dentry){ #else static struct dentry * cdfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ #endif struct inode * inode; int i; cd * this_cd = cdfs_info(dir->i_sb); PRINT("cdfs_lookup %s ino=%ld \n", dentry->d_name.name, dir->i_ino); for(i=0; i<T2I(this_cd->tracks); i++) if (!(strcmp(this_cd->track[i].name, dentry->d_name.name))) { goto found; } return ERR_PTR(-ENOENT); /* Use goto and read inode with iget()/cdfs_iget() */ /* Thanks to David Howells for patch and Master class in his mail */ found: #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) inode = cdfs_iget(dir->i_sb, i); if (IS_ERR(inode)) return ERR_CAST(inode); #else inode = iget(dir->i_sb, i); if (!inode) return ERR_PTR(-ENOMEM); #endif d_add(dentry, inode); return NULL; } /***************************************************************************/ static struct file_operations cdfs_dir_operations = { .read = generic_read_dir, .readdir = cdfs_readdir, }; static struct inode_operations cdfs_inode_operations = { .lookup = cdfs_lookup }; /**************************************************************************/ static void cdfs_read_inode(struct inode *i) { cd * this_cd = cdfs_info(i->i_sb); PRINT("this_cd = 0x%x\n", (unsigned)this_cd); PRINT("read inode %ld\n", i->i_ino); i->i_uid = this_cd->uid; i->i_gid = this_cd->gid; i->i_nlink = 1; i->i_op = &cdfs_inode_operations; i->i_fop = NULL; i->i_data.a_ops = NULL; if (i->i_ino <= 2) { /* . and .. */ i->i_size = 0; /* Uuugh ?? */ i->i_mtime = i->i_atime = i->i_ctime = CURRENT_TIME; i->i_mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; i->i_fop = &cdfs_dir_operations; } else { /* file */ i->i_size = this_cd->track[i->i_ino].size; #ifdef OLD_KERNEL i->i_mtime = i->i_atime = i->i_ctime = this_cd->track[i->i_ino].time; #else i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = this_cd->track[i->i_ino].time; i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0; #endif i->i_mode = this_cd->mode; if ((this_cd->track[i->i_ino].type==DATA) && this_cd->track[i->i_ino].iso_size) { i->i_fop = &cdfs_cddata_file_operations; i->i_data.a_ops = &cdfs_cddata_aops; } else if (this_cd->track[i->i_ino].type==AUDIO) { i->i_fop = &cdfs_cdda_file_operations; if (this_cd->raw_audio) i->i_data.a_ops = &cdfs_cdda_raw_aops; else i->i_data.a_ops = &cdfs_cdda_aops; } else if (this_cd->track[i->i_ino].type==BOOT) { i->i_fop = &cdfs_cddata_file_operations; i->i_data.a_ops = &cdfs_cddata_aops; } else if (this_cd->track[i->i_ino].type==HFS) { if (this_cd->track[i->i_ino].hfs_offset) { i->i_fop = &cdfs_cdhfs_file_operations; /* Bummer, this partition isn't properly aligned... */ i->i_data.a_ops = &cdfs_cdhfs_aops; } else { i->i_fop = &cdfs_cddata_file_operations; i->i_data.a_ops = &cdfs_cddata_aops; } } else { i->i_fop = &cdfs_cdXA_file_operations; i->i_data.a_ops = &cdfs_cdXA_aops; } } }
void cdfs_check_bootable(struct super_block *sb){ struct buffer_head * bh1, * bh2, *bh3; cd * this_cd = cdfs_info(sb); int boottrack=0; int no_bootimage=0; int sectionoffset=0; if (!(bh1 = cdfs_bread(sb, 17, CD_FRAMESIZE))) return; /* sector 17 is unreadable */ else if (!strncmp(bh1->b_data+7, "EL TORITO", 9)) { PRINT("BOOT, catalog at %d\n", *(unsigned int*)(bh1->b_data+71)); bh2 = cdfs_bread(sb, *(unsigned int*)(bh1->b_data+71), CD_FRAMESIZE); PRINT("Catalog:\n\tHeader ID=%d, Platform ID=%d, Developer ID=%s\n", *(unsigned char*)(bh2->b_data), *(unsigned char*)(bh2->b_data+1), bh2->b_data+4); do { this_cd->tracks++; boottrack = this_cd->tracks+2; PRINT("\tInitial/Default entry: %x Bootable, media: %d\n", *(unsigned char*)(bh2->b_data+32+0+sectionoffset), *(unsigned char*)(bh2->b_data+32+1+sectionoffset) & 15); PRINT("\tSector count: %d, Load LBA: %d\n", *(unsigned short*)(bh2->b_data+32+6+sectionoffset), *(unsigned int*)(bh2->b_data+32+8+sectionoffset)); this_cd->track[boottrack].type = BOOT; this_cd->track[boottrack].start_lba = *(unsigned int*) (bh2->b_data+32+8+sectionoffset); this_cd->track[boottrack].size = cdfs_bootmedia[ *(unsigned char*)(bh2->b_data+32+1+sectionoffset) & 15].size; if (!this_cd->track[boottrack].size) this_cd->track[boottrack].size = *(unsigned short*) (bh2->b_data+32+6+sectionoffset) * CD_FRAMESIZE ; this_cd->track[boottrack].stop_lba = this_cd->track[boottrack]. start_lba + this_cd->track[boottrack].size/CD_FRAMESIZE -1; this_cd->track[boottrack].time = 0; sprintf(this_cd->track[boottrack].name,"boot.image_%d",no_bootimage); strncpy(this_cd->track[boottrack].bootID, bh2->b_data+4+sectionoffset,24); /* 27?? */ this_cd->track[boottrack].bootID[24]=0; /* get first sector from boot image */ bh3=cdfs_bread(sb, this_cd->track[boottrack].start_lba, CD_FRAMESIZE); if ((*(unsigned char*)(bh3->b_data+511)==0xAA) && (*(unsigned char*)(bh3->b_data+512)==0x55)) { strcat(this_cd->track[boottrack].bootID, "\n\tType: x86 boot sector, "); if (!strncmp(bh3->b_data+2, "LILO", 4)) strcat(this_cd->track[boottrack].bootID, "LILO boot/chain loader with "); else if (!strncmp(bh3->b_data+495, "LDLINUX", 7)) { strncat(this_cd->track[boottrack].bootID, bh3->b_data+495, 12); strcat(this_cd->track[boottrack].bootID, " boot loader with "); } if (*(unsigned short*)(bh3->b_data+0x438)==0xEF53) strcat(this_cd->track[boottrack].bootID, "Linux/i386 ext2 filesystem\n"); else /* FAT */ strncat(this_cd->track[boottrack].bootID, bh3->b_data+54, 8); /* FAT type */ } brelse(bh3); if (sectionoffset==0) sectionoffset=0x60; sectionoffset=sectionoffset+0x20; } while (*(unsigned char*)(bh2->b_data+0x42)>no_bootimage++); brelse(bh2); } brelse(bh1); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) cdfs_iget(sb,boottrack); #endif }
static struct super_block * cdfs_mount(struct super_block *sb, void *data, int silent){ kdev_t dev = sb->s_dev; int i, j, t; struct cdrom_tochdr hdr; #else static int cdfs_fill_super(struct super_block *sb, void *data, int silent){ int i, t; #endif struct cdrom_tocentry entry; int no_audio=0, no_data=0; cd * this_cd; struct inode *retinode; PRINT("cdfs_mount\n"); #ifdef OLD_KERNEL MOD_INC_USE_COUNT; set_blocksize(dev, CD_FRAMESIZE); // voor bread met ide-cd #else sb_set_blocksize(sb, CD_FRAMESIZE); // voor bread met ide-cd #endif sb->s_blocksize = CD_FRAMESIZE; sb->s_blocksize_bits = 11; if (!(this_cd = cdfs_info(sb) = kmalloc(sizeof(cd), GFP_KERNEL))){ #ifdef OLD_KERNEL MOD_DEC_USE_COUNT; return NULL; #else return -ENOMEM; #endif } this_cd->mode = MODE; this_cd->gid = GID; this_cd->uid = UID; this_cd->single = FALSE; this_cd->raw_audio = 0; this_cd->toc_scsi = FALSE; // Initialize cache for maximum sector size if (!(this_cd->cache = kmalloc(CD_FRAMESIZE_RAWER*CACHE_SIZE, GFP_KERNEL))) { #ifdef OLD_KERNEL MOD_DEC_USE_COUNT; return NULL; #else kfree(cdfs_info(sb)); return -ENOMEM; #endif } // Cache is still invalid this_cd->cache_sector = -CACHE_SIZE; cdfs_parse_options((char *) data, this_cd); /* Populate CD info with '.' and '..' */ strcpy(this_cd->track[1].name, "."); this_cd->track[1].start_lba=0; strcpy(this_cd->track[2].name, ".."); this_cd->track[2].start_lba=0; this_cd->nr_iso_sessions = 0; this_cd->size = 0; if (this_cd->toc_scsi){ if (cdfs_toc_read_full(sb)){ printk("TOC read failed\n"); #ifdef OLD_KERNEL MOD_DEC_USE_COUNT; return NULL; #else goto invalid; #endif } } else { //if (cdfs_ioctl(sb, CDROMREADTOCHDR, (unsigned long)&hdr)){ if (cdfs_toc_read(sb)){ printk("cdfs_toc_read failed\n"); #ifdef OLD_KERNEL MOD_DEC_USE_COUNT; return NULL; #else goto invalid; #endif } } PRINT("CD contains %d tracks\n", this_cd->tracks); /* Collect track info */ entry.cdte_format = CDROM_LBA; for (t=this_cd->tracks; t>=0; t--) { i = T2I(t); // j = this_cd->tracks-i; // entry.cdte_track = (t==this_cd->tracks) ? CDROM_LEADOUT : t+1; // PRINT("Read track %d/%d/%d\n", entry.cdte_track, t, i); // if (cdfs_ioctl(sb, CDROMREADTOCENTRY, (unsigned long)&entry)){ // printk("ioctl(CDROMREADTOCENTRY) failed\n"); // MOD_DEC_USE_COUNT; // return NULL; // } // this_cd->track[i].start_lba = entry.cdte_addr.lba; // this_cd->track[i].stop_lba = this_cd->track[i+1].start_lba - 1; this_cd->track[i].track_size = this_cd->track[i+1].start_lba - this_cd->track[i].start_lba; /* in sectors! */ PRINT("Start[%d]: %d\n", i, this_cd->track[i].start_lba); if (t!=this_cd->tracks) { /* all tracks but the LEADOUT */ if (this_cd->track[i].type==DATA) { //int track=i; no_data++; this_cd->track[i].iso_info = cdfs_get_iso_info(sb, i); if (this_cd->track[i].iso_info) { this_cd->track[i].time = cdfs_constructtime((char*)&(this_cd->track[i].iso_info->creation_date)); this_cd->track[i].iso_size = cdfs_constructsize((char*)&(this_cd->track[i].iso_info->volume_space_size)) * CD_FRAMESIZE; if (!this_cd->single) this_cd->track[i].iso_size += this_cd->track[i].start_lba * CD_FRAMESIZE; this_cd->track[i].track_size *= CD_FRAMESIZE; this_cd->track[i].size = this_cd->track[i+1].start_lba * CD_FRAMESIZE; sprintf(this_cd->track[i].name, this_cd->single ? DATA_NAME_SINGLE : DATA_NAME_ISO, t+1); this_cd->lba_iso_sessions[this_cd->nr_iso_sessions].start = this_cd->track[i].start_lba; this_cd->lba_iso_sessions[this_cd->nr_iso_sessions].stop = this_cd->track[i].iso_size/CD_FRAMESIZE; this_cd->nr_iso_sessions++; cdfs_get_hfs_info(sb, i); // possibly also a HFS } else { // DATA, but no ISO -> either HFS or VideoCD if (cdfs_get_hfs_info(sb, i)==-1){ printk("CHECKING VIDEOCD!!\n"); cdfs_get_XA_info(sb, i); this_cd->track[i].time = 0; this_cd->track[i].iso_size = 0; this_cd->track[i].track_size = (this_cd->track[i].track_size-1) * this_cd->track[i].xa_data_size; this_cd->track[i].size = this_cd->track[i].track_size; sprintf(this_cd->track[i].name, DATA_NAME_VCD, no_data); } else { // HFS, no ISO, no VideoCD -> remove track this_cd->track[i].iso_info = NULL; this_cd->track[i].type = 0; } } } else { no_audio++; this_cd->track[i].iso_info = NULL; this_cd->track[i].type = AUDIO; this_cd->track[i].time = get_seconds(); this_cd->track[i].iso_size = 0; this_cd->track[i].track_size = this_cd->track[i].track_size * CD_FRAMESIZE_RAW + ((this_cd->raw_audio==0)?WAV_HEADER_SIZE:0); this_cd->track[i].size = this_cd->track[i].track_size; this_cd->track[i].avi = 0; sprintf(this_cd->track[i].name, (this_cd->raw_audio)? RAW_AUDIO_NAME:AUDIO_NAME, t+1); if (this_cd->raw_audio) { /* read the first sector. */ struct cdrom_read_audio cdda; int status,k,j,prevk=0; char* buf; buf=kmalloc(CD_FRAMESIZE_RAW*2,GFP_KERNEL); if(buf==NULL) { printk(FSNAME ": kmalloc failed in root.c !\n"); return(-ENOMEM); } for (j=0;j<10;j++) { cdda.addr_format = CDROM_LBA; cdda.nframes = 1; cdda.buf = buf+CD_FRAMESIZE_RAW; cdda.addr.lba = this_cd->track[i].start_lba+j; status = cdfs_ioctl(sb,CDROMREADAUDIO,(unsigned long)&cdda); if (status) { printk("cdfs_ioctl(CDROMREADAUDIO,%d) ioctl failed: %d\n", cdda.addr.lba, status); goto out; } /* search the first non-zero byte */ for (k=0;k<CD_FRAMESIZE_RAW;k++) if (buf[k+CD_FRAMESIZE_RAW]) break; if (k<=CD_FRAMESIZE_RAW-4) break; prevk=k; if (k<CD_FRAMESIZE_RAW) for (k=0;k<CD_FRAMESIZE_RAW;k++) buf[k]=buf[k+CD_FRAMESIZE_RAW]; } if (j==10) goto out; if ((j!=0)&&(prevk!=CD_FRAMESIZE_RAW)) { k=prevk; j--; } else k+=CD_FRAMESIZE_RAW; this_cd->track[i].avi_offset = j*CD_FRAMESIZE_RAW+k-CD_FRAMESIZE_RAW; if ((buf[k]=='R')&&(buf[k+1]=='I')&& (buf[k+2]=='F')&&(buf[k+3]=='F')) { this_cd->track[i].avi = 1; this_cd->track[i].avi_swab = 0; } else if ((buf[k]=='I')&&(buf[k+1]=='R')&& (buf[k+2]=='F')&&(buf[k+3]=='F')) { this_cd->track[i].avi = 1; this_cd->track[i].avi_swab = 1; } if (this_cd->track[i].avi) { if ((this_cd->track[i].avi_offset&1)!=0) { printk("AVI offset is not even, error\n"); this_cd->track[i].avi=0; } else { this_cd->track[i].track_size -= this_cd->track[i].avi_offset; sprintf(this_cd->track[i].name, AVI_AUDIO_NAME, t+1); } } out: kfree(buf); } } // Calculate total CD size this_cd->size += this_cd->track[i].track_size; PRINT("Track %2d: (%dB)\n", t, this_cd->track[i].size); } // else CDROM_LEADOUT } PRINT("CD ends at %d\n", this_cd->track[this_cd->tracks].start_lba); /* take care to get disc id after the toc has been read. JP, 29-12-2001 */ this_cd->discid = discid(this_cd); //////////////////////////////// /* Check if CD is bootable */ if (this_cd->track[T2I(0)].type==DATA) cdfs_check_bootable(sb); /* Check for an HFS partition in the first data track */ /*if (no_data) { i=T2I(0); while (i<T2I(this_cd->tracks)) { if (this_cd->track[i].type==DATA) break; i++; } cdfs_get_hfs_info(sb, i); } */ PRINT("%d audio tracks and %d data tracks => %dbytes\n", no_audio, no_data, this_cd->size); sb->s_magic = CDFS_MAGIC; sb->s_flags |= MS_RDONLY; sb->s_op = &cdfs_ops; /* always get inode status */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) retinode=cdfs_iget(sb, 0); #else retinode=iget(sb, 0); #endif if ( IS_ERR(retinode) ) return PTR_ERR(retinode); PRINT("retinode = %ld\n", retinode->i_ino); sb->s_root = d_alloc_root(retinode); cdfs_proc_cd = this_cd; #ifdef OLD_KERNEL return sb; #else return 0; invalid: kfree(this_cd->cache); kfree(cdfs_info(sb)); return -EINVAL; #endif }