3 /usr/src/ext2ed/dir_com.c
5 A part of the extended file system 2 disk editor.
11 This file contains the codes which allows the user to handle directories.
13 Most of the functions use the global variable file_info (along with the special directory fields there) to save
14 information and pass it between them.
16 Since a directory is just a big file which is composed of directory entries, you will find that
17 the functions here are a superset of those in the file_com.c source.
19 We assume that the user reached here using the dir command of the inode type and not by using settype dir, so
20 that init_dir_info is indeed called to gather the required information.
22 type_data is not changed! It still contains the inode of the file - We handle the directory in our own
23 variables, so that settype ext2_inode will "go back" to the inode of this directory.
25 First written on: April 28 1995
27 Copyright (C) 1995 Gadi Oxman
38 char name_search
[80];
39 long entry_num_search
;
41 int init_dir_info (struct struct_file_info
*info_ptr
)
45 This function is called by the inode of the directory when the user issues the dir command from the inode.
46 It is used to gather information about the inode and to reset some variables which we need in order to handle
52 struct ext2_inode
*ptr
;
54 ptr
=&type_data
.u
.t_ext2_inode
; /* type_data contains the inode */
56 info_ptr
->inode_ptr
=ptr
;
57 info_ptr
->inode_offset
=device_offset
; /* device offset contains the inode's offset */
59 /* Reset the current position to the start */
61 info_ptr
->global_block_num
=ptr
->i_block
[0];
62 info_ptr
->global_block_offset
=ptr
->i_block
[0]*file_system_info
.block_size
;
63 info_ptr
->block_num
=0;
64 info_ptr
->file_offset
=0;
65 /* Set the size of the directory */
67 info_ptr
->blocks_count
=(ptr
->i_size
+file_system_info
.block_size
-1)/file_system_info
.block_size
;
68 info_ptr
->file_length
=ptr
->i_size
;
70 info_ptr
->level
=0; /* We start using direct blocks */
71 info_ptr
->display
=HEX
; /* This is not actually used */
73 info_ptr
->dir_entry_num
=0;info_ptr
->dir_entries_count
=0; /* We'll start at the first directory entry */
74 info_ptr
->dir_entry_offset
=0;
76 /* Find dir_entries_count */
78 info_ptr
->dir_entries_count
=count_dir_entries (); /* Set the total number of entries */
83 struct struct_file_info
search_dir_entries (int (*action
) (struct struct_file_info
*info
),int *status
)
86 This is the main function in this source file. Various actions are implemented using this basic function.
88 This routine runs on all directory entries in the current directory.
89 For each entry, action is called. We'll act according to the return code of action:
91 ABORT - Current dir entry is returned.
92 CONTINUE - Continue searching.
93 FOUND - Current dir entry is returned.
95 If the last entry is reached, it is returned, along with an ABORT status.
97 status is updated to the returned code of action.
101 struct struct_file_info info
; /* Temporary variables used to */
102 struct ext2_dir_entry_2
*dir_entry_ptr
; /* contain the current search entries */
103 int return_code
, next
;
105 info
=first_file_info
; /* Start from the first entry - Read it */
106 low_read (info
.buffer
,file_system_info
.block_size
,info
.global_block_offset
);
107 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (info
.buffer
+info
.dir_entry_offset
);
109 while (info
.file_offset
< info
.file_length
) { /* While we haven't reached the end */
111 *status
=return_code
=action (&info
); /* Call the client function to test */
112 /* the current entry */
113 if (return_code
==ABORT
|| return_code
==FOUND
)
114 return (info
); /* Stop, if so asked */
116 /* Pass to the next entry */
118 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (info
.buffer
+info
.dir_entry_offset
);
120 info
.dir_entry_num
++;
121 next
= dir_entry_ptr
->rec_len
;
123 next
= file_system_info
.block_size
- info
.dir_entry_offset
;
124 info
.dir_entry_offset
+= next
;
125 info
.file_offset
+= next
;
127 if (info
.file_offset
>= info
.file_length
) break;
129 if (info
.dir_entry_offset
>= file_system_info
.block_size
) { /* We crossed a block boundary */
130 /* Find the next block, */
132 info
.global_block_num
=file_block_to_global_block (info
.block_num
,&info
);
133 info
.global_block_offset
=info
.global_block_num
*file_system_info
.block_size
;
134 info
.file_offset
=info
.block_num
*file_system_info
.block_size
;
135 info
.dir_entry_offset
=0;
136 /* read it and update the pointer */
138 low_read (info
.buffer
,file_system_info
.block_size
,info
.global_block_offset
);
139 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (info
.buffer
+info
.dir_entry_offset
);
145 *status
=ABORT
;return (info
); /* There was no match */
148 long count_dir_entries (void)
152 This function counts the number of entries in the directory. We just call search_dir_entries till the end.
153 The client function is action_count, which just tell search_dir_entries to continue.
160 return (search_dir_entries (&action_count
,&status
).dir_entry_num
);
163 int action_count (struct struct_file_info
*info
)
167 Used by count_dir_entries above - This function is called by search_dir_entries, and it tells it to continue
168 searching, until we get to the last entry.
173 return (CONTINUE
); /* Just continue searching */
176 void type_dir___cd (char *command_line
)
179 Changes to a directory, relative to the current directory.
181 This is a complicated operation, so I would repeat here the explanation from the design and
182 implementation document.
184 1. The path is checked that it is not an absolute path (from /). If it is, we let the general cd to do the job by
185 calling directly type_ext2___cd.
187 2. The path is divided into the nearest path and the rest of the path. For example, cd 1/2/3/4 is divided into
190 3. It is the first part of the path that we need to search for in the current directory. We search for it using
191 search_dir_entries, which accepts the action_name function as the client function.
193 4. search_dir_entries will scan the entire entries and will call our action_name function for each entry.
194 In action_name, the required name will be checked against the name of the current entry, and FOUND will be
195 returned when a match occurs.
197 5. If the required entry is found, we dispatch a remember command to insert the current inode (remember that
198 type_data is still intact and contains the inode of the current directory) into the object memory.
199 This is required to easily support symbolic links - If we find later that the inode pointed by the entry is
200 actually a symbolic link, we'll need to return to this point, and the above inode doesn't have (and can't have,
201 because of hard links) the information necessary to "move back".
203 6. We then dispatch a followinode command to reach the inode pointed by the required entry. This command will
204 automatically change the type to ext2_inode - We are now at an inode, and all the inode commands are available.
206 7. We check the inode's type to see if it is a directory. If it is, we dispatch a dir command to "enter the directory",
207 and recursively call ourself (The type is dir again) by dispatching a cd command, with the rest of the path
210 8. If the inode's type is a symbolic link (only fast symbolic link were meanwhile implemented. I guess this is
211 typically the case.), we note the path it is pointing at, the saved inode is recalled, we dispatch dir to
212 get back to the original directory, and we call ourself again with the link path/rest of the path argument.
214 9. In any other case, we just stop at the resulting inode.
220 char *ptr
,full_dir_name
[500],dir_name
[500],temp
[500],temp2
[500];
221 struct struct_file_info info
;
222 struct ext2_dir_entry_2
*dir_entry_ptr
;
224 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (file_info
.buffer
+file_info
.dir_entry_offset
);
226 ptr
=parse_word (command_line
,dir_name
);
228 if (*ptr
==0) { /* cd alone will enter the highlighted directory */
229 strncpy (full_dir_name
,dir_entry_ptr
->name
,dir_entry_ptr
->name_len
);
230 full_dir_name
[dir_entry_ptr
->name_len
]=0;
233 ptr
=parse_word (ptr
,full_dir_name
);
235 ptr
=strchr (full_dir_name
,'/');
237 if (ptr
==full_dir_name
) { /* Pathname is from root - Let the general cd do the job */
238 sprintf (temp
,"cd %s",full_dir_name
);type_ext2___cd (temp
);return;
242 strcpy (dir_name
,full_dir_name
);
247 strncpy (dir_name
,full_dir_name
,ptr
-full_dir_name
);
248 dir_name
[ptr
-full_dir_name
]=0;
249 strcpy (full_dir_name
,++ptr
);
251 /* dir_name contains the current entry, while */
252 /* full_dir_name contains the rest */
254 strcpy (name_search
,dir_name
); /* name_search is used to hold the required entry name */
256 if (dir_entry_ptr
->name_len
!= strlen (dir_name
) ||
257 strncmp (dir_name
,dir_entry_ptr
->name
,dir_entry_ptr
->name_len
)!=0)
258 info
=search_dir_entries (&action_name
,&status
); /* Search for the entry. Answer in info. */
260 status
=FOUND
;info
=file_info
;
263 if (status
==FOUND
) { /* If found */
264 file_info
=info
; /* Switch to it, by setting the global file_info */
265 dispatch ("remember internal_variable"); /* Move the inode into the objects memory */
267 dispatch ("followinode"); /* Go to the inode pointed by this directory entry */
269 if (S_ISLNK (type_data
.u
.t_ext2_inode
.i_mode
)) {/* Symbolic link ? */
271 if (type_data
.u
.t_ext2_inode
.i_size
> 60) { /* I'm lazy, I guess :-) */
272 wprintw (command_win
,"Error - Sorry, Only fast symbolic link following is currently supported\n");
273 refresh_command_win ();
276 /* Get the pointed name and append the previous path */
278 strcpy (temp2
,(unsigned char *) &type_data
.u
.t_ext2_inode
.i_block
);
280 strcat (temp2
,full_dir_name
);
282 dispatch ("recall internal_variable"); /* Return to the original inode */
283 dispatch ("dir"); /* and to the directory */
285 sprintf (temp
,"cd %s",temp2
); /* And continue from there by dispatching a cd command */
286 dispatch (temp
); /* (which can call ourself or the general cd) */
291 if (S_ISDIR (type_data
.u
.t_ext2_inode
.i_mode
)) { /* Is it an inode of a directory ? */
293 dispatch ("dir"); /* Yes - Pass to the pointed directory */
295 if (full_dir_name
[0] != 0) { /* And call ourself with the rest of the pathname */
296 sprintf (temp
,"cd %s",full_dir_name
);
303 else { /* If we can't continue from here, we'll just stop */
304 wprintw (command_win
,"Can\'t continue - Stopping at last inode\n");refresh_command_win ();
309 wprintw (command_win
,"Error - Directory entry %s not found.\n",dir_name
); /* Hmm, an invalid path somewhere */
310 refresh_command_win ();
313 int action_name (struct struct_file_info
*info
)
317 Compares the current search entry name (somewhere inside info) with the required name (in name_search).
318 Returns FOUND if found, or CONTINUE if not found.
323 struct ext2_dir_entry_2
*dir_entry_ptr
;
325 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (info
->buffer
+info
->dir_entry_offset
);
327 if (dir_entry_ptr
->name_len
!= strlen (name_search
))
330 if (strncmp (dir_entry_ptr
->name
,name_search
,dir_entry_ptr
->name_len
)==0)
336 void type_dir___entry (char *command_line
)
340 Selects a directory entry according to its number.
341 search_dir_entries is used along with action_entry_num, in the same fashion as the previous usage of search_dir_entries.
347 struct struct_file_info info
;
348 char *ptr
,buffer
[80];
350 ptr
=parse_word (command_line
,buffer
);
352 wprintw (command_win
,"Error - Argument_not_specified\n");wrefresh (command_win
);
355 ptr
=parse_word (ptr
,buffer
);
356 entry_num_search
=atol (buffer
);
358 if (entry_num_search
< 0 || entry_num_search
>= file_info
.dir_entries_count
) {
359 wprintw (command_win
,"Error - Entry number out of range\n");wrefresh (command_win
);
363 info
=search_dir_entries (&action_entry_num
,&status
);
370 internal_error ("dir_com","type_dir___entry","According to our gathered data, we should have found this entry");
374 int action_entry_num (struct struct_file_info
*info
)
378 Used by the above function. Just compares the current number (in info) with the required one.
383 if (info
->dir_entry_num
== entry_num_search
)
389 void type_dir___followinode (char *command_line
)
393 Here we pass to the inode pointed by the current entry.
394 It involves computing the device offset of the inode and using directly the setoffset and settype commands.
401 struct ext2_dir_entry_2
*dir_entry_ptr
;
403 low_read (file_info
.buffer
,file_system_info
.block_size
,file_info
.global_block_offset
);
404 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (file_info
.buffer
+file_info
.dir_entry_offset
);
406 inode_offset
=inode_num_to_inode_offset (dir_entry_ptr
->inode
); /* Compute the inode's offset */
407 sprintf (buffer
,"setoffset %ld",inode_offset
);dispatch (buffer
); /* Move to it */
408 sprintf (buffer
,"settype ext2_inode");dispatch (buffer
); /* and set the type to an inode */
411 void type_dir___inode (char *command_line
)
415 Returns to the parent inode of the current directory.
416 This is trivial, as we type_data is still intact and contains the parent inode !
421 dispatch ("settype ext2_inode");
425 void type_dir___show (char *command_line
)
429 We use search_dir_entries to run on all the entries. Each time, action_show will be called to show one entry.
436 wmove (show_pad
,0,0);
437 show_pad_info
.max_line
=-1;
439 search_dir_entries (&action_show
,&status
);
440 show_pad_info
.line
=file_info
.dir_entry_num
-show_pad_info
.display_lines
/2;
445 int action_show (struct struct_file_info
*info
)
449 Show the current search entry (info) in one line. If the entry happens to be the current edited entry, it is highlighted.
454 unsigned char temp
[80];
455 struct ext2_dir_entry_2
*dir_entry_ptr
;
457 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (info
->buffer
+info
->dir_entry_offset
);
459 if (info
->dir_entry_num
== file_info
.dir_entry_num
) /* Highlight the current entry */
460 wattrset (show_pad
,A_REVERSE
);
462 strncpy (temp
,dir_entry_ptr
->name
,dir_entry_ptr
->name_len
); /* The name is not terminated */
463 temp
[dir_entry_ptr
->name_len
]=0;
464 if (dir_entry_ptr
->name_len
> (COLS
- 55) && COLS
> 55)
466 wprintw (show_pad
,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n", /* Display the various fields */
467 dir_entry_ptr
->inode
,dir_entry_ptr
->rec_len
,dir_entry_ptr
->name_len
,temp
);
469 show_pad_info
.max_line
++;
471 if (info
->dir_entry_num
== file_info
.dir_entry_num
)
472 wattrset (show_pad
,A_NORMAL
);
474 return (CONTINUE
); /* And pass to the next */
477 void type_dir___next (char *command_line
)
481 This function moves to the next directory entry. It just uses the current information and the entry command.
487 char *ptr
,buffer
[80];
489 ptr
=parse_word (command_line
,buffer
);
492 ptr
=parse_word (ptr
,buffer
);
493 offset
*=atol (buffer
);
496 sprintf (buffer
,"entry %ld",file_info
.dir_entry_num
+offset
);dispatch (buffer
);
500 void type_dir___prev (char *command_line
)
504 char *ptr
,buffer
[80];
506 ptr
=parse_word (command_line
,buffer
);
509 ptr
=parse_word (ptr
,buffer
);
510 offset
*=atol (buffer
);
513 sprintf (buffer
,"entry %ld",file_info
.dir_entry_num
-offset
);dispatch (buffer
);
516 void show_dir_status (void)
520 Various statistics about the directory.
527 wmove (show_win
,0,0);
528 wprintw (show_win
,"Directory listing. Block %ld. ",file_info
.global_block_num
);
529 wprintw (show_win
,"Directory entry %ld of %ld.\n",file_info
.dir_entry_num
,file_info
.dir_entries_count
-1);
530 wprintw (show_win
,"Directory Offset %ld of %ld. ",file_info
.file_offset
,file_info
.file_length
-1);
532 inode_num
=inode_offset_to_inode_num (file_info
.inode_offset
);
533 wprintw (show_win
,"File inode %ld. Indirection level %ld.\n",inode_num
,file_info
.level
);
538 void type_dir___remember (char *command_line
)
542 This is overridden here because we don't remember a directory - It is too complicated. Instead, we remember the
543 inode of the current directory.
550 char *ptr
,buffer
[80];
551 struct struct_descriptor
*descriptor_ptr
;
553 ptr
=parse_word (command_line
,buffer
);
556 wprintw (command_win
,"Error - Argument not specified\n");wrefresh (command_win
);
560 ptr
=parse_word (ptr
,buffer
);
562 entry_num
=remember_lifo
.entries_count
++;
563 if (entry_num
>REMEMBER_COUNT
-1) {
565 remember_lifo
.entries_count
--;
568 descriptor_ptr
=first_type
;
569 while (descriptor_ptr
!=NULL
&& !found
) {
570 if (strcmp (descriptor_ptr
->name
,"ext2_inode")==0)
573 descriptor_ptr
=descriptor_ptr
->next
;
577 remember_lifo
.offset
[entry_num
]=device_offset
;
578 remember_lifo
.type
[entry_num
]=descriptor_ptr
;
579 strcpy (remember_lifo
.name
[entry_num
],buffer
);
581 wprintw (command_win
,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr
->name
,device_offset
,buffer
);
582 wrefresh (command_win
);
585 void type_dir___set (char *command_line
)
589 Since the dir object doesn't have variables, we provide the impression that it has here. ext2_dir_entry was not used
590 because it is of variable length.
596 unsigned char *ptr
,buffer
[80],variable
[80],value
[80],temp
[80];
597 struct ext2_dir_entry_2
*dir_entry_ptr
;
599 dir_entry_ptr
=(struct ext2_dir_entry_2
*) (file_info
.buffer
+file_info
.dir_entry_offset
);
601 ptr
=parse_word (command_line
,buffer
);
603 wprintw (command_win
,"Error - Missing arguments\n");refresh_command_win ();
606 parse_word (ptr
,buffer
);
607 ptr
=strchr (buffer
,'=');
609 wprintw (command_win
,"Error - Bad syntax\n");refresh_command_win ();return;
611 strncpy (variable
,buffer
,ptr
-buffer
);variable
[ptr
-buffer
]=0;
612 strcpy (value
,++ptr
);
614 if (strcasecmp ("inode",variable
)==0) {
616 dir_entry_ptr
->inode
=atol (value
);
617 wprintw (command_win
,"Variable %s set to %lu\n",variable
,dir_entry_ptr
->inode
);refresh_command_win ();
621 if (strcasecmp ("rec_len",variable
)==0) {
623 dir_entry_ptr
->rec_len
=(unsigned int) atol (value
);
624 wprintw (command_win
,"Variable %s set to %lu\n",variable
,dir_entry_ptr
->rec_len
);refresh_command_win ();
628 if (strcasecmp ("name_len",variable
)==0) {
630 dir_entry_ptr
->name_len
=(unsigned int) atol (value
);
631 wprintw (command_win
,"Variable %s set to %lu\n",variable
,dir_entry_ptr
->name_len
);refresh_command_win ();
635 if (strcasecmp ("name",variable
)==0) {
637 if (strlen (value
) > dir_entry_ptr
->name_len
) {
638 wprintw (command_win
,"Error - Length of name greater then name_len\n");
639 refresh_command_win ();return;
641 strncpy (dir_entry_ptr
->name
,value
,strlen (value
));
642 wprintw (command_win
,"Variable %s set to %s\n",variable
,value
);refresh_command_win ();
647 wattrset (show_pad
,A_REVERSE
);
648 strncpy (temp
,dir_entry_ptr
->name
,dir_entry_ptr
->name_len
);
649 temp
[dir_entry_ptr
->name_len
]=0;
650 wmove (show_pad
,file_info
.dir_entry_num
,0);
651 wprintw (show_pad
,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n",
652 dir_entry_ptr
->inode
,dir_entry_ptr
->rec_len
,dir_entry_ptr
->name_len
,temp
);
653 wattrset (show_pad
,A_NORMAL
);
654 show_pad_info
.line
=file_info
.dir_entry_num
-show_pad_info
.display_lines
/2;
660 wprintw (command_win
,"Error - Variable %s not found\n",variable
);
661 refresh_command_win ();
666 void type_dir___writedata (char *command_line
)
670 We need to override this since the data is not in type_data. Instead, we have to write the buffer which corresponds
671 to the current block.
676 low_write (file_info
.buffer
,file_system_info
.block_size
,file_info
.global_block_offset
);