Line 0
Link Here
|
|
|
1 |
/* |
2 |
* xfs.c - an implementation of the SGI XFS file system for aboot |
3 |
* Jan-Jaap van der Heijden <J.J.vanderHeijden@home.nl> |
4 |
* |
5 |
* Based on fsys_xfs.c from GRUB -- GRand Unified Bootloader |
6 |
* Copyright (C) 2001,2002,2004 Free Software Foundation, Inc. |
7 |
*/ |
8 |
/* |
9 |
* This program is free software; you can redistribute it and/or modify |
10 |
* it under the terms of the GNU General Public License as published by |
11 |
* the Free Software Foundation; either version 2 of the License, or |
12 |
* (at your option) any later version. |
13 |
* |
14 |
* This program is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
* GNU General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU General Public License |
20 |
* along with this program; if not, write to the Free Software |
21 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 |
*/ |
23 |
|
24 |
#include <asm/system.h> |
25 |
#include "config.h" |
26 |
#include "aboot.h" |
27 |
#include "bootfs.h" |
28 |
#include "cons.h" |
29 |
#include "disklabel.h" |
30 |
#include "utils.h" |
31 |
#include "xfs.h" |
32 |
|
33 |
static int xfs_mount(long cons_dev, long p_offset, long quiet); |
34 |
static int xfs_bread(int fd, long blkno, long nblks, char *buffer); |
35 |
static int xfs_open(const char *dirname); |
36 |
static void xfs_close(int fd); |
37 |
static const char *xfs_readdir(int fd, int rewind); |
38 |
static int xfs_fstat(int fd, struct stat* buf); |
39 |
|
40 |
struct bootfs xfsfs = { |
41 |
FS_EXT2, |
42 |
0, |
43 |
xfs_mount, |
44 |
xfs_open, |
45 |
xfs_bread, |
46 |
xfs_close, |
47 |
xfs_readdir, |
48 |
xfs_fstat |
49 |
}; |
50 |
|
51 |
static long dev = -1; |
52 |
static long partition_offset; |
53 |
static long filepos; |
54 |
static long filemax; /* filelen */ |
55 |
|
56 |
static long xfs_read (void *buf, long len); |
57 |
|
58 |
#define isspace(c) ((c) == 0x10) |
59 |
|
60 |
static int |
61 |
devread(long sector, long start, long length, void *buf) |
62 |
{ |
63 |
long pos = sector * SECT_SIZE; |
64 |
pos += partition_offset + start; |
65 |
#ifdef DEBUG_XFS |
66 |
printf("Reading %ld bytes, starting at sector %ld, disk offset %ld\n", |
67 |
length, sector, pos); |
68 |
#endif |
69 |
return cons_read(dev, buf, length, pos); |
70 |
} |
71 |
|
72 |
#define MAXNAMELEN 256 |
73 |
#define SECTOR_BITS 9 |
74 |
#define MAX_LINK_COUNT 8 |
75 |
|
76 |
typedef struct xad { |
77 |
xfs_fileoff_t offset; |
78 |
xfs_fsblock_t start; |
79 |
xfs_filblks_t len; |
80 |
} xad_t; |
81 |
|
82 |
struct xfs_info { |
83 |
int bsize; |
84 |
int dirbsize; |
85 |
int isize; |
86 |
unsigned int agblocks; |
87 |
int bdlog; |
88 |
int blklog; |
89 |
int inopblog; |
90 |
int agblklog; |
91 |
int agnolog; |
92 |
unsigned int nextents; |
93 |
xfs_daddr_t next; |
94 |
xfs_daddr_t daddr; |
95 |
xfs_dablk_t forw; |
96 |
xfs_dablk_t dablk; |
97 |
xfs_bmbt_rec_32_t *xt; |
98 |
xfs_bmbt_ptr_t ptr0; |
99 |
int btnode_ptr0_off; |
100 |
int i8param; |
101 |
int dirpos; |
102 |
int dirmax; |
103 |
int blkoff; |
104 |
int fpos; |
105 |
xfs_ino_t rootino; |
106 |
xfs_ino_t new_ino; |
107 |
}; |
108 |
|
109 |
static struct xfs_info xfs; |
110 |
|
111 |
#ifdef __alpha__ /* take care of alignment*/ |
112 |
static long FSYS_BUF[32768/sizeof(long)]; |
113 |
#define dirbuf ((long *)FSYS_BUF) |
114 |
#define filebuf ((long *)FSYS_BUF + 4096/sizeof(long)) |
115 |
#define inode ((xfs_dinode_t *)((long *)FSYS_BUF + 8192/sizeof(long))) |
116 |
#else |
117 |
static char FSYS_BUF[32768]; |
118 |
#define dirbuf ((char *)FSYS_BUF) |
119 |
#define filebuf ((char *)FSYS_BUF + 4096) |
120 |
#define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192)) |
121 |
#endif |
122 |
|
123 |
#define icore (inode->di_core) |
124 |
#define mask32lo(n) (((uint32_t)1 << (n)) - 1) |
125 |
|
126 |
#define XFS_INO_MASK(k) ((uint32_t)((1ULL << (k)) - 1)) |
127 |
#define XFS_INO_OFFSET_BITS xfs.inopblog |
128 |
#define XFS_INO_AGBNO_BITS xfs.agblklog |
129 |
#define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog) |
130 |
#define XFS_INO_AGNO_BITS xfs.agnolog |
131 |
|
132 |
static inline xfs_agblock_t |
133 |
agino2agbno (xfs_agino_t agino) |
134 |
{ |
135 |
return agino >> XFS_INO_OFFSET_BITS; |
136 |
} |
137 |
|
138 |
static inline xfs_agnumber_t |
139 |
ino2agno (xfs_ino_t ino) |
140 |
{ |
141 |
return ino >> XFS_INO_AGINO_BITS; |
142 |
} |
143 |
|
144 |
static inline xfs_agino_t |
145 |
ino2agino (xfs_ino_t ino) |
146 |
{ |
147 |
return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS); |
148 |
} |
149 |
|
150 |
static inline int |
151 |
ino2offset (xfs_ino_t ino) |
152 |
{ |
153 |
return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS); |
154 |
} |
155 |
|
156 |
/* XFS is big endian, alpha is little endian */ |
157 |
#define le16(x) __swab16(x) |
158 |
#define le32(x) __swab32(x) |
159 |
#define le64(x) __swab64(x) |
160 |
|
161 |
static xfs_fsblock_t |
162 |
xt_start (xfs_bmbt_rec_32_t *r) |
163 |
{ |
164 |
return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) | |
165 |
(((xfs_fsblock_t)le32 (r->l2)) << 11) | |
166 |
(((xfs_fsblock_t)le32 (r->l3)) >> 21); |
167 |
} |
168 |
|
169 |
static xfs_fileoff_t |
170 |
xt_offset (xfs_bmbt_rec_32_t *r) |
171 |
{ |
172 |
return (((xfs_fileoff_t)le32 (r->l0) & |
173 |
mask32lo(31)) << 23) | |
174 |
(((xfs_fileoff_t)le32 (r->l1)) >> 9); |
175 |
} |
176 |
|
177 |
static xfs_filblks_t |
178 |
xt_len (xfs_bmbt_rec_32_t *r) |
179 |
{ |
180 |
return le32(r->l3) & mask32lo(21); |
181 |
} |
182 |
|
183 |
static const char xfs_highbit[256] = { |
184 |
-1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ |
185 |
3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ |
186 |
4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ |
187 |
4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */ |
188 |
5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */ |
189 |
5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */ |
190 |
5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */ |
191 |
5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */ |
192 |
6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */ |
193 |
6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */ |
194 |
6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */ |
195 |
6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */ |
196 |
6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */ |
197 |
6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */ |
198 |
6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */ |
199 |
6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */ |
200 |
7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */ |
201 |
7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */ |
202 |
7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */ |
203 |
7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */ |
204 |
7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */ |
205 |
7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */ |
206 |
7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */ |
207 |
7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */ |
208 |
7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */ |
209 |
7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */ |
210 |
7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */ |
211 |
7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */ |
212 |
7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */ |
213 |
7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */ |
214 |
7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */ |
215 |
7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */ |
216 |
}; |
217 |
|
218 |
static int |
219 |
xfs_highbit32(uint32_t v) |
220 |
{ |
221 |
int i; |
222 |
|
223 |
if (v & 0xffff0000) |
224 |
if (v & 0xff000000) |
225 |
i = 24; |
226 |
else |
227 |
i = 16; |
228 |
else if (v & 0x0000ffff) |
229 |
if (v & 0x0000ff00) |
230 |
i = 8; |
231 |
else |
232 |
i = 0; |
233 |
else |
234 |
return -1; |
235 |
return i + xfs_highbit[(v >> i) & 0xff]; |
236 |
} |
237 |
|
238 |
static int |
239 |
isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len) |
240 |
{ |
241 |
return (key >= offset) ? (key < offset + len ? 1 : 0) : 0; |
242 |
} |
243 |
|
244 |
static xfs_daddr_t |
245 |
agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno) |
246 |
{ |
247 |
return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog; |
248 |
} |
249 |
|
250 |
static xfs_daddr_t |
251 |
fsb2daddr (xfs_fsblock_t fsbno) |
252 |
{ |
253 |
return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog), |
254 |
(xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog))); |
255 |
} |
256 |
|
257 |
#undef offsetof |
258 |
#define offsetof(t,m) ((int)&(((t *)0)->m)) |
259 |
|
260 |
static inline int |
261 |
btroot_maxrecs (void) |
262 |
{ |
263 |
int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize; |
264 |
|
265 |
return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) / |
266 |
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)); |
267 |
} |
268 |
|
269 |
static int |
270 |
di_read (xfs_ino_t ino) |
271 |
{ |
272 |
xfs_agino_t agino; |
273 |
xfs_agnumber_t agno; |
274 |
xfs_agblock_t agbno; |
275 |
xfs_daddr_t daddr; |
276 |
int offset; |
277 |
|
278 |
agno = ino2agno (ino); |
279 |
agino = ino2agino (ino); |
280 |
agbno = agino2agbno (agino); |
281 |
offset = ino2offset (ino); |
282 |
daddr = agb2daddr (agno, agbno); |
283 |
|
284 |
devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode); |
285 |
|
286 |
xfs.ptr0 = *(xfs_bmbt_ptr_t *) |
287 |
(inode->di_u.di_c + sizeof(xfs_bmdr_block_t) |
288 |
+ btroot_maxrecs ()*sizeof(xfs_bmbt_key_t)); |
289 |
|
290 |
return 1; |
291 |
} |
292 |
|
293 |
static void |
294 |
init_extents (void) |
295 |
{ |
296 |
xfs_bmbt_ptr_t ptr0; |
297 |
xfs_btree_lblock_t h; |
298 |
|
299 |
switch (icore.di_format) { |
300 |
case XFS_DINODE_FMT_EXTENTS: |
301 |
xfs.xt = inode->di_u.di_bmx; |
302 |
xfs.nextents = le32 (icore.di_nextents); |
303 |
break; |
304 |
case XFS_DINODE_FMT_BTREE: |
305 |
ptr0 = xfs.ptr0; |
306 |
for (;;) { |
307 |
xfs.daddr = fsb2daddr (le64(ptr0)); |
308 |
devread (xfs.daddr, 0, |
309 |
sizeof(xfs_btree_lblock_t), (char *)&h); |
310 |
if (!h.bb_level) { |
311 |
xfs.nextents = le16(h.bb_numrecs); |
312 |
xfs.next = fsb2daddr (le64(h.bb_rightsib)); |
313 |
xfs.fpos = sizeof(xfs_btree_block_t); |
314 |
return; |
315 |
} |
316 |
devread (xfs.daddr, xfs.btnode_ptr0_off, |
317 |
sizeof(xfs_bmbt_ptr_t), (char *)&ptr0); |
318 |
} |
319 |
} |
320 |
} |
321 |
|
322 |
static xad_t * |
323 |
next_extent (void) |
324 |
{ |
325 |
static xad_t xad; |
326 |
|
327 |
switch (icore.di_format) { |
328 |
case XFS_DINODE_FMT_EXTENTS: |
329 |
if (xfs.nextents == 0) |
330 |
return NULL; |
331 |
break; |
332 |
case XFS_DINODE_FMT_BTREE: |
333 |
if (xfs.nextents == 0) { |
334 |
xfs_btree_lblock_t h; |
335 |
if (xfs.next == 0) |
336 |
return NULL; |
337 |
xfs.daddr = xfs.next; |
338 |
devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h); |
339 |
xfs.nextents = le16(h.bb_numrecs); |
340 |
xfs.next = fsb2daddr (le64(h.bb_rightsib)); |
341 |
xfs.fpos = sizeof(xfs_btree_block_t); |
342 |
} |
343 |
/* Yeah, I know that's slow, but I really don't care */ |
344 |
devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf); |
345 |
xfs.xt = (xfs_bmbt_rec_32_t *)filebuf; |
346 |
xfs.fpos += sizeof(xfs_bmbt_rec_32_t); |
347 |
} |
348 |
xad.offset = xt_offset (xfs.xt); |
349 |
xad.start = xt_start (xfs.xt); |
350 |
xad.len = xt_len (xfs.xt); |
351 |
++xfs.xt; |
352 |
--xfs.nextents; |
353 |
|
354 |
return &xad; |
355 |
} |
356 |
|
357 |
/* |
358 |
* Name lies - the function reads only first 100 bytes |
359 |
*/ |
360 |
static void |
361 |
xfs_dabread (void) |
362 |
{ |
363 |
xad_t *xad; |
364 |
xfs_fileoff_t offset;; |
365 |
|
366 |
init_extents (); |
367 |
while ((xad = next_extent ())) { |
368 |
offset = xad->offset; |
369 |
if (isinxt (xfs.dablk, offset, xad->len)) { |
370 |
devread (fsb2daddr (xad->start + xfs.dablk - offset), |
371 |
0, 100, dirbuf); |
372 |
break; |
373 |
} |
374 |
} |
375 |
} |
376 |
|
377 |
static inline xfs_ino_t |
378 |
sf_ino (char *sfe, int namelen) |
379 |
{ |
380 |
void *p = sfe + namelen + 3; |
381 |
#ifdef __alpha__ |
382 |
xfs_ino_t ino = 0; |
383 |
if (xfs.i8param == 0) { |
384 |
memcpy(&ino, p, sizeof(xfs_dir2_ino8_t)); |
385 |
return le64(ino); |
386 |
} else { |
387 |
memcpy(&ino, p, sizeof(xfs_dir2_ino4_t)); |
388 |
return le32(ino); |
389 |
} |
390 |
#else |
391 |
/* unaligned access */ |
392 |
return (xfs.i8param == 0) |
393 |
? le64(*(xfs_ino_t *)p) : le32(*(uint32_t *)p); |
394 |
#endif |
395 |
} |
396 |
|
397 |
static inline xfs_ino_t |
398 |
sf_parent_ino (void) |
399 |
{ |
400 |
#ifdef __alpha__ |
401 |
void *p = &inode->di_u.di_dir2sf.hdr.parent; |
402 |
xfs_ino_t ino = 0; |
403 |
if (xfs.i8param == 0) { |
404 |
memcpy(&ino, p, sizeof(xfs_dir2_ino8_t)); |
405 |
return le64(ino); |
406 |
} else { |
407 |
memcpy(&ino, p, sizeof(xfs_dir2_ino4_t)); |
408 |
return le32(ino); |
409 |
} |
410 |
#else |
411 |
/* unaligned access */ |
412 |
return (xfs.i8param == 0) |
413 |
? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent)) |
414 |
: le32(*(uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent)); |
415 |
#endif |
416 |
} |
417 |
|
418 |
static inline int |
419 |
roundup8 (int n) |
420 |
{ |
421 |
return ((n+7)&~7); |
422 |
} |
423 |
|
424 |
static char * |
425 |
next_dentry (xfs_ino_t *ino) |
426 |
{ |
427 |
int namelen; |
428 |
int toread; |
429 |
static xfs_dir2_sf_entry_t *sfe; |
430 |
char *name = NULL; |
431 |
|
432 |
if (xfs.dirpos >= xfs.dirmax) { |
433 |
if (xfs.forw == 0) |
434 |
return NULL; |
435 |
xfs.dablk = xfs.forw; |
436 |
xfs_dabread (); |
437 |
#define h ((xfs_dir2_leaf_hdr_t *)dirbuf) |
438 |
xfs.dirmax = le16 (h->count) - le16 (h->stale); |
439 |
xfs.forw = le32 (h->info.forw); |
440 |
#undef h |
441 |
xfs.dirpos = 0; |
442 |
} |
443 |
|
444 |
switch (icore.di_format) { |
445 |
case XFS_DINODE_FMT_LOCAL: |
446 |
switch (xfs.dirpos) { |
447 |
case -2: |
448 |
*ino = 0; |
449 |
name = "."; |
450 |
namelen = 1; |
451 |
break; |
452 |
case -1: /* ".." */ |
453 |
*ino = sf_parent_ino (); |
454 |
name = ".."; |
455 |
namelen = 2; |
456 |
sfe = (xfs_dir2_sf_entry_t *) |
457 |
(inode->di_u.di_c |
458 |
+ sizeof(xfs_dir2_sf_hdr_t) |
459 |
- xfs.i8param); |
460 |
break; |
461 |
default: |
462 |
namelen = sfe->namelen; |
463 |
*ino = sf_ino ((char *)sfe, namelen); |
464 |
name = sfe->name; |
465 |
name[namelen] = 0; |
466 |
sfe = (xfs_dir2_sf_entry_t *) |
467 |
((char *)sfe + namelen + 11 - xfs.i8param); |
468 |
} |
469 |
break; |
470 |
case XFS_DINODE_FMT_BTREE: |
471 |
case XFS_DINODE_FMT_EXTENTS: |
472 |
#define dau ((xfs_dir2_data_union_t *)dirbuf) |
473 |
for (;;) { |
474 |
if (xfs.blkoff >= xfs.dirbsize) { |
475 |
xfs.blkoff = sizeof(xfs_dir2_data_hdr_t); |
476 |
filepos &= ~(xfs.dirbsize - 1); |
477 |
filepos |= xfs.blkoff; |
478 |
} |
479 |
xfs.blkoff += 4; |
480 |
if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) { |
481 |
toread = roundup8 (le16(dau->unused.length)) - 4; |
482 |
xfs.blkoff += toread; |
483 |
filepos += toread; |
484 |
continue; |
485 |
} |
486 |
break; |
487 |
} |
488 |
xfs_read ((char *)dirbuf + 4, 5); |
489 |
*ino = le64 (dau->entry.inumber); |
490 |
namelen = dau->entry.namelen; |
491 |
#undef dau |
492 |
toread = roundup8 (namelen + 11) - 9; |
493 |
xfs_read (dirbuf, toread); |
494 |
name = (char *)dirbuf; |
495 |
name[namelen] = 0; |
496 |
xfs.blkoff += toread + 5; |
497 |
} |
498 |
++xfs.dirpos; |
499 |
|
500 |
return name; |
501 |
} |
502 |
|
503 |
static char * |
504 |
first_dentry (xfs_ino_t *ino) |
505 |
{ |
506 |
xfs.forw = 0; |
507 |
switch (icore.di_format) { |
508 |
case XFS_DINODE_FMT_LOCAL: |
509 |
xfs.dirmax = inode->di_u.di_dir2sf.hdr.count; |
510 |
xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4; |
511 |
xfs.dirpos = -2; |
512 |
break; |
513 |
case XFS_DINODE_FMT_EXTENTS: |
514 |
case XFS_DINODE_FMT_BTREE: |
515 |
filepos = 0; |
516 |
xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t)); |
517 |
if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) { |
518 |
#define tail ((xfs_dir2_block_tail_t *)dirbuf) |
519 |
filepos = xfs.dirbsize - sizeof(*tail); |
520 |
xfs_read (dirbuf, sizeof(*tail)); |
521 |
xfs.dirmax = le32 (tail->count) - le32 (tail->stale); |
522 |
#undef tail |
523 |
} else { |
524 |
xfs.dablk = (1ULL << 35) >> xfs.blklog; |
525 |
#define h ((xfs_dir2_leaf_hdr_t *)dirbuf) |
526 |
#define n ((xfs_da_intnode_t *)dirbuf) |
527 |
for (;;) { |
528 |
xfs_dabread (); |
529 |
if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC)) |
530 |
|| (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) { |
531 |
xfs.dirmax = le16 (h->count) - le16 (h->stale); |
532 |
xfs.forw = le32 (h->info.forw); |
533 |
break; |
534 |
} |
535 |
xfs.dablk = le32 (n->btree[0].before); |
536 |
} |
537 |
#undef n |
538 |
#undef h |
539 |
} |
540 |
xfs.blkoff = sizeof(xfs_dir2_data_hdr_t); |
541 |
filepos = xfs.blkoff; |
542 |
xfs.dirpos = 0; |
543 |
} |
544 |
return next_dentry (ino); |
545 |
} |
546 |
|
547 |
|
548 |
|
549 |
/* |
550 |
* Initialize an XFS partition starting at offset P_OFFSET; this is |
551 |
* sort-of the same idea as "mounting" it. Read in the relevant |
552 |
* control structures and make them available to the user. Returns 0 |
553 |
* if successful, -1 on failure. |
554 |
*/ |
555 |
static int |
556 |
xfs_mount(long cons_dev, long p_offset, long quiet) |
557 |
{ |
558 |
xfs_sb_t super; |
559 |
|
560 |
partition_offset = p_offset; |
561 |
|
562 |
if (cons_read (cons_dev, &super, sizeof(super), partition_offset) != sizeof(super)) { |
563 |
printf("xfs_mount: read_disk_block failed!\n"); |
564 |
return -1; |
565 |
} else if (le32(super.sb_magicnum) != XFS_SB_MAGIC) { |
566 |
printf("xfs_mount: Bad magic: %x\n", super.sb_magicnum); |
567 |
return -1; |
568 |
} else if ((le16(super.sb_versionnum) & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) { |
569 |
printf("xfs_mount: Bad version: %x\n", super.sb_versionnum); |
570 |
return -1; |
571 |
} |
572 |
|
573 |
xfs.bsize = le32 (super.sb_blocksize); |
574 |
xfs.blklog = super.sb_blocklog; |
575 |
xfs.bdlog = xfs.blklog - SECTOR_BITS; |
576 |
xfs.rootino = le64 (super.sb_rootino); |
577 |
xfs.isize = le16 (super.sb_inodesize); |
578 |
xfs.agblocks = le32 (super.sb_agblocks); |
579 |
xfs.dirbsize = xfs.bsize << super.sb_dirblklog; |
580 |
|
581 |
xfs.inopblog = super.sb_inopblog; |
582 |
xfs.agblklog = super.sb_agblklog; |
583 |
xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount)); |
584 |
|
585 |
xfs.btnode_ptr0_off = |
586 |
((xfs.bsize - sizeof(xfs_btree_block_t)) / |
587 |
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t))) |
588 |
* sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t); |
589 |
|
590 |
#ifdef DEBUG |
591 |
printf("XFS: version = %d\n",le16(super.sb_versionnum) & XFS_SB_VERSION_NUMBITS); |
592 |
printf("XFS: blocksize = %d\n",xfs.bsize); |
593 |
#endif |
594 |
dev = cons_dev; |
595 |
xfsfs.blocksize = xfs.bsize; |
596 |
return 0; |
597 |
} |
598 |
|
599 |
static long |
600 |
xfs_read (void *buf, long len) |
601 |
{ |
602 |
xad_t *xad; |
603 |
xfs_fileoff_t endofprev, endofcur, offset; |
604 |
xfs_filblks_t xadlen; |
605 |
int toread, startpos, endpos; |
606 |
|
607 |
if (icore.di_format == XFS_DINODE_FMT_LOCAL) { |
608 |
memmove (buf, inode->di_u.di_c + filepos, len); |
609 |
filepos += len; |
610 |
return len; |
611 |
} |
612 |
|
613 |
startpos = filepos; |
614 |
endpos = filepos + len; |
615 |
endofprev = (xfs_fileoff_t)-1; |
616 |
init_extents (); |
617 |
while (len > 0 && (xad = next_extent ())) { |
618 |
offset = xad->offset; |
619 |
xadlen = xad->len; |
620 |
if (isinxt (filepos >> xfs.blklog, offset, xadlen)) { |
621 |
endofcur = (offset + xadlen) << xfs.blklog; |
622 |
toread = (endofcur >= endpos) |
623 |
? len : (endofcur - filepos); |
624 |
devread (fsb2daddr (xad->start), |
625 |
filepos - (offset << xfs.blklog), toread, buf); |
626 |
buf += toread; |
627 |
len -= toread; |
628 |
filepos += toread; |
629 |
} else if (offset > endofprev) { |
630 |
toread = ((offset << xfs.blklog) >= endpos) |
631 |
? len : ((offset - endofprev) << xfs.blklog); |
632 |
len -= toread; |
633 |
filepos += toread; |
634 |
for (; toread; toread--) { |
635 |
*(char*)buf++ = 0; |
636 |
} |
637 |
continue; |
638 |
} |
639 |
endofprev = offset + xadlen; |
640 |
} |
641 |
|
642 |
return filepos - startpos; |
643 |
} |
644 |
|
645 |
/* |
646 |
* Read block number "blkno". |
647 |
*/ |
648 |
|
649 |
static int |
650 |
xfs_bread(int fd, long blkno, long nblks, char *buffer) |
651 |
{ |
652 |
if (fd == 1) { |
653 |
/* |
654 |
* Duh. XFS doesn't read past EOF |
655 |
* aboot does just that by trying to read nblks*blksize, |
656 |
* where nblks*blksize > filesize |
657 |
*/ |
658 |
memset(buffer,0,nblks*xfs.bsize); |
659 |
long nbytes = xfs_read(buffer, nblks*xfs.bsize); |
660 |
if (nbytes == le64(icore.di_size)) |
661 |
return nblks*xfs.bsize; |
662 |
return (int)nbytes; |
663 |
} |
664 |
printf("XFS error: bad file descriptor!\n"); |
665 |
return -1; |
666 |
} |
667 |
|
668 |
/* |
669 |
* Unix-like open routine. Returns a small integer |
670 |
* (does not care what file, we say it's OK) |
671 |
*/ |
672 |
static int xfs_open(const char *dirname) |
673 |
{ |
674 |
xfs_ino_t ino, parent_ino; |
675 |
xfs_fsize_t di_size; |
676 |
int di_mode; |
677 |
int cmp, n, link_count; |
678 |
char linkbuf[xfs.bsize]; |
679 |
char *rest, *name, ch; |
680 |
char namebuf[MAXNAMELEN]; |
681 |
strncpy(namebuf,dirname,MAXNAMELEN); |
682 |
char *filename = namebuf; |
683 |
|
684 |
#ifdef DEBUG_XFS |
685 |
printf("xfs_open(): filename = %s\n", filename); |
686 |
#endif |
687 |
|
688 |
parent_ino = ino = xfs.rootino; |
689 |
link_count = 0; |
690 |
for (;;) { |
691 |
di_read (ino); |
692 |
di_size = le64 (icore.di_size); |
693 |
di_mode = le16 (icore.di_mode); |
694 |
|
695 |
#ifdef DEBUG_XFS |
696 |
printf("xfs_open(): di_mode = %o\n", di_mode); |
697 |
#endif |
698 |
if ((di_mode & IFMT) == IFLNK) { |
699 |
if (++link_count > MAX_LINK_COUNT) { |
700 |
printf("XFS error: symlink loop!\n"); |
701 |
return 0; |
702 |
} |
703 |
if (di_size < xfs.bsize - 1) { |
704 |
filepos = 0; |
705 |
filemax = di_size; |
706 |
n = xfs_read (linkbuf, filemax); |
707 |
} else { |
708 |
printf("XFS error: bad file length!\n"); |
709 |
return 0; |
710 |
} |
711 |
|
712 |
ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino; |
713 |
while (n < (xfs.bsize - 1) && (linkbuf[n++] = *filename++)); |
714 |
linkbuf[n] = 0; |
715 |
filename = linkbuf; |
716 |
continue; |
717 |
} |
718 |
|
719 |
if (!*filename || isspace (*filename)) { |
720 |
if (((di_mode & IFMT) != IFREG) |
721 |
&& ((di_mode & IFMT) != IFDIR)) { |
722 |
printf("XFS error: bad file type!\n"); |
723 |
return 0; |
724 |
} |
725 |
filepos = 0; |
726 |
filemax = di_size; |
727 |
return 1; |
728 |
} |
729 |
|
730 |
if ((di_mode & IFMT) != IFDIR) { |
731 |
printf("XFS error: bad file type!\n"); |
732 |
return 0; |
733 |
} |
734 |
|
735 |
for (; *filename == '/'; filename++); |
736 |
|
737 |
if (!strcmp(filename,"")) { |
738 |
filepos = 0; |
739 |
filemax = 0; |
740 |
return 1; |
741 |
} |
742 |
|
743 |
for (rest = filename; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); |
744 |
*rest = 0; |
745 |
|
746 |
name = first_dentry (&xfs.new_ino); |
747 |
for (;;) { |
748 |
#ifdef DEBUG |
749 |
printf("xfs_open(): found %s\n", name); |
750 |
#endif |
751 |
cmp = (!*filename) ? -1 : strcmp (filename, name); |
752 |
if (cmp == 0) { |
753 |
parent_ino = ino; |
754 |
if (xfs.new_ino) |
755 |
ino = xfs.new_ino; |
756 |
*(filename = rest) = ch; |
757 |
break; |
758 |
} |
759 |
name = next_dentry (&xfs.new_ino); |
760 |
if (name == NULL) { |
761 |
*rest = ch; |
762 |
return -1; |
763 |
} |
764 |
} |
765 |
} |
766 |
} |
767 |
|
768 |
/* |
769 |
* Only one file is opened at any time, so close is a nop. |
770 |
*/ |
771 |
static void xfs_close(int fd) |
772 |
{ |
773 |
} |
774 |
|
775 |
/* |
776 |
* Return the next directory entry. |
777 |
* Must have opened the directory with xfs_open() |
778 |
*/ |
779 |
static const char * |
780 |
xfs_readdir(int fd, int rewind) |
781 |
{ |
782 |
if (fd != 1) |
783 |
return NULL; |
784 |
if ((le16 (icore.di_mode) & IFMT) != IFDIR) { |
785 |
printf("Not a directory!\n"); |
786 |
return NULL; |
787 |
} |
788 |
if (rewind) |
789 |
return first_dentry (&xfs.new_ino); |
790 |
return next_dentry (&xfs.new_ino); |
791 |
} |
792 |
|
793 |
/* |
794 |
* Get file status |
795 |
*/ |
796 |
static int |
797 |
xfs_fstat(int fd, struct stat* buf) |
798 |
{ |
799 |
if (fd != 1) |
800 |
return -1; |
801 |
|
802 |
memset(buf, 0, sizeof(struct stat)); |
803 |
buf->st_mode = le16(icore.di_mode); |
804 |
buf->st_flags = le16(icore.di_flags); |
805 |
buf->st_nlink = le16(icore.di_onlink); |
806 |
buf->st_uid = le32(icore.di_uid); |
807 |
buf->st_gid = le32(icore.di_gid); |
808 |
buf->st_size = le64(icore.di_size); |
809 |
buf->st_blocks = le64(icore.di_nblocks); |
810 |
buf->st_atime = le32(icore.di_atime.t_sec); |
811 |
buf->st_mtime = le32(icore.di_mtime.t_sec); |
812 |
buf->st_ctime = le32(icore.di_ctime.t_sec); |
813 |
return 0; |
814 |
} |
815 |
|
816 |
|