symbolic links
[unix-history] / usr / src / sys / kern / vfs_lookup.c
... / ...
CommitLineData
1/* vfs_lookup.c 4.10 82/02/27 */
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"
10#include "../h/conf.h"
11
12/*
13 * Convert a pathname into a pointer to
14 * a locked inode.
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
22 * follow = 1 if links are to be followed at the end of the name
23 */
24struct inode *
25namei(func, flag, follow)
26 int (*func)(), flag, follow;
27{
28 register struct inode *dp;
29 register char *cp;
30 register struct buf *bp, *nbp;
31 register struct direct *ep;
32 struct inode *pdp;
33 int i, nlink;
34 dev_t d;
35 ino_t ino;
36 off_t eo;
37
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;
54 /*
55 * If name starts with '/' start from
56 * root; otherwise start from current dir.
57 */
58 dp = u.u_cdir;
59 if (*cp == '/') {
60 while (*cp == '/')
61 cp++;
62 if ((dp = u.u_rdir) == NULL)
63 dp = rootdir;
64 }
65 ilock(dp);
66 dp->i_count++;
67
68 /*
69 * dp must be a directory and
70 * must have X permission.
71 * cp is a path name relative to that directory.
72 */
73
74dirloop:
75 if ((dp->i_mode&IFMT) != IFDIR)
76 u.u_error = ENOTDIR;
77 (void) access(dp, IEXEC);
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 }
85 if (u.u_error)
86 goto out;
87 u.u_pdir = dp;
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 }
97 u.u_segflg = 1;
98 eo = -1;
99 bp = NULL;
100
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') {
140 if (access(dp, IWRITE))
141 goto out;
142 /* should fix unlink */
143 u.u_offset += sizeof(struct direct);
144 goto out1;
145 }
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;
169 irele(dp);
170 pdp = dp;
171 dp = iget(d, u.u_dent.d_ino);
172 if (dp == NULL) {
173 iput(pdp);
174 goto out1;
175 }
176 /*
177 * Check for symbolic link
178 */
179 if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp=='/')) {
180 char *ocp;
181
182 ocp = cp;
183 while (*cp++)
184 ;
185 if (dp->i_size + (cp-ocp) >= BSIZE-1 || ++nlink>8) {
186 u.u_error = ELOOP;
187 iput(pdp);
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);
194 iput(pdp);
195 goto out;
196 }
197 bcopy(bp->b_un.b_addr, nbp->b_un.b_addr, dp->i_size);
198 brelse(bp);
199 cp = nbp->b_un.b_addr;
200 iput(dp);
201 if (*cp == '/') {
202 iput(pdp);
203 while (*cp == '/')
204 cp++;
205 if ((dp = u.u_rdir) == NULL)
206 dp = rootdir;
207 ilock(dp);
208 dp->i_count++;
209 } else {
210 dp = pdp;
211 ilock(dp);
212 }
213 goto dirloop;
214 }
215 iput(pdp);
216 if (*cp == '/') {
217 while (*cp == '/')
218 cp++;
219 goto dirloop;
220 }
221 goto out1;
222 }
223 /*
224 * Search failed.
225 */
226 if (bp != NULL)
227 brelse(bp);
228 if (flag==1 && *cp=='\0' && dp->i_nlink) {
229 if (access(dp, IWRITE))
230 goto out;
231 if (eo>=0)
232 u.u_offset = eo;
233 dp->i_flag |= IUPD|ICHG;
234 dp = NULL;
235 goto out1;
236 }
237 u.u_error = ENOENT;
238out:
239 iput(dp);
240 dp = NULL;
241out1:
242 brelse(nbp);
243 return (dp);
244}
245
246/*
247 * Return the next character from the
248 * kernel string pointed at by dirp.
249 */
250schar()
251{
252
253 return (*u.u_dirp++ & 0377);
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++);
265 if (c == -1) {
266 u.u_error = EFAULT;
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);
285}
286#endif