xref: /minix/minix/fs/ext2/path.c (revision 7f5f010b)
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.
3  *
4  *  The entry points into this file are
5  *   eat_path:	 the 'main' routine of the path-to-inode conversion mechanism
6  *   last_dir:	 find the final directory on a given path
7  *   advance:	 parse one component of a path name
8  *   search_dir: search a directory for a string and return its inode number
9  *
10  * Created (MFS based):
11  *   February 2010 (Evgeniy Ivanov)
12  */
13 
14 #include "fs.h"
15 #include <assert.h>
16 #include <string.h>
17 #include <minix/endpoint.h>
18 #include <sys/stat.h>
19 #include <sys/param.h>
20 #include <sys/types.h>
21 #include "buf.h"
22 #include "inode.h"
23 #include "super.h"
24 #include <minix/vfsif.h>
25 #include <minix/libminixfs.h>
26 
27 char dot1[2] = ".";	/* used for search_dir to bypass the access */
28 char dot2[3] = "..";	/* permissions for . and ..		    */
29 
30 static char *get_name(char *name, char string[NAME_MAX+1]);
31 static int ltraverse(struct inode *rip, char *suffix);
32 static int parse_path(ino_t dir_ino, ino_t root_ino, int flags, struct
33 	inode **res_inop, size_t *offsetp, int *symlinkp);
34 
35 /*===========================================================================*
36  *                             fs_lookup				     *
37  *===========================================================================*/
38 int fs_lookup()
39 {
40   cp_grant_id_t grant;
41   int r, r1, flags, symlinks;
42   unsigned int len;
43   size_t offset = 0, path_size;
44   ino_t dir_ino, root_ino;
45   struct inode *rip;
46 
47   grant		= fs_m_in.m_vfs_fs_lookup.grant_path;
48   path_size	= fs_m_in.m_vfs_fs_lookup.path_size;	/* Size of the buffer */
49   len		= fs_m_in.m_vfs_fs_lookup.path_len;	/* including terminating nul */
50   dir_ino	= fs_m_in.m_vfs_fs_lookup.dir_ino;
51   root_ino	= fs_m_in.m_vfs_fs_lookup.root_ino;
52   flags		= fs_m_in.m_vfs_fs_lookup.flags;
53 
54   /* Check length. */
55   if(len > sizeof(user_path)) return(E2BIG);	/* too big for buffer */
56   if(len == 0) return(EINVAL);			/* too small */
57 
58   /* Copy the pathname and set up caller's user and group id */
59   r = sys_safecopyfrom(VFS_PROC_NR, grant, /*offset*/ 0,
60             (vir_bytes) user_path, (size_t) len);
61   if(r != OK) return(r);
62 
63   /* Verify this is a null-terminated path. */
64   if(user_path[len - 1] != '\0') return(EINVAL);
65 
66   memset(&credentials, 0, sizeof(credentials));
67   if(!(flags & PATH_GET_UCRED)) { /* Do we have to copy uid/gid credentials? */
68         caller_uid      = fs_m_in.m_vfs_fs_lookup.uid;
69         caller_gid      = fs_m_in.m_vfs_fs_lookup.gid;
70    } else {
71          if((r=fs_lookup_credentials(&credentials,
72                &caller_uid, &caller_gid, fs_m_in.m_vfs_fs_lookup.grant_ucred,
73                fs_m_in.m_vfs_fs_lookup.ucred_size)) != OK)
74                return r;
75   }
76 
77   /* Lookup inode */
78   rip = NULL;
79   r = parse_path(dir_ino, root_ino, flags, &rip, &offset, &symlinks);
80 
81   if(symlinks != 0 && (r == ELEAVEMOUNT || r == EENTERMOUNT || r == ESYMLINK)){
82 	len = strlen(user_path)+1;
83 	if(len > path_size) return(ENAMETOOLONG);
84 
85 	r1 = sys_safecopyto(VFS_PROC_NR, grant, (vir_bytes) 0,
86 			    (vir_bytes) user_path, (size_t) len);
87 	if (r1 != OK) return(r1);
88   }
89 
90   if(r == ELEAVEMOUNT || r == ESYMLINK) {
91 	  /* Report offset and the error */
92 	  fs_m_out.m_fs_vfs_lookup.offset = offset;
93 	  fs_m_out.m_fs_vfs_lookup.symloop = symlinks;
94 
95 	  return(r);
96   }
97 
98   if (r != OK && r != EENTERMOUNT) return(r);
99 
100   fs_m_out.m_fs_vfs_lookup.inode		= rip->i_num;
101   fs_m_out.m_fs_vfs_lookup.mode			= rip->i_mode;
102   fs_m_out.m_fs_vfs_lookup.file_size		= rip->i_size;
103   fs_m_out.m_fs_vfs_lookup.symloop		= symlinks;
104   fs_m_out.m_fs_vfs_lookup.uid			= rip->i_uid;
105   fs_m_out.m_fs_vfs_lookup.gid			= rip->i_gid;
106 
107   /* This is only valid for block and character specials. But it doesn't
108    * cause any harm to always set the device field. */
109   fs_m_out.m_fs_vfs_lookup.device		= (dev_t) rip->i_block[0];
110 
111   if(r == EENTERMOUNT) {
112 	  fs_m_out.m_fs_vfs_lookup.offset	= offset;
113 	  put_inode(rip); /* Only return a reference to the final object */
114   }
115 
116   return(r);
117 }
118 
119 
120 /*===========================================================================*
121  *                             parse_path				     *
122  *===========================================================================*/
123 static int parse_path(dir_ino, root_ino, flags, res_inop, offsetp, symlinkp)
124 ino_t dir_ino;
125 ino_t root_ino;
126 int flags;
127 struct inode **res_inop;
128 size_t *offsetp;
129 int *symlinkp;
130 {
131   /* Parse the path in user_path, starting at dir_ino. If the path is the empty
132    * string, just return dir_ino. It is upto the caller to treat an empty
133    * path in a special way. Otherwise, if the path consists of just one or
134    * more slash ('/') characters, the path is replaced with ".". Otherwise,
135    * just look up the first (or only) component in path after skipping any
136    * leading slashes.
137    */
138   int r, leaving_mount;
139   struct inode *rip, *dir_ip;
140   char *cp, *next_cp; /* component and next component */
141   char component[NAME_MAX+1];
142 
143   /* Start parsing path at the first component in user_path */
144   cp = user_path;
145 
146   /* No symlinks encountered yet */
147   *symlinkp = 0;
148 
149   /* Find starting inode inode according to the request message */
150   if((rip = find_inode(fs_dev, dir_ino)) == NULL)
151 	return(ENOENT);
152 
153   /* If dir has been removed return ENOENT. */
154   if (rip->i_links_count == NO_LINK) return(ENOENT);
155 
156   dup_inode(rip);
157 
158   /* If the given start inode is a mountpoint, we must be here because the file
159    * system mounted on top returned an ELEAVEMOUNT error. In this case, we must
160    * only accept ".." as the first path component.
161    */
162   leaving_mount = rip->i_mountpoint; /* True iff rip is a mountpoint */
163 
164   /* Scan the path component by component. */
165   while (TRUE) {
166 	if(cp[0] == '\0') {
167 		/* We're done; either the path was empty or we've parsed all
168 		   components of the path */
169 
170 		*res_inop = rip;
171 		*offsetp += cp - user_path;
172 
173 		/* Return EENTERMOUNT if we are at a mount point */
174 		if (rip->i_mountpoint) return(EENTERMOUNT);
175 
176 		return(OK);
177 	}
178 
179 	while(cp[0] == '/') cp++;
180 	next_cp = get_name(cp, component);
181 	if (next_cp == NULL) {
182 		put_inode(rip);
183 		return(err_code);
184 	}
185 
186 	/* Special code for '..'. A process is not allowed to leave a chrooted
187 	 * environment. A lookup of '..' at the root of a mounted filesystem
188 	 * has to return ELEAVEMOUNT. In both cases, the caller needs search
189 	 * permission for the current inode, as it is used as directory.
190 	 */
191 	if(strcmp(component, "..") == 0) {
192 		/* 'rip' is now accessed as directory */
193 		if ((r = forbidden(rip, X_BIT)) != OK) {
194 			put_inode(rip);
195 			return(r);
196 		}
197 
198 		if (rip->i_num == root_ino) {
199 			cp = next_cp;
200 			continue;	/* Ignore the '..' at a process' root
201 					   and move on to the next component */
202 		}
203 
204 		if (rip->i_num == ROOT_INODE && !rip->i_sp->s_is_root) {
205 			/* Climbing up to parent FS */
206 
207 			put_inode(rip);
208 			*offsetp += cp - user_path;
209 			return(ELEAVEMOUNT);
210 		}
211 	}
212 
213 	/* Only check for a mount point if we are not coming from one. */
214 	if (!leaving_mount && rip->i_mountpoint) {
215 		/* Going to enter a child FS */
216 
217 		*res_inop = rip;
218 		*offsetp += cp - user_path;
219 		return(EENTERMOUNT);
220 	}
221 
222 	/* There is more path.  Keep parsing.
223 	 * If we're leaving a mountpoint, skip directory permission checks.
224 	 */
225 	dir_ip = rip;
226 	rip = advance(dir_ip, leaving_mount ? dot2 : component, CHK_PERM);
227 	if(err_code == ELEAVEMOUNT || err_code == EENTERMOUNT)
228 		err_code = OK;
229 
230 	if (err_code != OK) {
231 		put_inode(dir_ip);
232 		return(err_code);
233 	}
234 
235 	leaving_mount = 0;
236 
237 	/* The call to advance() succeeded.  Fetch next component. */
238 	if (S_ISLNK(rip->i_mode)) {
239 
240 		if (next_cp[0] == '\0' && (flags & PATH_RET_SYMLINK)) {
241 			put_inode(dir_ip);
242 			*res_inop = rip;
243 			*offsetp += next_cp - user_path;
244 			return(OK);
245 		}
246 
247 		/* Extract path name from the symlink file */
248 		r = ltraverse(rip, next_cp);
249 		next_cp = user_path;
250 		*offsetp = 0;
251 
252 		/* Symloop limit reached? */
253 		if (++(*symlinkp) > _POSIX_SYMLOOP_MAX)
254 			r = ELOOP;
255 
256 		if (r != OK) {
257 			put_inode(dir_ip);
258 			put_inode(rip);
259 			return(r);
260 		}
261 
262 		if (next_cp[0] == '/') {
263                         put_inode(dir_ip);
264                         put_inode(rip);
265                         return(ESYMLINK);
266 		}
267 
268 		put_inode(rip);
269 		dup_inode(dir_ip);
270 		rip = dir_ip;
271 	}
272 
273 	put_inode(dir_ip);
274 	cp = next_cp; /* Process subsequent component in next round */
275   }
276 
277 }
278 
279 
280 /*===========================================================================*
281  *                             ltraverse				     *
282  *===========================================================================*/
283 static int ltraverse(rip, suffix)
284 register struct inode *rip;	/* symbolic link */
285 char *suffix;			/* current remaining path. Has to point in the
286 				 * user_path buffer
287 				 */
288 {
289 /* Traverse a symbolic link. Copy the link text from the inode and insert
290  * the text into the path. Return error code or report success. Base
291  * directory has to be determined according to the first character of the
292  * new pathname.
293  */
294 
295   size_t llen;		/* length of link */
296   size_t slen;		/* length of suffix */
297   struct buf *bp;	/* buffer containing link text */
298   const char *sp;	/* start of link text */
299 
300   llen = (size_t) rip->i_size;
301 
302   if (llen >= MAX_FAST_SYMLINK_LENGTH) {
303 	/* normal symlink */
304 	if(!(bp = get_block_map(rip, 0)))
305 		return(EIO);
306 	sp = b_data(bp);
307   } else {
308 	/* fast symlink, stored in inode */
309 	sp = (const char*) rip->i_block;
310   }
311 
312   slen = strlen(suffix);
313 
314   /* The path we're parsing looks like this:
315    * /already/processed/path/<link> or
316    * /already/processed/path/<link>/not/yet/processed/path
317    * After expanding the <link>, the path will look like
318    * <expandedlink> or
319    * <expandedlink>/not/yet/processed
320    * In both cases user_path must have enough room to hold <expandedlink>.
321    * However, in the latter case we have to move /not/yet/processed to the
322    * right place first, before we expand <link>. When strlen(<expandedlink>) is
323    * smaller than strlen(/already/processes/path), we move the suffix to the
324    * left. Is strlen(<expandedlink>) greater then we move it to the right. Else
325    * we do nothing.
326    */
327 
328   if (slen > 0) { /* Do we have path after the link? */
329 	/* For simplicity we require that suffix starts with a slash */
330 	if (suffix[0] != '/') {
331 		panic("ltraverse: suffix does not start with a slash");
332 	}
333 
334 	/* To be able to expand the <link>, we have to move the 'suffix'
335 	 * to the right place.
336 	 */
337 	if (slen + llen + 1 > sizeof(user_path))
338 		return(ENAMETOOLONG);/* <expandedlink>+suffix+\0 does not fit*/
339 	if ((unsigned)(suffix - user_path) != llen) {
340 		/* Move suffix left or right if needed */
341 		memmove(&user_path[llen], suffix, slen+1);
342 	}
343   } else {
344 	if (llen + 1 > sizeof(user_path))
345 		return(ENAMETOOLONG); /* <expandedlink> + \0 does not fit */
346 
347 	/* Set terminating nul */
348 	user_path[llen]= '\0';
349   }
350 
351   /* Everything is set, now copy the expanded link to user_path */
352   memmove(user_path, sp, llen);
353 
354   if (llen >= MAX_FAST_SYMLINK_LENGTH)
355 	put_block(bp, DIRECTORY_BLOCK);
356 
357   return(OK);
358 }
359 
360 
361 /*===========================================================================*
362  *				advance					     *
363  *===========================================================================*/
364 struct inode *advance(dirp, string, chk_perm)
365 struct inode *dirp;		/* inode for directory to be searched */
366 char string[NAME_MAX + 1];	/* component name to look for */
367 int chk_perm;			/* check permissions when string is looked up*/
368 {
369 /* Given a directory and a component of a path, look up the component in
370  * the directory, find the inode, open it, and return a pointer to its inode
371  * slot.
372  */
373   ino_t numb;
374   struct inode *rip;
375 
376   /* If 'string' is empty, return an error. */
377   if (string[0] == '\0') {
378 	err_code = ENOENT;
379 	return(NULL);
380   }
381 
382   /* Check for NULL. */
383   if (dirp == NULL) return(NULL);
384 
385   /* If 'string' is not present in the directory, signal error. */
386   if ( (err_code = search_dir(dirp, string, &numb, LOOK_UP,
387 			      chk_perm, 0)) != OK) {
388 	return(NULL);
389   }
390 
391   /* The component has been found in the directory.  Get inode. */
392   if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NULL)  {
393 	return(NULL);
394   }
395 
396   /* The following test is for "mountpoint/.." where mountpoint is a
397    * mountpoint. ".." will refer to the root of the mounted filesystem,
398    * but has to become a reference to the parent of the 'mountpoint'
399    * directory.
400    *
401    * This case is recognized by the looked up name pointing to a
402    * root inode, and the directory in which it is held being a
403    * root inode, _and_ the name[1] being '.'. (This is a test for '..'
404    * and excludes '.'.)
405    */
406   if (rip->i_num == ROOT_INODE) {
407 	  if (dirp->i_num == ROOT_INODE) {
408 		  if (string[1] == '.') {
409 			  if (!rip->i_sp->s_is_root) {
410 				  /* Climbing up mountpoint */
411 				  err_code = ELEAVEMOUNT;
412 			  }
413 		  }
414 	  }
415   }
416 
417   /* See if the inode is mounted on.  If so, switch to root directory of the
418    * mounted file system.  The super_block provides the linkage between the
419    * inode mounted on and the root directory of the mounted file system.
420    */
421   if (rip->i_mountpoint) {
422 	  /* Mountpoint encountered, report it */
423 	  err_code = EENTERMOUNT;
424   }
425 
426   return(rip);
427 }
428 
429 
430 /*===========================================================================*
431  *				get_name				     *
432  *===========================================================================*/
433 static char *get_name(path_name, string)
434 char *path_name;		/* path name to parse */
435 char string[NAME_MAX+1];	/* component extracted from 'old_name' */
436 {
437 /* Given a pointer to a path name in fs space, 'path_name', copy the first
438  * component to 'string' (truncated if necessary, always nul terminated).
439  * A pointer to the string after the first component of the name as yet
440  * unparsed is returned.  Roughly speaking,
441  * 'get_name' = 'path_name' - 'string'.
442  *
443  * This routine follows the standard convention that /usr/ast, /usr//ast,
444  * //usr///ast and /usr/ast/ are all equivalent.
445  *
446  * If len of component is greater, than allowed, then return 0.
447  */
448   size_t len;
449   char *cp, *ep;
450 
451   cp = path_name;
452 
453   /* Skip leading slashes */
454   while (cp[0] == '/') cp++;
455 
456   /* Find the end of the first component */
457   ep = cp;
458   while(ep[0] != '\0' && ep[0] != '/')
459 	ep++;
460 
461   len = (size_t) (ep - cp);
462 
463   if (len > NAME_MAX || len > EXT2_NAME_MAX) {
464   	err_code = ENAMETOOLONG;
465 	return(NULL);
466   }
467 
468   /* Special case of the string at cp is empty */
469   if (len == 0)
470 	strlcpy(string, ".", NAME_MAX + 1);  /* Return "." */
471   else {
472 	memcpy(string, cp, len);
473 	string[len]= '\0';
474   }
475 
476   return(ep);
477 }
478 
479 
480 /*===========================================================================*
481  *				search_dir				     *
482  *===========================================================================*/
483 int search_dir(ldir_ptr, string, numb, flag, check_permissions, ftype)
484 register struct inode *ldir_ptr; /* ptr to inode for dir to search */
485 const char string[NAME_MAX + 1];	 /* component to search for */
486 ino_t *numb;			 /* pointer to inode number */
487 int flag;			 /* LOOK_UP, ENTER, DELETE or IS_EMPTY */
488 int check_permissions;		 /* check permissions when flag is !IS_EMPTY */
489 int ftype;			 /* used when ENTER and
490 				  * INCOMPAT_FILETYPE */
491 {
492 /* This function searches the directory whose inode is pointed to by 'ldip':
493  * if (flag == ENTER)  enter 'string' in the directory with inode # '*numb';
494  * if (flag == DELETE) delete 'string' from the directory;
495  * if (flag == LOOK_UP) search for 'string' and return inode # in 'numb';
496  * if (flag == IS_EMPTY) return OK if only . and .. in dir else ENOTEMPTY;
497  *
498  *    if 'string' is dot1 or dot2, no access permissions are checked.
499  */
500 
501   register struct ext2_disk_dir_desc  *dp = NULL;
502   register struct ext2_disk_dir_desc  *prev_dp = NULL;
503   register struct buf *bp = NULL;
504   int i, r, e_hit, t, match;
505   mode_t bits;
506   off_t pos;
507   unsigned new_slots;
508   int extended = 0;
509   int required_space = 0;
510   int string_len = 0;
511 
512   /* If 'ldir_ptr' is not a pointer to a dir inode, error. */
513   if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY)  {
514 	return(ENOTDIR);
515   }
516 
517   r = OK;
518 
519   if (flag != IS_EMPTY) {
520 	bits = (flag == LOOK_UP ? X_BIT : W_BIT | X_BIT);
521 
522 	if (string == dot1 || string == dot2) {
523 		if (flag != LOOK_UP) r = read_only(ldir_ptr);
524 				     /* only a writable device is required. */
525         } else if(check_permissions) {
526 		r = forbidden(ldir_ptr, bits); /* check access permissions */
527 	}
528   }
529   if (r != OK) return(r);
530 
531   new_slots = 0;
532   e_hit = FALSE;
533   match = 0;    	/* set when a string match occurs */
534   pos = 0;
535 
536   if (flag == ENTER) {
537 	string_len = strlen(string);
538 	required_space = MIN_DIR_ENTRY_SIZE + string_len;
539 	required_space += (required_space & 0x03) == 0 ? 0 :
540 			     (DIR_ENTRY_ALIGN - (required_space & 0x03) );
541 
542 	if (ldir_ptr->i_last_dpos < ldir_ptr->i_size &&
543 	    ldir_ptr->i_last_dentry_size <= required_space)
544 		pos = ldir_ptr->i_last_dpos;
545   }
546 
547   for (; pos < ldir_ptr->i_size; pos += ldir_ptr->i_sp->s_block_size) {
548 	/* Since directories don't have holes, 'b' cannot be NO_BLOCK. */
549 	if(!(bp = get_block_map(ldir_ptr,
550 	   rounddown(pos, ldir_ptr->i_sp->s_block_size))))
551 		panic("get_block returned NO_BLOCK");
552 
553 	prev_dp = NULL; /* New block - new first dentry, so no prev. */
554 
555 	/* Search a directory block.
556 	 * Note, we set prev_dp at the end of the loop.
557 	 */
558 	for (dp = (struct ext2_disk_dir_desc*) &b_data(bp);
559 	     CUR_DISC_DIR_POS(dp, &b_data(bp)) < ldir_ptr->i_sp->s_block_size;
560 	     dp = NEXT_DISC_DIR_DESC(dp) ) {
561 		/* Match occurs if string found. */
562 		if (flag != ENTER && dp->d_ino != NO_ENTRY) {
563 			if (flag == IS_EMPTY) {
564 				/* If this test succeeds, dir is not empty. */
565 				if (ansi_strcmp(dp->d_name, ".", dp->d_name_len) != 0 &&
566 				    ansi_strcmp(dp->d_name, "..", dp->d_name_len) != 0) match = 1;
567 			} else {
568 				if (ansi_strcmp(dp->d_name, string, dp->d_name_len) == 0){
569 					match = 1;
570 				}
571 			}
572 		}
573 
574 		if (match) {
575 			/* LOOK_UP or DELETE found what it wanted. */
576 			r = OK;
577 			if (flag == IS_EMPTY) r = ENOTEMPTY;
578 			else if (flag == DELETE) {
579 				if (dp->d_name_len >= sizeof(ino_t)) {
580 					/* Save d_ino for recovery. */
581 					t = dp->d_name_len - sizeof(ino_t);
582 					*((ino_t *) &dp->d_name[t])= dp->d_ino;
583 				}
584 				dp->d_ino = NO_ENTRY;	/* erase entry */
585 				lmfs_markdirty(bp);
586 
587 				/* If we don't support HTree (directory index),
588 				 * which is fully compatible ext2 feature,
589 				 * we should reset EXT2_INDEX_FL, when modify
590 				 * linked directory structure.
591 				 *
592 				 * @TODO: actually we could just reset it for
593 				 * each directory, but I added if() to not
594 				 * forget about it later, when add HTree
595 				 * support.
596 				 */
597 				if (!HAS_COMPAT_FEATURE(ldir_ptr->i_sp,
598 							COMPAT_DIR_INDEX))
599 					ldir_ptr->i_flags &= ~EXT2_INDEX_FL;
600 				if (pos < ldir_ptr->i_last_dpos) {
601 					ldir_ptr->i_last_dpos = pos;
602 					ldir_ptr->i_last_dentry_size =
603 						conv2(le_CPU, dp->d_rec_len);
604 				}
605 				ldir_ptr->i_update |= CTIME | MTIME;
606 				ldir_ptr->i_dirt = IN_DIRTY;
607 				/* Now we have cleared dentry, if it's not
608 				 * the first one, merge it with previous one.
609 				 * Since we assume, that existing dentry must be
610 				 * correct, there is no way to spann a data block.
611 				 */
612 				if (prev_dp) {
613 					u16_t temp = conv2(le_CPU,
614 							prev_dp->d_rec_len);
615 					temp += conv2(le_CPU,
616 							dp->d_rec_len);
617 					prev_dp->d_rec_len = conv2(le_CPU,
618 							temp);
619 				}
620 			} else {
621 				/* 'flag' is LOOK_UP */
622 				*numb = (ino_t) conv4(le_CPU, dp->d_ino);
623 			}
624 			assert(lmfs_dev(bp) != NO_DEV);
625 			put_block(bp, DIRECTORY_BLOCK);
626 			return(r);
627 		}
628 
629 		/* Check for free slot for the benefit of ENTER. */
630 		if (flag == ENTER && dp->d_ino == NO_ENTRY) {
631 			/* we found a free slot, check if it has enough space */
632 			if (required_space <= conv2(le_CPU, dp->d_rec_len)) {
633 				e_hit = TRUE;	/* we found a free slot */
634 				break;
635 			}
636 		}
637 		/* Can we shrink dentry? */
638 		if (flag == ENTER && required_space <= DIR_ENTRY_SHRINK(dp)) {
639 			/* Shrink directory and create empty slot, now
640 			 * dp->d_rec_len = DIR_ENTRY_ACTUAL_SIZE + DIR_ENTRY_SHRINK.
641 			 */
642 			int new_slot_size = conv2(le_CPU, dp->d_rec_len);
643 			int actual_size = DIR_ENTRY_ACTUAL_SIZE(dp);
644 			new_slot_size -= actual_size;
645 			dp->d_rec_len = conv2(le_CPU, actual_size);
646 			dp = NEXT_DISC_DIR_DESC(dp);
647 			dp->d_rec_len = conv2(le_CPU, new_slot_size);
648 			/* if we fail before writing real ino */
649 			dp->d_ino = NO_ENTRY;
650 			lmfs_markdirty(bp);
651 			e_hit = TRUE;	/* we found a free slot */
652 			break;
653 		}
654 
655 		prev_dp = dp;
656 	}
657 
658 	/* The whole block has been searched or ENTER has a free slot. */
659 	assert(lmfs_dev(bp) != NO_DEV);
660 	if (e_hit) break;	/* e_hit set if ENTER can be performed now */
661 	put_block(bp, DIRECTORY_BLOCK); /* otherwise, continue searching dir */
662   }
663 
664   /* The whole directory has now been searched. */
665   if (flag != ENTER) {
666 	return(flag == IS_EMPTY ? OK : ENOENT);
667   }
668 
669   /* When ENTER next time, start searching for free slot from
670    * i_last_dpos. It gives solid performance improvement.
671    */
672   ldir_ptr->i_last_dpos = pos;
673   ldir_ptr->i_last_dentry_size = required_space;
674 
675   /* This call is for ENTER.  If no free slot has been found so far, try to
676    * extend directory.
677    */
678   if (e_hit == FALSE) { /* directory is full and no room left in last block */
679 	new_slots++;		/* increase directory size by 1 entry */
680 	if ( (bp = new_block(ldir_ptr, ldir_ptr->i_size)) == NULL)
681 		return(err_code);
682 	dp = (struct ext2_disk_dir_desc*) &b_data(bp);
683 	dp->d_rec_len = conv2(le_CPU, ldir_ptr->i_sp->s_block_size);
684 	dp->d_name_len = DIR_ENTRY_MAX_NAME_LEN(dp); /* for failure */
685 	extended = 1;
686   }
687 
688   /* 'bp' now points to a directory block with space. 'dp' points to slot. */
689   dp->d_name_len = string_len;
690   for (i = 0; i < NAME_MAX && i < dp->d_name_len && string[i]; i++)
691 	dp->d_name[i] = string[i];
692   dp->d_ino = (int) conv4(le_CPU, *numb);
693   if (HAS_INCOMPAT_FEATURE(ldir_ptr->i_sp, INCOMPAT_FILETYPE)) {
694 	/* Convert ftype (from inode.i_mode) to dp->d_file_type */
695 	if (ftype == I_REGULAR)
696 		dp->d_file_type = EXT2_FT_REG_FILE;
697 	else if (ftype == I_DIRECTORY)
698 		dp->d_file_type = EXT2_FT_DIR;
699 	else if (ftype == I_SYMBOLIC_LINK)
700 		dp->d_file_type = EXT2_FT_SYMLINK;
701 	else if (ftype == I_BLOCK_SPECIAL)
702 		dp->d_file_type = EXT2_FT_BLKDEV;
703 	else if (ftype == I_CHAR_SPECIAL)
704 		dp->d_file_type = EXT2_FT_CHRDEV;
705 	else if (ftype == I_NAMED_PIPE)
706 		dp->d_file_type = EXT2_FT_FIFO;
707 	else
708 		dp->d_file_type = EXT2_FT_UNKNOWN;
709   }
710   lmfs_markdirty(bp);
711   put_block(bp, DIRECTORY_BLOCK);
712   ldir_ptr->i_update |= CTIME | MTIME;	/* mark mtime for update later */
713   ldir_ptr->i_dirt = IN_DIRTY;
714 
715   if (new_slots == 1) {
716 	ldir_ptr->i_size += (off_t) conv2(le_CPU, dp->d_rec_len);
717 	/* Send the change to disk if the directory is extended. */
718 	if (extended) rw_inode(ldir_ptr, WRITING);
719   }
720   return(OK);
721 
722 }
723