dmr's nami
[unix-history] / usr / src / sys / kern / vfs_lookup.c
CommitLineData
f5039631 1/* vfs_lookup.c 4.9 82/02/26 */
10873320
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/inode.h"
6#include "../h/mount.h"
7#include "../h/dir.h"
8#include "../h/user.h"
9#include "../h/buf.h"
3cbbbe12 10#include "../h/conf.h"
10873320
BJ
11
12/*
13 * Convert a pathname into a pointer to
f5039631 14 * a locked inode.
10873320
BJ
15 *
16 * func = function called to get next char of name
17 * &uchar if name is in user space
18 * &schar if name is in system space
19 * flag = 0 if name is sought
20 * 1 if name is to be created
21 * 2 if name is to be deleted
f5039631 22 * follow = 1 if links are to be followed at the end of the name
10873320
BJ
23 */
24struct inode *
f5039631
BJ
25namei(func, flag, follow)
26 int (*func)(), flag, follow;
10873320
BJ
27{
28 register struct inode *dp;
10873320 29 register char *cp;
f5039631 30 register struct buf *bp, *nbp;
cee4ba58 31 register struct direct *ep;
f5039631 32 int i, nlink;
10873320 33 dev_t d;
f5039631 34 ino_t ino;
10873320
BJ
35 off_t eo;
36
f5039631
BJ
37 /*
38 * allocate name buffer; copy name
39 */
40 nbp = geteblk();
41 nlink = 0;
42 for (i=0, cp = nbp->b_un.b_addr; *cp = (*func)(); i++) {
43 if (*cp++&0200 && flag==1 || cp >= nbp->b_un.b_addr+BSIZE) {
44 u.u_error = ENOENT;
45 break;
46 }
47 }
48 if (u.u_error) {
49 dp = NULL;
50 goto out1;
51 }
52 cp = nbp->b_un.b_addr;
10873320
BJ
53 /*
54 * If name starts with '/' start from
55 * root; otherwise start from current dir.
56 */
10873320 57 dp = u.u_cdir;
f5039631
BJ
58 if (*cp == '/') {
59 while (*cp == '/')
60 cp++;
10873320
BJ
61 if ((dp = u.u_rdir) == NULL)
62 dp = rootdir;
10873320 63 }
f5039631
BJ
64 ilock(dp);
65 dp->i_count++;
10873320 66
10873320
BJ
67 /*
68 * dp must be a directory and
69 * must have X permission.
f5039631 70 * cp is a path name relative to that directory.
10873320
BJ
71 */
72
f5039631 73dirloop:
aa064819 74 if ((dp->i_mode&IFMT) != IFDIR)
10873320 75 u.u_error = ENOTDIR;
cee4ba58 76 (void) access(dp, IEXEC);
f5039631
BJ
77 for (i=0; *cp!='\0' && *cp!='/'; i++) {
78 if (i >= DIRSIZ) {
79 u.u_error = ENOENT;
80 break;
81 }
82 u.u_dbuf[i] = *cp++;
83 }
aa064819 84 if (u.u_error)
10873320 85 goto out;
f5039631
BJ
86 while (i < DIRSIZ)
87 u.u_dbuf[i++] = '\0';
88 if (u.u_dbuf[0] == '\0') { /* null name, e.g. "/" or "" */
89 if (flag) {
90 u.u_error = ENOENT;
91 goto out;
92 }
93 goto out1;
94 }
10873320 95 u.u_segflg = 1;
f5039631 96 eo = -1;
10873320
BJ
97 bp = NULL;
98
f5039631
BJ
99 for (u.u_offset=0; u.u_offset < dp->i_size;
100 u.u_offset += sizeof(struct direct), ep++) {
101 /*
102 * If offset is on a block boundary,
103 * read the next directory block.
104 * Release previous if it exists.
105 */
106 if ((u.u_offset&BMASK) == 0) {
107 if (bp != NULL)
108 brelse(bp);
109 bp = bread(dp->i_dev,
110 bmap(dp,(daddr_t)(u.u_offset>>BSHIFT), B_READ));
111 if (bp->b_flags & B_ERROR) {
112 brelse(bp);
113 goto out;
114 }
115 ep = (struct direct *)bp->b_un.b_addr;
116 }
117 /*
118 * Note first empty directory slot
119 * in eo for possible creat.
120 * String compare the directory entry
121 * and the current component.
122 */
123 if (ep->d_ino == 0) {
124 if (eo < 0)
125 eo = u.u_offset;
126 continue;
127 }
128 if (strncmp(u.u_dbuf, ep->d_name, DIRSIZ) != 0)
129 continue;
130 /*
131 * Here a component matched in a directory.
132 * If there is more pathname, go back to
133 * dirloop, otherwise return.
134 */
135 bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
136 brelse(bp);
137 if (flag==2 && *cp=='\0') {
aa064819 138 if (access(dp, IWRITE))
10873320 139 goto out;
f5039631
BJ
140 /* should fix unlink */
141 u.u_offset += sizeof(struct direct);
142 goto out1;
10873320 143 }
f5039631
BJ
144 /*
145 * Special handling for ".."
146 */
147 if (u.u_dent.d_name[0]=='.' && u.u_dent.d_name[1]=='.' &&
148 u.u_dent.d_name[2]=='\0') {
149 if (dp == u.u_rdir)
150 u.u_dent.d_ino = dp->i_number;
151 else if (u.u_dent.d_ino==ROOTINO &&
152 dp->i_number == ROOTINO) {
153 for(i=1; i<NMOUNT; i++)
154 if (mount[i].m_bufp != NULL &&
155 mount[i].m_dev == dp->i_dev) {
156 iput(dp);
157 dp = mount[i].m_inodp;
158 ilock(dp);
159 dp->i_count++;
160 cp -= 2; /* back over .. */
161 goto dirloop;
162 }
163 }
164 }
165 d = dp->i_dev;
166 ino = dp->i_number;
167 iput(dp);
168 dp = iget(d, u.u_dent.d_ino);
169 if (dp == NULL)
170 goto out1;
171 /*
172 * Check for symbolic link
173 */
174 if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
175 char *ocp;
10873320 176
f5039631
BJ
177 ocp = cp;
178 while (*cp++)
179 ;
180 if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
181 u.u_error = ELOOP;
182 goto out;
183 }
184 bcopy(ocp, nbp->b_un.b_addr+dp->i_size, cp-ocp);
185 bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
186 if (bp->b_flags & B_ERROR) {
187 brelse(bp);
188 goto out;
189 }
190 bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
10873320 191 brelse(bp);
f5039631
BJ
192 cp = nbp->b_un.b_addr;
193 iput(dp);
194 if (*cp == '/') {
195 while (*cp == '/')
196 cp++;
197 if ((dp = u.u_rdir) == NULL)
198 dp = rootdir;
199 ilock(dp);
200 dp->i_count++;
201 } else {
202 dp = iget(d, ino); /* retrieve directory */
203 if (dp == NULL)
204 goto out1;
205 }
206 goto dirloop;
10873320 207 }
f5039631
BJ
208 if (*cp == '/') {
209 while (*cp == '/')
210 cp++;
211 goto dirloop;
212 }
213 goto out1;
10873320 214 }
10873320 215 /*
f5039631 216 * Search failed.
10873320 217 */
aa064819 218 if (bp != NULL)
10873320 219 brelse(bp);
f5039631 220 if (flag==1 && *cp=='\0' && dp->i_nlink) {
aa064819 221 if (access(dp, IWRITE))
10873320 222 goto out;
f5039631
BJ
223 u.u_pdir = dp;
224 if (eo>=0)
225 u.u_offset = eo;
226 dp->i_flag |= IUPD|ICHG;
227 dp = NULL;
228 goto out1;
10873320 229 }
f5039631 230 u.u_error = ENOENT;
10873320
BJ
231out:
232 iput(dp);
f5039631
BJ
233 dp = NULL;
234out1:
235 brelse(nbp);
236 return (dp);
10873320
BJ
237}
238
239/*
240 * Return the next character from the
241 * kernel string pointed at by dirp.
242 */
243schar()
244{
245
f5039631 246 return (*u.u_dirp++ & 0377);
10873320
BJ
247}
248
249/*
250 * Return the next character from the
251 * user string pointed at by dirp.
252 */
253uchar()
254{
255 register c;
256
257 c = fubyte(u.u_dirp++);
f5039631 258 if (c == -1) {
10873320 259 u.u_error = EFAULT;
f5039631
BJ
260 c = 0;
261 }
262 return (c);
263}
264
265#ifndef vax
266strncmp(s1, s2, len)
267 register char *s1, *s2;
268 register len;
269{
270
271 do {
272 if (*s1 != *s2++)
273 return (1);
274 if (*s1++ == '\0')
275 return (0);
276 } while (--len);
277 return (0);
10873320 278}
f5039631 279#endif