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 
27 static void get_file_info (int sector);
28 static struct dir_entry *vstafs_readdir (long sector);
29 static 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  */
42 extern int filepos;
43 static int f_sector;
44 
45 int
vstafs_mount(void)46 vstafs_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 
59 static void
get_file_info(int sector)60 get_file_info (int sector)
61 {
62   devread (sector, 0, BLOCK_SIZE, (char *) FILE_INFO);
63 }
64 
65 static int curr_ext, current_direntry, current_blockpos;
66 static struct alloc *a;
67 
68 static struct dir_entry *
vstafs_readdir(long sector)69 vstafs_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 
90 static struct dir_entry *
vstafs_nextdir(void)91 vstafs_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 
117 int
vstafs_dir(char * dirname)118 vstafs_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 
186 int
vstafs_read(char * addr,int len)187 vstafs_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