自行实现linux命令之——CP命令

简单实现cp命令
源和目的操作数都只能是文件名。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
//参数错误退出
int main(int argc, char* argv[]){
    if(argc != 3){
        perror("参数不对");
        exit(0);
    }
    int fr = open(argv[1],O_RDONLY );
    struct stat sbuf;
    stat(argv[1], &sbuf);
    //不存在就创建,存在就失败
    int fw = open(argv[2], O_WRONLY|O_CREAT|O_EXCL, sbuf.st_mode);
    if(-1 == fw){
        printf("目标文件已经存在,是否覆盖?(y/n)");
        char ch;
        scanf("%c", &ch);
        if(ch == 'y'){
            fw = open(argv[2], O_WRONLY|O_TRUNC, sbuf.st_mode);
        }
        else{
            exit(1);
        }
    }   
    int r = 0;
    char buf[1024] = "";
    while((r = read(fr, buf, 1024)) > 0){
        write(fw, buf, r);
        memset(buf, 0x00, 1024);
    }
    close(fw);
    close(fr);
}

简易ls:取当前目录,排序后输出
用链表实现,每读取一个文件或目录插入到已排序链表。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
typedef struct node_t{
    char name[1024];
    struct node_t *next;    
}node_t;
int main(){
    //打开一个目录流
    DIR *pDir = opendir(".");
    if(pDir == NULL)
        perror("opendir");
    node_t *pHead = NULL;
    struct dirent *pd = NULL;
    //从目录流读取一个目录结构体
    while((pd = readdir(pDir)) != NULL){
        node_t *pNew = (node_t*)malloc(sizeof(node_t));
        memset(pNew, 0x00, sizeof(node_t));
        strcpy(pNew->name, pd->d_name);
        pNew->next = NULL;
        if(NULL == pHead){
            pHead = pNew;
        }else{
            //找待插入位置
            node_t *pCur = pHead;
            node_t *pPre = NULL;
            while(pCur != NULL){
                if(strcasecmp(pNew->name, pCur->name) > 0){
                    pPre = pCur;
                    pCur = pCur->next;
                }else{
                    break;
                }
            }
            if(NULL == pCur){
                pPre->next = pNew;
            }else if(NULL != pPre){
                pPre->next = pNew;
                pNew->next = pCur;  
            }else{
                pHead = pNew;
                pNew->next = pCur;
            }
        }
    }
    node_t *pCur = pHead;
    while(pCur){
        printf("%s\n", pCur->name);
        pCur = pCur->next;
    }
    close(pDir);
}

完备的cp命令

cp src dst
可以是文件到文件,文件到目录,目录到目录
这里写图片描述


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

void cp_file(const char *src, const char *dst, mode_t mode);
void cp_dir(const char *src , const char *dst);

int main( int argc, char *argv[] )
{
    if (argc != 3) {
        fprintf(stderr, "usage: %s src dst\n", argv[0]);
        exit(1);
    }
    //stat判断文件类型以及是否存在
    struct stat sbuf;
    if (stat(argv[1], &sbuf) == -1 ) perror("stat src");
    //src是文件
    if (S_ISREG(sbuf.st_mode)) {
        struct stat dbuf;
        if ( stat(argv[2], &dbuf) == -1 ) { 
            // 目标不存在 可以直接复制
            cp_file(argv[1], argv[2], sbuf.st_mode);
        } else if (S_ISDIR(dbuf.st_mode)) { // 目标是目录
            //拼接一个目标目录下的地址
            char tmp[1024] = {};
            sprintf(tmp, "%s/%s", argv[2], argv[1]);
            cp_file(argv[1], tmp, sbuf.st_mode);
        } else if (S_ISREG(dbuf.st_mode) ) { // 目标是已经存在的文件
            printf("是否覆盖%s文件? ", argv[2]);
            char ask = 'n';
            scanf("%c", &ask);
            if ( ask=='y' || ask=='Y' ) {
                truncate(argv[2], 0); // 清空目标文件
                cp_file(argv[1], argv[2], sbuf.st_mode);
            }
        }
    }else if(S_ISDIR(sbuf.st_mode)) { // 原文件是目录
        printf("源文件是目录 %d\n", S_ISDIR(sbuf.st_mode));
        struct stat dbuf;
        if ( stat(argv[2], &dbuf) == -1 ) { // 目标目录不存在
            mkdir(argv[2], sbuf.st_mode); // 创建目标目录
            char tmp[1024] = "";
            sprintf(tmp, "%s/%s", argv[2], argv[1]);
            mkdir(tmp, sbuf.st_mode);
            cp_dir(argv[1], tmp);
        } else if ( S_ISDIR(dbuf.st_mode) ) { // 目标是目录,作为子目录
            char tmp[1024] = {};
            sprintf(tmp, "%s/%s", argv[2], argv[1]);
            cp_dir(argv[1], tmp);
        } else { // 非法
            printf("目录不能拷贝到文件中\n");
            exit(0);
        }
    } 
}
//将src文件拷贝到dst文件
void cp_file(const char *src, const char *dst, mode_t mode)
{
    int fd_src = open(src, O_RDONLY);
    if (fd_src == -1 ) perror("open src");
    int fd_dst = open(dst, O_WRONLY|O_CREAT, mode);
    if (fd_dst == -1 ) perror("open dst");
    char buf[1024];
    memset(buf, 0x00, sizeof(buf));
    int r;
    while ((r=read(fd_src, buf, 1024)) > 0 )  {
        write(fd_dst, buf, r);
        memset(buf, 0x00, sizeof(buf));
    }
    close(fd_src);
    close(fd_dst);
}
//接受dst为目标目录
void cp_dir(const char *src , const char *dst)
{
    DIR *pdir = opendir(src);
    if ( pdir == NULL ) perror("opendir");

    struct dirent *pd = NULL;
    //循环将所有src目录下的内容拷贝
    while ((pd=readdir(pdir)) != NULL ) {
        if(strcmp(pd->d_name,".")==0 || strcmp(pd->d_name, "..")==0){
            continue;
        }
        struct stat sbuf;
        char srcTmp[1024] = ""; 
        sprintf(srcTmp, "%s/%s", src, pd->d_name);
        if(stat(srcTmp, &sbuf)== -1){
            perror("stat ");    
        }
        printf("当前处理的%s, 是目录吗%d\n",srcTmp, S_ISDIR(sbuf.st_mode));
        if(S_ISDIR(sbuf.st_mode)){
            //递归处理src下的子目录
            char tmpDir[1024] = "";
            sprintf(tmpDir, "%s/%s", dst, pd->d_name);
            printf("在dst下创建的目录%s\n", tmpDir);
            mkdir(tmpDir, sbuf.st_mode);
            printf("递归传入的src:%s dst %s\n", srcTmp, tmpDir);
            cp_dir(srcTmp, tmpDir); 
            continue;
        }
        //是普通文件
        char dstTmp[1024];
        sprintf(dstTmp, "%s/%s", dst, pd->d_name);
        printf("普通文件源地址%s 目的文件名:%s\n", srcTmp, dstTmp);
        cp_file(srcTmp, dstTmp, sbuf.st_mode);

    }
    close(pdir);
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值