Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
parent
a5ab33f563
commit
78e12f4a56
268
kernel/cdromfs.c
Normal file
268
kernel/cdromfs.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
Copyright (C) 2016-2019 The University of Notre Dame
|
||||
This software is distributed under the GNU General Public License.
|
||||
See the file LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "kmalloc.h"
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/error.h"
|
||||
#include "string.h"
|
||||
#include "page.h"
|
||||
#include "fs.h"
|
||||
#include "fs_internal.h"
|
||||
#include "cdromfs.h"
|
||||
#include "iso9660.h"
|
||||
#include "device.h"
|
||||
#include "bcache.h"
|
||||
|
||||
static struct fs_dirent *cdrom_dirent_create(struct fs_volume *volume, int sector, int length, int isdir)
|
||||
{
|
||||
struct fs_dirent *d = kmalloc(sizeof(*d));
|
||||
if(!d) return 0;
|
||||
|
||||
d->volume = volume;
|
||||
d->refcount = 1;
|
||||
d->size = length;
|
||||
d->isdir = isdir;
|
||||
d->cdrom.sector = sector;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static int cdrom_dirent_read_block(struct fs_dirent *d, char *buffer, uint32_t blocknum)
|
||||
{
|
||||
int nblocks = bcache_read(d->volume->device, buffer, 1, d->cdrom.sector + blocknum);
|
||||
if(nblocks == 1) {
|
||||
return CDROMFS_BLOCK_SIZE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void fix_filename(char *name, int length)
|
||||
{
|
||||
// Plain files typically end with a semicolon and version, remove it.
|
||||
if(length > 2 && name[length - 2] == ';') {
|
||||
length -= 2;
|
||||
}
|
||||
// Files without a suffix end with a dot, remove it.
|
||||
if(length > 1 && name[length - 1] == '.') {
|
||||
length--;
|
||||
}
|
||||
// In any case, null-terminate the string
|
||||
name[length] = 0;
|
||||
|
||||
// And make it lowercase
|
||||
strtolower(name);
|
||||
}
|
||||
|
||||
static struct fs_dirent *cdrom_dirent_lookup(struct fs_dirent *dir, const char *name)
|
||||
{
|
||||
if(!dir->isdir) return 0;
|
||||
|
||||
char *temp = page_alloc(0);
|
||||
if(!temp) return 0;
|
||||
|
||||
int nsectors = dir->size / CDROMFS_BLOCK_SIZE + (dir->size % CDROMFS_BLOCK_SIZE ? 1 : 0);
|
||||
|
||||
int i;
|
||||
for(i=0;i<nsectors;i++) {
|
||||
cdrom_dirent_read_block(dir,temp,i);
|
||||
// XXX check result here!
|
||||
|
||||
struct iso_9660_directory_entry *d = (struct iso_9660_directory_entry *) temp;
|
||||
|
||||
while(d->descriptor_length > 0) {
|
||||
|
||||
const char *dname;
|
||||
int dname_length;
|
||||
|
||||
if(d->ident[0] == 0) {
|
||||
dname = ".";
|
||||
dname_length = 2;
|
||||
} else if(d->ident[0] == 1) {
|
||||
dname = "..";
|
||||
dname_length = 3;
|
||||
} else {
|
||||
fix_filename(d->ident, d->ident_length);
|
||||
dname = d->ident;
|
||||
dname_length = strlen(dname) + 1;
|
||||
}
|
||||
|
||||
if(!strncmp(name,dname,dname_length)) {
|
||||
struct fs_dirent *r;
|
||||
r = cdrom_dirent_create(
|
||||
dir->volume,
|
||||
d->first_sector_little,
|
||||
d->length_little,
|
||||
d->flags & ISO_9660_EXTENT_FLAG_DIRECTORY);
|
||||
page_free(temp);
|
||||
return r;
|
||||
}
|
||||
d = (struct iso_9660_directory_entry *) ((char *) d + d->descriptor_length);
|
||||
}
|
||||
}
|
||||
|
||||
page_free(temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdrom_dirent_close( struct fs_dirent *d )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdrom_dirent_list(struct fs_dirent *dir, char *buffer, int buffer_length)
|
||||
{
|
||||
if(!dir->isdir) return KERROR_NOT_A_DIRECTORY;
|
||||
|
||||
char *temp = page_alloc(0);
|
||||
if(!temp) return KERROR_OUT_OF_MEMORY;
|
||||
|
||||
int nsectors = dir->size / CDROMFS_BLOCK_SIZE + (dir->size % CDROMFS_BLOCK_SIZE ? 1 : 0);
|
||||
int total = 0;
|
||||
|
||||
int i;
|
||||
for(i=0;i<nsectors;i++) {
|
||||
cdrom_dirent_read_block(dir,temp,i);
|
||||
|
||||
struct iso_9660_directory_entry *d = (struct iso_9660_directory_entry *) temp;
|
||||
|
||||
while(d->descriptor_length > 0 && buffer_length > 0) {
|
||||
|
||||
const char *dname;
|
||||
int dname_length;
|
||||
|
||||
if(d->ident[0] == 0) {
|
||||
dname = ".";
|
||||
dname_length = 2;
|
||||
} else if(d->ident[0] == 1) {
|
||||
dname = "..";
|
||||
dname_length = 3;
|
||||
} else {
|
||||
fix_filename(d->ident, d->ident_length);
|
||||
dname = d->ident;
|
||||
dname_length = strlen(dname) + 1;
|
||||
}
|
||||
|
||||
// If there is enough space, keep copying items.
|
||||
// If not, count them up to return the value.
|
||||
|
||||
if (buffer_length > dname_length) {
|
||||
strcpy(buffer,dname);
|
||||
buffer += dname_length;
|
||||
buffer_length -= dname_length;
|
||||
}
|
||||
|
||||
total += dname_length;
|
||||
|
||||
d = (struct iso_9660_directory_entry *) ((char *) d + d->descriptor_length);
|
||||
}
|
||||
}
|
||||
|
||||
page_free(temp);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static struct fs_volume *cdrom_volume_create( struct device *device )
|
||||
{
|
||||
struct fs_volume *v = kmalloc(sizeof(*v));
|
||||
if(!v) return 0;
|
||||
|
||||
memset(v, 0, sizeof(struct fs_volume));
|
||||
v->device = device;
|
||||
v->refcount = 1;
|
||||
v->block_size = device_block_size(device);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static int cdrom_volume_close(struct fs_volume *v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fs_volume *cdrom_volume_open( struct device *device )
|
||||
{
|
||||
struct fs_volume *v = cdrom_volume_create(device);
|
||||
|
||||
struct iso_9660_volume_descriptor *d = page_alloc(0);
|
||||
if(!d) {
|
||||
kfree(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("cdromfs: scanning %s unit %d...\n",device_name(device),device_unit(device));
|
||||
|
||||
int j;
|
||||
|
||||
for(j = 0; j < 16; j++) {
|
||||
printf("cdromfs: checking volume %d\n", j);
|
||||
|
||||
bcache_read(device, (char*)d, 1, j + 16);
|
||||
// XXX check reuslt
|
||||
|
||||
if(strncmp(d->magic, "CD001", 5))
|
||||
continue;
|
||||
|
||||
if(d->type == ISO_9660_VOLUME_TYPE_PRIMARY) {
|
||||
v->cdrom.root_sector = d->root.first_sector_little;
|
||||
v->cdrom.root_length = d->root.length_little;
|
||||
v->cdrom.total_sectors = d->nsectors_little;
|
||||
v->device = device;
|
||||
|
||||
printf("cdromfs: mounted filesystem on %s-%d\n", device_name(v->device), device_unit(v->device));
|
||||
|
||||
page_free(d);
|
||||
|
||||
return v;
|
||||
|
||||
} else if(d->type == ISO_9660_VOLUME_TYPE_TERMINATOR) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
page_free(d);
|
||||
cdrom_volume_close(v);
|
||||
|
||||
printf("cdromfs: no filesystem found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fs_dirent *cdrom_volume_root(struct fs_volume *v)
|
||||
{
|
||||
return cdrom_dirent_create(v,v->cdrom.root_sector,v->cdrom.root_length, 1);
|
||||
}
|
||||
|
||||
const static struct fs_ops cdrom_ops = {
|
||||
.volume_open = cdrom_volume_open,
|
||||
.volume_close = cdrom_volume_close,
|
||||
.volume_root = cdrom_volume_root,
|
||||
|
||||
.lookup = cdrom_dirent_lookup,
|
||||
.mkdir = 0,
|
||||
.mkfile = 0,
|
||||
.read_block = cdrom_dirent_read_block,
|
||||
.write_block = 0,
|
||||
.list = cdrom_dirent_list,
|
||||
.remove = 0,
|
||||
.resize = 0,
|
||||
.close = cdrom_dirent_close,
|
||||
};
|
||||
|
||||
static struct fs cdrom_fs = {
|
||||
"cdromfs",
|
||||
&cdrom_ops,
|
||||
0
|
||||
};
|
||||
|
||||
int cdrom_init()
|
||||
{
|
||||
fs_register(&cdrom_fs);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user