2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006 Free Software Foundation, Inc.
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.
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.
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.
20 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
21 * Use is subject to license terms.
24 /* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */
33 /* These are the pools of buffers, etc. */
35 #define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
36 #define INODE ((struct icommon *)(FSYS_BUF + 0x1000))
37 #define DIRENT (FSYS_BUF + 0x4000)
38 #define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
39 #define INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000)) /* 1st indirect blk */
41 static int indirblk0
, indirblk1
;
43 static int openi(grub_ino_t
);
44 static grub_ino_t
dlook(grub_ino_t
, char *);
45 static grub_daddr32_t
sbmap(grub_daddr32_t
);
47 /* read superblock and check fs magic */
51 if (! IS_PC_SLICE_TYPE_SOLARIS(current_slice
) ||
52 !devread(UFS_SBLOCK
, 0, UFS_SBSIZE
, (char *)SUPERBLOCK
) ||
53 SUPERBLOCK
->fs_magic
!= UFS_MAGIC
)
61 * searching for a file, if successful, inode will be loaded in INODE
62 * The entry point should really be named ufs_open(char *pathname).
63 * For now, keep it consistent with the rest of fsys modules.
66 ufs_dir(char *dirname
)
68 grub_ino_t inode
= ROOTINO
; /* start from root */
71 indirblk0
= indirblk1
= 0;
73 /* skip leading slashes */
74 while (*dirname
== '/')
77 while (inode
&& *dirname
&& !isspace(*dirname
)) {
81 /* parse for next path component */
83 while (*dirname
&& !isspace(*dirname
) && *dirname
!= '/')
86 *dirname
= 0; /* ensure null termination */
88 inode
= dlook(inode
, fname
);
90 while (*dirname
== '/')
94 /* return 1 only if inode exists and is a regular file */
98 filemax
= INODE
->ic_sizelo
;
99 return (inode
&& ((INODE
->ic_smode
& IFMT
) == IFREG
));
103 * This is the high-level read function.
106 ufs_read(char *buf
, int len
)
108 int off
, size
, ret
= 0, ok
;
109 grub_daddr32_t lblk
, dblk
;
112 off
= blkoff(SUPERBLOCK
, filepos
);
113 lblk
= lblkno(SUPERBLOCK
, filepos
);
114 size
= SUPERBLOCK
->fs_bsize
;
119 if ((dblk
= sbmap(lblk
)) <= 0) {
120 /* we are in a file hole, just zero the buf */
121 grub_memset(buf
, 0, size
);
123 disk_read_func
= disk_read_hook
;
124 ok
= devread(fsbtodb(SUPERBLOCK
, dblk
), off
, size
, buf
);
139 ufs_embed (unsigned long long *start_sector
, int needed_sectors
)
141 if (needed_sectors
> 14)
148 /* read inode and place content in INODE */
150 openi(grub_ino_t inode
)
155 /* get block and byte offset into the block */
156 dblk
= fsbtodb(SUPERBLOCK
, itod(SUPERBLOCK
, inode
));
157 off
= itoo(SUPERBLOCK
, inode
) * sizeof (struct icommon
);
159 return (devread(dblk
, off
, sizeof (struct icommon
), (char *)INODE
));
163 * Performs fileblock mapping. Convert file block no. to disk block no.
164 * Returns 0 when block doesn't exist and <0 when block isn't initialized
165 * (i.e belongs to a hole in the file).
168 sbmap(grub_daddr32_t bn
)
170 int level
, bound
, i
, index
;
171 grub_daddr32_t nb
, blkno
;
172 grub_daddr32_t
*db
= INODE
->ic_db
;
174 /* blocks 0..UFS_NDADDR are direct blocks */
175 if (bn
< UFS_NDADDR
) {
179 /* determine how many levels of indirection. */
182 bound
= UFS_NINDIR(SUPERBLOCK
);
183 while (bn
>= bound
) {
186 bound
*= UFS_NINDIR(SUPERBLOCK
);
188 if (level
>= UFS_NIADDR
) /* bn too big */
189 return ((grub_daddr32_t
)0);
191 /* fetch the first indirect block */
192 nb
= INODE
->ic_ib
[level
];
194 return ((grub_daddr32_t
)0);
196 if (indirblk0
!= nb
) {
198 blkno
= fsbtodb(SUPERBLOCK
, nb
);
199 if (!devread(blkno
, 0, SUPERBLOCK
->fs_bsize
,
204 bound
/= UFS_NINDIR(SUPERBLOCK
);
205 index
= (bn
/ bound
) % UFS_NINDIR(SUPERBLOCK
);
206 nb
= INDIRBLK0
[index
];
208 /* fetch through the indirect blocks */
209 for (i
= 1; i
<= level
; i
++) {
210 if (indirblk1
!= nb
) {
211 blkno
= fsbtodb(SUPERBLOCK
, nb
);
212 if (!devread(blkno
, 0, SUPERBLOCK
->fs_bsize
,
217 bound
/= UFS_NINDIR(SUPERBLOCK
);
218 index
= (bn
/ bound
) % UFS_NINDIR(SUPERBLOCK
);
219 nb
= INDIRBLK1
[index
];
221 return ((grub_daddr32_t
)0);
227 /* search directory content for name, return inode number */
229 dlook(grub_ino_t dir_ino
, char *name
)
232 grub_daddr32_t lbn
, dbn
, dblk
;
235 if ((INODE
->ic_smode
& IFMT
) != IFDIR
)
239 while (loc
< INODE
->ic_sizelo
) {
240 /* offset into block */
241 off
= blkoff(SUPERBLOCK
, loc
);
242 if (off
== 0) { /* need to read in a new block */
244 /* get logical block number */
245 lbn
= lblkno(SUPERBLOCK
, loc
);
246 /* resolve indrect blocks */
251 dblk
= fsbtodb(SUPERBLOCK
, dbn
);
252 if (!devread(dblk
, 0, SUPERBLOCK
->fs_bsize
,
258 dp
= (struct direct
*)(DIRENT
+ off
);
259 if (dp
->d_ino
&& substring(name
, dp
->d_name
) == 0)
266 #endif /* FSYS_UFS */