1 /* This file contains the procedures that look up path names in the directory
2 * system and determine the inode number that goes with a given path name.
13 /*===========================================================================*
15 *===========================================================================*/
16 int fs_lookup(ino_t dir_nr
, char *name
, struct fsdriver_node
*node
,
19 struct inode
*dirp
, *rip
;
21 /* Find the starting inode. */
22 if ((dirp
= find_inode(fs_dev
, dir_nr
)) == NULL
)
25 /* Look up the directory entry. */
26 if ((rip
= advance(dirp
, name
)) == NULL
)
29 /* On success, leave the resulting inode open and return its details. */
30 node
->fn_ino_nr
= rip
->i_num
;
31 node
->fn_mode
= rip
->i_mode
;
32 node
->fn_size
= rip
->i_size
;
33 node
->fn_uid
= rip
->i_uid
;
34 node
->fn_gid
= rip
->i_gid
;
35 /* This is only valid for block and character specials. But it doesn't
36 * cause any harm to always set the device field. */
37 node
->fn_dev
= (dev_t
) rip
->i_zone
[0];
39 *is_mountpt
= rip
->i_mountpoint
;
45 /*===========================================================================*
47 *===========================================================================*/
48 struct inode
*advance(dirp
, string
)
49 struct inode
*dirp
; /* inode for directory to be searched */
50 const char *string
; /* component name to look for */
52 /* Given a directory and a component of a path, look up the component in
53 * the directory, find the inode, open it, and return a pointer to its inode
61 /* If 'string' is empty, return an error. */
62 if (string
[0] == '\0') {
67 /* If dir has been removed return ENOENT. */
68 if (dirp
->i_nlinks
== NO_LINK
) {
73 /* If 'string' is not present in the directory, signal error. */
74 if ( (err_code
= search_dir(dirp
, string
, &numb
, LOOK_UP
)) != OK
) {
78 /* The component has been found in the directory. Get inode. */
79 if ( (rip
= get_inode(dirp
->i_dev
, (int) numb
)) == NULL
) {
80 assert(err_code
!= OK
);
84 assert(err_code
== OK
);
89 /*===========================================================================*
91 *===========================================================================*/
92 int search_dir(ldir_ptr
, string
, numb
, flag
)
93 register struct inode
*ldir_ptr
; /* ptr to inode for dir to search */
94 const char *string
; /* component to search for */
95 ino_t
*numb
; /* pointer to inode number */
96 int flag
; /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
98 /* This function searches the directory whose inode is pointed to by 'ldip':
99 * if (flag == ENTER) enter 'string' in the directory with inode # '*numb';
100 * if (flag == DELETE) delete 'string' from the directory;
101 * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
102 * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
104 * This function, and this function alone, implements name truncation,
105 * by simply considering only the first MFS_NAME_MAX bytes from 'string'.
107 register struct direct
*dp
= NULL
;
108 register struct buf
*bp
= NULL
;
109 int i
, r
, e_hit
, t
, match
;
111 unsigned new_slots
, old_slots
;
112 struct super_block
*sp
;
115 /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
116 if ( (ldir_ptr
->i_mode
& I_TYPE
) != I_DIRECTORY
) {
120 if((flag
== DELETE
|| flag
== ENTER
) && ldir_ptr
->i_sp
->s_rd_only
)
123 /* Step through the directory one block at a time. */
124 old_slots
= (unsigned) (ldir_ptr
->i_size
/DIR_ENTRY_SIZE
);
127 match
= 0; /* set when a string match occurs */
130 if (flag
== ENTER
&& ldir_ptr
->i_last_dpos
< ldir_ptr
->i_size
) {
131 pos
= ldir_ptr
->i_last_dpos
;
132 new_slots
= (unsigned) (pos
/DIR_ENTRY_SIZE
);
135 for (; pos
< ldir_ptr
->i_size
; pos
+= ldir_ptr
->i_sp
->s_block_size
) {
136 assert(ldir_ptr
->i_dev
!= NO_DEV
);
138 /* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
139 bp
= get_block_map(ldir_ptr
, pos
);
141 assert(ldir_ptr
->i_dev
!= NO_DEV
);
144 /* Search a directory block. */
145 for (dp
= &b_dir(bp
)[0];
146 dp
< &b_dir(bp
)[NR_DIR_ENTRIES(ldir_ptr
->i_sp
->s_block_size
)];
148 if (++new_slots
> old_slots
) { /* not found, but room left */
149 if (flag
== ENTER
) e_hit
= TRUE
;
153 /* Match occurs if string found. */
154 if (flag
!= ENTER
&& dp
->mfs_d_ino
!= NO_ENTRY
) {
155 if (flag
== IS_EMPTY
) {
156 /* If this test succeeds, dir is not empty. */
157 if (strcmp(dp
->mfs_d_name
, "." ) != 0 &&
158 strcmp(dp
->mfs_d_name
, "..") != 0)
161 if (strncmp(dp
->mfs_d_name
, string
,
162 sizeof(dp
->mfs_d_name
)) == 0){
169 /* LOOK_UP or DELETE found what it wanted. */
171 if (flag
== IS_EMPTY
) r
= ENOTEMPTY
;
172 else if (flag
== DELETE
) {
173 /* Save d_ino for recovery. */
174 t
= MFS_NAME_MAX
- sizeof(ino_t
);
175 *((ino_t
*) &dp
->mfs_d_name
[t
]) = dp
->mfs_d_ino
;
176 dp
->mfs_d_ino
= NO_ENTRY
; /* erase entry */
178 ldir_ptr
->i_update
|= CTIME
| MTIME
;
179 IN_MARKDIRTY(ldir_ptr
);
180 if (pos
< ldir_ptr
->i_last_dpos
)
181 ldir_ptr
->i_last_dpos
= pos
;
183 sp
= ldir_ptr
->i_sp
; /* 'flag' is LOOK_UP */
184 *numb
= (ino_t
) conv4(sp
->s_native
,
185 (int) dp
->mfs_d_ino
);
191 /* Check for free slot for the benefit of ENTER. */
192 if (flag
== ENTER
&& dp
->mfs_d_ino
== 0) {
193 e_hit
= TRUE
; /* we found a free slot */
198 /* The whole block has been searched or ENTER has a free slot. */
199 if (e_hit
) break; /* e_hit set if ENTER can be performed now */
200 put_block(bp
); /* otherwise, continue searching dir */
203 /* The whole directory has now been searched. */
205 return(flag
== IS_EMPTY
? OK
: ENOENT
);
208 /* When ENTER next time, start searching for free slot from
209 * i_last_dpos. It gives some performance improvement (3-5%).
211 ldir_ptr
->i_last_dpos
= pos
;
213 /* This call is for ENTER. If no free slot has been found so far, try to
216 if (e_hit
== FALSE
) { /* directory is full and no room left in last block */
217 new_slots
++; /* increase directory size by 1 entry */
218 if (new_slots
== 0) return(EFBIG
); /* dir size limited by slot count */
219 if ( (bp
= new_block(ldir_ptr
, ldir_ptr
->i_size
)) == NULL
)
225 /* 'bp' now points to a directory block with space. 'dp' points to slot. */
226 (void) memset(dp
->mfs_d_name
, 0, (size_t) MFS_NAME_MAX
); /* clear entry */
227 for (i
= 0; i
< MFS_NAME_MAX
&& string
[i
]; i
++) dp
->mfs_d_name
[i
] = string
[i
];
229 dp
->mfs_d_ino
= conv4(sp
->s_native
, (int) *numb
);
232 ldir_ptr
->i_update
|= CTIME
| MTIME
; /* mark mtime for update later */
233 IN_MARKDIRTY(ldir_ptr
);
234 if (new_slots
> old_slots
) {
235 ldir_ptr
->i_size
= (off_t
) new_slots
* DIR_ENTRY_SIZE
;
236 /* Send the change to disk if the directory is extended. */
237 if (extended
) rw_inode(ldir_ptr
, WRITING
);