Linux下回收站的设计与实现

 

Linux下回收站的设计与实现

 

概要:

学习Linux有一段时间了,最初为了更好的学习Linuxghost了原先的WinXp,安装了fedora 7,但最后还是忍无可忍把它卸了(想把Linux作为桌面系统人大概都知道为什么吧)并在Xp下装了VM。因为配置不高,我的电脑运行VM是很吃力的(不比蜗牛快多少,汗),所以能在文本模式下操作的都尽量在文本模式下操作。

前几天一个不小心把很重要的文件给删了,在整整郁闷了240s后,最终决定写一个能在文本模式下操作的回收站。

功能介绍:

insert photo

recycle.setup: 安装回收站程序、创建相应的文件夹和文件

recycle.uninstall:  卸载回收站

recycle.clean:清空该用户的回收站

recycle.del file1 file2 … filen :  删除文件file1, file2 … filen并移至回收站

recycle.restore file1 file2 … filen: 还原文件file1, file2 … filen

recycle.show:显示该用户回收站中的信息

 

工作流程:

1.         删除文件或文件夹(recycle.del

当用户要删除某个文件时,我们使用系统调用rename将文件移动到回收站的根目录下(/.recycle/),待用户需要时再将其还原。这样存在着一些问题:首先,用户可能删除具有相同文件名的文件,显然我们无法将它们一起放到/.recycle文件夹下面。其次,因为Linux是一个多用户的操作系统,一个用户(root出外)不因该有权限访问或修改他人的回收站中的内容。

对于第一个问题我们可以这样:当用户删除文件后,我们并不直接将其移动到回收站而是把它按照事先定义的重新命名方式将被删除文件重命名后再移动到回收站。为此再回收站目录下建立一个文本文件infotable,它保存如下信息:原始路径,重命名后的文件名,删除的日期。当删除文件时先向infotable注册一条新记录,如果注册成功则将文件移动到回收站下并重命名为新文件名。为了得到不重复的新文件名,再新建一个文本文件avaitable,它保存有一组数值(如:1224345522……),表示所新删除的文件可以取这些数值做为新的文件名,并保证它们不会重复。

对于安全性我们可以为每个用户建立一个文件夹,命名为该用户的ID号。文件夹的属性为“drwx------”并再各文件夹下保存有各自的infotableavaitable

删除文件的工作流程见下图:

2.         还原文件或文件夹(recycle.restore)

用户同过参数告诉还原程序要恢复文件的新文件名,还原程序再infotable表中查找它的原始路径,并将其重新移动到路径上去;再该文件的新文件名追加到avaitable文件中(说明该文名可以用了),最后删除文件infotable中的相关记录。

恢复文件流程见下图:

3.         安装以及初始化(recycle.setup)

首先root允许recycle.setup程序,该程序新建一个/.recycle文件夹(mode=0777)并复制回收站程序到/usr/bin目录下。

普通用户初次使用时也要先运行recycle.setup,它根据用户的ID/.recycle下创建一个子文件夹,接着建立一个空的infotableavaitable文件,最后将约定的数字写入到avaitable文件中,数据间以换行分隔。

4.         显示回收站信息(recycle.show)

用户输入命令reclcye.show,程序显示读取infotable文件并根据需求显示出用户所需的信息。

5.         清空用户回收站(recycle.clear

每个用户只有清空自己回收站的权力,清空回收站程序首先得到该用户的ID,接着删除该用户在/.recycle文件夹,最后重新关键avaitableinfotable文件。

回收站目录结构:

数据结构:

infotbale文件中存放的数据结构

struct information{

       char path[PATH_MAX];    //被删除的文件的原始位置

char newname[NEWNAMELEN];  //新文件名

       date_t time;  //被删除的日期

}

 

源代码:

 

/************************************************
 * common.h 
 * this file include and define most useful file and macro
*************************************************
*/


#include
< stdio.h >
#include
< dirent.h >
#include
< unistd.h >
#include
< stdlib.h >
#include
< sys / types.h >
#include
< fcntl.h >
#include
< string .h >
#include
< time.h >


// #define TESTDEL
// #define TESTRES
// #define TESTCLE

// 显示错误信息
#define  oop(msg)    {perror(msg);}
#define  oope(msg)    {perror(msg);exit(1);}
#define  oopr(msg) {perror(msg);return ;}


// 要安装的命令
#define  OCOMMDEL "./recycle.del"
#define  OCOMMSHO "./recycle.show"
#define  OCOMMRES "./recycle.restore"
#define  OCOMMUNI "./recycle.uninstall"
#define  OCOMMSET "./recycle.setup"
#define  OCOMMCLE "./recycle.clear"
// 要复制的新路径
#define  NCOMMCLE "/usr/bin/recycle.clear"
#define  NCOMMDEL "/usr/bin/recycle.del"
#define  NCOMMSHO "/usr/bin/recycle.show"
#define  NCOMMRES "/usr/bin/recycle.restore"
#define  NCOMMUNI "/bin/recycle.uninstall"
#define  NCOMMSET "/usr/bin/recycle.setup"


#define  RECPATH "/.recycle"
#define  INFOTAB "infotable"
#define  AVAITAB "avaitable"
#define  INFOTMP "infotmp"


#define  AVAIMAX 10     // 回收站最大支持的文件数
#define  PATH_MIN 32
#define  NEWNAMELEN 4


struct  information {
    time_t time;
    
char newname[NEWNAMELEN];
    
char oldpath[PATH_MAX];
}
;

 

 

/****************************************
 *clear.c
****************************************
*/



#include
" common.h "


void  commUser(uid_t uid) {
    
char path[PATH_MIN];
    
int fd;
    FILE 
*fp;
    
int avai;
//make user's private directory
    snprintf(path,PATH_MIN,"%s/%d",RECPATH,uid);
    
if(mkdir(path,0700)!=0)    oope("make user's directory error: ");
    chdir(path);
//make user's infotable file
    fd=open(INFOTAB,O_WRONLY|O_CREAT|O_EXCL,0700);
    
if(fd==-1)    oope("create infomation table error: ");
    close(fd);
//make user's avaitable file
    fp=fopen(AVAITAB,"w");
    
if(fp==NULL)    oope("can not use stream: ");
    
for(avai=0;avai<AVAIMAX;avai++)
        
if(fprintf(fp,"%d ",avai)<0)    perror("write avaitab error: ");
    fclose(fp);
}


int  main() {
    uid_t uid;
    
char path[PATH_MIN];
    uid
=getuid();
    snprintf(path,PATH_MIN,
"%s/%d",RECPATH,uid);
    
if(fork()==0){
        execlp(
"rm","rm","-rf",path,NULL);
    }

    
else{
        wait(NULL);
        commUser(uid);
    }

}

 

 

/**********************************************
 * del.c
**********************************************
*/


#include
" common.h "

uid_t uid;


void   lock ();
void  unlock();
void  delete();
int  getAvai(); // get a availavle file name from avaitable file
void  setAvai(); // update avaitable file
int  logInfotab(); // write information to infotable file

int  logInfotab( char   * oldpath, char   * newname) {
    
int fd;
    
char infopath[PATH_MIN];
    
struct information info;
    snprintf(infopath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,INFOTAB);
    fd
=open(infopath,O_WRONLY|O_APPEND);
    
if(fd==-1return -1;
    strcpy(info.oldpath,oldpath);
    strcpy(info.newname,newname);
    time(
&info.time);
    write(fd,
&info,sizeof(info));
#ifdef TESTDEL
    printf(
"write to infotable: %s %s %s",info.oldpath,info.newname,ctime(&info.time));
#endif
    
return 0;
}


void  setAvai() {
    
int len;
    FILE 
*fp1,*fp2;
    
char avaipath[PATH_MIN],temppath[PATH_MIN],buf[NEWNAMELEN];
    snprintf(avaipath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,AVAITAB);
    fp1
=fopen(avaipath,"r");
    
if(fp1==NULL)    oope(avaipath);
    snprintf(temppath,PATH_MIN,
"%s/%d/temp",RECPATH,uid);
    fp2
=fopen(temppath,"w");
    
if(fp2==NULL)    oope(temppath);
#ifdef TESTDEL
    printf(
"open %s open %s ",avaipath,temppath);
#endif
    fgets(buf,NEWNAMELEN,fp1);
    
while(fgets(buf,NEWNAMELEN,fp1)!=NULL)
        fputs(buf,fp2);
    fclose(fp1);
    fclose(fp2);
    unlink(avaipath);
    rename(temppath,avaipath);
//    unlink(avaipath);
}



int  getAvai( char   * newname) {
    
int len;
    FILE 
*fp;
    
char avaipath[PATH_MIN];
    snprintf(avaipath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,AVAITAB);
    fp
=fopen(avaipath,"r");
    
if(fgets(newname,NEWNAMELEN,fp)==NULL) return -1;
    newname[strlen(newname)]
='

 

/********************************************
 * restore.c
********************************************
*/



#include
" common.h "

uid_t uid;

int  main( int  ac, char   * av[]) {
    
char flag[ac];
    
struct information infobuf;
    FILE 
*fpi,*fpt,*fpa;
    
char infopath[PATH_MIN],temppath[PATH_MIN],avaipath[PATH_MIN];
    
char namepath[PATH_MAX],namebuf[NEWNAMELEN];
    size_t infosize;
    
int i,count;
//initalization
    uid=getuid();
    snprintf(infopath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,INFOTAB);
    fpi
=fopen(infopath,"r");
    
if(fpi==NULL)    oope(infopath);
    snprintf(temppath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,INFOTMP);
    fpt
=fopen(temppath,"w");
    
if(fpt==NULL)    oope(temppath);
    snprintf(avaipath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,AVAITAB);
    fpa
=fopen(avaipath,"a");
    
if(fpa==NULL)    oope(avaipath);
    bzero(flag,ac);
    infosize
=sizeof(struct information);
    count
=0;
//begin to restore
    while(fread(&infobuf,infosize,1,fpi)>0){
        
for(i=1;i<ac;i++{
            
if(flag[1]!=0continue;
            
if(strcmp(av[i],infobuf.newname)==0)  break;
        }

        
if(i==ac){    //not found information
            fwrite(&infobuf,infosize,1,fpt);
        }

        
else{    //found information
            strcpy(namebuf,infobuf.newname);
            snprintf(namepath,PATH_MAX,
"%s/%d/%s",RECPATH,uid,infobuf.newname);
#ifdef TESTRES
        printf(
"rename from '%s' to '%s' ",namepath,infobuf.oldpath);
#endif
            
if(rename(namepath,infobuf.oldpath)!=0)
                oope(infobuf.oldpath);                                    
        fprintf(fpa,
"%s ",namebuf);
        }

    }

    
while(fread(&infobuf,infosize,1,fpi)>0{
        fwrite(
&infobuf,infosize,1,fpt);
    }

    remove(infopath);
    rename(temppath,infopath);
    fclose(fpi);
    fclose(fpa);
}










 

 

/**********************************************************
* setup.c
**********************************************************
*/


#include
" common.h "

void  commUser();
void  superUser();


void  superUser(uid_t uid) {
    
if(link(OCOMMDEL,NCOMMDEL)!=0) oope("copy command recycle.delete error: ");
    
if(link(OCOMMSHO,NCOMMSHO)!=0) oope("copy command recycle.show error: ");
    
if(link(OCOMMRES,NCOMMRES)!=0) oope("copy command recycle.restore error: ");
    
if(link(OCOMMSET,NCOMMSET)!=0) oope("copy command recycle.setup error: ");    
    
if(link(OCOMMUNI,NCOMMUNI)!=0) oope("copy command recycle.uninstall error: ");    
    
if(link(OCOMMCLE,NCOMMCLE)!=0) oope("copy command recycle.clear error: ");
    chmod(NCOMMUNI,
0700);
    
if(mkdir(RECPATH,0777)!=0)  oope("make diretory /.recycle error: ");
    chmod(RECPATH,
0777);
    commUser(uid);
}


void  commUser(uid_t uid) {
    
char path[PATH_MIN];
    
int fd;
    FILE 
*fp;
    
int avai;
//make user's private directory
    snprintf(path,PATH_MIN,"%s/%d",RECPATH,uid);
    
if(mkdir(path,0700)!=0)    oope("make user's directory error: ");
    chdir(path);
//make user's infotable file
    fd=open(INFOTAB,O_WRONLY|O_CREAT|O_EXCL,0700);
    
if(fd==-1)    oope("create infomation table error: ");
    close(fd);
//make user's avaitable file
    fp=fopen(AVAITAB,"w");
    
if(fp==NULL)    oope("can not use stream: ");
    
for(avai=0;avai<AVAIMAX;avai++)
        
if(fprintf(fp,"%d ",avai)<0)    perror("write avaitab error: ");
    fclose(fp);
}


int  main( int  ac, char   * av[]) {
    uid_t uid;
    uid
=getuid();
    
if(uid==0)  superUser(uid);
    
else commUser(uid);
    puts(
"setup finished");
}

 

 

/*************************************
 * show.c
************************************
*/


#include
" common.h "

#define  MAXLINE 15

short  showtime = 0 ;
uid_t uid;
char  infopath[PATH_MIN];


int  main( int  ac, char   * av[]) {
    FILE 
*fp;
    
int n;
    
struct information info;
    uid
=getuid();
    snprintf(infopath,PATH_MIN,
"%s/%d/%s",RECPATH,uid,INFOTAB);
    fp
=fopen(infopath,"r");
    
if(fp==NULL)    oope(infopath);
    
if(ac!=1) showtime=1;
    n
=0;
    
while(fread(&info,sizeof(info),1,fp)>0){
        printf(
"%s %s ",info.newname,info.oldpath);
        
if(showtime)    printf("%s",ctime(&info.time));
        
else printf(" ");
    }

}


 

 

/****************************************************
 * uninstall.c
***************************************************
*/


#include
" common.h "

int  main() {
    
char c;
    puts(
"warning: if you want to uninstall recycle, all files belong to it will faild.");
    puts(
"input y/Y to ensure unistall, other will exit uninstall");
    c
=getchar();
    
if(c!='y' && c!='Y') exit(0);
    unlink(NCOMMDEL);
    unlink(NCOMMSHO);
    unlink(NCOMMRES);
    unlink(NCOMMUNI);
    unlink(NCOMMSET);
    unlink(NCOMMCLE);
    
if(fork()==0)    {execlp("rm","rm","-rf",RECPATH,NULL);}
    
else {wait(NULL);puts("uninstall success");}
    
}

 

 

/*******************************
 * make.sh
********************************
*/



#
!/ bin / tcsh
gcc 
- o recycle.setup setup.c
gcc 
- o recycle.uninstall uninstall.c
gcc 
- o recycle.del del.c
gcc 
- o recycle.show show.c
gcc 
- o recycle.restore restore.c
gcc 
- o recycle.clear clear.c
recycle.uninstall
.
/ recycle.setup
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值