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