diff options
Diffstat (limited to '')
-rw-r--r-- | ext2ed/dir_com.c | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/ext2ed/dir_com.c b/ext2ed/dir_com.c new file mode 100644 index 0000000..67bb4b5 --- /dev/null +++ b/ext2ed/dir_com.c @@ -0,0 +1,678 @@ +/* + +/usr/src/ext2ed/dir_com.c + +A part of the extended file system 2 disk editor. + +-------------------- +Handles directories. +-------------------- + +This file contains the codes which allows the user to handle directories. + +Most of the functions use the global variable file_info (along with the special directory fields there) to save +information and pass it between them. + +Since a directory is just a big file which is composed of directory entries, you will find that +the functions here are a superset of those in the file_com.c source. + +We assume that the user reached here using the dir command of the inode type and not by using settype dir, so +that init_dir_info is indeed called to gather the required information. + +type_data is not changed! It still contains the inode of the file - We handle the directory in our own +variables, so that settype ext2_inode will "go back" to the inode of this directory. + +First written on: April 28 1995 + +Copyright (C) 1995 Gadi Oxman + +*/ + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ext2ed.h" + +char name_search [80]; +long entry_num_search; + +int init_dir_info (struct struct_file_info *info_ptr) + +/* + +This function is called by the inode of the directory when the user issues the dir command from the inode. +It is used to gather information about the inode and to reset some variables which we need in order to handle +directories. + +*/ + +{ + struct ext2_inode *ptr; + + ptr=&type_data.u.t_ext2_inode; /* type_data contains the inode */ + + info_ptr->inode_ptr=ptr; + info_ptr->inode_offset=device_offset; /* device offset contains the inode's offset */ + + /* Reset the current position to the start */ + + info_ptr->global_block_num=ptr->i_block [0]; + info_ptr->global_block_offset=ptr->i_block [0]*file_system_info.block_size; + info_ptr->block_num=0; + info_ptr->file_offset=0; + /* Set the size of the directory */ + + info_ptr->blocks_count=(ptr->i_size+file_system_info.block_size-1)/file_system_info.block_size; + info_ptr->file_length=ptr->i_size; + + info_ptr->level=0; /* We start using direct blocks */ + info_ptr->display=HEX; /* This is not actually used */ + + info_ptr->dir_entry_num=0;info_ptr->dir_entries_count=0; /* We'll start at the first directory entry */ + info_ptr->dir_entry_offset=0; + + /* Find dir_entries_count */ + + info_ptr->dir_entries_count=count_dir_entries (); /* Set the total number of entries */ + + return (1); +} + +struct struct_file_info search_dir_entries (int (*action) (struct struct_file_info *info),int *status) + +/* + This is the main function in this source file. Various actions are implemented using this basic function. + + This routine runs on all directory entries in the current directory. + For each entry, action is called. We'll act according to the return code of action: + + ABORT - Current dir entry is returned. + CONTINUE - Continue searching. + FOUND - Current dir entry is returned. + + If the last entry is reached, it is returned, along with an ABORT status. + + status is updated to the returned code of action. +*/ + +{ + struct struct_file_info info; /* Temporary variables used to */ + struct ext2_dir_entry_2 *dir_entry_ptr; /* contain the current search entries */ + int return_code, next; + + info=first_file_info; /* Start from the first entry - Read it */ + low_read (info.buffer,file_system_info.block_size,info.global_block_offset); + dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset); + + while (info.file_offset < info.file_length) { /* While we haven't reached the end */ + + *status=return_code=action (&info); /* Call the client function to test */ + /* the current entry */ + if (return_code==ABORT || return_code==FOUND) + return (info); /* Stop, if so asked */ + + /* Pass to the next entry */ + + dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset); + + info.dir_entry_num++; + next = dir_entry_ptr->rec_len; + if (!next) + next = file_system_info.block_size - info.dir_entry_offset; + info.dir_entry_offset += next; + info.file_offset += next; + + if (info.file_offset >= info.file_length) break; + + if (info.dir_entry_offset >= file_system_info.block_size) { /* We crossed a block boundary */ + /* Find the next block, */ + info.block_num++; + info.global_block_num=file_block_to_global_block (info.block_num,&info); + info.global_block_offset=info.global_block_num*file_system_info.block_size; + info.file_offset=info.block_num*file_system_info.block_size; + info.dir_entry_offset=0; + /* read it and update the pointer */ + + low_read (info.buffer,file_system_info.block_size,info.global_block_offset); + dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset); + + } + + } + + *status=ABORT;return (info); /* There was no match */ +} + +long count_dir_entries (void) + +/* + +This function counts the number of entries in the directory. We just call search_dir_entries till the end. +The client function is action_count, which just tell search_dir_entries to continue. + +*/ + +{ + int status; + + return (search_dir_entries (&action_count,&status).dir_entry_num); +} + +int action_count (struct struct_file_info *info) + +/* + +Used by count_dir_entries above - This function is called by search_dir_entries, and it tells it to continue +searching, until we get to the last entry. + +*/ + +{ + return (CONTINUE); /* Just continue searching */ +} + +void type_dir___cd (char *command_line) + +/* + Changes to a directory, relative to the current directory. + + This is a complicated operation, so I would repeat here the explanation from the design and + implementation document. + +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 + calling directly type_ext2___cd. + +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 + 1 and into 2/3/4. + +3. It is the first part of the path that we need to search for in the current directory. We search for it using + search_dir_entries, which accepts the action_name function as the client function. + +4. search_dir_entries will scan the entire entries and will call our action_name function for each entry. + In action_name, the required name will be checked against the name of the current entry, and FOUND will be + returned when a match occurs. + +5. If the required entry is found, we dispatch a remember command to insert the current inode (remember that + type_data is still intact and contains the inode of the current directory) into the object memory. + This is required to easily support symbolic links - If we find later that the inode pointed by the entry is + actually a symbolic link, we'll need to return to this point, and the above inode doesn't have (and can't have, + because of hard links) the information necessary to "move back". + +6. We then dispatch a followinode command to reach the inode pointed by the required entry. This command will + automatically change the type to ext2_inode - We are now at an inode, and all the inode commands are available. + +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", + and recursively call ourself (The type is dir again) by dispatching a cd command, with the rest of the path + as an argument. + +8. If the inode's type is a symbolic link (only fast symbolic link were meanwhile implemented. I guess this is + typically the case.), we note the path it is pointing at, the saved inode is recalled, we dispatch dir to + get back to the original directory, and we call ourself again with the link path/rest of the path argument. + +9. In any other case, we just stop at the resulting inode. + +*/ + +{ + int status; + char *ptr,full_dir_name [500],dir_name [500],temp [500],temp2 [500]; + struct struct_file_info info; + struct ext2_dir_entry_2 *dir_entry_ptr; + + dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset); + + ptr=parse_word (command_line,dir_name); + + if (*ptr==0) { /* cd alone will enter the highlighted directory */ + strncpy (full_dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len); + full_dir_name [dir_entry_ptr->name_len]=0; + } + else + ptr=parse_word (ptr,full_dir_name); + + ptr=strchr (full_dir_name,'/'); + + if (ptr==full_dir_name) { /* Pathname is from root - Let the general cd do the job */ + sprintf (temp,"cd %s",full_dir_name);type_ext2___cd (temp);return; + } + + if (ptr==NULL) { + strcpy (dir_name,full_dir_name); + full_dir_name [0]=0; + } + + else { + strncpy (dir_name,full_dir_name,ptr-full_dir_name); + dir_name [ptr-full_dir_name]=0; + strcpy (full_dir_name,++ptr); + } + /* dir_name contains the current entry, while */ + /* full_dir_name contains the rest */ + + strcpy (name_search,dir_name); /* name_search is used to hold the required entry name */ + + if (dir_entry_ptr->name_len != strlen (dir_name) || + strncmp (dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len)!=0) + info=search_dir_entries (&action_name,&status); /* Search for the entry. Answer in info. */ + else { + status=FOUND;info=file_info; + } + + if (status==FOUND) { /* If found */ + file_info=info; /* Switch to it, by setting the global file_info */ + dispatch ("remember internal_variable"); /* Move the inode into the objects memory */ + + dispatch ("followinode"); /* Go to the inode pointed by this directory entry */ + + if (S_ISLNK (type_data.u.t_ext2_inode.i_mode)) {/* Symbolic link ? */ + + if (type_data.u.t_ext2_inode.i_size > 60) { /* I'm lazy, I guess :-) */ + wprintw (command_win,"Error - Sorry, Only fast symbolic link following is currently supported\n"); + refresh_command_win (); + return; + } + /* Get the pointed name and append the previous path */ + + strcpy (temp2,(unsigned char *) &type_data.u.t_ext2_inode.i_block); + strcat (temp2,"/"); + strcat (temp2,full_dir_name); + + dispatch ("recall internal_variable"); /* Return to the original inode */ + dispatch ("dir"); /* and to the directory */ + + sprintf (temp,"cd %s",temp2); /* And continue from there by dispatching a cd command */ + dispatch (temp); /* (which can call ourself or the general cd) */ + + return; + } + + if (S_ISDIR (type_data.u.t_ext2_inode.i_mode)) { /* Is it an inode of a directory ? */ + + dispatch ("dir"); /* Yes - Pass to the pointed directory */ + + if (full_dir_name [0] != 0) { /* And call ourself with the rest of the pathname */ + sprintf (temp,"cd %s",full_dir_name); + dispatch (temp); + } + + return; + } + + else { /* If we can't continue from here, we'll just stop */ + wprintw (command_win,"Can\'t continue - Stopping at last inode\n");refresh_command_win (); + return; + } + } + + wprintw (command_win,"Error - Directory entry %s not found.\n",dir_name); /* Hmm, an invalid path somewhere */ + refresh_command_win (); +} + +int action_name (struct struct_file_info *info) + +/* + +Compares the current search entry name (somewhere inside info) with the required name (in name_search). +Returns FOUND if found, or CONTINUE if not found. + +*/ + +{ + struct ext2_dir_entry_2 *dir_entry_ptr; + + dir_entry_ptr=(struct ext2_dir_entry_2 *) (info->buffer+info->dir_entry_offset); + + if (dir_entry_ptr->name_len != strlen (name_search)) + return (CONTINUE); + + if (strncmp (dir_entry_ptr->name,name_search,dir_entry_ptr->name_len)==0) + return (FOUND); + + return (CONTINUE); +} + +void type_dir___entry (char *command_line) + +/* + +Selects a directory entry according to its number. +search_dir_entries is used along with action_entry_num, in the same fashion as the previous usage of search_dir_entries. + +*/ + +{ + int status; + struct struct_file_info info; + char *ptr,buffer [80]; + + ptr=parse_word (command_line,buffer); + if (*ptr==0) { + wprintw (command_win,"Error - Argument_not_specified\n");wrefresh (command_win); + return; + } + ptr=parse_word (ptr,buffer); + entry_num_search=atol (buffer); + + if (entry_num_search < 0 || entry_num_search >= file_info.dir_entries_count) { + wprintw (command_win,"Error - Entry number out of range\n");wrefresh (command_win); + return; + } + + info=search_dir_entries (&action_entry_num,&status); + if (status==FOUND) { + file_info=info; + dispatch ("show"); + return; + } +#ifdef DEBUG + internal_error ("dir_com","type_dir___entry","According to our gathered data, we should have found this entry"); +#endif +} + +int action_entry_num (struct struct_file_info *info) + +/* + +Used by the above function. Just compares the current number (in info) with the required one. + +*/ + +{ + if (info->dir_entry_num == entry_num_search) + return (FOUND); + + return (CONTINUE); +} + +void type_dir___followinode (char *command_line) + +/* + +Here we pass to the inode pointed by the current entry. +It involves computing the device offset of the inode and using directly the setoffset and settype commands. + +*/ +{ + long inode_offset; + char buffer [80]; + + struct ext2_dir_entry_2 *dir_entry_ptr; + + low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset); + dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset); + + inode_offset=inode_num_to_inode_offset (dir_entry_ptr->inode); /* Compute the inode's offset */ + sprintf (buffer,"setoffset %ld",inode_offset);dispatch (buffer); /* Move to it */ + sprintf (buffer,"settype ext2_inode");dispatch (buffer); /* and set the type to an inode */ +} + +void type_dir___inode (char *command_line) + +/* + +Returns to the parent inode of the current directory. +This is trivial, as we type_data is still intact and contains the parent inode ! + +*/ + +{ + dispatch ("settype ext2_inode"); +} + + +void type_dir___show (char *command_line) + +/* + +We use search_dir_entries to run on all the entries. Each time, action_show will be called to show one entry. + +*/ + +{ + int status; + + wmove (show_pad,0,0); + show_pad_info.max_line=-1; + + search_dir_entries (&action_show,&status); + show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2; + refresh_show_pad (); + show_dir_status (); +} + +int action_show (struct struct_file_info *info) + +/* + +Show the current search entry (info) in one line. If the entry happens to be the current edited entry, it is highlighted. + +*/ + +{ + unsigned char temp [80]; + struct ext2_dir_entry_2 *dir_entry_ptr; + + dir_entry_ptr=(struct ext2_dir_entry_2 *) (info->buffer+info->dir_entry_offset); + + if (info->dir_entry_num == file_info.dir_entry_num) /* Highlight the current entry */ + wattrset (show_pad,A_REVERSE); + + strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len); /* The name is not terminated */ + temp [dir_entry_ptr->name_len]=0; + if (dir_entry_ptr->name_len > (COLS - 55) && COLS > 55) + temp [COLS-55]=0; + wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n", /* Display the various fields */ + dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp); + + show_pad_info.max_line++; + + if (info->dir_entry_num == file_info.dir_entry_num) + wattrset (show_pad,A_NORMAL); + + return (CONTINUE); /* And pass to the next */ +} + +void type_dir___next (char *command_line) + +/* + +This function moves to the next directory entry. It just uses the current information and the entry command. + +*/ + +{ + int offset=1; + char *ptr,buffer [80]; + + ptr=parse_word (command_line,buffer); + + if (*ptr!=0) { + ptr=parse_word (ptr,buffer); + offset*=atol (buffer); + } + + sprintf (buffer,"entry %ld",file_info.dir_entry_num+offset);dispatch (buffer); + +} + +void type_dir___prev (char *command_line) + +{ + int offset=1; + char *ptr,buffer [80]; + + ptr=parse_word (command_line,buffer); + + if (*ptr!=0) { + ptr=parse_word (ptr,buffer); + offset*=atol (buffer); + } + + sprintf (buffer,"entry %ld",file_info.dir_entry_num-offset);dispatch (buffer); +} + +void show_dir_status (void) + +/* + +Various statistics about the directory. + +*/ + +{ + long inode_num; + + wmove (show_win,0,0); + wprintw (show_win,"Directory listing. Block %ld. ",file_info.global_block_num); + wprintw (show_win,"Directory entry %ld of %ld.\n",file_info.dir_entry_num,file_info.dir_entries_count-1); + wprintw (show_win,"Directory Offset %ld of %ld. ",file_info.file_offset,file_info.file_length-1); + + inode_num=inode_offset_to_inode_num (file_info.inode_offset); + wprintw (show_win,"File inode %ld. Indirection level %ld.\n",inode_num,file_info.level); + + refresh_show_win (); +} + +void type_dir___remember (char *command_line) + +/* + +This is overridden here because we don't remember a directory - It is too complicated. Instead, we remember the +inode of the current directory. + +*/ + +{ + int found=0; + long entry_num; + char *ptr,buffer [80]; + struct struct_descriptor *descriptor_ptr; + + ptr=parse_word (command_line,buffer); + + if (*ptr==0) { + wprintw (command_win,"Error - Argument not specified\n");wrefresh (command_win); + return; + } + + ptr=parse_word (ptr,buffer); + + entry_num=remember_lifo.entries_count++; + if (entry_num>REMEMBER_COUNT-1) { + entry_num=0; + remember_lifo.entries_count--; + } + + descriptor_ptr=first_type; + while (descriptor_ptr!=NULL && !found) { + if (strcmp (descriptor_ptr->name,"ext2_inode")==0) + found=1; + else + descriptor_ptr=descriptor_ptr->next; + } + + + remember_lifo.offset [entry_num]=device_offset; + remember_lifo.type [entry_num]=descriptor_ptr; + strcpy (remember_lifo.name [entry_num],buffer); + + wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr->name,device_offset,buffer); + wrefresh (command_win); +} + +void type_dir___set (char *command_line) + +/* + +Since the dir object doesn't have variables, we provide the impression that it has here. ext2_dir_entry was not used +because it is of variable length. + +*/ + +{ + int found=0; + unsigned char *ptr,buffer [80],variable [80],value [80],temp [80]; + struct ext2_dir_entry_2 *dir_entry_ptr; + + dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset); + + ptr=parse_word (command_line,buffer); + if (*ptr==0) { + wprintw (command_win,"Error - Missing arguments\n");refresh_command_win (); + return; + } + parse_word (ptr,buffer); + ptr=strchr (buffer,'='); + if (ptr==NULL) { + wprintw (command_win,"Error - Bad syntax\n");refresh_command_win ();return; + } + strncpy (variable,buffer,ptr-buffer);variable [ptr-buffer]=0; + strcpy (value,++ptr); + + if (strcasecmp ("inode",variable)==0) { + found=1; + dir_entry_ptr->inode=atol (value); + wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->inode);refresh_command_win (); + + } + + if (strcasecmp ("rec_len",variable)==0) { + found=1; + dir_entry_ptr->rec_len=(unsigned int) atol (value); + wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->rec_len);refresh_command_win (); + + } + + if (strcasecmp ("name_len",variable)==0) { + found=1; + dir_entry_ptr->name_len=(unsigned int) atol (value); + wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->name_len);refresh_command_win (); + + } + + if (strcasecmp ("name",variable)==0) { + found=1; + if (strlen (value) > dir_entry_ptr->name_len) { + wprintw (command_win,"Error - Length of name greater then name_len\n"); + refresh_command_win ();return; + } + strncpy (dir_entry_ptr->name,value,strlen (value)); + wprintw (command_win,"Variable %s set to %s\n",variable,value);refresh_command_win (); + + } + + if (found) { + wattrset (show_pad,A_REVERSE); + strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len); + temp [dir_entry_ptr->name_len]=0; + wmove (show_pad,file_info.dir_entry_num,0); + wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n", + dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp); + wattrset (show_pad,A_NORMAL); + show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2; + refresh_show_pad (); + show_dir_status (); + } + + else { + wprintw (command_win,"Error - Variable %s not found\n",variable); + refresh_command_win (); + } + +} + +void type_dir___writedata (char *command_line) + +/* + +We need to override this since the data is not in type_data. Instead, we have to write the buffer which corresponds +to the current block. + +*/ + +{ + low_write (file_info.buffer,file_system_info.block_size,file_info.global_block_offset); + return; +} |