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