2N/A/* minix.c - The minix filesystem, version 1 and 2. */
2N/A/*
2N/A * GRUB -- GRand Unified Bootloader
2N/A * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc.
2N/A *
2N/A * GRUB is free software: you can redistribute it and/or modify
2N/A * it under the terms of the GNU General Public License as published by
2N/A * the Free Software Foundation, either version 3 of the License, or
2N/A * (at your option) any later version.
2N/A *
2N/A * GRUB is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU General Public License
2N/A * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A#include <grub/err.h>
2N/A#include <grub/file.h>
2N/A#include <grub/mm.h>
2N/A#include <grub/misc.h>
2N/A#include <grub/disk.h>
2N/A#include <grub/dl.h>
2N/A#include <grub/types.h>
2N/A
2N/AGRUB_MOD_LICENSE ("GPLv3+");
2N/A
2N/A#ifdef MODE_MINIX3
2N/A#define GRUB_MINIX_MAGIC 0x4D5A
2N/A#elif defined(MODE_MINIX2)
2N/A#define GRUB_MINIX_MAGIC 0x2468
2N/A#define GRUB_MINIX_MAGIC_30 0x2478
2N/A#else
2N/A#define GRUB_MINIX_MAGIC 0x137F
2N/A#define GRUB_MINIX_MAGIC_30 0x138F
2N/A#endif
2N/A
2N/A#define GRUB_MINIX_INODE_DIR_BLOCKS 7
2N/A#define GRUB_MINIX_LOG2_BSIZE 1
2N/A#define GRUB_MINIX_ROOT_INODE 1
2N/A#define GRUB_MINIX_MAX_SYMLNK_CNT 8
2N/A#define GRUB_MINIX_SBLOCK 2
2N/A
2N/A#define GRUB_MINIX_IFDIR 0040000U
2N/A#define GRUB_MINIX_IFLNK 0120000U
2N/A
2N/A#if defined(MODE_MINIX2) || defined(MODE_MINIX3)
2N/Atypedef grub_uint32_t grub_minix_uintn_t;
2N/A#define grub_minix_le_to_cpu_n grub_le_to_cpu32
2N/A#else
2N/Atypedef grub_uint16_t grub_minix_uintn_t;
2N/A#define grub_minix_le_to_cpu_n grub_le_to_cpu16
2N/A#endif
2N/A
2N/A#define GRUB_MINIX_INODE_BLKSZ(data) sizeof (grub_minix_uintn_t)
2N/A#ifdef MODE_MINIX3
2N/Atypedef grub_uint32_t grub_minix_ino_t;
2N/A#define grub_minix_le_to_cpu_ino grub_le_to_cpu32
2N/A#else
2N/Atypedef grub_uint16_t grub_minix_ino_t;
2N/A#define grub_minix_le_to_cpu_ino grub_le_to_cpu16
2N/A#endif
2N/A
2N/A#define GRUB_MINIX_INODE_SIZE(data) (grub_le_to_cpu32 (data->inode.size))
2N/A#define GRUB_MINIX_INODE_MODE(data) (grub_le_to_cpu16 (data->inode.mode))
2N/A#define GRUB_MINIX_INODE_DIR_ZONES(data,blk) (grub_minix_le_to_cpu_n \
2N/A (data->inode.dir_zones[blk]))
2N/A#define GRUB_MINIX_INODE_INDIR_ZONE(data) (grub_minix_le_to_cpu_n \
2N/A (data->inode.indir_zone))
2N/A#define GRUB_MINIX_INODE_DINDIR_ZONE(data) (grub_minix_le_to_cpu_n \
2N/A (data->inode.double_indir_zone))
2N/A
2N/A#ifndef MODE_MINIX3
2N/A#define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \
2N/A + grub_le_to_cpu16 (data->sblock.log2_zone_size))
2N/A#endif
2N/A#define GRUB_MINIX_ZONESZ (1 << (data->log_block_size \
2N/A + grub_le_to_cpu16 (data->sblock.log2_zone_size)))
2N/A
2N/A#ifdef MODE_MINIX3
2N/A#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << (data->log_block_size - GRUB_DISK_SECTOR_BITS))
2N/A#else
2N/A#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << GRUB_MINIX_LOG2_ZONESZ)
2N/A#endif
2N/A
2N/A
2N/A#ifdef MODE_MINIX3
2N/Astruct grub_minix_sblock
2N/A{
2N/A grub_uint32_t inode_cnt;
2N/A grub_uint16_t zone_cnt;
2N/A grub_uint16_t inode_bmap_size;
2N/A grub_uint16_t zone_bmap_size;
2N/A grub_uint16_t first_data_zone;
2N/A grub_uint16_t log2_zone_size;
2N/A grub_uint16_t pad;
2N/A grub_uint32_t max_file_size;
2N/A grub_uint32_t zones;
2N/A grub_uint16_t magic;
2N/A
2N/A grub_uint16_t pad2;
2N/A grub_uint16_t block_size;
2N/A grub_uint8_t disk_version;
2N/A};
2N/A#else
2N/Astruct grub_minix_sblock
2N/A{
2N/A grub_uint16_t inode_cnt;
2N/A grub_uint16_t zone_cnt;
2N/A grub_uint16_t inode_bmap_size;
2N/A grub_uint16_t zone_bmap_size;
2N/A grub_uint16_t first_data_zone;
2N/A grub_uint16_t log2_zone_size;
2N/A grub_uint32_t max_file_size;
2N/A grub_uint16_t magic;
2N/A};
2N/A#endif
2N/A
2N/A#if defined(MODE_MINIX3) || defined(MODE_MINIX2)
2N/Astruct grub_minix_inode
2N/A{
2N/A grub_uint16_t mode;
2N/A grub_uint16_t nlinks;
2N/A grub_uint16_t uid;
2N/A grub_uint16_t gid;
2N/A grub_uint32_t size;
2N/A grub_uint32_t atime;
2N/A grub_uint32_t mtime;
2N/A grub_uint32_t ctime;
2N/A grub_uint32_t dir_zones[7];
2N/A grub_uint32_t indir_zone;
2N/A grub_uint32_t double_indir_zone;
2N/A grub_uint32_t triple_indir_zone;
2N/A};
2N/A#else
2N/Astruct grub_minix_inode
2N/A{
2N/A grub_uint16_t mode;
2N/A grub_uint16_t uid;
2N/A grub_uint32_t size;
2N/A grub_uint32_t mtime;
2N/A grub_uint8_t gid;
2N/A grub_uint8_t nlinks;
2N/A grub_uint16_t dir_zones[7];
2N/A grub_uint16_t indir_zone;
2N/A grub_uint16_t double_indir_zone;
2N/A};
2N/A
2N/A#endif
2N/A
2N/A/* Information about a "mounted" minix filesystem. */
2N/Astruct grub_minix_data
2N/A{
2N/A struct grub_minix_sblock sblock;
2N/A struct grub_minix_inode inode;
2N/A int ino;
2N/A int linknest;
2N/A grub_disk_t disk;
2N/A int filename_size;
2N/A grub_size_t log_block_size;
2N/A};
2N/A
2N/Astatic grub_dl_t my_mod;
2N/A
2N/Astatic grub_err_t grub_minix_find_file (struct grub_minix_data *data,
2N/A const char *path);
2N/A
2N/Astatic grub_minix_uintn_t
2N/Agrub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
2N/A{
2N/A grub_minix_uintn_t indir;
2N/A const grub_uint32_t block_per_zone = (GRUB_MINIX_ZONESZ
2N/A / GRUB_MINIX_INODE_BLKSZ (data));
2N/A
2N/A auto grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t,
2N/A grub_minix_uintn_t);
2N/A
2N/A /* Read the block pointer in ZONE, on the offset NUM. */
2N/A grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t zone,
2N/A grub_minix_uintn_t num)
2N/A {
2N/A grub_minix_uintn_t indirn;
2N/A grub_disk_read (data->disk,
2N/A GRUB_MINIX_ZONE2SECT(zone),
2N/A sizeof (grub_minix_uintn_t) * num,
2N/A sizeof (grub_minix_uintn_t), (char *) &indirn);
2N/A return grub_minix_le_to_cpu_n (indirn);
2N/A }
2N/A
2N/A /* Direct block. */
2N/A if (blk < GRUB_MINIX_INODE_DIR_BLOCKS)
2N/A return GRUB_MINIX_INODE_DIR_ZONES (data, blk);
2N/A
2N/A /* Indirect block. */
2N/A blk -= GRUB_MINIX_INODE_DIR_BLOCKS;
2N/A if (blk < block_per_zone)
2N/A {
2N/A indir = grub_get_indir (GRUB_MINIX_INODE_INDIR_ZONE (data), blk);
2N/A return indir;
2N/A }
2N/A
2N/A /* Double indirect block. */
2N/A blk -= block_per_zone;
2N/A if (blk < block_per_zone * block_per_zone)
2N/A {
2N/A indir = grub_get_indir (GRUB_MINIX_INODE_DINDIR_ZONE (data),
2N/A blk / block_per_zone);
2N/A
2N/A indir = grub_get_indir (indir, blk % block_per_zone);
2N/A
2N/A return indir;
2N/A }
2N/A
2N/A#if defined (MODE_MINIX3) || defined (MODE_MINIX2)
2N/A blk -= block_per_zone * block_per_zone;
2N/A if (blk < ((grub_uint64_t) block_per_zone * (grub_uint64_t) block_per_zone
2N/A * (grub_uint64_t) block_per_zone))
2N/A {
2N/A indir = grub_get_indir (grub_minix_le_to_cpu_n (data->inode.triple_indir_zone),
2N/A (blk / block_per_zone) / block_per_zone);
2N/A indir = grub_get_indir (indir, (blk / block_per_zone) % block_per_zone);
2N/A indir = grub_get_indir (indir, blk % block_per_zone);
2N/A
2N/A return indir;
2N/A }
2N/A#endif
2N/A
2N/A /* This should never happen. */
2N/A grub_error (GRUB_ERR_OUT_OF_RANGE, "file bigger than maximum size");
2N/A
2N/A return 0;
2N/A}
2N/A
2N/A
2N/A/* Read LEN bytes from the file described by DATA starting with byte
2N/A POS. Return the amount of read bytes in READ. */
2N/Astatic grub_ssize_t
2N/Agrub_minix_read_file (struct grub_minix_data *data,
2N/A void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
2N/A unsigned offset, unsigned length),
2N/A grub_off_t pos, grub_disk_addr_t len, char *buf)
2N/A{
2N/A grub_disk_addr_t i;
2N/A grub_disk_addr_t blockcnt;
2N/A grub_uint64_t posblock;
2N/A grub_uint64_t blockoff;
2N/A
2N/A /* Adjust len so it we can't read past the end of the file. */
2N/A if (len + pos > GRUB_MINIX_INODE_SIZE (data))
2N/A len = GRUB_MINIX_INODE_SIZE (data) - pos;
2N/A
2N/A blockcnt = ((len + pos + (1 << data->log_block_size) - 1)
2N/A >> data->log_block_size);
2N/A posblock = pos >> data->log_block_size;
2N/A blockoff = pos & ((1 << data->log_block_size) - 1);
2N/A
2N/A for (i = posblock; i < blockcnt; i++)
2N/A {
2N/A grub_disk_addr_t blknr;
2N/A grub_uint64_t blockend = 1 << data->log_block_size;
2N/A grub_off_t skipfirst = 0;
2N/A
2N/A blknr = grub_minix_get_file_block (data, i);
2N/A if (grub_errno)
2N/A return -1;
2N/A
2N/A /* Last block. */
2N/A if (i == blockcnt - 1)
2N/A {
2N/A blockend = (len + pos) & ((1 << data->log_block_size) - 1);
2N/A
2N/A if (!blockend)
2N/A blockend = 1 << data->log_block_size;
2N/A }
2N/A
2N/A /* First block. */
2N/A if (i == posblock)
2N/A {
2N/A skipfirst = blockoff;
2N/A blockend -= skipfirst;
2N/A }
2N/A
2N/A data->disk->read_hook = read_hook;
2N/A grub_disk_read (data->disk,
2N/A GRUB_MINIX_ZONE2SECT(blknr),
2N/A skipfirst, blockend, buf);
2N/A data->disk->read_hook = 0;
2N/A if (grub_errno)
2N/A return -1;
2N/A
2N/A buf += (1 << data->log_block_size) - skipfirst;
2N/A }
2N/A
2N/A return len;
2N/A}
2N/A
2N/A
2N/A/* Read inode INO from the mounted filesystem described by DATA. This
2N/A inode is used by default now. */
2N/Astatic grub_err_t
2N/Agrub_minix_read_inode (struct grub_minix_data *data, int ino)
2N/A{
2N/A struct grub_minix_sblock *sblock = &data->sblock;
2N/A
2N/A /* Block in which the inode is stored. */
2N/A grub_disk_addr_t block;
2N/A data->ino = ino;
2N/A
2N/A /* The first inode in minix is inode 1. */
2N/A ino--;
2N/A block = GRUB_MINIX_ZONE2SECT (2 + grub_le_to_cpu16 (sblock->inode_bmap_size)
2N/A + grub_le_to_cpu16 (sblock->zone_bmap_size));
2N/A block += ino / (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode));
2N/A int offs = (ino % (GRUB_DISK_SECTOR_SIZE
2N/A / sizeof (struct grub_minix_inode))
2N/A * sizeof (struct grub_minix_inode));
2N/A
2N/A grub_disk_read (data->disk, block, offs,
2N/A sizeof (struct grub_minix_inode), &data->inode);
2N/A
2N/A return GRUB_ERR_NONE;
2N/A}
2N/A
2N/A
2N/A/* Lookup the symlink the current inode points to. INO is the inode
2N/A number of the directory the symlink is relative to. */
2N/Astatic grub_err_t
2N/Agrub_minix_lookup_symlink (struct grub_minix_data *data, int ino)
2N/A{
2N/A char symlink[GRUB_MINIX_INODE_SIZE (data) + 1];
2N/A
2N/A if (++data->linknest > GRUB_MINIX_MAX_SYMLNK_CNT)
2N/A return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
2N/A
2N/A if (grub_minix_read_file (data, 0, 0,
2N/A GRUB_MINIX_INODE_SIZE (data), symlink) < 0)
2N/A return grub_errno;
2N/A
2N/A symlink[GRUB_MINIX_INODE_SIZE (data)] = '\0';
2N/A
2N/A /* The symlink is an absolute path, go back to the root inode. */
2N/A if (symlink[0] == '/')
2N/A ino = GRUB_MINIX_ROOT_INODE;
2N/A
2N/A /* Now load in the old inode. */
2N/A if (grub_minix_read_inode (data, ino))
2N/A return grub_errno;
2N/A
2N/A grub_minix_find_file (data, symlink);
2N/A if (grub_errno)
2N/A grub_error (grub_errno, "cannot follow symlink `%s'", symlink);
2N/A
2N/A return grub_errno;
2N/A}
2N/A
2N/A
2N/A/* Find the file with the pathname PATH on the filesystem described by
2N/A DATA. */
2N/Astatic grub_err_t
2N/Agrub_minix_find_file (struct grub_minix_data *data, const char *path)
2N/A{
2N/A char fpath[grub_strlen (path) + 1];
2N/A char *name = fpath;
2N/A char *next;
2N/A unsigned int pos = 0;
2N/A int dirino;
2N/A
2N/A grub_strcpy (fpath, path);
2N/A
2N/A /* Skip the first slash. */
2N/A if (name[0] == '/')
2N/A {
2N/A name++;
2N/A if (!*name)
2N/A return 0;
2N/A }
2N/A
2N/A /* Extract the actual part from the pathname. */
2N/A next = grub_strchr (name, '/');
2N/A if (next)
2N/A {
2N/A next[0] = '\0';
2N/A next++;
2N/A }
2N/A
2N/A do
2N/A {
2N/A grub_minix_ino_t ino;
2N/A char filename[data->filename_size + 1];
2N/A
2N/A if (grub_strlen (name) == 0)
2N/A return GRUB_ERR_NONE;
2N/A
2N/A if (grub_minix_read_file (data, 0, pos, sizeof (ino),
2N/A (char *) &ino) < 0)
2N/A return grub_errno;
2N/A if (grub_minix_read_file (data, 0, pos + sizeof (ino),
2N/A data->filename_size, (char *) filename)< 0)
2N/A return grub_errno;
2N/A
2N/A filename[data->filename_size] = '\0';
2N/A
2N/A /* Check if the current direntry matches the current part of the
2N/A pathname. */
2N/A if (!grub_strcmp (name, filename))
2N/A {
2N/A dirino = data->ino;
2N/A grub_minix_read_inode (data, grub_minix_le_to_cpu_ino (ino));
2N/A
2N/A /* Follow the symlink. */
2N/A if ((GRUB_MINIX_INODE_MODE (data)
2N/A & GRUB_MINIX_IFLNK) == GRUB_MINIX_IFLNK)
2N/A {
2N/A grub_minix_lookup_symlink (data, dirino);
2N/A if (grub_errno)
2N/A return grub_errno;
2N/A }
2N/A
2N/A if (!next)
2N/A return 0;
2N/A
2N/A pos = 0;
2N/A
2N/A name = next;
2N/A next = grub_strchr (name, '/');
2N/A if (next)
2N/A {
2N/A next[0] = '\0';
2N/A next++;
2N/A }
2N/A
2N/A if ((GRUB_MINIX_INODE_MODE (data)
2N/A & GRUB_MINIX_IFDIR) != GRUB_MINIX_IFDIR)
2N/A return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
2N/A
2N/A continue;
2N/A }
2N/A
2N/A pos += sizeof (ino) + data->filename_size;
2N/A } while (pos < GRUB_MINIX_INODE_SIZE (data));
2N/A
2N/A grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
2N/A return grub_errno;
2N/A}
2N/A
2N/A
2N/A/* Mount the filesystem on the disk DISK. */
2N/Astatic struct grub_minix_data *
2N/Agrub_minix_mount (grub_disk_t disk)
2N/A{
2N/A struct grub_minix_data *data;
2N/A
2N/A data = grub_malloc (sizeof (struct grub_minix_data));
2N/A if (!data)
2N/A return 0;
2N/A
2N/A /* Read the superblock. */
2N/A grub_disk_read (disk, GRUB_MINIX_SBLOCK, 0,
2N/A sizeof (struct grub_minix_sblock),&data->sblock);
2N/A if (grub_errno)
2N/A goto fail;
2N/A
2N/A if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC)
2N/A {
2N/A#if !defined(MODE_MINIX3)
2N/A data->filename_size = 14;
2N/A#else
2N/A data->filename_size = 60;
2N/A#endif
2N/A }
2N/A#if !defined(MODE_MINIX3)
2N/A else if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC_30)
2N/A data->filename_size = 30;
2N/A#endif
2N/A else
2N/A goto fail;
2N/A
2N/A data->disk = disk;
2N/A data->linknest = 0;
2N/A#ifdef MODE_MINIX3
2N/A /* These tests are endian-independent. No need to byteswap. */
2N/A if (data->sblock.block_size == 0xffff)
2N/A data->log_block_size = 10;
2N/A else
2N/A {
2N/A if ((data->sblock.block_size & (data->sblock.block_size - 1))
2N/A || data->sblock.block_size == 0)
2N/A goto fail;
2N/A for (data->log_block_size = 0; (1 << data->log_block_size)
2N/A < grub_le_to_cpu16 (data->sblock.block_size);
2N/A data->log_block_size++);
2N/A }
2N/A#else
2N/A data->log_block_size = 10;
2N/A#endif
2N/A
2N/A return data;
2N/A
2N/A fail:
2N/A grub_free (data);
2N/A#if defined(MODE_MINIX3)
2N/A grub_error (GRUB_ERR_BAD_FS, "not a minix3 filesystem");
2N/A#elif defined(MODE_MINIX2)
2N/A grub_error (GRUB_ERR_BAD_FS, "not a minix2 filesystem");
2N/A#else
2N/A grub_error (GRUB_ERR_BAD_FS, "not a minix filesystem");
2N/A#endif
2N/A return 0;
2N/A}
2N/A
2N/Astatic grub_err_t
2N/Agrub_minix_dir (grub_device_t device, const char *path,
2N/A int (*hook) (const char *filename,
2N/A const struct grub_dirhook_info *info))
2N/A{
2N/A struct grub_minix_data *data = 0;
2N/A unsigned int pos = 0;
2N/A
2N/A data = grub_minix_mount (device->disk);
2N/A if (!data)
2N/A return grub_errno;
2N/A
2N/A grub_minix_read_inode (data, GRUB_MINIX_ROOT_INODE);
2N/A if (grub_errno)
2N/A goto fail;
2N/A
2N/A grub_minix_find_file (data, path);
2N/A if (grub_errno)
2N/A goto fail;
2N/A
2N/A if ((GRUB_MINIX_INODE_MODE (data) & GRUB_MINIX_IFDIR) != GRUB_MINIX_IFDIR)
2N/A {
2N/A grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
2N/A goto fail;
2N/A }
2N/A
2N/A while (pos < GRUB_MINIX_INODE_SIZE (data))
2N/A {
2N/A grub_minix_ino_t ino;
2N/A char filename[data->filename_size + 1];
2N/A int dirino = data->ino;
2N/A struct grub_dirhook_info info;
2N/A grub_memset (&info, 0, sizeof (info));
2N/A
2N/A
2N/A if (grub_minix_read_file (data, 0, pos, sizeof (ino),
2N/A (char *) &ino) < 0)
2N/A return grub_errno;
2N/A
2N/A if (grub_minix_read_file (data, 0, pos + sizeof (ino),
2N/A data->filename_size,
2N/A (char *) filename) < 0)
2N/A return grub_errno;
2N/A filename[data->filename_size] = '\0';
2N/A if (!ino)
2N/A {
2N/A pos += sizeof (ino) + data->filename_size;
2N/A continue;
2N/A }
2N/A
2N/A grub_minix_read_inode (data, grub_minix_le_to_cpu_ino (ino));
2N/A info.dir = ((GRUB_MINIX_INODE_MODE (data)
2N/A & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
2N/A info.mtimeset = 1;
2N/A info.mtime = grub_le_to_cpu32 (data->inode.mtime);
2N/A
2N/A if (hook (filename, &info) ? 1 : 0)
2N/A break;
2N/A
2N/A /* Load the old inode back in. */
2N/A grub_minix_read_inode (data, dirino);
2N/A
2N/A pos += sizeof (ino) + data->filename_size;
2N/A }
2N/A
2N/A fail:
2N/A grub_free (data);
2N/A return grub_errno;
2N/A}
2N/A
2N/A
2N/A/* Open a file named NAME and initialize FILE. */
2N/Astatic grub_err_t
2N/Agrub_minix_open (struct grub_file *file, const char *name)
2N/A{
2N/A struct grub_minix_data *data;
2N/A data = grub_minix_mount (file->device->disk);
2N/A if (!data)
2N/A return grub_errno;
2N/A
2N/A /* Open the inode op the root directory. */
2N/A grub_minix_read_inode (data, GRUB_MINIX_ROOT_INODE);
2N/A if (grub_errno)
2N/A {
2N/A grub_free (data);
2N/A return grub_errno;
2N/A }
2N/A
2N/A if (!name || name[0] != '/')
2N/A {
2N/A grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
2N/A return grub_errno;
2N/A }
2N/A
2N/A /* Traverse the directory tree to the node that should be
2N/A opened. */
2N/A grub_minix_find_file (data, name);
2N/A if (grub_errno)
2N/A {
2N/A grub_free (data);
2N/A return grub_errno;
2N/A }
2N/A
2N/A file->data = data;
2N/A file->size = GRUB_MINIX_INODE_SIZE (data);
2N/A
2N/A return GRUB_ERR_NONE;
2N/A}
2N/A
2N/A
2N/Astatic grub_ssize_t
2N/Agrub_minix_read (grub_file_t file, char *buf, grub_size_t len)
2N/A{
2N/A struct grub_minix_data *data =
2N/A (struct grub_minix_data *) file->data;
2N/A
2N/A return grub_minix_read_file (data, file->read_hook, file->offset, len, buf);
2N/A}
2N/A
2N/A
2N/Astatic grub_err_t
2N/Agrub_minix_close (grub_file_t file)
2N/A{
2N/A grub_free (file->data);
2N/A
2N/A return GRUB_ERR_NONE;
2N/A}
2N/A
2N/A
2N/A
2N/Astatic struct grub_fs grub_minix_fs =
2N/A {
2N/A#if defined(MODE_MINIX3)
2N/A .name = "minix3",
2N/A#elif defined(MODE_MINIX2)
2N/A .name = "minix2",
2N/A#else
2N/A .name = "minix",
2N/A#endif
2N/A .dir = grub_minix_dir,
2N/A .open = grub_minix_open,
2N/A .read = grub_minix_read,
2N/A .close = grub_minix_close,
2N/A .next = 0
2N/A };
2N/A
2N/A#if defined(MODE_MINIX3)
2N/AGRUB_MOD_INIT(minix3)
2N/A#elif defined(MODE_MINIX2)
2N/AGRUB_MOD_INIT(minix2)
2N/A#else
2N/AGRUB_MOD_INIT(minix)
2N/A#endif
2N/A{
2N/A grub_fs_register (&grub_minix_fs);
2N/A my_mod = mod;
2N/A}
2N/A
2N/A#if defined(MODE_MINIX3)
2N/AGRUB_MOD_FINI(minix3)
2N/A#elif defined(MODE_MINIX2)
2N/AGRUB_MOD_FINI(minix2)
2N/A#else
2N/AGRUB_MOD_FINI(minix)
2N/A#endif
2N/A{
2N/A grub_fs_unregister (&grub_minix_fs);
2N/A}