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_2 *dir_entry_ptr; /* contain the current search entries */
102
int return_code, next;
104
info=first_file_info; /* Start from the first entry - Read it */
105
low_read (info.buffer,file_system_info.block_size,info.global_block_offset);
106
dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset);
108
while (info.file_offset < info.file_length) { /* While we haven't reached the end */
110
*status=return_code=action (&info); /* Call the client function to test */
111
/* the current entry */
112
if (return_code==ABORT || return_code==FOUND)
113
return (info); /* Stop, if so asked */
115
/* Pass to the next entry */
117
dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset);
119
info.dir_entry_num++;
120
next = dir_entry_ptr->rec_len;
122
next = file_system_info.block_size - info.dir_entry_offset;
123
info.dir_entry_offset += next;
124
info.file_offset += next;
126
if (info.file_offset >= info.file_length) break;
128
if (info.dir_entry_offset >= file_system_info.block_size) { /* We crossed a block boundary */
129
/* Find the next block, */
131
info.global_block_num=file_block_to_global_block (info.block_num,&info);
132
info.global_block_offset=info.global_block_num*file_system_info.block_size;
133
info.file_offset=info.block_num*file_system_info.block_size;
134
info.dir_entry_offset=0;
135
/* read it and update the pointer */
137
low_read (info.buffer,file_system_info.block_size,info.global_block_offset);
138
dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset);
144
*status=ABORT;return (info); /* There was no match */
147
long count_dir_entries (void)
151
This function counts the number of entries in the directory. We just call search_dir_entries till the end.
152
The client function is action_count, which just tell search_dir_entries to continue.
159
return (search_dir_entries (&action_count,&status).dir_entry_num);
162
int action_count (struct struct_file_info *info)
166
Used by count_dir_entries above - This function is called by search_dir_entries, and it tells it to continue
167
searching, until we get to the last entry.
172
return (CONTINUE); /* Just continue searching */
175
void type_dir___cd (char *command_line)
178
Changes to a directory, relative to the current directory.
180
This is a complicated operation, so I would repeat here the explanation from the design and
181
implementation document.
183
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
184
calling directly type_ext2___cd.
186
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
189
3. It is the first part of the path that we need to search for in the current directory. We search for it using
190
search_dir_entries, which accepts the action_name function as the client function.
192
4. search_dir_entries will scan the entire entries and will call our action_name function for each entry.
193
In action_name, the required name will be checked against the name of the current entry, and FOUND will be
194
returned when a match occurs.
196
5. If the required entry is found, we dispatch a remember command to insert the current inode (remember that
197
type_data is still intact and contains the inode of the current directory) into the object memory.
198
This is required to easily support symbolic links - If we find later that the inode pointed by the entry is
199
actually a symbolic link, we'll need to return to this point, and the above inode doesn't have (and can't have,
200
because of hard links) the information necessary to "move back".
202
6. We then dispatch a followinode command to reach the inode pointed by the required entry. This command will
203
automatically change the type to ext2_inode - We are now at an inode, and all the inode commands are available.
205
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",
206
and recursively call ourself (The type is dir again) by dispatching a cd command, with the rest of the path
209
8. If the inode's type is a symbolic link (only fast symbolic link were meanwhile implemented. I guess this is
210
typically the case.), we note the path it is pointing at, the saved inode is recalled, we dispatch dir to
211
get back to the original directory, and we call ourself again with the link path/rest of the path argument.
213
9. In any other case, we just stop at the resulting inode.
219
char *ptr,full_dir_name [500],dir_name [500],temp [500],temp2 [500];
220
struct struct_file_info info;
221
struct ext2_dir_entry_2 *dir_entry_ptr;
223
dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset);
225
ptr=parse_word (command_line,dir_name);
227
if (*ptr==0) { /* cd alone will enter the highlighted directory */
228
strncpy (full_dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len);
229
full_dir_name [dir_entry_ptr->name_len]=0;
232
ptr=parse_word (ptr,full_dir_name);
234
ptr=strchr (full_dir_name,'/');
236
if (ptr==full_dir_name) { /* Pathname is from root - Let the general cd do the job */
237
sprintf (temp,"cd %s",full_dir_name);type_ext2___cd (temp);return;
241
strcpy (dir_name,full_dir_name);
246
strncpy (dir_name,full_dir_name,ptr-full_dir_name);
247
dir_name [ptr-full_dir_name]=0;
248
strcpy (full_dir_name,++ptr);
250
/* dir_name contains the current entry, while */
251
/* full_dir_name contains the rest */
253
strcpy (name_search,dir_name); /* name_search is used to hold the required entry name */
255
if (dir_entry_ptr->name_len != strlen (dir_name) ||
256
strncmp (dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len)!=0)
257
info=search_dir_entries (&action_name,&status); /* Search for the entry. Answer in info. */
259
status=FOUND;info=file_info;
262
if (status==FOUND) { /* If found */
263
file_info=info; /* Switch to it, by setting the global file_info */
264
dispatch ("remember internal_variable"); /* Move the inode into the objects memory */
266
dispatch ("followinode"); /* Go to the inode pointed by this directory entry */
268
if (S_ISLNK (type_data.u.t_ext2_inode.i_mode)) {/* Symbolic link ? */
270
if (type_data.u.t_ext2_inode.i_size > 60) { /* I'm lazy, I guess :-) */
271
wprintw (command_win,"Error - Sorry, Only fast symbolic link following is currently supported\n");
272
refresh_command_win ();
275
/* Get the pointed name and append the previous path */
277
strcpy (temp2,(unsigned char *) &type_data.u.t_ext2_inode.i_block);
279
strcat (temp2,full_dir_name);
281
dispatch ("recall internal_variable"); /* Return to the original inode */
282
dispatch ("dir"); /* and to the directory */
284
sprintf (temp,"cd %s",temp2); /* And continue from there by dispatching a cd command */
285
dispatch (temp); /* (which can call ourself or the general cd) */
290
if (S_ISDIR (type_data.u.t_ext2_inode.i_mode)) { /* Is it an inode of a directory ? */
292
dispatch ("dir"); /* Yes - Pass to the pointed directory */
294
if (full_dir_name [0] != 0) { /* And call ourself with the rest of the pathname */
295
sprintf (temp,"cd %s",full_dir_name);
302
else { /* If we can't continue from here, we'll just stop */
303
wprintw (command_win,"Can\'t continue - Stopping at last inode\n");refresh_command_win ();
308
wprintw (command_win,"Error - Directory entry %s not found.\n",dir_name); /* Hmm, an invalid path somewhere */
309
refresh_command_win ();
312
int action_name (struct struct_file_info *info)
316
Compares the current search entry name (somewhere inside info) with the required name (in name_search).
317
Returns FOUND if found, or CONTINUE if not found.
322
struct ext2_dir_entry_2 *dir_entry_ptr;
324
dir_entry_ptr=(struct ext2_dir_entry_2 *) (info->buffer+info->dir_entry_offset);
326
if (dir_entry_ptr->name_len != strlen (name_search))
329
if (strncmp (dir_entry_ptr->name,name_search,dir_entry_ptr->name_len)==0)
335
void type_dir___entry (char *command_line)
339
Selects a directory entry according to its number.
340
search_dir_entries is used along with action_entry_num, in the same fashion as the previous usage of search_dir_entries.
346
struct struct_file_info info;
347
char *ptr,buffer [80];
349
ptr=parse_word (command_line,buffer);
351
wprintw (command_win,"Error - Argument_not_specified\n");wrefresh (command_win);
354
ptr=parse_word (ptr,buffer);
355
entry_num_search=atol (buffer);
357
if (entry_num_search < 0 || entry_num_search >= file_info.dir_entries_count) {
358
wprintw (command_win,"Error - Entry number out of range\n");wrefresh (command_win);
362
info=search_dir_entries (&action_entry_num,&status);
369
internal_error ("dir_com","type_dir___entry","According to our gathered data, we should have found this entry");
373
int action_entry_num (struct struct_file_info *info)
377
Used by the above function. Just compares the current number (in info) with the required one.
382
if (info->dir_entry_num == entry_num_search)
388
void type_dir___followinode (char *command_line)
392
Here we pass to the inode pointed by the current entry.
393
It involves computing the device offset of the inode and using directly the setoffset and settype commands.
400
struct ext2_dir_entry_2 *dir_entry_ptr;
402
low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
403
dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset);
405
inode_offset=inode_num_to_inode_offset (dir_entry_ptr->inode); /* Compute the inode's offset */
406
sprintf (buffer,"setoffset %ld",inode_offset);dispatch (buffer); /* Move to it */
407
sprintf (buffer,"settype ext2_inode");dispatch (buffer); /* and set the type to an inode */
410
void type_dir___inode (char *command_line)
414
Returns to the parent inode of the current directory.
415
This is trivial, as we type_data is still intact and contains the parent inode !
420
dispatch ("settype ext2_inode");
424
void type_dir___show (char *command_line)
428
We use search_dir_entries to run on all the entries. Each time, action_show will be called to show one entry.
435
wmove (show_pad,0,0);
436
show_pad_info.max_line=-1;
438
search_dir_entries (&action_show,&status);
439
show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
444
int action_show (struct struct_file_info *info)
448
Show the current search entry (info) in one line. If the entry happens to be the current edited entry, it is highlighted.
453
unsigned char temp [80];
454
struct ext2_dir_entry_2 *dir_entry_ptr;
456
dir_entry_ptr=(struct ext2_dir_entry_2 *) (info->buffer+info->dir_entry_offset);
458
if (info->dir_entry_num == file_info.dir_entry_num) /* Highlight the current entry */
459
wattrset (show_pad,A_REVERSE);
461
strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len); /* The name is not terminated */
462
temp [dir_entry_ptr->name_len]=0;
463
if (dir_entry_ptr->name_len > (COLS - 55) && COLS > 55)
465
wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n", /* Display the various fields */
466
dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp);
468
show_pad_info.max_line++;
470
if (info->dir_entry_num == file_info.dir_entry_num)
471
wattrset (show_pad,A_NORMAL);
473
return (CONTINUE); /* And pass to the next */
476
void type_dir___next (char *command_line)
480
This function moves to the next directory entry. It just uses the current information and the entry command.
486
char *ptr,buffer [80];
488
ptr=parse_word (command_line,buffer);
491
ptr=parse_word (ptr,buffer);
492
offset*=atol (buffer);
495
sprintf (buffer,"entry %ld",file_info.dir_entry_num+offset);dispatch (buffer);
499
void type_dir___prev (char *command_line)
503
char *ptr,buffer [80];
505
ptr=parse_word (command_line,buffer);
508
ptr=parse_word (ptr,buffer);
509
offset*=atol (buffer);
512
sprintf (buffer,"entry %ld",file_info.dir_entry_num-offset);dispatch (buffer);
515
void show_dir_status (void)
519
Various statistics about the directory.
526
wmove (show_win,0,0);
527
wprintw (show_win,"Directory listing. Block %ld. ",file_info.global_block_num);
528
wprintw (show_win,"Directory entry %ld of %ld.\n",file_info.dir_entry_num,file_info.dir_entries_count-1);
529
wprintw (show_win,"Directory Offset %ld of %ld. ",file_info.file_offset,file_info.file_length-1);
531
inode_num=inode_offset_to_inode_num (file_info.inode_offset);
532
wprintw (show_win,"File inode %ld. Indirection level %ld.\n",inode_num,file_info.level);
537
void type_dir___remember (char *command_line)
541
This is overrided here because we don't remember a directory - It is too complicated. Instead, we remember the
542
inode of the current directory.
549
char *ptr,buffer [80];
550
struct struct_descriptor *descriptor_ptr;
552
ptr=parse_word (command_line,buffer);
555
wprintw (command_win,"Error - Argument not specified\n");wrefresh (command_win);
559
ptr=parse_word (ptr,buffer);
561
entry_num=remember_lifo.entries_count++;
562
if (entry_num>REMEMBER_COUNT-1) {
564
remember_lifo.entries_count--;
567
descriptor_ptr=first_type;
568
while (descriptor_ptr!=NULL && !found) {
569
if (strcmp (descriptor_ptr->name,"ext2_inode")==0)
572
descriptor_ptr=descriptor_ptr->next;
576
remember_lifo.offset [entry_num]=device_offset;
577
remember_lifo.type [entry_num]=descriptor_ptr;
578
strcpy (remember_lifo.name [entry_num],buffer);
580
wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr->name,device_offset,buffer);
581
wrefresh (command_win);
584
void type_dir___set (char *command_line)
588
Since the dir object doesn't have variables, we provide the impression that it has here. ext2_dir_entry was not used
589
because it is of variable length.
595
unsigned char *ptr,buffer [80],variable [80],value [80],temp [80];
596
struct ext2_dir_entry_2 *dir_entry_ptr;
598
dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset);
600
ptr=parse_word (command_line,buffer);
602
wprintw (command_win,"Error - Missing arguments\n");refresh_command_win ();
605
parse_word (ptr,buffer);
606
ptr=strchr (buffer,'=');
608
wprintw (command_win,"Error - Bad syntax\n");refresh_command_win ();return;
610
strncpy (variable,buffer,ptr-buffer);variable [ptr-buffer]=0;
611
strcpy (value,++ptr);
613
if (strcasecmp ("inode",variable)==0) {
615
dir_entry_ptr->inode=atol (value);
616
wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->inode);refresh_command_win ();
620
if (strcasecmp ("rec_len",variable)==0) {
622
dir_entry_ptr->rec_len=(unsigned int) atol (value);
623
wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->rec_len);refresh_command_win ();
627
if (strcasecmp ("name_len",variable)==0) {
629
dir_entry_ptr->name_len=(unsigned int) atol (value);
630
wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->name_len);refresh_command_win ();
634
if (strcasecmp ("name",variable)==0) {
636
if (strlen (value) > dir_entry_ptr->name_len) {
637
wprintw (command_win,"Error - Length of name greater then name_len\n");
638
refresh_command_win ();return;
640
strncpy (dir_entry_ptr->name,value,strlen (value));
641
wprintw (command_win,"Variable %s set to %s\n",variable,value);refresh_command_win ();
646
wattrset (show_pad,A_REVERSE);
647
strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len);
648
temp [dir_entry_ptr->name_len]=0;
649
wmove (show_pad,file_info.dir_entry_num,0);
650
wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n",
651
dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp);
652
wattrset (show_pad,A_NORMAL);
653
show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
659
wprintw (command_win,"Error - Variable %s not found\n",variable);
660
refresh_command_win ();
665
void type_dir___writedata (char *command_line)
669
We need to override this since the data is not in type_data. Instead, we have to write the buffer which corresponds
670
to the current block.
675
low_write (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);