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

📄 cdfs.c

📁 一个小型操作系统的源代码,其目的仅 仅是为了在x86电脑上在没有windows 操作系统的情况下能使用java虚拟机。 研究操作系统的好东西。
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// cdfs.c
//
// ISO-9660 CD-ROM Filesystem
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

#include <os/krnl.h>
#include "iso9660.h"

#define CDFS_DEFAULT_CACHESIZE 128
#define CDFS_BLOCKSIZE         2048

struct cdfs
{
  dev_t devno;
  int blks;
  int volblks;
  int vdblk;
  int joliet;
  struct bufpool *cache;
  unsigned char *path_table_buffer;
  struct iso_pathtable_record **path_table;
  int path_table_records;
};

struct cdfs_file
{
  int extent;
  int size;
  time_t date;
};

static int cdfs_fnmatch(struct cdfs *cdfs, char *fn1, int len1, char *fn2, int len2)
{
  if (cdfs->joliet)
  {
    wchar_t *wfn2 = (wchar_t *) fn2;
    int wlen2 = len2 / 2;
    if (wlen2 > 1 && ntohs(wfn2[wlen2 - 2]) == ';') wlen2 -= 2;
    if (wlen2 > 0 && ntohs(wfn2[wlen2 - 1]) == '.') wlen2 -= 1;
    if (len1 != wlen2) return 0;
    while (len1--) if (*fn1++ != ntohs(*wfn2++)) return 0;
    return 1;
  }
  else
  {
    if (len2 > 1 && fn2[len2 - 2] == ';') len2 -= 2;
    if (len2 > 0 && fn2[len2 - 1] == '.') len2 -= 1;
    if (len1 != len2) return 0;
    while (len1--) if (*fn1++ != *fn2++) return 0;
    return 1;
  }
}

static int cdfs_read_path_table(struct cdfs *cdfs, struct iso_volume_descriptor *vd)
{
  struct buf *buf;
  unsigned char *pt;
  int ptblk;
  int ptlen;
  int ptpos;
  int n;

  // Determine size and location of path table and allocate buffer
  ptlen = isonum_733(vd->path_table_size);
  ptblk = isonum_731(vd->type_l_path_table);
  cdfs->path_table_buffer = malloc(ptlen);
  if (!cdfs->path_table_buffer) return -ENOMEM;

  // Read L path table into buffer
  ptpos = 0;
  while (ptpos < ptlen)
  {
    buf = get_buffer(cdfs->cache, ptblk++);
    if (!buf) return -EIO;

    if (ptlen - ptpos > CDFS_BLOCKSIZE)
    {
      memcpy(cdfs->path_table_buffer + ptpos, buf->data, CDFS_BLOCKSIZE);
      ptpos += CDFS_BLOCKSIZE;
    }
    else
    {
      memcpy(cdfs->path_table_buffer + ptpos, buf->data, ptlen - ptpos);
      ptpos = ptlen;
    }

    release_buffer(cdfs->cache, buf);
  }

  // Determine number of records in pathtable
  // Path table records are indexed from 1 (first entry not used)
  pt = cdfs->path_table_buffer;
  n = 1;
  while (pt < cdfs->path_table_buffer + ptlen)
  {
    struct iso_pathtable_record *pathrec = (struct iso_pathtable_record *) pt;
    int namelen = pathrec->length;
    int reclen = sizeof(struct iso_pathtable_record) + namelen + (namelen & 1);

    n++;
    pt += reclen;
  }

  cdfs->path_table_records = n;

  // Allocate path table
  cdfs->path_table = (struct iso_pathtable_record **) kmalloc(cdfs->path_table_records * sizeof(struct iso_pathtable_record **));
  if (!cdfs->path_table) return -ENOMEM;
  cdfs->path_table[0] = NULL;

  // Setup pointers into path table buffer
  pt = cdfs->path_table_buffer;
  for (n = 1; n < cdfs->path_table_records; n++)
  {
    struct iso_pathtable_record *pathrec = (struct iso_pathtable_record *) pt;
    int namelen = pathrec->length;
    int reclen = sizeof(struct iso_pathtable_record) + namelen + (namelen & 1);

    cdfs->path_table[n] = pathrec;
    pt += reclen;
  }

  return 0;
}

static int cdfs_find_dir(struct cdfs *cdfs, char *name, int len)
{
  char *p;
  int l;
  int dir = 2;
  int parent = 1;

  while (1)
  {
    // Skip path separator
    if (*name == PS1 || *name == PS2)
    {
      name++;
      len--;
    }
    if (len == 0) return parent;

    // Find next part of name
    p = name;
    l = 0;
    while (l < len && *p != PS1 && *p != PS2)
    {
      l++;
      p++;
    }

    // Find directory for next name part
    while (dir < cdfs->path_table_records)
    {
      if (cdfs->path_table[dir]->parent != parent) return -ENOENT;
      if (cdfs_fnmatch(cdfs, name, l, cdfs->path_table[dir]->name, cdfs->path_table[dir]->length)) break;
      dir++;
    }

    // If we reached the end of the path table the directory does not exist
    if (dir == cdfs->path_table_records) return -ENOENT;
        
    // If we have parsed the whole name return the directory number
    if (l == len) return dir;

    // Go forward in path table until first entry for directory found
    parent = dir;
    while (dir < cdfs->path_table_records)
    {
      if (cdfs->path_table[dir]->parent == parent) break;
      dir++;
    }

    // Prepare for next name part
    name = p;
    len -= l;
  }
}

static int cdfs_find_in_dir(struct cdfs *cdfs, int dir, char *name, int len, struct buf **dirbuf, struct iso_directory_record **dirrec)
{
  struct buf *buf;
  char *p;
  struct iso_directory_record *rec;
  int blk;
  int left;
  int reclen;
  int namelen;

  // The first two directory records are . (current) and .. (parent)
  blk = cdfs->path_table[dir]->extent;
  buf = get_buffer(cdfs->cache, blk++);
  if (!buf) return -EIO;

  // Get length of directory from the first record
  p = buf->data;
  rec = (struct iso_directory_record *) p;
  left = isonum_733(rec->size);

  // Find named entry in directory
  while (left > 0)
  {
    // Read next block if all records in current block has been read
    // Directory records never cross block boundaries
    if (p >= buf->data + CDFS_BLOCKSIZE)
    {
      release_buffer(cdfs->cache, buf);
      if (p > buf->data + CDFS_BLOCKSIZE) return -EIO;
      buf = get_buffer(cdfs->cache, blk++);
      if (!buf) return -EIO;
      p = buf->data;
    }

    // Check for match
    rec = (struct iso_directory_record *) p;
    reclen = isonum_711(rec->length);
    namelen = isonum_711(rec->name_len);
    
    if (reclen > 0)
    {
      if (cdfs_fnmatch(cdfs, name, len, (char *) rec->name, namelen))
      {
        *dirrec = rec;
        *dirbuf = buf;
        return 0;
      }

      // Skip to next record
      p += reclen;
      left -= reclen;
    }
    else
    {
      // Skip to next block
      left -= (buf->data + CDFS_BLOCKSIZE) - p;
      p = buf->data + CDFS_BLOCKSIZE;
    }
  }

  release_buffer(cdfs->cache, buf);
  return -ENOENT;
}

static int cdfs_find_file(struct cdfs *cdfs, char *name, int len, struct buf **buf, struct iso_directory_record **rec)
{
  int dir;
  int split;
  int n;

  // If root get directory record from volume descriptor
  if (len == 0)
  {
    struct iso_volume_descriptor *vd;

    *buf = get_buffer(cdfs->cache, cdfs->vdblk);
    if (!*buf) return -EIO;
    vd = (struct iso_volume_descriptor *) (*buf)->data;
    *rec = (struct iso_directory_record *) vd->root_directory_record;
    return 0;
  }

  // Split path into directory part and file name part
  split = -1;
  for (n = 0; n < len; n++) if (name[n] == PS1 || name[n] == PS2) split = n;

  // Find directly if file located in root directory
  if (split == -1) return cdfs_find_in_dir(cdfs, 1, name, len, buf, rec);

  // Locate directory
  dir = cdfs_find_dir(cdfs, name, split + 1);
  if (dir < 0) return dir;

  // Find filename in directory
  return cdfs_find_in_dir(cdfs, dir, name + split + 1, len - split - 1, buf, rec);
}

static time_t cdfs_isodate(unsigned char *date)
{
  struct tm tm;

  memset(&tm, 0, sizeof tm);
  tm.tm_year = date[0];
  tm.tm_mon = date[1] - 1;
  tm.tm_mday = date[2];
  tm.tm_hour = date[3];
  tm.tm_min = date[4];
  tm.tm_sec = date[5];
  tm.tm_min += (*(char *) &date[6]) * 15;

  return mktime(&tm);
}

int cdfs_mount(struct fs *fs, char *opts)
{
  struct cdfs *cdfs;
  dev_t devno;
  int cachebufs;
  int rc;
  int blk;
  struct buf *buf;
  struct iso_volume_descriptor *vd;

  // Check device
  devno = dev_open(fs->mntfrom);
  if (devno == NODEV) return -NODEV;
  if (device(devno)->driver->type != DEV_TYPE_BLOCK) return -ENOTBLK;

  // Revalidate device and check block size
  if (get_option(opts, "revalidate", NULL, 0, NULL))
  {
    rc = dev_ioctl(devno, IOCTL_REVALIDATE, NULL, 0);
    if (rc < 0) return rc;
  }

  if (dev_ioctl(devno, IOCTL_GETBLKSIZE, NULL, 0) != CDFS_BLOCKSIZE) return -ENXIO;

  // Allocate file system
  cdfs = (struct cdfs *) kmalloc(sizeof(struct cdfs));
  memset(cdfs, 0, sizeof(struct cdfs));
  cdfs->devno = devno;
  cdfs->blks = dev_ioctl(devno, IOCTL_GETDEVSIZE, NULL, 0);
  if (cdfs->blks < 0) return cdfs->blks;

  // Allocate cache
  cachebufs = get_num_option(opts, "cache", CDFS_DEFAULT_CACHESIZE);
  cdfs->cache = init_buffer_pool(devno, cachebufs, CDFS_BLOCKSIZE, NULL, cdfs);
  if (!cdfs->cache) return -ENOMEM;

  // Read volume descriptors
  cdfs->vdblk = 0;
  blk = 16;
  while (1)
  {
    int type;
    unsigned char *esc;

    buf  = get_buffer(cdfs->cache, blk);
    if (!buf) return -EIO;
    vd = (struct iso_volume_descriptor *) buf->data;
    
    type = isonum_711(vd->type);
    esc = vd->escape_sequences;

    if (memcmp(vd->id, "CD001", 5) != 0)
    {
      free_buffer_pool(cdfs->cache);
      dev_close(cdfs->devno);
      kfree(cdfs);
      return -EIO;
    }

    if (cdfs->vdblk == 0 && type == ISO_VD_PRIMARY)
      cdfs->vdblk = blk;
    else if (type == ISO_VD_SUPPLEMENTAL && 
             esc[0] == 0x25 && esc[1] == 0x2F && 
	     (esc[2] == 0x40 || esc[2] == 0x43 || esc[2] == 0x45))
    {
      cdfs->vdblk = blk;
      cdfs->joliet = 1;
    }

    release_buffer(cdfs->cache, buf);
    if (type == ISO_VD_END) break;
    blk++;
  }
  if (cdfs->vdblk == 0) return -EIO;

  // Initialize filesystem from selected volume descriptor and read path table
  buf  = get_buffer(cdfs->cache, cdfs->vdblk);
  if (!buf) return -EIO;

⌨️ 快捷键说明

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