Jilin University operating system (Experiment 4: File System - Hash structure file)

Posted by amitsonikhandwa on Fri, 21 Jan 2022 11:57:17 +0100

Experiment 4: File System -- Hash structure file

Experimental purpose

1. Understand the internal technology of Linux file system, master Linux system call commands related to files, and establish hash structure files for random retrieval on this basis.

2. Linux system maintains the style of UNIX file system and provides streaming file interface. This structure has the characteristics of simplicity and flexibility, but it does not directly support record file and keyword retrieval. This experiment designs a set of library functions based on Linux file system to provide support for random retrieval.

Experimental content

1. Referring to the hash file construction algorithm in the textbook, a group of hash file functions are designed, including hash file creation, opening, closing, reading and writing.

2. Write a test program to check whether the above hash file realizes relevant functions through record saving, search, deletion and other operations.

Experimental preparation

1. Tutorial Hash file core algorithm, including record saving, record search, record deletion, etc.

2. Tutorial Linux system file system call commands: creat e, open, close, read, write, lseek.

experimental design

1. Because the hash file is simulated outside the Linux system core, the description information about the hash file cannot be saved in inode, but can only be recorded in the head of the file. This information includes hash file flag, record size, file length, number of records, etc.

2. Internal functions can be designed according to the hash file core algorithm, including record saving, searching, deletion, etc. on this basis, conventional operations such as reading and writing can be realized.

##Experimental code

hashfile.h

#ifndef HASHFILE_H
#define HASHFILE_H
 

#include<unistd.h>

#include<sys/stat.h>

#define COLLISIONFACTOR 0.5



struct HashFileHeader

{

int sig; //Seal of Hash document

int reclen; //Record length

int total_rec_num; //Total records

int current_rec_num; //Current records 

};

struct CFTag

{

char collision; //Conflict count

char free; //free token 

};



int hashfile_creat(const char *filename,mode_t mode,int reclen,int total_rec_num);

//int hashfile_open(const char *filename,int flags); 

int hashfile_open(const char *filename,int flags,mode_t mode);

int hashfile_close(int fd);

int hashfile_read(int fd,int keyoffset,int keylen,void *buf);

int hashfile_write(int fd,int keyoffset,int keylen,void *buf);

int hashfile_delrec(int fd,int keyoffset,int keylen,void *buf);

int hashfile_findrec(int fd,int keyoffset,int keylen,void *buf);

int hashfile_saverec(int fd,int keyoffset,int keylen,void *buf);

int hash(int keyoffset,int keylen,void *buf,int total_rec_num);

int checkHashFileFull(int fd);

int readHashFileHeader(int fd,struct HashFileHeader *hfh);
#endif

hashfile.c

//hashfile.c
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include"HashFile.h"

int hashfile_creat(const char *filename,mode_t mode,int reclen,int total_rec_num)
{
struct HashFileHeader hfh;
int fd;
int rtn;
char *buf;
int i=0;
hfh.sig = 31415926;
hfh.reclen = reclen;
hfh.total_rec_num = total_rec_num;
hfh.current_rec_num = 0;
//fd = open(filename,mode);
fd = creat(filename,mode);
if(fd != -1)
{
rtn = write(fd,&hfh,sizeof(struct HashFileHeader));
//lseek(fd,sizeof(struct HashFileHeader),SEEK_SET);
if(rtn != -1)
{
buf = (char*)malloc((reclen+sizeof(struct CFTag))*total_rec_num);
memset(buf,0,(reclen+sizeof(struct CFTag))*total_rec_num);   
rtn = write(fd,buf,(reclen+sizeof(struct CFTag))*total_rec_num);
free(buf);
}
close(fd);
return rtn;
}
else{
close(fd);
return -1;
}
}

int hashfile_open(const char *filename,int flags,mode_t mode)
{
int fd = open(filename,flags,mode);
struct HashFileHeader hfh;
if(read(fd,&hfh,sizeof(struct HashFileHeader))!= -1)
{
lseek(fd,0,SEEK_SET);
if(hfh.sig == 31415926)
return fd;
else
return -1;
}
else return -1;
}
int hashfile_close(int fd)
{
return close(fd);
}
int hashfile_read(int fd,int keyoffset,int keylen,void *buf)
{
struct HashFileHeader hfh;
readHashFileHeader(fd,&hfh);
int offset = hashfile_findrec(fd,keyoffset,keylen,buf);
if(offset != -1)
{
lseek(fd,offset+sizeof(struct CFTag),SEEK_SET);
return read(fd,buf,hfh.reclen);
}
else
{
return -1;
}
}
int hashfile_write(int fd,int keyoffset,int keylen,void *buf)
{
return hashfile_saverec(fd,keyoffset,keylen,buf);
//return -1;
}
int hashfile_delrec(int fd,int keyoffset,int keylen,void *buf)
{
int offset;
offset = hashfile_findrec(fd,keyoffset,keylen,buf);
if(offset != -1)
{
struct CFTag tag;
read(fd,&tag,sizeof(struct CFTag));
tag.free =0; //Set idle flag 
lseek(fd,offset,SEEK_SET);
write(fd,&tag,sizeof(struct CFTag));
struct HashFileHeader hfh;
readHashFileHeader(fd,&hfh);
int addr = hash(keyoffset,keylen,buf,hfh.total_rec_num);
offset = sizeof(struct HashFileHeader)+addr*(hfh.reclen+sizeof(struct CFTag));
if(lseek(fd,offset,SEEK_SET)==-1)
return -1;
read(fd,&tag,sizeof(struct CFTag));
tag.collision--; //Conflict count minus 1
lseek(fd,offset,SEEK_SET);
write(fd,&tag,sizeof(struct CFTag));
hfh.current_rec_num--; //Current records minus 1
lseek(fd,0,SEEK_SET);
write(fd,&hfh,sizeof(struct HashFileHeader));
}
else{
return -1;
}
}

int hashfile_findrec(int fd,int keyoffset,int keylen,void *buf)
{
struct HashFileHeader hfh;
readHashFileHeader(fd,&hfh);
int addr = hash(keyoffset,keylen,buf,hfh.total_rec_num);
int offset = sizeof(struct HashFileHeader)+addr*(hfh.reclen+sizeof(struct CFTag));
if(lseek(fd,offset,SEEK_SET)==-1)
return -1;
struct CFTag tag;
read(fd,&tag,sizeof(struct CFTag));
char count = tag.collision;
if(count==0)
return -1; //non-existent
recfree:
if(tag.free == 0)
{
offset += hfh.reclen+sizeof(struct CFTag);
if(lseek(fd,offset,SEEK_SET)==-1)
return -1;
read(fd,&tag,sizeof(struct CFTag));
goto recfree;
}
else{
char *p =(char*)malloc(hfh.reclen*sizeof(char));
read(fd,p,hfh.reclen);
//printf("Record is {%d , %s}\n",((struct jtRecord *)p)->key,((struct jtRecord *p)->other);
char *p1,*p2;
p1 = (char *)buf+keyoffset;
p2 = p + keyoffset;
int j=0;
while((*p1 == *p2)&&(j<keylen))
{
p1++;
p2++;
j++;
}
if(j==keylen)
{
free(p);
p = NULL;
return(offset);
}
else{
if(addr == hash(keyoffset,keylen,p,hfh.total_rec_num))
{
count--;
if(count == 0)
{
free(p);
p = NULL;
return -1;//non-existent 
}
}
free(p);
p = NULL;
offset += hfh.reclen+sizeof(struct CFTag);
if(lseek(fd,offset,SEEK_SET) == -1)
return -1;
read(fd,&tag,sizeof(struct CFTag));
goto recfree;
}
}
}
int hashfile_saverec(int fd,int keyoffset,int keylen,void *buf)
{
if(checkHashFileFull(fd))
{
return -1;
}
struct HashFileHeader hfh;
readHashFileHeader(fd,&hfh);
int addr = hash(keyoffset,keylen,buf,hfh.total_rec_num);
int offset = sizeof(struct HashFileHeader)+addr*(hfh.reclen+sizeof(struct CFTag));
if(lseek(fd,offset,SEEK_SET)==-1)
return -1;
struct CFTag tag;
read(fd,&tag,sizeof(struct CFTag));
tag.collision++;
lseek(fd,sizeof(struct CFTag)*(-1),SEEK_CUR);
write(fd,&tag,sizeof(struct CFTag));
while(tag.free!=0) //Conflict, sequential probe
{
offset += hfh.reclen+sizeof(struct CFTag);
if(offset >= lseek(fd,0,SEEK_END))
offset = sizeof(struct HashFileHeader); //reach at and,then rewind
if(lseek(fd,offset,SEEK_SET)==-1)
return -1;
read(fd,&tag,sizeof(struct CFTag));
} 
tag.free =-1;
lseek(fd,sizeof(struct CFTag)*(-1),SEEK_CUR);
write(fd,&tag,sizeof(struct CFTag));
write(fd,buf,hfh.reclen);
hfh.current_rec_num++;
lseek(fd,0,SEEK_SET);
return write(fd,&hfh,sizeof(struct HashFileHeader));  //Deposit record 
}

int hash(int keyoffset,int keylen,void *buf,int total_rec_num)
{
int i=0;
char *p =(char*)buf+keyoffset;
int addr =0;
for(i=0;i<keylen;i++)
{
addr += (int)(*p);
p++;
}
return addr%(int)(total_rec_num*COLLISIONFACTOR);
}

int checkHashFileFull(int fd)
{
struct HashFileHeader hfh;
readHashFileHeader(fd,&hfh);
if(hfh.current_rec_num<hfh.total_rec_num)
return 0;
else
return 1;
}
int readHashFileHeader(int fd,struct HashFileHeader *hfh)
{
lseek(fd,0,SEEK_SET);
return read(fd,hfh,sizeof(struct HashFileHeader));
}

jtRecord.h

//jtRecord.h
#define RECORDLEN 32

struct jtRecord
{
int key;
char other[RECORDLEN-sizeof(int)];
};

#ifdef HAVE_CONFIG_H
#include<config.h>
#endif

jtRecord.c

//jtRecord.c
#ifdef HAVE_CONFIG_H
#include<config.h>
#endif

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

#include"HashFile.h"
#include"jtRecord.h"
#define KEYOFFSET 0
#define KEYLEN sizeof(int)
#define FileNAME "jing.hash"

void showHashFile();

int main(int argc,char *argv[])
{
struct jtRecord rec[6] = {
{1,"jing"},{2,"wang"},{3,"li"},
{4,"zhang"},{5,"qing"},{6,"yuan"}
};
int j=0;
for(j=0;j<6;j++)
{
printf("<%d,%d>\t",rec[j].key,hash(KEYOFFSET,KEYLEN,&rec[j],6));
}
int fd = hashfile_creat(FileNAME,O_RDWR|O_CREAT,RECORDLEN,6);
int i=0;
printf("\nOpen and Save Record...\n");
fd = hashfile_open(FileNAME,O_RDWR,0);
for(i=0;i<6;i++)
{
hashfile_saverec(fd,KEYOFFSET,KEYLEN,&rec[i]);
}
hashfile_close(fd);
showHashFile();
//Demo find Rec
printf("\nFind Record...");
fd = hashfile_open(FileNAME,O_RDWR,0);
int offset = hashfile_findrec(fd,KEYOFFSET,KEYLEN,&rec[4]);
printf("\noffset is %d\n",offset);
hashfile_close(fd);
struct jtRecord jt;
struct CFTag tag;
fd = open(FileNAME,O_RDWR);
lseek(fd,offset,SEEK_SET);
read(fd,&tag,sizeof(struct CFTag));
printf("Tag is <%d,%d>\t",tag.collision,tag.free);
read(fd,&jt,sizeof(struct jtRecord));
printf("Record is {%d,%s}\n",jt.key,jt.other);
//Demo Delete Rec
printf("\nDelete Record...");
fd = hashfile_open(FileNAME,O_RDWR,0);
hashfile_delrec(fd,KEYOFFSET,KEYLEN,&rec[2]);
hashfile_close(fd);
showHashFile();
//Demo Read
fd = hashfile_open(FileNAME,O_RDWR,0);
char buf[32];
memcpy(buf,&rec[1],KEYLEN);
hashfile_read(fd,KEYOFFSET,KEYLEN,buf);
printf("\nRead Record is {%d,%s}\n",
((struct jtRecord *)buf)->key,((struct jtRecord *)buf)->other);
hashfile_close(fd);
//Demo Write
printf("\nWrite Record...");
fd = hashfile_open(FileNAME,O_RDWR,0);
hashfile_write(fd,KEYOFFSET,KEYLEN,&rec[3]);
hashfile_close(fd);
showHashFile();
return 0;
}

void showHashFile()
{
int fd;
printf("\n");
fd = open(FileNAME,O_RDWR);
lseek(fd,sizeof(struct HashFileHeader),SEEK_SET);
struct jtRecord jt;
struct CFTag tag;
while(1)
{
if(read(fd,&tag,sizeof(struct CFTag))<=0)
break;
printf("Tag is <%d,%d>\t",tag.collision,tag.free);
if(read(fd,&jt,sizeof(struct jtRecord))<=0)
break;
printf("Record is {%d,%s}\n",jt.key,jt.other);
}
close(fd);
}

Result output

It should be noted here that when compiling, it should be run under the administrator authority (root) (switch with the command su), because the program needs to run the system call of the file (create, write, etc.)

Thinking questions

Imitate the function of Linux system sink device (/ dev/null /), write a device driver module, and actually load the program module, corresponding to / dev/null0.
Add a device driver at the source code level, that is, download a linux source code, compile the device driver you wrote with the Linux source code, generate an executable file, and then run it. The characteristics of two methods of adding device driver are compared.

Topics: Operating System