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