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