linux C实现cp功能

一:背景

看了unix/linux编程实践,跟着书上代码实现了普通文件的拷贝,看到课后习题后需要实现目录之间的拷贝,因此有了本文,我最初实现cp用了180多行代码,后来觉得很多地方可以封装,但是最后居然越封装越多达到了200多行,今晚果断再次封装,修剪了代码大概170多行,要比课后答案的要简便点。该cp可以实现普通文件的拷贝,拷贝到指定目录下,和目录直接拷贝等功能。

二:思路

目录之间的拷贝我觉得最主要的功能就是path路径的拼装,处理好path路径问题,就很简单了。例如 /root/a.txt 拷贝到 /tmp下,那么只要传入/root/a.txt 和 /tmp/a.txt即可,那么关键就是/tmp和a.txt的拼装,在拷贝到/tmp/下你也可以先判断下目标是否有相同文件存在。若存在可以提示用户是否覆盖(这个功能我还没做)。这里主要还是字符串处理函数用的比较多,还有一个就是函数返回值得一个难点(下篇博文介绍下函数返回值)。

三:实现

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<dirent.h>
#include <libgen.h>
#define BUFFERSIZE 4096
#define COPYMODE 0644

char *deal_path(char *,char *);
char *deal_path1(char *,struct dirent *);
int is_file(char *);
char *deal_with(char *,char *);
void oops(char *,char *);
int exists(char *);
void do_cp(char *,char *);
int main(int argc,char *argv[])
{
        char answer[10];
        char c;
        //设置buf
        struct stat filebuf1;
        struct stat filebuf2;
        struct stat tmpbuf;
        char *filename=NULL;
        char *filename2=NULL;
        struct dirent  *dirname;
        DIR *dir_ptr;
        //判断参数
                if(argc != 3){
                fprintf(stderr,"Usage: %s source destination\n",*argv);
                exit(1);
        }
        //判断源文件和目标文件是否相等
        if(strcmp(argv[1],argv[2]) == 0)
        {
                fprintf(stderr,"No Copy Source File equal Dest File\n");
                exit(1);
        }
        //测试文件是否可以访问

        if(access(argv[2],F_OK) == 0){
                //询问文件是否可以覆盖
                printf("Can you ovver the file (y/n):");
                scanf("%9s",&answer);
                while((c = getchar()) != EOF && c != ‘\n‘);
        }

        //判断用户的输入

        if(*answer != ‘y‘ && *answer != ‘Y‘){
                fprintf(stderr,"the dst file exists,don‘t over\n");
                exit(1);
        }

        //判断目标是否是目录
        stat(argv[2],&filebuf2);
        stat(argv[1],&filebuf1);
        if(!S_ISDIR(filebuf1.st_mode)){
                if(S_ISDIR(filebuf2.st_mode))
                        filename = deal_path(argv[2],argv[1]);
                else
                        filename = argv[2];
        //      printf("%s\n",filename);
                do_cp(argv[1],filename);
                free(filename);
             }
             
        else{
                if(S_ISDIR(filebuf2.st_mode))
                if((dir_ptr = opendir(argv[1])) == NULL)
                        sprintf("stderr","Can‘t open dir %s\n",argv[1]);
                else
                        while((dirname=readdir(dir_ptr)) != NULL){
                                        filename = deal_path(argv[1],dirname->d_name);
                                        if(is_file(filename)){
                                                filename2 = deal_with(filename,argv[2]);
                                                do_cp(filename,filename2);
                                                free(filename);
                                                free(filename2);
                                        }else{
                                                free(filename);
                                                continue;
                                        }
                                }
                        }
                closedir(dir_ptr);
        }

void do_cp(char *path1,char *path2)
{
        int in_fd,out_fd,n_chars;
        char buf[BUFFERSIZE];
        if((in_fd = open(path1,O_RDONLY)) == -1)
                oops("Cannot open",path1);
        if((out_fd = open(path2,O_WRONLY|O_CREAT,COPYMODE)) == -1)
                oops("Cannot create",path2);
        //开始读取
        while((n_chars = read(in_fd,buf,BUFFERSIZE)) > 0)
                if(write(out_fd,buf,n_chars) != n_chars)
                oops("Write error to",path2);
        //判断最后是否写入
        if(n_chars == -1)
                oops("Read error from,path1","");
                        //判断最后是否写入
        if(n_chars == -1)
                oops("Read error from,path1","");
        //关闭文件
        if(close(in_fd) == -1||close(out_fd) == -1)
                oops("Error closing files","");
}

void oops(char *s1,char *s2)
{
        fprintf(stderr,"Error:%s ",s1);
        perror(s2);
        exit(1);
}

int exists(char *filename)
{
        return access(filename,F_OK);

}

int is_file(char *filename)
{
        struct stat filebuf;
        stat(filename,&filebuf);
        if(S_ISREG(filebuf.st_mode))
                return 1;
        else
                return 0;
}

char *deal_with(char *filename,char *filename2)
{
        char *file=NULL;;
        if((file = (char *)malloc(strlen(basename(filename))+strlen(filename2)+3)) == NULL)
                perror("malloc error");
                        else{
                if(filename2[strlen(filename2)-1] == ‘/‘){
                        strcpy(file,filename2);
                        strcat(file,basename(filename));
                }else{
                        strcpy(file,filename2);
                        strcat(file,"/");
                        strcat(file,basename(filename));
                     }
        }
        return file;
}

char *deal_path(char *file,char *file2)
{
        char *filename=NULL;
        if((filename = (char *)malloc(strlen(file)+strlen(file2)+3)) == NULL)
                                perror("Malloc erro:");
        else{

        if(file[strlen(file)-1] == ‘/‘){
                        strcpy(filename,file);
                        strcat(filename,file2);
        }else{
                        strcpy(filename,file);
                        strcat(filename,"/");
                        strcat(filename,file2);
                }
        }
        return filename;

}
用的最多的还是这个deal_path这个函数,这个函数会判断/tmp/ /tmp这个的区别,最终会将给出的
两个参数合并成一个文件路径创建并写入要拷贝的内容。

四:总结

C语言基础很重要,最近在看C专家编程,C和指针,感触很深里面很多C语言的细节我都不知道。还有linux C编程实战中的关于结构体的字节对齐我也知之甚少。后期会用博客记录相关内容加深自己对这些内容的理解。

时间: 2024-07-30 16:17:35

linux C实现cp功能的相关文章

Linux命令:cp、time、cut、awk 、获取文件大小命令

最近写了一个shell脚本,用到了cp.time.cut.awk命令,把他们的使用方法给写下来: 1.cp和mv cp命令:用来完成文件的复制,从源文件夹复制到目标文件夹.执行后源文件夹和目标文件夹均有源文件. mv 命令:用来移动文件.执行后,源文件夹中没有源文件.我经常用mv命令来重命名文件 注意:cp命令源文件夹与目标文件夹不能使同一个:而在mv中可以是同一个. 命令解析: #cp [-R] 源文件 目标文件夹 cp -R 参数 ---当复制整个文件夹时使用. #mv 源文件 目标文件夹

Linux学习—LVM快照功能

LVM快照功能--我们知道LVM能够通过增减PE的数量来弹性调整文件系统的大小,除此之外,LVM还有另外一个重要的功能,LV磁盘快照,就是通过快照的功能将此时的文件系统信息记录下来,以后对该文件系统操作的时候,当该文件系统的数据变化的时候,我们可以利用快照将文件系统恢复至当时的状态. 目录 LV的快照原理 创建快照 利用快照恢复系统 一.LV的快照(snapshot)原理 左边的图表示,LVM会在VG上预留一定的区域作为快照区,原本lv中存放着数据,同时快照区存放着lv中元数据,因此快照区大小不

Red Hat Enterprise Linux 7的新功能

?? 简介红帽最新版本的旗舰平台交付显著增强的可用性. 性能和可靠性. 丰富的新功能为架构. 系统管理员和开发人员提供所需的资源以更高效地进行创新和管理.架构师: 红帽® 企业 Linux® 7 适合您选择的任意基础架构, 它可以高效地与其他操作环境. 身份验证和管理系统集成到一起. 无论您是要构建网络密集型应用程序. 可大规模扩展的数据资料库, 亦或是一次构建而成但会频繁部署的并在物理. 虚拟和云环境中表现良好的解决方案, 红帽企业 Linux 7 都提供了必要的功能来支持您的项目.系统管理员

linux C实现mkdir功能

一:背景 linux 中的mkdir命令是用来创建一个目录的,相应的就需要使用到linux中的系统调用函数mkdir来实现目录创建的功能.单单只是创建目录的话一个系统调用足以,本文是使用mkdir函数来实现mkdir -p这个选项的功能,对其不存在的父目录实现创建. 二:思路 对于一个a/b/c这样的一个多级目录,要想实现父目录的创建方法和思路有很多,可以进行字符串处理分出一级一级目录来,但是这样实现很是繁琐,以至于我想到了递归实现. 思路如下: 1.先判断a/b/c是否存在,不存在获取其父目录

Linux shell命令 cp 加上-f还是提示是否覆盖

这是因为环境变量中有 allias cp='cp -i' 为了去掉这个系统自带的别名,可以使用grep -r --include="*" "alias cp"  /查找设置这个环境变量的脚本文件: 我的ubuntu机器上是: ./.bash_aliases:alias cp='cp -i' 于是我将./.bash_aliases文件中的这句话去掉即可 然后使用 source ./.bash_aliases 使其立即生效 2014年7月5日11:49:54 www.u

Linux系统中cgroup功能介绍

1  Cgroups简介 1.1 What are cgroups ? Cgroups(控制组)是Linux内核的一个功能,用来限制.统计和分离一个进程组的资源(CPU.内存.磁盘输入输出等).换句话说就是,如果一个进程加入了某一个控制组,该控制组对Linux的系统资源都有严格的限制,进程在使用这些资源时,不能超过其最大的限制数,例如:memory资源,如果加入控制组的进程使用的memory大于其限制,可能会出现OOM错误(关于OOM错误可参看Linux内核OOM机制分析).cgroup本身提供

Linux中的cp命令&老九门

cp命令详解 cp命令的老九门 我们先看第一种情况: 1.源是一个文件,目标是不存在的 使用 cp aa /testdir/dir1他会创建一个dir1的目标文件,并且将源的内容放到创建的dir目标文件中 2.源是一个文件,目标存在且为文件(上述命令执行后,dir1的文件就会被创建了),然后再次执行cp aa /testdir/dir1,会提示你是否覆盖dir1这个文件,选择y后,再次查看aa和dir1文件的属性,发现dir1的mtime发生了改变说明该文件是被修改了,的确完成了复制. 但是使用

Linux文件系统命令 cp

命令名:cp 功能:拷贝文件,把一个文件的内容拷贝到另外一个文件中去. eg: cp source_file dist_file [email protected]6380-MT:~$ cp minicom.log ./WorkSpace/ [email protected]-HP-Compaq-Pro-6380-MT:~$ ls -l ./WorkSpace/ | grep minicom.log -rw-r--r-- 1 renjg renjg 677 8月 22 13:16 minicom

php -- 实现linux关机、重启功能

有时候,我们自己可以DIY一个控制面板实现linux的关机重启功能.众所周知,linux是一个基于文件的操作系统,所以要实现系统的关机重启功能必须满足以下两点 一.知道命令的绝对路径 在linux下操作的时候,我们们直接敲入命令即可.但用PHP执行linux命令就不能这么操作了,需要知道命令的绝对路径. 重启命令reboot绝对路径/sbin/reboot关机命令shutdown绝对路径/sbin/shutdown 二.用PHP执行linux命令 有许多函数,之前我有些过博文介绍.这里推荐使用e