ia64/xen-unstable

changeset 14056:47db75f8cc76

Port fsys_fat.c from grub legacy. This enables pygrub to load from EFI
FAT partitions on ia64.

Signed-off-by: Aron Griffis <aron@hp.com>
author Aron Griffis <aron@hp.com>
date Tue Feb 13 12:30:23 2007 -0500 (2007-02-13)
parents fe3e024e38f8
children 3c581edac93a
files tools/libfsimage/Makefile tools/libfsimage/fat/Makefile tools/libfsimage/fat/fat.h tools/libfsimage/fat/fsys_fat.c
line diff
     1.1 --- a/tools/libfsimage/Makefile	Tue Feb 20 14:54:04 2007 -0800
     1.2 +++ b/tools/libfsimage/Makefile	Tue Feb 13 12:30:23 2007 -0500
     1.3 @@ -1,7 +1,7 @@
     1.4  XEN_ROOT = ../..
     1.5  include $(XEN_ROOT)/tools/Rules.mk
     1.6  
     1.7 -SUBDIRS-y = common ufs reiserfs iso9660
     1.8 +SUBDIRS-y = common ufs reiserfs iso9660 fat
     1.9  SUBDIRS-y += $(shell ./check-libext2fs)
    1.10  
    1.11  .PHONY: all
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/libfsimage/fat/Makefile	Tue Feb 13 12:30:23 2007 -0500
     2.3 @@ -0,0 +1,13 @@
     2.4 +XEN_ROOT = ../../..
     2.5 +
     2.6 +LIB_SRCS-y = fsys_fat.c
     2.7 +
     2.8 +FS = fat
     2.9 +
    2.10 +.PHONY: all
    2.11 +all: fs-all
    2.12 +
    2.13 +.PHONY: install
    2.14 +install: fs-install
    2.15 +
    2.16 +include $(XEN_ROOT)/tools/libfsimage/Rules.mk
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/libfsimage/fat/fat.h	Tue Feb 13 12:30:23 2007 -0500
     3.3 @@ -0,0 +1,100 @@
     3.4 +/*
     3.5 + *  GRUB  --  GRand Unified Bootloader
     3.6 + *  Copyright (C) 2001  Free Software Foundation, Inc.
     3.7 + *
     3.8 + *  This program is free software; you can redistribute it and/or modify
     3.9 + *  it under the terms of the GNU General Public License as published by
    3.10 + *  the Free Software Foundation; either version 2 of the License, or
    3.11 + *  (at your option) any later version.
    3.12 + *
    3.13 + *  This program is distributed in the hope that it will be useful,
    3.14 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.15 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.16 + *  GNU General Public License for more details.
    3.17 + *
    3.18 + *  You should have received a copy of the GNU General Public License
    3.19 + *  along with this program; if not, write to the Free Software
    3.20 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    3.21 + */
    3.22 +
    3.23 +
    3.24 +/*
    3.25 + *  Defines for the FAT BIOS Parameter Block (embedded in the first block
    3.26 + *  of the partition.
    3.27 + */
    3.28 +
    3.29 +typedef __signed__ char __s8;
    3.30 +typedef unsigned char __u8;
    3.31 +typedef __signed__ short __s16;
    3.32 +typedef unsigned short __u16;
    3.33 +typedef __signed__ int __s32;
    3.34 +typedef unsigned int __u32;
    3.35 +
    3.36 +/* Note that some shorts are not aligned, and must therefore
    3.37 + * be declared as array of two bytes.
    3.38 + */
    3.39 +struct fat_bpb {
    3.40 +	__s8	ignored[3];	/* Boot strap short or near jump */
    3.41 +	__s8	system_id[8];	/* Name - can be used to special case
    3.42 +				   partition manager volumes */
    3.43 +	__u8	bytes_per_sect[2];	/* bytes per logical sector */
    3.44 +	__u8	sects_per_clust;/* sectors/cluster */
    3.45 +	__u8	reserved_sects[2];	/* reserved sectors */
    3.46 +	__u8	num_fats;	/* number of FATs */
    3.47 +	__u8	dir_entries[2];	/* root directory entries */
    3.48 +	__u8	short_sectors[2];	/* number of sectors */
    3.49 +	__u8	media;		/* media code (unused) */
    3.50 +	__u16	fat_length;	/* sectors/FAT */
    3.51 +	__u16	secs_track;	/* sectors per track */
    3.52 +	__u16	heads;		/* number of heads */
    3.53 +	__u32	hidden;		/* hidden sectors (unused) */
    3.54 +	__u32	long_sectors;	/* number of sectors (if short_sectors == 0) */
    3.55 +
    3.56 +	/* The following fields are only used by FAT32 */
    3.57 +	__u32	fat32_length;	/* sectors/FAT */
    3.58 +	__u16	flags;		/* bit 8: fat mirroring, low 4: active fat */
    3.59 +	__u8	version[2];	/* major, minor filesystem version */
    3.60 +	__u32	root_cluster;	/* first cluster in root directory */
    3.61 +	__u16	info_sector;	/* filesystem info sector */
    3.62 +	__u16	backup_boot;	/* backup boot sector */
    3.63 +	__u16	reserved2[6];	/* Unused */
    3.64 +};
    3.65 +
    3.66 +#define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr))
    3.67 +
    3.68 +/*
    3.69 + *  Defines how to differentiate a 12-bit and 16-bit FAT.
    3.70 + */
    3.71 +
    3.72 +#define FAT_MAX_12BIT_CLUST       4087	/* 4085 + 2 */
    3.73 +
    3.74 +/*
    3.75 + *  Defines for the file "attribute" byte
    3.76 + */
    3.77 +
    3.78 +#define FAT_ATTRIB_OK_MASK        0x37
    3.79 +#define FAT_ATTRIB_NOT_OK_MASK    0xC8
    3.80 +#define FAT_ATTRIB_DIR            0x10
    3.81 +#define FAT_ATTRIB_LONGNAME       0x0F
    3.82 +
    3.83 +/*
    3.84 + *  Defines for FAT directory entries
    3.85 + */
    3.86 +
    3.87 +#define FAT_DIRENTRY_LENGTH       32
    3.88 +
    3.89 +#define FAT_DIRENTRY_ATTRIB(entry) \
    3.90 +  (*((unsigned char *) (entry+11)))
    3.91 +#define FAT_DIRENTRY_VALID(entry) \
    3.92 +  ( ((*((unsigned char *) entry)) != 0) \
    3.93 +    && ((*((unsigned char *) entry)) != 0xE5) \
    3.94 +    && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
    3.95 +#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
    3.96 +  ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
    3.97 +#define FAT_DIRENTRY_FILELENGTH(entry) \
    3.98 +  (*((unsigned long *) (entry+28)))
    3.99 +
   3.100 +#define FAT_LONGDIR_ID(entry) \
   3.101 +  (*((unsigned char *) (entry)))
   3.102 +#define FAT_LONGDIR_ALIASCHECKSUM(entry) \
   3.103 +  (*((unsigned char *) (entry+13)))
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/libfsimage/fat/fsys_fat.c	Tue Feb 13 12:30:23 2007 -0500
     4.3 @@ -0,0 +1,485 @@
     4.4 +/*
     4.5 + *  GRUB  --  GRand Unified Bootloader
     4.6 + *  Copyright (C) 2000,2001,2005   Free Software Foundation, Inc.
     4.7 + *
     4.8 + *  This program is free software; you can redistribute it and/or modify
     4.9 + *  it under the terms of the GNU General Public License as published by
    4.10 + *  the Free Software Foundation; either version 2 of the License, or
    4.11 + *  (at your option) any later version.
    4.12 + *
    4.13 + *  This program is distributed in the hope that it will be useful,
    4.14 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.15 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.16 + *  GNU General Public License for more details.
    4.17 + *
    4.18 + *  You should have received a copy of the GNU General Public License
    4.19 + *  along with this program; if not, write to the Free Software
    4.20 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    4.21 + */
    4.22 +
    4.23 +#include <limits.h>
    4.24 +#include <fsimage_grub.h>
    4.25 +#include "fat.h"
    4.26 +
    4.27 +struct fat_superblock 
    4.28 +{
    4.29 +  int fat_offset;
    4.30 +  int fat_length;
    4.31 +  int fat_size;
    4.32 +  int root_offset;
    4.33 +  int root_max;
    4.34 +  int data_offset;
    4.35 +  
    4.36 +  int num_sectors;
    4.37 +  int num_clust;
    4.38 +  int clust_eof_marker;
    4.39 +  int sects_per_clust;
    4.40 +  int sectsize_bits;
    4.41 +  int clustsize_bits;
    4.42 +  int root_cluster;
    4.43 +  
    4.44 +  int cached_fat;
    4.45 +  int file_cluster;
    4.46 +  int current_cluster_num;
    4.47 +  int current_cluster;
    4.48 +};
    4.49 +
    4.50 +/* pointer(s) into filesystem info buffer for DOS stuff */
    4.51 +#define FAT_SUPER ( (struct fat_superblock *) \
    4.52 + 		    ( FSYS_BUF + 32256) )/* 512 bytes long */
    4.53 +#define FAT_BUF   ( FSYS_BUF + 30208 )	/* 4 sector FAT buffer */
    4.54 +#define NAME_BUF  ( FSYS_BUF + 29184 )	/* Filename buffer (833 bytes) */
    4.55 +
    4.56 +#define FAT_CACHE_SIZE 2048
    4.57 +
    4.58 +#define log2 grub_log2
    4.59 +
    4.60 +int
    4.61 +fat_mount (fsi_file_t *ffi, const char *options)
    4.62 +{
    4.63 +  struct fat_bpb bpb;
    4.64 +  __u32 magic, first_fat;
    4.65 +  
    4.66 +  /* Read bpb */
    4.67 +  if (! devread (ffi, 0, 0, sizeof (bpb), (char *) &bpb))
    4.68 +    return 0;
    4.69 +
    4.70 +  /* Check if the number of sectors per cluster is zero here, to avoid
    4.71 +     zero division.  */
    4.72 +  if (bpb.sects_per_clust == 0)
    4.73 +    return 0;
    4.74 +  
    4.75 +  FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect));
    4.76 +  FAT_SUPER->clustsize_bits
    4.77 +    = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust);
    4.78 +  
    4.79 +  /* Fill in info about super block */
    4.80 +  FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors) 
    4.81 +    ? FAT_CVT_U16 (bpb.short_sectors) : bpb.long_sectors;
    4.82 +  
    4.83 +  /* FAT offset and length */
    4.84 +  FAT_SUPER->fat_offset = FAT_CVT_U16 (bpb.reserved_sects);
    4.85 +  FAT_SUPER->fat_length = 
    4.86 +    bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
    4.87 +  
    4.88 +  /* Rootdir offset and length for FAT12/16 */
    4.89 +  FAT_SUPER->root_offset = 
    4.90 +    FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
    4.91 +  FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries);
    4.92 +  
    4.93 +  /* Data offset and number of clusters */
    4.94 +  FAT_SUPER->data_offset = 
    4.95 +    FAT_SUPER->root_offset
    4.96 +    + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
    4.97 +  FAT_SUPER->num_clust = 
    4.98 +    2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset) 
    4.99 +	 / bpb.sects_per_clust);
   4.100 +  FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
   4.101 +  
   4.102 +  if (!bpb.fat_length)
   4.103 +    {
   4.104 +      /* This is a FAT32 */
   4.105 +      if (FAT_CVT_U16(bpb.dir_entries))
   4.106 + 	return 0;
   4.107 +      
   4.108 +      if (bpb.flags & 0x0080)
   4.109 +	{
   4.110 +	  /* FAT mirroring is disabled, get active FAT */
   4.111 +	  int active_fat = bpb.flags & 0x000f;
   4.112 +	  if (active_fat >= bpb.num_fats)
   4.113 +	    return 0;
   4.114 +	  FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length;
   4.115 +	}
   4.116 +      
   4.117 +      FAT_SUPER->fat_size = 8;
   4.118 +      FAT_SUPER->root_cluster = bpb.root_cluster;
   4.119 +
   4.120 +      /* Yes the following is correct.  FAT32 should be called FAT28 :) */
   4.121 +      FAT_SUPER->clust_eof_marker = 0xffffff8;
   4.122 +    } 
   4.123 +  else 
   4.124 +    {
   4.125 +      if (!FAT_SUPER->root_max)
   4.126 + 	return 0;
   4.127 +      
   4.128 +      FAT_SUPER->root_cluster = -1;
   4.129 +      if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST) 
   4.130 +	{
   4.131 +	  FAT_SUPER->fat_size = 4;
   4.132 +	  FAT_SUPER->clust_eof_marker = 0xfff8;
   4.133 +	} 
   4.134 +      else
   4.135 +	{
   4.136 +	  FAT_SUPER->fat_size = 3;
   4.137 +	  FAT_SUPER->clust_eof_marker = 0xff8;
   4.138 +	}
   4.139 +    }
   4.140 +
   4.141 +  /* Now do some sanity checks */
   4.142 +  
   4.143 +  if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits)
   4.144 +      || FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE
   4.145 +      || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
   4.146 + 				       - FAT_SUPER->sectsize_bits))
   4.147 +      || FAT_SUPER->num_clust <= 2
   4.148 +      || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
   4.149 + 	  > FAT_SUPER->fat_length))
   4.150 +    return 0;
   4.151 +  
   4.152 +  /* kbs: Media check on first FAT entry [ported from PUPA] */
   4.153 +
   4.154 +  if (!devread(ffi, FAT_SUPER->fat_offset, 0,
   4.155 +               sizeof(first_fat), (char *)&first_fat))
   4.156 +    return 0;
   4.157 +
   4.158 +  if (FAT_SUPER->fat_size == 8)
   4.159 +    {
   4.160 +      first_fat &= 0x0fffffff;
   4.161 +      magic = 0x0fffff00;
   4.162 +    }
   4.163 +  else if (FAT_SUPER->fat_size == 4)
   4.164 +    {
   4.165 +      first_fat &= 0x0000ffff;
   4.166 +      magic = 0xff00;
   4.167 +    }
   4.168 +  else
   4.169 +    {
   4.170 +      first_fat &= 0x00000fff;
   4.171 +      magic = 0x0f00;
   4.172 +    }
   4.173 +
   4.174 +  /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
   4.175 +     descriptor, even if it is a so-called superfloppy (e.g. an USB key).
   4.176 +     The check may be too strict for this kind of stupid BIOSes, as
   4.177 +     they overwrite the media descriptor.  */
   4.178 +  if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
   4.179 +    return 0;
   4.180 +
   4.181 +  FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
   4.182 +  return 1;
   4.183 +}
   4.184 +
   4.185 +int
   4.186 +fat_read (fsi_file_t *ffi, char *buf, int len)
   4.187 +{
   4.188 +  int logical_clust;
   4.189 +  int offset;
   4.190 +  int ret = 0;
   4.191 +  int size;
   4.192 +  
   4.193 +  if (FAT_SUPER->file_cluster < 0)
   4.194 +    {
   4.195 +      /* root directory for fat16 */
   4.196 +      size = FAT_SUPER->root_max - filepos;
   4.197 +      if (size > len)
   4.198 + 	size = len;
   4.199 +      if (!devread(ffi, FAT_SUPER->root_offset, filepos, size, buf))
   4.200 + 	return 0;
   4.201 +      filepos += size;
   4.202 +      return size;
   4.203 +    }
   4.204 +  
   4.205 +  logical_clust = filepos >> FAT_SUPER->clustsize_bits;
   4.206 +  offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
   4.207 +  if (logical_clust < FAT_SUPER->current_cluster_num)
   4.208 +    {
   4.209 +      FAT_SUPER->current_cluster_num = 0;
   4.210 +      FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
   4.211 +    }
   4.212 +  
   4.213 +  while (len > 0)
   4.214 +    {
   4.215 +      int sector;
   4.216 +      while (logical_clust > FAT_SUPER->current_cluster_num)
   4.217 +	{
   4.218 +	  /* calculate next cluster */
   4.219 +	  int fat_entry = 
   4.220 +	    FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
   4.221 +	  int next_cluster;
   4.222 +	  int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
   4.223 +	  
   4.224 +	  if (cached_pos < 0 || 
   4.225 +	      (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
   4.226 +	    {
   4.227 +	      FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
   4.228 +	      cached_pos = (fat_entry - FAT_SUPER->cached_fat);
   4.229 +	      sector = FAT_SUPER->fat_offset
   4.230 +		+ FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
   4.231 +	      if (!devread (ffi, sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
   4.232 +		return 0;
   4.233 +	    }
   4.234 +	  next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
   4.235 +	  if (FAT_SUPER->fat_size == 3)
   4.236 +	    {
   4.237 +	      if (cached_pos & 1)
   4.238 +		next_cluster >>= 4;
   4.239 +	      next_cluster &= 0xFFF;
   4.240 +	    }
   4.241 +	  else if (FAT_SUPER->fat_size == 4)
   4.242 +	    next_cluster &= 0xFFFF;
   4.243 +	  
   4.244 +	  if (next_cluster >= FAT_SUPER->clust_eof_marker)
   4.245 +	    return ret;
   4.246 +	  if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust)
   4.247 +	    {
   4.248 +	      errnum = ERR_FSYS_CORRUPT;
   4.249 +	      return 0;
   4.250 +	    }
   4.251 +	  
   4.252 +	  FAT_SUPER->current_cluster = next_cluster;
   4.253 +	  FAT_SUPER->current_cluster_num++;
   4.254 +	}
   4.255 +      
   4.256 +      sector = FAT_SUPER->data_offset +
   4.257 +	((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
   4.258 + 					      - FAT_SUPER->sectsize_bits));
   4.259 +      size = (1 << FAT_SUPER->clustsize_bits) - offset;
   4.260 +      if (size > len)
   4.261 +	size = len;
   4.262 +      
   4.263 +      disk_read_func = disk_read_hook;
   4.264 +      
   4.265 +      devread(ffi, sector, offset, size, buf);
   4.266 +      
   4.267 +      disk_read_func = NULL;
   4.268 +      
   4.269 +      len -= size;
   4.270 +      buf += size;
   4.271 +      ret += size;
   4.272 +      filepos += size;
   4.273 +      logical_clust++;
   4.274 +      offset = 0;
   4.275 +    }
   4.276 +  return errnum ? 0 : ret;
   4.277 +}
   4.278 +
   4.279 +int
   4.280 +fat_dir (fsi_file_t *ffi, char *dirname)
   4.281 +{
   4.282 +  char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
   4.283 +  char *filename = (char *) NAME_BUF;
   4.284 +  int attrib = FAT_ATTRIB_DIR;
   4.285 +#ifndef STAGE1_5
   4.286 +  int do_possibilities = 0;
   4.287 +#endif
   4.288 +  
   4.289 +  /* XXX I18N:
   4.290 +   * the positions 2,4,6 etc are high bytes of a 16 bit unicode char 
   4.291 +   */
   4.292 +  static unsigned char longdir_pos[] = 
   4.293 +  { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
   4.294 +  int slot = -2;
   4.295 +  int alias_checksum = -1;
   4.296 +  
   4.297 +  FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
   4.298 +  filepos = 0;
   4.299 +  FAT_SUPER->current_cluster_num = INT_MAX;
   4.300 +  
   4.301 +  /* main loop to find desired directory entry */
   4.302 + loop:
   4.303 +  
   4.304 +  /* if we have a real file (and we're not just printing possibilities),
   4.305 +     then this is where we want to exit */
   4.306 +  
   4.307 +  if (!*dirname || isspace (*dirname))
   4.308 +    {
   4.309 +      if (attrib & FAT_ATTRIB_DIR)
   4.310 +	{
   4.311 +	  errnum = ERR_BAD_FILETYPE;
   4.312 +	  return 0;
   4.313 +	}
   4.314 +      
   4.315 +      return 1;
   4.316 +    }
   4.317 +  
   4.318 +  /* continue with the file/directory name interpretation */
   4.319 +  
   4.320 +  while (*dirname == '/')
   4.321 +    dirname++;
   4.322 +  
   4.323 +  if (!(attrib & FAT_ATTRIB_DIR))
   4.324 +    {
   4.325 +      errnum = ERR_BAD_FILETYPE;
   4.326 +      return 0;
   4.327 +    }
   4.328 +  /* Directories don't have a file size */
   4.329 +  filemax = INT_MAX;
   4.330 +  
   4.331 +  for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
   4.332 +  
   4.333 +  *rest = 0;
   4.334 +  
   4.335 +# ifndef STAGE1_5
   4.336 +  if (print_possibilities && ch != '/')
   4.337 +    do_possibilities = 1;
   4.338 +# endif
   4.339 +  
   4.340 +  while (1)
   4.341 +    {
   4.342 +      if (fat_read (ffi, dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
   4.343 +	  || dir_buf[0] == 0)
   4.344 +	{
   4.345 +	  if (!errnum)
   4.346 +	    {
   4.347 +# ifndef STAGE1_5
   4.348 +	      if (print_possibilities < 0)
   4.349 +		{
   4.350 +#if 0
   4.351 +		  putchar ('\n');
   4.352 +#endif
   4.353 +		  return 1;
   4.354 +		}
   4.355 +# endif /* STAGE1_5 */
   4.356 +	      
   4.357 +	      errnum = ERR_FILE_NOT_FOUND;
   4.358 +	      *rest = ch;
   4.359 +	    }
   4.360 +	  
   4.361 +	  return 0;
   4.362 +	}
   4.363 +      
   4.364 +      if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
   4.365 +	{
   4.366 +	  /* This is a long filename.  The filename is build from back
   4.367 +	   * to front and may span multiple entries.  To bind these
   4.368 +	   * entries together they all contain the same checksum over
   4.369 +	   * the short alias.
   4.370 +	   *
   4.371 +	   * The id field tells if this is the first entry (the last
   4.372 +	   * part) of the long filename, and also at which offset this
   4.373 +	   * belongs.
   4.374 +	   *
   4.375 +	   * We just write the part of the long filename this entry
   4.376 +	   * describes and continue with the next dir entry.
   4.377 +	   */
   4.378 +	  int i, offset;
   4.379 +	  unsigned char id = FAT_LONGDIR_ID(dir_buf);
   4.380 +	  
   4.381 +	  if ((id & 0x40)) 
   4.382 +	    {
   4.383 +	      id &= 0x3f;
   4.384 +	      slot = id;
   4.385 +	      filename[slot * 13] = 0;
   4.386 +	      alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
   4.387 +	    } 
   4.388 +	  
   4.389 +	  if (id != slot || slot == 0
   4.390 +	      || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
   4.391 +	    {
   4.392 +	      alias_checksum = -1;
   4.393 +	      continue;
   4.394 +	    }
   4.395 +	  
   4.396 +	  slot--;
   4.397 +	  offset = slot * 13;
   4.398 +	  
   4.399 +	  for (i=0; i < 13; i++)
   4.400 +	    filename[offset+i] = dir_buf[longdir_pos[i]];
   4.401 +	  continue;
   4.402 +	}
   4.403 +      
   4.404 +      if (!FAT_DIRENTRY_VALID (dir_buf))
   4.405 +	continue;
   4.406 +      
   4.407 +      if (alias_checksum != -1 && slot == 0)
   4.408 +	{
   4.409 +	  int i;
   4.410 +	  unsigned char sum;
   4.411 +	  
   4.412 +	  slot = -2;
   4.413 +	  for (sum = 0, i = 0; i< 11; i++)
   4.414 +	    sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
   4.415 +	  
   4.416 +	  if (sum == alias_checksum)
   4.417 +	    {
   4.418 +# ifndef STAGE1_5
   4.419 +	      if (do_possibilities)
   4.420 +		goto print_filename;
   4.421 +# endif /* STAGE1_5 */
   4.422 +	      
   4.423 +	      if (substring (dirname, filename) == 0)
   4.424 +		break;
   4.425 +	    }
   4.426 +	}
   4.427 +      
   4.428 +      /* XXX convert to 8.3 filename format here */
   4.429 +      {
   4.430 +	int i, j, c;
   4.431 +	
   4.432 +	for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
   4.433 +	       && !isspace (c); i++);
   4.434 +	
   4.435 +	filename[i++] = '.';
   4.436 +	
   4.437 +	for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
   4.438 +	       && !isspace (c); j++);
   4.439 +	
   4.440 +	if (j == 0)
   4.441 +	  i--;
   4.442 +	
   4.443 +	filename[i + j] = 0;
   4.444 +      }
   4.445 +      
   4.446 +# ifndef STAGE1_5
   4.447 +      if (do_possibilities)
   4.448 +	{
   4.449 +	print_filename:
   4.450 +	  if (substring (dirname, filename) <= 0)
   4.451 +	    {
   4.452 +	      if (print_possibilities > 0)
   4.453 +		print_possibilities = -print_possibilities;
   4.454 +	      print_a_completion (filename);
   4.455 +	    }
   4.456 +	  continue;
   4.457 +	}
   4.458 +# endif /* STAGE1_5 */
   4.459 +      
   4.460 +      if (substring (dirname, filename) == 0)
   4.461 +	break;
   4.462 +    }
   4.463 +  
   4.464 +  *(dirname = rest) = ch;
   4.465 +  
   4.466 +  attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
   4.467 +  filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
   4.468 +  filepos = 0;
   4.469 +  FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
   4.470 +  FAT_SUPER->current_cluster_num = INT_MAX;
   4.471 +  
   4.472 +  /* go back to main loop at top of function */
   4.473 +  goto loop;
   4.474 +}
   4.475 +
   4.476 +fsi_plugin_ops_t *
   4.477 +fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
   4.478 +{
   4.479 +	static fsig_plugin_ops_t ops = {
   4.480 +		FSIMAGE_PLUGIN_VERSION,
   4.481 +		.fpo_mount = fat_mount,
   4.482 +		.fpo_dir = fat_dir,
   4.483 +		.fpo_read = fat_read
   4.484 +	};
   4.485 +
   4.486 +	*name = "fat";
   4.487 +	return (fsig_init(fp, &ops));
   4.488 +}