first working version (created and removed a file!)
[unix-history] / usr / src / sys / ufs / ffs / ufs_lookup.c
CommitLineData
6bd0bb92 1/* ufs_lookup.c 4.19 82/07/25 */
10873320
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/inode.h"
6459ebe0 6#include "../h/fs.h"
10873320
BJ
7#include "../h/mount.h"
8#include "../h/dir.h"
9#include "../h/user.h"
10#include "../h/buf.h"
3cbbbe12 11#include "../h/conf.h"
10873320 12
a0aead5a
BJ
13#ifdef EFS
14extern int efs_major;
15#endif
16
6bd0bb92
BJ
17struct buf *batoffset();
18int dirchk = 1;
10873320 19/*
6bd0bb92
BJ
20 * Convert a pathname into a pointer to a locked inode,
21 * with side effects usable in creating and removing files.
22 * This is a very central and rather complicated routine.
23 *
24 * The func argument gives the routine which returns successive
25 * characters of the name to be translated. The flag
26 * argument is (0, 1, 2) depending on whether the name is to be
27 * (looked up, created, deleted). The follow argument is 1 when
28 * symbolic links are to be followed when they occur at the end of
29 * the name translation process.
10873320 30 *
6bd0bb92
BJ
31 * Overall outline:
32 *
33 * copy in name
34 * get starting directory
35 * dirloop:
36 * check accessibility of directory
37 * dirloop2:
38 * copy next component of name to u.u_dent
39 * handle degenerate case where name is null string
40 * search for name in directory, to found or notfound
41 * notfound:
42 * if creating, return locked inode, leaving information on avail. slots
43 * else return error
44 * found:
45 * if at end of path and deleting, return information to allow delete
46 * if .. and on mounted filesys, look in mount table for parent
47 * if symbolic link, massage name in buffer and continue at dirloop
48 * if more components of name, do next level at dirloop
49 * return the answer as locked inode
10873320
BJ
50 */
51struct inode *
f5039631
BJ
52namei(func, flag, follow)
53 int (*func)(), flag, follow;
10873320 54{
6bd0bb92
BJ
55 register char *cp; /* pointer into pathname argument */
56/* these variables refer to things which must be freed or unlocked */
57 register struct inode *dp = 0; /* the directory we are searching */
58 register struct fs *fs; /* file system that directory is in */
59 register struct buf *bp = 0; /* a buffer of directory entries */
60 register struct direct *ep; /* the current directory entry */
61 int entryoffsetinblock; /* offset of ep in bp's buffer */
62 register struct buf *nbp; /* buffer storing path name argument */
63/* these variables hold information about the search for a slot */
64 enum {NONE, COMPACT, FOUND} slotstatus;
65 int slotoffset = -1; /* offset of area with free space */
66 int slotsize; /* size of area at slotoffset */
67 int slotfreespace; /* amount of space free in slot */
68 int slotneeded; /* size of the entry we're seeking */
69/* */
70 int dirsize;
71 int prevoff; /* u.u_offset of previous entry */
72 int nlink = 0; /* number of symbolic links taken */
73 struct inode *pdp; /* saved dp during symlink work */
74 int i;
10873320 75
f5039631 76 /*
6bd0bb92
BJ
77 * Get a buffer for the name to be translated, and copy the
78 * name into the buffer.
f5039631 79 */
6459ebe0 80 nbp = geteblk(MAXPATHLEN);
6bd0bb92
BJ
81 for (cp = nbp->b_un.b_addr; *cp = (*func)(); ) {
82 if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != 2) {
a21ae242 83 u.u_error = EPERM;
6bd0bb92 84 goto bad;
a21ae242 85 }
a21ae242 86 cp++;
6459ebe0 87 if (cp >= nbp->b_un.b_addr + MAXPATHLEN) {
f5039631 88 u.u_error = ENOENT;
6bd0bb92 89 goto bad;
f5039631
BJ
90 }
91 }
6bd0bb92
BJ
92 if (u.u_error)
93 goto bad;
94
10873320 95 /*
6bd0bb92 96 * Get starting directory.
10873320 97 */
6bd0bb92 98 cp = nbp->b_un.b_addr;
f5039631
BJ
99 if (*cp == '/') {
100 while (*cp == '/')
101 cp++;
10873320
BJ
102 if ((dp = u.u_rdir) == NULL)
103 dp = rootdir;
6bd0bb92
BJ
104 } else
105 dp = u.u_cdir;
106 fs = dp->i_fs;
f5039631
BJ
107 ilock(dp);
108 dp->i_count++;
6bd0bb92
BJ
109 u.u_pdir = (struct inode *)0xc0000000; /* illegal */
110
10873320 111 /*
6bd0bb92
BJ
112 * We come to dirloop to search a new directory.
113 * The directory must be locked so that it can be
114 * iput, and fs must be already set to dp->i_fs.
10873320 115 */
6bd0bb92 116dirloop:
a0aead5a 117 /*
6bd0bb92 118 * Check accessiblity of directory.
a0aead5a 119 */
6bd0bb92 120#ifdef EFS
a0aead5a
BJ
121 if ((dp->i_mode & IFMT) == IFCHR && major(dp->i_rdev) == efs_major) {
122 brelse(nbp);
123 return(dp);
124 }
125#endif
6bd0bb92 126 if ((dp->i_mode&IFMT) != IFDIR) {
10873320 127 u.u_error = ENOTDIR;
6bd0bb92
BJ
128 goto bad;
129 }
130 if (access(dp, IEXEC))
131 goto bad;
132
6f004ab5 133dirloop2:
6bd0bb92
BJ
134 /*
135 * Copy next component of name to u.u_dent.
136 */
137 for (i = 0; *cp != 0 && *cp != '/'; cp++) {
6459ebe0 138 if (i >= MAXNAMLEN) {
f5039631 139 u.u_error = ENOENT;
6bd0bb92 140 goto bad;
6459ebe0 141 }
6bd0bb92 142 u.u_dent.d_name[i++] = *cp;
6459ebe0
KM
143 }
144 u.u_dent.d_namlen = i;
6bd0bb92
BJ
145 u.u_dent.d_name[i] = 0;
146
147 /*
148 * Check for degenerate name (e.g. / or "")
149 * which is a way of talking about a directory,
150 * e.g. like "/." or ".".
151 */
152 if (u.u_dent.d_name[0] == 0) {
153 if (flag) {
f5039631 154 u.u_error = ENOENT;
6bd0bb92 155 goto bad;
f5039631 156 }
6459ebe0
KM
157 brelse(nbp);
158 return (dp);
f5039631 159 }
6bd0bb92 160
6459ebe0 161 /*
6bd0bb92
BJ
162 * Suppress search for slots unless creating
163 * file and at end of pathname, in which case
164 * we watch for a place to put the new file in
165 * case it doesn't already exist.
6459ebe0 166 */
6bd0bb92
BJ
167 slotstatus = FOUND;
168 if (flag == 1 && *cp == 0) {
169 slotstatus = NONE;
170 slotfreespace = 0;
171 slotneeded = DIRSIZ(&u.u_dent);
172 }
173
174 dirsize = roundup(dp->i_size, DIRBLKSIZ);
6459ebe0 175 u.u_offset = 0;
6bd0bb92 176 while (u.u_offset < dirsize) {
f5039631
BJ
177 /*
178 * If offset is on a block boundary,
179 * read the next directory block.
180 * Release previous if it exists.
181 */
6459ebe0 182 if (blkoff(fs, u.u_offset) == 0) {
f5039631
BJ
183 if (bp != NULL)
184 brelse(bp);
6bd0bb92
BJ
185 bp = batoffset(dp, u.u_offset, (char **)0);
186 if (bp == 0)
187 goto bad;
188 entryoffsetinblock = 0;
6459ebe0 189 }
6bd0bb92 190
6459ebe0 191 /*
6bd0bb92
BJ
192 * If still looking for a slot, and at a DIRBLKSIZE
193 * boundary, have to start looking for free space
194 * again.
6459ebe0 195 */
6bd0bb92
BJ
196 if (slotstatus == NONE &&
197 (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
198 slotoffset = -1;
199 slotfreespace = 0;
200 }
201
202 /*
203 * Get pointer to next entry, and do consistency checking:
204 * record length must be multiple of 4
205 * entry must fit in rest of this DIRBLKSIZ block
206 * record must be large enough to contain name
207 * name must be as long as advertised, and null terminated
208 * Checking last condition is expensive, it is done only
209 * when dirchk is set.
210 */
211 ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
212 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
213 if ((ep->d_reclen & 0x3) || ep->d_reclen > i ||
214 DIRSIZ(ep) > ep->d_reclen || dirchk && dirbadname(ep)) {
215 dirbad(dp, "mangled entry");
6459ebe0 216 u.u_offset += i;
6bd0bb92 217 entryoffsetinblock += i;
6459ebe0
KM
218 continue;
219 }
6bd0bb92 220
6459ebe0 221 /*
6bd0bb92 222 * If an appropriate sized slot has not yet been found,
6459ebe0
KM
223 * check to see if one is available. Also accumulate space
224 * in the current block so that we can determine if
225 * compaction is viable.
226 */
6bd0bb92
BJ
227 if (slotstatus != FOUND) {
228 int size = ep->d_reclen;
229
6459ebe0
KM
230 if (ep->d_ino != 0)
231 size -= DIRSIZ(ep);
232 if (size > 0) {
6bd0bb92
BJ
233 if (size >= slotneeded) {
234 slotstatus = FOUND;
235 slotoffset = u.u_offset;
236 slotsize = ep->d_reclen;
237 } else if (slotstatus == NONE) {
238 slotfreespace += size;
239 if (slotoffset == -1)
240 slotoffset = u.u_offset;
241 if (slotfreespace >= slotneeded) {
242 slotstatus = COMPACT;
243 slotsize =
244 u.u_offset+ep->d_reclen -
245 slotoffset;
246 }
6459ebe0 247 }
f5039631 248 }
f5039631 249 }
6bd0bb92 250
f5039631 251 /*
6bd0bb92 252 * Check for a name match.
f5039631 253 */
6bd0bb92
BJ
254 if (ep->d_ino) {
255 if (ep->d_namlen == u.u_dent.d_namlen &&
256 !bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen))
257 goto found;
258 }
259 prevoff = u.u_offset;
6459ebe0 260 u.u_offset += ep->d_reclen;
6bd0bb92
BJ
261 entryoffsetinblock += ep->d_reclen;
262 }
263/* notfound: */
264 /*
265 * If creating, and at end of pathname and current
266 * directory has not been removed, then can consider allowing
267 * file to be created.
268 */
269 if (flag == 1 && *cp == 0 && dp->i_nlink != 0) {
f5039631 270 /*
6bd0bb92
BJ
271 * Access for write is interpreted as allowing
272 * creation of files in the directory.
f5039631 273 */
6bd0bb92
BJ
274 if (access(dp, IWRITE))
275 goto bad;
f5039631 276 /*
6bd0bb92
BJ
277 * Return an indication of where the new directory
278 * entry should be put. If we didn't find a slot,
279 * then set u.u_count to 0 indicating that the
280 * new slot belongs at the end of the directory.
281 * If we found a slot, then the new entry can be
282 * put in the range [u.u_offset..u.u_offset+u.u_count)
f5039631 283 */
6bd0bb92
BJ
284 if (slotstatus == NONE)
285 u.u_count = 0;
286 else {
287 u.u_offset = slotoffset;
288 u.u_count = slotsize;
5485e062 289 }
6bd0bb92
BJ
290 dp->i_flag |= IUPD|ICHG;
291 if (bp)
292 brelse(bp);
293 brelse(nbp);
f5039631 294 /*
6bd0bb92
BJ
295 * We return with the directory locked, so that
296 * the parameters we set up above will still be
297 * valid if we actually decide to do a direnter().
298 * We return NULL to indicate that the entry doesn't
299 * currently exist, leaving a pointer to the (locked)
300 * directory inode in u.u_pdir.
f5039631 301 */
6bd0bb92
BJ
302 u.u_pdir = dp;
303 return (NULL);
304 }
305 u.u_error = ENOENT;
306 goto bad;
307found:
308 /*
309 * Check that directory length properly reflects presence
310 * of this entry.
311 */
312 if (entryoffsetinblock + ep->d_reclen > dp->i_size) {
313 dirbad(dp, "i_size too small");
314 dp->i_size = entryoffsetinblock + ep->d_reclen;
315 dp->i_flag |= IUPD|ICHG;
316 }
317
318 /*
319 * Found component in pathname; save directory
320 * entry in u.u_dent, and release directory buffer.
321 */
322 bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep));
323 brelse(bp);
324 bp = NULL;
325
326 /*
327 * If deleting, and at end of pathname, return
328 * parameters which can be used to remove file.
329 * Note that in this case we return the directory
330 * inode, not the inode of the file being deleted.
331 */
332 if (flag == 2 && *cp == 0) {
333 /*
334 * Write access to directory required to delete files.
335 */
336 if (access(dp, IWRITE))
337 goto bad;
338 /*
339 * Return pointer to current entry in u.u_offset,
340 * and distance past previous entry (if there
341 * is a previous entry in this block) in u.u_count.
342 * Save directory inode pointer in u.u_pdir for dirremove().
343 */
344 if ((u.u_offset&(DIRBLKSIZ-1)) == 0)
345 u.u_count = 0;
346 else
347 u.u_count = u.u_offset - prevoff;
348 brelse(nbp);
349 u.u_pdir = dp; /* for dirremove() */
350 return (dp);
351 }
352
353 /*
354 * Special handling for ".." allowing chdir out of mounted
355 * file system: indirect .. in root inode to reevaluate
356 * in directory file system was mounted on.
357 */
358 if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' &&
359 u.u_dent.d_name[2] == '\0') {
360 if (dp == u.u_rdir)
361 u.u_dent.d_ino = dp->i_number;
362 else if (u.u_dent.d_ino == ROOTINO &&
363 dp->i_number == ROOTINO) {
364 for (i = 1; i < NMOUNT; i++)
365 if (mount[i].m_bufp != NULL &&
366 mount[i].m_dev == dp->i_dev) {
6459ebe0 367 iput(dp);
6bd0bb92 368 dp = mount[i].m_inodp;
f5039631
BJ
369 ilock(dp);
370 dp->i_count++;
6bd0bb92
BJ
371 fs = dp->i_fs;
372 cp -= 2; /* back over .. */
373 goto dirloop2;
f5039631 374 }
10873320 375 }
6bd0bb92
BJ
376 }
377
378 /*
379 * Check for symbolic link, which may require us
380 * to massage the name before we continue translation.
381 * To avoid deadlock have to unlock the current directory,
382 * but don't iput it because we may need it again (if
383 * the symbolic link is relative to .). Instead save
384 * it (unlocked) as pdp.
385 */
386 pdp = dp;
387 iunlock(pdp);
388 dp = iget(dp->i_dev, fs, u.u_dent.d_ino);
389 if (dp == NULL)
390 goto bad2;
391 fs = dp->i_fs;
392
393 /*
394 * Check for symbolic link
395 */
396 if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) {
397 int pathlen = strlen(cp) + 1;
398 int bn;
399
400 if (dp->i_size + pathlen >= MAXPATHLEN - 1 ||
401 ++nlink > MAXSYMLINKS) {
402 u.u_error = ELOOP;
403 goto bad2;
404 }
405 bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
406 u.u_segflg = 1;
407 u.u_base = nbp->b_un.b_addr;
408 u.u_count = dp->i_size;
409 readi(dp);
410 if (u.u_error)
411 goto bad2;
412 cp = nbp->b_un.b_addr;
413 iput(dp);
f5039631 414 if (*cp == '/') {
6bd0bb92 415 irele(pdp);
f5039631
BJ
416 while (*cp == '/')
417 cp++;
6bd0bb92
BJ
418 if ((dp = u.u_rdir) == NULL)
419 dp = rootdir;
420 ilock(dp);
421 dp->i_count++;
422 } else {
423 dp = pdp;
424 ilock(dp);
f5039631 425 }
6bd0bb92
BJ
426 fs = dp->i_fs;
427 goto dirloop;
10873320 428 }
6bd0bb92
BJ
429 irele(pdp);
430
10873320 431 /*
6bd0bb92
BJ
432 * Not a symbolic link. If more pathname,
433 * continue at next component, else return.
10873320 434 */
6bd0bb92
BJ
435 if (*cp == '/') {
436 while (*cp == '/')
437 cp++;
438 goto dirloop;
10873320 439 }
6bd0bb92
BJ
440 brelse(nbp);
441 return (dp);
442bad2:
443 irele(pdp);
444bad:
445 if (bp)
446 brelse(bp);
447 if (dp)
448 iput(dp);
f5039631 449 brelse(nbp);
6459ebe0 450 return (NULL);
10873320
BJ
451}
452
6bd0bb92
BJ
453dirbad(ip, how)
454 struct inode *ip;
455 char *how;
456{
457
458 printf("%s: bad dir ino %d at offset %d: %s\n",
459 ip->i_fs->fs_fsmnt, ip->i_number, u.u_offset, how);
460}
461
462dirbadname(ep)
463 register struct direct *ep;
464{
465 register char *cp;
466 register int i;
467
468 for (i = 0; i < ep->d_namlen; i++)
469 if (ep->d_name[i] == 0)
470 return (1);
471 return (ep->d_name[i]);
472}
473
10873320
BJ
474/*
475 * Return the next character from the
476 * kernel string pointed at by dirp.
477 */
478schar()
479{
480
f5039631 481 return (*u.u_dirp++ & 0377);
10873320
BJ
482}
483
484/*
485 * Return the next character from the
486 * user string pointed at by dirp.
487 */
488uchar()
489{
490 register c;
491
492 c = fubyte(u.u_dirp++);
f5039631 493 if (c == -1) {
10873320 494 u.u_error = EFAULT;
f5039631
BJ
495 c = 0;
496 }
497 return (c);
498}
499
6bd0bb92
BJ
500/*
501 * Write a directory entry after a call to namei, using the parameters
502 * which it left in the u. area. The argument ip is the inode which
503 * the new directory entry will refer to. The u. area field u.u_pdir is
504 * a pointer to the directory to be written, which was left locked by
505 * namei. Remaining parameters (u.u_offset, u.u_count) indicate
506 * how the space for the new entry is to be gotten.
507 */
508direnter(ip)
509 struct inode *ip;
f5039631 510{
6bd0bb92
BJ
511 register struct direct *ep, *nep;
512 struct fs *fs;
513 struct buf *bp;
514 int loc, dsize, freespace, newentrysize;
515 char *dirbuf;
f5039631 516
6bd0bb92
BJ
517 u.u_dent.d_ino = ip->i_number;
518 u.u_segflg = 1;
519 newentrysize = DIRSIZ(&u.u_dent);
520 if (u.u_count == 0) {
521 /*
522 * If u.u_count is 0, then namei could find no space in the
523 * directory. In this case u.u_offset will be on a directory
524 * block boundary and we will write the new entry into a fresh
525 * block.
526 */
527 if (u.u_offset&(DIRBLKSIZ-1))
528 panic("wdir: newblk");
529 u.u_dent.d_reclen = DIRBLKSIZ;
530 u.u_count = newentrysize;
531 u.u_base = (caddr_t)&u.u_dent;
532 u.u_segflg = 1;
533 writei(u.u_pdir);
534 iput(u.u_pdir);
535 return;
536 }
537
538 /*
539 * If u.u_count is non-zero, then namei found space for the
540 * new entry in the range u.u_offset to u.u_offset+u.u_count.
541 * in the directory. To use this space, we may have to compact
542 * the entries located there, by copying them together towards
543 * the beginning of the block, leaving the free space in
544 * one usable chunk at the end.
545 */
546
547 /*
548 * Increase size of directory if entry eats into new space.
549 * This should never push the size past a new multiple of
550 * DIRBLKSIZE.
551 */
552 if (u.u_offset+u.u_count > u.u_pdir->i_size) {
553 if (((u.u_offset+u.u_count-1)&~(DIRBLKSIZ-1)) !=
554 ((u.u_pdir->i_size-1)&~(DIRBLKSIZ-1))) {
555printf("wdir i_size dir %s/%d (of=%d,cnt=%d,psz=%d))\n",
556u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number,u.u_offset,
557u.u_count,u.u_pdir->i_size);
558 panic("wdir: span");
559 }
560 u.u_pdir->i_size = u.u_offset + u.u_count;
561 }
562
563 /*
564 * Get the block containing the space for the new directory
565 * entry.
566 */
567 bp = batoffset(u.u_pdir, u.u_offset, (char **)&dirbuf);
568 if (bp == 0)
569 return;
570printf("direnter u.u_offset %d u.u_count %d, bpaddr %x, dirbuf %x\n",
571 u.u_offset, u.u_count, bp->b_un.b_addr, dirbuf);
572
573 /*
574 * Find space for the new entry. In the simple case, the
575 * entry at offset base will have the space. If it does
576 * not, then namei arranged that compacting the region
577 * u.u_offset to u.u_offset+u.u_count would yield the space.
578 */
579 ep = (struct direct *)dirbuf;
580 dsize = DIRSIZ(ep);
581 freespace = ep->d_reclen - dsize;
582 for (loc = ep->d_reclen; loc < u.u_count; ) {
583 nep = (struct direct *)(dirbuf + loc);
584 if (ep->d_ino) {
585 /* trim the existing slot */
586 ep->d_reclen = dsize;
587 ep = (struct direct *)((char *)ep + dsize);
588 } else {
589 /* overwrite; nothing there; header is ours */
590 freespace += dsize;
591 }
592 dsize = DIRSIZ(nep);
593 freespace += nep->d_reclen - dsize;
594 loc += nep->d_reclen;
595/*ZZ*/if((loc&~0x1ff)!=(loc+nep->d_reclen-1&~0x1ff))
596/*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,nep->d_reclen,
597/*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number);
598 bcopy(nep, ep, dsize);
599 }
600 /*
601 * Update the pointer fields in the previous entry (if any),
602 * copy in the new entry, and write out the block.
603 */
604 if (ep->d_ino == 0) {
605 if (freespace + dsize < newentrysize)
606 panic("wdir: compact1");
607/*ZZ*/if(freespace+dsize>512)panic("wdir: compact screwup");
608 u.u_dent.d_reclen = freespace + dsize;
609 } else {
610 if (freespace < newentrysize)
611 panic("wdir: compact2");
612 u.u_dent.d_reclen = freespace;
613/*ZZ*/if ((((char *)ep-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen");
614 ep->d_reclen = dsize;
615 ep = (struct direct *)((char *)ep + dsize);
616 }
617/*ZZ*/if((((char*)ep-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch");
618 bcopy(&u.u_dent, ep, newentrysize);
619 bwrite(bp);
620 u.u_pdir->i_flag |= IUPD|ICHG;
621 iput(u.u_pdir);
622}
623
624dirremove()
625{
626 register struct inode *dp = u.u_pdir;
627 register struct fs *fs = dp->i_fs;
628 register struct buf *bp;
629 struct direct *ep;
630
631printf("dirremove u.u_offset %d u.u_count %d\n", u.u_offset, u.u_count);
632 if (u.u_count == 0) {
633 /*
634 * First entry in block: set d_ino to zero.
635 */
636/*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n"
637/*ZZ*/,dp->i_fs->fs_fsmnt,dp->i_number,u.u_offset,u.u_dent.d_name);
638 u.u_base = (caddr_t)&u.u_dent;
639 u.u_count = DIRSIZ(&u.u_dent);
640 u.u_dent.d_ino = 0;
641 writei(dp);
642 } else {
643 /*
644 * Collapse new free space into previous entry.
645 */
646 bp = batoffset(dp, u.u_offset - u.u_count, (char **)&ep);
647 if (bp == 0)
648 return (0);
649 ep->d_reclen += u.u_dent.d_reclen;
650/*ZZ*/if((((char *)ep - bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen > 512)
651/*ZZ*/ panic("unlink: reclen");
652 bwrite(bp);
653 dp->i_flag |= IUPD|ICHG;
654 }
655 return (1);
10873320 656}
6459ebe0 657
6bd0bb92
BJ
658struct buf *
659batoffset(ip, offset, res)
660 struct inode *ip;
661 off_t offset;
662 char **res;
6459ebe0 663{
6bd0bb92
BJ
664 register struct fs *fs = ip->i_fs;
665 int lbn = lblkno(fs, offset);
666 int base = blkoff(fs, offset);
667 int bsize = blksize(fs, ip, lbn);
668 int bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize));
669 register struct buf *bp;
6459ebe0 670
6bd0bb92
BJ
671 if (u.u_error)
672 return (0);
673 bp = bread(ip->i_dev, bn, bsize);
674 if (bp->b_flags & B_ERROR) {
675 brelse(bp);
676 return (0);
677 }
678 if (res)
679 *res = bp->b_un.b_addr + base;
680printf("b_addr %x res pointer %x\n", bp->b_un.b_addr, *res);
681 return (bp);
6459ebe0 682}