shell编程

时间:2021-02-05 01:06:50

1、编译优化

//代码

#include <stdio.h>
int main(void)
{
double counter;
double result;
double temp;
for (counter = 0; counter < 2000.0 * 2000.0 * 2000.0 / 20.0 + 2020;
counter += (5 -1) / 4) {
temp = counter / 1979;
result = counter;
}
printf(Result is %lf\\n, result);
return 0;
}

shell编程 gdb调试:

优化后

shell编程 未优化

shell编程 优化分析:

  • 代码分析 shell编程
  • 执行分析 shell编程
  • 大小分析 shell编程 区别:-O优化会改变文件大小,会更小一点。但是这个程序太小所以这些特点表现的并不显著。但是优化后的代码执行时间会更短;优化后的代码会把数据全部存入xmm寄存器,计算时直接从寄存器读取数据;未优化的代码会把一些数据放在栈中来读取。栈中读取和寄存器读取,显然寄存器会更快。

makefiel

一个工程中的源文件不计数,其按类型功能模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

2、文件基本操作编程

使用Linux系统调用编写一个完成文件拷贝的C程序。比较拷贝得到的文件与源文件的大小和内容(命令diff,cmp)。

代码

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include<unistd.h>

int main(){
int f1,f1_l,f2;	//f1:文件a.txt的句柄;f2:文件b.txt的句柄;f1_l:a.txt文件内容的长度。
char buf[1024]={};//这个用于暂时存储被复制的文件内容

//打开源文件,读取文件内容
f1=open("a.txt",O_RDWR);
f1_l=read(f1,buf,1024);

//这里打开目标文件,如果没有就创建一个,且权限为777,然后将内容复制到目标文件
f2=open("b.txt",O_RDWR | O_CREAT,0777);
write(f2,buf,f1_l); 

close(f1);
close(f2);

}

执行结果: shell编程 用ls去查看,发现文件大小没有不同,只是两者权限不同。权限设置的是777,但是由于用户的默认权限掩码,

shell编程 0022,所以创建出来的权限就是0777-0022=0755。

​ 用diff去比较, shell编程

diff会针对文本内容逐行进行对比,如果有不同就会显示出这有差别的两行,这里看到文本内容上并没有什么差别。 shell编程 用cmp去对比, shell编程 cmp会逐个字符去比较,会告诉有差异的字符的位置,第几行第几个字符。不加参数的情况下它只会显示出第一个有差异的位置。-l参数会帮助显示出所有有差异的位置。这里也没有不同。

shell编程

编写C程序完成:创建一个新文件,输入一段数据,然后随机移动指针接着插入一段数据。完成后,查看该文件的大小和内容。怎样获取当前文件的读写指针位置?

代码

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

int main(){
    int fd,loc;
    char name[10]="\0";
    char context[1024]="\0";
    char tip[]="mkanewdir!";//插入字符串内容

    //创建一个新文件
    printf("文件名:");
    gets(name);
    fd=creat(name,0777);

    //输入一段内容写入新文件中
    printf("内容:");
    gets(context);
    write(fd,context,sizeof(context));

    //插入字符串
    lseek(fd,2,SEEK_SET);
    write(fd,tip,strlen(context)+8);
    //输入内容的字符串长度-偏移量:2+插入的字符串长度:10
    //这样是为了防止长度过长导致输入字符很少但是文件很大,也避免覆写原内容。

    //读取文件指针位置
    loc=lseek(fd,0,SEEK_CUR);
    printf("当前文件读写指针的位置:%d。",loc);
    close(fd);
}

获取字符串长度的话就是lseek,SEEK_CUR锁定到当前位置,偏移量为0,就可以得到当前位置了。这里有尝试用tell函数,但是编译时显示没有定义这样一个函数。不知道是我的gcc太老了还是啥。

shell编程shell编程 这里文件的大小就是总的字符串长度。

3、编写拷贝命令,实现文件或目录的复制

#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/vfs.h>
​
/*
命令格式:源地址 目标地址 (-r)
程序用三维数组去存储文件名,三维数组是全局变量。
流程:
    将源地址和目的地址存入数组中。
    先查看是否有重名文件,即目标路径是否已经存在。(复制的话,它的目录名可以存在,但是目标路径存在就代表有这样一个文件了。)
    获取目标路径所在磁盘大小的容量。
    对输入命令的判断,决定执行文件复制还是目录递归复制。
    复制文件:
        先判断磁盘大小是否足够。
        在目标路径下,将源文件内容拷贝过去。(向文件中写内容。)
        如果磁盘大小不足,会停止复制。 有个缺陷,如果创建文件的时候空间就不足了,这时候是没有检测的,估计会有系统的报错提示。
    复制目录:
        先获取目录的大小。
        再判断目录大小和磁盘容量是否满足要求。
        满足要求就复制。
存在问题:
    磁盘计算不够精准。
    每个函数都是对全局变量进行的操作,之后的修改会有影响,要考虑到其他函数的存在。
*/
​
long int dir_list[100][100][100];//用三维数组存放源文件和目标文件 [目录位][文件位][文件名]
long int dir_dst[100][100][100];
int loc=0,i=0,count=0,off=0;//loc:当前目录位置;i:当前文件位置;count:目录数量;off:是否复制目录的开关; 
int alow=0,sum=0;//alow:磁盘容量;sum:目录大小;
​
int ls();
void copy_file();
void copy_dir();
void samename(mode_t mode);
void counter();
int main(int num,char* name[])
{
    struct stat fl_str,fl_dst;
    struct statfs size;
    
    sprintf(dir_list[0][0],name[1]);//参数存如数组中
    sprintf(dir_dst[0][0],name[2]);
​
    stat(dir_list[0][0],&fl_str);
    stat(dir_dst[0][0],&fl_dst);
​
    samename(fl_str.st_mode);//同名判断
    statfs(dir_dst[0][0],&size);
    alow=4*size.f_bavail;
    switch(num)
    {
        case 3://文件复制
            if(S_ISREG(fl_str.st_mode)&&((fl_str.st_size/1000)<alow))
            {
                copy_file();
            }
            else
                printf("磁盘大小不足,复制中止!");
            break;
        case 4://目录复制
            if(S_ISDIR(fl_str.st_mode)&&!strcmp(name[3],"-r"))
            {
                ls();
            }
            else
                printf("复制目录格式有误!复制中止!\n格式:源路径 目标路径 -r");
            break;
    }
}
​
int ls()//遍历目录,递归复制
{
    char dst[100];
    DIR* dir_ptr[100];
    struct dirent* direntp;    
    struct stat type;
​
    while(off<2)
    {
        while((dir_ptr[loc] = opendir(dir_list[loc][0]))!=NULL)
        {
            while((direntp = readdir(dir_ptr[loc])) != NULL)
            {
                if(!strcmp(direntp->d_name,"..")||!strcmp(direntp->d_name,"."))
                {
                    continue;
                }
                sprintf(dir_list[loc][++i],"%s/%s",dir_list[loc][0],direntp->d_name);
                sprintf(dir_dst[loc][i],"%s/%s",dir_dst[loc][0],direntp->d_name);
                stat(dir_list[loc][i], &type);
                if(S_ISREG(type.st_mode))
                {
                    if(off==0)
                        sum+=type.st_size;
                    else
                        copy_file();
                }
                else if(S_ISDIR(type.st_mode))
                {
                    
                    ++count;
                    strcpy(dir_list[count][0],dir_list[loc][i]);
                    strcpy(dir_dst[count][0],dir_dst[loc][i]);
                    if(off==0)
                        sum+=type.st_size;
                    else
                        copy_dir();
                }
            }
            if(count>=loc)
            {
                loc++;
                i=0;
            }
        }
        switch(off)
        {
            case 0:
                if((sum/1000)>alow)
                {
                    perror("ERROR:磁盘容量不足,停止复制!\n");
                    _exit(2);
                }
                else
                    printf("复制成功!\n目录大小:%2dkb,可使用剩余磁盘容量:%2dkb。\n",sum/1000,alow-sum/1000);
                break;
            case 1:break;   
        }
        off++;
        loc=0,i=0,count=0;
    }
}
​
void copy_file()//复制文件
{
    int fl_str,fl_dst,len;
    char context[10240];
​
    fl_str=open(dir_list[loc][i],O_RDONLY);
    len=read(fl_str,context,10240);
    fl_dst=open(dir_dst[loc][i],O_RDWR|O_CREAT,0644);
    write(fl_dst,context,len);
    close(fl_str);
    close(fl_dst);
}
​
void copy_dir()//复制目录
{
    mkdir(dir_dst[loc][i],0777);
}
​
void samename(mode_t mode)//同名判断
{
    if(access(dir_dst[0][0],F_OK)==0)
    {
        perror("ERROR:有同名文件存在,停止复制!\n");
        _exit(2);
    }
    else if(S_ISREG(mode))
    {
        creat(dir_dst[0][0],0644);
    }
    else if(S_ISDIR(mode))
    {
        copy_dir();
    }
}
​
//这个代码网上转载
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
​
int is_dir(char *path);                         //判断是否是目录  是返回1 否则返回0
int copy_file(char *srcPath, char *destPath);   //复制文件  成功返回0 否则返回 -1
int copy_folder(char *srcPath, char *destPath); //复制文件夹  成功返回0 否则返回 -1
​
int main(int argc, char *argv[]) // argv[1] 源文件  argv[2] 目标文件
{
    if (argc != 3)
    {
        printf("Usage srcfile destfile\n");
        return -1;
    }
    char *srcPath = argv[1];
    char *destPath = argv[2];
​
    if (is_dir(srcPath)) //文件夹的拷贝
    {
        copy_folder(srcPath, destPath);
    }
    else
    {
        if (access(destPath, F_OK) == 0) //保证destPath是未存在的目录
        {
            printf("目标文件已存在\n");
            return -1;
        }
        copy_file(srcPath, destPath); //文件进行拷贝
    }
    return 0;
}
//判断是否是目录  是返回1 否则返回0
int is_dir(char *path)
{
    struct stat st;
    stat(path, &st);
    if (S_ISDIR(st.st_mode))
        return 1;
    else
        return 0;
}
​
//复制文件  成功返回0 否则返回 -1
int copy_file(char *srcPath, char *destPath)
{
    char Buf[1024] = {0};
    int count_read = 0;
    long fp_src_ltell = 0, fp_src_atell = 0;
    FILE *fp_src = fopen(srcPath, "r");  //只读方式打开
    FILE *fp_dst = fopen(destPath, "w"); //只写方式打开
    if (fp_dst == NULL || fp_src == NULL)
    {
        printf("文件打开有问题\n");
        return -1;
    }
    while (1)
    {
        memset(Buf, 0, sizeof(Buf));
        fp_src_ltell = ftell(fp_src); //上一次文件指针位置
        count_read = fread(Buf, sizeof(Buf), 1, fp_src);
        fp_src_atell = ftell(fp_src); //当前文件指针位置
        if (count_read < 1)           //异常或到达末尾结束
        {
            if (feof(fp_src))
            {
                long temp = fp_src_atell - fp_src_ltell;
                fwrite(Buf, temp, 1, fp_dst); //成功
                return 0;
            }
            else if (ferror(fp_src))
            {
                perror("fread error:");
                return -1;
            }
        }
        fwrite(Buf, sizeof(Buf), 1, fp_dst);
    }
    return 0;
}
​
//复制文件夹
int copy_folder(char *srcPath, char *destPath)
{
    char newsrcPath[4096];
    char newdestPath[4096];
​
    if (mkdir(destPath, 0777)) //如果不存在就用mkdir函数来创建
    {
        printf("目标文件已存在\n");
        return -1;
    }
​
    DIR *srcDp = opendir(srcPath);
    if (srcDp == NULL)
    {
        printf("打开文件夹[%s]失败!\n", srcPath);
        return -1;
    }
    struct dirent *srcDirent = NULL;
    int flag = 0;
    while (srcDirent = readdir(srcDp))
    {
        flag++;
        if (flag > 2) //去除隐藏文件 . ..
        {
            bzero(newsrcPath, sizeof(newsrcPath)); //清空
            bzero(newdestPath, sizeof(newdestPath));
​
            sprintf(newsrcPath, "%s/%s", srcPath, srcDirent->d_name); //保存新的文件路径
            sprintf(newdestPath, "%s/%s", destPath, srcDirent->d_name);
​
            if (srcDirent->d_type == DT_DIR) //文件夹的拷贝
                copy_folder(newsrcPath, newdestPath);
            else //普通文件
                copy_file(newsrcPath, newdestPath);
        }
    }
    return 0;
}
//cp.c源码
/* cp.c  -- file copying (main routines)
   Copyright (C) 1989-2022 Free Software Foundation, Inc.
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
   Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */
​
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <getopt.h>
#include <selinux/label.h>
​
#include "system.h"
#include "argmatch.h"
#include "backupfile.h"
#include "copy.h"
#include "cp-hash.h"
#include "die.h"
#include "error.h"
#include "filenamecat.h"
#include "ignore-value.h"
#include "quote.h"
#include "stat-time.h"
#include "targetdir.h"
#include "utimens.h"
#include "acl.h"
​
/* The official name of this program (e.g., no 'g' prefix).  */
#define PROGRAM_NAME "cp"
​
#define AUTHORS \
  proper_name ("Torbjorn Granlund"), \
  proper_name ("David MacKenzie"), \
  proper_name ("Jim Meyering")
​
/* Used by do_copy, make_dir_parents_private, and re_protect
   to keep a list of leading directories whose protections
   need to be fixed after copying. */
struct dir_attr
{
  struct stat st;
  bool restore_mode;
  size_t slash_offset;
  struct dir_attr *next;
};
​
/* For long options that have no equivalent short option, use a
   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
enum
{
  ATTRIBUTES_ONLY_OPTION = CHAR_MAX + 1,
  COPY_CONTENTS_OPTION,
  NO_PRESERVE_ATTRIBUTES_OPTION,
  PARENTS_OPTION,
  PRESERVE_ATTRIBUTES_OPTION,
  REFLINK_OPTION,
  SPARSE_OPTION,
  STRIP_TRAILING_SLASHES_OPTION,
  UNLINK_DEST_BEFORE_OPENING
};
​
/* True if the kernel is SELinux enabled.  */
static bool selinux_enabled;
​
/* If true, the command "cp x/e_file e_dir" uses "e_dir/x/e_file"
   as its destination instead of the usual "e_dir/e_file." */
static bool parents_option = false;
​
/* Remove any trailing slashes from each SOURCE argument.  */
static bool remove_trailing_slashes;
​
static char const *const sparse_type_string[] =
{
  "never", "auto", "always", NULL
};
static enum Sparse_type const sparse_type[] =
{
  SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS
};
ARGMATCH_VERIFY (sparse_type_string, sparse_type);
​
static char const *const reflink_type_string[] =
{
  "auto", "always", "never", NULL
};
static enum Reflink_type const reflink_type[] =
{
  REFLINK_AUTO, REFLINK_ALWAYS, REFLINK_NEVER
};
ARGMATCH_VERIFY (reflink_type_string, reflink_type);
​
static struct option const long_opts[] =
{
  {"archive", no_argument, NULL, 'a'},
  {"attributes-only", no_argument, NULL, ATTRIBUTES_ONLY_OPTION},
  {"backup", optional_argument, NULL, 'b'},
  {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION},
  {"dereference", no_argument, NULL, 'L'},
  {"force", no_argument, NULL, 'f'},
  {"interactive", no_argument, NULL, 'i'},
  {"link", no_argument, NULL, 'l'},
  {"no-clobber", no_argument, NULL, 'n'},
  {"no-dereference", no_argument, NULL, 'P'},
  {"no-preserve", required_argument, NULL, NO_PRESERVE_ATTRIBUTES_OPTION},
  {"no-target-directory", no_argument, NULL, 'T'},
  {"one-file-system", no_argument, NULL, 'x'},
  {"parents", no_argument, NULL, PARENTS_OPTION},
  {"path", no_argument, NULL, PARENTS_OPTION},   /* Deprecated.  */
  {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION},
  {"recursive", no_argument, NULL, 'R'},
  {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING},
  {"sparse", required_argument, NULL, SPARSE_OPTION},
  {"reflink", optional_argument, NULL, REFLINK_OPTION},
  {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
  {"suffix", required_argument, NULL, 'S'},
  {"symbolic-link", no_argument, NULL, 's'},
  {"target-directory", required_argument, NULL, 't'},
  {"update", no_argument, NULL, 'u'},
  {"verbose", no_argument, NULL, 'v'},
  {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
  {GETOPT_HELP_OPTION_DECL},
  {GETOPT_VERSION_OPTION_DECL},
  {NULL, 0, NULL, 0}
};
​
void
usage (int status)
{
  if (status != EXIT_SUCCESS)
    emit_try_help ();
  else
    {
      printf (_("\
Usage: %s [OPTION]... [-T] SOURCE DEST\n\
  or:  %s [OPTION]... SOURCE... DIRECTORY\n\
  or:  %s [OPTION]... -t DIRECTORY SOURCE...\n\
"),
              program_name, program_name, program_name);
      fputs (_("\
Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
"), stdout);
​
      emit_mandatory_arg_note ();
​
      fputs (_("\
  -a, --archive                same as -dR --preserve=all\n\
      --attributes-only        don't copy the file data, just the attributes\n\
      --backup[=CONTROL]       make a backup of each existing destination file\
\n\
  -b                           like --backup but does not accept an argument\n\
      --copy-contents          copy contents of special files when recursive\n\
  -d                           same as --no-dereference --preserve=links\n\
"), stdout);
      fputs (_("\
  -f, --force                  if an existing destination file cannot be\n\
                                 opened, remove it and try again (this option\n\
                                 is ignored when the -n option is also used)\n\
  -i, --interactive            prompt before overwrite (overrides a previous -n\
\n\
                                  option)\n\
  -H                           follow command-line symbolic links in SOURCE\n\
"), stdout);
      fputs (_("\
  -l, --link                   hard link files instead of copying\n\
  -L, --dereference            always follow symbolic links in SOURCE\n\
"), stdout);
      fputs (_("\
  -n, --no-clobber             do not overwrite an existing file (overrides\n\
                                 a previous -i option)\n\
  -P, --no-dereference         never follow symbolic links in SOURCE\n\
"), stdout);
      fputs (_("\
  -p                           same as --preserve=mode,ownership,timestamps\n\
      --preserve[=ATTR_LIST]   preserve the specified attributes (default:\n\
                                 mode,ownership,timestamps), if possible\n\
                                 additional attributes: context, links, xattr,\
\n\
                                 all\n\
"), stdout);
      fputs (_("\
      --no-preserve=ATTR_LIST  don't preserve the specified attributes\n\
      --parents                use full source file name under DIRECTORY\n\
"), stdout);
      fputs (_("\
  -R, -r, --recursive          copy directories recursively\n\
      --reflink[=WHEN]         control clone/CoW copies. See below\n\
      --remove-destination     remove each existing destination file before\n\
                                 attempting to open it (contrast with --force)\
\n"), stdout);
      fputs (_("\
      --sparse=WHEN            control creation of sparse files. See below\n\
      --strip-trailing-slashes  remove any trailing slashes from each SOURCE\n\
                                 argument\n\
"), stdout);
      fputs (_("\
  -s, --symbolic-link          make symbolic links instead of copying\n\
  -S, --suffix=SUFFIX          override the usual backup suffix\n\
  -t, --target-directory=DIRECTORY  copy all SOURCE arguments into DIRECTORY\n\
  -T, --no-target-directory    treat DEST as a normal file\n\
"), stdout);
      fputs (_("\
  -u, --update                 copy only when the SOURCE file is newer\n\
                                 than the destination file or when the\n\
                                 destination file is missing\n\
  -v, --verbose                explain what is being done\n\
  -x, --one-file-system        stay on this file system\n\
"), stdout);
      fputs (_("\
  -Z                           set SELinux security context of destination\n\
                                 file to default type\n\
      --context[=CTX]          like -Z, or if CTX is specified then set the\n\
                                 SELinux or SMACK security context to CTX\n\
"), stdout);
      fputs (HELP_OPTION_DESCRIPTION, stdout);
      fputs (VERSION_OPTION_DESCRIPTION, stdout);
      fputs (_("\
\n\
By default, sparse SOURCE files are detected by a crude heuristic and the\n\
corresponding DEST file is made sparse as well.  That is the behavior\n\
selected by --sparse=auto.  Specify --sparse=always to create a sparse DEST\n\
file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\
Use --sparse=never to inhibit creation of sparse files.\n\
"), stdout);
      fputs (_("\
\n\
When --reflink[=always] is specified, perform a lightweight copy, where the\n\
data blocks are copied only when modified.  If this is not possible the copy\n\
fails, or if --reflink=auto is specified, fall back to a standard copy.\n\
Use --reflink=never to ensure a standard copy is performed.\n\
"), stdout);
      emit_backup_suffix_note ();
      fputs (_("\
\n\
As a special case, cp makes a backup of SOURCE when the force and backup\n\
options are given and SOURCE and DEST are the same name for an existing,\n\
regular file.\n\
"), stdout);
      emit_ancillary_info (PROGRAM_NAME);
    }
  exit (status);
}
​
/* Ensure that parents of CONST_DST_NAME aka DST_DIRFD+DST_RELNAME have the
   correct protections, for the --parents option.  This is done
   after all copying has been completed, to allow permissions
   that don't include user write/execute.
   ATTR_LIST is a null-terminated linked list of structures that
   indicates the end of the filename of each intermediate directory
   in CONST_DST_NAME that may need to have its attributes changed.
   The command 'cp --parents --preserve a/b/c d/e_dir' changes the
   attributes of the directories d/e_dir/a and d/e_dir/a/b to match
   the corresponding source directories regardless of whether they
   existed before the 'cp' command was given.
   Return true if the parent of CONST_DST_NAME and any intermediate
   directories specified by ATTR_LIST have the proper permissions
   when done.  */
​
static bool
re_protect (char const *const_dst_name, int dst_dirfd, char const *dst_relname,
            struct dir_attr *attr_list, const struct cp_options *x)
{
  struct dir_attr *p;
  char *dst_name;       /* A copy of CONST_DST_NAME we can change. */
  char *src_name;       /* The source name in 'dst_name'. */
​
  ASSIGN_STRDUPA (dst_name, const_dst_name);
  src_name = dst_name + (dst_relname - const_dst_name);
​
  for (p = attr_list; p; p = p->next)
    {
      dst_name[p->slash_offset] = '\0';
​
      /* Adjust the times (and if possible, ownership) for the copy.
         chown turns off set[ug]id bits for non-root,
         so do the chmod last.  */
​
      if (x->preserve_timestamps)
        {
          struct timespec timespec[2];
​
          timespec[0] = get_stat_atime (&p->st);
          timespec[1] = get_stat_mtime (&p->st);
​
          if (utimensat (dst_dirfd, src_name, timespec, 0))
            {
              error (0, errno, _("failed to preserve times for %s"),
                     quoteaf (dst_name));
              return false;
            }
        }
​
      if (x->preserve_ownership)
        {
          if (lchownat (dst_dirfd, src_name, p->st.st_uid, p->st.st_gid) != 0)
            {
              if (! chown_failure_ok (x))
                {
                  error (0, errno, _("failed to preserve ownership for %s"),
                         quoteaf (dst_name));
                  return false;
                }
              /* Failing to preserve ownership is OK. Still, try to preserve
                 the group, but ignore the possible error. */
              ignore_value (lchownat (dst_dirfd, src_name, -1, p->st.st_gid));
            }
        }
​
      if (x->preserve_mode)
        {
          if (copy_acl (src_name, -1, dst_name, -1, p->st.st_mode) != 0)
            return false;
        }
      else if (p->restore_mode)
        {
          if (lchmodat (dst_dirfd, src_name, p->st.st_mode) != 0)
            {
              error (0, errno, _("failed to preserve permissions for %s"),
                     quoteaf (dst_name));
              return false;
            }
        }
​
      dst_name[p->slash_offset] = '/';
    }
  return true;
}
​
/* Ensure that the parent directory of CONST_DIR exists, for
   the --parents option.
   SRC_OFFSET is the index in CONST_DIR (which is a destination
   directory) of the beginning of the source directory name.
   Create any leading directories that don't already exist.
   DST_DIRFD is a file descriptor for the target directory.
   If VERBOSE_FMT_STRING is nonzero, use it as a printf format
   string for printing a message after successfully making a directory.
   The format should take two string arguments: the names of the
   source and destination directories.
   Creates a linked list of attributes of intermediate directories,
   *ATTR_LIST, for re_protect to use after calling copy.
   Sets *NEW_DST if this function creates parent of CONST_DIR.
   Return true if parent of CONST_DIR exists as a directory with the proper
   permissions when done.  */
​
/* FIXME: Synch this function with the one in ../lib/mkdir-p.c.  */
​
static bool
make_dir_parents_private (char const *const_dir, size_t src_offset,
                          int dst_dirfd,
                          char const *verbose_fmt_string,
                          struct dir_attr **attr_list, bool *new_dst,
                          const struct cp_options *x)
{
  struct stat stats;
  char *dir;        /* A copy of CONST_DIR we can change.  */
  char *src;        /* Source name in DIR.  */
  char *dst_dir;    /* Leading directory of DIR.  */
  idx_t dirlen = dir_len (const_dir);
​
  *attr_list = NULL;
​
  /* Succeed immediately if the parent of CONST_DIR must already exist,
     as the target directory has already been checked.  */
  if (dirlen <= src_offset)
    return true;
​
  ASSIGN_STRDUPA (dir, const_dir);
​
  src = dir + src_offset;
​
  dst_dir = alloca (dirlen + 1);
  memcpy (dst_dir, dir, dirlen);
  dst_dir[dirlen] = '\0';
  char const *dst_reldir = dst_dir + src_offset;
  while (*dst_reldir == '/')
    dst_reldir++;
​
  /* XXX: If all dirs are present at the destination,
     no permissions or security contexts will be updated.  */
  if (fstatat (dst_dirfd, dst_reldir, &stats, 0) != 0)
    {
      /* A parent of CONST_DIR does not exist.
         Make all missing intermediate directories. */
      char *slash;
​
      slash = src;
      while (*slash == '/')
        slash++;
      dst_reldir = slash;
​
      while ((slash = strchr (slash, '/')))
        {
          struct dir_attr *new;
          bool missing_dir;
​
          *slash = '\0';
          missing_dir = fstatat (dst_dirfd, dst_reldir, &stats, 0) != 0;
​
          if (missing_dir || x->preserve_ownership || x->preserve_mode
              || x->preserve_timestamps)
            {
              /* Add this directory to the list of directories whose
                 modes might need fixing later. */
              struct stat src_st;
              int src_errno = (stat (src, &src_st) != 0
                               ? errno
                               : S_ISDIR (src_st.st_mode)
                               ? 0
                               : ENOTDIR);
              if (src_errno)
                {
                  error (0, src_errno, _("failed to get attributes of %s"),
                         quoteaf (src));
                  return false;
                }
​
              new = xmalloc (sizeof *new);
              new->st = src_st;
              new->slash_offset = slash - dir;
              new->restore_mode = false;
              new->next = *attr_list;
              *attr_list = new;
            }
​
          /* If required set the default context for created dirs.  */
          if (! set_process_security_ctx (src, dir,
                                          missing_dir ? new->st.st_mode : 0,
                                          missing_dir, x))
            return false;
​
          if (missing_dir)
            {
              mode_t src_mode;
              mode_t omitted_permissions;
              mode_t mkdir_mode;
​
              /* This component does not exist.  We must set
                 *new_dst and new->st.st_mode inside this loop because,
                 for example, in the command 'cp --parents ../a/../b/c e_dir',
                 make_dir_parents_private creates only e_dir/../a if
                 ./b already exists. */
              *new_dst = true;
              src_mode = new->st.st_mode;
​
              /* If the ownership or special mode bits might change,
                 omit some permissions at first, so unauthorized users
                 cannot nip in before the file is ready.  */
              omitted_permissions = (src_mode
                                     & (x->preserve_ownership
                                        ? S_IRWXG | S_IRWXO
                                        : x->preserve_mode
                                        ? S_IWGRP | S_IWOTH
                                        : 0));
​
              /* POSIX says mkdir's behavior is implementation-defined when
                 (src_mode & ~S_IRWXUGO) != 0.  However, common practice is
                 to ask mkdir to copy all the CHMOD_MODE_BITS, letting mkdir
                 decide what to do with S_ISUID | S_ISGID | S_ISVTX.  */
              mkdir_mode = x->explicit_no_preserve_mode ? S_IRWXUGO : src_mode;
              mkdir_mode &= CHMOD_MODE_BITS & ~omitted_permissions;
              if (mkdirat (dst_dirfd, dst_reldir, mkdir_mode) != 0)
                {
                  error (0, errno, _("cannot make directory %s"),
                         quoteaf (dir));
                  return false;
                }
              else
                {
                  if (verbose_fmt_string != NULL)
                    printf (verbose_fmt_string, src, dir);
                }
​
              /* We need search and write permissions to the new directory
                 for writing the directory's contents. Check if these
                 permissions are there.  */
​
              if (fstatat (dst_dirfd, dst_reldir, &stats, AT_SYMLINK_NOFOLLOW))
                {
                  error (0, errno, _("failed to get attributes of %s"),
                         quoteaf (dir));
                  return false;
                }
​
​
              if (! x->preserve_mode)
                {
                  if (omitted_permissions & ~stats.st_mode)
                    omitted_permissions &= ~ cached_umask ();
                  if (omitted_permissions & ~stats.st_mode
                      || (stats.st_mode & S_IRWXU) != S_IRWXU)
                    {
                      new->st.st_mode = stats.st_mode | omitted_permissions;
                      new->restore_mode = true;
                    }
                }
​
              mode_t accessible = stats.st_mode | S_IRWXU;
              if (stats.st_mode != accessible)
                {
                  /* Make the new directory searchable and writable.
                     The original permissions will be restored later.  */
​
                  if (lchmodat (dst_dirfd, dst_reldir, accessible) != 0)
                    {
                      error (0, errno, _("setting permissions for %s"),
                             quoteaf (dir));
                      return false;
                    }
                }
            }
          else if (!S_ISDIR (stats.st_mode))
            {
              error (0, 0, _("%s exists but is not a directory"),
                     quoteaf (dir));
              return false;
            }
          else
            *new_dst = false;
​
          /* For existing dirs, set the security context as per that already
             set for the process global context.  */
          if (! *new_dst
              && (x->set_security_context || x->preserve_security_context))
            {
              if (! set_file_security_ctx (dir, false, x)
                  && x->require_preserve_context)
                return false;
            }
​
          *slash++ = '/';
​
          /* Avoid unnecessary calls to 'stat' when given
             file names containing multiple adjacent slashes.  */
          while (*slash == '/')
            slash++;
        }
    }
​
  /* We get here if the parent of DIR already exists.  */
​
  else if (!S_ISDIR (stats.st_mode))
    {
      error (0, 0, _("%s exists but is not a directory"), quoteaf (dst_dir));
      return false;
    }
  else
    {
      *new_dst = false;
    }
  return true;
}
​
/* Scan the arguments, and copy each by calling copy.
   Return true if successful.  */
​
static bool
do_copy (int n_files, char **file, char const *target_directory,
         bool no_target_directory, struct cp_options *x)
{
  struct stat sb;
  bool new_dst = false;
  bool ok = true;
​
  if (n_files <= !target_directory)
    {
      if (n_files <= 0)
        error (0, 0, _("missing file operand"));
      else
        error (0, 0, _("missing destination file operand after %s"),
               quoteaf (file[0]));
      usage (EXIT_FAILURE);
    }
​
  sb.st_mode = 0;
  int target_dirfd = AT_FDCWD;
  if (no_target_directory)
    {
      if (target_directory)
        die (EXIT_FAILURE, 0,
             _("cannot combine --target-directory (-t) "
               "and --no-target-directory (-T)"));
      if (2 < n_files)
        {
          error (0, 0, _("extra operand %s"), quoteaf (file[2]));
          usage (EXIT_FAILURE);
        }
    }
  else if (target_directory)
    {
      target_dirfd = target_directory_operand (target_directory, &sb);
      if (! target_dirfd_valid (target_dirfd))
        die (EXIT_FAILURE, errno, _("target directory %s"),
             quoteaf (target_directory));
    }
  else
    {
      char const *lastfile = file[n_files - 1];
      int fd = target_directory_operand (lastfile, &sb);
      if (target_dirfd_valid (fd))
        {
          target_dirfd = fd;
          target_directory = lastfile;
          n_files--;
        }
      else
        {
          int err = errno;
          if (err == ENOENT)
            new_dst = true;
​
          /* The last operand LASTFILE cannot be opened as a directory.
             If there are more than two operands, report an error.
             Also, report an error if LASTFILE is known to be a directory
             even though it could not be opened, which can happen if
             opening failed with EACCES on a platform lacking O_PATH.
             In this case use stat to test whether LASTFILE is a
             directory, in case opening a non-directory with (O_SEARCH
             | O_DIRECTORY) failed with EACCES not ENOTDIR.  */
          if (2 < n_files
              || (O_PATHSEARCH == O_SEARCH && err == EACCES
                  && (sb.st_mode || stat (lastfile, &sb) == 0)
                  && S_ISDIR (sb.st_mode)))
            die (EXIT_FAILURE, err, _("target %s"), quoteaf (lastfile));
        }
    }
​
  if (target_directory)
    {
      /* cp file1...filen edir
         Copy the files 'file1' through 'filen'
         to the existing directory 'edir'. */
​
      /* Initialize these hash tables only if we'll need them.
         The problems they're used to detect can arise only if
         there are two or more files to copy.  */
      if (2 <= n_files)
        {
          dest_info_init (x);
          src_info_init (x);
        }
​
      for (int i = 0; i < n_files; i++)
        {
          char *dst_name;
          bool parent_exists = true;  /* True if dir_name (dst_name) exists. */
          struct dir_attr *attr_list;
          char *arg_in_concat = NULL;
          char *arg = file[i];
​
          /* Trailing slashes are meaningful (i.e., maybe worth preserving)
             only in the source file names.  */
          if (remove_trailing_slashes)
            strip_trailing_slashes (arg);
​
          if (parents_option)
            {
              char *arg_no_trailing_slash;
​
              /* Use 'arg' without trailing slashes in constructing destination
                 file names.  Otherwise, we can end up trying to create a
                 directory using a name with trailing slash, which fails on
                 NetBSD 1.[34] systems.  */
              ASSIGN_STRDUPA (arg_no_trailing_slash, arg);
              strip_trailing_slashes (arg_no_trailing_slash);
​
              /* Append all of 'arg' (minus any trailing slash) to 'dest'.  */
              dst_name = file_name_concat (target_directory,
                                           arg_no_trailing_slash,
                                           &arg_in_concat);
​
              /* For --parents, we have to make sure that the directory
                 dir_name (dst_name) exists.  We may have to create a few
                 leading directories. */
              parent_exists =
                (make_dir_parents_private
                 (dst_name, arg_in_concat - dst_name, target_dirfd,
                  (x->verbose ? "%s -> %s\n" : NULL),
                  &attr_list, &new_dst, x));
​
              while (*arg_in_concat == '/')
                arg_in_concat++;
            }
          else
            {
              char *arg_base;
              /* Append the last component of 'arg' to 'target_directory'.  */
              ASSIGN_STRDUPA (arg_base, last_component (arg));
              strip_trailing_slashes (arg_base);
              /* For 'cp -R source/.. dest', don't copy into 'dest/..'. */
              arg_base += STREQ (arg_base, "..");
              dst_name = file_name_concat (target_directory, arg_base,
                                           &arg_in_concat);
            }
​
          if (!parent_exists)
            {
              /* make_dir_parents_private failed, so don't even
                 attempt the copy.  */
              ok = false;
            }
          else
            {
              bool copy_into_self;
              ok &= copy (arg, dst_name, target_dirfd, arg_in_concat,
                          new_dst, x, &copy_into_self, NULL);
​
              if (parents_option)
                ok &= re_protect (dst_name, target_dirfd, arg_in_concat,
                                  attr_list, x);
            }
​
          if (parents_option)
            {
              while (attr_list)
                {
                  struct dir_attr *p = attr_list;
                  attr_list = attr_list->next;
                  free (p);
                }
            }
​
          free (dst_name);
        }
    }
  else /* !target_directory */
    {
      char const *source = file[0];
      char const *dest = file[1];
      bool unused;
​
      if (parents_option)
        {
          error (0, 0,
                 _("with --parents, the destination must be a directory"));
          usage (EXIT_FAILURE);
        }
​
      /* When the force and backup options have been specified and
         the source and destination are the same name for an existing
         regular file, convert the user's command, e.g.,
         'cp --force --backup foo foo' to 'cp --force foo fooSUFFIX'
         where SUFFIX is determined by any version control options used.  */
​
      if (x->unlink_dest_after_failed_open
          && x->backup_type != no_backups
          && STREQ (source, dest)
          && !new_dst
          && (sb.st_mode != 0 || stat (dest, &sb) == 0) && S_ISREG (sb.st_mode))
        {
          static struct cp_options x_tmp;
​
          dest = find_backup_file_name (AT_FDCWD, dest, x->backup_type);
          /* Set x->backup_type to 'no_backups' so that the normal backup
             mechanism is not used when performing the actual copy.
             backup_type must be set to 'no_backups' only *after* the above
             call to find_backup_file_name -- that function uses
             backup_type to determine the suffix it applies.  */
          x_tmp = *x;
          x_tmp.backup_type = no_backups;
          x = &x_tmp;
        }
​
      ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
    }
​
  return ok;
}
​
static void
cp_option_init (struct cp_options *x)
{
  cp_options_default (x);
  x->copy_as_regular = true;
  x->dereference = DEREF_UNDEFINED;
  x->unlink_dest_before_opening = false;
  x->unlink_dest_after_failed_open = false;
  x->hard_link = false;
  x->interactive = I_UNSPECIFIED;
  x->move_mode = false;
  x->install_mode = false;
  x->one_file_system = false;
  x->reflink_mode = REFLINK_AUTO;
​
  x->preserve_ownership = false;
  x->preserve_links = false;
  x->preserve_mode = false;
  x->preserve_timestamps = false;
  x->explicit_no_preserve_mode = false;
  x->preserve_security_context = false; /* -a or --preserve=context.  */
  x->require_preserve_context = false;  /* --preserve=context.  */
  x->set_security_context = NULL;       /* -Z, set sys default context. */
  x->preserve_xattr = false;
  x->reduce_diagnostics = false;
  x->require_preserve_xattr = false;
​
  x->data_copy_required = true;
  x->require_preserve = false;
  x->recursive = false;
  x->sparse_mode = SPARSE_AUTO;
  x->symbolic_link = false;
  x->set_mode = false;
  x->mode = 0;
​
  /* Not used.  */
  x->stdin_tty = false;
​
  x->update = false;
  x->verbose = false;
​
  /* By default, refuse to open a dangling destination symlink, because
     in general one cannot do that safely, give the current semantics of
     open's O_EXCL flag, (which POSIX doesn't even allow cp to use, btw).
     But POSIX requires it.  */
  x->open_dangling_dest_symlink = getenv ("POSIXLY_CORRECT") != NULL;
​
  x->dest_info = NULL;
  x->src_info = NULL;
}
​
/* Given a string, ARG, containing a comma-separated list of arguments
   to the --preserve option, set the appropriate fields of X to ON_OFF.  */
static void
decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
{
  enum File_attribute
    {
      PRESERVE_MODE,
      PRESERVE_TIMESTAMPS,
      PRESERVE_OWNERSHIP,
      PRESERVE_LINK,
      PRESERVE_CONTEXT,
      PRESERVE_XATTR,
      PRESERVE_ALL
    };
  static enum File_attribute const preserve_vals[] =
    {
      PRESERVE_MODE, PRESERVE_TIMESTAMPS,
      PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_XATTR,
      PRESERVE_ALL
    };
  /* Valid arguments to the '--preserve' option. */
  static char const *const preserve_args[] =
    {
      "mode", "timestamps",
      "ownership", "links", "context", "xattr", "all", NULL
    };
  ARGMATCH_VERIFY (preserve_args, preserve_vals);
​
  char *arg_writable = xstrdup (arg);
  char *s = arg_writable;
  do
    {
      /* find next comma */
      char *comma = strchr (s, ',');
      enum File_attribute val;
​
      /* If we found a comma, put a NUL in its place and advance.  */
      if (comma)
        *comma++ = 0;
​
      /* process S.  */
      val = XARGMATCH (on_off ? "--preserve" : "--no-preserve",
                       s, preserve_args, preserve_vals);
      switch (val)
        {
        case PRESERVE_MODE:
          x->preserve_mode = on_off;
          x->explicit_no_preserve_mode = !on_off;
          break;
​
        case PRESERVE_TIMESTAMPS:
          x->preserve_timestamps = on_off;
          break;
​
        case PRESERVE_OWNERSHIP:
          x->preserve_ownership = on_off;
          break;
​
        case PRESERVE_LINK:
          x->preserve_links = on_off;
          break;
​
        case PRESERVE_CONTEXT:
          x->require_preserve_context = on_off;
          x->preserve_security_context = on_off;
          break;
​
        case PRESERVE_XATTR:
          x->preserve_xattr = on_off;
          x->require_preserve_xattr = on_off;
          break;
​
        case PRESERVE_ALL:
          x->preserve_mode = on_off;
          x->preserve_timestamps = on_off;
          x->preserve_ownership = on_off;
          x->preserve_links = on_off;
          x->explicit_no_preserve_mode = !on_off;
          if (selinux_enabled)
            x->preserve_security_context = on_off;
          x->preserve_xattr = on_off;
          break;
​
        default:
          abort ();
        }
      s = comma;
    }
  while (s);
​
  free (arg_writable);
}
​
int
main (int argc, char **argv)
{
  int c;
  bool ok;
  bool make_backups = false;
  char const *backup_suffix = NULL;
  char *version_control_string = NULL;
  struct cp_options x;
  bool copy_contents = false;
  char *target_directory = NULL;
  bool no_target_directory = false;
  char const *scontext = NULL;
​
  initialize_main (&argc, &argv);
  set_program_name (argv[0]);
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);
​
  atexit (close_stdin);
​
  selinux_enabled = (0 < is_selinux_enabled ());
  cp_option_init (&x);
​
  while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
                           long_opts, NULL))
         != -1)
    {
      switch (c)
        {
        case SPARSE_OPTION:
          x.sparse_mode = XARGMATCH ("--sparse", optarg,
                                     sparse_type_string, sparse_type);
          break;
​
        case REFLINK_OPTION:
          if (optarg == NULL)
            x.reflink_mode = REFLINK_ALWAYS;
          else
            x.reflink_mode = XARGMATCH ("--reflink", optarg,
                                       reflink_type_string, reflink_type);
          break;
​
        case 'a':
          /* Like -dR --preserve=all with reduced failure diagnostics.  */
          x.dereference = DEREF_NEVER;
          x.preserve_links = true;
          x.preserve_ownership = true;
          x.preserve_mode = true;
          x.preserve_timestamps = true;
          x.require_preserve = true;
          if (selinux_enabled)
             x.preserve_security_context = true;
          x.preserve_xattr = true;
          x.reduce_diagnostics = true;
          x.recursive = true;
          break;
​
        case 'b':
          make_backups = true;
          if (optarg)
            version_control_string = optarg;
          break;
​
        case ATTRIBUTES_ONLY_OPTION:
          x.data_copy_required = false;
          break;
​
        case COPY_CONTENTS_OPTION:
          copy_contents = true;
          break;
​
        case 'd':
          x.preserve_links = true;
          x.dereference = DEREF_NEVER;
          break;
​
        case 'f':
          x.unlink_dest_after_failed_open = true;
          break;
​
        case 'H':
          x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
          break;
​
        case 'i':
          x.interactive = I_ASK_USER;
          break;
​
        case 'l':
          x.hard_link = true;
          break;
​
        case 'L':
          x.dereference = DEREF_ALWAYS;
          break;
​
        case 'n':
          x.interactive = I_ALWAYS_NO;
          break;
​
        case 'P':
          x.dereference = DEREF_NEVER;
          break;
​
        case NO_PRESERVE_ATTRIBUTES_OPTION:
          decode_preserve_arg (optarg, &x, false);
          break;
​
        case PRESERVE_ATTRIBUTES_OPTION:
          if (optarg == NULL)
            {
              /* Fall through to the case for 'p' below.  */
            }
          else
            {
              decode_preserve_arg (optarg, &x, true);
              x.require_preserve = true;
              break;
            }
          FALLTHROUGH;
​
        case 'p':
          x.preserve_ownership = true;
          x.preserve_mode = true;
          x.preserve_timestamps = true;
          x.require_preserve = true;
          break;
​
        case PARENTS_OPTION:
          parents_option = true;
          break;
​
        case 'r':
        case 'R':
          x.recursive = true;
          break;
​
        case UNLINK_DEST_BEFORE_OPENING:
          x.unlink_dest_before_opening = true;
          break;
​
        case STRIP_TRAILING_SLASHES_OPTION:
          remove_trailing_slashes = true;
          break;
​
        case 's':
          x.symbolic_link = true;
          break;
​
        case 't':
          if (target_directory)
            die (EXIT_FAILURE, 0,
                 _("multiple target directories specified"));
          target_directory = optarg;
          break;
​
        case 'T':
          no_target_directory = true;
          break;
​
        case 'u':
          x.update = true;
          break;
​
        case 'v':
          x.verbose = true;
          break;
​
        case 'x':
          x.one_file_system = true;
          break;
​
        case 'Z':
          /* politely decline if we're not on a selinux-enabled kernel.  */
          if (selinux_enabled)
            {
              if (optarg)
                scontext = optarg;
              else
                {
                  x.set_security_context = selabel_open (SELABEL_CTX_FILE,
                                                         NULL, 0);
                  if (! x.set_security_context)
                    error (0, errno, _("warning: ignoring --context"));
                }
            }
          else if (optarg)
            {
              error (0, 0,
                     _("warning: ignoring --context; "
                       "it requires an SELinux-enabled kernel"));
            }
          break;
​
        case 'S':
          make_backups = true;
          backup_suffix = optarg;
          break;
​
        case_GETOPT_HELP_CHAR;
​
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
​
        default:
          usage (EXIT_FAILURE);
        }
    }
​
  if (x.hard_link && x.symbolic_link)
    {
      error (0, 0, _("cannot make both hard and symbolic links"));
      usage (EXIT_FAILURE);
    }
​
  if (x.interactive == I_ALWAYS_NO)
    x.update = false;
​
  if (make_backups && x.interactive == I_ALWAYS_NO)
    {
      error (0, 0,
             _("options --backup and --no-clobber are mutually exclusive"));
      usage (EXIT_FAILURE);
    }
​
  if (x.reflink_mode == REFLINK_ALWAYS && x.sparse_mode != SPARSE_AUTO)
    {
      error (0, 0, _("--reflink can be used only with --sparse=auto"));
      usage (EXIT_FAILURE);
    }
​
  x.backup_type = (make_backups
                   ? xget_version (_("backup type"),
                                   version_control_string)
                   : no_backups);
  set_simple_backup_suffix (backup_suffix);
​
  if (x.dereference == DEREF_UNDEFINED)
    {
      if (x.recursive && ! x.hard_link)
        /* This is compatible with FreeBSD.  */
        x.dereference = DEREF_NEVER;
      else
        x.dereference = DEREF_ALWAYS;
    }
​
  if (x.recursive)
    x.copy_as_regular = copy_contents;
​
  /* Ensure -Z overrides -a.  */
  if ((x.set_security_context || scontext)
      && ! x.require_preserve_context)
    x.preserve_security_context = false;
​
  if (x.preserve_security_context && (x.set_security_context || scontext))
    die (EXIT_FAILURE, 0,
         _("cannot set target context and preserve it"));
​
  if (x.require_preserve_context && ! selinux_enabled)
    die (EXIT_FAILURE, 0,
         _("cannot preserve security context "
           "without an SELinux-enabled kernel"));
​
  /* FIXME: This handles new files.  But what about existing files?
     I.e., if updating a tree, new files would have the specified context,
     but shouldn't existing files be updated for consistency like this?
       if (scontext && !restorecon (NULL, dst_path, 0))
          error (...);
   */
  if (scontext && setfscreatecon (scontext) < 0)
    die (EXIT_FAILURE, errno,
         _("failed to set default file creation context to %s"),
         quote (scontext));
​
#if !USE_XATTR
  if (x.require_preserve_xattr)
    die (EXIT_FAILURE, 0, _("cannot preserve extended attributes, cp is "
                            "built without xattr support"));
#endif
​
  /* Allocate space for remembering copied and created files.  */
​
  hash_init ();
​
  ok = do_copy (argc - optind, argv + optind,
                target_directory, no_target_directory, &x);
​
  main_exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
}

复制单个文件 shell编程 查看复制文件的大小,和源文件的区别 shell编程 比较量文件的差别。 shell编程 递归复制目录 shell编程 复制文件到目录下 shell编程

4、gdb 调试工具

  • file

    在gdb内装载可执行程序 (gdb)a1.out

  • b

    下断点,b main (主函数处下断点),b 0x70123456(在某个地址处下断点)

  • start

    直接执行程序到main()函数第一条指令

  • r

    执行程序,一般就是在下好断点之后执行r运行到断点处,然后分析。

  • n

    单步执行,它不会进入函数内部,遇到一个函数它会直接执行,并返回函数结果。

  • s

    步进,进入函数内部。

  • display

    查看变量值,display a,就会显示a的值。

  • l

    查看源码,如果编译时加入了-g参数,就可以用l去查看源码。

  • info break

    查看有哪些断点

  • d

    删除断点

  • q

    退出 shell编程

用file装载文件,start执行到main的第一行,查看c代码,然后单步执行。 shell编程 跟踪查看变量a的值。 shell编程

使用s步进函数,用l查看函数内部c代码。finish跳出hello函数。