| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 2001 Free Software Foundation, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| #ifdef FSYS_VSTAFS |
| |
| #include "shared.h" |
| #include "filesys.h" |
| #include "vstafs.h" |
| |
| |
| static void get_file_info (int sector); |
| static struct dir_entry *vstafs_readdir (long sector); |
| static struct dir_entry *vstafs_nextdir (void); |
| |
| |
| #define FIRST_SECTOR ((struct first_sector *) FSYS_BUF) |
| #define FILE_INFO ((struct fs_file *) (int) FIRST_SECTOR + 8192) |
| #define DIRECTORY_BUF ((struct dir_entry *) (int) FILE_INFO + 512) |
| |
| #define ROOT_SECTOR 1 |
| |
| /* |
| * In f_sector we store the sector number in which the information about |
| * the found file is. |
| */ |
| extern int filepos; |
| static int f_sector; |
| |
| int |
| vstafs_mount (void) |
| { |
| int retval = 1; |
| |
| if( (((current_drive & 0x80) || (current_slice != 0)) |
| && current_slice != PC_SLICE_TYPE_VSTAFS) |
| || ! devread (0, 0, BLOCK_SIZE, (char *) FSYS_BUF) |
| || FIRST_SECTOR->fs_magic != 0xDEADFACE) |
| retval = 0; |
| |
| return retval; |
| } |
| |
| static void |
| get_file_info (int sector) |
| { |
| devread (sector, 0, BLOCK_SIZE, (char *) FILE_INFO); |
| } |
| |
| static int curr_ext, current_direntry, current_blockpos; |
| static struct alloc *a; |
| |
| static struct dir_entry * |
| vstafs_readdir (long sector) |
| { |
| /* |
| * Get some information from the current directory |
| */ |
| get_file_info (sector); |
| if (FILE_INFO->type != 2) |
| { |
| errnum = ERR_FILE_NOT_FOUND; |
| return 0; |
| } |
| |
| a = FILE_INFO->blocks; |
| curr_ext = 0; |
| devread (a[curr_ext].a_start, 0, 512, (char *) DIRECTORY_BUF); |
| current_direntry = 11; |
| current_blockpos = 0; |
| |
| return &DIRECTORY_BUF[10]; |
| } |
| |
| static struct dir_entry * |
| vstafs_nextdir (void) |
| { |
| if (current_direntry > 15) |
| { |
| current_direntry = 0; |
| if (++current_blockpos > (a[curr_ext].a_len - 1)) |
| { |
| current_blockpos = 0; |
| curr_ext++; |
| } |
| |
| if (curr_ext < FILE_INFO->extents) |
| { |
| devread (a[curr_ext].a_start + current_blockpos, 0, |
| 512, (char *) DIRECTORY_BUF); |
| } |
| else |
| { |
| /* errnum =ERR_FILE_NOT_FOUND; */ |
| return 0; |
| } |
| } |
| |
| return &DIRECTORY_BUF[current_direntry++]; |
| } |
| |
| int |
| vstafs_dir (char *dirname) |
| { |
| char *fn, ch; |
| struct dir_entry *d; |
| /* int l, i, s; */ |
| |
| /* |
| * Read in the entries of the current directory. |
| */ |
| f_sector = ROOT_SECTOR; |
| do |
| { |
| if (! (d = vstafs_readdir (f_sector))) |
| { |
| return 0; |
| } |
| |
| /* |
| * Find the file in the path |
| */ |
| while (*dirname == '/') dirname++; |
| fn = dirname; |
| while ((ch = *fn) && ch != '/' && ! isspace (ch)) fn++; |
| *fn = 0; |
| |
| do |
| { |
| if (d->name[0] == 0 || d->name[0] & 0x80) |
| continue; |
| |
| #ifndef STAGE1_5 |
| if (print_possibilities && ch != '/' |
| && (! *dirname || strcmp (dirname, d->name) <= 0)) |
| { |
| if (print_possibilities > 0) |
| print_possibilities = -print_possibilities; |
| |
| printf (" %s", d->name); |
| } |
| #endif |
| if (! grub_strcmp (dirname, d->name)) |
| { |
| f_sector = d->start; |
| get_file_info (f_sector); |
| filemax = FILE_INFO->len; |
| break; |
| } |
| } |
| while ((d =vstafs_nextdir ())); |
| |
| *(dirname = fn) = ch; |
| if (! d) |
| { |
| if (print_possibilities < 0) |
| { |
| putchar ('\n'); |
| return 1; |
| } |
| |
| errnum = ERR_FILE_NOT_FOUND; |
| return 0; |
| } |
| } |
| while (*dirname && ! isspace (ch)); |
| |
| return 1; |
| } |
| |
| int |
| vstafs_read (char *addr, int len) |
| { |
| struct alloc *a; |
| int size, ret = 0, offset, curr_len = 0; |
| int curr_ext; |
| char extent; |
| int ext_size; |
| char *curr_pos; |
| |
| get_file_info (f_sector); |
| size = FILE_INFO->len-VSTAFS_START_DATA; |
| a = FILE_INFO->blocks; |
| |
| if (filepos > 0) |
| { |
| if (filepos < a[0].a_len * 512 - VSTAFS_START_DATA) |
| { |
| offset = filepos + VSTAFS_START_DATA; |
| extent = 0; |
| curr_len = a[0].a_len * 512 - offset - filepos; |
| } |
| else |
| { |
| ext_size = a[0].a_len * 512 - VSTAFS_START_DATA; |
| offset = filepos - ext_size; |
| extent = 1; |
| do |
| { |
| curr_len -= ext_size; |
| offset -= ext_size; |
| ext_size = a[extent+1].a_len * 512; |
| } |
| while (extent < FILE_INFO->extents && offset>ext_size); |
| } |
| } |
| else |
| { |
| offset = VSTAFS_START_DATA; |
| extent = 0; |
| curr_len = a[0].a_len * 512 - offset; |
| } |
| |
| curr_pos = addr; |
| if (curr_len > len) |
| curr_len = len; |
| |
| for (curr_ext=extent; |
| curr_ext < FILE_INFO->extents; |
| curr_len = a[curr_ext].a_len * 512, curr_pos += curr_len, curr_ext++) |
| { |
| ret += curr_len; |
| size -= curr_len; |
| if (size < 0) |
| { |
| ret += size; |
| curr_len += size; |
| } |
| |
| devread (a[curr_ext].a_start,offset, curr_len, curr_pos); |
| offset = 0; |
| } |
| |
| return ret; |
| } |
| |
| #endif /* FSYS_VSTAFS */ |