minor fixups to restart stuff; version 4.1 for distrib
[unix-history] / usr / src / sys / ufs / ffs / ufs_lookup.c
CommitLineData
15f789ea 1/* ufs_lookup.c 4.1 %G% */
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"
10
11/*
12 * Convert a pathname into a pointer to
13 * an inode. Note that the inode is locked.
14 *
15 * func = function called to get next char of name
16 * &uchar if name is in user space
17 * &schar if name is in system space
18 * flag = 0 if name is sought
19 * 1 if name is to be created
20 * 2 if name is to be deleted
21 */
22struct inode *
23namei(func, flag)
24int (*func)();
25{
26 register struct inode *dp;
27 register c;
28 register char *cp;
29 struct buf *bp;
cee4ba58 30 register struct direct *ep;
10873320
BJ
31 int i;
32 dev_t d;
33 off_t eo;
34
35 /*
36 * If name starts with '/' start from
37 * root; otherwise start from current dir.
38 */
39
40 dp = u.u_cdir;
41 if((c=(*func)()) == '/')
42 if ((dp = u.u_rdir) == NULL)
43 dp = rootdir;
cee4ba58 44 (void) iget(dp->i_dev, dp->i_number);
10873320
BJ
45 while(c == '/')
46 c = (*func)();
47 if(c == '\0' && flag != 0)
48 u.u_error = ENOENT;
49
50cloop:
51 /*
52 * Here dp contains pointer
53 * to last component matched.
54 */
55
56 if(u.u_error)
57 goto out;
58 if(c == '\0')
59 return(dp);
60
61 /*
62 * If there is another component,
63 * Gather up name into
64 * users' dir buffer.
65 */
66
67 cp = &u.u_dbuf[0];
68 while (c != '/' && c != '\0' && u.u_error == 0 ) {
69 if (mpxip!=NULL && c=='!')
70 break;
cee4ba58 71 if (cp < &u.u_dbuf[DIRSIZ])
10873320
BJ
72 *cp++ = c;
73 c = (*func)();
74 }
75 while(cp < &u.u_dbuf[DIRSIZ])
76 *cp++ = '\0';
77 while(c == '/')
78 c = (*func)();
79 if (c == '!' && mpxip != NULL) {
80 iput(dp);
81 plock(mpxip);
82 mpxip->i_count++;
83 return(mpxip);
84 }
85
86seloop:
87 /*
88 * dp must be a directory and
89 * must have X permission.
90 */
91
92 if((dp->i_mode&IFMT) != IFDIR)
93 u.u_error = ENOTDIR;
cee4ba58 94 (void) access(dp, IEXEC);
10873320
BJ
95 if(u.u_error)
96 goto out;
97
98 /*
99 * set up to search a directory
100 */
101 u.u_offset = 0;
102 u.u_segflg = 1;
103 eo = 0;
104 bp = NULL;
105
106eloop:
107
108 /*
109 * If at the end of the directory,
110 * the search failed. Report what
111 * is appropriate as per flag.
112 */
113
114 if(u.u_offset >= dp->i_size) {
115 if(bp != NULL)
116 brelse(bp);
7f606d19 117 if(flag==1 && c=='\0' && dp->i_nlink) {
10873320
BJ
118 if(access(dp, IWRITE))
119 goto out;
120 u.u_pdir = dp;
121 if(eo)
122 u.u_offset = eo-sizeof(struct direct);
123 else
124 dp->i_flag |= IUPD|ICHG;
125 return(NULL);
126 }
127 u.u_error = ENOENT;
128 goto out;
129 }
130
131 /*
132 * If offset is on a block boundary,
133 * read the next directory block.
134 * Release previous if it exists.
135 */
136
137 if((u.u_offset&BMASK) == 0) {
138 if(bp != NULL)
139 brelse(bp);
140 bp = bread(dp->i_dev,
141 bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
142 if (bp->b_flags & B_ERROR) {
143 brelse(bp);
144 goto out;
145 }
cee4ba58
BJ
146 ep = (struct direct *)bp->b_un.b_addr;
147 } else
148 ep++;
10873320
BJ
149
150 /*
151 * Note first empty directory slot
152 * in eo for possible creat.
153 * String compare the directory entry
154 * and the current component.
155 * If they do not match, go back to eloop.
156 */
157
10873320 158 u.u_offset += sizeof(struct direct);
cee4ba58 159 if(ep->d_ino == 0) {
10873320
BJ
160 if(eo == 0)
161 eo = u.u_offset;
162 goto eloop;
163 }
164 for(i=0; i<DIRSIZ; i++) {
cee4ba58 165 if(u.u_dbuf[i] != ep->d_name[i])
10873320
BJ
166 goto eloop;
167 if(u.u_dbuf[i] == 0)
168 break;
169 }
170
171 /*
172 * Here a component matched in a directory.
173 * If there is more pathname, go back to
174 * cloop, otherwise return.
175 */
cee4ba58 176 bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
10873320
BJ
177 if(bp != NULL)
178 brelse(bp);
179 if(flag==2 && c=='\0') {
180 if(access(dp, IWRITE))
181 goto out;
182 return(dp);
183 }
184 d = dp->i_dev;
185 if(u.u_dent.d_ino == ROOTINO)
186 if(dp->i_number == ROOTINO)
187 if(u.u_dent.d_name[1] == '.')
188 for(i=1; i<NMOUNT; i++)
189 if(mount[i].m_bufp != NULL)
190 if(mount[i].m_dev == d) {
191 iput(dp);
192 dp = mount[i].m_inodp;
193 dp->i_count++;
194 plock(dp);
195 goto seloop;
196 }
197 iput(dp);
198 dp = iget(d, u.u_dent.d_ino);
199 if(dp == NULL)
200 return(NULL);
201 goto cloop;
202
203out:
204 iput(dp);
205 return(NULL);
206}
207
208/*
209 * Return the next character from the
210 * kernel string pointed at by dirp.
211 */
212schar()
213{
214
215 return(*u.u_dirp++ & 0377);
216}
217
218/*
219 * Return the next character from the
220 * user string pointed at by dirp.
221 */
222uchar()
223{
224 register c;
225
226 c = fubyte(u.u_dirp++);
227 if(c == -1)
228 u.u_error = EFAULT;
229 return(c);
230}