有时候要对整个目录做备份,修改cp1.c使得当两个参数都是目录时,把第一个目录中的所有文件复制到第二个目录中,文件名不变。那么该如何实现?
  我们先来看看cp1.c的实现方式,它从一个文件中读取数据然后写到另一个文件中,通过系统调用open(或者creat)、read、wirte和close来完成。从上面我们看出,cp1.c只是针对于一个文件进行的复制操作,而现在我们需要完成对整个目录的备份。参数由一个单独的文件(file)变成一个目录(directory),所以我们首先想到的就是要先进入到这个目录下,然后对该目录下的文件依次进行cp操作,那么这就涉及到了目录的操作,而我们在第三章ls命令的实现过程中,用到的就是对目录的操作,涉及到的系统调用包含有opendir、readdir和closedir。所以现在我们需要把两者用到的技术联系起来,以便完成对目录的备份工作。
  具体实现:
    1、命令行参数
      int argc、char *argv[]
    2、cp源、目的的类型判断
      src为dir,dst也必须是dir
      src为file,dst可以是anything
    3、目录操作
      opendir进入src目录下;
      while{
        readdir获得当前目录下的文件(或目录),递归判断是否还是目录,如果是继续深入;
        srcpath、dstpath获取,调用cp完成复制;
      }
      closedir完成目录复制
    4、cp实现
      in=open(src);out=creat(dst)
      while{
        read(in);
        write(out);
      }
      close(in);close(out)

具体的代码如下:

 /** cp1.c
* version 1 of cp - uses read and write with tunable buffer size
*
* usage: cp1 src dest
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h> #define BUFFERSIZE 4096
#define COPYMODE 0644 void oops(char *, char *); main(int ac, char *av[])
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
/* check args */
if ( ac != ){
fprintf( stderr, "usage: %s source destination\n", *av);
exit();
}
/* open files */ if ( (in_fd=open(av[], O_RDONLY)) == - )
oops("Cannot open ", av[]); if ( (out_fd=creat( av[], COPYMODE)) == - )
oops( "Cannot creat", av[]); /* copy files */ while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > )
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", av[]);
if ( n_chars == - )
oops("Read error from ", av[]); /* close files */ if ( close(in_fd) == - || close(out_fd) == - )
oops("Error closing files","");
} void oops(char *s1, char *s2)
{
fprintf(stderr,"Error: %s ", s1);
perror(s2);
exit();
}

 改进(添加目录判断)之后的具体实现:

 /** cp2.c
** ------------------------------------------------------------
cp2.c is a
revised version of cp1.c that can copy an entire directory
file by file to a second directory. It also supports some
of the features required by earlier exercises. ** ------------------------------------------------------------
**
**
* A version of cp1.c that works if src or dest name directories
* (but not if src is a directory and dest is not)
*
* usage: cp1 src dest
* If dest names a directory, then copy src to dest/src
* If src names a directory, then copy all files in src to dest
* If src is a directory and dest is NOT a directory, quit
* Note: if src has a leading path, then only use last component
*
* build: cc sol03.14.c -o sol03.14
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h> #define BUFFERSIZE 4096
/*
* note: the real copy takes the mode of the copy from
* the mode of the source.
*/
#define COPYMODE 0644 void oops(char *, char *);
void *emalloc(size_t); int
main(int ac, char *av[])
{
if ( ac != ){
fprintf( stderr, "usage: %s source destination\n", *av);
exit();
} /*
* if source is a dir, then the dest has to be, too
*/ if ( isadir(av[]) ){
if ( isadir(av[]) )
copydir(av[], av[]);
else {
fprintf(stderr,"cp1: %s is not a directory\n", av[]);
exit();
}
}
/*
* if source is not a dir, then the dest can be anything
*/
else
do_copy( av[], av[] );
return ;
} /*
* copydir()
* loops through all files in srcdir, copying each to destdir
* uses do_copy but builds the paths here
* Note: this function skips subdirectories of srcdir
*/
copydir(char *srcdir, char *destdir)
{
char *srcpath, *destpath;
DIR *dir_ptr;
struct dirent *direntp; srcpath = (char *) emalloc(strlen(srcdir)++MAXNAMLEN+);
destpath = (char *) emalloc(strlen(destdir)++MAXNAMLEN+);
if ( (dir_ptr = opendir(srcdir)) == NULL )
oops("Cannot open directory", srcdir); /*
* loop through all items in src dir
* Do not copy directories, and report that so user
* realizes not all the items are copied.
*/
while( ( direntp = readdir(dir_ptr)) != NULL )
{
sprintf(srcpath,"%s/%s", srcdir, direntp->d_name);
if ( isadir(srcpath) ){
if ( strcmp(direntp->d_name,".") != &&
strcmp(direntp->d_name,"..") != )
printf("skipping directory %s\n", srcpath);
continue;
}
sprintf(destpath, "%s/%s", destdir, direntp->d_name);
do_copy( srcpath, destpath );
}
closedir(dir_ptr);
free(srcpath);
free(destpath);
} /*
* copies a file from src to dest
* If dest is a directory, then do_copy() copies to
* a file in dest with the name taken from the filename for
* src
*/
do_copy(char *src, char *dest)
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
char *destfilename;
char *make_destfilename(char*,char*); destfilename = make_destfilename(src, dest); /*
* open files
*/ if ( (in_fd=open(src, O_RDONLY)) == - )
oops("Cannot open ", src); if ( (out_fd=creat( destfilename, COPYMODE)) == - )
oops( "Cannot creat", destfilename); /*
* copy files
*/ while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > )
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", destfilename);
if ( n_chars == - )
oops("Read error from ", src); /*
* close files
*/ if ( close(in_fd) == - || close(out_fd) == - )
oops("Error closing files","");
} void oops(char *s1, char *s2)
{
fprintf(stderr,"Error: %s ", s1);
perror(s2);
exit();
} /*
* if dest is a directory, then combine src and dest
* (see header to this program)
*/ char *
make_destfilename(char *src, char *dest)
{
struct stat info;
char *srcfilename;
char *rv; if ( stat(dest, &info) == - ) /* let someone else handle this */
return dest; if ( ! S_ISDIR(info.st_mode) ) /* ok to copy to other types */
return dest; /* find last component of source name */
if ( (srcfilename = strrchr(src, '/')) != NULL )
srcfilename++;
else
srcfilename = src; /* use that to construct target name */
rv = emalloc(strlen(srcfilename) + strlen(dest) + );
sprintf(rv, "%s/%s", dest, srcfilename); return rv;
} void *
emalloc(size_t n)
{
void *rv = malloc(n);
if ( rv == NULL )
oops("Out of memory","");
return rv;
}
/*
* boolean: tells if arg names a directory
*/
isadir(char *str)
{
struct stat info; return ( stat(str,&info) != - && S_ISDIR(info.st_mode) );
}

编写自己的cp命令的更多相关文章

  1. cp/tar/用c语言编写程序 实现cp命令的效果

    1.cp (拷贝) 已存在文件路径  要拷贝的文件路径 实现cp命令的代码如下: #include <stdio.h> //因为要在命令中得到两个路径,所以要用到main函数的两个参数 i ...

  2. 关于cp命令的编写

    关于cp命令的编写 娄老师在课上详细的讲了命令who的编写过程~对此,我很有启发!于是想亲自动手试试~ 有什么不足的地方请大家提出来! Learning by doing ~ 做中学,真的只有自己动手 ...

  3. cp命令的编写——浅谈系统调用

    摘要:linux中cp命令的实现,通过这个程序,我们需要了解系统调用耗费时间的方面,同时学会系统调用的错误处理机制. 本文来源:http://blog.csdn.net/trochiluses/art ...

  4. linux系统编程:自己动手写一个cp命令

    cp命令的基本用法: cp 源文件 目标文件 如果目标文件不存在 就创建, 如果存在就覆盖 实现一个cp命令其实就是读写文件的操作: 对于源文件: 把内容全部读取到缓存中,用到的函数read 对于目标 ...

  5. 每天一个Linux命令(10)cp命令

    cp命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录.它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下.cp命令还支持同时复制多个文件,当一次复制多个文件时,目标文 ...

  6. Linux命令学习总结:cp命令

    命令简介: cp命令用来复制文件或目录.指令英文原义:copy 指令所在路径:/bin/cp 命令语法: Usage: cp [OPTION]... [-T] SOURCE DEST or: cp [ ...

  7. 【初级】linux cp 命令详解及使用方法实战

    cp:复制文件或者目录 前言: cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在,就会询问是否覆盖,不 ...

  8. linux命令(8):cp 命令

    cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在,就会询问是否覆盖,不管你是否使用-i参数.但是如果是 ...

  9. Linux cp命令使用说明

    Linux cp命令使用说明 --功能说明:复制目录或文件 --命令格式:cp  [参数]  <文件或目录>  <文件或目录> --常用参数: -R 复制目录 -i 覆盖文件之 ...

随机推荐

  1. Hex dump

    Hex dump From Wikipedia, the free encyclopedia       A hex dump of the 318 byte Wikipedia favicon In ...

  2. REDIS 内存满时删除策略

    REDIS 内存满时删除策略

  3. mui 事件绑定(on)

    除了可以使用addEventListener()方法监听某个特定元素上的事件外, 也可以使用.on()方法实现批量元素的事件绑定. 示例: 点击新闻列表,获取当前列表项的id,并将该id传给新闻详情页 ...

  4. java之static关键字

    介绍: 1.在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份. 2.用static声明的方法为静态方 ...

  5. CSS之Position全面认识

    CSS的很多其他属性大多容易理解,比如字体,文本,背景等.有些CSS书籍也会对这些简单的属性进行大张旗鼓的介绍,而偏偏忽略了对一些难缠的属 性讲解,有避重就轻的嫌疑.CSS中主要难以理解的属性包括盒型 ...

  6. lucene ParallelMultiSearcher与MultiSearcher的区别

    http://www.cnblogs.com/twilight/archive/2009/10/09/1579793.html ParallelMultiSearcher与MultiSearcher的 ...

  7. Velocity写法注意

    1.$Proerty与$!{Property}的区别 比如: 简单的key-value数据格式情况下 a.<C_APP_NME>$Applicant_CAppNme</C_APP_N ...

  8. vue 跨域:使用vue-cli 配置 proxyTable 实现跨域问题

    路径在/config/index.js 中,找到dev.proxyTable.如下配置示例: proxyTable: { '/api': { // 我要请求的地址 target: 'http://oa ...

  9. Ionic学习笔记3_ionic指令简单布局

    1)   添加引用类库(ionic样式和ionic js文件) 2)   标题栏,页脚栏,内容区 3)   Js引入ionic类库,添加页面操作方法和对象 4)   数据初始化 5)   Html页面 ...

  10. Restore IP Addresses -- LeetCode

    原题链接: http://oj.leetcode.com/problems/restore-ip-addresses/  这道题的解法很接近于NP问题.也是採用递归的解法. 基本思路就是取出一个合法的 ...