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