11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/fs/adfs/dir_fplus.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1997-1999 Russell King
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/buffer_head.h>
112f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales#include <linux/slab.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "adfs.h"
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dir_fplus.h"
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct adfs_bigdirheader *h;
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct adfs_bigdirtail *t;
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long block;
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int blk, size;
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, ret = -EIO;
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->nr_buffers = 0;
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	/* start off using fixed bh set - only alloc for big dirs */
272f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	dir->bh_fplus = &dir->bh[0];
282f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	block = __adfs_block_map(sb, id, 0);
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!block) {
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		adfs_error(sb, "dir object %X has a hole at offset 0", id);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
352f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	dir->bh_fplus[0] = sb_bread(sb, block);
362f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	if (!dir->bh_fplus[0])
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->nr_buffers += 1;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
402f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	h = (struct adfs_bigdirheader *)dir->bh_fplus[0]->b_data;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = le32_to_cpu(h->bigdirsize);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size != sz) {
432f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		printk(KERN_WARNING "adfs: adfs_fplus_read:"
442f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales					" directory header size %X\n"
452f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales					" does not match directory size %X\n",
462f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales					size, sz);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    h->bigdirversion[2] != 0 || size & 2047 ||
512f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	    h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
522f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		printk(KERN_WARNING "adfs: dir object %X has"
532f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales					" malformed dir header\n", id);
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
552f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	}
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size >>= sb->s_blocksize_bits;
58e2ffcf5c7ee7eb979b1f2375404668a2f5076c1bFabian Frederick	if (size > ARRAY_SIZE(dir->bh)) {
592f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		/* this directory is too big for fixed bh set, must allocate */
602f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		struct buffer_head **bh_fplus =
61b16214d43d9060722360360f741416660b54c4f5Fabian Frederick			kcalloc(size, sizeof(struct buffer_head *),
622f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales				GFP_KERNEL);
632f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		if (!bh_fplus) {
642f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			adfs_error(sb, "not enough memory for"
652f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales					" dir object %X (%d blocks)", id, size);
662f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			goto out;
672f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		}
682f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		dir->bh_fplus = bh_fplus;
692f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		/* copy over the pointer to the block that we've already read */
702f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		dir->bh_fplus[0] = dir->bh[0];
712f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	}
722f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (blk = 1; blk < size; blk++) {
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		block = __adfs_block_map(sb, id, blk);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!block) {
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			adfs_error(sb, "dir object %X has a hole at offset %d", id, blk);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
802f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		dir->bh_fplus[blk] = sb_bread(sb, block);
812f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		if (!dir->bh_fplus[blk]) {
8219bdd41a57e1418b8661148125e9b6d99f468c1bJoe Perches			adfs_error(sb,	"dir object %x failed read for offset %d, mapped block %lX",
8319bdd41a57e1418b8661148125e9b6d99f468c1bJoe Perches				   id, blk, block);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
852f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		}
862f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
872f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		dir->nr_buffers += 1;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
902f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	t = (struct adfs_bigdirtail *)
912f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		(dir->bh_fplus[size - 1]->b_data + (sb->s_blocksize - 8));
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    t->bigdirendmasseq != h->startmasseq ||
952f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	    t->reserved[0] != 0 || t->reserved[1] != 0) {
962f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		printk(KERN_WARNING "adfs: dir object %X has "
972f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales					"malformed dir end\n", id);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
992f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->parent_id = le32_to_cpu(h->bigdirparent);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->sb = sb;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1042f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1062f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	if (dir->bh_fplus) {
1072f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		for (i = 0; i < dir->nr_buffers; i++)
1082f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			brelse(dir->bh_fplus[i]);
1092f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
1102f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		if (&dir->bh[0] != dir->bh_fplus)
1112f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			kfree(dir->bh_fplus);
1122f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
1132f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		dir->bh_fplus = NULL;
1142f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	}
1152f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
1162f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	dir->nr_buffers = 0;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->sb = NULL;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1242f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	struct adfs_bigdirheader *h =
1252f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		(struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = -ENOENT;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fpos <= le32_to_cpu(h->bigdirentries)) {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dir->pos = fpos;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct super_block *sb = dir->sb;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int buffer, partial, remainder;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer = offset >> sb->s_blocksize_bits;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset &= sb->s_blocksize - 1;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	partial = sb->s_blocksize - offset;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (partial >= len)
1482f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		memcpy(to, dir->bh_fplus[buffer]->b_data + offset, len);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *c = (char *)to;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remainder = len - partial;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1542f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		memcpy(c,
1552f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			dir->bh_fplus[buffer]->b_data + offset,
1562f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			partial);
1572f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
1582f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		memcpy(c + partial,
1592f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			dir->bh_fplus[buffer + 1]->b_data,
1602f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			remainder);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1672f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	struct adfs_bigdirheader *h =
1682f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		(struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct adfs_bigdirentry bde;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int offset;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, ret = -ENOENT;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dir->pos >= le32_to_cpu(h->bigdirentries))
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = offsetof(struct adfs_bigdirheader, bigdirname);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset += dir->pos * sizeof(struct adfs_bigdirentry);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir_memcpy(dir, offset, &bde, sizeof(struct adfs_bigdirentry));
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->loadaddr = le32_to_cpu(bde.bigdirload);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->execaddr = le32_to_cpu(bde.bigdirexec);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->size     = le32_to_cpu(bde.bigdirlen);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->file_id  = le32_to_cpu(bde.bigdirindaddr);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->attr     = le32_to_cpu(bde.bigdirattr);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = offsetof(struct adfs_bigdirheader, bigdirname);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset += le32_to_cpu(h->bigdirentries) * sizeof(struct adfs_bigdirentry);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset += le32_to_cpu(bde.bigdirobnameptr);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir_memcpy(dir, offset, obj->name, obj->name_len);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < obj->name_len; i++)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (obj->name[i] == '/')
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			obj->name[i] = '.';
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
199da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	obj->filetype = -1;
200da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales
201da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	/*
202da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	 * object is a file and is filetyped and timestamped?
203da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	 * RISC OS 12-bit filetype is stored in load_address[19:8]
204da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	 */
205da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&
206da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales		(0xfff00000 == (0xfff00000 & obj->loadaddr))) {
207da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales		obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);
208da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales
209da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales		/* optionally append the ,xyz hex filetype suffix */
210da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales		if (ADFS_SB(dir->sb)->s_ftsuffix)
211da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales			obj->name_len +=
212da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales				append_filetype_suffix(
213da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales					&obj->name[obj->name_len],
214da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales					obj->filetype);
215da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales	}
216da23ef0549d4205ca9b576cf6cce9a80d0c3e43aStuart Swales
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->pos += 1;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Virostatic int
224ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viroadfs_fplus_sync(struct adfs_dir *dir)
225ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro{
226ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro	int err = 0;
227ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro	int i;
228ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro
229ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro	for (i = dir->nr_buffers - 1; i >= 0; i--) {
2302f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		struct buffer_head *bh = dir->bh_fplus[i];
231ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro		sync_dirty_buffer(bh);
232ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro		if (buffer_req(bh) && !buffer_uptodate(bh))
233ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro			err = -EIO;
234ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro	}
235ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro
236ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro	return err;
237ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro}
238ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadfs_fplus_free(struct adfs_dir *dir)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2442f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	if (dir->bh_fplus) {
2452f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		for (i = 0; i < dir->nr_buffers; i++)
2462f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			brelse(dir->bh_fplus[i]);
2472f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
2482f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		if (&dir->bh[0] != dir->bh_fplus)
2492f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales			kfree(dir->bh_fplus);
2502f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
2512f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales		dir->bh_fplus = NULL;
2522f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	}
2532f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales
2542f09719af705db56032ae480a2d9c32c2a3fcbd3Stuart Swales	dir->nr_buffers = 0;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dir->sb = NULL;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct adfs_dir_ops adfs_fplus_dir_ops = {
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read		= adfs_fplus_read,
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setpos		= adfs_fplus_setpos,
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.getnext	= adfs_fplus_getnext,
262ffdc9064f8b4fa9db37a7d5180f41cce2ea2b7adAl Viro	.sync		= adfs_fplus_sync,
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free		= adfs_fplus_free
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
265