source: trunk/packages/xen-3.1/xen-3.1/tools/libfsimage/ufs/fsys_ufs.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 6.6 KB
Line 
1/* 
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2006 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 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
21 * Use is subject to license terms.
22 */
23
24/* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */
25
26#include <fsimage_grub.h>
27
28#include "ufs.h"
29
30/* These are the pools of buffers, etc. */
31
32#define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
33#define INODE ((struct icommon *)(FSYS_BUF + 0x1000))
34#define DIRENT (FSYS_BUF + 0x4000)
35#define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
36#define INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000))  /* 1st indirect blk */
37
38#define indirblk0 (*fsig_int1(ffi))
39#define indirblk1 (*fsig_int2(ffi))
40
41static int openi(fsi_file_t *, grub_ino_t);
42static grub_ino_t dlook(fsi_file_t *, grub_ino_t, char *);
43static grub_daddr32_t sbmap(fsi_file_t *, grub_daddr32_t);
44
45/* read superblock and check fs magic */
46int
47ufs_mount(fsi_file_t *ffi, const char *options)
48{
49        if (/*! IS_PC_SLICE_TYPE_SOLARIS(current_slice) || */
50            !devread(ffi, UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) ||
51            SUPERBLOCK->fs_magic != UFS_MAGIC)
52                return 0;
53
54        return 1;
55}
56
57
58/*
59 * searching for a file, if successful, inode will be loaded in INODE
60 * The entry point should really be named ufs_open(char *pathname).
61 * For now, keep it consistent with the rest of fsys modules.
62 */
63int
64ufs_dir(fsi_file_t *ffi, char *dirname)
65{
66        grub_ino_t inode = ROOTINO;     /* start from root */
67        char *fname, ch;
68
69        indirblk0 = indirblk1 = 0;
70
71        /* skip leading slashes */
72        while (*dirname == '/')
73                dirname++;
74
75        while (inode && *dirname && !isspace(*dirname)) {
76                if (!openi(ffi, inode))
77                        return 0;
78
79                /* parse for next path component */
80                fname = dirname;
81                while (*dirname && !isspace(*dirname) && *dirname != '/')
82                        dirname++;
83                ch = *dirname;
84                *dirname = 0;   /* ensure null termination */
85
86                inode = dlook(ffi, inode, fname);
87                *dirname = ch;
88                while (*dirname == '/')
89                        dirname++;
90        }
91
92        /* return 1 only if inode exists and is a regular file */
93        if  (! openi(ffi, inode))
94                return (0);
95        filepos = 0;
96        filemax = INODE->ic_sizelo;
97        return (inode && ((INODE->ic_smode & IFMT) == IFREG));
98}
99
100/*
101 * This is the high-level read function.
102 */
103int
104ufs_read(fsi_file_t *ffi, char *buf, int len)
105{
106        int off, size, ret = 0, ok;
107        grub_daddr32_t lblk, dblk;
108
109        while (len) {
110                off = blkoff(SUPERBLOCK, filepos);
111                lblk = lblkno(SUPERBLOCK, filepos);
112                size = SUPERBLOCK->fs_bsize;
113                size -= off;
114                if (size > len)
115                        size = len;
116
117                if ((dblk = sbmap(ffi, lblk)) <= 0) {
118                        /* we are in a file hole, just zero the buf */
119                        grub_memset(buf, 0, size);
120                } else {
121                        disk_read_func = disk_read_hook;
122                        ok = devread(ffi, fsbtodb(SUPERBLOCK, dblk),
123                                off, size, buf);
124                        disk_read_func = 0;
125                        if (!ok)
126                                return 0;
127                }
128                buf += size;
129                len -= size;
130                filepos += size;
131                ret += size;
132        }
133
134        return (ret);
135}
136
137int
138ufs_embed (int *start_sector, int needed_sectors)
139{
140        if (needed_sectors > 14)
141                return 0;
142
143        *start_sector = 2;
144        return 1;
145}
146
147/* read inode and place content in INODE */
148static int
149openi(fsi_file_t *ffi, grub_ino_t inode)
150{
151        grub_daddr32_t dblk;
152        int off;
153
154        /* get block and byte offset into the block */
155        dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode));
156        off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon);
157
158        return (devread(ffi, dblk, off, sizeof (struct icommon), (char *)INODE));
159}
160
161/*
162 * Performs fileblock mapping. Convert file block no. to disk block no.
163 * Returns 0 when block doesn't exist and <0 when block isn't initialized
164 * (i.e belongs to a hole in the file).
165 */
166grub_daddr32_t
167sbmap(fsi_file_t *ffi, grub_daddr32_t bn)
168{
169        int level, bound, i, index;
170        grub_daddr32_t nb, blkno;
171        grub_daddr32_t *db = INODE->ic_db;
172
173        /* blocks 0..UFS_NDADDR are direct blocks */
174        if (bn < UFS_NDADDR) {
175                return db[bn];
176        }
177
178        /* determine how many levels of indirection. */
179        level = 0;
180        bn -= UFS_NDADDR;
181        bound = UFS_NINDIR(SUPERBLOCK);
182        while (bn >= bound) {
183                level++;
184                bn -= bound;
185                bound *= UFS_NINDIR(SUPERBLOCK);
186        }
187        if (level >= UFS_NIADDR)        /* bn too big */
188                return ((grub_daddr32_t)0);
189
190        /* fetch the first indirect block */
191        nb = INODE->ic_ib[level];
192        if (nb == 0) {
193                return ((grub_daddr32_t)0);
194        }
195        if (indirblk0 != nb) {
196                indirblk0 = 0;
197                blkno = fsbtodb(SUPERBLOCK, nb);
198                if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
199                    (char *)INDIRBLK0))
200                        return (0);
201                indirblk0 = nb;
202        }
203        bound /= UFS_NINDIR(SUPERBLOCK);
204        index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
205        nb = INDIRBLK0[index];
206
207        /* fetch through the indirect blocks */
208        for (i = 1; i <= level; i++) {
209                if (indirblk1 != nb) {
210                        blkno = fsbtodb(SUPERBLOCK, nb);
211                        if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
212                            (char *)INDIRBLK1))
213                                return (0);
214                        indirblk1 = nb;
215                }
216                bound /= UFS_NINDIR(SUPERBLOCK);
217                index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
218                nb = INDIRBLK1[index];
219                if (nb == 0)
220                        return ((grub_daddr32_t)0);
221        }
222
223        return (nb);
224}
225
226/* search directory content for name, return inode number */
227static grub_ino_t
228dlook(fsi_file_t *ffi, grub_ino_t dir_ino, char *name)
229{
230        int loc, off;
231        grub_daddr32_t lbn, dbn, dblk;
232        struct direct *dp;
233
234        if ((INODE->ic_smode & IFMT) != IFDIR)
235                return 0;
236
237        loc = 0;
238        while (loc < INODE->ic_sizelo) {
239                /* offset into block */
240                off = blkoff(SUPERBLOCK, loc);
241                if (off == 0) {         /* need to read in a new block */
242                        /* get logical block number */
243                        lbn = lblkno(SUPERBLOCK, loc);
244                        /* resolve indrect blocks */
245                        dbn = sbmap(ffi, lbn);
246                        if (dbn == 0)
247                                return (0);
248
249                        dblk = fsbtodb(SUPERBLOCK, dbn);
250                        if (!devread(ffi, dblk, 0, SUPERBLOCK->fs_bsize,
251                            (char *)DIRENT)) {
252                                return 0;
253                        }
254                }
255
256                dp = (struct direct *)(DIRENT + off);
257                if (dp->d_ino && substring(name, dp->d_name) == 0)
258                        return (dp->d_ino);
259                loc += dp->d_reclen;
260        }
261        return (0);
262}
263
264fsi_plugin_ops_t *
265fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
266{
267        static fsig_plugin_ops_t ops = {
268                FSIMAGE_PLUGIN_VERSION,
269                .fpo_mount = ufs_mount,
270                .fpo_dir = ufs_dir,
271                .fpo_read = ufs_read
272        };
273
274        *name = "ufs";
275        return (fsig_init(fp, &ops));
276}
Note: See TracBrowser for help on using the repository browser.