summaryrefslogtreecommitdiffstats
path: root/fs/ufs/ufs_namei.c
blob: 4ae2587383979ec38ceab1299cce7a05345c3224 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 *  linux/fs/ufs/ufs_namei.c
 *
 * Copyright (C) 1996
 * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
 * Laboratory for Computer Science Research Computing Facility
 * Rutgers, The State University of New Jersey
 *
 * $Id: ufs_namei.c,v 1.2 1997/07/20 15:00:17 ralf Exp $
 *
 */

#include <linux/fs.h>
#include <linux/ufs_fs.h>

#include <linux/string.h>

/*
 * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
 * stolen from ext2fs
 */
static int ufs_match (int len, const char * const name, struct ufs_direct * d)
{
	if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */
		return 0;
	/*
	 * "" means "." ---> so paths like "/usr/lib//libc.a" work
	 */
	if (!len && (ufs_swab16(d->d_namlen) == 1) && (d->d_name[0] == '.') &&
	   (d->d_name[1] == '\0'))
		return 1;
	if (len != ufs_swab16(d->d_namlen))
		return 0;
	return !memcmp(name, d->d_name, len);
}

/* XXX - this is a mess, especially for endianity */
int ufs_lookup (struct inode * dir, struct qstr *qname,
	        struct inode ** result)
{
	unsigned long int lfragno, fragno;
	struct buffer_head * bh;
	struct ufs_direct * d;
	const char *name = qname->name;
	int len = qname->len;

	if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
		printk("Passed name: %s\nPassed length: %d\n", name, len);

	/*
	 * Touching /xyzzy in a filesystem toggles debugging messages.
	 */
	if ((len == 5) && !(memcmp(name, "xyzzy", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
	        printk("UFS debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
	               "on": "off");
		iput(dir);
	        return(-ENOENT);
	}

	/*
	 * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c.
	 */
	if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
	        printk("UFS inode debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
	               "on": "off");
		iput(dir);
	        return(-ENOENT);
	}

	if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
	        printk("UFS namei debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
	               "on": "off");
		iput(dir);
	        return(-ENOENT);
	}

	if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
	    (dir->i_ino == UFS_ROOTINO)) {
	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
	        printk("UFS symlink debugging %s\n",
	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
	               "on": "off");
		iput(dir);
	        return(-ENOENT);
	}

	if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
	        printk("ufs_lookup: called for ino %lu  name %s\n",
	               dir->i_ino, name);
	}

	/* XXX - do I want i_blocks in 512-blocks or 1024-blocks? */
	for (lfragno = 0; lfragno < (dir->i_blocks)>>1; lfragno++) {
	        fragno = ufs_bmap(dir, lfragno);
	        /* XXX - ufs_bmap() call needs error checking */
	        /* XXX - s_blocksize is actually the UFS frag size */
	        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                printk("ufs_lookup: ino %lu lfragno %lu  fragno %lu\n",
	                       dir->i_ino, lfragno, fragno);
	        }
	        if (fragno == 0) {
	                /* XXX - bug bug bug */
			iput(dir);
	                return(-ENOENT);
	        }
	        bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
	        if (bh == NULL) {
	                printk("ufs_lookup: bread failed: ino %lu, lfragno %lu",
	                       dir->i_ino, lfragno);
			iput(dir);
	                return(-EIO);
	        }
	        d = (struct ufs_direct *)(bh->b_data);
	        while (((char *)d - bh->b_data + ufs_swab16(d->d_reclen)) <=
	               dir->i_sb->s_blocksize) {
	                /* XXX - skip block if d_reclen or d_namlen is 0 */
	                if ((ufs_swab16(d->d_reclen) == 0) || (ufs_swab16(d->d_namlen) == 0)) {
	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                                printk("ufs_lookup: skipped space in directory, ino %lu\n",
	                                       dir->i_ino);
	                        }
	                        break;
	                }
	                if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                        printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  "
				       "d_reclen %u  d_namlen %u  d_name `%s'\n",
	                               lfragno, (unsigned int)((unsigned long)d),
				       ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen),
				       ufs_swab16(d->d_namlen), d->d_name);
	                }
	                if ((ufs_swab16(d->d_namlen) == len) &&
	                    /* XXX - don't use strncmp() - see ext2fs */
	                    (ufs_match(len, name, d))) {
	                        /* We have a match */
	                        *result = iget(dir->i_sb, ufs_swab32(d->d_ino));
	                        brelse(bh);
				iput(dir);
	                        return(0);
	                } else {
	                        /* XXX - bounds checking */
	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
	                                printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n",
	                                       name, len, d->d_name, ufs_swab16(d->d_namlen));
	                        }
	                }
	                d = (struct ufs_direct *)((char *)d + ufs_swab16(d->d_reclen));
	        }
	        brelse(bh);
	}
	iput(dir);
	return(-ENOENT);
}