cp指令的简单实现

本文介绍了如何在C语言中实现Linux的cp指令,包括复制文件到文件、文件到文件夹以及文件夹到文件夹的详细代码实现,并讨论了Makefile中遇到的问题及可能原因分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、复制的三种情况:

  1. 将文件复制成另外一个文件;

    int
    copy_file2file( char *cpSrcPath,char *cpDstPath )
    {
       int     iFdSrc = 0;
       int     iFdDst = 0;
       int     iRdNum = 0;
       int     iWrNum = 0;
       char    caLine[ LINELEN ];
    
       /* open thhe source file */
       if( ( iFdSrc = open( cpSrcPath, O_RDONLY ) )  < 0 
       {
            /* fail to open the source file */
            return -1;
       }
     
       /* open the dest file */
       if( ( iFdDst = open( cpDstPath, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR |S_IRUSR ) ) < 0 )
       {
            return -1;
       }
     
       /* read the file until the EOF or some error */
       while( ( iRdNum = read( iFdSrc, caLine, sizeof( caLine ) ) ) > 0 )
       {
            if( ( iWrNum = write( iFdDst, caLine,iRdNum ) ) != iRdNum )
            {
                /* write error */
                close_fd( 2, iFdSrc, iFdDst );
                /* delete the dest file */
                unlink( cpDstPath );
                return -1;
            }
       }
    
       /* read error */
       if( iRdNum != 0 )
       {
            close_fd( 2, iFdSrc, iFdDst );
            /* delete the dest file */
            unlink( cpDstPath );
            return -1;
       }
    
       close_fd( iFdSrc, iFdDst );
       return 0;
    }
    

  2. 将文件复制到另外一个文件夹里;

    int
    copy_file2dir( char *cpSrcPath, char *cpDstPath )
    {
        char caTmpDstPath[ NAMELEN ];
        char caTmpBaseName[ NAMELEN ];
    
        get_path_basename( cpSrcPath, caTmpBaseName );
        combine_path( cpDstPath, caTmpBaseName, caTmpDstPath );
    
        return copy_file2file( cpSrcPath, caTmpDstPath );
    }
    

  3. 将文件夹复制到另外一个文件夹里;

    int
    copy_dir2dir( char *cpSrcPath, char *cpDstPath )
    {
        char caTmpSrcPath[ NAMELEN ];
        char caTmpDstPath[ NAMELEN ];
        char caTmpBaseName[ NAMELEN ];
        DIR  *fpDir = NULL;
        struct dirent *dirpCurr = NULL;
        int  iTmpErrno;
    
        if( ( fpDir = opendir( cpSrcPath ) ) == NULL )
        {
            return -1;
        }
    
        iTmpErrno = errno;
    
        get_path_basename( cpSrcPath, caTmpBaseName );
        combine_path( cpDstPath, caTmpBaseName, caTmpDstPath );
        if( mkdir( caTmpDstPath, S_IRWXU ) != 0 )
        {
            return -1;
        }
    
        while( ( dirpCurr = readdir( fpDir ) ) != NULL )
        {
            if( ( strcmp( dirpCurr->d_name, "." ) == 0 ) || ( strcmp( dirpCurr->d_name, ".." ) == 0 ) )
                continue;
    
            combine_path( cpSrcPath, dirpCurr->d_name, caTmpSrcPath );
    
            if( file_type( caTmpSrcPath ) == EN_DIR )
                copy_dir2dir( caTmpSrcPath, caTmpDstPath );
            else
                copy_file2dir( caTmpSrcPath, caTmpDstPath );
        }
    
        if( errno != iTmpErrno )
        {
            /* some error */
            return -1;
        }
    
        closedir( fpDir );
        return 0;
    }

二、Makefile

# when update the src/cp.c file
# first time to compile, there is some errors
# but second time, it's OK, to find the resond
ROOT=../..
include $(ROOT)/Make.defines

VPATH:=src include obj
PRGS:=mycp

.PHONY=all
all: $(PRGS)

$(PRGS): mycp.c cp.o
	$(CC) $(CFLAGS) -I./include -o $@ $^ $(CLIBS)

cp.o: cp.c
	$(CC) $(CFLAGS) -I./include -c $<
	$(MV) $@ obj/

.PHONY=clean
clean:
	$(RM) $(TMPFILE) $(PRGS)


Make.defines和实现more时候的文件是基本是一样的,除了将Make.defines的CFLAGS里定义了一个宏-D_XOPEN_SOURCE=500,因为在判断文件类型的时候使用了S_ISSOCK(m)这个宏在一些版本里没有,所以定义了它。

但是这个Makefile有个问题是每次修改了cp.c这个文件或重新生成的时候,第一编译会出错,提示找不到cp.o;第二次编译才能成功。

 可能的原因分析:

当cp.c更新或重新生成的时候,make要生成最后的mycp目标文件,会检查依赖文件mycp.c和cp.o。

因为VPATH=include src obj,所以mycp.c会在src下找到,也就是编译时候的src/mycp.c,这没有问题;cp.o的问题应该是下面两种情况

当没有找到cp.o,make会根据定义的cp.o生成规则在当前目录生成cp.o,编译的时候会使用cp.o而不是obj/cp.o,但是我在生成cp.o之后马上将cp.o移动到了obj目录,而make并不知道,所以报找不到cp.o文件;

当找到obj/cp.o,但是发现其依赖文件src/cp.c已经更新,这时make放弃之前找到的obj/cp.o文件,转而采用根据规则重新生成的cp.o文件,这样就和上面的那种情况一样了。

ROOT=../..
include $(ROOT)/Make.defines

VPATH:=src include obj
PRGS:=mycp

OBJ=cp.o
define IF_MV
    @if[ -e "$(OBJ)" ];  \
    then                 \
       $(MV) $(OBJ) obj; \
    fi
endef

.PHONY=all
all: $(PRGS)

$(PRGS): mycp.c cp.o
	$(CC) $(CFLAGS) -I./include -o $@ $^ $(CLIBS)
	$(IF_MV)

cp.o: cp.c
	$(CC) $(CFLAGS) -I./include -c $<

.PHONY=clean
clean:
	$(RM) $(TMPFILE) $(PRGS)
针对Makefile之前的情况,我将移动cp.o的动作放到生成最终目标文件之后,所有添加了一个宏IF_MV,在执行完生成操作之后,如果在当前目录发现cp.o就将其移到obj目录

三、源代码

http://download.youkuaiyun.com/detail/qq123386926/9007767

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值