/* ufs_lookup.c 4.16 82/06/07 */
/* merged into kernel: @(#)nami.c 2.3 4/8/82 */
* Convert a pathname into a pointer to
* func = function called to get next char of name
* &uchar if name is in user space
* &schar if name is in system space
* flag = 0 if name is sought
* 1 if name is to be created
* 2 if name is to be deleted
* follow = 1 if links are to be followed at the end of the name
namei(func
, flag
, follow
)
int (*func
)(), flag
, follow
;
register struct inode
*dp
;
register struct buf
*bp
, *nbp
;
register struct direct
*ep
;
enum {NONE
, COMPACT
, FOUND
} slot
;
int entryfree
, entrysize
;
int spccnt
, size
, newsize
;
int loc
, prevoff
, curoff
;
* allocate name buffer; copy name
nbp
= geteblk(MAXPATHLEN
);
for (i
= 0, cp
= nbp
->b_un
.b_addr
; *cp
= (*func
)(); i
++) {
if ((*cp
& 0377) == ('/'|0200)) {
if (*cp
++ & 0200 && flag
== 1 ||
cp
>= nbp
->b_un
.b_addr
+ MAXPATHLEN
) {
if (cp
>= nbp
->b_un
.b_addr
+ MAXPATHLEN
) {
* If name starts with '/' start from
* root; otherwise start from current dir.
if ((dp
= u
.u_rdir
) == NULL
)
* dp must be a directory and
* must have X permission.
* cp is a path name relative to that directory.
if ((dp
->i_mode
&IFMT
) != IFDIR
)
(void) access(dp
, IEXEC
);
for (i
= 0; *cp
!= '\0' && *cp
!= '/'; cp
++) {
u
.u_dent
.d_name
[i
] = *cp
;
u
.u_dent
.d_name
[i
] = *cp
;
u
.u_dent
.d_name
[i
] = '\0';
newsize
= DIRSIZ(&u
.u_dent
);
if (u
.u_dent
.d_name
[0] == '\0') { /* null name, e.g. "/" or "" */
* set up to search a directory
while (u
.u_offset
< dp
->i_size
) {
* check to see if enough space has been accumulated to make
* an entry by compaction. Reset the free space counter each
* time a directory block is crossed.
entrysize
= u
.u_offset
- entryfree
;
} else if (loc
% DIRBLKSIZ
== 0) {
* If offset is on a block boundary,
* read the next directory block.
* Release previous if it exists.
if (blkoff(fs
, u
.u_offset
) == 0) {
lbn
= (daddr_t
)lblkno(fs
, u
.u_offset
);
bsize
= blksize(fs
, dp
, lbn
);
if ((bn
= bmap(dp
, lbn
, B_READ
)) < 0) {
printf("hole in dir: %s i = %d\n",
fs
->fs_fsmnt
, dp
->i_number
);
(bn
= bmap(dp
, lbn
, B_WRITE
, bsize
)) < 0) {
bp
= bread(dp
->i_dev
, fsbtodb(fs
, bn
), bsize
);
if (bp
->b_flags
& B_ERROR
) {
* calculate the next directory entry and run
* some rudimentary bounds checks to make sure
* that it is reasonable. If the check fails
* resync at the beginning of the next directory
ep
= (struct direct
*)(bp
->b_un
.b_addr
+ loc
);
i
= DIRBLKSIZ
- (loc
& (DIRBLKSIZ
- 1));
if (ep
->d_reclen
<= 0 || ep
->d_reclen
> i
) {
* If an appropriate sized hole has not yet been found,
* check to see if one is available. Also accumulate space
* in the current block so that we can determine if
entrysize
= DIRSIZ(ep
) + newsize
;
* String compare the directory entry
* and the current component.
* If they do not match, continue to the next entry.
u
.u_offset
+= ep
->d_reclen
;
if (ep
->d_namlen
!= u
.u_dent
.d_namlen
)
if (bcmp(u
.u_dent
.d_name
, ep
->d_name
, ep
->d_namlen
))
* Here a component matched in a directory.
* If there is more pathname, go back to
* dirloop, otherwise return.
bcopy((caddr_t
)ep
, (caddr_t
)&u
.u_dent
, DIRSIZ(ep
));
if (flag
== 2 && *cp
== '\0') {
if (access(dp
, IWRITE
)) {
if (curoff
% DIRBLKSIZ
== 0) {
u
.u_count
= DIRSIZ((struct direct
*)
(bp
->b_un
.b_addr
+ blkoff(fs
, prevoff
)));
* Special handling for ".."
if (u
.u_dent
.d_name
[0] == '.' && u
.u_dent
.d_name
[1] == '.' &&
u
.u_dent
.d_name
[2] == '\0') {
u
.u_dent
.d_ino
= dp
->i_number
;
else if (u
.u_dent
.d_ino
== ROOTINO
&&
dp
->i_number
== ROOTINO
) {
for (i
= 1; i
< NMOUNT
; i
++)
if (mount
[i
].m_bufp
!= NULL
&&
mount
[i
].m_dev
== dp
->i_dev
) {
cp
-= 2; /* back over .. */
dp
= iget(d
, fs
, u
.u_dent
.d_ino
);
* Check for symbolic link
if ((dp
->i_mode
& IFMT
) == IFLNK
&& (follow
|| *cp
== '/')) {
pathlen
= strlen(cp
) + 1;
if (dp
->i_size
+ pathlen
>= MAXPATHLEN
- 1 ||
bcopy(cp
, nbp
->b_un
.b_addr
+ dp
->i_size
, pathlen
);
bn
= bmap(dp
, (daddr_t
)0, B_READ
);
printf("hole in symlink: %s i = %d\n",
fs
->fs_fsmnt
, dp
->i_number
);
bp
= bread(dp
->i_dev
, fsbtodb(fs
, bn
),
(int)blksize(fs
, dp
, (daddr_t
)0));
if (bp
->b_flags
& B_ERROR
) {
bcopy(bp
->b_un
.b_addr
, nbp
->b_un
.b_addr
,
if ((dp
= u
.u_rdir
) == NULL
)
* End of path, so return name matched.
u
.u_offset
-= ep
->d_reclen
;
* Report what is appropriate as per flag.
if (flag
== 1 && *cp
== '\0' && dp
->i_nlink
!= 0) {
if (access(dp
, IWRITE
)) {
* Return the next character from the
* kernel string pointed at by dirp.
return (*u
.u_dirp
++ & 0377);
* Return the next character from the
* user string pointed at by dirp.
for (len
= 0; *s1
++ != '\0'; len
++)