您的位置:首页 > 其它

编写自己的cp命令

2014-05-09 14:43 288 查看
  有时候要对整个目录做备份,修改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 != 3 ){
fprintf( stderr, "usage: %s source destination\n", *av);
exit(1);
}
/* open files    */

if ( (in_fd=open(av[1], O_RDONLY)) == -1 )
oops("Cannot open ", av[1]);

if ( (out_fd=creat( av[2], COPYMODE)) == -1 )
oops( "Cannot creat", av[2]);

/* copy files    */

while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", av[2]);
if ( n_chars == -1 )
oops("Read error from ", av[1]);

/* close files    */

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);
}


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

/** 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 != 3 ){
fprintf( stderr, "usage: %s source destination\n", *av);
exit(1);
}

/*
* if source is a dir, then the dest has to be, too
*/

if ( isadir(av[1]) ){
if ( isadir(av[2]) )
copydir(av[1], av[2]);
else {
fprintf(stderr,"cp1: %s is not a directory\n", av[2]);
exit(1);
}
}
/*
* if source is not a dir, then the dest can be anything
*/
else
do_copy( av[1], av[2] );
return 0;
}

/*
* 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)+1+MAXNAMLEN+1);
destpath = (char *) emalloc(strlen(destdir)+1+MAXNAMLEN+1);
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,".") != 0 &&
strcmp(direntp->d_name,"..") != 0 )
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)) == -1 )
oops("Cannot open ", src);

if ( (out_fd=creat( destfilename, COPYMODE)) == -1 )
oops( "Cannot creat", destfilename);

/*
* copy files
*/

while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 )
if ( write( out_fd, buf, n_chars ) != n_chars )
oops("Write error to ", destfilename);
if ( n_chars == -1 )
oops("Read error from ", src);

/*
* close files
*/

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);
}

/*
* 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) == -1 )    /* 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) + 2);
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) != -1 && S_ISDIR(info.st_mode) );
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: