~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openbios/fs/grubfs/fsys_xfs.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* fsys_xfs.c - an implementation for the SGI XFS file system */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2001,2002  Free Software Foundation, Inc.
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
 
19
 *  MA 02110-1301, USA.
 
20
 */
 
21
 
 
22
#ifdef FSYS_XFS
 
23
 
 
24
#include "shared.h"
 
25
#include "filesys.h"
 
26
#include "xfs.h"
 
27
 
 
28
#define MAX_LINK_COUNT  8
 
29
 
 
30
typedef struct xad {
 
31
        xfs_fileoff_t offset;
 
32
        xfs_fsblock_t start;
 
33
        xfs_filblks_t len;
 
34
} xad_t;
 
35
 
 
36
struct xfs_info {
 
37
        int bsize;
 
38
        int dirbsize;
 
39
        int isize;
 
40
        unsigned int agblocks;
 
41
        int bdlog;
 
42
        int blklog;
 
43
        int inopblog;
 
44
        int agblklog;
 
45
        int agnolog;
 
46
        unsigned int nextents;
 
47
        xfs_daddr_t next;
 
48
        xfs_daddr_t daddr;
 
49
        xfs_dablk_t forw;
 
50
        xfs_dablk_t dablk;
 
51
        xfs_bmbt_rec_32_t *xt;
 
52
        xfs_bmbt_ptr_t ptr0;
 
53
        int btnode_ptr0_off;
 
54
        int i8param;
 
55
        int dirpos;
 
56
        int dirmax;
 
57
        int blkoff;
 
58
        int fpos;
 
59
        xfs_ino_t rootino;
 
60
};
 
61
 
 
62
static struct xfs_info xfs;
 
63
 
 
64
#define dirbuf          ((char *)FSYS_BUF)
 
65
#define filebuf         ((char *)FSYS_BUF + 4096)
 
66
#define inode           ((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
 
67
#define icore           (inode->di_core)
 
68
 
 
69
#define mask32lo(n)     (((__uint32_t)1 << (n)) - 1)
 
70
 
 
71
#define XFS_INO_MASK(k)         ((__uint32_t)((1ULL << (k)) - 1))
 
72
#define XFS_INO_OFFSET_BITS     xfs.inopblog
 
73
#define XFS_INO_AGBNO_BITS      xfs.agblklog
 
74
#define XFS_INO_AGINO_BITS      (xfs.agblklog + xfs.inopblog)
 
75
#define XFS_INO_AGNO_BITS       xfs.agnolog
 
76
 
 
77
static inline xfs_agblock_t
 
78
agino2agbno (xfs_agino_t agino)
 
79
{
 
80
        return agino >> XFS_INO_OFFSET_BITS;
 
81
}
 
82
 
 
83
static inline xfs_agnumber_t
 
84
ino2agno (xfs_ino_t ino)
 
85
{
 
86
        return ino >> XFS_INO_AGINO_BITS;
 
87
}
 
88
 
 
89
static inline xfs_agino_t
 
90
ino2agino (xfs_ino_t ino)
 
91
{
 
92
        return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS);
 
93
}
 
94
 
 
95
static inline int
 
96
ino2offset (xfs_ino_t ino)
 
97
{
 
98
        return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
 
99
}
 
100
 
 
101
static inline __uint16_t
 
102
le16 (__uint16_t x)
 
103
{
 
104
#ifdef __i386__
 
105
        __asm__("xchgb %b0,%h0" \
 
106
                : "=q" (x) \
 
107
                :  "0" (x)); \
 
108
                return x;
 
109
#else
 
110
        return __be16_to_cpu(x);
 
111
#endif
 
112
}
 
113
 
 
114
static inline __uint32_t
 
115
le32 (__uint32_t x)
 
116
{
 
117
#ifdef __i386__
 
118
#if 1
 
119
        /* 386 doesn't have bswap. So what. */
 
120
        __asm__("bswap %0" : "=r" (x) : "0" (x));
 
121
#else
 
122
        /* This is slower but this works on all x86 architectures.  */
 
123
        __asm__("xchgb %b0, %h0" \
 
124
                "\n\troll $16, %0" \
 
125
                "\n\txchgb %b0, %h0" \
 
126
                : "=q" (x) : "0" (x));
 
127
#endif
 
128
        return x;
 
129
#else
 
130
        return __be32_to_cpu(x);
 
131
#endif
 
132
}
 
133
 
 
134
static inline __uint64_t
 
135
le64 (__uint64_t x)
 
136
{
 
137
        __uint32_t h = x >> 32;
 
138
        __uint32_t l = x & ((1ULL<<32)-1);
 
139
        return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h)));
 
140
}
 
141
 
 
142
 
 
143
static xfs_fsblock_t
 
144
xt_start (xfs_bmbt_rec_32_t *r)
 
145
{
 
146
        return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) |
 
147
               (((xfs_fsblock_t)le32 (r->l2)) << 11) |
 
148
               (((xfs_fsblock_t)le32 (r->l3)) >> 21);
 
149
}
 
150
 
 
151
static xfs_fileoff_t
 
152
xt_offset (xfs_bmbt_rec_32_t *r)
 
153
{
 
154
        return (((xfs_fileoff_t)le32 (r->l0) &
 
155
                mask32lo(31)) << 23) |
 
156
                (((xfs_fileoff_t)le32 (r->l1)) >> 9);
 
157
}
 
158
 
 
159
static xfs_filblks_t
 
160
xt_len (xfs_bmbt_rec_32_t *r)
 
161
{
 
162
        return le32(r->l3) & mask32lo(21);
 
163
}
 
164
 
 
165
static inline int
 
166
xfs_highbit32(__uint32_t v)
 
167
{
 
168
        int i;
 
169
 
 
170
        if (--v) {
 
171
                for (i = 0; i < 31; i++, v >>= 1) {
 
172
                        if (v == 0)
 
173
                                return i;
 
174
                }
 
175
        }
 
176
        return 0;
 
177
}
 
178
 
 
179
static int
 
180
isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
 
181
{
 
182
        return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
 
183
}
 
184
 
 
185
static xfs_daddr_t
 
186
agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno)
 
187
{
 
188
        return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog;
 
189
}
 
190
 
 
191
static xfs_daddr_t
 
192
fsb2daddr (xfs_fsblock_t fsbno)
 
193
{
 
194
        return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog),
 
195
                         (xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog)));
 
196
}
 
197
 
 
198
#undef offsetof
 
199
#define offsetof(t,m)   ((long)&(((t *)0)->m))
 
200
 
 
201
static inline int
 
202
btroot_maxrecs (void)
 
203
{
 
204
        int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize;
 
205
 
 
206
        return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
 
207
                (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
 
208
}
 
209
 
 
210
static int
 
211
di_read (xfs_ino_t ino)
 
212
{
 
213
        xfs_agino_t agino;
 
214
        xfs_agnumber_t agno;
 
215
        xfs_agblock_t agbno;
 
216
        xfs_daddr_t daddr;
 
217
        int offset;
 
218
 
 
219
        agno = ino2agno (ino);
 
220
        agino = ino2agino (ino);
 
221
        agbno = agino2agbno (agino);
 
222
        offset = ino2offset (ino);
 
223
        daddr = agb2daddr (agno, agbno);
 
224
 
 
225
        devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode);
 
226
 
 
227
        xfs.ptr0 = *(xfs_bmbt_ptr_t *)
 
228
                    (inode->di_u.di_c + sizeof(xfs_bmdr_block_t)
 
229
                    + btroot_maxrecs ()*sizeof(xfs_bmbt_key_t));
 
230
 
 
231
        return 1;
 
232
}
 
233
 
 
234
static void
 
235
init_extents (void)
 
236
{
 
237
        xfs_bmbt_ptr_t ptr0;
 
238
        xfs_btree_lblock_t h;
 
239
 
 
240
        switch (icore.di_format) {
 
241
        case XFS_DINODE_FMT_EXTENTS:
 
242
                xfs.xt = inode->di_u.di_bmx;
 
243
                xfs.nextents = le32 (icore.di_nextents);
 
244
                break;
 
245
        case XFS_DINODE_FMT_BTREE:
 
246
                ptr0 = xfs.ptr0;
 
247
                for (;;) {
 
248
                        xfs.daddr = fsb2daddr (le64(ptr0));
 
249
                        devread (xfs.daddr, 0,
 
250
                                 sizeof(xfs_btree_lblock_t), (char *)&h);
 
251
                        if (!h.bb_level) {
 
252
                                xfs.nextents = le16(h.bb_numrecs);
 
253
                                xfs.next = fsb2daddr (le64(h.bb_rightsib));
 
254
                                xfs.fpos = sizeof(xfs_btree_block_t);
 
255
                                return;
 
256
                        }
 
257
                        devread (xfs.daddr, xfs.btnode_ptr0_off,
 
258
                                 sizeof(xfs_bmbt_ptr_t), (char *)&ptr0);
 
259
                }
 
260
        }
 
261
}
 
262
 
 
263
static xad_t *
 
264
next_extent (void)
 
265
{
 
266
        static xad_t xad;
 
267
 
 
268
        switch (icore.di_format) {
 
269
        case XFS_DINODE_FMT_EXTENTS:
 
270
                if (xfs.nextents == 0)
 
271
                        return NULL;
 
272
                break;
 
273
        case XFS_DINODE_FMT_BTREE:
 
274
                if (xfs.nextents == 0) {
 
275
                        xfs_btree_lblock_t h;
 
276
                        if (xfs.next == 0)
 
277
                                return NULL;
 
278
                        xfs.daddr = xfs.next;
 
279
                        devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h);
 
280
                        xfs.nextents = le16(h.bb_numrecs);
 
281
                        xfs.next = fsb2daddr (le64(h.bb_rightsib));
 
282
                        xfs.fpos = sizeof(xfs_btree_block_t);
 
283
                }
 
284
                /* Yeah, I know that's slow, but I really don't care */
 
285
                devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf);
 
286
                xfs.xt = (xfs_bmbt_rec_32_t *)filebuf;
 
287
                xfs.fpos += sizeof(xfs_bmbt_rec_32_t);
 
288
        }
 
289
        xad.offset = xt_offset (xfs.xt);
 
290
        xad.start = xt_start (xfs.xt);
 
291
        xad.len = xt_len (xfs.xt);
 
292
        ++xfs.xt;
 
293
        --xfs.nextents;
 
294
 
 
295
        return &xad;
 
296
}
 
297
 
 
298
/*
 
299
 * Name lies - the function reads only first 100 bytes
 
300
 */
 
301
static void
 
302
xfs_dabread (void)
 
303
{
 
304
        xad_t *xad;
 
305
        xfs_fileoff_t offset;;
 
306
 
 
307
        init_extents ();
 
308
        while ((xad = next_extent ())) {
 
309
                offset = xad->offset;
 
310
                if (isinxt (xfs.dablk, offset, xad->len)) {
 
311
                        devread (fsb2daddr (xad->start + xfs.dablk - offset),
 
312
                                 0, 100, dirbuf);
 
313
                        break;
 
314
                }
 
315
        }
 
316
}
 
317
 
 
318
static inline xfs_ino_t
 
319
sf_ino (char *sfe, int namelen)
 
320
{
 
321
        void *p = sfe + namelen + 3;
 
322
 
 
323
        return (xfs.i8param == 0)
 
324
                ? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p);
 
325
}
 
326
 
 
327
static inline xfs_ino_t
 
328
sf_parent_ino (void)
 
329
{
 
330
        return (xfs.i8param == 0)
 
331
                ? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent))
 
332
                : le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent));
 
333
}
 
334
 
 
335
static inline int
 
336
roundup8 (int n)
 
337
{
 
338
        return ((n+7)&~7);
 
339
}
 
340
 
 
341
static char *
 
342
next_dentry (xfs_ino_t *ino)
 
343
{
 
344
        int namelen = 1;
 
345
        int toread;
 
346
        static char *usual[2];
 
347
        static xfs_dir2_sf_entry_t *sfe;
 
348
        char *name;
 
349
 
 
350
        if (!usual[0]) {
 
351
            usual[0] = strdup(".");
 
352
            usual[1] = strdup("..");
 
353
        }
 
354
        name = usual[0];
 
355
 
 
356
        if (xfs.dirpos >= xfs.dirmax) {
 
357
                if (xfs.forw == 0)
 
358
                        return NULL;
 
359
                xfs.dablk = xfs.forw;
 
360
                xfs_dabread ();
 
361
#define h       ((xfs_dir2_leaf_hdr_t *)dirbuf)
 
362
                xfs.dirmax = le16 (h->count) - le16 (h->stale);
 
363
                xfs.forw = le32 (h->info.forw);
 
364
#undef h
 
365
                xfs.dirpos = 0;
 
366
        }
 
367
 
 
368
        switch (icore.di_format) {
 
369
        case XFS_DINODE_FMT_LOCAL:
 
370
                switch (xfs.dirpos) {
 
371
                case -2:
 
372
                        *ino = 0;
 
373
                        break;
 
374
                case -1:
 
375
                        *ino = sf_parent_ino ();
 
376
                        ++name;
 
377
                        ++namelen;
 
378
                        sfe = (xfs_dir2_sf_entry_t *)
 
379
                                (inode->di_u.di_c
 
380
                                 + sizeof(xfs_dir2_sf_hdr_t)
 
381
                                 - xfs.i8param);
 
382
                        break;
 
383
                default:
 
384
                        namelen = sfe->namelen;
 
385
                        *ino = sf_ino ((char *)sfe, namelen);
 
386
                        name = (char *)sfe->name;
 
387
                        sfe = (xfs_dir2_sf_entry_t *)
 
388
                                  ((char *)sfe + namelen + 11 - xfs.i8param);
 
389
                }
 
390
                break;
 
391
        case XFS_DINODE_FMT_BTREE:
 
392
        case XFS_DINODE_FMT_EXTENTS:
 
393
#define dau     ((xfs_dir2_data_union_t *)dirbuf)
 
394
                for (;;) {
 
395
                        if (xfs.blkoff >= xfs.dirbsize) {
 
396
                                xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
 
397
                                filepos &= ~(xfs.dirbsize - 1);
 
398
                                filepos |= xfs.blkoff;
 
399
                        }
 
400
                        xfs_read (dirbuf, 4);
 
401
                        xfs.blkoff += 4;
 
402
                        if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) {
 
403
                                toread = roundup8 (le16(dau->unused.length)) - 4;
 
404
                                xfs.blkoff += toread;
 
405
                                filepos += toread;
 
406
                                continue;
 
407
                        }
 
408
                        break;
 
409
                }
 
410
                xfs_read ((char *)dirbuf + 4, 5);
 
411
                *ino = le64 (dau->entry.inumber);
 
412
                namelen = dau->entry.namelen;
 
413
#undef dau
 
414
                toread = roundup8 (namelen + 11) - 9;
 
415
                xfs_read (dirbuf, toread);
 
416
                name = (char *)dirbuf;
 
417
                xfs.blkoff += toread + 5;
 
418
        }
 
419
        ++xfs.dirpos;
 
420
        name[namelen] = 0;
 
421
 
 
422
        return name;
 
423
}
 
424
 
 
425
static char *
 
426
first_dentry (xfs_ino_t *ino)
 
427
{
 
428
        xfs.forw = 0;
 
429
        switch (icore.di_format) {
 
430
        case XFS_DINODE_FMT_LOCAL:
 
431
                xfs.dirmax = inode->di_u.di_dir2sf.hdr.count;
 
432
                xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4;
 
433
                xfs.dirpos = -2;
 
434
                break;
 
435
        case XFS_DINODE_FMT_EXTENTS:
 
436
        case XFS_DINODE_FMT_BTREE:
 
437
                filepos = 0;
 
438
                xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t));
 
439
                if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) {
 
440
#define tail            ((xfs_dir2_block_tail_t *)dirbuf)
 
441
                        filepos = xfs.dirbsize - sizeof(*tail);
 
442
                        xfs_read (dirbuf, sizeof(*tail));
 
443
                        xfs.dirmax = le32 (tail->count) - le32 (tail->stale);
 
444
#undef tail
 
445
                } else {
 
446
                        xfs.dablk = (1ULL << 35) >> xfs.blklog;
 
447
#define h               ((xfs_dir2_leaf_hdr_t *)dirbuf)
 
448
#define n               ((xfs_da_intnode_t *)dirbuf)
 
449
                        for (;;) {
 
450
                                xfs_dabread ();
 
451
                                if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC))
 
452
                                    || (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) {
 
453
                                        xfs.dirmax = le16 (h->count) - le16 (h->stale);
 
454
                                        xfs.forw = le32 (h->info.forw);
 
455
                                        break;
 
456
                                }
 
457
                                xfs.dablk = le32 (n->btree[0].before);
 
458
                        }
 
459
#undef n
 
460
#undef h
 
461
                }
 
462
                xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
 
463
                filepos = xfs.blkoff;
 
464
                xfs.dirpos = 0;
 
465
        }
 
466
        return next_dentry (ino);
 
467
}
 
468
 
 
469
int
 
470
xfs_mount (void)
 
471
{
 
472
        xfs_sb_t super;
 
473
 
 
474
        if (!devread (0, 0, sizeof(super), (char *)&super)
 
475
            || (le32(super.sb_magicnum) != XFS_SB_MAGIC)
 
476
            || ((le16(super.sb_versionnum)
 
477
                & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
 
478
                return 0;
 
479
        }
 
480
 
 
481
        xfs.bsize = le32 (super.sb_blocksize);
 
482
        xfs.blklog = super.sb_blocklog;
 
483
        xfs.bdlog = xfs.blklog - SECTOR_BITS;
 
484
        xfs.rootino = le64 (super.sb_rootino);
 
485
        xfs.isize = le16 (super.sb_inodesize);
 
486
        xfs.agblocks = le32 (super.sb_agblocks);
 
487
        xfs.dirbsize = xfs.bsize << super.sb_dirblklog;
 
488
 
 
489
        xfs.inopblog = super.sb_inopblog;
 
490
        xfs.agblklog = super.sb_agblklog;
 
491
        xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount));
 
492
 
 
493
        xfs.btnode_ptr0_off =
 
494
                ((xfs.bsize - sizeof(xfs_btree_block_t)) /
 
495
                (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
 
496
                 * sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t);
 
497
 
 
498
        return 1;
 
499
}
 
500
 
 
501
int
 
502
xfs_read (char *buf, int len)
 
503
{
 
504
        xad_t *xad;
 
505
        xfs_fileoff_t endofprev, endofcur, offset;
 
506
        xfs_filblks_t xadlen;
 
507
        int toread, startpos, endpos;
 
508
 
 
509
        if (icore.di_format == XFS_DINODE_FMT_LOCAL) {
 
510
                grub_memmove (buf, inode->di_u.di_c + filepos, len);
 
511
                filepos += len;
 
512
                return len;
 
513
        }
 
514
 
 
515
        startpos = filepos;
 
516
        endpos = filepos + len;
 
517
        endofprev = (xfs_fileoff_t)-1;
 
518
        init_extents ();
 
519
        while (len > 0 && (xad = next_extent ())) {
 
520
                offset = xad->offset;
 
521
                xadlen = xad->len;
 
522
                if (isinxt (filepos >> xfs.blklog, offset, xadlen)) {
 
523
                        endofcur = (offset + xadlen) << xfs.blklog;
 
524
                        toread = (endofcur >= endpos)
 
525
                                  ? len : (endofcur - filepos);
 
526
 
 
527
                        disk_read_func = disk_read_hook;
 
528
                        devread (fsb2daddr (xad->start),
 
529
                                 filepos - (offset << xfs.blklog), toread, buf);
 
530
                        disk_read_func = NULL;
 
531
 
 
532
                        buf += toread;
 
533
                        len -= toread;
 
534
                        filepos += toread;
 
535
                } else if (offset > endofprev) {
 
536
                        toread = ((offset << xfs.blklog) >= endpos)
 
537
                                  ? len : ((offset - endofprev) << xfs.blklog);
 
538
                        len -= toread;
 
539
                        filepos += toread;
 
540
                        for (; toread; toread--) {
 
541
                                *buf++ = 0;
 
542
                        }
 
543
                        continue;
 
544
                }
 
545
                endofprev = offset + xadlen;
 
546
        }
 
547
 
 
548
        return filepos - startpos;
 
549
}
 
550
 
 
551
int
 
552
xfs_dir (char *dirname)
 
553
{
 
554
        xfs_ino_t ino, parent_ino, new_ino;
 
555
        xfs_fsize_t di_size;
 
556
        int di_mode;
 
557
        int cmp, n, link_count;
 
558
        char linkbuf[xfs.bsize];
 
559
        char *rest, *name, ch;
 
560
 
 
561
        parent_ino = ino = xfs.rootino;
 
562
        link_count = 0;
 
563
        for (;;) {
 
564
                di_read (ino);
 
565
                di_size = le64 (icore.di_size);
 
566
                di_mode = le16 (icore.di_mode);
 
567
 
 
568
                if ((di_mode & IFMT) == IFLNK) {
 
569
                        if (++link_count > MAX_LINK_COUNT) {
 
570
                                errnum = ERR_SYMLINK_LOOP;
 
571
                                return 0;
 
572
                        }
 
573
                        if (di_size < xfs.bsize - 1) {
 
574
                                filepos = 0;
 
575
                                filemax = di_size;
 
576
                                n = xfs_read (linkbuf, filemax);
 
577
                        } else {
 
578
                                errnum = ERR_FILELENGTH;
 
579
                                return 0;
 
580
                        }
 
581
 
 
582
                        ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino;
 
583
                        while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++));
 
584
                        linkbuf[n] = 0;
 
585
                        dirname = linkbuf;
 
586
                        continue;
 
587
                }
 
588
 
 
589
                if (!*dirname || isspace (*dirname)) {
 
590
                        if ((di_mode & IFMT) != IFREG) {
 
591
                                errnum = ERR_BAD_FILETYPE;
 
592
                                return 0;
 
593
                        }
 
594
                        filepos = 0;
 
595
                        filemax = di_size;
 
596
                        return 1;
 
597
                }
 
598
 
 
599
                if ((di_mode & IFMT) != IFDIR) {
 
600
                        errnum = ERR_BAD_FILETYPE;
 
601
                        return 0;
 
602
                }
 
603
 
 
604
                for (; *dirname == '/'; dirname++);
 
605
 
 
606
                for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
 
607
                *rest = 0;
 
608
 
 
609
                name = first_dentry (&new_ino);
 
610
                for (;;) {
 
611
                        cmp = (!*dirname) ? -1 : substring (dirname, name);
 
612
#ifndef STAGE1_5
 
613
                        if (print_possibilities && ch != '/' && cmp <= 0) {
 
614
                                if (print_possibilities > 0)
 
615
                                        print_possibilities = -print_possibilities;
 
616
                                print_a_completion (name);
 
617
                        } else
 
618
#endif
 
619
                        if (cmp == 0) {
 
620
                                parent_ino = ino;
 
621
                                if (new_ino)
 
622
                                        ino = new_ino;
 
623
                                *(dirname = rest) = ch;
 
624
                                break;
 
625
                        }
 
626
                        name = next_dentry (&new_ino);
 
627
                        if (name == NULL) {
 
628
                                if (print_possibilities < 0)
 
629
                                        return 1;
 
630
 
 
631
                                errnum = ERR_FILE_NOT_FOUND;
 
632
                                *rest = ch;
 
633
                                return 0;
 
634
                        }
 
635
                }
 
636
        }
 
637
}
 
638
 
 
639
#endif /* FSYS_XFS */