| /* | 
 |  | 
 | /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 <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 overrided 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; | 
 | } |