gET iT i sAY .giis - ext3 File Undelete Tool
Author: Lakshmipathi.G
Description: Free File Undelete Tool or Recovery Tool for Linux ext3FS
Keywords: Linux File Undelete, ext3 File System, ext2 File System, File Recovery

### Quick Overview and Implementation of giis

### gET iT i sAY - giis

###

    							    By
    							    G.Lakshmipathi.
    							    <lakshmipathi_g@rediffmail.com>
    							    July 2005.

If you feel you need to know basic file system then read "Kick starting with file system" then come to this part which will help you to understand more quickly and most importantly "easily".
A little flashback,
When i got a system a year back started to learn on file system and trying for file recovery and De-fragmentation. De-fragmentation came to halt when i learned that Linux manages fragments on it's own. I read books again and again without going anywhere.Whenever i tried to access say an inode/super block i used to get same message "Segmentation Fault".
I was told by my teacher that one should know device drivers for file system operations so started to learn device driver a bit without going anywhere in device drivers and tried some LKM without success and my dream to access inode remains a dream.
Last month i read Gadi Oxman's EXT2ED and came across his doc part in which he says he don't how use device drivers then only i realized that device drivers are not needed to access file system.
Gadi Oxman's doc part helped me a lot to explore something with linux right now rather than just reading and reading about File system.The idea of this kind of documentation is inspired by Gadi Oxman doc part and beej.
Thanks Gadi Oxman and beej!!!. The name "get it i say" was decided more than year back for file recovery ( It's quite funny that i had nothing but project's name).
This version of gET iT i sAY -(giis) can recover files up to 8.04MB in size. This documentation will show how this giis is implemented. I try to explain everything-as far as possible- about giis here. First have a look at giis/giis.h file which have global variables and most important unions used through out giis. After few macros we come to unions like,

    union get_ext_super_block{
    	struct ext3_super_block sb;
    	char buffer[sizeof(struct ext3_super_block)];
    	}isb;

This is union will be used to read a super block into our buffer. Similar the case with following unions,

    union get_ext_group_desc{
    	struct ext3_group_desc gd;
    	char buffer[sizeof(struct ext3_group_desc)];
    	}igd;

    union get_ext_inode{
    	struct ext3_inode in;
    	char buffer[sizeof(struct ext3_inode)];
    	}iin;
    union get_ext_dir{
    	struct ext3_dir_entry_2 de;
    	char buffer[sizeof(struct ext3_dir_entry_2)];
    	}ide;

    All these unions provide most important data and they will be recorded in

    struct file_system{
    ...
    ...
    }fs;

This is THE most vital structure.Take a look at function prototypes in /giis/giis.h You will find that most functions don't take any parameter.Yes i did this intentionally in order to avoid so many arguments passing here and there.i want to keep this simple so that others can go through codes simply in the sequentital manner and easily understand.i guess this is not elegant coding but i tried my best to keep it simple so that quick understanding of concept is made without much headache =(:-}

    Then we have four unions,
    u_file_recover_info{}
    u_dir_recover_info{} and
    u_big_file_recover_info{}
    u_bigger_file_recover_info{}

In u_file_recover_info{} the members a self-explanatory.searchflag is used to denote whether the file is recovered or not. sindirect_block_hole indicates fragmen-tations on single indirect entry. In u_dir_recover_info{} the searchflag is used to denote which directories to examine. These two are used to record file and sub-directory information's of directory. Just have look at their members.

    union u_file_recover_info{
    struct s_file_recover_info{
    	char            date_time[30];		  /* When this entry recorded */
    	char            name[30];		  /* filename */
    	unsigned long	inode_number;		  /* inode number */
    	unsigned long   parent_inode_number;	  /* Directory inode number */
    	int             search_flag;		  /* Search flags*/
    	int             mode;			  /* File type */
    	int             owner;		  	  /* owner's uid */
    	unsigned long	file_blocks_count;	  /* Blocks count */
    	unsigned long	file_size;
    	unsigned long	file_flags;
    	unsigned long	data_block[EXT3_N_BLOCKS];/* Contents pointer */
    	unsigned long   sindirect_block_hole[10]; /* Single Indirect Block */
    	unsigned long   dindirect_block_hole[10]; /* Double indirect Block */
    	int             sfragment_flag;		  /* Which to use */
    	int 		dfragment_flag;
    	}info;
    char buffer[sizeof(struct s_file_recover_info)];
    }giis_f;

Say For example we recover a deleted file then to avoid retrieving the file again search_flag is used. sindirect_block_hole will record the blocks which are not in sequence.It's a {Index,Blocknumber} pair.Index specifies when to use the block_number. fragment_flag denotes which method to use in case of fragmented file.(soon we will what these methods are ).

    union u_dir_recover_info{
    struct s_dir_recover_info{
    	char  		date_time[30];		  /* When this entry recorded */
    	char            name[30];		  /* Directory	name */
    	unsigned long	inode_number;		  /* inode number */
    	unsigned long   parent_inode_number;	  /* Directory inode number */
    	int 		search_flag;		  /* Indicates entry search or not */
    	}info;
    char buffer[sizeof(struct s_dir_recover_info)];
    }giis_d;

Here search_flag will be used to indicate whether the directory is being in use or it is excluded from giis.This is achieved with the help of LEVEL_VALUE. LEVEL_VALUE specifies how many levels of directories to be included.For example, /home/lg LEVEL_VALUE is 2.
/home/lg/Desktop LEVEL_VALUE is 3.
/root/Desktop LEVEL_VALUE is 2. Default LEVEL_VALUE is 3. u_big_file_recover_info{} contains address of files that uses single indirect block. In case of file blocks are in sequence or it has less than minimum fragments we use u_file_recover_info and avoid u_big_file_recover_info to save space.
u_bigger_file_recover_info{} contains address of files that uses double indirect block. This also will be used if file has high fragments, if the file blocks are in sequence or minimum fragments then we don't use this to save space.

There are mainly four files which contains details needed by giis.

    /giis/sys/file_info_file ==> used by all files.
    /giis/sys/dir_info_file  ==> Has directory details.
    /giis/sys/sind_info_file ==> Has fragmented file details.
    /giis/sys/dind_info_file ==> Has fragmented file details.

sind_info_file and dind_info_file will be used only when it's absolutely necessary. All files will be updated and those details are used for file recovery.
Take look at main.c, it calls init() for some initialization activities like get file system number which in is root resides like /dev/hda6 by using search4fs() from /etc/mtab. Then searches for superblock using search4super_block() on offset 1024,after this set_file_system() will initialize member of the structure file_system. These structure members are used from here onwards. Then it searches for group descriptor and loads it using search4group_desc(). Then we creat or open files. That's it about init.c.
Next we know that root inode number is 2.Using this first find root inodes offset by invoking find_inode_offset() after some computation of group offset calls get_group_desc().

Code of find_inode_offset() is given below,

    int find_inode_offset()
    {
    int i;
    	fs.group_number=(fs.inode_number-1)/fs.inodes_per_group;
    	fs.index_number=(fs.inode_number-1)%fs.inodes_per_group;
    	fs.group_offset=fs.first_group_desc+fs.group_number*GROUP_DESC_SIZE;
    	i=get_group_desc();/* Get corresponding group values */
    	CHECK
    	fs.inode_offset=(unsigned long long)fs.inode_table*fs.block_size+fs.index_number*INODE_SIZE;
    	if(fs.inode_number==ROOT_INODE)
    		fs.root_inode_offset=fs.inode_offset;
    return 1;
    }

(I hope you know how about these entries if not see Kick starting with File system) From There we get root inode offset.Then read_inode() will load root inode into our buffer then call show_inode() to display some properties of root inode.
Then we have access entries of this file by using set_content_offset() is called. set_content_offset() as name suggests it sets offset of file to it's data. (We know that / has entries like bin,home,root,usr.....)
If it's inode is a directory then global variable dir is set for future use. Then use read_dir() to read directory whereas,if the inode is a file use read_show_file(). Remember directory contents is in a format of struct ext3_dir_entry_2{}.Use this structure to access directory contents.show_dir() is a important function which helps to record files and directories details.

    Note that these functions,
    find_inode_offset()
    read_inode()
    set_content_offset()
    read_dir()
    show_dir()

will be the same for all inodes. Just change fs.inode_number to appropriate number. The fs structure is used in all these functions.

show_dir() is most important procedure which stores all necessary details about files. In show_dir(),the directory entries are stored into DIR_INFO_FILE while file entries are stored into FILE_INFO_FILE for recovery actually fill up unions like,

    u_file_recover_info{}
    u_dir_recover_info{} and
    u_big_file_recover_info{}
    u_bigger_file_recover_info{}

From show_dir() call to record_file() used to store files while record_dir() used for directories. Here we call search4sequence12() to record those file which has size>48 KB and less than 4.04MB .
A call to search4sequence13() made to record those file which has size>4.04 MB and less than 8.04MB .
How files are searched:
First take look at search4dir() will search for a directory entry in DIR_INFO_FILE whose search_flag=1 (We set search_flag of home and root in show_dir() already.) So now take up home entries and record it into DIR_INFO_FILE if it's a directory or FILE_INFO_FILE if entry is a file. Then,call update_dir_info_file() to set these new directories to 1 with the help of get_parent_inode().So that these new directory contents are records.Interesting this update_dir_info_file called during installation.
Remember the LEVEL_VALUE limitation. Note that LEVEL_VALUE is used to record how many levels of directories to include in this file recovery.
If LEVEL_VALUE is 2 Then files from /home/lg or /root/Desktop is available of recovery.
If LEVEL_VALUE is 3 then one more level is added, so we can retrieve files from three levels say,/home/lg/Desktop files are recorded.
How files handled in giis:
Here is the most critical part,
First i planned giis for only unfragmented files with size less than 48KB. But still i just don't want to let other files being trashed away...
The major problem to provide support for larger files is space.It eats up lot of space. The solution must be found to avoid major space is being wasted and still support larger files.
During the course of this project i did some raw test and found that most of files has only less than five holes-Hole refer to non-consecutive block.
So i split up files into two types,
one which has fragmentation up to 5 holes(up to 5 block numbers are not in order) and another which has more than 5 holes fragmentation size.
If the file size less than 48KB don't need sindirect_block_hole[] or dindirect_block_hole[]. If the file has no hole or fragments then we don't need sindirect_block_hole[] or dindirect_block_hole[].
sindirect_block_hole[] or dindirect_block_hole[] will be used for files up to 5 holes of fragmentation thus we don't need the use of sind_info_file or dind_info_file thus saves plenty of space.
The sind_info_file or dind_info_file used only when fragment size goes beyond 5 holes. That's how fragmented files are managed.This is operations are performed by search4sequence12() and search4sequence13().source codes of both more or less same here it's code for search4sequence12().

    int search4sequence12(){
    unsigned long indirect_block[1024],prev;
    int i,hole,fp;
    hole=0;		/* Counts holes */

    	lseek64(fd,(unsigned long long )giis_f.info.data_block[12]*fs.block_size,0);
    	read(fd,indirect_block,fs.block_size);
    	prev=indirect_block[0];

    	if(indirect_block[0]-giis_f.info.data_block[12]!=1){
    		giis_f.info.sindirect_block_hole[hole]=0;
    		giis_f.info.sindirect_block_hole[hole+5]=indirect_block[0];
    		hole++;
    	}

    	if(prev!=0)
    for(i=1;i<1024;i++){

    		if(indirect_block[i]==0){
    				if(hole==0){
    				giis_f.info.sfragment_flag=1;
    				return(hole);
    				}

    				if(hole>0 && hole<5){
    				giis_f.info.sfragment_flag=2;
    				return(hole);
    				}

    		if(hole>5) /* Will be handled by SIND_INFO_FILE */
    		break;
    		}
    		if(indirect_block[i]-prev==1 && hole<5){
    			prev=indirect_block[i];
    			continue;
    			}
    	else{

    	if(hole>=5){
    	/* Highly fragmented so use giis_s n remove all entries sindirect_block_hole */

    		for(i=0;i<10;i++)
    		giis_f.info.sindirect_block_hole[i]=0;

    			/*Set values for file */
    		giis_f.info.sfragment_flag=3;

    		strcpy(giis_s.info.date_time,giis_f.info.date_time);
    		giis_s.info.inode_number=giis_f.info.inode_number;

    		for(i=0;i<1024;i++)
    		giis_s.info.sindirect_block[i]=indirect_block[i];

    			/*store */
    		fp=open(SIND_INFO_FILE,1);
    			if(fp==-1){
    				perror("Open:");
    				printf("Error no :%d",errno);
    				return -1;
    			}
    		lseek(fp,0,2);
    		i=write(fp,giis_s.buffer,GIIS_SSSIZE);
    			if(i!=GIIS_SSSIZE){
    				perror("write");
    				printf("Error no :%d",errno);
    				return -1;
    			}
    	close(fp);
    	return(hole);
    	}

    			giis_f.info.sindirect_block_hole[hole]=i;
    			giis_f.info.sindirect_block_hole[hole+5]=indirect_block[i];
    			hole++;
    			prev=indirect_block[i];
    	}

    }
    	if(hole==0){
    	giis_f.info.sfragment_flag=1;
    	return (hole);
    	}

    	if(hole>0 && hole<5){
    	giis_f.info.sfragment_flag=2;
    	return (hole);
    	}

    }

As you can see first computes offset and then keep track of holes if the hole goes up more than five then we use sind_info_file. search4sequence13() is also same except computation steps and uses dind_info_file. Both search4sequence12() and search4sequence13()plays a vital role.Here we actually test their sequence and set fragment_flags to appropriate values.
If file uses single indirect (giis_s.info.sfragment_flag=2) and it has up to 5 holes. It's combination of {index,block_number}. Blocknumber of Index is will be 5+index. if sindirect_block_hole[0]=244; then it's corresponding block number is at sindirect_block_hole[5+0]=12345; At index number 244 we should may jump to block numbered 12345. Similarly,sindirect_block_hole[1]=444;block number is at sindirect_block_hole[5+1]=34567 So jump to 34567 at 444 to avoid falling into hole :-}
dindirect_block_hole[] is similar to sindirect_block_hole[]. Note that we make these jumps in order to avoid accessing wrong data from other file.
Fragment_flags:
There are two fragment flags are used sfragment_flag and dfragment_flag which takes values ranges between 0 to 3. Some description on these values,

    giis_f.info.sfragment_flag=0 when file size less than 48 KB and not uses single indirect block
    giis_f.info.sfragment_flag=1 when file size up to 4.04 MB and no fragmentation at all.
    giis_f.info.sfragment_flag=2 when file size up to 4.04MB and it has up to 5 holes(some fragments)
    giis_f.info.sfragment_flag=3 when file size up to 4.04MB and highly fragmented.

    giis_f.info.dfragment_flag=0 when file size less than 4.04 MB and not uses double indirect block.
    giis_f.info.dfragment_flag=1 when file size up to 8.04 MB and no fragmentation at all.
    giis_f.info.dfragment_flag=2 when file size up to 8.04MB and it has up to 5 holes(some fragments)
    giis_f.info.dfragment_flag=3 when file size up to 8.04MB and highly fragmented.

So there are 16 combinations are possible. {s-fragment_flag,d_fragment_flag} Like,

     {0,0},{0,1},{0,2},{0,3}
     {1,0},{1,1},{1,2},{1,3}
     {2,0},{2,1},{2,2},{2,3}
     {3,0},{3,1},{3,2},{3,3}

But the following combinations are not possible,
{0,1},{0,2},{0,3}
So we have following 13 combinations for Handling a file.

     {0,0}
     {1,0},{1,1},{1,2},{1,3}
     {2,0},{2,1},{2,2},{2,3}
     {3,0},{3,1},{3,2},{3,3}

The most challenging part is to test all possible combinations and to figure out how giis reacts to it. The structure used to recover a larger-fragmented file is,

    union u_big_file_recover_info{
    struct s_big_file_recover_info{
    	char 		date_time[30];
    	unsigned long	inode_number;
    	unsigned long sindirect_block[1024];
    	}info;
    char buffer[sizeof(struct s_big_file_recover_info)];
    }giis_s;

    union u_bigger_file_recover_info{
    struct s_bigger_file_recover_info{
    	char 		date_time[30];
    	unsigned long	inode_number;
    	unsigned long dindirect_block[1024];
    	}info;
    char buffer[sizeof(struct s_bigger_file_recover_info)];
    }giis_t;

Most fragmented files refer that their data stored say at block number 10 then at block 12 then 13,14,15....18,250,251....We can recover these files.But Some files i guess stored like this,starts at block 500,501,(partially -some data but not all in-502 ),partial-555..... These kind of fragmentation - Really i don't know such thing of partial usage of block is used in file system.I don't how to get these types of files which seems to be fragmented within a block.If you know the reason then mail me.

i remember something about fragmented files, a year ago started and stop a project on disk defragmentation when i read in Bach's book that file system handles fragmentation on it's own by allocating a separate block for all fragmented files.
Here when trying to recover a fragment_flag=3 files giis throws up mixed data.Testing it on mp3 songs the result is mixture of some songs.So that might accessing one of those fragmented block used by linux and not a partially used block as said in previous para.Next version of giis will try to overcome this limitation.
How files recovered?

Two methods of recovering are,recovery from specific user files or recover all user files. Say for example,one wants to recover a user named "human" then only the deleted files that has owner as human will be recovered and other users deleted files will not be recovered.
If all users options is select then all files will be retrieved regardless of user.
get_it() performs about said actions.It also scans through inodes using verify_inode() in search of a deleted file. verify_inode() looks for i_links_count, and if it's zero then this is a deleted file. Here is code of verify_inode,

    /*
    * verify_inode() -  This is a helper file to get_it_i_say() this one verifies inode
    * is deleted or is being in use.
    */

    int verify_inode(unsigned long inode)
    {
    int i;
    fs.inode_number=inode;

    	i=find_inode_offset();
    		CHECK
    	i=read_inode();
    		CHECK
    	if(iin.in.i_links_count==0)
    		{
    		deleted_inode_offset=fs.inode_offset;
    		return 1;
    		}
    	else
    		return 0;

    }

If verify_inode() founds a deleted file then a call to get_it_i_say() is made for recovery.
Methods used in get_it_i_say():
In get_it_i_say() we get that deleted files details from file_info_file. then call to get_data_from_block() with appropriate values. get_data_from_block() has three parameters they are,

    first parameter  -- file descriptor in which data will be copied.
    second parameter -- file descriptor from which data will be taken.
    Third parameter  -- Block number  which has data.

get_data_from_block() returns file size.So we stop when size=0. Coding of get_it_i_say() is given here because it's an important part of giis. Note that sfragment_flag and dfragment_flag plays a vital role to find third parameter for get_data_from_block().

    int get_it_i_say()
    {
    int i,fp,fdes,fd,num,index,hole,ret,eof;
    unsigned long indirect_block;
    char name[75]="/giis/got_it/";

    	/* just always create a  new file */

    	strcat(name,giis_f.info.name);
    		fp=open(name,O_CREAT | O_RDWR | O_TRUNC);
    			if(fp==-1){
    				return -1;
    				}

    		fd=open(device_name,0);
    			if(fd==-1)
    			ERROR
    		i=0;
    		eof=1;
    		size=giis_f.info.file_size; /*  file size after every read  */

    	if(size>8433664){/* size>8.04MB.skip.*/
    		close(fp);
    		close(fd);
    		return 1;
    		}
    /* O.k examine what we did so far... creat a file and open a file.If size > 8.04 then
    we ignore that file.*/

    while((i<=14)&&eof){

    		/*Don't use fragment_flag Here */
    		/* Direct blocks so just call get_data_from_block */
    	if(i<12 && giis_f.info.data_block[i]!=0){
    				eof=get_data_from_block(fp,fd,i);
    				if(eof==0){
    				close(fp);
    				close(fd);
    				return 1;
    				}
    		}

    /*
     part 1:  single direct block are used so get into this block
     */

    	if(i==12 && giis_f.info.data_block[12]!=0){

    			indirect_block=giis_f.info.data_block[12];

    /*
    sfragment_flag=1 then that means block numbers of single indirect are in sequence so  just read by incrementing block numbers.
    */

    		if(giis_f.info.sfragment_flag==1){
    				while(eof){		/* Sequence */
    				indirect_block++;
    				eof=get_data_from_block(fp,fd,indirect_block);
    				if(eof==0){
    					close(fp);
    					close(fd);
    					return 1;
    					}
    				}
    		}

    /*
    sfragment_flag=2 So we have holes and must make some jumps with help of sindirect_block_hole[].
    if sindirect_block_hole[0]=123 Then it's corressponding block entry is at sindirect_block_hole[5+0]=44444.
    So indirect_block comes to entry number 123 we use this block number 44444.
    Then call get_data_from_block.

    Then go on incrementing until we reach next hole.i.e sindirect_block_hole[1] and make appropriate adjustments.
    */

    	if(giis_f.info.sfragment_flag==2){	/* holes here n there */

    				index=0;
    				num=0;
    				hole=giis_f.info.sindirect_block_hole[num];
    			while(eof){
    					if(index==hole && num<5){
    				       indirect_block=giis_f.info.sindirect_block_hole[num+5];
    					num++;
    					hole=giis_f.info.sindirect_block_hole[num];
    					}
    				else
    					indirect_block++;

    					index++;
    				eof=get_data_from_block(fp,fd,indirect_block);
    					if(eof==0){
    						close(fp);
    						close(fd);
    						return 1;
    					}
    			}
    	}

    /*
     sfragment_flag=3 so block number are at sind_info_file  so read from that file
     and make a call to get_data_from_block.
    */

    	if(giis_f.info.sfragment_flag==3){

    		fdes=open(SIND_INFO_FILE,0);
    				if(fdes==-1){
    					perror("open");
    					printf("\nError No : %d",errno);
    				}
    		ret=read(fdes,giis_s.buffer,GIIS_SSSIZE);
    				if(ret!=GIIS_SSSIZE){
    					perror("read");
    					printf("\n Error No:%d",errno);
    				}
    	while(ret>0){

    		if(giis_s.info.inode_number==giis_f.info.inode_number){
    		ret=0;
    		while(giis_s.info.sindirect_block[ret])	{
    		eof=get_data_from_block(fp,fd,giis_s.info.sindirect_block[ret]);
    					if(eof==0){
    						close(fd);
    						close(fp);
    						return 1;
    					}

    		ret++;
    		}
    		}
    		ret=read(fdes,giis_s.buffer,GIIS_SSSIZE);
    	 }
    	 }

    	}

    /*
    part 2:double indirect blocks are used so get into this block
    Here we deal same problem like part1.Major part is to increment indirect_block twice
    before calling get_data_from_block for first time.-That's the reason we call it as
    double indirect.
    If dfragment_flag=1 then used double indirect blocks are in sequence so just read by
    incrementing indirect_block.
    If dfragment_flag=2 then we have holes so use dindirect_block_hole[] at appropriate
    places.
    If dfragment_flag=3 then get block number from dind_info_file.

    */

    	if(i==13 && giis_f.info.data_block[13]!=0){

    			indirect_block=giis_f.info.data_block[13];
    			indirect_block++;
    		/* fragment_flag=1 just read by incrementing number */

    		if(giis_f.info.dfragment_flag==1){
    				while(eof){		/* Sequence */
    				indirect_block++;
    				eof=get_data_from_block(fp,fd,indirect_block);
    				if(eof==0){
    					close(fp);
    					close(fd);
    					return 1;
    					}
    				}
    		}

    		/* fragment_flag=2 read from file_info_file */

    	if(giis_f.info.dfragment_flag==2){	/* holes here n there */
    				index=0;
    				num=0;
    				hole=giis_f.info.dindirect_block_hole[num];
    			while(eof){
    					if(index==hole && num<5){
    				       indirect_block=giis_f.info.dindirect_block_hole[num+5];
    					num++;
    					hole=giis_f.info.dindirect_block_hole[num];
    					}
    				else
    					indirect_block++;

    					index++;
    				eof=get_data_from_block(fp,fd,indirect_block);
    					if(eof==0){
    						close(fp);
    						close(fd);
    						return 1;
    					}
    			}
    	}

    		/* fragment_flag=3 read from dind_info_file */

    	if(giis_f.info.dfragment_flag==3){

    		fdes=open(DIND_INFO_FILE,0);
    				if(fdes==-1){
    					perror("open");
    					printf("\nError No : %d",errno);
    				}
    		ret=read(fdes,giis_t.buffer,GIIS_DDSIZE);
    				if(ret!=GIIS_DDSIZE){
    					perror("read");
    					printf("\n Error No:%d",errno);
    				}
    	while(ret>0){

    		if(giis_t.info.inode_number==giis_f.info.inode_number){
    		ret=0;
    		while(giis_t.info.dindirect_block[ret]){
    		eof=get_data_from_block(fp,fd,giis_t.info.dindirect_block[ret]);
    					if(eof==0){
    						close(fd);
    						close(fp);
    						return 1;
    					}

    		ret++;
    		}
    		}
    		ret=read(fdes,giis_t.buffer,GIIS_DDSIZE);
    	 }
    	 }

    	}

    i++;

    }
    	close(fd);
    	close(fp);
    return 1;
    }

So a total recall,

If the file uses only direct block -giis_s.info.sfragment_flag=0 and giis_s.info.dfragment_flag=0 - so no problem just read their giis_f.info.data_block[]. If file uses single/double indirect but it's in sequence(s/d fragment_flag=1) then just read using by incrementing blocknumber. If a file (s/d fragment_flag=2) then read block number from sindirect_block_hole[] at necessary places. If a file (s/d fragment_flag=3) then read block number from s/dind_info_files. After getting block number all call get_data_from_block().

Code for get_data_from_block is,

    int get_data_from_block(int fp,int fd,unsigned long data_block){
    int group_number;
    unsigned long long device_block_number;

    	if(data_block<12)		/* Direct blocks */
    			fs.block_number=giis_f.info.data_block[data_block];
    	else
    			fs.block_number=data_block; /* Direct block */

    	if(fs.block_number!=0){

    	group_number=(giis_f.info.inode_number-1)/fs.inodes_per_group;
    	device_block_number=((fs.block_number-1)%fs.blocks_per_group)+group_number*fs.blocks_per_group;
    	device_block_number+=fs.first_data_block;
    	fs.content_offset=(unsigned long long )device_block_number*fs.block_size;
    	fs.content_offset+=fs.block_size;
    	lseek64(fd,fs.content_offset,0);
    	read_show_file(fd,fp);

    		if(size==0)
    				return 0;

    		else
    				return 444;/*... nothing special. my lucky number */
    	}

    }

get_data_from_block computes content_offset and makes a final call to read_show_file() to copy the data from given block number into the created file fp. read_show_file() reads in two ways block by block reading to reduce time and char by char reading for files with size less than block size.It returns file size,if size is zero then obvious we reached the end of file.

Code of read_show_file is,

    int read_show_file(int fd,int fp){
    int i,count=0;
    char buffer[4096],a;  /* buffer_size=fs.block_size */
    while((count<fs.block_size)&&(size>0)){

    			/*Reading char by char */

    	if(size<sizeof(buffer) && size>0){
    		i=read(fd,&a,1);
    		while(size && count<fs.block_size){
    			i=write(fp,&a,1);
    			if(i!=1)
    			ERROR
    			size--;
    			count++;
    			i=read(fd,&a,1);
    		}
    	}

    			/*Read block by block */

    	if(size>=sizeof(buffer)&&(count==0)){
    		i=read(fd,buffer,sizeof(buffer));
    		if(i!=sizeof(buffer))
    				ERROR
    		i=write(fp,buffer,sizeof(buffer));
    		if(i!=sizeof(buffer))
    				ERROR
    		size-=sizeof(buffer);
    		count=fs.block_size;

    	}
    }
    return(size);
    }

Thus the data is now recovered.
So this how giis is implemented to recover a file.
giis had/has/will have bugs... All that we can do is to decrease the bugs...
Due to time restrictions I'm ending this doc right here right now.For more refer giis codes.
Finally,i thank All those in Open source for keeping spirit Open source alive.
If you encounter any bugs (definitely you will)please mail me at <lakshmipathi_g@rediffmail.com> (I will get plenty of mails :-)
See also"Improved giis"