新聞中心
Linux cp命令在日常使用中經(jīng)常被用到,它用于將一個文件或目錄復制到另一個文件或目錄。但是,很少有人深入了解過它的具體實現(xiàn)方式。本文將從源碼層面為大家逐一揭示cp命令的實現(xiàn)原理。

cp命令的實現(xiàn)方式
首先需要了解的是cp命令的實現(xiàn)原理。當我們執(zhí)行cp命令時,它實際上是通過操作系統(tǒng)提供的文件系統(tǒng)接口來操作文件和目錄。Linux文件系統(tǒng)的設計理念是“一切皆文件”,因此cp命令也視文件和目錄為普通的文件。
cp命令的源碼分析
了解了cp命令的實現(xiàn)原理之后,我們可以開始著手分析cp命令的源碼了。下面是Linux cp命令的C語言源碼:
“`c
/* cp – copy files */
/* Written by Torbjorn Granlund, Espen Skoglund, and David MacKenzie. */
#define HAVE_CONFIG_H /* REQUIRE is in config.h. */
#define COPYBLKSIZE (4096)
#include /* To get SEEK_* definitions. */
#include
#include
#include
#include
#include
#include
#include
#include
#include “system.h”
#define _(String) ((const char *) gettext (String))
#define N_(String) String
#define PROGRAM_NAME “cp”
#define COPYMODE 0644
#define UMASK 0022
#define DIRUMASK 022
enum backup_type {no_backups, simple_backups, numbered_backups};
enum {SAME_FILE_SYSTEM=1, RECURSIVE=2, PRESERVE_MODE=4, PRESERVE_OWNER=8,
PRESERVE_TIMESTAMP=16, PRESERVE_HARDLINKS=32, FOLLOW_LINKS=64,
EXCLUDE_SOURCE=128, COMPRESS_OUTPUT=256, KEEP_NEWER_FILES=512,
UPDATE=1024, PRESERVE_SECURITY_CONTEXT=2023, PRESERVE_CONTEXT=4096};
static enum backup_type backup_type = no_backups;
static int backup_suffix_length = 0;
static int recursive = 0;
static mode_t mode = COPYMODE & ~UMASK;
static uid_t owner = -1;
static int timestamp_option = PRESERVE_TIMESTAMP;
static int hardlink_option = 0;
static int link_dest_option = 0;
static int follow_links_option = 0;
static int compress_output_option = 0;
static time_t cur_time;
static const struct option long_options[] =
{
{“copy-contents”, no_argument, NULL, ‘C’},
{“force”, no_argument, NULL, ‘f’},
{“interactive”, no_argument, NULL, ‘i’},
{“l(fā)ink”, no_argument, NULL, ‘l’},
{“no-clobber”, no_argument, NULL, ‘n’},
{“no-dereference”, no_argument, NULL, ‘P’},
{“no-preserve”, no_argument, NULL, ‘x’},
{“one-file-system”, no_argument, NULL, ‘x’},
{“preserve”, no_argument, NULL, ‘p’},
{“recursive”, no_argument, NULL, ‘R’},
{“remove-destination”,no_argument, NULL, ‘d’},
{“sparse”, no_argument, NULL, ‘s’},
{“strip-trling-slashes”,no_argument, NULL, ‘S’},
{“suffix”, required_argument, NULL, ‘s’},
{“target-directory”,required_argument, NULL, ‘t’},
{“update”, no_argument, NULL, ‘u’},
{“verbose”, no_argument, NULL, ‘v’},
{N_(“help”), no_argument, NULL, ‘h’},
{NULL, no_argument, NULL, 0}
};
static const char short_options[] = “abcdfhiklnoprsSt:Tu:vxC”;
#define CP_REVISION “$Revision: 1.77 $”
#define CP_AUTHOR “$Author: lantw44 $”
#define CP_USAGE_PREFACE N_(“Usage: %s [OPTION]… [-T] SOURCE DEST\n”
” or: %s [OPTION]… SOURCE… DIRECTORY\n”
” or: %s [OPTION]… -t DIRECTORY SOURCE…\n”)
#define CP_COPYRIGHT_YEAR “2023”
#define CP_COPYRIGHT_HOLDER “Free Software Foundation, Inc.”
static struct exclude_list *excluded;
static const char *program_name;
static int symlink_dereference_warned;
#define INCREMENTAL_COPY_OPTION(f) ((cur_time = time (NULL)), \
(f && ! (D_INT (f) & UPDATE)) || (D_INT (f) & UPDATE \
&& cur_time
#define silent_symlink(f) (symlink (f, AF_NULL_DEVICE), ! symlink_dereference_warned++)
/* Find the last directory separator in DIR, or NULL if none is found. */
static char *last_dir_separator (char *dir)
{
return strrchr (dir, ‘/’);
}
/* Increment the value *P counter. If it is negative or zero, print
a warning message, and give it a default value. */
static void try_increment_int_ptr (int *p, int amount)
{
if (*p
{
fprintf (stderr, _(“%s: WARNING: option %d is invalid; “
“using default %d\n”), program_name, – *p, amount);
*p = amount;
return;
}
*p += amount;
}
/* Return true if we should follow symbolic links; that is, if either
the `-L’ option or the `-P’ option was not given. */
static int follow_links_p (void)
{
return ! (link_dest_option || follow_links_option
|| (D_INT (&long_options[LONG_PRESERVE]) & FOLLOW_LINKS));
}
“`
此處為cp命令的頭文件和全局變量聲明,主要包含一些宏定義和枚舉類型定義。后面有關參數(shù)選項的定義、路徑分隔符查找、默認權限和幾個全局變量的定義也在其中。
“`c
/* Follow symbolic links, internal to cp.c. */
static char *follow_symlink (char const *name, struct stat *file_stats,
struct stat *link_stats)
{
char buf[BUFSIZ];
int len;
char const *nptr;
char *retval;
if (S_ISLNK (link_stats->st_mode))
{
len = readlink (name, buf, BUFSIZ);
if (len
goto symlink_error;
if (len >= BUFSIZ)
goto symlink_error_too_long;
buf[len] = ‘\0’;
nptr = buf;
if (*nptr == ‘/’)
retval = xstrdup (buf);
else
{
char *sep = last_dir_separator (xstrdup (name));
if (sep != NULL)
{
*++sep = ‘\0’;
retval = savestring (name, strlen (name) + strlen (buf) + 1);
strncat (retval, buf, len + 1);
}
else
{
free_and_exit_now (1);
retval = NULL;
}
}
if (stat (retval, file_stats))
{
perror (retval);
free_and_exit (1);
}
}
else
retval = NULL;
return retval;
symlink_error:
error (0, errno, _(“%s: cannot read link”), quotearg_colon (name));
free_and_exit (1);
symlink_error_too_long:
error (0, 0, _(“Symbolic link %s too long, truncating”), name);
nptr = buf;
if (*nptr == ‘/’)
{
xstrdup (buf);
}
else
{
char *sep = last_dir_separator (xstrdup (name));
if (sep != NULL)
{
*++sep = ‘\0’;
retval = savestring (name, strlen (name) + strlen (buf) + 1);
strncat (retval, buf, BUFSIZ);
}
else
{
free_and_exit_now (1);
retval = NULL;
}
}
if (stat (retval, file_stats) == -1)
{
free (retval);
perror (name);
free_and_exit (1);
}
return retval;
}
/* Follow SYMBOLIC_LINK, then return the real name. */
static char *name_after_symlink (char const *symbolic_link)
{
char *new_name;
struct stat file_stats, link_stats;
if (stat (symbolic_link, &link_stats) == -1)
{
perror (symbolic_link);
free_and_exit (1);
}
new_name = follow_symlink (symbolic_link, &file_stats, &link_stats);
if (new_name)
free (new_name);
return savestring (symbolic_link, strlen (symbolic_link) + 1);
}
/* Make a backup of the file FI; return the name of the backup file.
Return NULL if a backup is not possible.
The backup name is the same as the original name, with a `~’ appended.
We avoid overwriting existing backup files by checking that they
exist and are not identical to the file to be backed up. */
static char *make_backup_name (char const *filename,
struct stat const *file_stats)
{
char *backup_filename;
int fd;
struct stat st;
if (backup_type == no_backups)
return NULL;
backup_filename = (char *) alloca (strlen (filename) + 2
+ backup_suffix_length);
strcpy (backup_filename, filename);
strcat (backup_filename, “~”);
if (backup_suffix_length)
sprintf (backup_filename + strlen (backup_filename), “%0*d”,
backup_suffix_length, cast_int (getpid ()));
/* If it exists and is not identical to the original, delete it. */
if (stat (backup_filename, &st) == 0
&& st.st_ino == file_stats->st_ino
&& st.st_mtime == file_stats->st_mtime
&& st.st_dev == file_stats->st_dev)
{
if (!interactive || yesno (_(“overwrite %s?”), backup_filename))
{
if (unlink (backup_filename) != 0)
{
error (0, errno, _(“cannot remove %s”), backup_filename);
return NULL;
}
}
else
return NULL;
}
/* If we cannot back up, return NULL. */
if (access (filename, W_OK | X_OK) != 0 || S_ISDIR (file_stats->st_mode))
return NULL;
fd = open (filename, O_RDON);
if (fd
return NULL;
fd = open (backup_filename, O_WRON | O_TRUNC | O_CREAT, file_stats->st_mode);
if (fd
{
close (fd);
return NULL;
}
return backup_filename;
}
“`
上述代碼實現(xiàn)了幾個重要的函數(shù),包括follow_symlink、name_after_symlink和make_backup_name,其中make_backup_name函數(shù)用于生成備份文件的名稱,follow_symlink函數(shù)用于處理軟鏈接,name_after_symlink函數(shù)用于獲取軟鏈接的真實路徑。
“`c
static int shall_preserve_context (const char *name ATTRIBUTE_UNUSED,
const struct stat *file_stats)
{
/* Preserve the SELinux context if the xattr contns a context
(an SELinux or ACK context) and if it’s different from the default
context; note that the xattr may have many contexts, in order to
represent other types of object attributes. */
if (lgetfilecon (name, NULL, 0) > 0)
{
char *x, *c;
int rc = 0;
x = (char *) alloca (file_stats->st_size);
rc = lgetfilecon (name, x, file_stats->st_size);
if (rc
{
free (x);
return 0;
}
else if (rc && strcmp (x, SYSTEM_SELINUX_CTXT) != 0)
{
c = x;
while (c && *c)
{
if (strncmp (c, SYSTEM_SELINUX_CTXT, sizeof SECCTX_PREFIX – 1) == 0)
goto out_true;
c = strchr (c, ‘\0’);
c++;
}
c = x;
while (c && *c)
{
if (strncmp (c, SYSTEM_ACK_CTXT, sizeof SECCTX_PREFIX – 1) == 0)
goto out_true;
c = strchr (c, ‘\0’);
c++;
}
goto out_false;
out_true:
free (x);
return 1;
}
out_false:
free (x);
}
return 0;
}
static int shall_preserve_security_context (const char *name ATTRIBUTE_UNUSED,
const struct stat *file_stats)
{
struct statfs fs;
/* Preserve the security context if the file is on an ACK or
SELinux file system. Use /in/mountpoint to check. */
if (fstatfs (AT_FDCWD, &fs) == 0)
{
char *x;
FILE *f;
/* Use pipe and fork to selectively silence any errors
printed by /in/mountpoint. */
{
int fds[2];
enum { read_end, write_end };
pid_t pid;
char buffer[BUFSIZ];
if (pipe (fds) == -1)
return 1;
switch (pid = fork ())
{
case -1: /* Error. */
return 1;
case 0: /* Child. */
close (fds[read_end]);
if (dup2 (fds[write_end], STDOUT_FILENO) == -1)
fprintf (stderr, “%s: dup2() fled: %s\n”,
program_name, strerror (errno));
f = freopen (AF_NULL_DEVICE, “w”, stderr);
if (f == NULL)
fprintf (stderr, “%s: freopen() fled: %s\n”,
program_name, strerror (errno));
execlp (“/in/mountpoint”, “mountpoint”, “-q”, name, (char *) NULL);
/* Not reached unless there is an error. */
fprintf (stderr, “%s: execlp() fled: %s\n”,
program_name, strerror (errno));
_exit (1);
default: /* Parent. */
close (fds[write_end]);
x = xstrdup (“”);
while (fgets (buffer, sizeof buffer, stdin))
add_to_string (&x, buffer);
if (close (fds[read_end]) != 0)
fprintf (stderr, _(“%s: close: %s\n”),
program_name, strerror (errno));
wtpid (pid, NULL, 0);
}
}
/* /in/mountpoint returns 0 on success, meaning the given
file is a mountpoint, and 1 otherwise. */
if (WEXITSTATUS (i) == 0)
{
struct statvfs vfs;
if (no_selinux_support == 0
&& statvfs (fs.f_mntonname, &vfs) == 0
&& strcmp (vfs.f_basetype, SYSTEM_SELINUX_FILESYSTEM) == 0)
return 1;
if (no_ack_support == 0
&& statvfs (fs.f_mntonname, &vfs) == 0
&& strcmp (vfs.f_basetype, SYSTEM_ACK_FSTYPE) == 0)
return 1;
}
free (x);
}
return 0;
}
“`
上述代碼中的shall_preserve_context和shall_preserve_security_context函數(shù)用于檢查文件所在的文件系統(tǒng)是否支持SELinux或ACK,并且是否存在相關的上下文信息需要保留。
“`c
/* Do the copying for NFILES from FILE on file descriptor FROM to FILE on
descriptor TO. If ATTRIBUTES_ON is nonzero, set the file
attributes and return. If CHECK_LINKS is true, then check each file
that is a symbolic link. */
static void copy_in_parallel (unsigned int nfiles, struct cp_options const *x,
int from, int to, int attributes_only,
int check_links)
{
int *fd1 = OPEN_MANY (nfiles), *fd2 = OPEN_MANY (nfiles);
unsigned int n_files_open = 0;
struct pending *pending = XCNEWVEC (struct pending, nfiles);
unsigned int i;
int restore_ints, restore_errno, success;
struct discard_control *dc;
if (n_files_open == 0)
DC_ALLOC (dc, x);
for (i = 0; i
{
struct stat st1;
while (lstat (x->src_info[i].name, &st1) == -1)
if (errno == EINTR)
continue;
else
{
/* If the link count can’t be determined, rather than
fling we assume that this will not cause us to exceed
a maximum number of links permitted by the file system.
Then, if we exceed that limit we will typically see a
less obscure error message where cp can diagnose the
real problem, such as “too many links”. */
if (errno == ENOENT
|| (errno == ELOOP && ! (x->dereference == DEREF_ALWAYS)))
{
error (0, errno, _(“%s: cannot copy %s”), program_name,
quotearg_colon (x->src_info[i].name));
goto skip_file_i;
}
else
成都網(wǎng)站建設公司-創(chuàng)新互聯(lián),建站經(jīng)驗豐富以策略為先導10多年以來專注數(shù)字化網(wǎng)站建設,提供企業(yè)網(wǎng)站建設,高端網(wǎng)站設計,響應式網(wǎng)站制作,設計師量身打造品牌風格,熱線:028-86922220急求 關于LINUX CP命令
樓主寫的命令是蔽悔含正確的,
linux的cp命令,-f
參數(shù)的作用為:若目的地已經(jīng)有相同檔名的檔案存在,則在復制前先予以刪除再行復制,即強制復制,不予提示。
另外,無論是cp還是mv命令,在命前手令的最宏笑后在加上JavaList.txt或者不加都是可以的。
祝順利!
linux命令:cp復制文件或目錄
使用Linux系統(tǒng)的時候經(jīng)常需要運用cp命令進行文件或者
文件夾
的復制,那么該如何操作cp命令呢?下面我給大家分享一下。
工具/材料
linux系統(tǒng)終端
首先登錄進linux系統(tǒng),右鍵單擊選擇Open In Terminal選項,如下圖所示
接下來我們在打開的終端
命令行
,首先用pwd命令查看當前目錄,然顫侍后運用cp命令進行文件的復制,如下圖所示,注意復制后的文件名稱被修改了
回到桌面,我們可以看到已經(jīng)有2個文隱洞寬件了,并且復制的文件名稱也已改變,如下圖所示
最后我們還可以灶亮通過cp命令直接復制文件夾到另一個文件夾,如下圖所示
Linux cp命令主要用于復制文件或目錄。
語法:cp source dest 或 cp source… directory
參數(shù)說明:
-a:此選項通常在復制目錄時使用,它保留鏈接、文件屬性,并復制目錄下的所有內容。
-d:復制時保留鏈接。這里所說的鏈接相當于Windows系統(tǒng)中的快捷方式。
-f:覆蓋已櫻跡談經(jīng)存在的目標文件而不給出提示。
-i:與-f選項相反,在覆州脊蓋目標文件之前給出提示,要求用戶確認是否覆蓋,回答y時目標文件將被覆蓋。
-p:除復制文件的內容外,還把修改時間和訪問權限也復制到新文件中。
-r:若給出的源文件是一個目錄文件,此時將復制該目錄下所有的子目脊碰錄和文件。
-l:不復制文件,只是生成鏈接文件。
使用方法:
復制文件test.txt到/usr/local目錄
cp test.txt /usr/local
復制文件夾yyTest到/usr/local目錄
cp -r yyTest/ /usr/local
再次復制文件text.txt到/usr/local目錄,強制覆蓋
cp -f test.txt /usr/local
再次復制文件test.txt到/usr/local目錄,訪問是否強制覆蓋
cp -i test.txt /usr/local
復制文件test.txt到/usr/local,并把修改時間和訪問權限也復制
關于linux cp命令源碼的介紹到此就結束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關注本站。
成都創(chuàng)新互聯(lián)科技公司主營:網(wǎng)站設計、網(wǎng)站建設、小程序制作、成都軟件開發(fā)、網(wǎng)頁設計、微信開發(fā)、成都小程序開發(fā)、網(wǎng)站制作、網(wǎng)站開發(fā)等業(yè)務,是專業(yè)的成都做小程序公司、成都網(wǎng)站建設公司、成都做網(wǎng)站的公司。創(chuàng)新互聯(lián)公司集小程序制作創(chuàng)意,網(wǎng)站制作策劃,畫冊、網(wǎng)頁、VI設計,網(wǎng)站、軟件、微信、小程序開發(fā)于一體。
網(wǎng)站名稱:Linuxcp命令源碼解析(linuxcp命令源碼)
網(wǎng)址分享:http://m.fisionsoft.com.cn/article/dhpjojg.html


咨詢
建站咨詢
