Whamcloud - gitweb
Remove trailing whitespace for the entire source tree
[tools/e2fsprogs.git] / ext2ed / dir_com.c
1 /*
2
3 /usr/src/ext2ed/dir_com.c
4
5 A part of the extended file system 2 disk editor.
6
7 --------------------
8 Handles directories.
9 --------------------
10
11 This file contains the codes which allows the user to handle directories.
12
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.
15
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.
18
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.
21
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.
24
25 First written on: April 28 1995
26
27 Copyright (C) 1995 Gadi Oxman
28
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "ext2ed.h"
36
37 char name_search [80];
38 long entry_num_search;
39
40 int init_dir_info (struct struct_file_info *info_ptr)
41
42 /*
43
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
46 directories.
47
48 */
49
50 {
51         struct ext2_inode *ptr;
52
53         ptr=&type_data.u.t_ext2_inode;                                  /* type_data contains the inode */
54
55         info_ptr->inode_ptr=ptr;
56         info_ptr->inode_offset=device_offset;                           /* device offset contains the inode's offset */
57
58                                                                         /* Reset the current position to the start */
59
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 */
65
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;
68
69         info_ptr->level=0;                                              /* We start using direct blocks */
70         info_ptr->display=HEX;                                          /* This is not actually used */
71
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;
74
75         /* Find dir_entries_count */
76
77         info_ptr->dir_entries_count=count_dir_entries ();               /* Set the total number of entries */
78
79         return (1);
80 }
81
82 struct struct_file_info search_dir_entries (int (*action) (struct struct_file_info *info),int *status)
83
84 /*
85         This is the main function in this source file. Various actions are implemented using this basic function.
86
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:
89
90                 ABORT           -       Current dir entry is returned.
91                 CONTINUE        -       Continue searching.
92                 FOUND           -       Current dir entry is returned.
93
94         If the last entry is reached, it is returned, along with an ABORT status.
95
96         status is updated to the returned code of action.
97 */
98
99 {
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;
103
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);
107
108         while (info.file_offset < info.file_length) {                           /* While we haven't reached the end */
109
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 */
114
115                                                                                 /* Pass to the next entry */
116
117                 dir_entry_ptr=(struct ext2_dir_entry_2 *) (info.buffer+info.dir_entry_offset);
118
119                 info.dir_entry_num++;
120                 next = dir_entry_ptr->rec_len;
121                 if (!next)
122                         next = file_system_info.block_size - info.dir_entry_offset;
123                 info.dir_entry_offset += next;
124                 info.file_offset += next;
125
126                 if (info.file_offset >= info.file_length) break;
127
128                 if (info.dir_entry_offset >= file_system_info.block_size) {     /* We crossed a block boundary */
129                                                                                 /* Find the next block, */
130                         info.block_num++;
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 */
136
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);
139
140                 }
141
142         }
143
144         *status=ABORT;return (info);                                            /* There was no match */
145 }
146
147 long count_dir_entries (void)
148
149 /*
150
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.
153
154 */
155
156 {
157         int status;
158
159         return (search_dir_entries (&action_count,&status).dir_entry_num);
160 }
161
162 int action_count (struct struct_file_info *info)
163
164 /*
165
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.
168
169 */
170
171 {
172         return (CONTINUE);                                                      /* Just continue searching */
173 }
174
175 void type_dir___cd (char *command_line)
176
177 /*
178         Changes to a directory, relative to the current directory.
179
180         This is a complicated operation, so I would repeat here the explanation from the design and
181         implementation document.
182
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.
185
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
187         1 and into 2/3/4.
188
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.
191
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.
195
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".
201
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.
204
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
207         as an argument.
208
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.
212
213 9.      In any other case, we just stop at the resulting inode.
214
215 */
216
217 {
218         int status;
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;
222
223         dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset);
224
225         ptr=parse_word (command_line,dir_name);
226
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;
230         }
231         else
232                 ptr=parse_word (ptr,full_dir_name);
233
234         ptr=strchr (full_dir_name,'/');
235
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;
238         }
239
240         if (ptr==NULL) {
241                 strcpy (dir_name,full_dir_name);
242                 full_dir_name [0]=0;
243         }
244
245         else {
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);
249         }
250                                                                 /* dir_name contains the current entry, while */
251                                                                 /* full_dir_name contains the rest */
252
253         strcpy (name_search,dir_name);                          /* name_search is used to hold the required entry name */
254
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. */
258         else {
259                 status=FOUND;info=file_info;
260         }
261
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 */
265
266                 dispatch ("followinode");                       /* Go to the inode pointed by this directory entry */
267
268                 if (S_ISLNK (type_data.u.t_ext2_inode.i_mode)) {/* Symbolic link ? */
269
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 ();
273                                 return;
274                         }
275                                                                 /* Get the pointed name and append the previous path */
276
277                         strcpy (temp2,(unsigned char *) &type_data.u.t_ext2_inode.i_block);
278                         strcat (temp2,"/");
279                         strcat (temp2,full_dir_name);
280
281                         dispatch ("recall internal_variable");  /* Return to the original inode */
282                         dispatch ("dir");                       /* and to the directory */
283
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) */
286
287                         return;
288                 }
289
290                 if (S_ISDIR (type_data.u.t_ext2_inode.i_mode)) { /* Is it an inode of a directory ? */
291
292                         dispatch ("dir");                       /* Yes - Pass to the pointed directory */
293
294                         if (full_dir_name [0] != 0) {           /* And call ourself with the rest of the pathname */
295                                 sprintf (temp,"cd %s",full_dir_name);
296                                 dispatch (temp);
297                         }
298
299                         return;
300                 }
301
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 ();
304                         return;
305                 }
306         }
307
308         wprintw (command_win,"Error - Directory entry %s not found.\n",dir_name);       /* Hmm, an invalid path somewhere */
309         refresh_command_win ();
310 }
311
312 int action_name (struct struct_file_info *info)
313
314 /*
315
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.
318
319 */
320
321 {
322         struct ext2_dir_entry_2 *dir_entry_ptr;
323
324         dir_entry_ptr=(struct ext2_dir_entry_2 *) (info->buffer+info->dir_entry_offset);
325
326         if (dir_entry_ptr->name_len != strlen (name_search))
327                 return (CONTINUE);
328
329         if (strncmp (dir_entry_ptr->name,name_search,dir_entry_ptr->name_len)==0)
330                 return (FOUND);
331
332         return (CONTINUE);
333 }
334
335 void type_dir___entry (char *command_line)
336
337 /*
338
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.
341
342 */
343
344 {
345         int status;
346         struct struct_file_info info;
347         char *ptr,buffer [80];
348
349         ptr=parse_word (command_line,buffer);
350         if (*ptr==0) {
351                 wprintw (command_win,"Error - Argument_not_specified\n");wrefresh (command_win);
352                 return;
353         }
354         ptr=parse_word (ptr,buffer);
355         entry_num_search=atol (buffer);
356
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);
359                 return;
360         }
361
362         info=search_dir_entries (&action_entry_num,&status);
363         if (status==FOUND) {
364                 file_info=info;
365                 dispatch ("show");
366                 return;
367         }
368 #ifdef DEBUG
369         internal_error ("dir_com","type_dir___entry","According to our gathered data, we should have found this entry");
370 #endif
371 }
372
373 int action_entry_num (struct struct_file_info *info)
374
375 /*
376
377 Used by the above function. Just compares the current number (in info) with the required one.
378
379 */
380
381 {
382         if (info->dir_entry_num == entry_num_search)
383                 return (FOUND);
384
385         return (CONTINUE);
386 }
387
388 void type_dir___followinode (char *command_line)
389
390 /*
391
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.
394
395 */
396 {
397         long inode_offset;
398         char buffer [80];
399
400         struct ext2_dir_entry_2 *dir_entry_ptr;
401
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);
404
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 */
408 }
409
410 void type_dir___inode (char *command_line)
411
412 /*
413
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 !
416
417 */
418
419 {
420         dispatch ("settype ext2_inode");
421 }
422
423
424 void type_dir___show (char *command_line)
425
426 /*
427
428 We use search_dir_entries to run on all the entries. Each time, action_show will be called to show one entry.
429
430 */
431
432 {
433         int status;
434
435         wmove (show_pad,0,0);
436         show_pad_info.max_line=-1;
437
438         search_dir_entries (&action_show,&status);
439         show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
440         refresh_show_pad ();
441         show_dir_status ();
442 }
443
444 int action_show (struct struct_file_info *info)
445
446 /*
447
448 Show the current search entry (info) in one line. If the entry happens to be the current edited entry, it is highlighted.
449
450 */
451
452 {
453         unsigned char temp [80];
454         struct ext2_dir_entry_2 *dir_entry_ptr;
455
456         dir_entry_ptr=(struct ext2_dir_entry_2 *) (info->buffer+info->dir_entry_offset);
457
458         if (info->dir_entry_num == file_info.dir_entry_num)                             /* Highlight the current entry */
459                 wattrset (show_pad,A_REVERSE);
460
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)
464                 temp [COLS-55]=0;
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);
467
468         show_pad_info.max_line++;
469
470         if (info->dir_entry_num == file_info.dir_entry_num)
471                 wattrset (show_pad,A_NORMAL);
472
473         return (CONTINUE);                                                              /* And pass to the next */
474 }
475
476 void type_dir___next (char *command_line)
477
478 /*
479
480 This function moves to the next directory entry. It just uses the current information and the entry command.
481
482 */
483
484 {
485         int offset=1;
486         char *ptr,buffer [80];
487
488         ptr=parse_word (command_line,buffer);
489
490         if (*ptr!=0) {
491                 ptr=parse_word (ptr,buffer);
492                 offset*=atol (buffer);
493         }
494
495         sprintf (buffer,"entry %ld",file_info.dir_entry_num+offset);dispatch (buffer);
496
497 }
498
499 void type_dir___prev (char *command_line)
500
501 {
502         int offset=1;
503         char *ptr,buffer [80];
504
505         ptr=parse_word (command_line,buffer);
506
507         if (*ptr!=0) {
508                 ptr=parse_word (ptr,buffer);
509                 offset*=atol (buffer);
510         }
511
512         sprintf (buffer,"entry %ld",file_info.dir_entry_num-offset);dispatch (buffer);
513 }
514
515 void show_dir_status (void)
516
517 /*
518
519 Various statistics about the directory.
520
521 */
522
523 {
524         long inode_num;
525
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);
530
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);
533
534         refresh_show_win ();
535 }
536
537 void type_dir___remember (char *command_line)
538
539 /*
540
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.
543
544 */
545
546 {
547         int found=0;
548         long entry_num;
549         char *ptr,buffer [80];
550         struct struct_descriptor *descriptor_ptr;
551
552         ptr=parse_word (command_line,buffer);
553
554         if (*ptr==0) {
555                 wprintw (command_win,"Error - Argument not specified\n");wrefresh (command_win);
556                 return;
557         }
558
559         ptr=parse_word (ptr,buffer);
560
561         entry_num=remember_lifo.entries_count++;
562         if (entry_num>REMEMBER_COUNT-1) {
563                 entry_num=0;
564                 remember_lifo.entries_count--;
565         }
566
567         descriptor_ptr=first_type;
568         while (descriptor_ptr!=NULL && !found) {
569                 if (strcmp (descriptor_ptr->name,"ext2_inode")==0)
570                         found=1;
571                 else
572                         descriptor_ptr=descriptor_ptr->next;
573         }
574
575
576         remember_lifo.offset [entry_num]=device_offset;
577         remember_lifo.type [entry_num]=descriptor_ptr;
578         strcpy (remember_lifo.name [entry_num],buffer);
579
580         wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr->name,device_offset,buffer);
581         wrefresh (command_win);
582 }
583
584 void type_dir___set (char *command_line)
585
586 /*
587
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.
590
591 */
592
593 {
594         int found=0;
595         unsigned char *ptr,buffer [80],variable [80],value [80],temp [80];
596         struct ext2_dir_entry_2 *dir_entry_ptr;
597
598         dir_entry_ptr=(struct ext2_dir_entry_2 *) (file_info.buffer+file_info.dir_entry_offset);
599
600         ptr=parse_word (command_line,buffer);
601         if (*ptr==0) {
602                 wprintw (command_win,"Error - Missing arguments\n");refresh_command_win ();
603                 return;
604         }
605         parse_word (ptr,buffer);
606         ptr=strchr (buffer,'=');
607         if (ptr==NULL) {
608                 wprintw (command_win,"Error - Bad syntax\n");refresh_command_win ();return;
609         }
610         strncpy (variable,buffer,ptr-buffer);variable [ptr-buffer]=0;
611         strcpy (value,++ptr);
612
613         if (strcasecmp ("inode",variable)==0) {
614                 found=1;
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 ();
617
618         }
619
620         if (strcasecmp ("rec_len",variable)==0) {
621                 found=1;
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 ();
624
625         }
626
627         if (strcasecmp ("name_len",variable)==0) {
628                 found=1;
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 ();
631
632         }
633
634         if (strcasecmp ("name",variable)==0) {
635                 found=1;
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;
639                 }
640                 strncpy (dir_entry_ptr->name,value,strlen (value));
641                 wprintw (command_win,"Variable %s set to %s\n",variable,value);refresh_command_win ();
642
643         }
644
645         if (found) {
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;
654                 refresh_show_pad ();
655                 show_dir_status ();
656         }
657
658         else {
659                 wprintw (command_win,"Error - Variable %s not found\n",variable);
660                 refresh_command_win ();
661         }
662
663 }
664
665 void type_dir___writedata (char *command_line)
666
667 /*
668
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.
671
672 */
673
674 {
675         low_write (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
676         return;
677 }