1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2001   Free Software Foundation, Inc.
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#ifdef FSYS_VSTAFS
21
22#include "shared.h"
23#include "filesys.h"
24#include "vstafs.h"
25
26
27static void get_file_info (int sector);
28static struct dir_entry *vstafs_readdir (long sector);
29static struct dir_entry *vstafs_nextdir (void);
30
31
32#define FIRST_SECTOR	((struct first_sector *) FSYS_BUF)
33#define FILE_INFO	((struct fs_file *) (int) FIRST_SECTOR + 8192)
34#define DIRECTORY_BUF	((struct dir_entry *) (int) FILE_INFO + 512)
35
36#define ROOT_SECTOR	1
37
38/*
39 * In f_sector we store the sector number in which the information about
40 * the found file is.
41 */
42extern int filepos;
43static int f_sector;
44
45int
46vstafs_mount (void)
47{
48  int retval = 1;
49
50  if( (((current_drive & 0x80) || (current_slice != 0))
51       && current_slice != PC_SLICE_TYPE_VSTAFS)
52      ||  ! devread (0, 0, BLOCK_SIZE, (char *) FSYS_BUF)
53      ||  FIRST_SECTOR->fs_magic != 0xDEADFACE)
54    retval = 0;
55
56  return retval;
57}
58
59static void
60get_file_info (int sector)
61{
62  devread (sector, 0, BLOCK_SIZE, (char *) FILE_INFO);
63}
64
65static int curr_ext, current_direntry, current_blockpos;
66static struct alloc *a;
67
68static struct dir_entry *
69vstafs_readdir (long sector)
70{
71  /*
72   * Get some information from the current directory
73   */
74  get_file_info (sector);
75  if (FILE_INFO->type != 2)
76    {
77      errnum = ERR_FILE_NOT_FOUND;
78      return 0;
79    }
80
81  a = FILE_INFO->blocks;
82  curr_ext = 0;
83  devread (a[curr_ext].a_start, 0, 512, (char *) DIRECTORY_BUF);
84  current_direntry = 11;
85  current_blockpos = 0;
86
87  return &DIRECTORY_BUF[10];
88}
89
90static struct dir_entry *
91vstafs_nextdir (void)
92{
93  if (current_direntry > 15)
94    {
95      current_direntry = 0;
96      if (++current_blockpos > (a[curr_ext].a_len - 1))
97	{
98	  current_blockpos = 0;
99	  curr_ext++;
100	}
101
102      if (curr_ext < FILE_INFO->extents)
103	{
104	  devread (a[curr_ext].a_start + current_blockpos, 0,
105		   512, (char *) DIRECTORY_BUF);
106	}
107      else
108	{
109	  /* errnum =ERR_FILE_NOT_FOUND; */
110	  return 0;
111	}
112    }
113
114  return &DIRECTORY_BUF[current_direntry++];
115}
116
117int
118vstafs_dir (char *dirname)
119{
120  char *fn, ch;
121  struct dir_entry *d;
122  /* int l, i, s; */
123
124  /*
125   * Read in the entries of the current directory.
126   */
127  f_sector = ROOT_SECTOR;
128  do
129    {
130      if (! (d = vstafs_readdir (f_sector)))
131	{
132	  return 0;
133	}
134
135      /*
136       * Find the file in the path
137       */
138      while (*dirname == '/') dirname++;
139      fn = dirname;
140      while ((ch = *fn) && ch != '/' && ! isspace (ch)) fn++;
141      *fn = 0;
142
143      do
144	{
145	  if (d->name[0] == 0 || d->name[0] & 0x80)
146	    continue;
147
148#ifndef STAGE1_5
149	  if (print_possibilities && ch != '/'
150	      && (! *dirname || strcmp (dirname, d->name) <= 0))
151	    {
152	      if (print_possibilities > 0)
153		print_possibilities = -print_possibilities;
154
155	      printf ("  %s", d->name);
156	    }
157#endif
158	  if (! grub_strcmp (dirname, d->name))
159	    {
160	      f_sector = d->start;
161	      get_file_info (f_sector);
162	      filemax = FILE_INFO->len;
163	      break;
164	    }
165	}
166      while ((d =vstafs_nextdir ()));
167
168      *(dirname = fn) = ch;
169      if (! d)
170	{
171	  if (print_possibilities < 0)
172	    {
173	      putchar ('\n');
174	      return 1;
175	    }
176
177	  errnum = ERR_FILE_NOT_FOUND;
178	  return 0;
179	}
180    }
181  while (*dirname && ! isspace (ch));
182
183  return 1;
184}
185
186int
187vstafs_read (char *addr, int len)
188{
189  struct alloc *a;
190  int size, ret = 0, offset, curr_len = 0;
191  int curr_ext;
192  char extent;
193  int ext_size;
194  char *curr_pos;
195
196  get_file_info (f_sector);
197  size = FILE_INFO->len-VSTAFS_START_DATA;
198  a = FILE_INFO->blocks;
199
200  if (filepos > 0)
201    {
202      if (filepos < a[0].a_len * 512 - VSTAFS_START_DATA)
203	{
204	  offset = filepos + VSTAFS_START_DATA;
205	  extent = 0;
206	  curr_len = a[0].a_len * 512 - offset - filepos;
207	}
208      else
209	{
210	  ext_size = a[0].a_len * 512 - VSTAFS_START_DATA;
211	  offset = filepos - ext_size;
212	  extent = 1;
213	  do
214	    {
215	      curr_len -= ext_size;
216	      offset -= ext_size;
217	      ext_size = a[extent+1].a_len * 512;
218	    }
219	  while (extent < FILE_INFO->extents && offset>ext_size);
220	}
221    }
222  else
223    {
224      offset = VSTAFS_START_DATA;
225      extent = 0;
226      curr_len = a[0].a_len * 512 - offset;
227    }
228
229  curr_pos = addr;
230  if (curr_len > len)
231    curr_len = len;
232
233  for (curr_ext=extent;
234       curr_ext < FILE_INFO->extents;
235       curr_len = a[curr_ext].a_len * 512, curr_pos += curr_len, curr_ext++)
236    {
237      ret += curr_len;
238      size -= curr_len;
239      if (size < 0)
240	{
241	  ret += size;
242	  curr_len += size;
243	}
244
245      devread (a[curr_ext].a_start,offset, curr_len, curr_pos);
246      offset = 0;
247    }
248
249  return ret;
250}
251
252#endif /* FSYS_VSTAFS */
253