1 /* ufs_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 */ 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 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 74 dirloop: 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; 238 out: 239 iput(dp); 240 dp = NULL; 241 out1: 242 brelse(nbp); 243 return (dp); 244 } 245 246 /* 247 * Return the next character from the 248 * kernel string pointed at by dirp. 249 */ 250 schar() 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 */ 260 uchar() 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 273 strncmp(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 287