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
37 char name_search [80];
38 long entry_num_search;
40 int init_dir_info (struct struct_file_info *info_ptr)
44 This function is called by the inode of the directory when the user issues the dir command from the inode.
45 It is used to gather information about the inode and to reset some variables which we need in order to handle
51 struct ext2_inode *ptr;
53 ptr=&type_data.u.t_ext2_inode; /* type_data contains the inode */
55 info_ptr->inode_ptr=ptr;
56 info_ptr->inode_offset=device_offset; /* device offset contains the inode's offset */
58 /* Reset the current position to the start */
60 info_ptr->global_block_num=ptr->i_block [0];
61 info_ptr->global_block_offset=ptr->i_block [0]*file_system_info.block_size;
62 info_ptr->block_num=0;
63 info_ptr->file_offset=0;
64 /* Set the size of the directory */
66 info_ptr->blocks_count=(ptr->i_size+file_system_info.block_size-1)/file_system_info.block_size;
67 info_ptr->file_length=ptr->i_size;
69 info_ptr->level=0; /* We start using direct blocks */
70 info_ptr->display=HEX; /* This is not actually used */
72 info_ptr->dir_entry_num=0;info_ptr->dir_entries_count=0; /* We'll start at the first directory entry */
73 info_ptr->dir_entry_offset=0;
75 /* Find dir_entries_count */
77 info_ptr->dir_entries_count=count_dir_entries (); /* Set the total number of entries */
82 struct struct_file_info search_dir_entries (int (*action) (struct struct_file_info *info),int *status)
85 This is the main function in this source file. Various actions are implemented using this basic function.
87 This routine runs on all directory entries in the current directory.
88 For each entry, action is called. We'll act according to the return code of action:
90 ABORT - Current dir entry is returned.
91 CONTINUE - Continue searching.
92 FOUND - Current dir entry is returned.
94 If the last entry is reached, it is returned, along with an ABORT status.
96 status is updated to the returned code of action.
100 struct struct_file_info info; /* Temporary variables used to */
101 struct ext2_dir_entry *dir_entry_ptr; /* contain the current search entries */
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 *) (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 *) (info.buffer+info.dir_entry_offset);
120 info.dir_entry_num++;
121 info.dir_entry_offset+=dir_entry_ptr->rec_len;
122 info.file_offset+=dir_entry_ptr->rec_len;
124 if (info.file_offset >= info.file_length) break;
126 if (info.dir_entry_offset >= file_system_info.block_size) { /* We crossed a block boundary */
127 /* Find the next block, */
129 info.global_block_num=file_block_to_global_block (info.block_num,&info);
130 info.global_block_offset=info.global_block_num*file_system_info.block_size;
131 info.file_offset=info.block_num*file_system_info.block_size;
132 info.dir_entry_offset=0;
133 /* read it and update the pointer */
135 low_read (info.buffer,file_system_info.block_size,info.global_block_offset);
136 dir_entry_ptr=(struct ext2_dir_entry *) (info.buffer+info.dir_entry_offset);
142 *status=ABORT;return (info); /* There was no match */
145 long count_dir_entries (void)
149 This function counts the number of entries in the directory. We just call search_dir_entries till the end.
150 The client function is action_count, which just tell search_dir_entries to continue.
157 return (search_dir_entries (&action_count,&status).dir_entry_num);
160 int action_count (struct struct_file_info *info)
164 Used by count_dir_entries above - This function is called by search_dir_entries, and it tells it to continue
165 searching, until we get to the last entry.
170 return (CONTINUE); /* Just continue searching */
173 void type_dir___cd (char *command_line)
176 Changes to a directory, relative to the current directory.
178 This is a complicated operation, so I would repeat here the explanation from the design and
179 implementation document.
181 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
182 calling directly type_ext2___cd.
184 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
187 3. It is the first part of the path that we need to search for in the current directory. We search for it using
188 search_dir_entries, which accepts the action_name function as the client function.
190 4. search_dir_entries will scan the entire entries and will call our action_name function for each entry.
191 In action_name, the required name will be checked against the name of the current entry, and FOUND will be
192 returned when a match occurs.
194 5. If the required entry is found, we dispatch a remember command to insert the current inode (remember that
195 type_data is still intact and contains the inode of the current directory) into the object memory.
196 This is required to easily support symbolic links - If we find later that the inode pointed by the entry is
197 actually a symbolic link, we'll need to return to this point, and the above inode doesn't have (and can't have,
198 because of hard links) the information necessary to "move back".
200 6. We then dispatch a followinode command to reach the inode pointed by the required entry. This command will
201 automatically change the type to ext2_inode - We are now at an inode, and all the inode commands are available.
203 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",
204 and recursively call ourself (The type is dir again) by dispatching a cd command, with the rest of the path
207 8. If the inode's type is a symbolic link (only fast symbolic link were meanwhile implemented. I guess this is
208 typically the case.), we note the path it is pointing at, the saved inode is recalled, we dispatch dir to
209 get back to the original directory, and we call ourself again with the link path/rest of the path argument.
211 9. In any other case, we just stop at the resulting inode.
217 char *ptr,full_dir_name [500],dir_name [500],temp [500],temp2 [500];
218 struct struct_file_info info;
219 struct ext2_dir_entry *dir_entry_ptr;
221 dir_entry_ptr=(struct ext2_dir_entry *) (file_info.buffer+file_info.dir_entry_offset);
223 ptr=parse_word (command_line,dir_name);
225 if (*ptr==0) { /* cd alone will enter the highlighted directory */
226 strncpy (full_dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len);
227 full_dir_name [dir_entry_ptr->name_len]=0;
230 ptr=parse_word (ptr,full_dir_name);
232 ptr=strchr (full_dir_name,'/');
234 if (ptr==full_dir_name) { /* Pathname is from root - Let the general cd do the job */
235 sprintf (temp,"cd %s",full_dir_name);type_ext2___cd (temp);return;
239 strcpy (dir_name,full_dir_name);
244 strncpy (dir_name,full_dir_name,ptr-full_dir_name);
245 dir_name [ptr-full_dir_name]=0;
246 strcpy (full_dir_name,++ptr);
248 /* dir_name contains the current entry, while */
249 /* full_dir_name contains the rest */
251 strcpy (name_search,dir_name); /* name_search is used to hold the required entry name */
253 if (dir_entry_ptr->name_len != strlen (dir_name) ||
254 strncmp (dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len)!=0)
255 info=search_dir_entries (&action_name,&status); /* Search for the entry. Answer in info. */
257 status=FOUND;info=file_info;
260 if (status==FOUND) { /* If found */
261 file_info=info; /* Switch to it, by setting the global file_info */
262 dispatch ("remember internal_variable"); /* Move the inode into the objects memory */
264 dispatch ("followinode"); /* Go to the inode pointed by this directory entry */
266 if (S_ISLNK (type_data.u.t_ext2_inode.i_mode)) {/* Symbolic link ? */
268 if (type_data.u.t_ext2_inode.i_size > 60) { /* I'm lazy, I guess :-) */
269 wprintw (command_win,"Error - Sorry, Only fast symbolic link following is currently supported\n");
270 refresh_command_win ();
273 /* Get the pointed name and append the previous path */
275 strcpy (temp2,(unsigned char *) &type_data.u.t_ext2_inode.i_block);
277 strcat (temp2,full_dir_name);
279 dispatch ("recall internal_variable"); /* Return to the original inode */
280 dispatch ("dir"); /* and to the directory */
282 sprintf (temp,"cd %s",temp2); /* And continue from there by dispatching a cd command */
283 dispatch (temp); /* (which can call ourself or the general cd) */
288 if (S_ISDIR (type_data.u.t_ext2_inode.i_mode)) { /* Is it an inode of a directory ? */
290 dispatch ("dir"); /* Yes - Pass to the pointed directory */
292 if (full_dir_name [0] != 0) { /* And call ourself with the rest of the pathname */
293 sprintf (temp,"cd %s",full_dir_name);
300 else { /* If we can't continue from here, we'll just stop */
301 wprintw (command_win,"Can\'t continue - Stopping at last inode\n");refresh_command_win ();
306 wprintw (command_win,"Error - Directory entry %s not found.\n",dir_name); /* Hmm, an invalid path somewhere */
307 refresh_command_win ();
310 int action_name (struct struct_file_info *info)
314 Compares the current search entry name (somewhere inside info) with the required name (in name_search).
315 Returns FOUND if found, or CONTINUE if not found.
320 struct ext2_dir_entry *dir_entry_ptr;
322 dir_entry_ptr=(struct ext2_dir_entry *) (info->buffer+info->dir_entry_offset);
324 if (dir_entry_ptr->name_len != strlen (name_search))
327 if (strncmp (dir_entry_ptr->name,name_search,dir_entry_ptr->name_len)==0)
333 void type_dir___entry (char *command_line)
337 Selects a directory entry according to its number.
338 search_dir_entries is used along with action_entry_num, in the same fashion as the previous usage of search_dir_entries.
344 struct struct_file_info info;
345 char *ptr,buffer [80];
347 ptr=parse_word (command_line,buffer);
349 wprintw (command_win,"Error - Argument_not_specified\n");wrefresh (command_win);
352 ptr=parse_word (ptr,buffer);
353 entry_num_search=atol (buffer);
355 if (entry_num_search < 0 || entry_num_search >= file_info.dir_entries_count) {
356 wprintw (command_win,"Error - Entry number out of range\n");wrefresh (command_win);
360 info=search_dir_entries (&action_entry_num,&status);
367 internal_error ("dir_com","type_dir___entry","According to our gathered data, we should have found this entry");
371 int action_entry_num (struct struct_file_info *info)
375 Used by the above function. Just compares the current number (in info) with the required one.
380 if (info->dir_entry_num == entry_num_search)
386 void type_dir___followinode (char *command_line)
390 Here we pass to the inode pointed by the current entry.
391 It involves computing the device offset of the inode and using directly the setoffset and settype commands.
398 struct ext2_dir_entry *dir_entry_ptr;
400 low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
401 dir_entry_ptr=(struct ext2_dir_entry *) (file_info.buffer+file_info.dir_entry_offset);
403 inode_offset=inode_num_to_inode_offset (dir_entry_ptr->inode); /* Compute the inode's offset */
404 sprintf (buffer,"setoffset %ld",inode_offset);dispatch (buffer); /* Move to it */
405 sprintf (buffer,"settype ext2_inode");dispatch (buffer); /* and set the type to an inode */
408 void type_dir___inode (char *command_line)
412 Returns to the parent inode of the current directory.
413 This is trivial, as we type_data is still intact and contains the parent inode !
418 dispatch ("settype ext2_inode");
422 void type_dir___show (char *command_line)
426 We use search_dir_entries to run on all the entries. Each time, action_show will be called to show one entry.
433 wmove (show_pad,0,0);
434 show_pad_info.max_line=-1;
436 search_dir_entries (&action_show,&status);
437 show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
442 int action_show (struct struct_file_info *info)
446 Show the current search entry (info) in one line. If the entry happens to be the current edited entry, it is highlighted.
451 unsigned char temp [80];
452 struct ext2_dir_entry *dir_entry_ptr;
454 dir_entry_ptr=(struct ext2_dir_entry *) (info->buffer+info->dir_entry_offset);
456 if (info->dir_entry_num == file_info.dir_entry_num) /* Highlight the current entry */
457 wattrset (show_pad,A_REVERSE);
459 strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len); /* The name is not terminated */
460 temp [dir_entry_ptr->name_len]=0;
461 if (dir_entry_ptr->name_len > (COLS - 55) && COLS > 55)
463 wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n", /* Display the various fields */
464 dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp);
466 show_pad_info.max_line++;
468 if (info->dir_entry_num == file_info.dir_entry_num)
469 wattrset (show_pad,A_NORMAL);
471 return (CONTINUE); /* And pass to the next */
474 void type_dir___next (char *command_line)
478 This function moves to the next directory entry. It just uses the current information and the entry command.
484 char *ptr,buffer [80];
486 ptr=parse_word (command_line,buffer);
489 ptr=parse_word (ptr,buffer);
490 offset*=atol (buffer);
493 sprintf (buffer,"entry %ld",file_info.dir_entry_num+offset);dispatch (buffer);
497 void type_dir___prev (char *command_line)
501 char *ptr,buffer [80];
503 ptr=parse_word (command_line,buffer);
506 ptr=parse_word (ptr,buffer);
507 offset*=atol (buffer);
510 sprintf (buffer,"entry %ld",file_info.dir_entry_num-offset);dispatch (buffer);
513 void show_dir_status (void)
517 Various statistics about the directory.
524 wmove (show_win,0,0);
525 wprintw (show_win,"Directory listing. Block %ld. ",file_info.global_block_num);
526 wprintw (show_win,"Directory entry %ld of %ld.\n",file_info.dir_entry_num,file_info.dir_entries_count-1);
527 wprintw (show_win,"Directory Offset %ld of %ld. ",file_info.file_offset,file_info.file_length-1);
529 inode_num=inode_offset_to_inode_num (file_info.inode_offset);
530 wprintw (show_win,"File inode %ld. Indirection level %ld.\n",inode_num,file_info.level);
535 void type_dir___remember (char *command_line)
539 This is overrided here because we don't remember a directory - It is too complicated. Instead, we remember the
540 inode of the current directory.
547 char *ptr,buffer [80];
548 struct struct_descriptor *descriptor_ptr;
550 ptr=parse_word (command_line,buffer);
553 wprintw (command_win,"Error - Argument not specified\n");wrefresh (command_win);
557 ptr=parse_word (ptr,buffer);
559 entry_num=remember_lifo.entries_count++;
560 if (entry_num>REMEMBER_COUNT-1) {
562 remember_lifo.entries_count--;
565 descriptor_ptr=first_type;
566 while (descriptor_ptr!=NULL && !found) {
567 if (strcmp (descriptor_ptr->name,"ext2_inode")==0)
570 descriptor_ptr=descriptor_ptr->next;
574 remember_lifo.offset [entry_num]=device_offset;
575 remember_lifo.type [entry_num]=descriptor_ptr;
576 strcpy (remember_lifo.name [entry_num],buffer);
578 wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr->name,device_offset,buffer);
579 wrefresh (command_win);
582 void type_dir___set (char *command_line)
586 Since the dir object doesn't have variables, we provide the impression that it has here. ext2_dir_entry was not used
587 because it is of variable length.
593 unsigned char *ptr,buffer [80],variable [80],value [80],temp [80];
594 struct ext2_dir_entry *dir_entry_ptr;
596 dir_entry_ptr=(struct ext2_dir_entry *) (file_info.buffer+file_info.dir_entry_offset);
598 ptr=parse_word (command_line,buffer);
600 wprintw (command_win,"Error - Missing arguments\n");refresh_command_win ();
603 parse_word (ptr,buffer);
604 ptr=strchr (buffer,'=');
606 wprintw (command_win,"Error - Bad syntax\n");refresh_command_win ();return;
608 strncpy (variable,buffer,ptr-buffer);variable [ptr-buffer]=0;
609 strcpy (value,++ptr);
611 if (strcasecmp ("inode",variable)==0) {
613 dir_entry_ptr->inode=atol (value);
614 wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->inode);refresh_command_win ();
618 if (strcasecmp ("rec_len",variable)==0) {
620 dir_entry_ptr->rec_len=(unsigned int) atol (value);
621 wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->rec_len);refresh_command_win ();
625 if (strcasecmp ("name_len",variable)==0) {
627 dir_entry_ptr->name_len=(unsigned int) atol (value);
628 wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->name_len);refresh_command_win ();
632 if (strcasecmp ("name",variable)==0) {
634 if (strlen (value) > dir_entry_ptr->name_len) {
635 wprintw (command_win,"Error - Length of name greater then name_len\n");
636 refresh_command_win ();return;
638 strncpy (dir_entry_ptr->name,value,strlen (value));
639 wprintw (command_win,"Variable %s set to %s\n",variable,value);refresh_command_win ();
644 wattrset (show_pad,A_REVERSE);
645 strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len);
646 temp [dir_entry_ptr->name_len]=0;
647 wmove (show_pad,file_info.dir_entry_num,0);
648 wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n",
649 dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp);
650 wattrset (show_pad,A_NORMAL);
651 show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
657 wprintw (command_win,"Error - Variable %s not found\n",variable);
658 refresh_command_win ();
663 void type_dir___writedata (char *command_line)
667 We need to override this since the data is not in type_data. Instead, we have to write the buffer which corresponds
668 to the current block.
673 low_write (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);