Linux下回收站的设计与实现

原创 2007年09月29日 20:28:00

 

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

Access建表SQL语句Create Table设置自动增长列的关键字AUTOINCREMENT使用方法

Access建表SQL语句Create Table设置自动增长列的关键字AUTOINCREMENT使用方法SQL AUTO INCREMENT 字段uto-increment 会在新记录插入表中时生成...

linux下默认删除文件到回收站(bash实现)

fedora下总是会把文件不小心删除了,所以下面的脚本把实现:文件删除默认移动到自己的回收站里面。 功能: 脚本实现删除文件或者目录到~/waste/(自己定义)。 脚本附带文件名或...

将linux下的rm命令改造成移动文件至回收站

将linux下的rm命令改造成移动文件至回收站 rm是Linux下文件删除的命令,它是Linux下非常强大却又非常危险的一条命令,特别是rm -rf有时候强大到让你欲哭无泪,当你想清除当前目录下的所...

Linux 终端命令 rm 删除的文件进入回收站实现方法

Linux 终端命令 rm 删除的文件进入回收站实现方法 作者: Venus | 时间: 2010-11-14 | 分类: IT技术, Linux | 分享次数: 587...
  • ymwugui
  • ymwugui
  • 2011年12月19日 02:15
  • 1968

回收站功能在 Linux 中的实现

本文仿照 Windows 回收站的功能,运用 Bash 脚本在 Linux 上做了实现,创建 delete 脚本代替 rm 命令对文件或目录进行删除操做。该脚本实现了以下功能:对大于 2G 的文件或目...
  • sdulibh
  • sdulibh
  • 2015年06月02日 09:50
  • 447

Linux下Boot Loader的设计与实现

  • 2014年10月24日 11:44
  • 385KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux下回收站的设计与实现
举报原因:
原因补充:

(最多只允许输入30个字)