http://blog.chinaunix.net/u3/101042/showart_2020063.html
----------------------------------------------------------------------------------------------------------------------------------------
首先是进入main
获得program_name //这个是执行程序的文件名
然后设置环境变量,初始化退出的状态,代码如下:
1566 program_name =
argv[
0]
;
1567 setlocale
(
LC_ALL
,
""
)
;
1568 textdomain (
PACKAGE)
;
1570 exit_status =
TAREXIT_SUCCESS;
|
下面这个函数是tar里封装的一个申请内存的函数:
74 /* Allocate N bytes of memory dynamically, with error checking. */
75
76 VOID
*
77 xmalloc (
n)
78 size_t
n;
79 {
80 VOID
*
p;
81
82 p =
malloc
(
n)
;
83 if
(
p =
=
0)
84 p =
fixup_null_alloc (
n)
;
85 return
p;
=
>
86 }
|
decode_options (argc, argv);这个函数是在main函数里面的,用来获得我们执行tar的时候带的参数的里面我们会看到一个getopt
1072 /*----------------------------.
1073 | Parse the options for tar. |
1074 `----------------------------*/
1075
1076 #
define
OPTION_STRING \
1077 "-01234567ABC:F:GK:L:MN:OPRST:V:WX:Zb:cdf:g:hiklmoprstuvwxz"
1078
1079 #
define
SET_COMMAND_MODE(
Mode)
\
1080 (
command_mode =
command_mode =
=
COMMAND_NONE ?
(
Mode)
:
COMMAND_TOO_MANY)
1081
1082 static
void
1083 decode_options (
int
argc,
char
*
const
*
argv)
1084 {
1085 int
optchar;
/* option letter */
1086
1087 /* Set some default option values. */
1088 =
>
1089 blocking =
DEFAULT_BLOCKING;
1090 flag_rsh_command =
NULL
;
1091
|
接着通过下面这个循环获得指令中的参数
1141 /* Parse all options and non-options as they appear. */
1142
1143 while
(
optchar =
getopt_long (
argc,
argv,
OPTION_STRING,
long_options,
NULL
)
,
1144 optchar !
=
EOF
)
=
>
1145 switch
(
optchar)
|
看一下optchar
1848 (
gdb)
print optchar
1849 $68 =
99
|
输出的是99,可以看一下对应的ascii,在终端里输入man ascii的时候,找到
143 99 63 c
这么一行,第一列是八进制,第二列是10进制,第三列式16进制,第四列就是对应的字符了。
这个是在一个while循环里面做的,我使用的是一个打包的参数,不带压缩参数:
1837 (
gdb)
p argv[
0]
1838 $63 =
0xbffff758 "/home/liuqi/dvntar/dvntar"
1839 (
gdb)
p argv[
1]
1840 $64 =
0xbffff772 "-cf"
1841 (
gdb)
p argv[
2]
1842 $65 =
0xbffff776 "example.tar"
1843 (
gdb)
p argv[
3]
1844 $66 =
0xbffff782 "example"
1845 (
gdb)
p argv[
4]
1846 $67 =
0x0
1847 (
gdb)
|
以上是命令行输入的参数,可以看到我输入的是:
/
home/
liuqi/
dvntar/
dvntar -
cf example.
tar example
|
然后继续向下走,就会到
1315 case
'c'
:
=
>
1316 SET_COMMAND_MODE (
COMMAND_CREATE)
;
1317 break
;
|
这里需要注意,后面会提到,设置命令模式为COMMAND_CREATE模式,这个在main里面会看到,打包的工作主要是也在这里做
在循环获得参数后,会得到一个f参数
这个时候会进入:
1331 case
'f'
:
=
>
1332 if
(
archive_names =
=
allocated_archive_names)
1333 {
1334 allocated_archive_names *
=
2;
1335 archive_name_array =
(
const
char
*
*
)
xrealloc(
archive_name_array,
sizeof
(
const
char
*
)
*
allocated_archive_names)
;
1336 }
1337 archive_name_array[
archive_names+
+
]
=
optarg;
1338 break
;
1339
1857 (
gdb)
print archive_names
1858 $70 =
0
1859 (
gdb)
print allocated_archive_names
1860 $71 =
10
1861 (
gdb)
|
因为两个值不同,所以不会进if条件的立面,会直接进入archive_name_array[archive_names++] = optarg;
再回到循环获得optarg的时候,会看到
1865 (
gdb)
print optchar
1866 $72 =
1
1867 (
gdb)
|
然后就进入了
1157 case
1:
1158 /* File name or non-parsed option, because of RETURN_IN_ORDER
1159 ordering triggerred by the leading dash in OPTION_STRING. */
1160 =
>
1161 name_add (
optarg)
;
1162 break
;
|
添加文件名在name_array字符串结尾
109 /*--------------------------------------------------------------.
110 | Add NAME at end of name_array, reallocating it as necessary. |
111 `--------------------------------------------------------------*/
112
113 static
void
114 name_add (
const
char
*
name)
115 {
=
>
116 if
(
names =
=
allocated_names)
117 {
118 allocated_names *
=
2;
119 name_array =
(
const
char
*
*
)
xrealloc (
name_array,
sizeof
(
const
char
*
)
*
allocated_names)
;
120 }
121 name_array[
names+
+
]
=
name;
122 }
|
从gdb里面可以看到,name是
1868 (
gdb)
step
1869 name_add (
name=
0xbffff782 "example"
)
at /
home/
liuqi/
dvntar/
src/
tar.
c:
116
1870 (
gdb)
|
由于参数里面没有带z或者j的压缩,所以,这里
1551 if (flag_compress_block && !flag_compressprog)
没有设置flag_compressprog和flag_compress_block
如果带了对应的参数的话,将会多起一个进程,使用管道来进行gzip压缩,这个在代码里面会看到,用gdb可以跟到起新进程那里,fork函数启动的子进程。
执行完了以后会回到main函数,这个时候会进行下一步
=>1590 if (!names_argv)
1591 name_init (argc, argv);
gdb打印一下names_argv,得出结果如下
1885 (gdb) print names_argv
1886 $73 = (char * const *) 0x0
1887 (gdb)
看结果会进入 name_init (argc, argv);
进去看看:
由于参数里面没有带z或者j的压缩,所以,这里
1551 if
(
flag_compress_block &
&
!
flag_compressprog)
没有设置flag_compressprog和flag_compress_block
如果带了对应的参数的话,将会多起一个进程,使用管道来进行gzip压缩,这个在代码里面会看到,用gdb可以跟到起新进程那里,fork函数启动的子进程。
执行完了以后会回到main函数,这个时候会进行下一步 =
>
1590 if
(
!
names_argv)
1591 name_init (
argc,
argv)
;
gdb打印一下names_argv,得出结果如下
1885 (
gdb)
print names_argv
1886 $73 =
(
char
*
const
*
)
0x0
1887 (
gdb)
看结果会进入 name_init (
argc,
argv)
;
进去看看:
|
从代码看,并用gdb输出了一下
1890 (
gdb)
print flag_namefile
1891 $74 =
0
1892 (
gdb)
|
结果是这个函数会将参数设置给公共变量names_argc和names_argv。
然后开始之前的设置的
=
>
1598 switch
(
command_mode)
1599 {
|
前面设置过命令模式就是当我们解析参数为-c的时候设置的,在这里会用到:
1619 case
COMMAND_CREATE:
=
>
1620 create_archive (
)
;
1621 if
(
flag_totals)
1622 fprintf
(
stderr
,
_(
"Total bytes written: %d\n"
)
,
tot_written)
;
1623 break
;
|
到这里了,会进入create_archive ();
打包的操作主要是在这里进行,进去看看就知道了
610 void
611 create_archive (
void
)
612 {
613 register
char
*
p;
614 =
>
615 open_archive (
0)
;
/* open for writing */
|
遇到一个open_archive函数,在这之前,我们会看到,还没有创建我们要写入的文件包,创建包是在这里进行的,执行完这个函数后,就会看到打包的文件了。(如果不信的话可以试试,在这里设断点就可以了)
接着进入该函数后会看到如下的代码:
532 current_file_name =
NULL
;
533 current_link_name =
NULL
;
534 save_name =
NULL
;
535
536 if
(
flag_multivol)
537 {
538 ar_block
539 =
(
union
record *
)
valloc (
(
unsigned
)
(
blocksize +
(
2 *
RECORDSIZE)
)
)
;
540 if
(
ar_block)
541 ar_block +
=
2;
542 }
543 else
=
>
544 ar_block =
(
union
record *
)
valloc (
(
unsigned
)
blocksize)
;
|
因为前面没有对flag_multivol进行赋值,所以,这里会进入else里面执行申请内存
=
>
556 if
(
flag_compressprog)
557 {
558 if
(
reading =
=
2 |
|
flag_verify)
559 ERROR
(
(
TAREXIT_FAILURE,
0,
560 _(
"Cannot update or verify compressed archives"
)
)
)
;
561 if
(
flag_multivol)
562 ERROR
(
(
TAREXIT_FAILURE,
0,
563 _(
"Cannot use multi-volume compressed archives"
)
)
)
;
564 child_open (
)
;
565 if
(
!
reading &
&
strcmp
(
archive_name_array[
0]
,
"-"
)
=
=
0)
566 stdlis =
stderr
;
567 #
if
0
568 child_open (
rem_host,
rem_file)
;
569 #
endif
570 }
|
由于没有添加压缩参数,所以,这里不会进入if条件内而是进入的
596 else
=
>
597 archive =
rmtcreat (
archive_name_array[
0]
,
0666,
flag_rsh_command)
;
|
这里开始创建一个文件执行完这一句以后,就创建了一个example.tar文件,创建完以后会继续回到create_archive里面
610 void
611 create_archive (
void
)
612 {
613 register
char
*
p;
614
615 open_archive (
0)
;
/* open for writing */
616 =
>
617 if
(
flag_gnudump)
618 {
|
根据打印看
2039 (
gdb)
print flag_gnudump
2040 $80 =
0
2041 (
gdb)
|
不会进入这个if条件内,而是进入了else
653 else
654 {
=
>
655 while
(
p =
name_next (
1)
,
p)
656 dump_file (
p,
-
1,
1)
;
657 }
|
接着是一个while循环,条件是如果有p的话,查找p里的name,进入看一下
197 /*-------------------------------------------------------------------------.
198 | Get the next name from argv or the name file. Result is in static |
199 | storage and can't be relied upon across two calls. |
200 | |
201 | If CHANGE_DIRS is non-zero, treat a filename of the form "-C" as meaning |
202 | that the next filename is the name of a directory to change to. If |
203 | `filename_terminator' is '\0', CHANGE_DIRS is effectively always 0. |
204 `-------------------------------------------------------------------------*/
205
206 char
*
207 name_next (
int
change_dirs)
208 {
209 const
char
*
source;
210 char
*
cursor;
211 int
chdir_flag =
0;
212
213 if
(
filename_terminator =
=
'\0'
)
214 change_dirs =
0;
215 =
>
216 if
(
name_file)
|
关于这个函数,在注释里面已经说得很明白了,首先我们看一下这个目录里面有什么文件
[
root@1jjk dvntar]
#
ls example
aaa bbb [
root@1jjk dvntar]
#
|
文件里面有两个文件,分别是aaa,bbb,继续往下跟,可以输出一下name_file
2046 (
gdb)
print name_file
2047 $81 =
(
FILE
*
)
0x0
2048 (
gdb)
|
结果告诉我们她不会进入这个条件里面,而是进入了
250 else
251 {
252
253 /* Read from argv, after options. */
254
255 while
(
1)
256 {
257 if
(
name_index <
names)
258 source =
name_array[
name_index+
+
]
;
259 else
if
(
optind <
names_argc)
260 source =
names_argv[
optind+
+
]
;
261 else
262 break
;
263 =
>
264 if
(
strlen
(
source)
>
name_buffer_length)
265 {
266 free
(
name_buffer)
;
267 name_buffer_length =
strlen
(
source)
;
268 name_buffer =
xmalloc (
name_buffer_length +
2)
;
269 }
其实经过gdb输出,进入
259 else
if
(
optind <
names_argc)
260 source =
names_argv[
optind+
+
]
;
|
这里是活的目录名
2059 (
gdb)
print source
2060 $86 =
0xbffff782 "example"
2061 (
gdb)
|
以后,我们可以继续了
270 strcpy
(
name_buffer,
source)
;
271
272 /* Zap trailing slashes. */
273 =
>
274 cursor =
name_buffer +
strlen
(
name_buffer)
-
1;
|
其实通过打印,我们可以知道name_buffer其实是一个用来记录一个字符串的地址
2065 (
gdb)
print name_buffer
2066 $88 =
0x806e888 "example"
2067 (
gdb)
|
而cursor相当于一个指针,也可以理解为光标
2068 (
gdb)
print cursor
2069 $89 =
0x806e88e "e"
2070 (
gdb)
|
接着往下走
278 if
(
chdir_flag)
279 {
280 if
(
chdir (
name_buffer)
<
0)
281 ERROR
(
(
TAREXIT_FAILURE,
errno
,
282 _(
"Cannot chdir to %s"
)
,
name_buffer)
)
;
283 chdir_flag =
0;
284 }
285 else
if
(
change_dirs &
&
strcmp
(
name_buffer,
"-C"
)
=
=
0)
286 chdir_flag =
1;
287 else
=
>
291 return
un_quote_string (
name_buffer)
;
|
因为我们这个不是chdir_flag,通过gdb输出可以看出来,所以进入到了un_quote_string (name_buffer);
2077 (
gdb)
step
2078 un_quote_string (
string
=
0x806e888 "example"
)
at /
home/
liuqi/
dvntar/
src/
port.
c:
730
2079 (
gdb)
|
进去以后,会看到如下代码
714 /*-----------------------------------------------------------------------.
715 | Un_quote_string takes a quoted c-string (like those produced by |
716 | quote_string or quote_copy_string and turns it back into the un-quoted |
717 | original. This is done in place. |
718 `-----------------------------------------------------------------------*/
719
720 /* There is no un-quote-copy-string. Write it yourself */
721
722 char
*
723 un_quote_string (
char
*
string
)
724 {
725 char
*
ret;
726 char
*
from_here;
727 char
*
to_there;
728 int
tmp;
729
730 ret =
string
;
731 to_there =
string
;
732 from_here =
string
;
=
>
733 while
(
*
from_here)
734 {
735 if
(
*
from_here !
=
'\\'
)
736 {
737 if
(
from_here !
=
to_there)
738 *
to_there+
+
=
*
from_here+
+
;
739 else
740 from_here+
+
,
to_there+
+
;
741 continue
;
742 }
|
从代码分析,会进入这个循环里面执行,执行完以后会退出这个函数,
805 if
(
*
to_there)
806 *
to_there+
+
=
'\0'
;
=
>
807 return
ret;
808 }
|
然后会回到create_archive中,执行 dump_file (p, -1, 1);
进去看一下:
666 /*-------------------------------------------------------------------------.
667 | Dump a single file. If it's a directory, recurse. Result is 1 for |
668 | success, 0 for failure. Sets global "hstat" to stat() output for this |
669 | file. P is file name to dump. CURDEV is device our parent dir was on. |
670 | TOPLEVEL tells wether we are a toplevel call. |
671 `-------------------------------------------------------------------------*/
672
673 void
674 dump_file (
char
*
p,
int
curdev,
int
toplevel)
675 {
676 union
record *
header;
677 char
type;
678 union
record *
exhdr;
679 char
save_linkflag;
=
>
680 int
critical_error =
0;
681 struct
utimbuf restore_times;
从注释可以看出,这个事用来遍历目录的函数。
1151 else
if
(
S_ISDIR (
hstat.
st_mode)
)
1152 {
1153 register
DIR *
dirp;
1154 register
struct
dirent *
d;
1155 char
*
namebuf;
1156 int
buflen;
1157 register
int
len;
1158 int
our_device =
hstat.
st_dev;
1159
1160 /* Build new prototype name. */
1161
1162 len =
strlen
(
p)
;
1163 buflen =
len +
NAMSIZ;
1164 namebuf =
xmalloc (
(
size_t
)
(
buflen +
1)
)
;
1165 strncpy
(
namebuf,
p,
(
size_t
)
buflen)
;
1166 while
(
len >
=
1 &
&
namebuf[
len -
1]
=
=
'/'
)
1167 len-
-
;
/* delete trailing slashes */
=
>
1168 namebuf[
len+
+
]
=
'/'
;
/* now add exactly one back */
1169 namebuf[
len]
=
'\0'
;
/* make sure null-terminated */
|
如果遇到了目录的话,会在后面加上一个'/'
1175 if
(
!
flag_oldarch)
1176 {
1177 hstat.
st_size =
0;
/* force 0 size on dir */
1178
1179 /* If people could really read standard archives, this should
1180 be: (FIXME)
1181
1182 header = start_header (flag_standard ? p : namebuf, &hstat);
1183
1184 but since they'd interpret LF_DIR records as regular files,
1185 we'd better put the / on the name. */
1186 =
>
1187 header =
start_header (
namebuf,
&
hstat)
;
|
这里会进入start_header,建立一个header.
185 /* Header handling. */
186
187 /*---------------------------------------------------------------------.
188 | Make a header block for the file name whose stat info is st. Return |
189 | header pointer for success, NULL if the name is too long. |
190 `---------------------------------------------------------------------*/
191
192 static
union
record *
193 start_header (
const
char
*
name,
register
struct
stat *
st)
分享到:
Global site tag (gtag.js) - Google Analytics
|
相关推荐
在Linux/Unix环境中,通常先用tar打包,再用gzip压缩,以节省存储空间。在处理"tar-1.27.tar.gz"时,我们需要先用gunzip解压,得到"tar-1.27.tar",然后再用tar提取出原始文件。这一过程涉及到的压缩和解压缩原理,...
《tar-1.26源代码详解:洞察命令行打包工具的奥秘》 在信息技术领域,tar是一个不可或缺的工具,尤其在Linux和Unix系统中,它被广泛用于打包和归档文件。当我们看到"tar-1.26.tar.gz"这样的文件名时,我们可以推断...
APKTool是一款强大的Android应用分析和反编译工具,它由布拉德·科尔(Brad Collier)开发,主要用于帮助开发者和安全研究人员查看、修改以及重新打包Android应用。这两个压缩文件,"apktool1.5.2.tar.bz2" 和 ...
".tar" 是一个归档文件格式,它能够将多个文件和目录打包成一个单一的文件,便于存储、传输和备份。而 ".gz" 是使用Gzip压缩算法对 ".tar" 文件进行压缩后的结果,可以显著减小文件大小,加快传输速度。 在处理 ...
【标签】"httpd.tar.gz.tar.jar" 这个标签可能表明压缩包中包含了多个级别的压缩,首先是 ".tar" 归档,它通常用于将多个文件打包到一起,便于管理和传输。接着是 ".gz" 压缩,这是GNU zip的缩写,用于减小文件大小...
《Linux系统下的tar压缩工具详解及其源码分析》 在Linux和Unix操作系统中,`tar`是一个非常重要的命令行工具,用于打包和压缩文件。它并非一个真正的压缩工具,而是一个文件打包程序,可以将多个文件和目录组合成一...
《Linux系统下tar命令详解与源码分析》 在Linux操作系统中,`tar`命令是不可或缺的工具之一,它主要用于处理文件归档和压缩。在本文中,我们将深入探讨`tar`命令的基本用法,以及如何从源码层面理解其工作原理。 1...
`tar`是用于打包多个文件或目录到一个单一文件的工具,而`.gz`则是GNU Zip的缩写,它是一种数据压缩算法,用于减小文件大小以便更有效地存储和传输。 `jpegsrc.v8c` 指的是JPEG库的特定版本,这里的"v8c"可能表示该...
".tar.gz"是Unix/Linux系统中常见的文件打包格式,它先用tar命令将多个文件打包成一个大文件,然后用gzip压缩这个大文件,以达到节省存储空间的目的。解压这个包后,我们可以看到File-Tail-0.99.3目录,里面包含了源...
因此,ltsa-0.1.tar.gz文件是ltsa-0.1版本的源代码经过tar打包和gzip压缩后的结果。 “ltsa”这个库可能指的是Long Short-Term Memory Analysis(长期短期记忆分析),这是在自然语言处理(NLP)领域常用的一种技术...
通过`.tar.gz`扩展名我们可以推断,这是一个使用`tar`命令打包,并通过`gzip`进行压缩的文件,这是Linux和Unix系统中常见的文件打包压缩方式。 在Linux环境中,`tar`命令用于将多个文件和目录打包成一个单一的归档...
3. 研究与教育:在学术研究中,zmap可用于分析网络拓扑结构,或者在教学环境中教授网络扫描原理。 然而,使用zmap时也需要注意合法性和道德问题。因为大规模扫描可能会对目标网络造成影响,甚至触犯法律,所以务必...
"rarlinux"表示这是专为Linux系统设计的RAR工具,"3.8.b4"代表版本信息,"tar.gz"则表明该软件包采用了tar打包和gzip压缩的方式。这种组合方式使得文件在保持较小体积的同时,便于在Linux系统中分发和安装。 在...
"chrome.tar"这个文件名暗示了我们可能在处理与Chrome浏览器相关的源代码或资源的打包文件。在这种情况下,".tar"扩展名表示这是一个归档文件,通常用于在Linux或Unix系统中组合多个文件和目录。这种格式不提供任何...
标题和描述中提到的“TLS.tar.gz”资料包,指的是一个使用gzip压缩算法并打包成tar格式的文件,其中包含了与Transport Layer Security(TLS)相关的资源。TLS是一种网络通信协议,主要用于确保数据在互联网上传输时...
`tar` 命令用于将多个文件和目录打包成一个单一的归档文件,而 `.gz` 是 GNU zip 压缩算法的应用,可以进一步减小文件大小,方便存储和传输。 ELK(Elasticsearch, Logstash, Kibana)堆栈是日志管理和分析的流行...
"tar.gz"是Unix/Linux系统中常见的文件打包方式,"tar"用于将多个文件和目录打包成一个单一的文件,"gz"则是使用gzip压缩工具进行压缩,以减小文件大小,方便传输和存储。 在解压"Pcre-8.01.tar.gz"后,你会得到一...
`.tar`文件本身是一个归档文件,可以将多个文件和目录打包到一起,而`.gz`则是gzip压缩算法的结果,用于减少文件大小,方便存储和传输。解压`sourcenav-6.0.tar.gz`通常需要先使用`tar`命令进行解包,再用`gzip`或`...
- **源代码分析**:通过获取MySQL的源代码,开发者可以深入了解其内部工作原理,进行自定义修改或二次开发,满足特定需求。 - **编译与安装**:解压`.tar.gz`文件后,开发者需要遵循标准的编译流程(如配置、编译...
10. **故障排查**:当遇到连接问题或性能下降时,了解ZeroTier One的内部工作原理和日志分析技巧对于解决问题至关重要。 总的来说,zerotier-1.4.6.tar.gz是一个为OpenWrt系统设计的ZeroTier One软件包,它提供了一...