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;
}
gdb调试:
优化后
未优化
优化分析:
- 代码分析
- 执行分析
- 大小分析 区别:-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);
}
执行结果: 用ls去查看,发现文件大小没有不同,只是两者权限不同。权限设置的是777,但是由于用户的默认权限掩码,
0022,所以创建出来的权限就是0777-0022=0755。
用diff去比较,
diff会针对文本内容逐行进行对比,如果有不同就会显示出这有差别的两行,这里看到文本内容上并没有什么差别。 用cmp去对比, cmp会逐个字符去比较,会告诉有差异的字符的位置,第几行第几个字符。不加参数的情况下它只会显示出第一个有差异的位置。-l参数会帮助显示出所有有差异的位置。这里也没有不同。
编写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太老了还是啥。
这里文件的大小就是总的字符串长度。
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, ©_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);
}
复制单个文件 查看复制文件的大小,和源文件的区别 比较量文件的差别。 递归复制目录 复制文件到目录下
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
退出
用file装载文件,start执行到main的第一行,查看c代码,然后单步执行。 跟踪查看变量a的值。
使用s步进函数,用l查看函数内部c代码。finish跳出hello函数。