mirror of
http://galexander.org/git/simplesshd.git
synced 2025-01-14 17:10:55 +00:00
rsync 3.1.1 source, after i trimmed away the parts we obviously won't
need...but most of it remains.
This commit is contained in:
parent
d77c8ef8af
commit
d8cc8daef9
674
rsync/COPYING
Normal file
674
rsync/COPYING
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
187
rsync/Doxyfile
Normal file
187
rsync/Doxyfile
Normal file
@ -0,0 +1,187 @@
|
||||
# Doxyfile 1.2.15
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = rsync
|
||||
PROJECT_NUMBER = HEAD
|
||||
OUTPUT_DIRECTORY = dox
|
||||
OUTPUT_LANGUAGE = English
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH = *source
|
||||
INTERNAL_DOCS = YES
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
SHORT_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = YES
|
||||
VERBATIM_HEADERS = YES
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
INHERIT_DOCS = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
ALIASES =
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SHOW_USED_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = NO
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
FILE_PATTERNS = *.c \
|
||||
*.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE = proto.h \
|
||||
zlib \
|
||||
popt
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 3
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 3
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = NO
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
TEMPLATE_RELATIONS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
CGI_NAME = search.cgi
|
||||
CGI_URL =
|
||||
DOC_URL =
|
||||
DOC_ABSPATH =
|
||||
BIN_ABSPATH = /usr/local/bin/
|
||||
EXT_DOC_PATHS =
|
74
rsync/INSTALL
Normal file
74
rsync/INSTALL
Normal file
@ -0,0 +1,74 @@
|
||||
To build and install rsync:
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
|
||||
You may set the installation directory and other parameters by options
|
||||
to ./configure. To see them, use:
|
||||
|
||||
$ ./configure --help
|
||||
|
||||
Configure tries to figure out if the local system uses group "nobody" or
|
||||
"nogroup" by looking in the /etc/group file. (This is only used for the
|
||||
default group of an rsync daemon, which attempts to run with "nobody"
|
||||
user and group permissions.) You can change the default user and group
|
||||
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
|
||||
config.h, or just override them in your /etc/rsyncd.conf file.
|
||||
|
||||
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
|
||||
cut-down copy of a recent release is included in the rsync distribution,
|
||||
and will be used if there is no popt library on your build host, or if
|
||||
the --with-included-popt option is passed to ./configure.
|
||||
|
||||
If you configure using --enable-maintainer-mode, then rsync will try
|
||||
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
|
||||
useful, but it should be turned off for production builds.
|
||||
|
||||
MAKE COMPATIBILITY
|
||||
------------------
|
||||
|
||||
Note that Makefile.in has a rule that uses a wildcard in a prerequisite. If
|
||||
your make has a problem with this rule, you will see an error like this:
|
||||
|
||||
Don't know how to make ./*.c
|
||||
|
||||
You can change the "proto.h-tstamp" target in Makefile.in to list all the *.c
|
||||
filenames explicitly in order to avoid this issue.
|
||||
|
||||
RPM NOTES
|
||||
---------
|
||||
|
||||
Under packaging you will find .spec files for several distributions.
|
||||
The .spec file in packaging/lsb can be used for Linux systems that
|
||||
adhere to the Linux Standards Base (e.g., RedHat and others).
|
||||
|
||||
HP-UX NOTES
|
||||
-----------
|
||||
|
||||
The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with
|
||||
ANSI C. You may see this error message in config.log if ./configure
|
||||
fails:
|
||||
|
||||
(Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature.
|
||||
|
||||
Install gcc or HP's "ANSI/C Compiler".
|
||||
|
||||
MAC OSX NOTES
|
||||
-------------
|
||||
|
||||
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
|
||||
not completely implement the "New Sockets" API.
|
||||
|
||||
<http://www.ipv6.org/impl/mac.html> says that Apple started to support
|
||||
IPv6 in 10.2 (Jaguar). If your build fails, try again after running
|
||||
configure with --disable-ipv6.
|
||||
|
||||
IBM AIX NOTES
|
||||
-------------
|
||||
|
||||
IBM AIX has a largefile problem with mkstemp. See IBM PR-51921.
|
||||
The workaround is to append the below to config.h
|
||||
#ifdef _LARGE_FILES
|
||||
#undef HAVE_SECURE_MKSTEMP
|
||||
#endif
|
323
rsync/Makefile.in
Normal file
323
rsync/Makefile.in
Normal file
@ -0,0 +1,323 @@
|
||||
# Makefile for rsync. This is processed by configure to produce the final
|
||||
# Makefile
|
||||
|
||||
prefix=@prefix@
|
||||
datarootdir=@datarootdir@
|
||||
exec_prefix=@exec_prefix@
|
||||
stunnel4=@STUNNEL4@
|
||||
bindir=@bindir@
|
||||
mandir=@mandir@
|
||||
|
||||
LIBS=@LIBS@
|
||||
CC=@CC@
|
||||
CFLAGS=@CFLAGS@
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
EXEEXT=@EXEEXT@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
||||
INSTALLCMD=@INSTALL@
|
||||
INSTALLMAN=@INSTALL@
|
||||
|
||||
srcdir=@srcdir@
|
||||
MKDIR_P=@MKDIR_P@
|
||||
VPATH=$(srcdir)
|
||||
SHELL=/bin/sh
|
||||
|
||||
VERSION=@RSYNC_VERSION@
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
GENFILES=configure.sh config.h.in proto.h proto.h-tstamp rsync.1 rsyncd.conf.5
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \
|
||||
lib/pool_alloc.h
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
|
||||
lib/permstring.o lib/pool_alloc.o lib/sysacls.o lib/sysxattrs.o @LIBOBJS@
|
||||
zlib_OBJS=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
|
||||
zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
|
||||
OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
|
||||
util.o util2.o main.o checksum.o match.o syscall.o log.o backup.o delete.o
|
||||
OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
|
||||
fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
|
||||
OBJS3=progress.o pipe.o
|
||||
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
|
||||
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
popt/popthelp.o popt/poptparse.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
|
||||
|
||||
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
testrun$(EXEEXT) trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
|
||||
|
||||
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test testsuite/xattrs-hlink.test
|
||||
|
||||
# Objects for CHECK_PROGS to clean
|
||||
CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
|
||||
# note that the -I. is needed to handle config.h when using VPATH
|
||||
.c.o:
|
||||
@OBJ_SAVE@
|
||||
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
|
||||
@OBJ_RESTORE@
|
||||
|
||||
all: Makefile rsync$(EXEEXT) rsync-ssl stunnel-rsync stunnel-rsyncd.conf @MAKE_MAN@
|
||||
|
||||
install: all
|
||||
-${MKDIR_P} ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
-${MKDIR_P} ${DESTDIR}${mandir}/man1
|
||||
-${MKDIR_P} ${DESTDIR}${mandir}/man5
|
||||
if test -f rsync.1; then ${INSTALLMAN} -m 644 rsync.1 ${DESTDIR}${mandir}/man1; fi
|
||||
if test -f rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
|
||||
|
||||
install-ssl-client: rsync-ssl stunnel-rsync
|
||||
-${MKDIR_P} ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync-ssl ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 stunnel-rsync ${DESTDIR}${bindir}
|
||||
|
||||
install-ssl-daemon: stunnel-rsyncd.conf
|
||||
-${MKDIR_P} ${DESTDIR}/etc/stunnel
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 644 stunnel-rsyncd.conf ${DESTDIR}/etc/stunnel/rsyncd.conf
|
||||
@if ! ls /etc/rsync-ssl/certs/server.* >/dev/null 2>/dev/null; then \
|
||||
echo "Note that you'll need to install the certificate used by /etc/stunnel/rsyncd.conf"; \
|
||||
fi
|
||||
|
||||
install-all: install install-ssl-client install-ssl-daemon
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALL_STRIP='-s' install
|
||||
|
||||
rsync$(EXEEXT): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
$(OBJS): $(HEADERS)
|
||||
$(CHECK_OBJS): $(HEADERS)
|
||||
|
||||
flist.o: rounding.h
|
||||
|
||||
rounding.h: rounding.c rsync.h
|
||||
@for r in 0 1 3; do \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \
|
||||
echo "#define EXTRA_ROUNDING $$r" >rounding.h; \
|
||||
if test -f "$$HOME/build_farm/build_test.fns"; then \
|
||||
echo "EXTRA_ROUNDING is $$r" >&2; \
|
||||
fi; \
|
||||
break; \
|
||||
fi; \
|
||||
done
|
||||
@rm -f rounding
|
||||
@if test -f rounding.h; then : ; else \
|
||||
cat rounding.out 1>&2; \
|
||||
echo "Failed to create rounding.h!" 1>&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
@rm -f rounding.out
|
||||
|
||||
tls$(EXEEXT): $(TLS_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
|
||||
|
||||
testrun$(EXEEXT): testrun.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ testrun.o
|
||||
|
||||
getgroups$(EXEEXT): getgroups.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
|
||||
|
||||
getfsdev$(EXEEXT): getfsdev.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
|
||||
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
gen: conf proto.h man
|
||||
|
||||
gensend: gen
|
||||
rsync -aivzc $(GENFILES) samba.org:/home/ftp/pub/rsync/generated-files/
|
||||
|
||||
conf:
|
||||
cd $(srcdir) && $(MAKE) -f prepare-source.mak conf
|
||||
|
||||
configure.sh config.h.in: configure.ac aclocal.m4
|
||||
@if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi
|
||||
@if test -f config.h.in; then cp -p config.h.in config.h.in.old; else touch config.h.in.old; fi
|
||||
autoconf -o configure.sh
|
||||
autoheader && touch config.h.in
|
||||
@if diff configure.sh configure.sh.old >/dev/null 2>&1; then \
|
||||
echo "configure.sh is unchanged."; \
|
||||
rm configure.sh.old; \
|
||||
else \
|
||||
echo "configure.sh has CHANGED."; \
|
||||
fi
|
||||
@if diff config.h.in config.h.in.old >/dev/null 2>&1; then \
|
||||
echo "config.h.in is unchanged."; \
|
||||
rm config.h.in.old; \
|
||||
else \
|
||||
echo "config.h.in has CHANGED."; \
|
||||
fi
|
||||
@if test -f configure.sh.old -o -f config.h.in.old; then \
|
||||
if test "$(MAKECMDGOALS)" = reconfigure; then \
|
||||
echo 'Continuing with "make reconfigure".'; \
|
||||
else \
|
||||
echo 'You may need to run:'; \
|
||||
echo ' make reconfigure'; \
|
||||
exit 1; \
|
||||
fi \
|
||||
fi
|
||||
|
||||
reconfigure: configure.sh
|
||||
./config.status --recheck
|
||||
./config.status
|
||||
|
||||
Makefile: Makefile.in config.status configure.sh config.h.in
|
||||
@if test -f Makefile; then cp -p Makefile Makefile.old; else touch Makefile.old; fi
|
||||
@./config.status
|
||||
@if diff Makefile Makefile.old >/dev/null 2>&1; then \
|
||||
echo "Makefile is unchanged."; \
|
||||
rm Makefile.old; \
|
||||
else \
|
||||
if test "$(MAKECMDGOALS)" = reconfigure; then \
|
||||
echo 'Continuing with "make reconfigure".'; \
|
||||
else \
|
||||
echo "Makefile updated -- rerun your make command."; \
|
||||
exit 1; \
|
||||
fi \
|
||||
fi
|
||||
|
||||
rsync-ssl: $(srcdir)/rsync-ssl.in Makefile
|
||||
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/rsync-ssl.in >rsync-ssl
|
||||
@chmod +x rsync-ssl
|
||||
|
||||
stunnel-rsync: $(srcdir)/stunnel-rsync.in Makefile
|
||||
sed 's;\@stunnel4\@;$(stunnel4);g' <$(srcdir)/stunnel-rsync.in >stunnel-rsync
|
||||
@chmod +x stunnel-rsync
|
||||
|
||||
stunnel-rsyncd.conf: $(srcdir)/stunnel-rsyncd.conf.in Makefile
|
||||
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/stunnel-rsyncd.conf.in >stunnel-rsyncd.conf
|
||||
|
||||
proto: proto.h-tstamp
|
||||
|
||||
proto.h: proto.h-tstamp
|
||||
@if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi
|
||||
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c config.h
|
||||
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
|
||||
man: rsync.1 rsyncd.conf.5 man-copy
|
||||
|
||||
man-copy:
|
||||
@-if test -f rsync.1; then :; else echo 'Copying srcdir rsync.1'; cp -p $(srcdir)/rsync.1 .; fi
|
||||
@-if test -f rsyncd.conf.5; then :; else echo 'Copying srcdir rsyncd.conf.5'; cp -p $(srcdir)/rsyncd.conf.5 .; fi
|
||||
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 $(srcdir)/rsync.yo
|
||||
-$(srcdir)/tweak_manpage rsync.1
|
||||
|
||||
rsyncd.conf.5: rsyncd.conf.yo
|
||||
yodl2man -o rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
-$(srcdir)/tweak_manpage rsyncd.conf.5
|
||||
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
|
||||
rounding rounding.h *.old
|
||||
|
||||
cleantests:
|
||||
rm -rf ./testtmp*
|
||||
|
||||
# We try to delete built files from both the source and build
|
||||
# directories, just in case somebody previously configured things in
|
||||
# the source directory.
|
||||
distclean: clean
|
||||
rm -f Makefile config.h config.status
|
||||
rm -f rsync-ssl stunnel-rsync stunnel-rsyncd.conf
|
||||
rm -f lib/dummy popt/dummy zlib/dummy
|
||||
rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status
|
||||
rm -f $(srcdir)/lib/dummy $(srcdir)/popt/dummy $(srcdir)/zlib/dummy
|
||||
rm -f config.cache config.log
|
||||
rm -f $(srcdir)/config.cache $(srcdir)/config.log
|
||||
rm -f shconfig $(srcdir)/shconfig
|
||||
rm -f $(GENFILES)
|
||||
rm -rf autom4te.cache
|
||||
|
||||
# this target is really just for my use. It only works on a limited
|
||||
# range of machines and is used to produce a list of potentially
|
||||
# dead (ie. unused) functions in the code. (tridge)
|
||||
finddead:
|
||||
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
|
||||
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
|
||||
comm -13 nmused.txt nmfns.txt
|
||||
|
||||
# 'check' is the GNU name, 'test' is the name for everybody else :-)
|
||||
.PHONY: check test
|
||||
|
||||
test: check
|
||||
|
||||
# There seems to be no standard way to specify some variables as
|
||||
# exported from a Makefile apart from listing them like this.
|
||||
|
||||
# This depends on building rsync; if we need any helper programs it
|
||||
# should depend on them too.
|
||||
|
||||
# We try to run the scripts with POSIX mode on, in the hope that will
|
||||
# catch Bash-isms earlier even if we're running on GNU. Of course, we
|
||||
# might lose in the future where POSIX diverges from old sh.
|
||||
|
||||
check: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
|
||||
|
||||
check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29
|
||||
|
||||
check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=30
|
||||
|
||||
wildtest.o: wildtest.c lib/wildmatch.c rsync.h config.h
|
||||
wildtest$(EXEEXT): wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ $(LIBS)
|
||||
|
||||
testsuite/chown-fake.test:
|
||||
ln -s chown.test $(srcdir)/testsuite/chown-fake.test
|
||||
|
||||
testsuite/devices-fake.test:
|
||||
ln -s devices.test $(srcdir)/testsuite/devices-fake.test
|
||||
|
||||
testsuite/xattrs-hlink.test:
|
||||
ln -s xattrs.test $(srcdir)/testsuite/xattrs-hlink.test
|
||||
|
||||
# This does *not* depend on building or installing: you can use it to
|
||||
# check a version installed from a binary or some other source tree,
|
||||
# if you want.
|
||||
|
||||
installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
|
||||
|
||||
# TODO: Add 'dist' target; need to know which files will be included
|
||||
|
||||
# Run the SPLINT (Secure Programming Lint) tool. <www.splint.org>
|
||||
.PHONY: splint
|
||||
splint:
|
||||
splint +unixlib +gnuextensions -weak rsync.c
|
||||
|
||||
|
||||
rsync.dvi: doc/rsync.texinfo
|
||||
texi2dvi -o $@ $<
|
||||
|
||||
rsync.ps: rsync.dvi
|
||||
dvips -ta4 -o $@ $<
|
||||
|
||||
rsync.pdf: doc/rsync.texinfo
|
||||
texi2dvi -o $@ --pdf $<
|
||||
|
||||
|
||||
doxygen:
|
||||
cd $(srcdir) && rm dox/html/* && doxygen
|
||||
|
||||
# for maintainers only
|
||||
doxygen-upload:
|
||||
rsync -avzv $(srcdir)/dox/html/ --delete \
|
||||
samba.org:/home/httpd/html/rsync/doxygen/head/
|
115
rsync/NEWS
Normal file
115
rsync/NEWS
Normal file
@ -0,0 +1,115 @@
|
||||
NEWS for rsync 3.1.1 (22 Jun 2014)
|
||||
Protocol: 31 (unchanged)
|
||||
Changes since 3.1.0:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- If the receiver gets bogus filenames from the sender (an unexpected
|
||||
leading slash or a ".." infix dir), exit with an error. This prevents a
|
||||
malicious sender from trying to inject filenames that would affect an
|
||||
area outside the destination directories.
|
||||
|
||||
- Fixed a failure to remove the partial-transfer temp file when interrupted
|
||||
(and rsync is not saving the partial files).
|
||||
|
||||
- Changed the chown/group/xattr-set order to avoid losing some security-
|
||||
related xattr info (that would get cleared by a chown).
|
||||
|
||||
- Fixed a bug in the xattr-finding code that could make a non-root-run
|
||||
receiver not able to find some xattr numbers.
|
||||
|
||||
- Fixed a bug in the early daemon protocol where a timeout failed to be
|
||||
honored (e.g. if the remote side fails to send us the initial protocol
|
||||
greeting).
|
||||
|
||||
- Fixed unintended inclusion of commas in file numbers in the daemon log.
|
||||
|
||||
- We once again send the 'f' sub-flag (of -e) to the server side so it
|
||||
knows that we can handle incremental-recursion directory errors properly
|
||||
in older protocols.
|
||||
|
||||
- Fixed an issue with too-aggressive keep-alive messages causing a problem
|
||||
for older rsync versions early in the transfer.
|
||||
|
||||
- Fixed an incorrect message about backup-directory-creation when using
|
||||
--dry-run and the backup dir is not an absolute path.
|
||||
|
||||
- Fixed a bug where a failed deletion and/or a failed sender-side removal
|
||||
would not affect the exit code.
|
||||
|
||||
- Fixed a bug that caused a failure when combining --delete-missing-args
|
||||
with --xattrs and/or --acls.
|
||||
|
||||
- Fixed a strange dir_depth assertion error that was caused by empty-dir
|
||||
removals and/or duplicate files in the transfer.
|
||||
|
||||
- Fixed a problem with --info=progress2's output stats where rsync would
|
||||
only update the stats at the end of each file's transfer. It now uses
|
||||
the data that is flowing for the current file, making the stats more
|
||||
accurate and less jumpy.
|
||||
|
||||
- Fixed an itemize bug that affected the combo of --link-dest, -X, and -n.
|
||||
|
||||
- Fixed a problem with delete messages not appearing in the log file when
|
||||
the user didn't use --verbose.
|
||||
|
||||
- Improve chunked xattr reading for OS X.
|
||||
|
||||
- Removed an attempted hard-link xattr optimization that was causing a
|
||||
transfer failure. This removal is flagged in the compatibility code, so
|
||||
if a better fix can be discovered, we have a way to flip it on again.
|
||||
|
||||
- Fixed a bug when the receiver is not configured to be able to hard link
|
||||
symlimks/devices/special-file items but the sender sent some of these
|
||||
items flagged as hard-linked.
|
||||
|
||||
- We now generate a better error if the buffer overflows in do_mknod().
|
||||
|
||||
- Fixed a problem reading more than 16 ACLs on some OSes.
|
||||
|
||||
- Fixed the reading of the secrets file to avoid an infinite wait when
|
||||
the username is missing.
|
||||
|
||||
- Fixed a parsing problem in the --usermap/--groupmap options when using
|
||||
MIN-MAX numbers.
|
||||
|
||||
- Switched Cygwin back to using socketpair "pipes" to try to speed it up.
|
||||
|
||||
- Added knowledge of a few new options to rrsync.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Tweaked the temp-file naming when --temp-dir=DIR is used: the temp-file
|
||||
names will not get a '.' prepended.
|
||||
|
||||
- Added support for a new-compression idiom that does not compress all the
|
||||
matching data in a transfer. This can help rsync to use less cpu when a
|
||||
transfer has a lot of matching data, and also makes rsync compatible with
|
||||
a non-bundled zlib. See the --new-compress and --old-compress options in
|
||||
the manpage.
|
||||
|
||||
- Added the support/rsync-no-vanished wrapper script.
|
||||
|
||||
- Made configure more prominently mention when we failed to find yodl (in
|
||||
case the user wants to be able to generate manpages from *.yo files).
|
||||
|
||||
- Have manpage mention how a daemon's max-verbosity setting affects info
|
||||
and debug options. Also added more clarification on backslash removals
|
||||
for excludes that contain wildcards.
|
||||
|
||||
- Have configure check if for the attr lib (for getxattr) for those systems
|
||||
that need to link against it explicitly.
|
||||
|
||||
- Change the early dir-creation logic to only use that idiom in an
|
||||
inc-recursive copy that is preserving directory times. e.g. using
|
||||
--omit-dir-times will avoid these early directories being created.
|
||||
|
||||
- Fix a bug in cmp_time() that would return a wrong result if the 2 times
|
||||
differed by an amount greater than what a time_t can hold.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- We now include an example systemd file (in packaging/systemd).
|
||||
|
||||
- Tweaked configure to make sure that any intended use of the included popt
|
||||
and/or zlib code is put early in the CFLAGS.
|
3599
rsync/OLDNEWS
Normal file
3599
rsync/OLDNEWS
Normal file
File diff suppressed because it is too large
Load Diff
140
rsync/README
Normal file
140
rsync/README
Normal file
@ -0,0 +1,140 @@
|
||||
WHAT IS RSYNC?
|
||||
--------------
|
||||
|
||||
Rsync is a fast and extraordinarily versatile file copying tool for
|
||||
both remote and local files.
|
||||
|
||||
Rsync uses a delta-transfer algorithm which provides a very fast method
|
||||
for bringing remote files into sync. It does this by sending just the
|
||||
differences in the files across the link, without requiring that both
|
||||
sets of files are present at one of the ends of the link beforehand. At
|
||||
first glance this may seem impossible because the calculation of diffs
|
||||
between two files normally requires local access to both files.
|
||||
|
||||
A technical report describing the rsync algorithm is included with this
|
||||
package.
|
||||
|
||||
|
||||
USAGE
|
||||
-----
|
||||
|
||||
Basically you use rsync just like scp, but rsync has many additional
|
||||
options. To get a complete list of supported options type:
|
||||
|
||||
rsync --help
|
||||
|
||||
See the manpage for more detailed information.
|
||||
|
||||
|
||||
SETUP
|
||||
-----
|
||||
|
||||
Rsync normally uses ssh or rsh for communication with remote systems.
|
||||
It does not need to be setuid and requires no special privileges for
|
||||
installation. You must, however, have a working ssh or rsh system.
|
||||
Using ssh is recommended for its security features.
|
||||
|
||||
Alternatively, rsync can run in `daemon' mode, listening on a socket.
|
||||
This is generally used for public file distribution, although
|
||||
authentication and access control are available.
|
||||
|
||||
To install rsync, first run the "configure" script. This will create a
|
||||
Makefile and config.h appropriate for your system. Then type "make".
|
||||
|
||||
Note that on some systems you will have to force configure not to use
|
||||
gcc because gcc may not support some features (such as 64 bit file
|
||||
offsets) that your system may support. Set the environment variable CC
|
||||
to the name of your native compiler before running configure in this
|
||||
case.
|
||||
|
||||
Once built put a copy of rsync in your search path on the local and
|
||||
remote systems (or use "make install"). That's it!
|
||||
|
||||
|
||||
RSYNC DAEMONS
|
||||
-------------
|
||||
|
||||
Rsync can also talk to "rsync daemons" which can provide anonymous or
|
||||
authenticated rsync. See the rsyncd.conf(5) man page for details on how
|
||||
to setup an rsync daemon. See the rsync(1) man page for info on how to
|
||||
connect to an rsync daemon.
|
||||
|
||||
|
||||
WEB SITE
|
||||
--------
|
||||
|
||||
The main rsync web site is here:
|
||||
|
||||
http://rsync.samba.org/
|
||||
|
||||
You'll find a FAQ list, downloads, resources, HTML versions of the
|
||||
manpages, etc.
|
||||
|
||||
|
||||
MAILING LISTS
|
||||
-------------
|
||||
|
||||
There is a mailing list for the discussion of rsync and its applications
|
||||
that is open to anyone to join. New releases are announced on this
|
||||
list, and there is also an announcement-only mailing list for those that
|
||||
want official announcements. See the mailing-list page for full
|
||||
details:
|
||||
|
||||
http://rsync.samba.org/lists.html
|
||||
|
||||
|
||||
BUG REPORTS
|
||||
-----------
|
||||
|
||||
To visit this web page for full the details on bug reporting:
|
||||
|
||||
http://rsync.samba.org/bugzilla.html
|
||||
|
||||
That page contains links to the current bug list, and information on how
|
||||
to report a bug well. You might also like to try searching the Internet
|
||||
for the error message you've received, or looking in the mailing list
|
||||
archives at:
|
||||
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
Alternately, email your bug report to rsync@lists.samba.org .
|
||||
|
||||
|
||||
GIT REPOSITORY
|
||||
--------------
|
||||
|
||||
If you want to get the very latest version of rsync direct from the
|
||||
source code repository then you can use git:
|
||||
|
||||
git clone git://git.samba.org/rsync.git
|
||||
|
||||
See the download page for full details on all the ways to grab the
|
||||
source, including nightly tar files, web-browsing of the git repository,
|
||||
etc.:
|
||||
|
||||
http://rsync.samba.org/download.html
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
|
||||
Rsync was originally written by Andrew Tridgell and is currently
|
||||
maintained by Wayne Davison. It has been improved by many developers
|
||||
from around the world.
|
||||
|
||||
Rsync may be used, modified and redistributed only under the terms of
|
||||
the GNU General Public License, found in the file COPYING in this
|
||||
distribution, or at:
|
||||
|
||||
http://www.fsf.org/licenses/gpl.html
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
------------
|
||||
|
||||
The main web site for rsync is http://rsync.samba.org/
|
||||
The main ftp site is ftp://rsync.samba.org/pub/rsync/
|
||||
This is also available as rsync://rsync.samba.org/rsyncftp/
|
528
rsync/TODO
Normal file
528
rsync/TODO
Normal file
@ -0,0 +1,528 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
Use chroot only if supported
|
||||
Allow supplementary groups in rsyncd.conf 2002/04/09
|
||||
Handling IPv6 on old machines
|
||||
Other IPv6 stuff
|
||||
Add ACL support 2001/12/02
|
||||
proxy authentication 2002/01/23
|
||||
SOCKS 2002/01/23
|
||||
FAT support
|
||||
--diff david.e.sewell 2002/03/15
|
||||
Add daemon --no-fork option
|
||||
Create more granular verbosity 2003/05/15
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
Keep list of open issues and todos on the web site
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
LOGGING --------------------------------------------------------------
|
||||
Memory accounting
|
||||
Improve error messages
|
||||
Better statistics Rasmus 2002/03/08
|
||||
Perhaps flush stdout like syslog
|
||||
Log child death on signal
|
||||
verbose output David Stein 2001/12/20
|
||||
internationalization
|
||||
|
||||
DEVELOPMENT --------------------------------------------------------
|
||||
Handling duplicate names
|
||||
Use generic zlib 2002/02/25
|
||||
TDB 2002/03/12
|
||||
Splint 2002/03/12
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
Traverse just one directory at a time
|
||||
Allow skipping MD4 file_sum 2002/04/08
|
||||
Accelerate MD4
|
||||
|
||||
TESTING --------------------------------------------------------------
|
||||
Torture test
|
||||
Cross-test versions 2001/08/22
|
||||
Test on kernel source
|
||||
Test large files
|
||||
Create mutator program for testing
|
||||
Create configure option to enable dangerous tests
|
||||
Create pipe program for testing
|
||||
Create test makefile target for some tests
|
||||
|
||||
RELATED PROJECTS -----------------------------------------------------
|
||||
rsyncsh
|
||||
http://rsync.samba.org/rsync-and-debian/
|
||||
rsyncable gzip patch
|
||||
rsyncsplit as alternative to real integration with gzip?
|
||||
reverse rsync over HTTP Range
|
||||
|
||||
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
|
||||
|
||||
Use chroot only if supported
|
||||
|
||||
If the platform doesn't support it, then don't even try.
|
||||
|
||||
If running as non-root, then don't fail, just give a warning.
|
||||
(There was a thread about this a while ago?)
|
||||
|
||||
http://lists.samba.org/pipermail/rsync/2001-August/thread.html
|
||||
http://lists.samba.org/pipermail/rsync/2001-September/thread.html
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Allow supplementary groups in rsyncd.conf 2002/04/09
|
||||
|
||||
Perhaps allow supplementary groups to be specified in rsyncd.conf;
|
||||
then make the first one the primary gid and all the rest be
|
||||
supplementary gids.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Handling IPv6 on old machines
|
||||
|
||||
The KAME IPv6 patch is nice in theory but has proved a bit of a
|
||||
nightmare in practice. The basic idea of their patch is that rsync
|
||||
is rewritten to use the new getaddrinfo()/getnameinfo() interface,
|
||||
rather than gethostbyname()/gethostbyaddr() as in rsync 2.4.6.
|
||||
Systems that don't have the new interface are handled by providing
|
||||
our own implementation in lib/, which is selectively linked in.
|
||||
|
||||
The problem with this is that it is really hard to get right on
|
||||
platforms that have a half-working implementation, so redefining
|
||||
these functions clashes with system headers, and leaving them out
|
||||
breaks. This affects at least OSF/1, RedHat 5, and Cobalt, which
|
||||
are moderately improtant.
|
||||
|
||||
Perhaps the simplest solution would be to have two different files
|
||||
implementing the same interface, and choose either the new or the
|
||||
old API. This is probably necessary for systems that e.g. have
|
||||
IPv6, but gethostbyaddr() can't handle it. The Linux manpage claims
|
||||
this is currently the case.
|
||||
|
||||
In fact, our internal sockets interface (things like
|
||||
open_socket_out(), etc) is much narrower than the getaddrinfo()
|
||||
interface, and so probably simpler to get right. In addition, the
|
||||
old code is known to work well on old machines.
|
||||
|
||||
We could drop the rather large lib/getaddrinfo files.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Other IPv6 stuff
|
||||
|
||||
Implement suggestions from http://www.kame.net/newsletter/19980604/
|
||||
and ftp://ftp.iij.ad.jp/pub/RFC/rfc2553.txt
|
||||
|
||||
If a host has multiple addresses, then listen try to connect to all
|
||||
in order until we get through. (getaddrinfo may return multiple
|
||||
addresses.) This is kind of implemented already.
|
||||
|
||||
Possibly also when starting as a server we may need to listen on
|
||||
multiple passive addresses. This might be a bit harder, because we
|
||||
may need to select on all of them. Hm.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Add ACL support 2001/12/02
|
||||
|
||||
Transfer ACLs. Need to think of a standard representation.
|
||||
Probably better not to even try to convert between NT and POSIX.
|
||||
Possibly can share some code with Samba.
|
||||
NOTE: there is a patch that implements this in the "patches" subdir.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
proxy authentication 2002/01/23
|
||||
|
||||
Allow RSYNC_PROXY to be http://user:pass@proxy.foo:3128/, and do
|
||||
HTTP Basic Proxy-Authentication.
|
||||
|
||||
Multiple schemes are possible, up to and including the insanity that
|
||||
is NTLM, but Basic probably covers most cases.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
SOCKS 2002/01/23
|
||||
|
||||
Add --with-socks, and then perhaps a command-line option to put them
|
||||
on or off. This might be more reliable than LD_PRELOAD hacks.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
FAT support
|
||||
|
||||
rsync to a FAT partition on a Unix machine doesn't work very well at
|
||||
the moment. I think we get errors about invalid filenames and
|
||||
perhaps also trying to do atomic renames.
|
||||
|
||||
I guess the code to do this is currently #ifdef'd on Windows;
|
||||
perhaps we ought to intelligently fall back to it on Unix too.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
--diff david.e.sewell 2002/03/15
|
||||
|
||||
Allow people to specify the diff command. (Might want to use wdiff,
|
||||
gnudiff, etc.)
|
||||
|
||||
Just diff the temporary file with the destination file, and delete
|
||||
the tmp file rather than moving it into place.
|
||||
|
||||
Interaction with --partial.
|
||||
|
||||
Security interactions with daemon mode?
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Add daemon --no-fork option
|
||||
|
||||
Very useful for debugging. Also good when running under a
|
||||
daemon-monitoring process that tries to restart the service when the
|
||||
parent exits.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create more granular verbosity 2003/05/15
|
||||
|
||||
Control output with the --report option.
|
||||
|
||||
The option takes as a single argument (no whitespace) a
|
||||
comma delimited lists of keywords.
|
||||
|
||||
This would separate debugging from "logging" as well as
|
||||
fine grained selection of statistical reporting and what
|
||||
actions are logged.
|
||||
|
||||
http://lists.samba.org/archive/rsync/2003-May/006059.html
|
||||
|
||||
-- --
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
|
||||
|
||||
Keep list of open issues and todos on the web site
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
The man page is getting rather large, and there is more information
|
||||
that ought to be added.
|
||||
|
||||
TexInfo source is probably a dying format.
|
||||
|
||||
Linuxdoc looks like the most likely contender. I know DocBook is
|
||||
favoured by some people, but it's so bloody verbose, even with emacs
|
||||
support.
|
||||
|
||||
-- --
|
||||
|
||||
LOGGING --------------------------------------------------------------
|
||||
|
||||
|
||||
Memory accounting
|
||||
|
||||
At exit, show how much memory was used for the file list, etc.
|
||||
|
||||
Also we do a wierd exponential-growth allocation in flist.c. I'm
|
||||
not sure this makes sense with modern mallocs. At any rate it will
|
||||
make us allocate a huge amount of memory for large file lists.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Improve error messages
|
||||
|
||||
If we hang or get SIGINT, then explain where we were up to. Perhaps
|
||||
have a static buffer that contains the current function name, or
|
||||
some kind of description of what we were trying to do. This is a
|
||||
little easier on people than needing to run strace/truss.
|
||||
|
||||
"The dungeon collapses! You are killed." Rather than "unexpected
|
||||
eof" give a message that is more detailed if possible and also more
|
||||
helpful.
|
||||
|
||||
If we get an error writing to a socket, then we should perhaps
|
||||
continue trying to read to see if an error message comes across
|
||||
explaining why the socket is closed. I'm not sure if this would
|
||||
work, but it would certainly make our messages more helpful.
|
||||
|
||||
What happens if a directory is missing -x attributes. Do we lose
|
||||
our load? (Debian #28416) Probably fixed now, but a test case would
|
||||
be good.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Better statistics Rasmus 2002/03/08
|
||||
|
||||
<Rasmus>
|
||||
hey, how about an rsync option that just gives you the
|
||||
summary without the list of files? And perhaps gives
|
||||
more information like the number of new files, number
|
||||
of changed, deleted, etc. ?
|
||||
|
||||
<mbp>
|
||||
nice idea there is --stats but at the moment it's very
|
||||
tridge-oriented rather than user-friendly it would be
|
||||
nice to improve it that would also work well with
|
||||
--dryrun
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Perhaps flush stdout like syslog
|
||||
|
||||
Perhaps flush stdout after each filename, so that people trying to
|
||||
monitor progress in a log file can do so more easily. See
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Log child death on signal
|
||||
|
||||
If a child of the rsync daemon dies with a signal, we should notice
|
||||
that when we reap it and log a message.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
verbose output David Stein 2001/12/20
|
||||
|
||||
At end of transfer, show how many files were or were not transferred
|
||||
correctly.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
internationalization
|
||||
|
||||
Change to using gettext(). Probably need to ship this for platforms
|
||||
that don't have it.
|
||||
|
||||
Solicit translations.
|
||||
|
||||
Does anyone care? Before we bother modifying the code, we ought to
|
||||
get the manual translated first, because that's possibly more useful
|
||||
and at any rate demonstrates desire.
|
||||
|
||||
-- --
|
||||
|
||||
DEVELOPMENT --------------------------------------------------------
|
||||
|
||||
Handling duplicate names
|
||||
|
||||
Some folks would like rsync to be deterministic in how it handles
|
||||
duplicate names that come from mering multiple source directories
|
||||
into a single destination directory; e.g. the last name wins. We
|
||||
could do this by switching our sort algorithm to one that will
|
||||
guarantee that the names won't be reordered. Alternately, we could
|
||||
assign an ever-increasing number to each item as we insert it into
|
||||
the list and then make sure that we leave the largest number when
|
||||
cleaning the file list (see clean_flist()). Another solution would
|
||||
be to add a hash table, and thus never put any duplicate names into
|
||||
the file list (and bump the protocol to handle this).
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Use generic zlib 2002/02/25
|
||||
|
||||
Perhaps don't use our own zlib.
|
||||
|
||||
Advantages:
|
||||
|
||||
- will automatically be up to date with bugfixes in zlib
|
||||
|
||||
- can leave it out for small rsync on e.g. recovery disks
|
||||
|
||||
- can use a shared library
|
||||
|
||||
- avoids people breaking rsync by trying to do this themselves and
|
||||
messing up
|
||||
|
||||
Should we ship zlib for systems that don't have it, or require
|
||||
people to install it separately?
|
||||
|
||||
Apparently this will make us incompatible with versions of rsync
|
||||
that use the patched version of rsync. Probably the simplest way to
|
||||
do this is to just disable gzip (with a warning) when talking to old
|
||||
versions.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Splint 2002/03/12
|
||||
|
||||
Build rsync with SPLINT to try to find security holes. Add
|
||||
annotations as necessary. Keep track of the number of warnings
|
||||
found initially, and see how many of them are real bugs, or real
|
||||
security bugs. Knowing the percentage of likely hits would be
|
||||
really interesting for other projects.
|
||||
|
||||
-- --
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
|
||||
Allow skipping MD4 file_sum 2002/04/08
|
||||
|
||||
If we're doing a local transfer, or using -W, then perhaps don't
|
||||
send the file checksum. If we're doing a local transfer, then
|
||||
calculating MD4 checksums uses 90% of CPU and is unlikely to be
|
||||
useful.
|
||||
|
||||
We should not allow it to be disabled separately from -W, though
|
||||
as it is the only thing that lets us know when the rsync algorithm
|
||||
got out of sync and messed the file up (i.e. if the basis file
|
||||
changed between checksum generation and reception).
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Accelerate MD4
|
||||
|
||||
Perhaps borrow an assembler MD4 from someone?
|
||||
|
||||
Make sure we call MD4 with properly-sized blocks whenever possible
|
||||
to avoid copying into the residue region?
|
||||
|
||||
-- --
|
||||
|
||||
TESTING --------------------------------------------------------------
|
||||
|
||||
Torture test
|
||||
|
||||
Something that just keeps running rsync continuously over a data set
|
||||
likely to generate problems.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Cross-test versions 2001/08/22
|
||||
|
||||
Part of the regression suite should be making sure that we
|
||||
don't break backwards compatibility: old clients vs new
|
||||
servers and so on. Ideally we would test both up and down
|
||||
from the current release to all old versions.
|
||||
|
||||
Run current rsync versions against significant past releases.
|
||||
|
||||
We might need to omit broken old versions, or versions in which
|
||||
particular functionality is broken
|
||||
|
||||
It might be sufficient to test downloads from well-known public
|
||||
rsync servers running different versions of rsync. This will give
|
||||
some testing and also be the most common case for having different
|
||||
versions and not being able to upgrade.
|
||||
|
||||
The new --protocol option may help in this.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Test on kernel source
|
||||
|
||||
Download all versions of kernel; unpack, sync between them. Also
|
||||
sync between uncompressed tarballs. Compare directories after
|
||||
transfer.
|
||||
|
||||
Use local mode; ssh; daemon; --whole-file and --no-whole-file.
|
||||
|
||||
Use awk to pull out the 'speedup' number for each transfer. Make
|
||||
sure it is >= x.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Test large files
|
||||
|
||||
Sparse and non-sparse
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create mutator program for testing
|
||||
|
||||
Insert bytes, delete bytes, swap blocks, ...
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create configure option to enable dangerous tests
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create pipe program for testing
|
||||
|
||||
Create pipe program that makes slow/jerky connections for
|
||||
testing Versions of read() and write() that corrupt the
|
||||
stream, or abruptly fail
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create test makefile target for some tests
|
||||
|
||||
Separate makefile target to run rough tests -- or perhaps
|
||||
just run them every time?
|
||||
|
||||
-- --
|
||||
|
||||
RELATED PROJECTS -----------------------------------------------------
|
||||
|
||||
rsyncsh
|
||||
|
||||
Write a small emulation of interactive ftp as a Pythonn program
|
||||
that calls rsync. Commands such as "cd", "ls", "ls *.c" etc map
|
||||
fairly directly into rsync commands: it just needs to remember the
|
||||
current host, directory and so on. We can probably even do
|
||||
completion of remote filenames.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
http://rsync.samba.org/rsync-and-debian/
|
||||
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
rsyncable gzip patch
|
||||
|
||||
Exhaustive, tortuous testing
|
||||
|
||||
Cleanups?
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
rsyncsplit as alternative to real integration with gzip?
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
reverse rsync over HTTP Range
|
||||
|
||||
Goswin Brederlow suggested this on Debian; I think tridge and I
|
||||
talked about it previous in relation to rproxy.
|
||||
|
||||
Addendum: It looks like someone is working on a version of this:
|
||||
|
||||
http://zsync.moria.org.uk/
|
||||
|
||||
-- --
|
||||
|
290
rsync/access.c
Normal file
290
rsync/access.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Routines to authenticate access to a daemon (hosts allow/deny).
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
static int allow_forward_dns;
|
||||
|
||||
extern const char undetermined_hostname[];
|
||||
|
||||
static int match_hostname(const char **host_ptr, const char *addr, const char *tok)
|
||||
{
|
||||
struct hostent *hp;
|
||||
unsigned int i;
|
||||
const char *host = *host_ptr;
|
||||
|
||||
if (!host || !*host)
|
||||
return 0;
|
||||
|
||||
/* First check if the reverse-DNS-determined hostname matches. */
|
||||
if (iwildmatch(tok, host))
|
||||
return 1;
|
||||
|
||||
if (!allow_forward_dns)
|
||||
return 0;
|
||||
|
||||
/* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */
|
||||
if (!tok[strspn(tok, ".0123456789")] || tok[strcspn(tok, ":/*?[")])
|
||||
return 0;
|
||||
|
||||
/* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */
|
||||
if (!(hp = gethostbyname(tok)))
|
||||
return 0;
|
||||
|
||||
for (i = 0; hp->h_addr_list[i] != NULL; i++) {
|
||||
if (strcmp(addr, inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i]))) == 0) {
|
||||
/* If reverse lookups are off, we'll use the conf-specified
|
||||
* hostname in preference to UNDETERMINED. */
|
||||
if (host == undetermined_hostname) {
|
||||
if (!(*host_ptr = strdup(tok)))
|
||||
*host_ptr = undetermined_hostname;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < addrlen; i++) {
|
||||
if ((b1[i] ^ b2[i]) & mask[i])
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void make_mask(char *mask, int plen, int addrlen)
|
||||
{
|
||||
int w, b;
|
||||
|
||||
w = plen >> 3;
|
||||
b = plen & 0x7;
|
||||
|
||||
if (w)
|
||||
memset(mask, 0xff, w);
|
||||
if (w < addrlen)
|
||||
mask[w] = 0xff & (0xff<<(8-b));
|
||||
if (w+1 < addrlen)
|
||||
memset(mask+w+1, 0, addrlen-w-1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int match_address(const char *addr, const char *tok)
|
||||
{
|
||||
char *p;
|
||||
struct addrinfo hints, *resa, *rest;
|
||||
int gai;
|
||||
int ret = 0;
|
||||
int addrlen = 0;
|
||||
#ifdef HAVE_STRTOL
|
||||
long int bits;
|
||||
#else
|
||||
int bits;
|
||||
#endif
|
||||
char mask[16];
|
||||
char *a = NULL, *t = NULL;
|
||||
|
||||
if (!addr || !*addr)
|
||||
return 0;
|
||||
|
||||
p = strchr(tok,'/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
/* Fail quietly if tok is a hostname, not an address. */
|
||||
if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) {
|
||||
if (p)
|
||||
*p = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
#ifdef AI_NUMERICHOST
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
|
||||
if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
|
||||
if (p)
|
||||
*p = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
gai = getaddrinfo(tok, NULL, &hints, &rest);
|
||||
if (p)
|
||||
*p++ = '/';
|
||||
if (gai != 0) {
|
||||
rprintf(FLOG, "error matching address %s: %s\n",
|
||||
tok, gai_strerror(gai));
|
||||
freeaddrinfo(resa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rest->ai_family != resa->ai_family) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch(resa->ai_family) {
|
||||
case PF_INET:
|
||||
a = (char *)&((struct sockaddr_in *)resa->ai_addr)->sin_addr;
|
||||
t = (char *)&((struct sockaddr_in *)rest->ai_addr)->sin_addr;
|
||||
addrlen = 4;
|
||||
|
||||
break;
|
||||
|
||||
#ifdef INET6
|
||||
case PF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *sin6a, *sin6t;
|
||||
|
||||
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
|
||||
sin6t = (struct sockaddr_in6 *)rest->ai_addr;
|
||||
|
||||
a = (char *)&sin6a->sin6_addr;
|
||||
t = (char *)&sin6t->sin6_addr;
|
||||
|
||||
addrlen = 16;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
if (sin6t->sin6_scope_id &&
|
||||
sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bits = -1;
|
||||
if (p) {
|
||||
if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) {
|
||||
#ifdef HAVE_STRTOL
|
||||
char *ep = NULL;
|
||||
#else
|
||||
unsigned char *pp;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRTOL
|
||||
bits = strtol(p, &ep, 10);
|
||||
if (!*p || *ep) {
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
for (pp = (unsigned char *)p; *pp; pp++) {
|
||||
if (!isascii(*pp) || !isdigit(*pp)) {
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
bits = atoi(p);
|
||||
#endif
|
||||
if (bits == 0) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
if (bits < 0 || bits > (addrlen << 3)) {
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bits = 128;
|
||||
}
|
||||
|
||||
if (bits >= 0)
|
||||
make_mask(mask, bits, addrlen);
|
||||
|
||||
ret = match_binary(a, t, mask, addrlen);
|
||||
|
||||
out:
|
||||
freeaddrinfo(resa);
|
||||
freeaddrinfo(rest);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int access_match(const char *list, const char *addr, const char **host_ptr)
|
||||
{
|
||||
char *tok;
|
||||
char *list2 = strdup(list);
|
||||
|
||||
if (!list2)
|
||||
out_of_memory("access_match");
|
||||
|
||||
strlower(list2);
|
||||
|
||||
for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
|
||||
if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) {
|
||||
free(list2);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(list2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int allow_access(const char *addr, const char **host_ptr, int i)
|
||||
{
|
||||
const char *allow_list = lp_hosts_allow(i);
|
||||
const char *deny_list = lp_hosts_deny(i);
|
||||
|
||||
if (allow_list && !*allow_list)
|
||||
allow_list = NULL;
|
||||
if (deny_list && !*deny_list)
|
||||
deny_list = NULL;
|
||||
|
||||
allow_forward_dns = lp_forward_lookup(i);
|
||||
|
||||
/* If we match an allow-list item, we always allow access. */
|
||||
if (allow_list) {
|
||||
if (access_match(allow_list, addr, host_ptr))
|
||||
return 1;
|
||||
/* For an allow-list w/o a deny-list, disallow non-matches. */
|
||||
if (!deny_list)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we match a deny-list item (and got past any allow-list
|
||||
* items), we always disallow access. */
|
||||
if (deny_list && access_match(deny_list, addr, host_ptr))
|
||||
return 0;
|
||||
|
||||
/* Allow all other access. */
|
||||
return 1;
|
||||
}
|
92
rsync/aclocal.m4
vendored
Normal file
92
rsync/aclocal.m4
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
|
||||
dnl if the cache file is inconsistent with the current host,
|
||||
dnl target and build system types, execute CMD or print a default
|
||||
dnl error message.
|
||||
AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
|
||||
AC_REQUIRE([AC_CANONICAL_SYSTEM])
|
||||
AC_MSG_CHECKING([config.cache system type])
|
||||
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_host_system_type" != x"$host"; } ||
|
||||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_build_system_type" != x"$build"; } ||
|
||||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_target_system_type" != x"$target"; }; then
|
||||
AC_MSG_RESULT([different])
|
||||
ifelse($#, 1, [$1],
|
||||
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
|
||||
else
|
||||
AC_MSG_RESULT([same])
|
||||
fi
|
||||
ac_cv_host_system_type="$host"
|
||||
ac_cv_build_system_type="$build"
|
||||
ac_cv_target_system_type="$target"
|
||||
])
|
||||
|
||||
dnl Check for socklen_t: historically on BSD it is an int, and in
|
||||
dnl POSIX 1g it is a type of its own, but some platforms use different
|
||||
dnl types for the argument to getsockopt, getpeername, etc. So we
|
||||
dnl have to test to find something that will work.
|
||||
|
||||
dnl This is no good, because passing the wrong pointer on C compilers is
|
||||
dnl likely to only generate a warning, not an error. We don't call this at
|
||||
dnl the moment.
|
||||
|
||||
AC_DEFUN([TYPE_SOCKLEN_T],
|
||||
[
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([rsync_cv_socklen_t_equiv],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
rsync_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
],[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
],[
|
||||
rsync_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$rsync_cv_socklen_t_equiv" = x; then
|
||||
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($rsync_cv_socklen_t_equiv)
|
||||
AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv,
|
||||
[type to use in place of socklen_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
])
|
||||
|
||||
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
|
||||
AC_DEFUN([AC_HAVE_TYPE], [
|
||||
AC_REQUIRE([AC_HEADER_STDC])
|
||||
cv=`echo "$1" | sed 'y%./+- %__p__%'`
|
||||
AC_MSG_CHECKING(for $1)
|
||||
AC_CACHE_VAL([ac_cv_type_$cv],
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
AC_INCLUDES_DEFAULT
|
||||
$2]],
|
||||
[[$1 foo;]])],
|
||||
[eval "ac_cv_type_$cv=yes"],
|
||||
[eval "ac_cv_type_$cv=no"]))dnl
|
||||
ac_foo=`eval echo \\$ac_cv_type_$cv`
|
||||
AC_MSG_RESULT($ac_foo)
|
||||
if test "$ac_foo" = yes; then
|
||||
ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
|
||||
if false; then
|
||||
AC_CHECK_TYPES($1)
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
|
||||
fi
|
||||
])
|
1155
rsync/acls.c
Normal file
1155
rsync/acls.c
Normal file
File diff suppressed because it is too large
Load Diff
373
rsync/authenticate.c
Normal file
373
rsync/authenticate.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern int read_only;
|
||||
extern char *password_file;
|
||||
|
||||
/***************************************************************************
|
||||
encode a buffer using base64 - simple and slow algorithm. null terminates
|
||||
the result.
|
||||
***************************************************************************/
|
||||
void base64_encode(const char *buf, int len, char *out, int pad)
|
||||
{
|
||||
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i;
|
||||
const uchar *d = (const uchar *)buf;
|
||||
int bytes = (len*8 + 5)/6;
|
||||
|
||||
for (i = 0; i < bytes; i++) {
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
if (bit_offset < 3) {
|
||||
idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
|
||||
} else {
|
||||
idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
|
||||
if (byte_offset+1 < len) {
|
||||
idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
|
||||
}
|
||||
}
|
||||
out[i] = b64[idx];
|
||||
}
|
||||
|
||||
while (pad && (i % 4))
|
||||
out[i++] = '=';
|
||||
|
||||
out[i] = '\0';
|
||||
}
|
||||
|
||||
/* Generate a challenge buffer and return it base64-encoded. */
|
||||
static void gen_challenge(const char *addr, char *challenge)
|
||||
{
|
||||
char input[32];
|
||||
char digest[MAX_DIGEST_LEN];
|
||||
struct timeval tv;
|
||||
int len;
|
||||
|
||||
memset(input, 0, sizeof input);
|
||||
|
||||
strlcpy(input, addr, 17);
|
||||
sys_gettimeofday(&tv);
|
||||
SIVAL(input, 16, tv.tv_sec);
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
|
||||
sum_init(0);
|
||||
sum_update(input, sizeof input);
|
||||
len = sum_end(digest);
|
||||
|
||||
base64_encode(digest, len, challenge, 0);
|
||||
}
|
||||
|
||||
/* Generate an MD4 hash created from the combination of the password
|
||||
* and the challenge string and return it base64-encoded. */
|
||||
static void generate_hash(const char *in, const char *challenge, char *out)
|
||||
{
|
||||
char buf[MAX_DIGEST_LEN];
|
||||
int len;
|
||||
|
||||
sum_init(0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
len = sum_end(buf);
|
||||
|
||||
base64_encode(buf, len, out, 0);
|
||||
}
|
||||
|
||||
/* Return the secret for a user from the secret file, null terminated.
|
||||
* Maximum length is len (not counting the null). */
|
||||
static const char *check_secret(int module, const char *user, const char *group,
|
||||
const char *challenge, const char *pass)
|
||||
{
|
||||
char line[1024];
|
||||
char pass2[MAX_DIGEST_LEN*2];
|
||||
const char *fname = lp_secrets_file(module);
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
int user_len = strlen(user);
|
||||
int group_len = group ? strlen(group) : 0;
|
||||
char *err;
|
||||
FILE *fh;
|
||||
|
||||
if (!fname || !*fname || (fh = fopen(fname, "r")) == NULL)
|
||||
return "no secrets file";
|
||||
|
||||
if (do_fstat(fileno(fh), &st) == -1) {
|
||||
rsyserr(FLOG, errno, "fstat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
|
||||
ok = 0;
|
||||
} else if (MY_UID() == 0 && st.st_uid != 0) {
|
||||
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
fclose(fh);
|
||||
return "ignoring secrets file";
|
||||
}
|
||||
|
||||
if (*user == '#') {
|
||||
/* Reject attempt to match a comment. */
|
||||
fclose(fh);
|
||||
return "invalid username";
|
||||
}
|
||||
|
||||
/* Try to find a line that starts with the user (or @group) name and a ':'. */
|
||||
err = "secret not found";
|
||||
while ((user || group) && fgets(line, sizeof line, fh) != NULL) {
|
||||
const char **ptr, *s = strtok(line, "\n\r");
|
||||
int len;
|
||||
if (!s)
|
||||
continue;
|
||||
if (*s == '@') {
|
||||
ptr = &group;
|
||||
len = group_len;
|
||||
s++;
|
||||
} else {
|
||||
ptr = &user;
|
||||
len = user_len;
|
||||
}
|
||||
if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':')
|
||||
continue;
|
||||
generate_hash(s+len+1, challenge, pass2);
|
||||
if (strcmp(pass, pass2) == 0) {
|
||||
err = NULL;
|
||||
break;
|
||||
}
|
||||
err = "password mismatch";
|
||||
*ptr = NULL; /* Don't look for name again. */
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
|
||||
memset(line, 0, sizeof line);
|
||||
memset(pass2, 0, sizeof pass2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *getpassf(const char *filename)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
char buffer[512], *p;
|
||||
int n;
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
if (strcmp(filename, "-") == 0) {
|
||||
n = fgets(buffer, sizeof buffer, stdin) == NULL ? -1 : (int)strlen(buffer);
|
||||
} else {
|
||||
int fd;
|
||||
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FERROR, errno, "could not open password file %s", filename);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (do_stat(filename, &st) == -1) {
|
||||
rsyserr(FERROR, errno, "stat(%s)", filename);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR, "ERROR: password file must not be other-accessible\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (MY_UID() == 0 && st.st_uid != 0) {
|
||||
rprintf(FERROR, "ERROR: password file must be owned by root when running as root\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
n = read(fd, buffer, sizeof buffer - 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
if ((p = strtok(buffer, "\n\r")) != NULL)
|
||||
return strdup(p);
|
||||
}
|
||||
|
||||
rprintf(FERROR, "ERROR: failed to read a password from %s\n", filename);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
* start off the auth if necessary.
|
||||
*
|
||||
* Return NULL if authentication failed. Return "" if anonymous access.
|
||||
* Otherwise return username.
|
||||
*/
|
||||
char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
const char *addr, const char *leader)
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
char challenge[MAX_DIGEST_LEN*2];
|
||||
char line[BIGPATHBUFLEN];
|
||||
char **auth_uid_groups = NULL;
|
||||
int auth_uid_groups_cnt = -1;
|
||||
const char *err = NULL;
|
||||
int group_match = -1;
|
||||
char *tok, *pass;
|
||||
char opt_ch = '\0';
|
||||
|
||||
/* if no auth list then allow anyone in! */
|
||||
if (!users || !*users)
|
||||
return "";
|
||||
|
||||
gen_challenge(addr, challenge);
|
||||
|
||||
io_printf(f_out, "%s%s\n", leader, challenge);
|
||||
|
||||
if (!read_line_old(f_in, line, sizeof line, 0)
|
||||
|| (pass = strchr(line, ' ')) == NULL) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"invalid challenge response\n",
|
||||
lp_name(module), host, addr);
|
||||
return NULL;
|
||||
}
|
||||
*pass++ = '\0';
|
||||
|
||||
if (!(users = strdup(users)))
|
||||
out_of_memory("auth_server");
|
||||
|
||||
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
|
||||
char *opts;
|
||||
/* See if the user appended :deny, :ro, or :rw. */
|
||||
if ((opts = strchr(tok, ':')) != NULL) {
|
||||
*opts++ = '\0';
|
||||
opt_ch = isUpper(opts) ? toLower(opts) : *opts;
|
||||
if (opt_ch == 'r') { /* handle ro and rw */
|
||||
opt_ch = isUpper(opts+1) ? toLower(opts+1) : opts[1];
|
||||
if (opt_ch == 'o')
|
||||
opt_ch = 'r';
|
||||
else if (opt_ch != 'w')
|
||||
opt_ch = '\0';
|
||||
} else if (opt_ch != 'd') /* if it's not deny, ignore it */
|
||||
opt_ch = '\0';
|
||||
} else
|
||||
opt_ch = '\0';
|
||||
if (*tok != '@') {
|
||||
/* Match the username */
|
||||
if (wildmatch(tok, line))
|
||||
break;
|
||||
} else {
|
||||
#ifdef HAVE_GETGROUPLIST
|
||||
int j;
|
||||
/* See if authorizing user is a real user, and if so, see
|
||||
* if it is in a group that matches tok+1 wildmat. */
|
||||
if (auth_uid_groups_cnt < 0) {
|
||||
gid_t gid_list[64];
|
||||
uid_t auth_uid;
|
||||
auth_uid_groups_cnt = sizeof gid_list / sizeof (gid_t);
|
||||
if (!user_to_uid(line, &auth_uid, False)
|
||||
|| getallgroups(auth_uid, gid_list, &auth_uid_groups_cnt) != NULL)
|
||||
auth_uid_groups_cnt = 0;
|
||||
else {
|
||||
if ((auth_uid_groups = new_array(char *, auth_uid_groups_cnt)) == NULL)
|
||||
out_of_memory("auth_server");
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++)
|
||||
auth_uid_groups[j] = gid_to_group(gid_list[j]);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++) {
|
||||
if (auth_uid_groups[j] && wildmatch(tok+1, auth_uid_groups[j])) {
|
||||
group_match = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group_match >= 0)
|
||||
break;
|
||||
#else
|
||||
rprintf(FLOG, "your computer doesn't support getgrouplist(), so no @group authorization is possible.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
free(users);
|
||||
|
||||
if (!tok)
|
||||
err = "no matching rule";
|
||||
else if (opt_ch == 'd')
|
||||
err = "denied by rule";
|
||||
else {
|
||||
char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL;
|
||||
err = check_secret(module, line, group, challenge, pass);
|
||||
}
|
||||
|
||||
memset(challenge, 0, sizeof challenge);
|
||||
memset(pass, 0, strlen(pass));
|
||||
|
||||
if (auth_uid_groups) {
|
||||
int j;
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++) {
|
||||
if (auth_uid_groups[j])
|
||||
free(auth_uid_groups[j]);
|
||||
}
|
||||
free(auth_uid_groups);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s) for %s: %s\n",
|
||||
lp_name(module), host, addr, line, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (opt_ch == 'r')
|
||||
read_only = 1;
|
||||
else if (opt_ch == 'w')
|
||||
read_only = 0;
|
||||
|
||||
return strdup(line);
|
||||
}
|
||||
|
||||
void auth_client(int fd, const char *user, const char *challenge)
|
||||
{
|
||||
const char *pass;
|
||||
char pass2[MAX_DIGEST_LEN*2];
|
||||
|
||||
if (!user || !*user)
|
||||
user = "nobody";
|
||||
|
||||
if (!(pass = getpassf(password_file))
|
||||
&& !(pass = getenv("RSYNC_PASSWORD"))) {
|
||||
/* XXX: cyeoh says that getpass is deprecated, because
|
||||
* it may return a truncated password on some systems,
|
||||
* and it is not in the LSB.
|
||||
*
|
||||
* Andrew Klein says that getpassphrase() is present
|
||||
* on Solaris and reads up to 256 characters.
|
||||
*
|
||||
* OpenBSD has a readpassphrase() that might be more suitable.
|
||||
*/
|
||||
pass = getpass("Password: ");
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
pass = "";
|
||||
|
||||
generate_hash(pass, challenge, pass2);
|
||||
io_printf(fd, "%s %s\n", user, pass2);
|
||||
}
|
341
rsync/backup.c
Normal file
341
rsync/backup.c
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Backup handling code.
|
||||
*
|
||||
* Copyright (C) 1999 Andrew Tridgell
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int am_root;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
extern int preserve_links;
|
||||
extern int safe_symlinks;
|
||||
extern int backup_dir_len;
|
||||
extern unsigned int backup_dir_remainder;
|
||||
extern char backup_dir_buf[MAXPATHLEN];
|
||||
extern char *backup_suffix;
|
||||
extern char *backup_dir;
|
||||
|
||||
/* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
|
||||
static int validate_backup_dir(void)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
|
||||
if (do_lstat(backup_dir_buf, &st) < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
|
||||
if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create a backup path from the given fname, putting the result into
|
||||
* backup_dir_buf. Any new directories (compared to the prior backup
|
||||
* path) are ensured to exist as directories, replacing anything else
|
||||
* that may be in the way (e.g. a symlink). */
|
||||
static BOOL copy_valid_path(const char *fname)
|
||||
{
|
||||
const char *f;
|
||||
int val;
|
||||
BOOL ret = True;
|
||||
stat_x sx;
|
||||
char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel;
|
||||
|
||||
for (f = fname, b = rel; *f && *f == *b; f++, b++) {
|
||||
if (*b == '/')
|
||||
name = b + 1;
|
||||
}
|
||||
|
||||
if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) {
|
||||
rprintf(FERROR, "backup filename too long\n");
|
||||
*name = '\0';
|
||||
return False;
|
||||
}
|
||||
|
||||
for ( ; ; name = b + 1) {
|
||||
if ((b = strchr(name, '/')) == NULL)
|
||||
return True;
|
||||
*b = '\0';
|
||||
|
||||
val = validate_backup_dir();
|
||||
if (val == 0)
|
||||
break;
|
||||
if (val < 0) {
|
||||
*name = '\0';
|
||||
return False;
|
||||
}
|
||||
|
||||
*b = '/';
|
||||
}
|
||||
|
||||
init_stat_x(&sx);
|
||||
|
||||
for ( ; b; name = b + 1, b = strchr(name, '/')) {
|
||||
*b = '\0';
|
||||
|
||||
while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
val = validate_backup_dir();
|
||||
if (val > 0)
|
||||
break;
|
||||
if (val == 0)
|
||||
continue;
|
||||
} else
|
||||
rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf);
|
||||
*name = '\0';
|
||||
ret = False;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Try to transfer the directory settings of the actual dir
|
||||
* that the files are coming from. */
|
||||
if (x_stat(rel, &sx.st, NULL) < 0)
|
||||
rsyserr(FERROR, errno, "backup stat %s failed", full_fname(rel));
|
||||
else {
|
||||
struct file_struct *file;
|
||||
if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
|
||||
continue;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
get_acl(rel, &sx);
|
||||
cache_tmp_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(rel, &sx);
|
||||
cache_tmp_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
set_file_attrs(backup_dir_buf, file, NULL, NULL, 0);
|
||||
unmake_file(file);
|
||||
}
|
||||
|
||||
*b = '/';
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make a complete pathname for backup file and verify any new path elements. */
|
||||
char *get_backup_name(const char *fname)
|
||||
{
|
||||
if (backup_dir) {
|
||||
/* copy fname into backup_dir_buf while validating the dirs. */
|
||||
if (copy_valid_path(fname))
|
||||
return backup_dir_buf;
|
||||
/* copy_valid_path() has printed an error message. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN)
|
||||
return backup_dir_buf;
|
||||
|
||||
rprintf(FERROR, "backup filename too long\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Has same return codes as make_backup(). */
|
||||
static inline int link_or_rename(const char *from, const char *to,
|
||||
BOOL prefer_rename, STRUCT_STAT *stp)
|
||||
{
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (!prefer_rename) {
|
||||
#ifndef CAN_HARDLINK_SYMLINK
|
||||
if (S_ISLNK(stp->st_mode))
|
||||
return 0; /* Use copy code. */
|
||||
#endif
|
||||
#ifndef CAN_HARDLINK_SPECIAL
|
||||
if (IS_SPECIAL(stp->st_mode) || IS_DEVICE(stp->st_mode))
|
||||
return 0; /* Use copy code. */
|
||||
#endif
|
||||
if (do_link(from, to) == 0) {
|
||||
if (DEBUG_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "make_backup: HLINK %s successful.\n", from);
|
||||
return 2;
|
||||
}
|
||||
/* We prefer to rename a regular file rather than copy it. */
|
||||
if (!S_ISREG(stp->st_mode) || errno == EEXIST || errno == EISDIR)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (do_rename(from, to) == 0) {
|
||||
if (stp->st_nlink > 1 && !S_ISDIR(stp->st_mode)) {
|
||||
/* If someone has hard-linked the file into the backup
|
||||
* dir, rename() might return success but do nothing! */
|
||||
robust_unlink(from); /* Just in case... */
|
||||
}
|
||||
if (DEBUG_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "make_backup: RENAME %s successful.\n", from);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Hard-link, rename, or copy an item to the backup name. Returns 2 if item
|
||||
* was duplicated into backup area, 1 if item was moved, or 0 for failure.*/
|
||||
int make_backup(const char *fname, BOOL prefer_rename)
|
||||
{
|
||||
stat_x sx;
|
||||
struct file_struct *file;
|
||||
int save_preserve_xattrs;
|
||||
char *buf = get_backup_name(fname);
|
||||
int ret = 0;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
init_stat_x(&sx);
|
||||
/* Return success if no file to keep. */
|
||||
if (x_lstat(fname, &sx.st, NULL) < 0)
|
||||
return 1;
|
||||
|
||||
/* Try a hard-link or a rename first. Using rename is not atomic, but
|
||||
* is more efficient than forcing a copy for larger files when no hard-
|
||||
* linking is possible. */
|
||||
if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
|
||||
goto success;
|
||||
if (errno == EEXIST || errno == EISDIR) {
|
||||
STRUCT_STAT bakst;
|
||||
if (do_lstat(buf, &bakst) == 0) {
|
||||
int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
|
||||
if (delete_item(buf, bakst.st_mode, flags) != 0)
|
||||
return 0;
|
||||
}
|
||||
if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* Fall back to making a copy. */
|
||||
if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
|
||||
return 1; /* the file could have disappeared */
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
get_acl(fname, &sx);
|
||||
cache_tmp_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(fname, &sx);
|
||||
cache_tmp_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check to see if this is a device file, or link */
|
||||
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|
||||
|| (preserve_specials && IS_SPECIAL(file->mode))) {
|
||||
if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
|
||||
rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf));
|
||||
else if (DEBUG_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (!ret && preserve_links && S_ISLNK(file->mode)) {
|
||||
const char *sl = F_SYMLINK(file);
|
||||
if (safe_symlinks && unsafe_symlink(sl, fname)) {
|
||||
if (INFO_GTE(SYMSAFE, 1)) {
|
||||
rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
|
||||
fname, sl);
|
||||
}
|
||||
ret = 2;
|
||||
} else {
|
||||
if (do_symlink(sl, buf) < 0)
|
||||
rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl);
|
||||
else if (DEBUG_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname);
|
||||
ret = 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ret && !S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname);
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Copy to backup tree if a file. */
|
||||
if (!ret) {
|
||||
if (copy_file(fname, buf, -1, file->mode) < 0) {
|
||||
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
|
||||
full_fname(fname), buf);
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if (DEBUG_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "make_backup: COPY %s successful.\n", fname);
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
save_preserve_xattrs = preserve_xattrs;
|
||||
preserve_xattrs = 0;
|
||||
set_file_attrs(buf, file, NULL, fname, 0);
|
||||
preserve_xattrs = save_preserve_xattrs;
|
||||
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
|
||||
success:
|
||||
if (INFO_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
|
||||
return ret;
|
||||
}
|
283
rsync/batch.c
Normal file
283
rsync/batch.c
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Support for the batch-file options.
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include <zlib.h>
|
||||
#include <time.h>
|
||||
|
||||
extern int eol_nulls;
|
||||
extern int recurse;
|
||||
extern int xfer_dirs;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int always_checksum;
|
||||
extern int do_compression;
|
||||
extern int inplace;
|
||||
extern int append_mode;
|
||||
extern int protocol_version;
|
||||
extern char *batch_name;
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
|
||||
extern filter_rule_list filter_list;
|
||||
|
||||
int batch_stream_flags;
|
||||
|
||||
static int tweaked_append;
|
||||
static int tweaked_append_verify;
|
||||
static int tweaked_iconv;
|
||||
|
||||
static int *flag_ptr[] = {
|
||||
&recurse, /* 0 */
|
||||
&preserve_uid, /* 1 */
|
||||
&preserve_gid, /* 2 */
|
||||
&preserve_links, /* 3 */
|
||||
&preserve_devices, /* 4 */
|
||||
&preserve_hard_links, /* 5 */
|
||||
&always_checksum, /* 6 */
|
||||
&xfer_dirs, /* 7 (protocol 29) */
|
||||
&do_compression, /* 8 (protocol 29) */
|
||||
&tweaked_iconv, /* 9 (protocol 30) */
|
||||
&preserve_acls, /* 10 (protocol 30) */
|
||||
&preserve_xattrs, /* 11 (protocol 30) */
|
||||
&inplace, /* 12 (protocol 30) */
|
||||
&tweaked_append, /* 13 (protocol 30) */
|
||||
&tweaked_append_verify, /* 14 (protocol 30) */
|
||||
NULL
|
||||
};
|
||||
|
||||
static char *flag_name[] = {
|
||||
"--recurse (-r)",
|
||||
"--owner (-o)",
|
||||
"--group (-g)",
|
||||
"--links (-l)",
|
||||
"--devices (-D)",
|
||||
"--hard-links (-H)",
|
||||
"--checksum (-c)",
|
||||
"--dirs (-d)",
|
||||
"--compress (-z)",
|
||||
"--iconv",
|
||||
"--acls (-A)",
|
||||
"--xattrs (-X)",
|
||||
"--inplace",
|
||||
"--append",
|
||||
"--append-verify",
|
||||
NULL
|
||||
};
|
||||
|
||||
void write_stream_flags(int fd)
|
||||
{
|
||||
int i, flags;
|
||||
|
||||
tweaked_append = append_mode == 1;
|
||||
tweaked_append_verify = append_mode == 2;
|
||||
#ifdef ICONV_OPTION
|
||||
tweaked_iconv = iconv_opt != NULL;
|
||||
#endif
|
||||
|
||||
/* Start the batch file with a bitmap of data-stream-affecting
|
||||
* flags. */
|
||||
for (i = 0, flags = 0; flag_ptr[i]; i++) {
|
||||
if (*flag_ptr[i])
|
||||
flags |= 1 << i;
|
||||
}
|
||||
write_int(fd, flags);
|
||||
}
|
||||
|
||||
void read_stream_flags(int fd)
|
||||
{
|
||||
batch_stream_flags = read_int(fd);
|
||||
}
|
||||
|
||||
void check_batch_flags(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (protocol_version < 29)
|
||||
flag_ptr[7] = NULL;
|
||||
else if (protocol_version < 30)
|
||||
flag_ptr[9] = NULL;
|
||||
tweaked_append = append_mode == 1;
|
||||
tweaked_append_verify = append_mode == 2;
|
||||
#ifdef ICONV_OPTION
|
||||
tweaked_iconv = iconv_opt != NULL;
|
||||
#endif
|
||||
for (i = 0; flag_ptr[i]; i++) {
|
||||
int set = batch_stream_flags & (1 << i) ? 1 : 0;
|
||||
if (*flag_ptr[i] != set) {
|
||||
if (i == 9) {
|
||||
rprintf(FERROR,
|
||||
"%s specify the --iconv option to use this batch file.\n",
|
||||
set ? "Please" : "Do not");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (INFO_GTE(MISC, 1)) {
|
||||
rprintf(FINFO,
|
||||
"%sing the %s option to match the batchfile.\n",
|
||||
set ? "Sett" : "Clear", flag_name[i]);
|
||||
}
|
||||
*flag_ptr[i] = set;
|
||||
}
|
||||
}
|
||||
if (protocol_version < 29) {
|
||||
if (recurse)
|
||||
xfer_dirs |= 1;
|
||||
else if (xfer_dirs < 2)
|
||||
xfer_dirs = 0;
|
||||
}
|
||||
|
||||
if (tweaked_append)
|
||||
append_mode = 1;
|
||||
else if (tweaked_append_verify)
|
||||
append_mode = 2;
|
||||
}
|
||||
|
||||
static int write_arg(int fd, char *arg)
|
||||
{
|
||||
char *x, *s;
|
||||
int len, ret = 0;
|
||||
|
||||
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
|
||||
if (write(fd, arg, x - arg + 1) != x - arg + 1)
|
||||
ret = -1;
|
||||
arg += x - arg + 1;
|
||||
}
|
||||
|
||||
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
|
||||
if (write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
|
||||
if (write(fd, s, x - s + 1) != x - s + 1
|
||||
|| write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
}
|
||||
len = strlen(s);
|
||||
if (write(fd, s, len) != len
|
||||
|| write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
if (write(fd, arg, len) != len)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void write_filter_rules(int fd)
|
||||
{
|
||||
filter_rule *ent;
|
||||
|
||||
write_sbuf(fd, " <<'#E#'\n");
|
||||
for (ent = filter_list.head; ent; ent = ent->next) {
|
||||
unsigned int plen;
|
||||
char *p = get_rule_prefix(ent, "- ", 0, &plen);
|
||||
write_buf(fd, p, plen);
|
||||
write_sbuf(fd, ent->pattern);
|
||||
if (ent->rflags & FILTRULE_DIRECTORY)
|
||||
write_byte(fd, '/');
|
||||
write_byte(fd, eol_nulls ? 0 : '\n');
|
||||
}
|
||||
if (eol_nulls)
|
||||
write_sbuf(fd, ";\n");
|
||||
write_sbuf(fd, "#E#");
|
||||
}
|
||||
|
||||
/* This routine tries to write out an equivalent --read-batch command
|
||||
* given the user's --write-batch args. However, it doesn't really
|
||||
* understand most of the options, so it uses some overly simple
|
||||
* heuristics to munge the command line into something that will
|
||||
* (hopefully) work. */
|
||||
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
{
|
||||
int fd, i, len, err = 0;
|
||||
char *p, filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_name, ".sh", NULL);
|
||||
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IXUSR);
|
||||
if (fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
filename);
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
/* Write argvs info to BATCH.sh file */
|
||||
if (write_arg(fd, argv[0]) < 0)
|
||||
err = 1;
|
||||
if (filter_list.head) {
|
||||
if (protocol_version >= 29)
|
||||
write_sbuf(fd, " --filter=._-");
|
||||
else
|
||||
write_sbuf(fd, " --exclude-from=-");
|
||||
}
|
||||
for (i = 1; i < argc - file_arg_cnt; i++) {
|
||||
p = argv[i];
|
||||
if (strncmp(p, "--files-from", 12) == 0
|
||||
|| strncmp(p, "--filter", 8) == 0
|
||||
|| strncmp(p, "--include", 9) == 0
|
||||
|| strncmp(p, "--exclude", 9) == 0) {
|
||||
if (strchr(p, '=') == NULL)
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(p, "-f") == 0) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (write(fd, " ", 1) != 1)
|
||||
err = 1;
|
||||
if (strncmp(p, "--write-batch", len = 13) == 0
|
||||
|| strncmp(p, "--only-write-batch", len = 18) == 0) {
|
||||
if (write(fd, "--read-batch", 12) != 12)
|
||||
err = 1;
|
||||
if (p[len] == '=') {
|
||||
if (write(fd, "=", 1) != 1
|
||||
|| write_arg(fd, p + len + 1) < 0)
|
||||
err = 1;
|
||||
}
|
||||
} else {
|
||||
if (write_arg(fd, p) < 0)
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
|
||||
p = argv[argc - 1];
|
||||
if (write(fd, " ${1:-", 6) != 6
|
||||
|| write_arg(fd, p) < 0)
|
||||
err = 1;
|
||||
write_byte(fd, '}');
|
||||
if (filter_list.head)
|
||||
write_filter_rules(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0 || err) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error",
|
||||
filename);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
}
|
124
rsync/byteorder.h
Normal file
124
rsync/byteorder.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Simple byteorder handling.
|
||||
*
|
||||
* Copyright (C) 1992-1995 Andrew Tridgell
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#undef CAREFUL_ALIGNMENT
|
||||
#undef AVOID_BYTEORDER_INLINE
|
||||
|
||||
/* We know that the x86 can handle misalignment and has the same
|
||||
* byte order (LSB-first) as the 32-bit numbers we transmit. */
|
||||
#if defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__ || __amd64
|
||||
#define CAREFUL_ALIGNMENT 0
|
||||
#endif
|
||||
|
||||
#ifndef CAREFUL_ALIGNMENT
|
||||
#define CAREFUL_ALIGNMENT 1
|
||||
#endif
|
||||
|
||||
#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
|
||||
#define UVAL(buf,pos) ((uint32)CVAL(buf,pos))
|
||||
|
||||
#if CAREFUL_ALIGNMENT
|
||||
|
||||
#define PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8)
|
||||
#define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16)
|
||||
#define IVAL64(buf,pos) (IVAL(buf,pos)|(int64)IVAL(buf,(pos)+4)<<32)
|
||||
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
|
||||
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
|
||||
#define SIVAL(buf,pos,val) SIVALX(buf,pos,(uint32)(val))
|
||||
#define SIVAL64(buf,pos,val) (SIVAL(buf,pos,val),SIVAL(buf,(pos)+4,(val)>>32))
|
||||
|
||||
#define IVALu(buf,pos) IVAL(buf,pos)
|
||||
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
|
||||
|
||||
#else /* !CAREFUL_ALIGNMENT */
|
||||
|
||||
/* This handles things for architectures like the 386 that can handle alignment errors.
|
||||
* WARNING: This section is dependent on the length of an int32 (and thus a uint32)
|
||||
* being correct (4 bytes)! Set CAREFUL_ALIGNMENT if it is not. */
|
||||
|
||||
# ifdef AVOID_BYTEORDER_INLINE
|
||||
|
||||
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
|
||||
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
|
||||
|
||||
#define IVALu(buf,pos) IVAL(buf,pos)
|
||||
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
|
||||
|
||||
# else /* !AVOID_BYTEORDER_INLINE */
|
||||
|
||||
static inline uint32
|
||||
IVALu(const uchar *buf, int pos)
|
||||
{
|
||||
union {
|
||||
const uchar *b;
|
||||
const uint32 *num;
|
||||
} u;
|
||||
u.b = buf + pos;
|
||||
return *u.num;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVALu(uchar *buf, int pos, uint32 val)
|
||||
{
|
||||
union {
|
||||
uchar *b;
|
||||
uint32 *num;
|
||||
} u;
|
||||
u.b = buf + pos;
|
||||
*u.num = val;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
IVAL(const char *buf, int pos)
|
||||
{
|
||||
return IVALu((uchar*)buf, pos);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVAL(char *buf, int pos, uint32 val)
|
||||
{
|
||||
SIVALu((uchar*)buf, pos, val);
|
||||
}
|
||||
|
||||
static inline int64
|
||||
IVAL64(const char *buf, int pos)
|
||||
{
|
||||
union {
|
||||
const char *b;
|
||||
const int64 *num;
|
||||
} u;
|
||||
u.b = buf + pos;
|
||||
return *u.num;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVAL64(char *buf, int pos, int64 val)
|
||||
{
|
||||
union {
|
||||
char *b;
|
||||
int64 *num;
|
||||
} u;
|
||||
u.b = buf + pos;
|
||||
*u.num = val;
|
||||
}
|
||||
|
||||
# endif /* !AVOID_BYTEORDER_INLINE */
|
||||
|
||||
#endif /* !CAREFUL_ALIGNMENT */
|
76
rsync/case_N.h
Normal file
76
rsync/case_N.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Allow an arbitrary sequence of case labels.
|
||||
*
|
||||
* Copyright (C) 2006-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This is included multiple times, once for every segement in a switch statement.
|
||||
* This produces the next "case N:" statement in sequence. */
|
||||
|
||||
#if !defined CASE_N_STATE_0
|
||||
#define CASE_N_STATE_0
|
||||
case 0:
|
||||
#elif !defined CASE_N_STATE_1
|
||||
#define CASE_N_STATE_1
|
||||
case 1:
|
||||
#elif !defined CASE_N_STATE_2
|
||||
#define CASE_N_STATE_2
|
||||
case 2:
|
||||
#elif !defined CASE_N_STATE_3
|
||||
#define CASE_N_STATE_3
|
||||
case 3:
|
||||
#elif !defined CASE_N_STATE_4
|
||||
#define CASE_N_STATE_4
|
||||
case 4:
|
||||
#elif !defined CASE_N_STATE_5
|
||||
#define CASE_N_STATE_5
|
||||
case 5:
|
||||
#elif !defined CASE_N_STATE_6
|
||||
#define CASE_N_STATE_6
|
||||
case 6:
|
||||
#elif !defined CASE_N_STATE_7
|
||||
#define CASE_N_STATE_7
|
||||
case 7:
|
||||
#elif !defined CASE_N_STATE_8
|
||||
#define CASE_N_STATE_8
|
||||
case 8:
|
||||
#elif !defined CASE_N_STATE_9
|
||||
#define CASE_N_STATE_9
|
||||
case 9:
|
||||
#elif !defined CASE_N_STATE_10
|
||||
#define CASE_N_STATE_10
|
||||
case 10:
|
||||
#elif !defined CASE_N_STATE_11
|
||||
#define CASE_N_STATE_11
|
||||
case 11:
|
||||
#elif !defined CASE_N_STATE_12
|
||||
#define CASE_N_STATE_12
|
||||
case 12:
|
||||
#elif !defined CASE_N_STATE_13
|
||||
#define CASE_N_STATE_13
|
||||
case 13:
|
||||
#elif !defined CASE_N_STATE_14
|
||||
#define CASE_N_STATE_14
|
||||
case 14:
|
||||
#elif !defined CASE_N_STATE_15
|
||||
#define CASE_N_STATE_15
|
||||
case 15:
|
||||
#elif !defined CASE_N_STATE_16
|
||||
#define CASE_N_STATE_16
|
||||
case 16:
|
||||
#else
|
||||
#error Need to add more case statements!
|
||||
#endif
|
223
rsync/checksum.c
Normal file
223
rsync/checksum.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Routines to support checksumming of bytes.
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
|
||||
/*
|
||||
a simple 32 bit checksum that can be upadted from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
*/
|
||||
uint32 get_checksum1(char *buf1, int32 len)
|
||||
{
|
||||
int32 i;
|
||||
uint32 s1, s2;
|
||||
schar *buf = (schar *)buf1;
|
||||
|
||||
s1 = s2 = 0;
|
||||
for (i = 0; i < (len-4); i+=4) {
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
|
||||
10*CHAR_OFFSET;
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
|
||||
}
|
||||
return (s1 & 0xffff) + (s2 << 16);
|
||||
}
|
||||
|
||||
|
||||
void get_checksum2(char *buf, int32 len, char *sum)
|
||||
{
|
||||
md_context m;
|
||||
|
||||
if (protocol_version >= 30) {
|
||||
uchar seedbuf[4];
|
||||
md5_begin(&m);
|
||||
md5_update(&m, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m, seedbuf, 4);
|
||||
}
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
int32 i;
|
||||
static char *buf1;
|
||||
static int32 len1;
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
if (len > len1) {
|
||||
if (buf1)
|
||||
free(buf1);
|
||||
buf1 = new_array(char, len+4);
|
||||
len1 = len;
|
||||
if (!buf1)
|
||||
out_of_memory("get_checksum2");
|
||||
}
|
||||
|
||||
memcpy(buf1, buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(buf1,len,checksum_seed);
|
||||
len += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
|
||||
|
||||
/*
|
||||
* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
}
|
||||
|
||||
void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
{
|
||||
struct map_struct *buf;
|
||||
OFF_T i, len = st_p->st_size;
|
||||
md_context m;
|
||||
int32 remainder;
|
||||
int fd;
|
||||
|
||||
memset(sum, 0, MAX_DIGEST_LEN);
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK);
|
||||
|
||||
if (protocol_version >= 30) {
|
||||
md5_begin(&m);
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
mdfour_begin(&m);
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes. */
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
unmap_file(buf);
|
||||
}
|
||||
|
||||
static int32 sumresidue;
|
||||
static md_context md;
|
||||
|
||||
void sum_init(int seed)
|
||||
{
|
||||
char s[4];
|
||||
|
||||
if (protocol_version >= 30)
|
||||
md5_begin(&md);
|
||||
else {
|
||||
mdfour_begin(&md);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed data into an MD4 accumulator, md. The results may be
|
||||
* retrieved using sum_end(). md is used for different purposes at
|
||||
* different points during execution.
|
||||
*
|
||||
* @todo Perhaps get rid of md and just pass in the address each time.
|
||||
* Very slightly clearer and slower.
|
||||
**/
|
||||
void sum_update(const char *p, int32 len)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_update(&md, (uchar *)p, len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(md.buffer + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sumresidue) {
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(md.buffer + sumresidue, p, i);
|
||||
mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
|
||||
while (len >= CSUM_CHUNK) {
|
||||
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(md.buffer, p, sumresidue);
|
||||
}
|
||||
|
||||
int sum_end(char *sum)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_result(&md, (uchar *)sum);
|
||||
return MD5_DIGEST_LEN;
|
||||
}
|
||||
|
||||
if (sumresidue || protocol_version >= 27)
|
||||
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
|
||||
|
||||
mdfour_result(&md, (uchar *)sum);
|
||||
|
||||
return MD4_DIGEST_LEN;
|
||||
}
|
249
rsync/chmod.c
Normal file
249
rsync/chmod.c
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Implement the core of the --chmod option.
|
||||
*
|
||||
* Copyright (C) 2002 Scott Howard
|
||||
* Copyright (C) 2005-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern mode_t orig_umask;
|
||||
|
||||
#define FLAG_X_KEEP (1<<0)
|
||||
#define FLAG_DIRS_ONLY (1<<1)
|
||||
#define FLAG_FILES_ONLY (1<<2)
|
||||
|
||||
struct chmod_mode_struct {
|
||||
struct chmod_mode_struct *next;
|
||||
int ModeAND, ModeOR;
|
||||
char flags;
|
||||
};
|
||||
|
||||
#define CHMOD_ADD 1
|
||||
#define CHMOD_SUB 2
|
||||
#define CHMOD_EQ 3
|
||||
#define CHMOD_SET 4
|
||||
|
||||
#define STATE_ERROR 0
|
||||
#define STATE_1ST_HALF 1
|
||||
#define STATE_2ND_HALF 2
|
||||
#define STATE_OCTAL_NUM 3
|
||||
|
||||
/* Parse a chmod-style argument, and break it down into one or more AND/OR
|
||||
* pairs in a linked list. We return a pointer to new items on succcess
|
||||
* (appending the items to the specified list), or NULL on error. */
|
||||
struct chmod_mode_struct *parse_chmod(const char *modestr,
|
||||
struct chmod_mode_struct **root_mode_ptr)
|
||||
{
|
||||
int state = STATE_1ST_HALF;
|
||||
int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
|
||||
struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
|
||||
*prev_mode = NULL;
|
||||
|
||||
while (state != STATE_ERROR) {
|
||||
if (!*modestr || *modestr == ',') {
|
||||
int bits;
|
||||
|
||||
if (!op) {
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
prev_mode = curr_mode;
|
||||
curr_mode = new_array(struct chmod_mode_struct, 1);
|
||||
if (prev_mode)
|
||||
prev_mode->next = curr_mode;
|
||||
else
|
||||
first_mode = curr_mode;
|
||||
curr_mode->next = NULL;
|
||||
|
||||
if (where)
|
||||
bits = where * what;
|
||||
else {
|
||||
where = 0111;
|
||||
bits = (where * what) & ~orig_umask;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case CHMOD_ADD:
|
||||
curr_mode->ModeAND = CHMOD_BITS;
|
||||
curr_mode->ModeOR = bits + topoct;
|
||||
break;
|
||||
case CHMOD_SUB:
|
||||
curr_mode->ModeAND = CHMOD_BITS - bits - topoct;
|
||||
curr_mode->ModeOR = 0;
|
||||
break;
|
||||
case CHMOD_EQ:
|
||||
curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
|
||||
curr_mode->ModeOR = bits + topoct;
|
||||
break;
|
||||
case CHMOD_SET:
|
||||
curr_mode->ModeAND = 0;
|
||||
curr_mode->ModeOR = bits;
|
||||
break;
|
||||
}
|
||||
|
||||
curr_mode->flags = flags;
|
||||
|
||||
if (!*modestr)
|
||||
break;
|
||||
modestr++;
|
||||
|
||||
state = STATE_1ST_HALF;
|
||||
where = what = op = topoct = topbits = flags = 0;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case STATE_1ST_HALF:
|
||||
switch (*modestr) {
|
||||
case 'D':
|
||||
if (flags & FLAG_FILES_ONLY)
|
||||
state = STATE_ERROR;
|
||||
flags |= FLAG_DIRS_ONLY;
|
||||
break;
|
||||
case 'F':
|
||||
if (flags & FLAG_DIRS_ONLY)
|
||||
state = STATE_ERROR;
|
||||
flags |= FLAG_FILES_ONLY;
|
||||
break;
|
||||
case 'u':
|
||||
where |= 0100;
|
||||
topbits |= 04000;
|
||||
break;
|
||||
case 'g':
|
||||
where |= 0010;
|
||||
topbits |= 02000;
|
||||
break;
|
||||
case 'o':
|
||||
where |= 0001;
|
||||
break;
|
||||
case 'a':
|
||||
where |= 0111;
|
||||
break;
|
||||
case '+':
|
||||
op = CHMOD_ADD;
|
||||
state = STATE_2ND_HALF;
|
||||
break;
|
||||
case '-':
|
||||
op = CHMOD_SUB;
|
||||
state = STATE_2ND_HALF;
|
||||
break;
|
||||
case '=':
|
||||
op = CHMOD_EQ;
|
||||
state = STATE_2ND_HALF;
|
||||
break;
|
||||
default:
|
||||
if (isDigit(modestr) && *modestr < '8' && !where) {
|
||||
op = CHMOD_SET;
|
||||
state = STATE_OCTAL_NUM;
|
||||
where = 1;
|
||||
what = *modestr - '0';
|
||||
} else
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_2ND_HALF:
|
||||
switch (*modestr) {
|
||||
case 'r':
|
||||
what |= 4;
|
||||
break;
|
||||
case 'w':
|
||||
what |= 2;
|
||||
break;
|
||||
case 'X':
|
||||
flags |= FLAG_X_KEEP;
|
||||
/* FALL THROUGH */
|
||||
case 'x':
|
||||
what |= 1;
|
||||
break;
|
||||
case 's':
|
||||
if (topbits)
|
||||
topoct |= topbits;
|
||||
else
|
||||
topoct = 04000;
|
||||
break;
|
||||
case 't':
|
||||
topoct |= 01000;
|
||||
break;
|
||||
default:
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_OCTAL_NUM:
|
||||
if (isDigit(modestr) && *modestr < '8') {
|
||||
what = what*8 + *modestr - '0';
|
||||
if (what > CHMOD_BITS)
|
||||
state = STATE_ERROR;
|
||||
} else
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
modestr++;
|
||||
}
|
||||
|
||||
if (state == STATE_ERROR) {
|
||||
free_chmod_mode(first_mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(curr_mode = *root_mode_ptr))
|
||||
*root_mode_ptr = first_mode;
|
||||
else {
|
||||
while (curr_mode->next)
|
||||
curr_mode = curr_mode->next;
|
||||
curr_mode->next = first_mode;
|
||||
}
|
||||
|
||||
return first_mode;
|
||||
}
|
||||
|
||||
|
||||
/* Takes an existing file permission and a list of AND/OR changes, and
|
||||
* create a new permissions. */
|
||||
int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
|
||||
{
|
||||
int IsX = mode & 0111;
|
||||
int NonPerm = mode & ~CHMOD_BITS;
|
||||
|
||||
for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
|
||||
if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
|
||||
continue;
|
||||
if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
|
||||
continue;
|
||||
mode &= chmod_modes->ModeAND;
|
||||
if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
|
||||
mode |= chmod_modes->ModeOR & ~0111;
|
||||
else
|
||||
mode |= chmod_modes->ModeOR;
|
||||
}
|
||||
|
||||
return mode | NonPerm;
|
||||
}
|
||||
|
||||
/* Free the linked list created by parse_chmod. */
|
||||
int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
|
||||
{
|
||||
struct chmod_mode_struct *next;
|
||||
|
||||
while (chmod_modes) {
|
||||
next = chmod_modes->next;
|
||||
free(chmod_modes);
|
||||
chmod_modes = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
292
rsync/cleanup.c
Normal file
292
rsync/cleanup.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* End-of-run cleanup routines.
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_receiver;
|
||||
extern int io_error;
|
||||
extern int keep_partial;
|
||||
extern int got_xfer_error;
|
||||
extern int protocol_version;
|
||||
extern int output_needs_newline;
|
||||
extern char *partial_dir;
|
||||
extern char *logfile_name;
|
||||
|
||||
BOOL shutting_down = False;
|
||||
BOOL flush_ok_after_signal = False;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Close all open sockets and files, allowing a (somewhat) graceful
|
||||
* shutdown() of socket connections. This eliminates the abortive
|
||||
* TCP RST sent by a Winsock-based system when the close() occurs.
|
||||
**/
|
||||
void close_all(void)
|
||||
{
|
||||
#ifdef SHUTDOWN_ALL_SOCKETS
|
||||
int max_fd;
|
||||
int fd;
|
||||
int ret;
|
||||
STRUCT_STAT st;
|
||||
|
||||
max_fd = sysconf(_SC_OPEN_MAX) - 1;
|
||||
for (fd = max_fd; fd >= 0; fd--) {
|
||||
if ((ret = do_fstat(fd, &st)) == 0) {
|
||||
if (is_a_socket(fd))
|
||||
ret = shutdown(fd, 2);
|
||||
ret = close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @file cleanup.c
|
||||
*
|
||||
* Code for handling interrupted transfers. Depending on the @c
|
||||
* --partial option, we may either delete the temporary file, or go
|
||||
* ahead and overwrite the destination. This second behaviour only
|
||||
* occurs if we've sent literal data and therefore hopefully made
|
||||
* progress on the transfer.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Set to True once literal data has been sent across the link for the
|
||||
* current file. (????)
|
||||
*
|
||||
* Handling the cleanup when a transfer is interrupted is tricky when
|
||||
* --partial is selected. We need to ensure that the partial file is
|
||||
* kept if any real data has been transferred.
|
||||
**/
|
||||
int cleanup_got_literal = 0;
|
||||
|
||||
static const char *cleanup_fname;
|
||||
static const char *cleanup_new_fname;
|
||||
static struct file_struct *cleanup_file;
|
||||
static int cleanup_fd_r = -1, cleanup_fd_w = -1;
|
||||
static pid_t cleanup_pid = 0;
|
||||
|
||||
pid_t cleanup_child_pid = -1;
|
||||
|
||||
/**
|
||||
* Eventually calls exit(), passing @p code, therefore does not return.
|
||||
*
|
||||
* @param code one of the RERR_* codes from errcode.h.
|
||||
**/
|
||||
NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
static int switch_step = 0;
|
||||
static int exit_code = 0, exit_line = 0;
|
||||
static const char *exit_file = NULL;
|
||||
static int first_code = 0;
|
||||
|
||||
SIGACTION(SIGUSR1, SIG_IGN);
|
||||
SIGACTION(SIGUSR2, SIG_IGN);
|
||||
|
||||
if (!exit_code) { /* Preserve first error exit info when recursing. */
|
||||
exit_code = code;
|
||||
exit_file = file;
|
||||
exit_line = line < 0 ? -line : line;
|
||||
}
|
||||
|
||||
/* If this is the exit at the end of the run, the server side
|
||||
* should not attempt to output a message (see log_exit()). */
|
||||
if (am_server && code == 0)
|
||||
am_server = 2;
|
||||
|
||||
/* Some of our actions might cause a recursive call back here, so we
|
||||
* keep track of where we are in the cleanup and never repeat a step. */
|
||||
switch (switch_step) {
|
||||
#include "case_N.h" /* case 0: */
|
||||
switch_step++;
|
||||
|
||||
first_code = code;
|
||||
|
||||
if (output_needs_newline) {
|
||||
fputc('\n', stdout);
|
||||
output_needs_newline = 0;
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(EXIT, 2)) {
|
||||
rprintf(FINFO,
|
||||
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
who_am_i(), code, file, line);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (cleanup_child_pid != -1) {
|
||||
int status;
|
||||
int pid = wait_process(cleanup_child_pid, &status, WNOHANG);
|
||||
if (pid == cleanup_child_pid) {
|
||||
status = WEXITSTATUS(status);
|
||||
if (status > exit_code)
|
||||
exit_code = status;
|
||||
}
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (cleanup_got_literal && (cleanup_fname || cleanup_fd_w != -1)) {
|
||||
if (cleanup_fd_r != -1) {
|
||||
close(cleanup_fd_r);
|
||||
cleanup_fd_r = -1;
|
||||
}
|
||||
if (cleanup_fd_w != -1) {
|
||||
flush_write_file(cleanup_fd_w);
|
||||
close(cleanup_fd_w);
|
||||
cleanup_fd_w = -1;
|
||||
}
|
||||
if (cleanup_fname && cleanup_new_fname && keep_partial
|
||||
&& handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
|
||||
int tweak_modtime = 0;
|
||||
const char *fname = cleanup_fname;
|
||||
cleanup_fname = NULL;
|
||||
if (!partial_dir) {
|
||||
/* We don't want to leave a partial file with a modern time or it
|
||||
* could be skipped via --update. Setting the time to something
|
||||
* really old also helps it to stand out as unfinished in an ls. */
|
||||
tweak_modtime = 1;
|
||||
cleanup_file->modtime = 0;
|
||||
}
|
||||
finish_transfer(cleanup_new_fname, fname, NULL, NULL,
|
||||
cleanup_file, tweak_modtime, !partial_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (flush_ok_after_signal) {
|
||||
flush_ok_after_signal = False;
|
||||
if (code == RERR_SIGNAL)
|
||||
io_flush(FULL_FLUSH);
|
||||
}
|
||||
if (!exit_code && !code)
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (cleanup_fname)
|
||||
do_unlink(cleanup_fname);
|
||||
if (exit_code)
|
||||
kill_all(SIGUSR1);
|
||||
if (cleanup_pid && cleanup_pid == getpid()) {
|
||||
char *pidf = lp_pid_file();
|
||||
if (pidf && *pidf)
|
||||
unlink(lp_pid_file());
|
||||
}
|
||||
|
||||
if (exit_code == 0) {
|
||||
if (code)
|
||||
exit_code = code;
|
||||
if (io_error & IOERR_DEL_LIMIT)
|
||||
exit_code = RERR_DEL_LIMIT;
|
||||
if (io_error & IOERR_VANISHED)
|
||||
exit_code = RERR_VANISHED;
|
||||
if (io_error & IOERR_GENERAL || got_xfer_error)
|
||||
exit_code = RERR_PARTIAL;
|
||||
}
|
||||
|
||||
/* If line < 0, this exit is after a MSG_ERROR_EXIT event, so
|
||||
* we don't want to output a duplicate error. */
|
||||
if ((exit_code && line > 0)
|
||||
|| am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1))))
|
||||
log_exit(exit_code, exit_file, exit_line);
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (DEBUG_GTE(EXIT, 1)) {
|
||||
rprintf(FINFO,
|
||||
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): "
|
||||
"about to call exit(%d)\n",
|
||||
who_am_i(), first_code, exit_file, exit_line, exit_code);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (exit_code && exit_code != RERR_SOCKETIO && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1
|
||||
&& exit_code != RERR_TIMEOUT && !shutting_down && (protocol_version >= 31 || am_receiver)) {
|
||||
if (line > 0) {
|
||||
if (DEBUG_GTE(EXIT, 3)) {
|
||||
rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n",
|
||||
who_am_i(), exit_code);
|
||||
}
|
||||
send_msg_int(MSG_ERROR_EXIT, exit_code);
|
||||
}
|
||||
noop_io_until_death();
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (am_server && exit_code)
|
||||
msleep(100);
|
||||
close_all();
|
||||
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
void cleanup_disable(void)
|
||||
{
|
||||
cleanup_fname = cleanup_new_fname = NULL;
|
||||
cleanup_fd_r = cleanup_fd_w = -1;
|
||||
cleanup_got_literal = 0;
|
||||
}
|
||||
|
||||
|
||||
void cleanup_set(const char *fnametmp, const char *fname, struct file_struct *file,
|
||||
int fd_r, int fd_w)
|
||||
{
|
||||
cleanup_fname = fnametmp;
|
||||
cleanup_new_fname = fname; /* can be NULL on a partial-dir failure */
|
||||
cleanup_file = file;
|
||||
cleanup_fd_r = fd_r;
|
||||
cleanup_fd_w = fd_w;
|
||||
}
|
||||
|
||||
void cleanup_set_pid(pid_t pid)
|
||||
{
|
||||
cleanup_pid = pid;
|
||||
}
|
348
rsync/clientname.c
Normal file
348
rsync/clientname.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Functions for looking up the remote name or addr of a socket.
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is now converted to use the new-style getaddrinfo()
|
||||
* interface, which supports IPv6 but is also supported on recent
|
||||
* IPv4-only machines. On systems that don't have that interface, we
|
||||
* emulate it using the KAME implementation.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
static const char default_name[] = "UNKNOWN";
|
||||
extern int am_server;
|
||||
|
||||
|
||||
/**
|
||||
* Return the IP addr of the client as a string
|
||||
**/
|
||||
char *client_addr(int fd)
|
||||
{
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
|
||||
if (initialised)
|
||||
return addr_buf;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
char *env_str;
|
||||
strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
|
||||
if ((env_str = getenv("REMOTE_HOST")) != NULL
|
||||
|| (env_str = getenv("SSH_CONNECTION")) != NULL
|
||||
|| (env_str = getenv("SSH_CLIENT")) != NULL
|
||||
|| (env_str = getenv("SSH2_CLIENT")) != NULL) {
|
||||
char *p;
|
||||
strlcpy(addr_buf, env_str, sizeof addr_buf);
|
||||
/* Truncate the value to just the IP address. */
|
||||
if ((p = strchr(addr_buf, ' ')) != NULL)
|
||||
*p = '\0';
|
||||
}
|
||||
} else {
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
getnameinfo((struct sockaddr *)&ss, length,
|
||||
addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
|
||||
}
|
||||
|
||||
return addr_buf;
|
||||
}
|
||||
|
||||
|
||||
static int get_sockaddr_family(const struct sockaddr_storage *ss)
|
||||
{
|
||||
return ((struct sockaddr *) ss)->sa_family;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the DNS name of the client.
|
||||
*
|
||||
* The name is statically cached so that repeated lookups are quick,
|
||||
* so there is a limit of one lookup per customer.
|
||||
*
|
||||
* If anything goes wrong, including the name->addr->name check, then
|
||||
* we just use "UNKNOWN", so you can use that value in hosts allow
|
||||
* lines.
|
||||
*
|
||||
* After translation from sockaddr to name we do a forward lookup to
|
||||
* make sure nobody is spoofing PTR records.
|
||||
**/
|
||||
char *client_name(int fd)
|
||||
{
|
||||
static char name_buf[100];
|
||||
static char port_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t ss_len;
|
||||
|
||||
if (initialised)
|
||||
return name_buf;
|
||||
|
||||
strlcpy(name_buf, default_name, sizeof name_buf);
|
||||
initialised = 1;
|
||||
|
||||
memset(&ss, 0, sizeof ss);
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
char *addr = client_addr(fd);
|
||||
struct addrinfo hint, *answer;
|
||||
int err;
|
||||
|
||||
if (strcmp(addr, "0.0.0.0") == 0)
|
||||
return name_buf;
|
||||
|
||||
memset(&hint, 0, sizeof hint);
|
||||
|
||||
#ifdef AI_NUMERICHOST
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FLOG, "malformed address %s: %s\n",
|
||||
addr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
switch (answer->ai_family) {
|
||||
case AF_INET:
|
||||
ss_len = sizeof (struct sockaddr_in);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ss_len = sizeof (struct sockaddr_in6);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
freeaddrinfo(answer);
|
||||
} else {
|
||||
ss_len = sizeof ss;
|
||||
client_sockaddr(fd, &ss, &ss_len);
|
||||
}
|
||||
|
||||
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf) == 0)
|
||||
check_name(fd, &ss, name_buf, sizeof name_buf);
|
||||
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the sockaddr for the client.
|
||||
*
|
||||
* If it comes in as an ipv4 address mapped into IPv6 format then we
|
||||
* convert it back to a regular IPv4.
|
||||
**/
|
||||
void client_sockaddr(int fd,
|
||||
struct sockaddr_storage *ss,
|
||||
socklen_t *ss_len)
|
||||
{
|
||||
memset(ss, 0, sizeof *ss);
|
||||
|
||||
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
|
||||
/* FIXME: Can we really not continue? */
|
||||
rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
if (get_sockaddr_family(ss) == AF_INET6 &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
|
||||
/* OK, so ss is in the IPv6 family, but it is really
|
||||
* an IPv4 address: something like
|
||||
* "::ffff:10.130.1.2". If we use it as-is, then the
|
||||
* reverse lookup might fail or perhaps something else
|
||||
* bad might happen. So instead we convert it to an
|
||||
* equivalent address in the IPv4 address family. */
|
||||
struct sockaddr_in6 sin6;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
memcpy(&sin6, ss, sizeof sin6);
|
||||
sin = (struct sockaddr_in *)ss;
|
||||
memset(sin, 0, sizeof *sin);
|
||||
sin->sin_family = AF_INET;
|
||||
*ss_len = sizeof (struct sockaddr_in);
|
||||
#ifdef HAVE_SOCKADDR_IN_LEN
|
||||
sin->sin_len = *ss_len;
|
||||
#endif
|
||||
sin->sin_port = sin6.sin6_port;
|
||||
|
||||
/* There is a macro to extract the mapped part
|
||||
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
|
||||
* to be present in the Linux headers. */
|
||||
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
|
||||
sizeof sin->sin_addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up a name from @p ss into @p name_buf.
|
||||
*
|
||||
* @param fd file descriptor for client socket.
|
||||
**/
|
||||
int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
socklen_t ss_len,
|
||||
char *name_buf, size_t name_buf_size,
|
||||
char *port_buf, size_t port_buf_size)
|
||||
{
|
||||
int name_err;
|
||||
|
||||
/* reverse lookup */
|
||||
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
|
||||
name_buf, name_buf_size,
|
||||
port_buf, port_buf_size,
|
||||
NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (name_err != 0) {
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n",
|
||||
client_addr(fd), gai_strerror(name_err));
|
||||
return name_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compare an addrinfo from the resolver to a sockinfo.
|
||||
*
|
||||
* Like strcmp, returns 0 for identical.
|
||||
**/
|
||||
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
const struct sockaddr_storage *ss)
|
||||
{
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
const char fn[] = "compare_addrinfo_sockaddr";
|
||||
|
||||
if (ai->ai_family != ss_family) {
|
||||
rprintf(FLOG, "%s: response family %d != %d\n",
|
||||
fn, ai->ai_family, ss_family);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The comparison method depends on the particular AF. */
|
||||
if (ss_family == AF_INET) {
|
||||
const struct sockaddr_in *sin1, *sin2;
|
||||
|
||||
sin1 = (const struct sockaddr_in *) ss;
|
||||
sin2 = (const struct sockaddr_in *) ai->ai_addr;
|
||||
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
|
||||
sizeof sin1->sin_addr);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
if (ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *sin1, *sin2;
|
||||
|
||||
sin1 = (const struct sockaddr_in6 *) ss;
|
||||
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
|
||||
|
||||
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
|
||||
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
|
||||
fn, (int)ai->ai_addrlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
|
||||
sizeof sin1->sin6_addr))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
if (sin1->sin6_scope_id != sin2->sin6_scope_id)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
/* don't know */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do a forward lookup on @p name_buf and make sure it corresponds to
|
||||
* @p ss -- otherwise we may be being spoofed. If we suspect we are,
|
||||
* then we don't abort the connection but just emit a warning, and
|
||||
* change @p name_buf to be "UNKNOWN".
|
||||
*
|
||||
* We don't do anything with the service when checking the name,
|
||||
* because it doesn't seem that it could be spoofed in any way, and
|
||||
* getaddrinfo on random service names seems to cause problems on AIX.
|
||||
**/
|
||||
int check_name(int fd,
|
||||
const struct sockaddr_storage *ss,
|
||||
char *name_buf, size_t name_buf_size)
|
||||
{
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int error;
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = ss_family;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
error = getaddrinfo(name_buf, NULL, &hints, &res0);
|
||||
if (error) {
|
||||
rprintf(FLOG, "forward name lookup for %s failed: %s\n",
|
||||
name_buf, gai_strerror(error));
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Given all these results, we expect that one of them will be
|
||||
* the same as ss. The comparison is a bit complicated. */
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
if (!compare_addrinfo_sockaddr(res, ss))
|
||||
break; /* OK, identical */
|
||||
}
|
||||
|
||||
if (!res0) {
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FLOG, "no known address for \"%s\": "
|
||||
"spoofed address?\n", name_buf);
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
} else if (res == NULL) {
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FLOG, "%s is not a known address for \"%s\": "
|
||||
"spoofed address?\n", client_addr(fd), name_buf);
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
return 0;
|
||||
}
|
1204
rsync/clientserver.c
Normal file
1204
rsync/clientserver.c
Normal file
File diff suppressed because it is too large
Load Diff
336
rsync/compat.c
Normal file
336
rsync/compat.c
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Compatibility routines for older rsync protocol versions.
|
||||
*
|
||||
* Copyright (C) Andrew Tridgell 1996
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
int compat_flags = 0;
|
||||
int use_safe_inc_flist = 0;
|
||||
int want_xattr_optim = 0;
|
||||
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int local_server;
|
||||
extern int inplace;
|
||||
extern int recurse;
|
||||
extern int use_qsort;
|
||||
extern int allow_inc_recurse;
|
||||
extern int preallocate_files;
|
||||
extern int append_mode;
|
||||
extern int fuzzy_basis;
|
||||
extern int read_batch;
|
||||
extern int delay_updates;
|
||||
extern int checksum_seed;
|
||||
extern int basis_dir_cnt;
|
||||
extern int prune_empty_dirs;
|
||||
extern int protocol_version;
|
||||
extern int protect_args;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int need_messages_from_generator;
|
||||
extern int delete_mode, delete_before, delete_during, delete_after;
|
||||
extern char *shell_cmd;
|
||||
extern char *partial_dir;
|
||||
extern char *dest_option;
|
||||
extern char *files_from;
|
||||
extern char *filesfrom_host;
|
||||
extern filter_rule_list filter_list;
|
||||
extern int need_unsorted_flist;
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
|
||||
/* These index values are for the file-list's extra-attribute array. */
|
||||
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
|
||||
|
||||
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
|
||||
int sender_symlink_iconv = 0; /* sender should convert symlink content */
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
int filesfrom_convert = 0;
|
||||
#endif
|
||||
|
||||
#define CF_INC_RECURSE (1<<0)
|
||||
#define CF_SYMLINK_TIMES (1<<1)
|
||||
#define CF_SYMLINK_ICONV (1<<2)
|
||||
#define CF_SAFE_FLIST (1<<3)
|
||||
#define CF_AVOID_XATTR_OPTIM (1<<4)
|
||||
|
||||
static const char *client_info;
|
||||
|
||||
/* The server makes sure that if either side only supports a pre-release
|
||||
* version of a protocol, that both sides must speak a compatible version
|
||||
* of that protocol for it to be advertised as available. */
|
||||
static void check_sub_protocol(void)
|
||||
{
|
||||
char *dot;
|
||||
int their_protocol, their_sub;
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
int our_sub = 0;
|
||||
#endif
|
||||
|
||||
/* client_info starts with VER.SUB string if client is a pre-release. */
|
||||
if (!(their_protocol = atoi(client_info))
|
||||
|| !(dot = strchr(client_info, '.'))
|
||||
|| !(their_sub = atoi(dot+1))) {
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
if (our_sub)
|
||||
protocol_version--;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (their_protocol < protocol_version) {
|
||||
if (their_sub)
|
||||
protocol_version = their_protocol - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (their_protocol > protocol_version)
|
||||
their_sub = 0; /* 0 == final version of older protocol */
|
||||
if (their_sub != our_sub)
|
||||
protocol_version--;
|
||||
}
|
||||
|
||||
void set_allow_inc_recurse(void)
|
||||
{
|
||||
client_info = shell_cmd ? shell_cmd : "";
|
||||
|
||||
if (!recurse || use_qsort)
|
||||
allow_inc_recurse = 0;
|
||||
else if (!am_sender
|
||||
&& (delete_before || delete_after
|
||||
|| delay_updates || prune_empty_dirs))
|
||||
allow_inc_recurse = 0;
|
||||
else if (am_server && !local_server
|
||||
&& (strchr(client_info, 'i') == NULL))
|
||||
allow_inc_recurse = 0;
|
||||
}
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
if (am_sender)
|
||||
file_extra_cnt += PTR_EXTRA_CNT;
|
||||
else
|
||||
file_extra_cnt++;
|
||||
if (preserve_uid)
|
||||
uid_ndx = ++file_extra_cnt;
|
||||
if (preserve_gid)
|
||||
gid_ndx = ++file_extra_cnt;
|
||||
if (preserve_acls && !am_sender)
|
||||
acls_ndx = ++file_extra_cnt;
|
||||
if (preserve_xattrs)
|
||||
xattrs_ndx = ++file_extra_cnt;
|
||||
|
||||
if (am_server)
|
||||
set_allow_inc_recurse();
|
||||
|
||||
if (remote_protocol == 0) {
|
||||
if (am_server && !local_server)
|
||||
check_sub_protocol();
|
||||
if (!read_batch)
|
||||
write_int(f_out, protocol_version);
|
||||
remote_protocol = read_int(f_in);
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
}
|
||||
if (read_batch && remote_protocol > protocol_version) {
|
||||
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
|
||||
remote_protocol, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(PROTO, 1)) {
|
||||
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
|
||||
am_server? "Server" : "Client", remote_protocol, protocol_version);
|
||||
}
|
||||
if (remote_protocol < MIN_PROTOCOL_VERSION
|
||||
|| remote_protocol > MAX_PROTOCOL_VERSION) {
|
||||
rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n");
|
||||
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (remote_protocol < OLD_PROTOCOL_VERSION) {
|
||||
rprintf(FINFO,"%s is very old version of rsync, upgrade recommended.\n",
|
||||
am_server? "Client" : "Server");
|
||||
}
|
||||
if (protocol_version < MIN_PROTOCOL_VERSION) {
|
||||
rprintf(FERROR, "--protocol must be at least %d on the %s.\n",
|
||||
MIN_PROTOCOL_VERSION, am_server? "Server" : "Client");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (protocol_version > PROTOCOL_VERSION) {
|
||||
rprintf(FERROR, "--protocol must be no more than %d on the %s.\n",
|
||||
PROTOCOL_VERSION, am_server? "Server" : "Client");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (read_batch)
|
||||
check_batch_flags();
|
||||
|
||||
#ifndef SUPPORT_PREALLOCATION
|
||||
if (preallocate_files && !am_sender) {
|
||||
rprintf(FERROR, "preallocation is not supported on this %s\n",
|
||||
am_server ? "Server" : "Client");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (protocol_version < 30) {
|
||||
if (append_mode == 1)
|
||||
append_mode = 2;
|
||||
if (preserve_acls && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--acls requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (preserve_xattrs && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--xattrs requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_mode && !(delete_before+delete_during+delete_after)) {
|
||||
if (protocol_version < 30)
|
||||
delete_before = 1;
|
||||
else
|
||||
delete_during = 1;
|
||||
}
|
||||
|
||||
if (protocol_version < 29) {
|
||||
if (fuzzy_basis) {
|
||||
rprintf(FERROR,
|
||||
"--fuzzy requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (basis_dir_cnt && inplace) {
|
||||
rprintf(FERROR,
|
||||
"%s with --inplace requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (basis_dir_cnt > 1) {
|
||||
rprintf(FERROR,
|
||||
"Using more than one %s option requires protocol"
|
||||
" 29 or higher (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (prune_empty_dirs) {
|
||||
rprintf(FERROR,
|
||||
"--prune-empty-dirs requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
} else if (protocol_version >= 30) {
|
||||
if (am_server) {
|
||||
compat_flags = allow_inc_recurse ? CF_INC_RECURSE : 0;
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
compat_flags |= CF_SYMLINK_TIMES;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
compat_flags |= CF_SYMLINK_ICONV;
|
||||
#endif
|
||||
if (local_server || strchr(client_info, 'f') != NULL)
|
||||
compat_flags |= CF_SAFE_FLIST;
|
||||
if (local_server || strchr(client_info, 'x') != NULL)
|
||||
compat_flags |= CF_AVOID_XATTR_OPTIM;
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
compat_flags = read_byte(f_in);
|
||||
/* The inc_recurse var MUST be set to 0 or 1. */
|
||||
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0;
|
||||
want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
|
||||
if (am_sender) {
|
||||
receiver_symlink_times = am_server
|
||||
? strchr(client_info, 'L') != NULL
|
||||
: !!(compat_flags & CF_SYMLINK_TIMES);
|
||||
}
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
else
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
sender_symlink_iconv = iconv_opt && (am_server
|
||||
? local_server || strchr(client_info, 's') != NULL
|
||||
: !!(compat_flags & CF_SYMLINK_ICONV));
|
||||
#endif
|
||||
if (inc_recurse && !allow_inc_recurse) {
|
||||
/* This should only be able to happen in a batch. */
|
||||
fprintf(stderr,
|
||||
"Incompatible options specified for inc-recursive %s.\n",
|
||||
read_batch ? "batch file" : "connection");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31;
|
||||
need_messages_from_generator = 1;
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
} else if (!am_sender) {
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (need_unsorted_flist && (!am_sender || inc_recurse))
|
||||
unsort_ndx = ++file_extra_cnt;
|
||||
|
||||
if (partial_dir && *partial_dir != '/' && (!am_server || local_server)) {
|
||||
int rflags = FILTRULE_NO_PREFIXES | FILTRULE_DIRECTORY;
|
||||
if (!am_sender || protocol_version >= 30)
|
||||
rflags |= FILTRULE_PERISHABLE;
|
||||
parse_filter_str(&filter_list, partial_dir, rule_template(rflags), 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (protect_args && files_from) {
|
||||
if (am_sender)
|
||||
filesfrom_convert = filesfrom_host && ic_send != (iconv_t)-1;
|
||||
else
|
||||
filesfrom_convert = !filesfrom_host && ic_recv != (iconv_t)-1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (am_server) {
|
||||
if (!checksum_seed)
|
||||
checksum_seed = time(NULL);
|
||||
write_int(f_out, checksum_seed);
|
||||
} else {
|
||||
checksum_seed = read_int(f_in);
|
||||
}
|
||||
}
|
769
rsync/config.h.in
Normal file
769
rsync/config.h.in
Normal file
@ -0,0 +1,769 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define to 1 if link() can hard-link special files. */
|
||||
#undef CAN_HARDLINK_SPECIAL
|
||||
|
||||
/* Define to 1 if link() can hard-link symlinks. */
|
||||
#undef CAN_HARDLINK_SYMLINK
|
||||
|
||||
/* Define to 1 if chown modifies symlinks. */
|
||||
#undef CHOWN_MODIFIES_SYMLINK
|
||||
|
||||
/* Undefine if you do not want locale features. By default this is defined. */
|
||||
#undef CONFIG_LOCALE
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define to 1 if using external zlib */
|
||||
#undef EXTERNAL_ZLIB
|
||||
|
||||
/* Used to make "checker" understand that FD_ZERO() clears memory. */
|
||||
#undef FORCE_FD_ZERO_MEMSET
|
||||
|
||||
/* Define to the type of elements in the array set by `getgroups'. Usually
|
||||
this is either `int' or `gid_t'. */
|
||||
#undef GETGROUPS_T
|
||||
|
||||
/* Define to 1 if the `getpgrp' function requires zero arguments. */
|
||||
#undef GETPGRP_VOID
|
||||
|
||||
/* Define to 1 if you have the `aclsort' function. */
|
||||
#undef HAVE_ACLSORT
|
||||
|
||||
/* true if you have acl_get_perm_np */
|
||||
#undef HAVE_ACL_GET_PERM_NP
|
||||
|
||||
/* Define to 1 if you have the <acl/libacl.h> header file. */
|
||||
#undef HAVE_ACL_LIBACL_H
|
||||
|
||||
/* true if you have AIX ACLs */
|
||||
#undef HAVE_AIX_ACLS
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||
#undef HAVE_ARPA_NAMESER_H
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Define to 1 if you have the `attropen' function. */
|
||||
#undef HAVE_ATTROPEN
|
||||
|
||||
/* Define to 1 if you have the <attr/xattr.h> header file. */
|
||||
#undef HAVE_ATTR_XATTR_H
|
||||
|
||||
/* Define to 1 if readdir() is broken */
|
||||
#undef HAVE_BROKEN_READDIR
|
||||
|
||||
/* Define to 1 if vsprintf has a C99-compatible return value */
|
||||
#undef HAVE_C99_VSNPRINTF
|
||||
|
||||
/* Define to 1 if you have the `chmod' function. */
|
||||
#undef HAVE_CHMOD
|
||||
|
||||
/* Define to 1 if you have the `chown' function. */
|
||||
#undef HAVE_CHOWN
|
||||
|
||||
/* Define to 1 if you have the <compat.h> header file. */
|
||||
#undef HAVE_COMPAT_H
|
||||
|
||||
/* Define to 1 if you have the "connect" function */
|
||||
#undef HAVE_CONNECT
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define if posix_fallocate is efficient (Cygwin) */
|
||||
#undef HAVE_EFFICIENT_POSIX_FALLOCATE
|
||||
|
||||
/* Define to 1 if errno is declared in errno.h */
|
||||
#undef HAVE_ERRNO_DECL
|
||||
|
||||
/* Define to 1 if you have the `extattr_get_link' function. */
|
||||
#undef HAVE_EXTATTR_GET_LINK
|
||||
|
||||
/* Define to 1 if you have the fallocate function and it compiles and links
|
||||
without error */
|
||||
#undef HAVE_FALLOCATE
|
||||
|
||||
/* Define to 1 if you have the `fchmod' function. */
|
||||
#undef HAVE_FCHMOD
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <float.h> header file. */
|
||||
#undef HAVE_FLOAT_H
|
||||
|
||||
/* True if you have FreeBSD xattrs */
|
||||
#undef HAVE_FREEBSD_XATTRS
|
||||
|
||||
/* Define to 1 if you have the `fstat' function. */
|
||||
#undef HAVE_FSTAT
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#undef HAVE_FTRUNCATE
|
||||
|
||||
/* Define to 1 if you have the "getaddrinfo" function and required types. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define to 1 if you have the `getcwd' function. */
|
||||
#undef HAVE_GETCWD
|
||||
|
||||
/* Define to 1 if you have the `getegid' function. */
|
||||
#undef HAVE_GETEGID
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
/* Define to 1 if you have the `getgrouplist' function. */
|
||||
#undef HAVE_GETGROUPLIST
|
||||
|
||||
/* Define to 1 if you have the `getgroups' function. */
|
||||
#undef HAVE_GETGROUPS
|
||||
|
||||
/* Define to 1 if you have the `getpass' function. */
|
||||
#undef HAVE_GETPASS
|
||||
|
||||
/* Define to 1 if you have the `getpgrp' function. */
|
||||
#undef HAVE_GETPGRP
|
||||
|
||||
/* Define to 1 if gettimeofday() takes a time-zone arg */
|
||||
#undef HAVE_GETTIMEOFDAY_TZ
|
||||
|
||||
/* Define to 1 if you have the `getxattr' function. */
|
||||
#undef HAVE_GETXATTR
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#undef HAVE_GRP_H
|
||||
|
||||
/* true if you have HPUX ACLs */
|
||||
#undef HAVE_HPUX_ACLS
|
||||
|
||||
/* Define to 1 if you have the <iconv.h> header file. */
|
||||
#undef HAVE_ICONV_H
|
||||
|
||||
/* Define to 1 if you have the `iconv_open' function. */
|
||||
#undef HAVE_ICONV_OPEN
|
||||
|
||||
/* Define to 1 if the system has the type `id_t'. */
|
||||
#undef HAVE_ID_T
|
||||
|
||||
/* Define to 1 if you have the `inet_ntop' function. */
|
||||
#undef HAVE_INET_NTOP
|
||||
|
||||
/* Define to 1 if you have the `inet_pton' function. */
|
||||
#undef HAVE_INET_PTON
|
||||
|
||||
/* Define to 1 if you have the `initgroups' function. */
|
||||
#undef HAVE_INITGROUPS
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* true if you have IRIX ACLs */
|
||||
#undef HAVE_IRIX_ACLS
|
||||
|
||||
/* Define to 1 if you have the <langinfo.h> header file. */
|
||||
#undef HAVE_LANGINFO_H
|
||||
|
||||
/* Define to 1 if you have the `lchmod' function. */
|
||||
#undef HAVE_LCHMOD
|
||||
|
||||
/* Define to 1 if you have the `lchown' function. */
|
||||
#undef HAVE_LCHOWN
|
||||
|
||||
/* Define to 1 if you have the `acl' library (-lacl). */
|
||||
#undef HAVE_LIBACL
|
||||
|
||||
/* Define to 1 if you have the `attr' library (-lattr). */
|
||||
#undef HAVE_LIBATTR
|
||||
|
||||
/* Define to 1 if you have the <libcharset.h> header file. */
|
||||
#undef HAVE_LIBCHARSET_H
|
||||
|
||||
/* Define to 1 if you have the `inet' library (-linet). */
|
||||
#undef HAVE_LIBINET
|
||||
|
||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define to 1 if you have the `nsl_s' library (-lnsl_s). */
|
||||
#undef HAVE_LIBNSL_S
|
||||
|
||||
/* Define to 1 if you have the `popt' library (-lpopt). */
|
||||
#undef HAVE_LIBPOPT
|
||||
|
||||
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
||||
#undef HAVE_LIBRESOLV
|
||||
|
||||
/* Define to 1 if you have the `sec' library (-lsec). */
|
||||
#undef HAVE_LIBSEC
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#undef HAVE_LIBZ
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the `link' function. */
|
||||
#undef HAVE_LINK
|
||||
|
||||
/* Define to 1 if you have the <linux/falloc.h> header file. */
|
||||
#undef HAVE_LINUX_FALLOC_H
|
||||
|
||||
/* True if you have Linux xattrs */
|
||||
#undef HAVE_LINUX_XATTRS
|
||||
|
||||
/* Define to 1 if you have the `locale_charset' function. */
|
||||
#undef HAVE_LOCALE_CHARSET
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define to 1 if the type `long double' works and has more range or precision
|
||||
than `double'. */
|
||||
#undef HAVE_LONG_DOUBLE
|
||||
|
||||
/* Define to 1 if the type `long double' works and has more range or precision
|
||||
than `double'. */
|
||||
#undef HAVE_LONG_DOUBLE_WIDER
|
||||
|
||||
/* Define to 1 if you have the `lseek64' function. */
|
||||
#undef HAVE_LSEEK64
|
||||
|
||||
/* Define to 1 if you have the `lutimes' function. */
|
||||
#undef HAVE_LUTIMES
|
||||
|
||||
/* Define to 1 if you have the `mallinfo' function. */
|
||||
#undef HAVE_MALLINFO
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the <mcheck.h> header file. */
|
||||
#undef HAVE_MCHECK_H
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mkfifo' function. */
|
||||
#undef HAVE_MKFIFO
|
||||
|
||||
/* Define to 1 if you have the `mknod' function. */
|
||||
#undef HAVE_MKNOD
|
||||
|
||||
/* Define to 1 if you have the `mkstemp64' function. */
|
||||
#undef HAVE_MKSTEMP64
|
||||
|
||||
/* Define to 1 if the system has the type `mode_t'. */
|
||||
#undef HAVE_MODE_T
|
||||
|
||||
/* Define to 1 if you have the `mtrace' function. */
|
||||
#undef HAVE_MTRACE
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in_systm.h> header file. */
|
||||
#undef HAVE_NETINET_IN_SYSTM_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/ip.h> header file. */
|
||||
#undef HAVE_NETINET_IP_H
|
||||
|
||||
/* Define to 1 if you have the `nl_langinfo' function. */
|
||||
#undef HAVE_NL_LANGINFO
|
||||
|
||||
/* Define to 1 if the system has the type `off_t'. */
|
||||
#undef HAVE_OFF_T
|
||||
|
||||
/* Define to 1 if you have the `open64' function. */
|
||||
#undef HAVE_OPEN64
|
||||
|
||||
/* true if you have Mac OS X ACLs */
|
||||
#undef HAVE_OSX_ACLS
|
||||
|
||||
/* True if you have Mac OS X xattrs */
|
||||
#undef HAVE_OSX_XATTRS
|
||||
|
||||
/* Define to 1 if the system has the type `pid_t'. */
|
||||
#undef HAVE_PID_T
|
||||
|
||||
/* Define to 1 if you have the <popt.h> header file. */
|
||||
#undef HAVE_POPT_H
|
||||
|
||||
/* Define to 1 if you have the <popt/popt.h> header file. */
|
||||
#undef HAVE_POPT_POPT_H
|
||||
|
||||
/* true if you have posix ACLs */
|
||||
#undef HAVE_POSIX_ACLS
|
||||
|
||||
/* Define to 1 if you have the `posix_fallocate' function. */
|
||||
#undef HAVE_POSIX_FALLOCATE
|
||||
|
||||
/* Define to 1 if you have the `putenv' function. */
|
||||
#undef HAVE_PUTENV
|
||||
|
||||
/* Define to 1 if you have the `readlink' function. */
|
||||
#undef HAVE_READLINK
|
||||
|
||||
/* Define to 1 if remote shell is remsh, not rsh */
|
||||
#undef HAVE_REMSH
|
||||
|
||||
/* Define to 1 if mkstemp() is available and works right */
|
||||
#undef HAVE_SECURE_MKSTEMP
|
||||
|
||||
/* Define to 1 if you have the `setattrlist' function. */
|
||||
#undef HAVE_SETATTRLIST
|
||||
|
||||
/* Define to 1 if you have the `seteuid' function. */
|
||||
#undef HAVE_SETEUID
|
||||
|
||||
/* Define to 1 if you have the `setgroups' function. */
|
||||
#undef HAVE_SETGROUPS
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
/* Define to 1 if you have the `setmode' function. */
|
||||
#undef HAVE_SETMODE
|
||||
|
||||
/* Define to 1 if you have the `setsid' function. */
|
||||
#undef HAVE_SETSID
|
||||
|
||||
/* Define to 1 if you have the `setvbuf' function. */
|
||||
#undef HAVE_SETVBUF
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define to 1 if you have the `sigprocmask' function. */
|
||||
#undef HAVE_SIGPROCMASK
|
||||
|
||||
/* Define to 1 if the system has the type `size_t'. */
|
||||
#undef HAVE_SIZE_T
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Do we have sockaddr_in6.sin6_scope_id? */
|
||||
#undef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
|
||||
/* Do we have sockaddr_in.sin_len? */
|
||||
#undef HAVE_SOCKADDR_IN_LEN
|
||||
|
||||
/* Do we have sockaddr.sa_len? */
|
||||
#undef HAVE_SOCKADDR_LEN
|
||||
|
||||
/* Do we have sockaddr_un.sun_len? */
|
||||
#undef HAVE_SOCKADDR_UN_LEN
|
||||
|
||||
/* Define to 1 if you have the "socketpair" function */
|
||||
#undef HAVE_SOCKETPAIR
|
||||
|
||||
/* true if you have solaris ACLs */
|
||||
#undef HAVE_SOLARIS_ACLS
|
||||
|
||||
/* True if you have Solaris xattrs */
|
||||
#undef HAVE_SOLARIS_XATTRS
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the `strftime' function. */
|
||||
#undef HAVE_STRFTIME
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strlcat' function. */
|
||||
#undef HAVE_STRLCAT
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
#undef HAVE_STRLCPY
|
||||
|
||||
/* Define to 1 if you have the `strpbrk' function. */
|
||||
#undef HAVE_STRPBRK
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#undef HAVE_STRTOL
|
||||
|
||||
/* Define to 1 if the system has the type `struct addrinfo'. */
|
||||
#undef HAVE_STRUCT_ADDRINFO
|
||||
|
||||
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
|
||||
/* Define to 1 if the system has the type `struct stat64'. */
|
||||
#undef HAVE_STRUCT_STAT64
|
||||
|
||||
/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
|
||||
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||
|
||||
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_RDEV
|
||||
|
||||
/* Define to 1 if you have the "struct utimbuf" type */
|
||||
#undef HAVE_STRUCT_UTIMBUF
|
||||
|
||||
/* Define to 1 if you have the <sys/acl.h> header file. */
|
||||
#undef HAVE_SYS_ACL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/attr.h> header file. */
|
||||
#undef HAVE_SYS_ATTR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/extattr.h> header file. */
|
||||
#undef HAVE_SYS_EXTATTR_H
|
||||
|
||||
/* Define to 1 if you have the SYS_fallocate syscall number */
|
||||
#undef HAVE_SYS_FALLOCATE
|
||||
|
||||
/* Define to 1 if you have the <sys/fcntl.h> header file. */
|
||||
#undef HAVE_SYS_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/filio.h> header file. */
|
||||
#undef HAVE_SYS_FILIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mode.h> header file. */
|
||||
#undef HAVE_SYS_MODE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/unistd.h> header file. */
|
||||
#undef HAVE_SYS_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <sys/un.h> header file. */
|
||||
#undef HAVE_SYS_UN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/xattr.h> header file. */
|
||||
#undef HAVE_SYS_XATTR_H
|
||||
|
||||
/* Define to 1 if you have the `tcgetpgrp' function. */
|
||||
#undef HAVE_TCGETPGRP
|
||||
|
||||
/* true if you have Tru64 ACLs */
|
||||
#undef HAVE_TRU64_ACLS
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* true if you have UnixWare ACLs */
|
||||
#undef HAVE_UNIXWARE_ACLS
|
||||
|
||||
/* Define to 1 if you have the `utime' function. */
|
||||
#undef HAVE_UTIME
|
||||
|
||||
/* Define to 1 if you have the `utimensat' function. */
|
||||
#undef HAVE_UTIMENSAT
|
||||
|
||||
/* Define to 1 if you have the `utimes' function. */
|
||||
#undef HAVE_UTIMES
|
||||
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#undef HAVE_UTIME_H
|
||||
|
||||
/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
|
||||
#undef HAVE_UTIME_NULL
|
||||
|
||||
/* Define to 1 if you have the `vasprintf' function. */
|
||||
#undef HAVE_VASPRINTF
|
||||
|
||||
/* Define to 1 if you have the `va_copy' function. */
|
||||
#undef HAVE_VA_COPY
|
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */
|
||||
#undef HAVE_VSNPRINTF
|
||||
|
||||
/* Define to 1 if you have the `wait4' function. */
|
||||
#undef HAVE_WAIT4
|
||||
|
||||
/* Define to 1 if you have the `waitpid' function. */
|
||||
#undef HAVE_WAITPID
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#undef HAVE_ZLIB_H
|
||||
|
||||
/* Define to 1 if you have the `_acl' function. */
|
||||
#undef HAVE__ACL
|
||||
|
||||
/* Define to 1 if you have the `_facl' function. */
|
||||
#undef HAVE__FACL
|
||||
|
||||
/* Define to 1 if you have the `__acl' function. */
|
||||
#undef HAVE___ACL
|
||||
|
||||
/* Define to 1 if you have the `__facl' function. */
|
||||
#undef HAVE___FACL
|
||||
|
||||
/* Define to 1 if you have the `__va_copy' function. */
|
||||
#undef HAVE___VA_COPY
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
#undef ICONV_CONST
|
||||
|
||||
/* Define if you want the --iconv option. Specifing a value will set the
|
||||
default iconv setting (a NULL means no --iconv processing by default). */
|
||||
#undef ICONV_OPTION
|
||||
|
||||
/* true if you have IPv6 */
|
||||
#undef INET6
|
||||
|
||||
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
|
||||
*/
|
||||
#undef MAJOR_IN_MKDEV
|
||||
|
||||
/* Define to 1 if `major', `minor', and `makedev' are declared in
|
||||
<sysmacros.h>. */
|
||||
#undef MAJOR_IN_SYSMACROS
|
||||
|
||||
/* Define to 1 if makedev() takes 3 args */
|
||||
#undef MAKEDEV_TAKES_3_ARGS
|
||||
|
||||
/* Define to 1 if mknod() can create FIFOs. */
|
||||
#undef MKNOD_CREATES_FIFOS
|
||||
|
||||
/* Define to 1 if mknod() can create sockets. */
|
||||
#undef MKNOD_CREATES_SOCKETS
|
||||
|
||||
/* unprivileged group for unprivileged user */
|
||||
#undef NOBODY_GROUP
|
||||
|
||||
/* unprivileged user--e.g. nobody */
|
||||
#undef NOBODY_USER
|
||||
|
||||
/* True if device files do not support xattrs */
|
||||
#undef NO_DEVICE_XATTRS
|
||||
|
||||
/* True if special files do not support xattrs */
|
||||
#undef NO_SPECIAL_XATTRS
|
||||
|
||||
/* True if symlinks do not support user xattrs */
|
||||
#undef NO_SYMLINK_USER_XATTRS
|
||||
|
||||
/* True if symlinks do not support xattrs */
|
||||
#undef NO_SYMLINK_XATTRS
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* location of configuration file for rsync server */
|
||||
#undef RSYNCD_SYSCONF
|
||||
|
||||
/* location of rsync on remote machine */
|
||||
#undef RSYNC_PATH
|
||||
|
||||
/* default -e command */
|
||||
#undef RSYNC_RSH
|
||||
|
||||
/* Define to 1 if --protected-args should be the default */
|
||||
#undef RSYNC_USE_PROTECTED_ARGS
|
||||
|
||||
/* rsync release version */
|
||||
#undef RSYNC_VERSION
|
||||
|
||||
/* Define to 1 if sockets need to be shutdown */
|
||||
#undef SHUTDOWN_ALL_SOCKETS
|
||||
|
||||
/* Define to 1 if "signed char" is a valid type */
|
||||
#undef SIGNED_CHAR_OK
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#undef SIZEOF_INT
|
||||
|
||||
/* The size of `int16_t', as computed by sizeof. */
|
||||
#undef SIZEOF_INT16_T
|
||||
|
||||
/* The size of `int32_t', as computed by sizeof. */
|
||||
#undef SIZEOF_INT32_T
|
||||
|
||||
/* The size of `int64_t', as computed by sizeof. */
|
||||
#undef SIZEOF_INT64_T
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* The size of `long long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG_LONG
|
||||
|
||||
/* The size of `off64_t', as computed by sizeof. */
|
||||
#undef SIZEOF_OFF64_T
|
||||
|
||||
/* The size of `off_t', as computed by sizeof. */
|
||||
#undef SIZEOF_OFF_T
|
||||
|
||||
/* The size of `short', as computed by sizeof. */
|
||||
#undef SIZEOF_SHORT
|
||||
|
||||
/* The size of `time_t', as computed by sizeof. */
|
||||
#undef SIZEOF_TIME_T
|
||||
|
||||
/* The size of `uint16_t', as computed by sizeof. */
|
||||
#undef SIZEOF_UINT16_T
|
||||
|
||||
/* The size of `uint32_t', as computed by sizeof. */
|
||||
#undef SIZEOF_UINT32_T
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 to add support for ACLs */
|
||||
#undef SUPPORT_ACLS
|
||||
|
||||
/* Define to 1 to add support for extended attributes */
|
||||
#undef SUPPORT_XATTRS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Define to 1 if you want rsync to make use of iconv_open() */
|
||||
#undef USE_ICONV_OPEN
|
||||
|
||||
/* String to pass to iconv() for the UTF-8 charset. */
|
||||
#undef UTF8_CHARSET
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define _GNU_SOURCE so that we get all necessary prototypes */
|
||||
#undef _GNU_SOURCE
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* type to use in place of socklen_t if not defined */
|
||||
#undef socklen_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
46
rsync/connection.c
Normal file
46
rsync/connection.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Support the max connections option.
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
/* A simple routine to do connection counting. This returns 1 on success
|
||||
* and 0 on failure, with errno also being set if the open() failed (errno
|
||||
* will be 0 if the lock request failed). */
|
||||
int claim_connection(char *fname, int max_connections)
|
||||
{
|
||||
int fd, i;
|
||||
|
||||
if (max_connections == 0)
|
||||
return 1;
|
||||
|
||||
if ((fd = open(fname, O_RDWR|O_CREAT, 0600)) < 0)
|
||||
return 0;
|
||||
|
||||
/* Find a free spot. */
|
||||
for (i = 0; i < max_connections; i++) {
|
||||
if (lock_range(fd, i*4, 4))
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* A lock failure needs to return an errno of 0. */
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
88
rsync/csprotocol.txt
Normal file
88
rsync/csprotocol.txt
Normal file
@ -0,0 +1,88 @@
|
||||
This is kind of informal and may be wrong, but it helped me. It's
|
||||
basically a summary of clientserver.c and authenticate.c.
|
||||
|
||||
-- Martin Pool <mbp@samba.org>
|
||||
|
||||
|
||||
This is the protocol used for rsync --daemon; i.e. connections to port
|
||||
873 rather than invocations over a remote shell.
|
||||
|
||||
When the server accepts a connection, it prints a greeting
|
||||
|
||||
@RSYNCD: <version>.<subprotocol>
|
||||
|
||||
where <version> is the numeric version (see PROTOCOL_VERSION in rsync.h)
|
||||
'.' is a literal period, and <subprotocol> is the numeric subprotocol
|
||||
version (see SUBPROTOCOL_VERSION -- it will be 0 for final releases).
|
||||
Protocols prior to 30 only output <version> alone. The daemon expects
|
||||
to see a similar greeting back from the client. For protocols prior to
|
||||
30, an absent ".<subprotocol>" value is assumed to be 0. For protocol
|
||||
30, an absent value is a fatal error. The daemon then follows this line
|
||||
with a free-format text message-of-the-day (if any is defined).
|
||||
|
||||
The server is now in the connected state. The client can either send
|
||||
the command
|
||||
|
||||
#list
|
||||
|
||||
to get a listing of modules, or the name of a module. After this, the
|
||||
connection is now bound to a particular module. Access per host for
|
||||
this module is now checked, as is per-module connection limits.
|
||||
|
||||
If authentication is required to use this module, the server will say
|
||||
|
||||
@RSYNCD: AUTHREQD <challenge>
|
||||
|
||||
where <challenge> is a random string of base64 characters. The client
|
||||
must respond with
|
||||
|
||||
<user> <response>
|
||||
|
||||
where <user> is the username they claim to be, and <response> is the
|
||||
base64 form of the MD4 hash of challenge+password.
|
||||
|
||||
At this point the server applies all remaining constraints before
|
||||
handing control to the client, including switching uid/gid, setting up
|
||||
include and exclude lists, moving to the root of the module, and doing
|
||||
chroot.
|
||||
|
||||
If the login is acceptable, then the server will respond with
|
||||
|
||||
@RSYNCD: OK
|
||||
|
||||
The client now writes some rsync options, as if it were remotely
|
||||
executing the command. The server parses these arguments as if it had
|
||||
just been invoked with them, but they're added to the existing state.
|
||||
So if the client specifies a list of files to be included or excluded,
|
||||
they'll defer to existing limits specified in the server
|
||||
configuration.
|
||||
|
||||
At this point the client and server both switch to using a
|
||||
multiplexing layer across the socket. The main point of this is to
|
||||
allow the server to asynchronously pass errors back, while still
|
||||
allowing streamed and pipelined data.
|
||||
|
||||
Unfortunately, the multiplex protocol is not used at every stage. We
|
||||
start up in plain socket mode and then change over by calling
|
||||
io_start_buffering. Of course both the client and the server have to
|
||||
do this at the same point.
|
||||
|
||||
The server then talks to the client as normal across the socket,
|
||||
passing checksums, file lists and so on. For documentation of that,
|
||||
stay tuned (or write it yourself!).
|
||||
|
||||
|
||||
|
||||
------------
|
||||
Protocol version changes
|
||||
|
||||
30 (2007-10-04, 3.0.0pre1)
|
||||
|
||||
The use of a ".<subprotocol>" number was added to
|
||||
@RSYNCD: <version>.<subprotocol>
|
||||
|
||||
25 (2001-08-20, 2.4.7pre2)
|
||||
|
||||
Send an explicit "@RSYNC EXIT" command at the end of the
|
||||
module listing. We never intentionally end the transmission
|
||||
by just closing the socket anymore.
|
240
rsync/delete.c
Normal file
240
rsync/delete.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Deletion routines used in rsync.
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_root;
|
||||
extern int make_backups;
|
||||
extern int max_delete;
|
||||
extern char *backup_dir;
|
||||
extern char *backup_suffix;
|
||||
extern int backup_suffix_len;
|
||||
extern struct stats stats;
|
||||
|
||||
int ignore_perishable = 0;
|
||||
int non_perishable_cnt = 0;
|
||||
int skipped_deletes = 0;
|
||||
|
||||
static inline int is_backup_file(char *fn)
|
||||
{
|
||||
int k = strlen(fn) - backup_suffix_len;
|
||||
return k > 0 && strcmp(fn+k, backup_suffix) == 0;
|
||||
}
|
||||
|
||||
/* The directory is about to be deleted: if DEL_RECURSE is given, delete all
|
||||
* its contents, otherwise just checks for content. Returns DR_SUCCESS or
|
||||
* DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
|
||||
* buffer is used for recursion, but returned unchanged.)
|
||||
*/
|
||||
static enum delret delete_dir_contents(char *fname, uint16 flags)
|
||||
{
|
||||
struct file_list *dirlist;
|
||||
enum delret ret;
|
||||
unsigned remainder;
|
||||
void *save_filters;
|
||||
int j, dlen;
|
||||
char *p;
|
||||
|
||||
if (DEBUG_GTE(DEL, 3)) {
|
||||
rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
|
||||
fname, flags);
|
||||
}
|
||||
|
||||
dlen = strlen(fname);
|
||||
save_filters = push_local_filters(fname, dlen);
|
||||
|
||||
non_perishable_cnt = 0;
|
||||
dirlist = get_dirlist(fname, dlen, 0);
|
||||
ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;
|
||||
|
||||
if (!dirlist->used)
|
||||
goto done;
|
||||
|
||||
if (!(flags & DEL_RECURSE)) {
|
||||
ret = DR_NOT_EMPTY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
p = fname + dlen;
|
||||
if (dlen != 1 || *fname != '/')
|
||||
*p++ = '/';
|
||||
remainder = MAXPATHLEN - (p - fname);
|
||||
|
||||
/* We do our own recursion, so make delete_item() non-recursive. */
|
||||
flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
|
||||
| DEL_DIR_IS_EMPTY;
|
||||
|
||||
for (j = dirlist->used; j--; ) {
|
||||
struct file_struct *fp = dirlist->files[j];
|
||||
|
||||
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
|
||||
if (DEBUG_GTE(DEL, 1)) {
|
||||
rprintf(FINFO,
|
||||
"mount point, %s, pins parent directory\n",
|
||||
f_name(fp, NULL));
|
||||
}
|
||||
ret = DR_NOT_EMPTY;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlcpy(p, fp->basename, remainder);
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
|
||||
do_chmod(fname, fp->mode | S_IWUSR);
|
||||
/* Save stack by recursing to ourself directly. */
|
||||
if (S_ISDIR(fp->mode)) {
|
||||
if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
|
||||
ret = DR_NOT_EMPTY;
|
||||
}
|
||||
if (delete_item(fname, fp->mode, flags) != DR_SUCCESS)
|
||||
ret = DR_NOT_EMPTY;
|
||||
}
|
||||
|
||||
fname[dlen] = '\0';
|
||||
|
||||
done:
|
||||
flist_free(dirlist);
|
||||
pop_local_filters(save_filters);
|
||||
|
||||
if (ret == DR_NOT_EMPTY) {
|
||||
rprintf(FINFO, "cannot delete non-empty directory: %s\n",
|
||||
fname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
|
||||
* delete recursively.
|
||||
*
|
||||
* Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
|
||||
* a directory! (The buffer is used for recursion, but returned unchanged.)
|
||||
*/
|
||||
enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
|
||||
{
|
||||
enum delret ret;
|
||||
char *what;
|
||||
int ok;
|
||||
|
||||
if (DEBUG_GTE(DEL, 2)) {
|
||||
rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
|
||||
fbuf, (int)mode, (int)flags);
|
||||
}
|
||||
|
||||
if (flags & DEL_NO_UID_WRITE)
|
||||
do_chmod(fbuf, mode | S_IWUSR);
|
||||
|
||||
if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
|
||||
/* This only happens on the first call to delete_item() since
|
||||
* delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */
|
||||
ignore_perishable = 1;
|
||||
/* If DEL_RECURSE is not set, this just reports emptiness. */
|
||||
ret = delete_dir_contents(fbuf, flags);
|
||||
ignore_perishable = 0;
|
||||
if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT)
|
||||
goto check_ret;
|
||||
/* OK: try to delete the directory. */
|
||||
}
|
||||
|
||||
if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) {
|
||||
skipped_deletes++;
|
||||
return DR_AT_LIMIT;
|
||||
}
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
what = "rmdir";
|
||||
ok = do_rmdir(fbuf) == 0;
|
||||
} else {
|
||||
if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir || !is_backup_file(fbuf))) {
|
||||
what = "make_backup";
|
||||
ok = make_backup(fbuf, True);
|
||||
if (ok == 2) {
|
||||
what = "unlink";
|
||||
ok = robust_unlink(fbuf) == 0;
|
||||
}
|
||||
} else {
|
||||
what = "unlink";
|
||||
ok = robust_unlink(fbuf) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (!(flags & DEL_MAKE_ROOM)) {
|
||||
log_delete(fbuf, mode);
|
||||
stats.deleted_files++;
|
||||
if (S_ISREG(mode)) {
|
||||
/* Nothing more to count */
|
||||
} else if (S_ISDIR(mode))
|
||||
stats.deleted_dirs++;
|
||||
#ifdef SUPPORT_LINKS
|
||||
else if (S_ISLNK(mode))
|
||||
stats.deleted_symlinks++;
|
||||
#endif
|
||||
else if (IS_DEVICE(mode))
|
||||
stats.deleted_symlinks++;
|
||||
else
|
||||
stats.deleted_specials++;
|
||||
}
|
||||
ret = DR_SUCCESS;
|
||||
} else {
|
||||
if (S_ISDIR(mode) && errno == ENOTEMPTY) {
|
||||
rprintf(FINFO, "cannot delete non-empty directory: %s\n",
|
||||
fbuf);
|
||||
ret = DR_NOT_EMPTY;
|
||||
} else if (errno != ENOENT) {
|
||||
rsyserr(FERROR_XFER, errno, "delete_file: %s(%s) failed",
|
||||
what, fbuf);
|
||||
ret = DR_FAILURE;
|
||||
} else
|
||||
ret = DR_SUCCESS;
|
||||
}
|
||||
|
||||
check_ret:
|
||||
if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) {
|
||||
const char *desc;
|
||||
switch (flags & DEL_MAKE_ROOM) {
|
||||
case DEL_FOR_FILE: desc = "regular file"; break;
|
||||
case DEL_FOR_DIR: desc = "directory"; break;
|
||||
case DEL_FOR_SYMLINK: desc = "symlink"; break;
|
||||
case DEL_FOR_DEVICE: desc = "device file"; break;
|
||||
case DEL_FOR_SPECIAL: desc = "special file"; break;
|
||||
default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
|
||||
}
|
||||
rprintf(FERROR_XFER, "could not make way for %s %s: %s\n",
|
||||
flags & DEL_FOR_BACKUP ? "backup" : "new",
|
||||
desc, fbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 get_del_for_flag(uint16 mode)
|
||||
{
|
||||
if (S_ISREG(mode))
|
||||
return DEL_FOR_FILE;
|
||||
if (S_ISDIR(mode))
|
||||
return DEL_FOR_DIR;
|
||||
if (S_ISLNK(mode))
|
||||
return DEL_FOR_SYMLINK;
|
||||
if (IS_DEVICE(mode))
|
||||
return DEL_FOR_DEVICE;
|
||||
if (IS_SPECIAL(mode))
|
||||
return DEL_FOR_SPECIAL;
|
||||
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
|
||||
}
|
20
rsync/doc/README-SGML
Normal file
20
rsync/doc/README-SGML
Normal file
@ -0,0 +1,20 @@
|
||||
Handling the rsync SGML documentation
|
||||
|
||||
rsync documentation is now primarily in Docbook format. Docbook is an
|
||||
SGML/XML documentation format that is becoming standard on free
|
||||
operating systems. It's also used for Samba documentation.
|
||||
|
||||
The SGML files are source code that can be translated into various
|
||||
useful output formats, primarily PDF, HTML, Postscript and plain text.
|
||||
|
||||
To do this transformation on Debian, you should install the
|
||||
docbook-utils package. Having done that, you can say
|
||||
|
||||
docbook2pdf rsync.sgml
|
||||
|
||||
and so on.
|
||||
|
||||
On other systems you probably need James Clark's "sp" and "JadeTeX"
|
||||
packages. Work it out for yourself and send a note to the mailing
|
||||
list.
|
||||
|
42
rsync/doc/profile.txt
Normal file
42
rsync/doc/profile.txt
Normal file
@ -0,0 +1,42 @@
|
||||
Notes on rsync profiling
|
||||
|
||||
strlcpy is hot:
|
||||
|
||||
0.00 0.00 1/7735635 push_dir [68]
|
||||
0.00 0.00 1/7735635 pop_dir [71]
|
||||
0.00 0.00 1/7735635 send_file_list [15]
|
||||
0.01 0.00 18857/7735635 send_files [4]
|
||||
0.04 0.00 129260/7735635 send_file_entry [18]
|
||||
0.04 0.00 129260/7735635 make_file [20]
|
||||
0.04 0.00 141666/7735635 send_directory <cycle 1> [36]
|
||||
2.29 0.00 7316589/7735635 f_name [13]
|
||||
[14] 11.7 2.42 0.00 7735635 strlcpy [14]
|
||||
|
||||
|
||||
Here's the top few functions:
|
||||
|
||||
46.23 9.57 9.57 13160929 0.00 0.00 mdfour64
|
||||
14.78 12.63 3.06 13160929 0.00 0.00 copy64
|
||||
11.69 15.05 2.42 7735635 0.00 0.00 strlcpy
|
||||
10.05 17.13 2.08 41438 0.05 0.38 sum_update
|
||||
4.11 17.98 0.85 13159996 0.00 0.00 mdfour_update
|
||||
1.50 18.29 0.31 file_compare
|
||||
1.45 18.59 0.30 129261 0.00 0.01 send_file_entry
|
||||
1.23 18.84 0.26 2557585 0.00 0.00 f_name
|
||||
1.11 19.07 0.23 1483750 0.00 0.00 u_strcmp
|
||||
1.11 19.30 0.23 118129 0.00 0.00 writefd_unbuffered
|
||||
0.92 19.50 0.19 1085011 0.00 0.00 writefd
|
||||
0.43 19.59 0.09 156987 0.00 0.00 read_timeout
|
||||
0.43 19.68 0.09 129261 0.00 0.00 clean_fname
|
||||
0.39 19.75 0.08 32887 0.00 0.38 matched
|
||||
0.34 19.82 0.07 1 70.00 16293.92 send_files
|
||||
0.29 19.89 0.06 129260 0.00 0.00 make_file
|
||||
0.29 19.95 0.06 75430 0.00 0.00 read_unbuffered
|
||||
|
||||
|
||||
|
||||
mdfour could perhaps be made faster:
|
||||
|
||||
/* NOTE: This code makes no attempt to be fast! */
|
||||
|
||||
There might be an optimized version somewhere that we can borrow.
|
351
rsync/doc/rsync.sgml
Normal file
351
rsync/doc/rsync.sgml
Normal file
@ -0,0 +1,351 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
|
||||
<book id="rsync">
|
||||
<bookinfo>
|
||||
<title>rsync</title>
|
||||
<copyright>
|
||||
<year>1996 -- 2002</year>
|
||||
<holder>Martin Pool</holder>
|
||||
<holder>Andrew Tridgell</holder>
|
||||
</copyright>
|
||||
<author>
|
||||
<firstname>Martin</firstname>
|
||||
<surname>Pool</surname>
|
||||
</author>
|
||||
</bookinfo>
|
||||
|
||||
<chapter>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>rsync is a flexible program for efficiently copying files or
|
||||
directory trees.
|
||||
|
||||
<para>rsync has many options to select which files will be copied
|
||||
and how they are to be transferred. It may be used as an
|
||||
alternative to ftp, http, scp or rcp.
|
||||
|
||||
<para>The rsync remote-update protocol allows rsync to transfer just
|
||||
the differences between two sets of files across the network link,
|
||||
using an efficient checksum-search algorithm described in the
|
||||
technical report that accompanies this package.</para>
|
||||
|
||||
<para>Some of the additional features of rsync are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>support for copying links, devices, owners, groups and
|
||||
permissions
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
exclude and exclude-from options similar to GNU tar
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
a CVS exclude mode for ignoring the same files that CVS would ignore
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
can use any transparent remote shell, including rsh or ssh
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
does not require root privileges
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
pipelining of file transfers to minimize latency costs
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
support for anonymous or authenticated rsync servers (ideal for
|
||||
mirroring)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</chapter>
|
||||
|
||||
|
||||
|
||||
<chapter>
|
||||
<title>Using rsync</title>
|
||||
<section>
|
||||
<title>
|
||||
Introductory example
|
||||
</title>
|
||||
|
||||
<para>
|
||||
Probably the most common case of rsync usage is to copy files
|
||||
to or from a remote machine using
|
||||
<application>ssh</application> as a network transport. In
|
||||
this situation rsync is a good alternative to
|
||||
<application>scp</application>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The most commonly used arguments for rsync are
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-v</option></term>
|
||||
<listitem>
|
||||
<para>Be verbose. Primarily, display the name of each file as it is copied.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Reproduce the structure and attributes of the origin files as exactly
|
||||
as possible: this includes copying subdirectories, symlinks, special
|
||||
files, ownership and permissions. (@xref{Attributes to
|
||||
copy}.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
|
||||
|
||||
<para><option>-v </option>
|
||||
|
||||
<para><option>-z</option>
|
||||
Compress network traffic, using a modified version of the
|
||||
@command{zlib} library.</para>
|
||||
|
||||
<para><option>-P</option>
|
||||
Display a progress indicator while files are transferred. This should
|
||||
normally be ommitted if rsync is not run on a terminal.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<title>Local and remote</title>
|
||||
|
||||
<para>There are six different ways of using rsync. They
|
||||
are:</para>
|
||||
|
||||
|
||||
|
||||
<!-- one of (CALLOUTLIST GLOSSLIST ITEMIZEDLIST ORDEREDLIST SEGMENTEDLIST SIMPLELIST VARIABLELIST CAUTION IMPORTANT NOTE TIP WARNING LITERALLAYOUT PROGRAMLISTING PROGRAMLISTINGCO SCREEN SCREENCO SCREENSHOT SYNOPSIS CMDSYNOPSIS FUNCSYNOPSIS CLASSSYNOPSIS FIELDSYNOPSIS CONSTRUCTORSYNOPSIS DESTRUCTORSYNOPSIS METHODSYNOPSIS FORMALPARA PARA SIMPARA ADDRESS BLOCKQUOTE GRAPHIC GRAPHICCO MEDIAOBJECT MEDIAOBJECTCO INFORMALEQUATION INFORMALEXAMPLE INFORMALFIGURE INFORMALTABLE EQUATION EXAMPLE FIGURE TABLE MSGSET PROCEDURE SIDEBAR QANDASET ANCHOR BRIDGEHEAD REMARK HIGHLIGHTS ABSTRACT AUTHORBLURB EPIGRAPH INDEXTERM REFENTRY SECTION) -->
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
for copying local files. This is invoked when neither
|
||||
source nor destination path contains a @code{:} separator
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from the local machine to a remote machine using
|
||||
a remote shell program as the transport (such as rsh or
|
||||
ssh). This is invoked when the destination path contains a
|
||||
single @code{:} separator.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from a remote machine to the local machine
|
||||
using a remote shell program. This is invoked when the source
|
||||
contains a @code{:} separator.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from a remote rsync server to the local
|
||||
machine. This is invoked when the source path contains a @code{::}
|
||||
separator or a @code{rsync://} URL.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for copying from the local machine to a remote rsync
|
||||
server. This is invoked when the destination path contains a @code{::}
|
||||
separator.
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
for listing files on a remote machine. This is done the
|
||||
same way as rsync transfers except that you leave off the
|
||||
local destination.
|
||||
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
Note that in all cases (other than listing) at least one of the source
|
||||
and destination paths must be local.
|
||||
|
||||
<para>
|
||||
Any one invocation of rsync makes a copy in a single direction. rsync
|
||||
currently has no equivalent of @command{ftp}'s interactive mode.
|
||||
|
||||
@cindex @sc{nfs}
|
||||
@cindex network filesystems
|
||||
@cindex remote filesystems
|
||||
|
||||
<para>
|
||||
rsync's network protocol is generally faster at copying files than
|
||||
network filesystems such as @sc{nfs} or @sc{cifs}. It is better to
|
||||
run rsync on the file server either as a daemon or over ssh than
|
||||
running rsync giving the network directory.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
|
||||
|
||||
<chapter>
|
||||
<title>Frequently asked questions</title>
|
||||
|
||||
|
||||
<!-- one of (CALLOUTLIST GLOSSLIST ITEMIZEDLIST ORDEREDLIST SEGMENTEDLIST SIMPLELIST VARIABLELIST CAUTION IMPORTANT NOTE TIP WARNING LITERALLAYOUT PROGRAMLISTING PROGRAMLISTINGCO SCREEN SCREENCO SCREENSHOT SYNOPSIS CMDSYNOPSIS FUNCSYNOPSIS CLASSSYNOPSIS FIELDSYNOPSIS CONSTRUCTORSYNOPSIS DESTRUCTORSYNOPSIS METHODSYNOPSIS FORMALPARA PARA SIMPARA ADDRESS BLOCKQUOTE GRAPHIC GRAPHICCO MEDIAOBJECT MEDIAOBJECTCO INFORMALEQUATION INFORMALEXAMPLE INFORMALFIGURE INFORMALTABLE EQUATION EXAMPLE FIGURE TABLE MSGSET PROCEDURE SIDEBAR QANDASET ANCHOR BRIDGEHEAD REMARK HIGHLIGHTS ABSTRACT AUTHORBLURB EPIGRAPH INDEXTERM SECTION SIMPLESECT REFENTRY SECT1) -->
|
||||
<qandaset>
|
||||
<!-- one of (QANDADIV QANDAENTRY) -->
|
||||
|
||||
<qandaentry>
|
||||
<question>
|
||||
<!-- one of (CALLOUTLIST GLOSSLIST ITEMIZEDLIST ORDEREDLIST
|
||||
SEGMENTEDLIST SIMPLELIST VARIABLELIST CAUTION IMPORTANT NOTE
|
||||
TIP WARNING LITERALLAYOUT PROGRAMLISTING PROGRAMLISTINGCO
|
||||
SCREEN SCREENCO SCREENSHOT SYNOPSIS CMDSYNOPSIS FUNCSYNOPSIS
|
||||
CLASSSYNOPSIS FIELDSYNOPSIS CONSTRUCTORSYNOPSIS
|
||||
DESTRUCTORSYNOPSIS METHODSYNOPSIS FORMALPARA PARA SIMPARA
|
||||
ADDRESS BLOCKQUOTE GRAPHIC GRAPHICCO MEDIAOBJECT
|
||||
MEDIAOBJECTCO INFORMALEQUATION INFORMALEXAMPLE
|
||||
INFORMALFIGURE INFORMALTABLE EQUATION EXAMPLE FIGURE TABLE
|
||||
PROCEDURE ANCHOR BRIDGEHEAD REMARK HIGHLIGHTS INDEXTERM) -->
|
||||
<para>Are there mailing lists for rsync?
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
<para>Yes, and you can subscribe and unsubscribe through a
|
||||
web interface at
|
||||
<ulink
|
||||
url="http://lists.samba.org/">http://lists.samba.org/</ulink>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you are having trouble with the mailing list, please
|
||||
send mail to the administrator
|
||||
|
||||
<email>rsync-admin@lists.samba.org</email>
|
||||
|
||||
not to the list itself.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The mailing list archives are searchable. Use
|
||||
<ulink url="http://google.com/">Google</ulink> and prepend
|
||||
the search with <userinput>site:lists.samba.org
|
||||
rsync</userinput>, plus relevant keywords.
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
|
||||
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>
|
||||
Why is rsync so much bigger when I build it with
|
||||
<command>gcc</command>?
|
||||
</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
On gcc, rsync builds by default with debug symbols
|
||||
included. If you strip both executables, they should end
|
||||
up about the same size. (Use <command>make
|
||||
install-strip</command>.)
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
|
||||
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Is rsync useful for a single large file like an ISO image?</para>
|
||||
</question>
|
||||
<answer>
|
||||
<para>
|
||||
Yes, but note the following:
|
||||
|
||||
<para>
|
||||
Background: A common use of rsync is to update a file (or set of files) in one location from a more
|
||||
correct or up-to-date copy in another location, taking advantage of portions of the files that are
|
||||
identical to speed up the process. (Note that rsync will transfer a file in its entirety if no copy
|
||||
exists at the destination.)
|
||||
|
||||
<para>
|
||||
(This discussion is written in terms of updating a local copy of a file from a correct file in a
|
||||
remote location, although rsync can work in either direction.)
|
||||
|
||||
<para>
|
||||
The file to be updated (the local file) must be in a destination directory that has enough space for
|
||||
two copies of the file. (In addition, keep an extra copy of the file to be updated in a different
|
||||
location for safety -- see the discussion (below) about rsync's behavior when the rsync process is
|
||||
interrupted before completion.)
|
||||
|
||||
<para>
|
||||
The local file must have the same name as the remote file being sync'd to (I think?). If you are
|
||||
trying to upgrade an iso from, for example, beta1 to beta2, rename the local file to the same name
|
||||
as the beta2 file. *(This is a useful thing to do -- only the changed portions will be
|
||||
transmitted.)*
|
||||
|
||||
<para>
|
||||
The extra copy of the local file kept in a different location is because of rsync's behavior if
|
||||
interrupted before completion:
|
||||
|
||||
<para>
|
||||
* If you specify the --partial option and rsync is interrupted, rsync will save the partially
|
||||
rsync'd file and throw away the original local copy. (The partially rsync'd file is correct but
|
||||
truncated.) If rsync is restarted, it will not have a local copy of the file to check for duplicate
|
||||
blocks beyond the section of the file that has already been rsync'd, thus the remainder of the rsync
|
||||
process will be a "pure transfer" of the file rather than taking advantage of the rsync algorithm.
|
||||
|
||||
<para>
|
||||
* If you don't specify the --partial option and rsync is interrupted, rsync will throw away the
|
||||
partially rsync'd file, and, when rsync is restarted starts the rsync process over from the
|
||||
beginning.
|
||||
|
||||
<para>
|
||||
Which of these is most desirable depends on the degree of commonality between the local and remote
|
||||
copies of the file *and how much progress was made before the interruption*.
|
||||
|
||||
<para>
|
||||
The ideal approach after an interruption would be to create a new file by taking the original file
|
||||
and deleting a portion equal in size to the portion already rsync'd and then appending *the
|
||||
remaining* portion to the portion of the file that has already been rsync'd. (There has been some
|
||||
discussion about creating an option to do this automatically.)
|
||||
|
||||
The --compare-dest option is useful when transferring multiple files, but is of no benefit in
|
||||
transferring a single file. (AFAIK)
|
||||
|
||||
*Other potentially useful information can be found at:
|
||||
-[3]http://twiki.org/cgi-bin/view/Wikilearn/RsyncingALargeFile
|
||||
|
||||
This answer, formatted with "real" bullets, can be found at:
|
||||
-[4]http://twiki.org/cgi-bin/view/Wikilearn/RsyncingALargeFileFAQ*
|
||||
|
||||
</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
</qandaset>
|
||||
</chapter>
|
||||
|
||||
|
||||
<appendix>
|
||||
<title>Other Resources</title>
|
||||
|
||||
<para><ulink url="http://www.ccp14.ac.uk/ccp14admin/rsync/"></ulink></para>
|
||||
</appendix>
|
||||
</book>
|
64
rsync/errcode.h
Normal file
64
rsync/errcode.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Error codes returned by rsync.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* If you change these, please also update the string mappings in log.c and
|
||||
* the EXIT VALUES in rsync.yo. */
|
||||
|
||||
#define RERR_OK 0
|
||||
#define RERR_SYNTAX 1 /* syntax or usage error */
|
||||
#define RERR_PROTOCOL 2 /* protocol incompatibility */
|
||||
#define RERR_FILESELECT 3 /* errors selecting input/output files, dirs */
|
||||
#define RERR_UNSUPPORTED 4 /* requested action not supported */
|
||||
#define RERR_STARTCLIENT 5 /* error starting client-server protocol */
|
||||
|
||||
#define RERR_SOCKETIO 10 /* error in socket IO */
|
||||
#define RERR_FILEIO 11 /* error in file IO */
|
||||
#define RERR_STREAMIO 12 /* error in rsync protocol data stream */
|
||||
#define RERR_MESSAGEIO 13 /* errors with program diagnostics */
|
||||
#define RERR_IPC 14 /* error in IPC code */
|
||||
#define RERR_CRASHED 15 /* sibling crashed */
|
||||
#define RERR_TERMINATED 16 /* sibling terminated abnormally */
|
||||
|
||||
#define RERR_SIGNAL1 19 /* status returned when sent SIGUSR1 */
|
||||
#define RERR_SIGNAL 20 /* status returned when sent SIGINT, SIGTERM, SIGHUP */
|
||||
#define RERR_WAITCHILD 21 /* some error returned by waitpid() */
|
||||
#define RERR_MALLOC 22 /* error allocating core memory buffers */
|
||||
#define RERR_PARTIAL 23 /* partial transfer */
|
||||
#define RERR_VANISHED 24 /* file(s) vanished on sender side */
|
||||
#define RERR_DEL_LIMIT 25 /* skipped some deletes due to --max-delete */
|
||||
|
||||
#define RERR_TIMEOUT 30 /* timeout in data send/receive */
|
||||
#define RERR_CONTIMEOUT 35 /* timeout waiting for daemon connection */
|
||||
|
||||
/* Although it doesn't seem to be specified anywhere,
|
||||
* ssh and the shell seem to return these values:
|
||||
*
|
||||
* 124 if the command exited with status 255
|
||||
* 125 if the command is killed by a signal
|
||||
* 126 if the command cannot be run
|
||||
* 127 if the command is not found
|
||||
*
|
||||
* and we could use this to give a better explanation if the remote
|
||||
* command is not found.
|
||||
*/
|
||||
#define RERR_CMD_FAILED 124
|
||||
#define RERR_CMD_KILLED 125
|
||||
#define RERR_CMD_RUN 126
|
||||
#define RERR_CMD_NOTFOUND 127
|
1401
rsync/exclude.c
Normal file
1401
rsync/exclude.c
Normal file
File diff suppressed because it is too large
Load Diff
288
rsync/fileio.c
Normal file
288
rsync/fileio.c
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* File IO utilities used in rsync.
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "inums.h"
|
||||
|
||||
#ifndef ENODATA
|
||||
#define ENODATA EAGAIN
|
||||
#endif
|
||||
|
||||
/* We want all reads to be aligned on 1K boundries. */
|
||||
#define ALIGN_BOUNDRY 1024
|
||||
/* How far past the boundary is an offset? */
|
||||
#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDRY-1))
|
||||
/* Round up a length to the next boundary */
|
||||
#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1)
|
||||
|
||||
extern int sparse_files;
|
||||
|
||||
static OFF_T sparse_seek = 0;
|
||||
|
||||
int sparse_end(int f, OFF_T size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sparse_seek)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
ret = do_ftruncate(f, size);
|
||||
#else
|
||||
if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
|
||||
ret = -1;
|
||||
else {
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
ret = ret <= 0 ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sparse_seek = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int write_sparse(int f, char *buf, int len)
|
||||
{
|
||||
int l1 = 0, l2 = 0;
|
||||
int ret;
|
||||
|
||||
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
|
||||
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
|
||||
|
||||
sparse_seek += l1;
|
||||
|
||||
if (l1 == len)
|
||||
return len;
|
||||
|
||||
if (sparse_seek)
|
||||
do_lseek(f, sparse_seek, SEEK_CUR);
|
||||
sparse_seek = l2;
|
||||
|
||||
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
|
||||
if (ret < 0 && errno == EINTR)
|
||||
continue;
|
||||
sparse_seek = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != (int)(len - (l1+l2))) {
|
||||
sparse_seek = 0;
|
||||
return l1+ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static char *wf_writeBuf;
|
||||
static size_t wf_writeBufSize;
|
||||
static size_t wf_writeBufCnt;
|
||||
|
||||
int flush_write_file(int f)
|
||||
{
|
||||
int ret = 0;
|
||||
char *bp = wf_writeBuf;
|
||||
|
||||
while (wf_writeBufCnt > 0) {
|
||||
if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return ret;
|
||||
}
|
||||
wf_writeBufCnt -= ret;
|
||||
bp += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write_file does not allow incomplete writes. It loops internally
|
||||
* until len bytes are written or errno is set.
|
||||
*/
|
||||
int write_file(int f, char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (len > 0) {
|
||||
int r1;
|
||||
if (sparse_files > 0) {
|
||||
int len1 = MIN(len, SPARSE_WRITE_SIZE);
|
||||
r1 = write_sparse(f, buf, len1);
|
||||
} else {
|
||||
if (!wf_writeBuf) {
|
||||
wf_writeBufSize = WRITE_SIZE * 8;
|
||||
wf_writeBufCnt = 0;
|
||||
wf_writeBuf = new_array(char, wf_writeBufSize);
|
||||
if (!wf_writeBuf)
|
||||
out_of_memory("write_file");
|
||||
}
|
||||
r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt);
|
||||
if (r1) {
|
||||
memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
|
||||
wf_writeBufCnt += r1;
|
||||
}
|
||||
if (wf_writeBufCnt == wf_writeBufSize) {
|
||||
if (flush_write_file(f) < 0)
|
||||
return -1;
|
||||
if (!r1 && len)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (r1 <= 0) {
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
return r1;
|
||||
}
|
||||
len -= r1;
|
||||
buf += r1;
|
||||
ret += r1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* This provides functionality somewhat similar to mmap() but using read().
|
||||
* It gives sliding window access to a file. mmap() is not used because of
|
||||
* the possibility of another program (such as a mailer) truncating the
|
||||
* file thus giving us a SIGBUS. */
|
||||
struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size)
|
||||
{
|
||||
struct map_struct *map;
|
||||
|
||||
if (!(map = new0(struct map_struct)))
|
||||
out_of_memory("map_file");
|
||||
|
||||
if (blk_size && (read_size % blk_size))
|
||||
read_size += blk_size - (read_size % blk_size);
|
||||
|
||||
map->fd = fd;
|
||||
map->file_size = len;
|
||||
map->def_window_size = ALIGNED_LENGTH(read_size);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/* slide the read window in the file */
|
||||
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
||||
{
|
||||
OFF_T window_start, read_start;
|
||||
int32 window_size, read_size, read_offset, align_fudge;
|
||||
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
if (len < 0) {
|
||||
rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
|
||||
(long)len);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
/* in most cases the region will already be available */
|
||||
if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len)
|
||||
return map->p + (offset - map->p_offset);
|
||||
|
||||
/* nope, we are going to have to do a read. Work out our desired window */
|
||||
align_fudge = (int32)ALIGNED_OVERSHOOT(offset);
|
||||
window_start = offset - align_fudge;
|
||||
window_size = map->def_window_size;
|
||||
if (window_start + window_size > map->file_size)
|
||||
window_size = (int32)(map->file_size - window_start);
|
||||
if (window_size < len + align_fudge)
|
||||
window_size = ALIGNED_LENGTH(len + align_fudge);
|
||||
|
||||
/* make sure we have allocated enough memory for the window */
|
||||
if (window_size > map->p_size) {
|
||||
map->p = realloc_array(map->p, char, window_size);
|
||||
if (!map->p)
|
||||
out_of_memory("map_ptr");
|
||||
map->p_size = window_size;
|
||||
}
|
||||
|
||||
/* Now try to avoid re-reading any bytes by reusing any bytes from the previous buffer. */
|
||||
if (window_start >= map->p_offset && window_start < map->p_offset + map->p_len
|
||||
&& window_start + window_size >= map->p_offset + map->p_len) {
|
||||
read_start = map->p_offset + map->p_len;
|
||||
read_offset = (int32)(read_start - window_start);
|
||||
read_size = window_size - read_offset;
|
||||
memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
|
||||
} else {
|
||||
read_start = window_start;
|
||||
read_size = window_size;
|
||||
read_offset = 0;
|
||||
}
|
||||
|
||||
if (read_size <= 0) {
|
||||
rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
|
||||
(long)read_size);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (map->p_fd_offset != read_start) {
|
||||
OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
|
||||
if (ret != read_start) {
|
||||
rsyserr(FERROR, errno, "lseek returned %s, not %s",
|
||||
big_num(ret), big_num(read_start));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
map->p_fd_offset = read_start;
|
||||
}
|
||||
map->p_offset = window_start;
|
||||
map->p_len = window_size;
|
||||
|
||||
while (read_size > 0) {
|
||||
int32 nread = read(map->fd, map->p + read_offset, read_size);
|
||||
if (nread <= 0) {
|
||||
if (!map->status)
|
||||
map->status = nread ? errno : ENODATA;
|
||||
/* The best we can do is zero the buffer -- the file
|
||||
* has changed mid transfer! */
|
||||
memset(map->p + read_offset, 0, read_size);
|
||||
break;
|
||||
}
|
||||
map->p_fd_offset += nread;
|
||||
read_offset += nread;
|
||||
read_size -= nread;
|
||||
}
|
||||
|
||||
return map->p + align_fudge;
|
||||
}
|
||||
|
||||
|
||||
int unmap_file(struct map_struct *map)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (map->p) {
|
||||
free(map->p);
|
||||
map->p = NULL;
|
||||
}
|
||||
ret = map->status;
|
||||
memset(map, 0, sizeof map[0]);
|
||||
free(map);
|
||||
|
||||
return ret;
|
||||
}
|
3231
rsync/flist.c
Normal file
3231
rsync/flist.c
Normal file
File diff suppressed because it is too large
Load Diff
2370
rsync/generator.c
Normal file
2370
rsync/generator.c
Normal file
File diff suppressed because it is too large
Load Diff
23
rsync/getfsdev.c
Normal file
23
rsync/getfsdev.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "rsync.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
int ret;
|
||||
|
||||
while (--argc > 0) {
|
||||
#ifdef USE_STAT64_FUNCS
|
||||
ret = stat64(*++argv, &st);
|
||||
#else
|
||||
ret = stat(*++argv, &st);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Unable to stat `%s'\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
printf("%ld/%ld\n", (long)major(st.st_dev),
|
||||
(long)minor(st.st_dev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
62
rsync/getgroups.c
Normal file
62
rsync/getgroups.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Print out the gids of all groups for the current user. This is like
|
||||
* `id -G` on Linux, but it's too hard to find a portable equivalent.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int
|
||||
main(UNUSED(int argc), UNUSED(char *argv[]))
|
||||
{
|
||||
int n, i;
|
||||
gid_t *list;
|
||||
gid_t gid = MY_GID();
|
||||
int gid_in_list = 0;
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
if ((n = getgroups(0, NULL)) < 0) {
|
||||
perror("getgroups");
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
n = 0;
|
||||
#endif
|
||||
|
||||
list = (gid_t*)malloc(sizeof (gid_t) * (n + 1));
|
||||
if (!list) {
|
||||
fprintf(stderr, "out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
if (n > 0)
|
||||
n = getgroups(n, list);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
printf("%lu ", (unsigned long)list[i]);
|
||||
if (list[i] == gid)
|
||||
gid_in_list = 1;
|
||||
}
|
||||
/* The default gid might not be in the list on some systems. */
|
||||
if (!gid_in_list)
|
||||
printf("%lu", (unsigned long)gid);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
172
rsync/hashtable.c
Normal file
172
rsync/hashtable.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#define HASH_LOAD_LIMIT(size) ((size)*3/4)
|
||||
|
||||
struct hashtable *hashtable_create(int size, int key64)
|
||||
{
|
||||
int req = size;
|
||||
struct hashtable *tbl;
|
||||
int node_size = key64 ? sizeof (struct ht_int64_node)
|
||||
: sizeof (struct ht_int32_node);
|
||||
|
||||
/* Pick a power of 2 that can hold the requested size. */
|
||||
if (size & (size-1) || size < 16) {
|
||||
size = 16;
|
||||
while (size < req)
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
if (!(tbl = new(struct hashtable))
|
||||
|| !(tbl->nodes = new_array0(char, size * node_size)))
|
||||
out_of_memory("hashtable_create");
|
||||
tbl->size = size;
|
||||
tbl->entries = 0;
|
||||
tbl->node_size = node_size;
|
||||
tbl->key64 = key64 ? 1 : 0;
|
||||
|
||||
if (DEBUG_GTE(HASH, 1)) {
|
||||
char buf[32];
|
||||
if (req != size)
|
||||
snprintf(buf, sizeof buf, "req: %d, ", req);
|
||||
else
|
||||
*buf = '\0';
|
||||
rprintf(FINFO, "[%s] created hashtable %lx (%ssize: %d, keys: %d-bit)\n",
|
||||
who_am_i(), (long)tbl, buf, size, key64 ? 64 : 32);
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
void hashtable_destroy(struct hashtable *tbl)
|
||||
{
|
||||
if (DEBUG_GTE(HASH, 1)) {
|
||||
rprintf(FINFO, "[%s] destroyed hashtable %lx (size: %d, keys: %d-bit)\n",
|
||||
who_am_i(), (long)tbl, tbl->size, tbl->key64 ? 64 : 32);
|
||||
}
|
||||
free(tbl->nodes);
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
/* This returns the node for the indicated key, either newly created or
|
||||
* already existing. Returns NULL if not allocating and not found. */
|
||||
void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
{
|
||||
int key64 = tbl->key64;
|
||||
struct ht_int32_node *node;
|
||||
uint32 ndx;
|
||||
|
||||
if (key64 ? key == 0 : (int32)key == 0) {
|
||||
rprintf(FERROR, "Internal hashtable error: illegal key supplied!\n");
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
|
||||
void *old_nodes = tbl->nodes;
|
||||
int size = tbl->size * 2;
|
||||
int i;
|
||||
|
||||
if (!(tbl->nodes = new_array0(char, size * tbl->node_size)))
|
||||
out_of_memory("hashtable_node");
|
||||
tbl->size = size;
|
||||
tbl->entries = 0;
|
||||
|
||||
if (DEBUG_GTE(HASH, 1)) {
|
||||
rprintf(FINFO, "[%s] growing hashtable %lx (size: %d, keys: %d-bit)\n",
|
||||
who_am_i(), (long)tbl, size, key64 ? 64 : 32);
|
||||
}
|
||||
|
||||
for (i = size / 2; i-- > 0; ) {
|
||||
struct ht_int32_node *move_node = HT_NODE(tbl, old_nodes, i);
|
||||
int64 move_key = HT_KEY(move_node, key64);
|
||||
if (move_key == 0)
|
||||
continue;
|
||||
node = hashtable_find(tbl, move_key, 1);
|
||||
node->data = move_node->data;
|
||||
}
|
||||
|
||||
free(old_nodes);
|
||||
}
|
||||
|
||||
if (!key64) {
|
||||
/* Based on Jenkins One-at-a-time hash. */
|
||||
uchar buf[4], *keyp = buf;
|
||||
int i;
|
||||
|
||||
SIVALu(buf, 0, key);
|
||||
for (ndx = 0, i = 0; i < 4; i++) {
|
||||
ndx += keyp[i];
|
||||
ndx += (ndx << 10);
|
||||
ndx ^= (ndx >> 6);
|
||||
}
|
||||
ndx += (ndx << 3);
|
||||
ndx ^= (ndx >> 11);
|
||||
ndx += (ndx << 15);
|
||||
} else {
|
||||
/* Based on Jenkins hashword() from lookup3.c. */
|
||||
uint32 a, b, c;
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + (8 << 2);
|
||||
|
||||
#define rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k))))
|
||||
#if SIZEOF_INT64 >= 8
|
||||
b += (uint32)(key >> 32);
|
||||
#endif
|
||||
a += (uint32)key;
|
||||
c ^= b; c -= rot(b, 14);
|
||||
a ^= c; a -= rot(c, 11);
|
||||
b ^= a; b -= rot(a, 25);
|
||||
c ^= b; c -= rot(b, 16);
|
||||
a ^= c; a -= rot(c, 4);
|
||||
b ^= a; b -= rot(a, 14);
|
||||
c ^= b; c -= rot(b, 24);
|
||||
#undef rot
|
||||
ndx = c;
|
||||
}
|
||||
|
||||
/* If it already exists, return the node. If we're not
|
||||
* allocating, return NULL if the key is not found. */
|
||||
while (1) {
|
||||
int64 nkey;
|
||||
|
||||
ndx &= tbl->size - 1;
|
||||
node = HT_NODE(tbl, tbl->nodes, ndx);
|
||||
nkey = HT_KEY(node, key64);
|
||||
|
||||
if (nkey == key)
|
||||
return node;
|
||||
if (nkey == 0) {
|
||||
if (!allocate_if_missing)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
ndx++;
|
||||
}
|
||||
|
||||
/* Take over this empty spot and then return the node. */
|
||||
if (key64)
|
||||
((struct ht_int64_node*)node)->key = key;
|
||||
else
|
||||
node->key = (int32)key;
|
||||
tbl->entries++;
|
||||
return node;
|
||||
}
|
571
rsync/hlink.c
Normal file
571
rsync/hlink.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Routines to support hard-linking.
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "inums.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int dry_run;
|
||||
extern int list_only;
|
||||
extern int am_sender;
|
||||
extern int inc_recurse;
|
||||
extern int do_xfers;
|
||||
extern int link_dest;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int protocol_version;
|
||||
extern int remove_source_files;
|
||||
extern int stdout_format_has_i;
|
||||
extern int maybe_ATTRS_REPORT;
|
||||
extern int unsort_ndx;
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern struct file_list *cur_flist;
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
|
||||
/* Starting with protocol 30, we use a simple hashtable on the sending side
|
||||
* for hashing the st_dev and st_ino info. The receiving side gets told
|
||||
* (via flags and a "group index") which items are hard-linked together, so
|
||||
* we can avoid the pool of dev+inode data. For incremental recursion mode,
|
||||
* the receiver will use a ndx hash to remember old pathnames. */
|
||||
|
||||
static struct hashtable *dev_tbl;
|
||||
|
||||
static struct hashtable *prior_hlinks;
|
||||
|
||||
static struct file_list *hlink_flist;
|
||||
|
||||
void init_hard_links(void)
|
||||
{
|
||||
if (am_sender || protocol_version < 30)
|
||||
dev_tbl = hashtable_create(16, 1);
|
||||
else if (inc_recurse)
|
||||
prior_hlinks = hashtable_create(1024, 0);
|
||||
}
|
||||
|
||||
struct ht_int64_node *idev_find(int64 dev, int64 ino)
|
||||
{
|
||||
static struct ht_int64_node *dev_node = NULL;
|
||||
struct hashtable *tbl;
|
||||
|
||||
/* Note that some OSes have a dev == 0, so increment to avoid storing a 0. */
|
||||
if (!dev_node || dev_node->key != dev+1) {
|
||||
/* We keep a separate hash table of inodes for every device. */
|
||||
dev_node = hashtable_find(dev_tbl, dev+1, 1);
|
||||
if (!(tbl = dev_node->data)) {
|
||||
tbl = dev_node->data = hashtable_create(512, 1);
|
||||
if (DEBUG_GTE(HLINK, 3)) {
|
||||
rprintf(FINFO,
|
||||
"[%s] created hashtable for dev %s\n",
|
||||
who_am_i(), big_num(dev));
|
||||
}
|
||||
}
|
||||
} else
|
||||
tbl = dev_node->data;
|
||||
|
||||
return hashtable_find(tbl, ino, 1);
|
||||
}
|
||||
|
||||
void idev_destroy(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev_tbl->size; i++) {
|
||||
struct ht_int32_node *node = HT_NODE(dev_tbl, dev_tbl->nodes, i);
|
||||
if (node->data)
|
||||
hashtable_destroy(node->data);
|
||||
}
|
||||
|
||||
hashtable_destroy(dev_tbl);
|
||||
}
|
||||
|
||||
static int hlink_compare_gnum(int *int1, int *int2)
|
||||
{
|
||||
struct file_struct *f1 = hlink_flist->sorted[*int1];
|
||||
struct file_struct *f2 = hlink_flist->sorted[*int2];
|
||||
int32 gnum1 = F_HL_GNUM(f1);
|
||||
int32 gnum2 = F_HL_GNUM(f2);
|
||||
|
||||
if (gnum1 != gnum2)
|
||||
return gnum1 > gnum2 ? 1 : -1;
|
||||
|
||||
return *int1 > *int2 ? 1 : -1;
|
||||
}
|
||||
|
||||
static void match_gnums(int32 *ndx_list, int ndx_count)
|
||||
{
|
||||
int32 from, prev;
|
||||
struct file_struct *file, *file_next;
|
||||
struct ht_int32_node *node = NULL;
|
||||
int32 gnum, gnum_next;
|
||||
|
||||
qsort(ndx_list, ndx_count, sizeof ndx_list[0],
|
||||
(int (*)()) hlink_compare_gnum);
|
||||
|
||||
for (from = 0; from < ndx_count; from++) {
|
||||
file = hlink_flist->sorted[ndx_list[from]];
|
||||
gnum = F_HL_GNUM(file);
|
||||
if (inc_recurse) {
|
||||
node = hashtable_find(prior_hlinks, gnum, 1);
|
||||
if (!node->data) {
|
||||
if (!(node->data = new_array0(char, 5)))
|
||||
out_of_memory("match_gnums");
|
||||
assert(gnum >= hlink_flist->ndx_start);
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
} else if (CVAL(node->data, 0) == 0) {
|
||||
struct file_list *flist;
|
||||
prev = IVAL(node->data, 1);
|
||||
flist = flist_for_ndx(prev, NULL);
|
||||
if (flist)
|
||||
flist->files[prev - flist->ndx_start]->flags &= ~FLAG_HLINK_LAST;
|
||||
else {
|
||||
/* We skipped all prior files in this
|
||||
* group, so mark this as a "first". */
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
}
|
||||
} else
|
||||
prev = -1;
|
||||
} else {
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
}
|
||||
for ( ; from < ndx_count-1; file = file_next, gnum = gnum_next, from++) { /*SHARED ITERATOR*/
|
||||
file_next = hlink_flist->sorted[ndx_list[from+1]];
|
||||
gnum_next = F_HL_GNUM(file_next);
|
||||
if (gnum != gnum_next)
|
||||
break;
|
||||
F_HL_PREV(file) = prev;
|
||||
/* The linked list uses over-the-wire ndx values. */
|
||||
if (unsort_ndx)
|
||||
prev = F_NDX(file);
|
||||
else
|
||||
prev = ndx_list[from] + hlink_flist->ndx_start;
|
||||
}
|
||||
if (prev < 0 && !inc_recurse) {
|
||||
/* Disable hard-link bit and set DONE so that
|
||||
* HLINK_BUMP()-dependent values are unaffected. */
|
||||
file->flags &= ~(FLAG_HLINKED | FLAG_HLINK_FIRST);
|
||||
file->flags |= FLAG_HLINK_DONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
file->flags |= FLAG_HLINK_LAST;
|
||||
F_HL_PREV(file) = prev;
|
||||
if (inc_recurse && CVAL(node->data, 0) == 0) {
|
||||
if (unsort_ndx)
|
||||
prev = F_NDX(file);
|
||||
else
|
||||
prev = ndx_list[from] + hlink_flist->ndx_start;
|
||||
SIVAL(node->data, 1, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Analyze the hard-links in the file-list by creating a list of all the
|
||||
* items that have hlink data, sorting them, and matching up identical
|
||||
* values into clusters. These will be a single linked list from last
|
||||
* to first when we're done. */
|
||||
void match_hard_links(struct file_list *flist)
|
||||
{
|
||||
if (!list_only && flist->used) {
|
||||
int i, ndx_count = 0;
|
||||
int32 *ndx_list;
|
||||
|
||||
if (!(ndx_list = new_array(int32, flist->used)))
|
||||
out_of_memory("match_hard_links");
|
||||
|
||||
for (i = 0; i < flist->used; i++) {
|
||||
if (F_IS_HLINKED(flist->sorted[i]))
|
||||
ndx_list[ndx_count++] = i;
|
||||
}
|
||||
|
||||
hlink_flist = flist;
|
||||
|
||||
if (ndx_count)
|
||||
match_gnums(ndx_list, ndx_count);
|
||||
|
||||
free(ndx_list);
|
||||
}
|
||||
if (protocol_version < 30)
|
||||
idev_destroy();
|
||||
}
|
||||
|
||||
static int maybe_hard_link(struct file_struct *file, int ndx,
|
||||
char *fname, int statret, stat_x *sxp,
|
||||
const char *oldname, STRUCT_STAT *old_stp,
|
||||
const char *realname, int itemizing, enum logcode code)
|
||||
{
|
||||
if (statret == 0) {
|
||||
if (sxp->st.st_dev == old_stp->st_dev
|
||||
&& sxp->st.st_ino == old_stp->st_ino) {
|
||||
if (itemizing) {
|
||||
itemize(fname, file, ndx, statret, sxp,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
|
||||
0, "");
|
||||
}
|
||||
if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
file->flags |= FLAG_HLINK_DONE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic_create(file, fname, NULL, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
|
||||
if (itemizing) {
|
||||
itemize(fname, file, ndx, statret, sxp,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
|
||||
realname);
|
||||
}
|
||||
if (code != FNONE && INFO_GTE(NAME, 1))
|
||||
rprintf(code, "%s => %s\n", fname, realname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Figure out if a prior entry is still there or if we just have a
|
||||
* cached name for it. */
|
||||
static char *check_prior(struct file_struct *file, int gnum,
|
||||
int *prev_ndx_p, struct file_list **flist_p)
|
||||
{
|
||||
struct file_struct *fp;
|
||||
struct ht_int32_node *node;
|
||||
int prev_ndx = F_HL_PREV(file);
|
||||
|
||||
while (1) {
|
||||
struct file_list *flist;
|
||||
if (prev_ndx < 0
|
||||
|| (flist = flist_for_ndx(prev_ndx, NULL)) == NULL)
|
||||
break;
|
||||
fp = flist->files[prev_ndx - flist->ndx_start];
|
||||
if (!(fp->flags & FLAG_SKIP_HLINK)) {
|
||||
*prev_ndx_p = prev_ndx;
|
||||
*flist_p = flist;
|
||||
return NULL;
|
||||
}
|
||||
F_HL_PREV(file) = prev_ndx = F_HL_PREV(fp);
|
||||
}
|
||||
|
||||
if (inc_recurse
|
||||
&& (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
|
||||
assert(node->data != NULL);
|
||||
if (CVAL(node->data, 0) != 0) {
|
||||
*prev_ndx_p = -1;
|
||||
*flist_p = NULL;
|
||||
return node->data;
|
||||
}
|
||||
/* The prior file must have been skipped. */
|
||||
F_HL_PREV(file) = -1;
|
||||
}
|
||||
|
||||
*prev_ndx_p = -1;
|
||||
*flist_p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
|
||||
* 0 = process the file, 1 = skip the file, -1 = error occurred. */
|
||||
int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
int statret, stat_x *sxp, int itemizing,
|
||||
enum logcode code)
|
||||
{
|
||||
STRUCT_STAT prev_st;
|
||||
char namebuf[MAXPATHLEN], altbuf[MAXPATHLEN];
|
||||
char *realname, *prev_name;
|
||||
struct file_list *flist;
|
||||
int gnum = inc_recurse ? F_HL_GNUM(file) : -1;
|
||||
int prev_ndx;
|
||||
|
||||
prev_name = realname = check_prior(file, gnum, &prev_ndx, &flist);
|
||||
|
||||
if (!prev_name) {
|
||||
struct file_struct *prev_file;
|
||||
|
||||
if (!flist) {
|
||||
/* The previous file was skipped, so this one is
|
||||
* treated as if it were the first in its group. */
|
||||
if (DEBUG_GTE(HLINK, 2)) {
|
||||
rprintf(FINFO, "hlink for %d (%s,%d): virtual first\n",
|
||||
ndx, f_name(file, NULL), gnum);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev_file = flist->files[prev_ndx - flist->ndx_start];
|
||||
|
||||
/* Is the previous link not complete yet? */
|
||||
if (!(prev_file->flags & FLAG_HLINK_DONE)) {
|
||||
/* Is the previous link being transferred? */
|
||||
if (prev_file->flags & FLAG_FILE_SENT) {
|
||||
/* Add ourselves to the list of files that will
|
||||
* be updated when the transfer completes, and
|
||||
* mark ourself as waiting for the transfer. */
|
||||
F_HL_PREV(file) = F_HL_PREV(prev_file);
|
||||
F_HL_PREV(prev_file) = ndx;
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
cur_flist->in_progress++;
|
||||
if (DEBUG_GTE(HLINK, 2)) {
|
||||
rprintf(FINFO, "hlink for %d (%s,%d): waiting for %d\n",
|
||||
ndx, f_name(file, NULL), gnum, F_HL_PREV(file));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (DEBUG_GTE(HLINK, 2)) {
|
||||
rprintf(FINFO, "hlink for %d (%s,%d): looking for a leader\n",
|
||||
ndx, f_name(file, NULL), gnum);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There is a finished file to link with! */
|
||||
if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
|
||||
/* The previous previous is FIRST when prev is not. */
|
||||
prev_name = realname = check_prior(prev_file, gnum, &prev_ndx, &flist);
|
||||
/* Update our previous pointer to point to the FIRST. */
|
||||
F_HL_PREV(file) = prev_ndx;
|
||||
}
|
||||
|
||||
if (!prev_name) {
|
||||
int alt_dest;
|
||||
|
||||
assert(flist != NULL);
|
||||
prev_file = flist->files[prev_ndx - flist->ndx_start];
|
||||
/* F_HL_PREV() is alt_dest value when DONE && FIRST. */
|
||||
alt_dest = F_HL_PREV(prev_file);
|
||||
if (DEBUG_GTE(HLINK, 2)) {
|
||||
rprintf(FINFO, "hlink for %d (%s,%d): found flist match (alt %d)\n",
|
||||
ndx, f_name(file, NULL), gnum, alt_dest);
|
||||
}
|
||||
|
||||
if (alt_dest >= 0 && dry_run) {
|
||||
pathjoin(namebuf, MAXPATHLEN, basis_dir[alt_dest],
|
||||
f_name(prev_file, NULL));
|
||||
prev_name = namebuf;
|
||||
realname = f_name(prev_file, altbuf);
|
||||
} else {
|
||||
prev_name = f_name(prev_file, namebuf);
|
||||
realname = prev_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(HLINK, 2)) {
|
||||
rprintf(FINFO, "hlink for %d (%s,%d): leader is %d (%s)\n",
|
||||
ndx, f_name(file, NULL), gnum, prev_ndx, prev_name);
|
||||
}
|
||||
|
||||
if (link_stat(prev_name, &prev_st, 0) < 0) {
|
||||
if (!dry_run || errno != ENOENT) {
|
||||
rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(prev_name));
|
||||
return -1;
|
||||
}
|
||||
/* A new hard-link will get a new dev & inode, so approximate
|
||||
* those values in dry-run mode by zeroing them. */
|
||||
memset(&prev_st, 0, sizeof prev_st);
|
||||
}
|
||||
|
||||
if (statret < 0 && basis_dir[0] != NULL) {
|
||||
/* If we match an alt-dest item, we don't output this as a change. */
|
||||
char cmpbuf[MAXPATHLEN];
|
||||
stat_x alt_sx;
|
||||
int j = 0;
|
||||
init_stat_x(&alt_sx);
|
||||
do {
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
|
||||
continue;
|
||||
if (link_dest) {
|
||||
if (prev_st.st_dev != alt_sx.st.st_dev
|
||||
|| prev_st.st_ino != alt_sx.st.st_ino)
|
||||
continue;
|
||||
statret = 1;
|
||||
if (stdout_format_has_i == 0
|
||||
|| (!INFO_GTE(NAME, 2) && stdout_format_has_i < 2)) {
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!unchanged_file(cmpbuf, file, &alt_sx.st))
|
||||
continue;
|
||||
statret = 1;
|
||||
if (unchanged_attrs(cmpbuf, file, &alt_sx))
|
||||
break;
|
||||
} while (basis_dir[++j] != NULL);
|
||||
if (statret == 1) {
|
||||
sxp->st = alt_sx.st;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
free_acl(sxp);
|
||||
if (!ACL_READY(alt_sx))
|
||||
get_acl(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->acc_acl = alt_sx.acc_acl;
|
||||
sxp->def_acl = alt_sx.def_acl;
|
||||
alt_sx.acc_acl = alt_sx.def_acl = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
free_xattr(sxp);
|
||||
if (!XATTR_READY(alt_sx))
|
||||
get_xattr(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->xattr = alt_sx.xattr;
|
||||
alt_sx.xattr = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
free_stat_x(&alt_sx);
|
||||
}
|
||||
|
||||
if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
|
||||
realname, itemizing, code) < 0)
|
||||
return -1;
|
||||
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hard_link_one(struct file_struct *file, const char *fname,
|
||||
const char *oldname, int terse)
|
||||
{
|
||||
if (do_link(oldname, fname) < 0) {
|
||||
enum logcode code;
|
||||
if (terse) {
|
||||
if (!INFO_GTE(NAME, 1))
|
||||
return 0;
|
||||
code = FINFO;
|
||||
} else
|
||||
code = FERROR_XFER;
|
||||
rsyserr(code, errno, "link %s => %s failed",
|
||||
full_fname(fname), oldname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->flags |= FLAG_HLINK_DONE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
STRUCT_STAT *stp, int itemizing, enum logcode code,
|
||||
int alt_dest)
|
||||
{
|
||||
stat_x prev_sx;
|
||||
STRUCT_STAT st;
|
||||
char prev_name[MAXPATHLEN], alt_name[MAXPATHLEN];
|
||||
const char *our_name;
|
||||
struct file_list *flist;
|
||||
int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
|
||||
|
||||
if (stp == NULL && prev_ndx >= 0) {
|
||||
if (link_stat(fname, &st, 0) < 0 && !dry_run) {
|
||||
rsyserr(FERROR_XFER, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
return;
|
||||
}
|
||||
stp = &st;
|
||||
}
|
||||
|
||||
/* FIRST combined with DONE means we were the first to get done. */
|
||||
file->flags |= FLAG_HLINK_FIRST | FLAG_HLINK_DONE;
|
||||
F_HL_PREV(file) = alt_dest;
|
||||
if (alt_dest >= 0 && dry_run) {
|
||||
pathjoin(alt_name, MAXPATHLEN, basis_dir[alt_dest],
|
||||
f_name(file, NULL));
|
||||
our_name = alt_name;
|
||||
} else
|
||||
our_name = fname;
|
||||
|
||||
init_stat_x(&prev_sx);
|
||||
|
||||
while ((ndx = prev_ndx) >= 0) {
|
||||
int val;
|
||||
flist = flist_for_ndx(ndx, "finish_hard_link");
|
||||
file = flist->files[ndx - flist->ndx_start];
|
||||
file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
|
||||
prev_ndx = F_HL_PREV(file);
|
||||
F_HL_PREV(file) = fin_ndx;
|
||||
prev_statret = link_stat(f_name(file, prev_name), &prev_sx.st, 0);
|
||||
val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
|
||||
our_name, stp, fname, itemizing, code);
|
||||
flist->in_progress--;
|
||||
free_stat_x(&prev_sx);
|
||||
if (val < 0)
|
||||
continue;
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
}
|
||||
|
||||
if (inc_recurse) {
|
||||
int gnum = F_HL_GNUM(file);
|
||||
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
|
||||
if (node == NULL) {
|
||||
rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
if (node->data == NULL) {
|
||||
rprintf(FERROR, "Hlink node data for %d is NULL (%s)\n", gnum, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
if (CVAL(node->data, 0) != 0) {
|
||||
rprintf(FERROR, "Hlink node data for %d already has path=%s (%s)\n",
|
||||
gnum, (char*)node->data, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
free(node->data);
|
||||
if (!(node->data = strdup(our_name)))
|
||||
out_of_memory("finish_hard_link");
|
||||
}
|
||||
}
|
||||
|
||||
int skip_hard_link(struct file_struct *file, struct file_list **flist_p)
|
||||
{
|
||||
struct file_list *flist;
|
||||
int prev_ndx;
|
||||
|
||||
file->flags |= FLAG_SKIP_HLINK;
|
||||
if (!(file->flags & FLAG_HLINK_LAST))
|
||||
return -1;
|
||||
|
||||
check_prior(file, F_HL_GNUM(file), &prev_ndx, &flist);
|
||||
if (prev_ndx >= 0) {
|
||||
file = flist->files[prev_ndx - flist->ndx_start];
|
||||
if (file->flags & (FLAG_HLINK_DONE|FLAG_FILE_SENT))
|
||||
return -1;
|
||||
file->flags |= FLAG_HLINK_LAST;
|
||||
*flist_p = flist;
|
||||
}
|
||||
|
||||
return prev_ndx;
|
||||
}
|
||||
#endif
|
106
rsync/ifuncs.h
Normal file
106
rsync/ifuncs.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
alloc_xbuf(xbuf *xb, size_t sz)
|
||||
{
|
||||
if (!(xb->buf = new_array(char, sz)))
|
||||
out_of_memory("alloc_xbuf");
|
||||
xb->size = sz;
|
||||
xb->len = xb->pos = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
realloc_xbuf(xbuf *xb, size_t sz)
|
||||
{
|
||||
char *bf = realloc_array(xb->buf, char, sz);
|
||||
if (!bf)
|
||||
out_of_memory("realloc_xbuf");
|
||||
xb->buf = bf;
|
||||
xb->size = sz;
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_xbuf(xbuf *xb)
|
||||
{
|
||||
if (xb->buf)
|
||||
free(xb->buf);
|
||||
memset(xb, 0, sizeof (xbuf));
|
||||
}
|
||||
|
||||
static inline int
|
||||
to_wire_mode(mode_t mode)
|
||||
{
|
||||
#ifdef SUPPORT_LINKS
|
||||
#if _S_IFLNK != 0120000
|
||||
if (S_ISLNK(mode))
|
||||
return (mode & ~(_S_IFMT)) | 0120000;
|
||||
#endif
|
||||
#endif
|
||||
return mode;
|
||||
}
|
||||
|
||||
static inline mode_t
|
||||
from_wire_mode(int mode)
|
||||
{
|
||||
#if _S_IFLNK != 0120000
|
||||
if ((mode & (_S_IFMT)) == 0120000)
|
||||
return (mode & ~(_S_IFMT)) | _S_IFLNK;
|
||||
#endif
|
||||
return mode;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
d_name(struct dirent *di)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_READDIR
|
||||
return (di->d_name - 2);
|
||||
#else
|
||||
return di->d_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_stat_x(stat_x *sx_p)
|
||||
{
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx_p->acc_acl = sx_p->def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx_p->xattr = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_stat_x(stat_x *sx_p)
|
||||
{
|
||||
#ifdef SUPPORT_ACLS
|
||||
{
|
||||
extern int preserve_acls;
|
||||
if (preserve_acls)
|
||||
free_acl(sx_p);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
{
|
||||
extern int preserve_xattrs;
|
||||
if (preserve_xattrs)
|
||||
free_xattr(sx_p);
|
||||
}
|
||||
#endif
|
||||
}
|
238
rsync/install-sh
Executable file
238
rsync/install-sh
Executable file
@ -0,0 +1,238 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
57
rsync/inums.h
Normal file
57
rsync/inums.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2008-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
static inline char *
|
||||
big_num(int64 num)
|
||||
{
|
||||
return do_big_num(num, 0, NULL);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
comma_num(int64 num)
|
||||
{
|
||||
extern int human_readable;
|
||||
return do_big_num(num, human_readable != 0, NULL);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
human_num(int64 num)
|
||||
{
|
||||
extern int human_readable;
|
||||
return do_big_num(num, human_readable, NULL);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
big_dnum(double dnum, int decimal_digits)
|
||||
{
|
||||
return do_big_dnum(dnum, 0, decimal_digits);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
comma_dnum(double dnum, int decimal_digits)
|
||||
{
|
||||
extern int human_readable;
|
||||
return do_big_dnum(dnum, human_readable != 0, decimal_digits);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
human_dnum(double dnum, int decimal_digits)
|
||||
{
|
||||
extern int human_readable;
|
||||
return do_big_dnum(dnum, human_readable, decimal_digits);
|
||||
}
|
2384
rsync/io.c
Normal file
2384
rsync/io.c
Normal file
File diff suppressed because it is too large
Load Diff
52
rsync/io.h
Normal file
52
rsync/io.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
extern int protocol_version;
|
||||
|
||||
static inline int32
|
||||
read_varint30(int f)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
return read_int(f);
|
||||
return read_varint(f);
|
||||
}
|
||||
|
||||
static inline int64
|
||||
read_varlong30(int f, uchar min_bytes)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
return read_longint(f);
|
||||
return read_varlong(f, min_bytes);
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_varint30(int f, int32 x)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
write_int(f, x);
|
||||
else
|
||||
write_varint(f, x);
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_varlong30(int f, int64 x, uchar min_bytes)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
write_longint(f, x);
|
||||
else
|
||||
write_varlong(f, x, min_bytes);
|
||||
}
|
59
rsync/itypes.h
Normal file
59
rsync/itypes.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
static inline int
|
||||
isDigit(const char *ptr)
|
||||
{
|
||||
return isdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isPrint(const char *ptr)
|
||||
{
|
||||
return isprint(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isSpace(const char *ptr)
|
||||
{
|
||||
return isspace(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isLower(const char *ptr)
|
||||
{
|
||||
return islower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isUpper(const char *ptr)
|
||||
{
|
||||
return isupper(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toLower(const char *ptr)
|
||||
{
|
||||
return tolower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toUpper(const char *ptr)
|
||||
{
|
||||
return toupper(*(unsigned char *)ptr);
|
||||
}
|
180
rsync/lib/addrinfo.h
Normal file
180
rsync/lib/addrinfo.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
PostgreSQL Database Management System
|
||||
(formerly known as Postgres, then as Postgres95)
|
||||
|
||||
Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
|
||||
|
||||
Portions Copyright (c) 1994, The Regents of the University of California
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose, without fee, and without a written agreement
|
||||
is hereby granted, provided that the above copyright notice and this paragraph
|
||||
and the following two paragraphs appear in all copies.
|
||||
|
||||
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
||||
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
|
||||
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
|
||||
EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
|
||||
TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* getaddrinfo.h
|
||||
* Support getaddrinfo() on platforms that don't have it.
|
||||
*
|
||||
* Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO,
|
||||
* whether or not the library routine getaddrinfo() can be found. This
|
||||
* policy is needed because on some platforms a manually installed libbind.a
|
||||
* may provide getaddrinfo(), yet the system headers may not provide the
|
||||
* struct definitions needed to call it. To avoid conflict with the libbind
|
||||
* definition in such cases, we rename our routines to pg_xxx() via macros.
|
||||
*
|
||||
* This code will also work on platforms where struct addrinfo is defined
|
||||
* in the system headers but no getaddrinfo() can be located.
|
||||
*
|
||||
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ADDRINFO_H
|
||||
#define ADDRINFO_H
|
||||
|
||||
|
||||
/* Various macros that ought to be in <netdb.h>, but might not be */
|
||||
|
||||
#ifndef EAI_FAIL
|
||||
#define EAI_BADFLAGS (-1)
|
||||
#define EAI_NONAME (-2)
|
||||
#define EAI_AGAIN (-3)
|
||||
#define EAI_FAIL (-4)
|
||||
#define EAI_FAMILY (-6)
|
||||
#define EAI_SOCKTYPE (-7)
|
||||
#define EAI_SERVICE (-8)
|
||||
#define EAI_MEMORY (-10)
|
||||
#define EAI_SYSTEM (-11)
|
||||
#endif /* !EAI_FAIL */
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
#define AI_PASSIVE 0x0001
|
||||
#endif
|
||||
|
||||
#ifndef AI_NUMERICHOST
|
||||
/*
|
||||
* some platforms don't support AI_NUMERICHOST; define as zero if using
|
||||
* the system version of getaddrinfo...
|
||||
*/
|
||||
#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
|
||||
#define AI_NUMERICHOST 0
|
||||
#else
|
||||
#define AI_NUMERICHOST 0x0004
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AI_CANONNAME
|
||||
#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
|
||||
#define AI_CANONNAME 0
|
||||
#else
|
||||
#define AI_CANONNAME 0x0008
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AI_NUMERICSERV
|
||||
#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO)
|
||||
#define AI_NUMERICSERV 0
|
||||
#else
|
||||
#define AI_NUMERICSERV 0x0010
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
#define NI_NUMERICHOST 1
|
||||
#endif
|
||||
|
||||
#ifndef NI_NUMERICSERV
|
||||
#define NI_NUMERICSERV 2
|
||||
#endif
|
||||
|
||||
#ifndef NI_NOFQDN
|
||||
#define NI_NOFQDN 4
|
||||
#endif
|
||||
|
||||
#ifndef NI_NAMEREQD
|
||||
#define NI_NAMEREQD 8
|
||||
#endif
|
||||
|
||||
#ifndef NI_DGRAM
|
||||
#define NI_DGRAM 16
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
#define NI_MAXSERV 32
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo
|
||||
{
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
size_t ai_addrlen;
|
||||
struct sockaddr *ai_addr;
|
||||
char *ai_canonname;
|
||||
struct addrinfo *ai_next;
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
struct sockaddr_storage {
|
||||
unsigned short ss_family;
|
||||
unsigned long ss_align;
|
||||
char ss_padding[128 - sizeof (unsigned long)];
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
|
||||
/* Rename private copies per comments above */
|
||||
#ifdef getaddrinfo
|
||||
#undef getaddrinfo
|
||||
#endif
|
||||
#define getaddrinfo pg_getaddrinfo
|
||||
|
||||
#ifdef freeaddrinfo
|
||||
#undef freeaddrinfo
|
||||
#endif
|
||||
#define freeaddrinfo pg_freeaddrinfo
|
||||
|
||||
#ifdef gai_strerror
|
||||
#undef gai_strerror
|
||||
#endif
|
||||
#define gai_strerror pg_gai_strerror
|
||||
|
||||
#ifdef getnameinfo
|
||||
#undef getnameinfo
|
||||
#endif
|
||||
#define getnameinfo pg_getnameinfo
|
||||
|
||||
extern int getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo * hints, struct addrinfo ** res);
|
||||
extern void freeaddrinfo(struct addrinfo * res);
|
||||
extern const char *gai_strerror(int errcode);
|
||||
extern int getnameinfo(const struct sockaddr * sa, socklen_t salen,
|
||||
char *node, size_t nodelen,
|
||||
char *service, size_t servicelen, int flags);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#endif /* ADDRINFO_H */
|
275
rsync/lib/compat.c
Normal file
275
rsync/lib/compat.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Reimplementations of standard functions for platforms that don't have them.
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
static char number_separator;
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(char *s)
|
||||
{
|
||||
int len = strlen(s) + 1;
|
||||
char *ret = (char *)malloc(len);
|
||||
if (ret)
|
||||
memcpy(ret, s, len);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETCWD
|
||||
char *getcwd(char *buf, int size)
|
||||
{
|
||||
return getwd(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_WAITPID
|
||||
pid_t waitpid(pid_t pid, int *statptr, int options)
|
||||
{
|
||||
#ifdef HAVE_WAIT4
|
||||
return wait4(pid, statptr, options, NULL);
|
||||
#else
|
||||
/* If wait4 is also not available, try wait3 for SVR3 variants */
|
||||
/* Less ideal because can't actually request a specific pid */
|
||||
/* At least the WNOHANG option is supported */
|
||||
/* Code borrowed from apache fragment written by dwd@bell-labs.com */
|
||||
int tmp_pid, dummystat;;
|
||||
if (kill(pid, 0) == -1) {
|
||||
errno = ECHILD;
|
||||
return -1;
|
||||
}
|
||||
if (statptr == NULL)
|
||||
statptr = &dummystat;
|
||||
while (((tmp_pid = wait3(statptr, options, 0)) != pid) &&
|
||||
(tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
|
||||
;
|
||||
return tmp_pid;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_MEMMOVE
|
||||
void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
bcopy((char *) src, (char *) dest, n);
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRPBRK
|
||||
/**
|
||||
* Find the first ocurrence in @p s of any character in @p accept.
|
||||
*
|
||||
* Derived from glibc
|
||||
**/
|
||||
char *strpbrk(const char *s, const char *accept)
|
||||
{
|
||||
while (*s != '\0') {
|
||||
const char *a = accept;
|
||||
while (*a != '\0') {
|
||||
if (*a++ == *s) return (char *)s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
/**
|
||||
* Like strncpy but does not 0 fill the buffer and always null
|
||||
* terminates.
|
||||
*
|
||||
* @param bufsize is the size of the destination buffer.
|
||||
*
|
||||
* @return index of the terminating byte.
|
||||
**/
|
||||
size_t strlcpy(char *d, const char *s, size_t bufsize)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
size_t ret = len;
|
||||
if (bufsize > 0) {
|
||||
if (len >= bufsize)
|
||||
len = bufsize-1;
|
||||
memcpy(d, s, len);
|
||||
d[len] = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
/**
|
||||
* Like strncat() but does not 0 fill the buffer and always null
|
||||
* terminates.
|
||||
*
|
||||
* @param bufsize length of the buffer, which should be one more than
|
||||
* the maximum resulting string length.
|
||||
**/
|
||||
size_t strlcat(char *d, const char *s, size_t bufsize)
|
||||
{
|
||||
size_t len1 = strlen(d);
|
||||
size_t len2 = strlen(s);
|
||||
size_t ret = len1 + len2;
|
||||
|
||||
if (len1 < bufsize - 1) {
|
||||
if (len2 >= bufsize - len1)
|
||||
len2 = bufsize - len1 - 1;
|
||||
memcpy(d+len1, s, len2);
|
||||
d[len1+len2] = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* some systems don't take the 2nd argument */
|
||||
int sys_gettimeofday(struct timeval *tv)
|
||||
{
|
||||
#ifdef HAVE_GETTIMEOFDAY_TZ
|
||||
return gettimeofday(tv, NULL);
|
||||
#else
|
||||
return gettimeofday(tv);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define HUMANIFY(mult) \
|
||||
do { \
|
||||
if (num >= mult || num <= -mult) { \
|
||||
double dnum = (double)num / mult; \
|
||||
char units; \
|
||||
if (num < 0) \
|
||||
dnum = -dnum; \
|
||||
if (dnum < mult) \
|
||||
units = 'K'; \
|
||||
else if ((dnum /= mult) < mult) \
|
||||
units = 'M'; \
|
||||
else if ((dnum /= mult) < mult) \
|
||||
units = 'G'; \
|
||||
else { \
|
||||
dnum /= mult; \
|
||||
units = 'T'; \
|
||||
} \
|
||||
if (num < 0) \
|
||||
dnum = -dnum; \
|
||||
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \
|
||||
return bufs[n]; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Return the int64 number as a string. If the human_flag arg is non-zero,
|
||||
* we may output the number in K, M, G, or T units. If we don't add a unit
|
||||
* suffix, we will append the fract string, if it is non-NULL. We can
|
||||
* return up to 4 buffers at a time. */
|
||||
char *do_big_num(int64 num, int human_flag, const char *fract)
|
||||
{
|
||||
static char bufs[4][128]; /* more than enough room */
|
||||
static unsigned int n;
|
||||
char *s;
|
||||
int len, negated;
|
||||
|
||||
if (human_flag && !number_separator) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof buf, "%f", 3.14);
|
||||
if (strchr(buf, '.') != NULL)
|
||||
number_separator = ',';
|
||||
else
|
||||
number_separator = '.';
|
||||
}
|
||||
|
||||
n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
|
||||
|
||||
if (human_flag > 1) {
|
||||
if (human_flag == 2)
|
||||
HUMANIFY(1000);
|
||||
else
|
||||
HUMANIFY(1024);
|
||||
}
|
||||
|
||||
s = bufs[n] + sizeof bufs[0] - 1;
|
||||
if (fract) {
|
||||
len = strlen(fract);
|
||||
s -= len;
|
||||
strlcpy(s, fract, len + 1);
|
||||
} else
|
||||
*s = '\0';
|
||||
|
||||
len = 0;
|
||||
|
||||
if (!num)
|
||||
*--s = '0';
|
||||
if (num < 0) {
|
||||
/* A maximum-size negated number can't fit as a positive,
|
||||
* so do one digit in negated form to start us off. */
|
||||
*--s = (char)(-(num % 10)) + '0';
|
||||
num = -(num / 10);
|
||||
len++;
|
||||
negated = 1;
|
||||
} else
|
||||
negated = 0;
|
||||
|
||||
while (num) {
|
||||
if (human_flag) {
|
||||
if (len == 3) {
|
||||
*--s = number_separator;
|
||||
len = 1;
|
||||
} else
|
||||
len++;
|
||||
}
|
||||
*--s = (char)(num % 10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
|
||||
if (negated)
|
||||
*--s = '-';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return the double number as a string. If the human_flag option is > 1,
|
||||
* we may output the number in K, M, G, or T units. The buffer we use for
|
||||
* our result is either a single static buffer defined here, or a buffer
|
||||
* we get from do_big_num(). */
|
||||
char *do_big_dnum(double dnum, int human_flag, int decimal_digits)
|
||||
{
|
||||
static char tmp_buf[128];
|
||||
#if SIZEOF_INT64 >= 8
|
||||
char *fract;
|
||||
|
||||
snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum);
|
||||
|
||||
if (!human_flag || (dnum < 1000.0 && dnum > -1000.0))
|
||||
return tmp_buf;
|
||||
|
||||
for (fract = tmp_buf+1; isDigit(fract); fract++) {}
|
||||
|
||||
return do_big_num((int64)dnum, human_flag, fract);
|
||||
#else
|
||||
/* A big number might lose digits converting to a too-short int64,
|
||||
* so let's just return the raw double conversion. */
|
||||
snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum);
|
||||
return tmp_buf;
|
||||
#endif
|
||||
}
|
2
rsync/lib/dummy.in
Normal file
2
rsync/lib/dummy.in
Normal file
@ -0,0 +1,2 @@
|
||||
This is a dummy file to ensure that the lib directory gets created
|
||||
by configure when a VPATH is used.
|
504
rsync/lib/getaddrinfo.c
Normal file
504
rsync/lib/getaddrinfo.c
Normal file
@ -0,0 +1,504 @@
|
||||
/*
|
||||
PostgreSQL Database Management System
|
||||
(formerly known as Postgres, then as Postgres95)
|
||||
|
||||
Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
|
||||
|
||||
Portions Copyright (c) 1994, The Regents of the University of California
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose, without fee, and without a written agreement
|
||||
is hereby granted, provided that the above copyright notice and this paragraph
|
||||
and the following two paragraphs appear in all copies.
|
||||
|
||||
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
||||
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
|
||||
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
|
||||
EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
|
||||
TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* getaddrinfo.c
|
||||
* Support getaddrinfo() on platforms that don't have it.
|
||||
*
|
||||
* We also supply getnameinfo() here, assuming that the platform will have
|
||||
* it if and only if it has getaddrinfo(). If this proves false on some
|
||||
* platform, we'll need to split this file and provide a separate configure
|
||||
* test for getnameinfo().
|
||||
*
|
||||
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
* Copyright (C) 2007 Jeremy Allison.
|
||||
* Modified to return multiple IPv4 addresses for Samba.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifndef SMB_MALLOC
|
||||
#define SMB_MALLOC(s) malloc(s)
|
||||
#endif
|
||||
|
||||
#ifndef SMB_STRDUP
|
||||
#define SMB_STRDUP(s) strdup(s)
|
||||
#endif
|
||||
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX 255
|
||||
#endif
|
||||
|
||||
static int check_hostent_err(struct hostent *hp)
|
||||
{
|
||||
#ifndef INET6
|
||||
extern int h_errno;
|
||||
#endif
|
||||
if (!hp) {
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND:
|
||||
case NO_DATA:
|
||||
return EAI_NONAME;
|
||||
case TRY_AGAIN:
|
||||
return EAI_AGAIN;
|
||||
case NO_RECOVERY:
|
||||
default:
|
||||
return EAI_FAIL;
|
||||
}
|
||||
}
|
||||
if (!hp->h_name || hp->h_addrtype != AF_INET) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *canon_name_from_hostent(struct hostent *hp,
|
||||
int *perr)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
*perr = check_hostent_err(hp);
|
||||
if (*perr) {
|
||||
return NULL;
|
||||
}
|
||||
ret = SMB_STRDUP(hp->h_name);
|
||||
if (!ret) {
|
||||
*perr = EAI_MEMORY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *get_my_canon_name(int *perr)
|
||||
{
|
||||
char name[HOST_NAME_MAX+1];
|
||||
|
||||
if (gethostname(name, HOST_NAME_MAX) == -1) {
|
||||
*perr = EAI_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
/* Ensure null termination. */
|
||||
name[HOST_NAME_MAX] = '\0';
|
||||
return canon_name_from_hostent(gethostbyname(name), perr);
|
||||
}
|
||||
|
||||
static char *get_canon_name_from_addr(struct in_addr ip,
|
||||
int *perr)
|
||||
{
|
||||
return canon_name_from_hostent(
|
||||
gethostbyaddr((void *)&ip, sizeof ip, AF_INET),
|
||||
perr);
|
||||
}
|
||||
|
||||
static struct addrinfo *alloc_entry(const struct addrinfo *hints,
|
||||
struct in_addr ip,
|
||||
unsigned short port)
|
||||
{
|
||||
struct sockaddr_in *psin = NULL;
|
||||
struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
|
||||
|
||||
if (!ai) {
|
||||
return NULL;
|
||||
}
|
||||
memset(ai, '\0', sizeof(*ai));
|
||||
|
||||
psin = SMB_MALLOC(sizeof(*psin));
|
||||
if (!psin) {
|
||||
free(ai);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(psin, '\0', sizeof(*psin));
|
||||
|
||||
psin->sin_family = AF_INET;
|
||||
psin->sin_port = htons(port);
|
||||
psin->sin_addr = ip;
|
||||
|
||||
ai->ai_flags = 0;
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
ai->ai_protocol = hints->ai_protocol;
|
||||
ai->ai_addrlen = sizeof(*psin);
|
||||
ai->ai_addr = (struct sockaddr *) psin;
|
||||
ai->ai_canonname = NULL;
|
||||
ai->ai_next = NULL;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
/*
|
||||
* get address info for a single ipv4 address.
|
||||
*
|
||||
* Bugs: - servname can only be a number, not text.
|
||||
*/
|
||||
|
||||
static int getaddr_info_single_addr(const char *service,
|
||||
uint32 addr,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
|
||||
struct addrinfo *ai = NULL;
|
||||
struct in_addr ip;
|
||||
unsigned short port = 0;
|
||||
|
||||
if (service) {
|
||||
port = (unsigned short)atoi(service);
|
||||
}
|
||||
ip.s_addr = htonl(addr);
|
||||
|
||||
ai = alloc_entry(hints, ip, port);
|
||||
if (!ai) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
/* If we're asked for the canonical name,
|
||||
* make sure it returns correctly. */
|
||||
if (!(hints->ai_flags & AI_NUMERICSERV) &&
|
||||
hints->ai_flags & AI_CANONNAME) {
|
||||
int err;
|
||||
if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
|
||||
ai->ai_canonname = get_my_canon_name(&err);
|
||||
} else {
|
||||
ai->ai_canonname =
|
||||
get_canon_name_from_addr(ip,&err);
|
||||
}
|
||||
if (ai->ai_canonname == NULL) {
|
||||
freeaddrinfo(ai);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
*res = ai;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get address info for multiple ipv4 addresses.
|
||||
*
|
||||
* Bugs: - servname can only be a number, not text.
|
||||
*/
|
||||
|
||||
static int getaddr_info_name(const char *node,
|
||||
const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
struct addrinfo *listp = NULL, *prevp = NULL;
|
||||
char **pptr = NULL;
|
||||
int err;
|
||||
struct hostent *hp = NULL;
|
||||
unsigned short port = 0;
|
||||
|
||||
if (service) {
|
||||
port = (unsigned short)atoi(service);
|
||||
}
|
||||
|
||||
hp = gethostbyname(node);
|
||||
err = check_hostent_err(hp);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for(pptr = hp->h_addr_list; *pptr; pptr++) {
|
||||
struct in_addr ip = *(struct in_addr *)*pptr;
|
||||
struct addrinfo *ai = alloc_entry(hints, ip, port);
|
||||
|
||||
if (!ai) {
|
||||
freeaddrinfo(listp);
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
if (!listp) {
|
||||
listp = ai;
|
||||
prevp = ai;
|
||||
ai->ai_canonname = SMB_STRDUP(hp->h_name);
|
||||
if (!ai->ai_canonname) {
|
||||
freeaddrinfo(listp);
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
} else {
|
||||
prevp->ai_next = ai;
|
||||
prevp = ai;
|
||||
}
|
||||
}
|
||||
*res = listp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get address info for ipv4 sockets.
|
||||
*
|
||||
* Bugs: - servname can only be a number, not text.
|
||||
*/
|
||||
|
||||
int getaddrinfo(const char *node,
|
||||
const char *service,
|
||||
const struct addrinfo * hintp,
|
||||
struct addrinfo ** res)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
|
||||
/* Setup the hints struct. */
|
||||
if (hintp == NULL) {
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
} else {
|
||||
memcpy(&hints, hintp, sizeof(hints));
|
||||
}
|
||||
|
||||
if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if (hints.ai_socktype == 0) {
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
}
|
||||
|
||||
if (!node && !service) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
if (node[0] == '\0') {
|
||||
return getaddr_info_single_addr(service,
|
||||
INADDR_ANY,
|
||||
&hints,
|
||||
res);
|
||||
} else if (hints.ai_flags & AI_NUMERICHOST) {
|
||||
struct in_addr ip;
|
||||
if (inet_pton(AF_INET, node, &ip) <= 0)
|
||||
return EAI_FAIL;
|
||||
return getaddr_info_single_addr(service,
|
||||
ntohl(ip.s_addr),
|
||||
&hints,
|
||||
res);
|
||||
} else {
|
||||
return getaddr_info_name(node,
|
||||
service,
|
||||
&hints,
|
||||
res);
|
||||
}
|
||||
} else if (hints.ai_flags & AI_PASSIVE) {
|
||||
return getaddr_info_single_addr(service,
|
||||
INADDR_ANY,
|
||||
&hints,
|
||||
res);
|
||||
}
|
||||
return getaddr_info_single_addr(service,
|
||||
INADDR_LOOPBACK,
|
||||
&hints,
|
||||
res);
|
||||
}
|
||||
|
||||
|
||||
void freeaddrinfo(struct addrinfo *res)
|
||||
{
|
||||
struct addrinfo *next = NULL;
|
||||
|
||||
for (;res; res = next) {
|
||||
next = res->ai_next;
|
||||
if (res->ai_canonname) {
|
||||
free(res->ai_canonname);
|
||||
}
|
||||
if (res->ai_addr) {
|
||||
free(res->ai_addr);
|
||||
}
|
||||
free(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *gai_strerror(int errcode)
|
||||
{
|
||||
#ifdef HAVE_HSTRERROR
|
||||
int hcode;
|
||||
|
||||
switch (errcode)
|
||||
{
|
||||
case EAI_NONAME:
|
||||
hcode = HOST_NOT_FOUND;
|
||||
break;
|
||||
case EAI_AGAIN:
|
||||
hcode = TRY_AGAIN;
|
||||
break;
|
||||
case EAI_FAIL:
|
||||
default:
|
||||
hcode = NO_RECOVERY;
|
||||
break;
|
||||
}
|
||||
|
||||
return hstrerror(hcode);
|
||||
#else /* !HAVE_HSTRERROR */
|
||||
|
||||
switch (errcode)
|
||||
{
|
||||
case EAI_NONAME:
|
||||
return "Unknown host";
|
||||
case EAI_AGAIN:
|
||||
return "Host name lookup failure";
|
||||
#ifdef EAI_BADFLAGS
|
||||
case EAI_BADFLAGS:
|
||||
return "Invalid argument";
|
||||
#endif
|
||||
#ifdef EAI_FAMILY
|
||||
case EAI_FAMILY:
|
||||
return "Address family not supported";
|
||||
#endif
|
||||
#ifdef EAI_MEMORY
|
||||
case EAI_MEMORY:
|
||||
return "Not enough memory";
|
||||
#endif
|
||||
#ifdef EAI_NODATA
|
||||
case EAI_NODATA:
|
||||
return "No host data of that type was found";
|
||||
#endif
|
||||
#ifdef EAI_SERVICE
|
||||
case EAI_SERVICE:
|
||||
return "Class type not found";
|
||||
#endif
|
||||
#ifdef EAI_SOCKTYPE
|
||||
case EAI_SOCKTYPE:
|
||||
return "Socket type not supported";
|
||||
#endif
|
||||
default:
|
||||
return "Unknown server error";
|
||||
}
|
||||
#endif /* HAVE_HSTRERROR */
|
||||
}
|
||||
|
||||
static int gethostnameinfo(const struct sockaddr *sa,
|
||||
char *node,
|
||||
size_t nodelen,
|
||||
int flags)
|
||||
{
|
||||
int ret = -1;
|
||||
char *p = NULL;
|
||||
|
||||
if (!(flags & NI_NUMERICHOST)) {
|
||||
struct hostent *hp = gethostbyaddr(
|
||||
(void *)&((struct sockaddr_in *)sa)->sin_addr,
|
||||
sizeof (struct in_addr),
|
||||
sa->sa_family);
|
||||
ret = check_hostent_err(hp);
|
||||
if (ret == 0) {
|
||||
/* Name looked up successfully. */
|
||||
ret = snprintf(node, nodelen, "%s", hp->h_name);
|
||||
if (ret < 0 || (size_t)ret >= nodelen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
if (flags & NI_NOFQDN) {
|
||||
p = strchr(node,'.');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & NI_NAMEREQD) {
|
||||
/* If we require a name and didn't get one,
|
||||
* automatically fail. */
|
||||
return ret;
|
||||
}
|
||||
/* Otherwise just fall into the numeric host code... */
|
||||
}
|
||||
p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
|
||||
ret = snprintf(node, nodelen, "%s", p);
|
||||
if (ret < 0 || (size_t)ret >= nodelen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getservicenameinfo(const struct sockaddr *sa,
|
||||
char *service,
|
||||
size_t servicelen,
|
||||
int flags)
|
||||
{
|
||||
int ret = -1;
|
||||
int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
|
||||
|
||||
if (!(flags & NI_NUMERICSERV)) {
|
||||
struct servent *se = getservbyport(
|
||||
port,
|
||||
(flags & NI_DGRAM) ? "udp" : "tcp");
|
||||
if (se && se->s_name) {
|
||||
/* Service name looked up successfully. */
|
||||
ret = snprintf(service, servicelen, "%s", se->s_name);
|
||||
if (ret < 0 || (size_t)ret >= servicelen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* Otherwise just fall into the numeric service code... */
|
||||
}
|
||||
ret = snprintf(service, servicelen, "%d", port);
|
||||
if (ret < 0 || (size_t)ret >= servicelen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an ipv4 address to a hostname.
|
||||
*
|
||||
* Bugs: - No IPv6 support.
|
||||
*/
|
||||
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
char *node, size_t nodelen,
|
||||
char *service, size_t servicelen, int flags)
|
||||
{
|
||||
|
||||
/* Invalid arguments. */
|
||||
if (sa == NULL || (node == NULL && service == NULL)) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
if (sa->sa_family != AF_INET) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
if (salen < (socklen_t)sizeof (struct sockaddr_in)) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
int ret = gethostnameinfo(sa, node, nodelen, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (service) {
|
||||
return getservicenameinfo(sa, service, servicelen, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
72
rsync/lib/getpass.c
Normal file
72
rsync/lib/getpass.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* An implementation of getpass for systems that lack one.
|
||||
*
|
||||
* Copyright (C) 2013 Roman Donchenko
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
char *getpass(const char *prompt)
|
||||
{
|
||||
static char password[256];
|
||||
|
||||
BOOL tty_changed = False, read_success;
|
||||
struct termios tty_old, tty_new;
|
||||
FILE *in = stdin, *out = stderr;
|
||||
FILE *tty = fopen("/dev/tty", "w+");
|
||||
|
||||
if (tty)
|
||||
in = out = tty;
|
||||
|
||||
if (tcgetattr(fileno(in), &tty_old) == 0) {
|
||||
tty_new = tty_old;
|
||||
tty_new.c_lflag &= ~(ECHO | ISIG);
|
||||
|
||||
if (tcsetattr(fileno(in), TCSAFLUSH, &tty_new) == 0)
|
||||
tty_changed = True;
|
||||
}
|
||||
|
||||
if (!tty_changed)
|
||||
fputs("(WARNING: will be visible) ", out);
|
||||
fputs(prompt, out);
|
||||
fflush(out);
|
||||
|
||||
read_success = fgets(password, sizeof password, in) != NULL;
|
||||
|
||||
/* Print the newline that hasn't been echoed. */
|
||||
fputc('\n', out);
|
||||
|
||||
if (tty_changed)
|
||||
tcsetattr(fileno(in), TCSAFLUSH, &tty_old);
|
||||
|
||||
if (tty)
|
||||
fclose(tty);
|
||||
|
||||
if (read_success) {
|
||||
/* Remove the trailing newline. */
|
||||
size_t password_len = strlen(password);
|
||||
if (password_len && password[password_len - 1] == '\n')
|
||||
password[password_len - 1] = '\0';
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
186
rsync/lib/inet_ntop.c
Normal file
186
rsync/lib/inet_ntop.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#define NS_INT16SZ 2
|
||||
#define NS_IN6ADDRSZ 16
|
||||
|
||||
/*
|
||||
* WARNING: Don't even consider trying to compile this on a system where
|
||||
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
|
||||
*/
|
||||
|
||||
static const char *inet_ntop4(const unsigned char *src, char *dst,
|
||||
size_t size);
|
||||
|
||||
#ifdef AF_INET6
|
||||
static const char *inet_ntop6(const unsigned char *src, char *dst,
|
||||
size_t size);
|
||||
#endif
|
||||
|
||||
/* char *
|
||||
* isc_net_ntop(af, src, dst, size)
|
||||
* convert a network format address to presentation format.
|
||||
* return:
|
||||
* pointer to presentation format address (`dst'), or NULL (see errno).
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
const char *
|
||||
inet_ntop(int af, const void *src, char *dst, size_t size)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_ntop4(src, dst, size));
|
||||
#ifdef AF_INET6
|
||||
case AF_INET6:
|
||||
return (inet_ntop6(src, dst, size));
|
||||
#endif
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return (NULL);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* const char *
|
||||
* inet_ntop4(src, dst, size)
|
||||
* format an IPv4 address
|
||||
* return:
|
||||
* `dst' (as a const)
|
||||
* notes:
|
||||
* (1) uses no statics
|
||||
* (2) takes a unsigned char* not an in_addr as input
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static const char *
|
||||
inet_ntop4(const unsigned char *src, char *dst, size_t size)
|
||||
{
|
||||
static const char *fmt = "%u.%u.%u.%u";
|
||||
char tmp[sizeof "255.255.255.255"];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]);
|
||||
if (len >= size) {
|
||||
errno = ENOSPC;
|
||||
return (NULL);
|
||||
}
|
||||
memcpy(dst, tmp, len + 1);
|
||||
|
||||
return (dst);
|
||||
}
|
||||
|
||||
/* const char *
|
||||
* isc_inet_ntop6(src, dst, size)
|
||||
* convert IPv6 binary address into presentation (printable) format
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
#ifdef AF_INET6
|
||||
static const char *
|
||||
inet_ntop6(const unsigned char *src, char *dst, size_t size)
|
||||
{
|
||||
/*
|
||||
* Note that int32_t and int16_t need only be "at least" large enough
|
||||
* to contain a value of the specified size. On some systems, like
|
||||
* Crays, there is no such thing as an integer variable with 16 bits.
|
||||
* Keep this in mind if you think this function should have been coded
|
||||
* to use pointer overlays. All the world's not a VAX.
|
||||
*/
|
||||
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
|
||||
struct { int base, len; } best, cur;
|
||||
unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
|
||||
int i, inc;
|
||||
|
||||
/*
|
||||
* Preprocess:
|
||||
* Copy the input (bytewise) array into a wordwise array.
|
||||
* Find the longest run of 0x00's in src[] for :: shorthanding.
|
||||
*/
|
||||
memset(words, '\0', sizeof words);
|
||||
for (i = 0; i < NS_IN6ADDRSZ; i++)
|
||||
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
|
||||
best.base = -1;
|
||||
cur.base = -1;
|
||||
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
|
||||
if (words[i] == 0) {
|
||||
if (cur.base == -1)
|
||||
cur.base = i, cur.len = 1;
|
||||
else
|
||||
cur.len++;
|
||||
} else {
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
cur.base = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
}
|
||||
if (best.base != -1 && best.len < 2)
|
||||
best.base = -1;
|
||||
|
||||
/*
|
||||
* Format the result.
|
||||
*/
|
||||
tp = tmp;
|
||||
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
|
||||
/* Are we inside the best run of 0x00's? */
|
||||
if (best.base != -1 && i >= best.base &&
|
||||
i < (best.base + best.len)) {
|
||||
if (i == best.base)
|
||||
*tp++ = ':';
|
||||
continue;
|
||||
}
|
||||
/* Are we following an initial run of 0x00s or any real hex? */
|
||||
if (i != 0)
|
||||
*tp++ = ':';
|
||||
/* Is this address an encapsulated IPv4? */
|
||||
if (i == 6 && best.base == 0 &&
|
||||
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
|
||||
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
|
||||
return (NULL);
|
||||
tp += strlen(tp);
|
||||
break;
|
||||
}
|
||||
inc = snprintf(tp, 5, "%x", words[i]);
|
||||
assert(inc < 5);
|
||||
tp += inc;
|
||||
}
|
||||
/* Was it a trailing run of 0x00's? */
|
||||
if (best.base != -1 && (best.base + best.len) ==
|
||||
(NS_IN6ADDRSZ / NS_INT16SZ))
|
||||
*tp++ = ':';
|
||||
*tp++ = '\0';
|
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done.
|
||||
*/
|
||||
if ((size_t)(tp - tmp) > size) {
|
||||
errno = ENOSPC;
|
||||
return (NULL);
|
||||
}
|
||||
memcpy(dst, tmp, tp - tmp);
|
||||
return (dst);
|
||||
}
|
||||
#endif /* AF_INET6 */
|
212
rsync/lib/inet_pton.c
Normal file
212
rsync/lib/inet_pton.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 1996-2001 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#define NS_INT16SZ 2
|
||||
#define NS_INADDRSZ 4
|
||||
#define NS_IN6ADDRSZ 16
|
||||
|
||||
/*
|
||||
* WARNING: Don't even consider trying to compile this on a system where
|
||||
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
|
||||
*/
|
||||
|
||||
static int inet_pton4(const char *src, unsigned char *dst);
|
||||
#ifdef INET6
|
||||
static int inet_pton6(const char *src, unsigned char *dst);
|
||||
#endif
|
||||
|
||||
/* int
|
||||
* inet_pton(af, src, dst)
|
||||
* convert from presentation format (which usually means ASCII printable)
|
||||
* to network format (which is usually some kind of binary format).
|
||||
* return:
|
||||
* 1 if the address was valid for the specified address family
|
||||
* 0 if the address wasn't valid (`dst' is untouched in this case)
|
||||
* -1 if some other error occurred (`dst' is untouched in this case, too)
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
int
|
||||
inet_pton(int af,
|
||||
const char *src,
|
||||
void *dst)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_pton4(src, dst));
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
return (inet_pton6(src, dst));
|
||||
#endif
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* int
|
||||
* inet_pton4(src, dst)
|
||||
* like inet_aton() but without all the hexadecimal and shorthand.
|
||||
* return:
|
||||
* 1 if `src' is a valid dotted quad, else 0.
|
||||
* notice:
|
||||
* does not touch `dst' unless it's returning 1.
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton4(src, dst)
|
||||
const char *src;
|
||||
unsigned char *dst;
|
||||
{
|
||||
static const char digits[] = "0123456789";
|
||||
int saw_digit, octets, ch;
|
||||
unsigned char tmp[NS_INADDRSZ], *tp;
|
||||
|
||||
saw_digit = 0;
|
||||
octets = 0;
|
||||
*(tp = tmp) = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr(digits, ch)) != NULL) {
|
||||
unsigned int new = *tp * 10 + (pch - digits);
|
||||
|
||||
if (new > 255)
|
||||
return (0);
|
||||
*tp = new;
|
||||
if (! saw_digit) {
|
||||
if (++octets > 4)
|
||||
return (0);
|
||||
saw_digit = 1;
|
||||
}
|
||||
} else if (ch == '.' && saw_digit) {
|
||||
if (octets == 4)
|
||||
return (0);
|
||||
*++tp = 0;
|
||||
saw_digit = 0;
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
if (octets < 4)
|
||||
return (0);
|
||||
memcpy(dst, tmp, NS_INADDRSZ);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* int
|
||||
* inet_pton6(src, dst)
|
||||
* convert presentation level address to network order binary form.
|
||||
* return:
|
||||
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
|
||||
* notice:
|
||||
* (1) does not touch `dst' unless it's returning 1.
|
||||
* (2) :: in a full address is silently ignored.
|
||||
* credit:
|
||||
* inspired by Mark Andrews.
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
#ifdef INET6
|
||||
static int
|
||||
inet_pton6(src, dst)
|
||||
const char *src;
|
||||
unsigned char *dst;
|
||||
{
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
|
||||
const char *xdigits, *curtok;
|
||||
int ch, saw_xdigit;
|
||||
unsigned int val;
|
||||
|
||||
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
|
||||
endp = tp + NS_IN6ADDRSZ;
|
||||
colonp = NULL;
|
||||
/* Leading :: requires some special handling. */
|
||||
if (*src == ':')
|
||||
if (*++src != ':')
|
||||
return (0);
|
||||
curtok = src;
|
||||
saw_xdigit = 0;
|
||||
val = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
|
||||
pch = strchr((xdigits = xdigits_u), ch);
|
||||
if (pch != NULL) {
|
||||
val <<= 4;
|
||||
val |= (pch - xdigits);
|
||||
if (val > 0xffff)
|
||||
return (0);
|
||||
saw_xdigit = 1;
|
||||
continue;
|
||||
}
|
||||
if (ch == ':') {
|
||||
curtok = src;
|
||||
if (!saw_xdigit) {
|
||||
if (colonp)
|
||||
return (0);
|
||||
colonp = tp;
|
||||
continue;
|
||||
}
|
||||
if (tp + NS_INT16SZ > endp)
|
||||
return (0);
|
||||
*tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||
*tp++ = (unsigned char) val & 0xff;
|
||||
saw_xdigit = 0;
|
||||
val = 0;
|
||||
continue;
|
||||
}
|
||||
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
|
||||
inet_pton4(curtok, tp) > 0) {
|
||||
tp += NS_INADDRSZ;
|
||||
saw_xdigit = 0;
|
||||
break; /* '\0' was seen by inet_pton4(). */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (saw_xdigit) {
|
||||
if (tp + NS_INT16SZ > endp)
|
||||
return (0);
|
||||
*tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||
*tp++ = (unsigned char) val & 0xff;
|
||||
}
|
||||
if (colonp != NULL) {
|
||||
/*
|
||||
* Since some memmove()'s erroneously fail to handle
|
||||
* overlapping regions, we'll do the shift by hand.
|
||||
*/
|
||||
const int n = tp - colonp;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
endp[- i] = colonp[n - i];
|
||||
colonp[n - i] = 0;
|
||||
}
|
||||
tp = endp;
|
||||
}
|
||||
if (tp != endp)
|
||||
return (0);
|
||||
memcpy(dst, tmp, NS_IN6ADDRSZ);
|
||||
return (1);
|
||||
}
|
||||
#endif
|
304
rsync/lib/md5.c
Normal file
304
rsync/lib/md5.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
void md5_begin(md_context *ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xEFCDAB89;
|
||||
ctx->C = 0x98BADCFE;
|
||||
ctx->D = 0x10325476;
|
||||
|
||||
ctx->totalN = ctx->totalN2 = 0;
|
||||
}
|
||||
|
||||
static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
|
||||
{
|
||||
uint32 X[16], A, B, C, D;
|
||||
|
||||
A = ctx->A;
|
||||
B = ctx->B;
|
||||
C = ctx->C;
|
||||
D = ctx->D;
|
||||
|
||||
X[0] = IVALu(data, 0);
|
||||
X[1] = IVALu(data, 4);
|
||||
X[2] = IVALu(data, 8);
|
||||
X[3] = IVALu(data, 12);
|
||||
X[4] = IVALu(data, 16);
|
||||
X[5] = IVALu(data, 20);
|
||||
X[6] = IVALu(data, 24);
|
||||
X[7] = IVALu(data, 28);
|
||||
X[8] = IVALu(data, 32);
|
||||
X[9] = IVALu(data, 36);
|
||||
X[10] = IVALu(data, 40);
|
||||
X[11] = IVALu(data, 44);
|
||||
X[12] = IVALu(data, 48);
|
||||
X[13] = IVALu(data, 52);
|
||||
X[14] = IVALu(data, 56);
|
||||
X[15] = IVALu(data, 60);
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) a += F(b,c,d) + X[k] + t, a = S(a,s) + b
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P(A, B, C, D, 0, 7, 0xD76AA478);
|
||||
P(D, A, B, C, 1, 12, 0xE8C7B756);
|
||||
P(C, D, A, B, 2, 17, 0x242070DB);
|
||||
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
|
||||
P(A, B, C, D, 4, 7, 0xF57C0FAF);
|
||||
P(D, A, B, C, 5, 12, 0x4787C62A);
|
||||
P(C, D, A, B, 6, 17, 0xA8304613);
|
||||
P(B, C, D, A, 7, 22, 0xFD469501);
|
||||
P(A, B, C, D, 8, 7, 0x698098D8);
|
||||
P(D, A, B, C, 9, 12, 0x8B44F7AF);
|
||||
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
|
||||
P(B, C, D, A, 11, 22, 0x895CD7BE);
|
||||
P(A, B, C, D, 12, 7, 0x6B901122);
|
||||
P(D, A, B, C, 13, 12, 0xFD987193);
|
||||
P(C, D, A, B, 14, 17, 0xA679438E);
|
||||
P(B, C, D, A, 15, 22, 0x49B40821);
|
||||
|
||||
#undef F
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P(A, B, C, D, 1, 5, 0xF61E2562);
|
||||
P(D, A, B, C, 6, 9, 0xC040B340);
|
||||
P(C, D, A, B, 11, 14, 0x265E5A51);
|
||||
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
|
||||
P(A, B, C, D, 5, 5, 0xD62F105D);
|
||||
P(D, A, B, C, 10, 9, 0x02441453);
|
||||
P(C, D, A, B, 15, 14, 0xD8A1E681);
|
||||
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
|
||||
P(A, B, C, D, 9, 5, 0x21E1CDE6);
|
||||
P(D, A, B, C, 14, 9, 0xC33707D6);
|
||||
P(C, D, A, B, 3, 14, 0xF4D50D87);
|
||||
P(B, C, D, A, 8, 20, 0x455A14ED);
|
||||
P(A, B, C, D, 13, 5, 0xA9E3E905);
|
||||
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
|
||||
P(C, D, A, B, 7, 14, 0x676F02D9);
|
||||
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
|
||||
|
||||
#undef F
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P(A, B, C, D, 5, 4, 0xFFFA3942);
|
||||
P(D, A, B, C, 8, 11, 0x8771F681);
|
||||
P(C, D, A, B, 11, 16, 0x6D9D6122);
|
||||
P(B, C, D, A, 14, 23, 0xFDE5380C);
|
||||
P(A, B, C, D, 1, 4, 0xA4BEEA44);
|
||||
P(D, A, B, C, 4, 11, 0x4BDECFA9);
|
||||
P(C, D, A, B, 7, 16, 0xF6BB4B60);
|
||||
P(B, C, D, A, 10, 23, 0xBEBFBC70);
|
||||
P(A, B, C, D, 13, 4, 0x289B7EC6);
|
||||
P(D, A, B, C, 0, 11, 0xEAA127FA);
|
||||
P(C, D, A, B, 3, 16, 0xD4EF3085);
|
||||
P(B, C, D, A, 6, 23, 0x04881D05);
|
||||
P(A, B, C, D, 9, 4, 0xD9D4D039);
|
||||
P(D, A, B, C, 12, 11, 0xE6DB99E5);
|
||||
P(C, D, A, B, 15, 16, 0x1FA27CF8);
|
||||
P(B, C, D, A, 2, 23, 0xC4AC5665);
|
||||
|
||||
#undef F
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P(A, B, C, D, 0, 6, 0xF4292244);
|
||||
P(D, A, B, C, 7, 10, 0x432AFF97);
|
||||
P(C, D, A, B, 14, 15, 0xAB9423A7);
|
||||
P(B, C, D, A, 5, 21, 0xFC93A039);
|
||||
P(A, B, C, D, 12, 6, 0x655B59C3);
|
||||
P(D, A, B, C, 3, 10, 0x8F0CCC92);
|
||||
P(C, D, A, B, 10, 15, 0xFFEFF47D);
|
||||
P(B, C, D, A, 1, 21, 0x85845DD1);
|
||||
P(A, B, C, D, 8, 6, 0x6FA87E4F);
|
||||
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
|
||||
P(C, D, A, B, 6, 15, 0xA3014314);
|
||||
P(B, C, D, A, 13, 21, 0x4E0811A1);
|
||||
P(A, B, C, D, 4, 6, 0xF7537E82);
|
||||
P(D, A, B, C, 11, 10, 0xBD3AF235);
|
||||
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
|
||||
P(B, C, D, A, 9, 21, 0xEB86D391);
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->A += A;
|
||||
ctx->B += B;
|
||||
ctx->C += C;
|
||||
ctx->D += D;
|
||||
}
|
||||
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
{
|
||||
uint32 left, fill;
|
||||
|
||||
if (!length)
|
||||
return;
|
||||
|
||||
left = ctx->totalN & 0x3F;
|
||||
fill = CSUM_CHUNK - left;
|
||||
|
||||
ctx->totalN += length;
|
||||
ctx->totalN &= 0xFFFFFFFF;
|
||||
|
||||
if (ctx->totalN < length)
|
||||
ctx->totalN2++;
|
||||
|
||||
if (left && length >= fill) {
|
||||
memcpy(ctx->buffer + left, input, fill);
|
||||
md5_process(ctx, ctx->buffer);
|
||||
length -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (length >= CSUM_CHUNK) {
|
||||
md5_process(ctx, input);
|
||||
length -= CSUM_CHUNK;
|
||||
input += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
if (length)
|
||||
memcpy(ctx->buffer + left, input, length);
|
||||
}
|
||||
|
||||
static uchar md5_padding[CSUM_CHUNK] = { 0x80 };
|
||||
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
|
||||
{
|
||||
uint32 last, padn;
|
||||
uint32 high, low;
|
||||
uchar msglen[8];
|
||||
|
||||
high = (ctx->totalN >> 29)
|
||||
| (ctx->totalN2 << 3);
|
||||
low = (ctx->totalN << 3);
|
||||
|
||||
SIVALu(msglen, 0, low);
|
||||
SIVALu(msglen, 4, high);
|
||||
|
||||
last = ctx->totalN & 0x3F;
|
||||
padn = last < 56 ? 56 - last : 120 - last;
|
||||
|
||||
md5_update(ctx, md5_padding, padn);
|
||||
md5_update(ctx, msglen, 8);
|
||||
|
||||
SIVALu(digest, 0, ctx->A);
|
||||
SIVALu(digest, 4, ctx->B);
|
||||
SIVALu(digest, 8, ctx->C);
|
||||
SIVALu(digest, 12, ctx->D);
|
||||
}
|
||||
|
||||
void get_md5(uchar *out, const uchar *input, int n)
|
||||
{
|
||||
md_context ctx;
|
||||
md5_begin(&ctx);
|
||||
md5_update(&ctx, input, n);
|
||||
md5_result(&ctx, out);
|
||||
}
|
||||
|
||||
#ifdef TEST_MD5
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* those are the standard RFC 1321 test vectors
|
||||
*/
|
||||
|
||||
static struct {
|
||||
char *str, *md5;
|
||||
} tests[] = {
|
||||
{ "",
|
||||
"d41d8cd98f00b204e9800998ecf8427e" },
|
||||
{ "a",
|
||||
"0cc175b9c0f1b6a831c399e269772661" },
|
||||
{ "abc",
|
||||
"900150983cd24fb0d6963f7d28e17f72" },
|
||||
{ "message digest",
|
||||
"f96b697d7cb7938d525a2f31aaf161d0" },
|
||||
{ "abcdefghijklmnopqrstuvwxyz",
|
||||
"c3fcd3d76192e4007dfb496cca67e13b" },
|
||||
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
"d174ab98d277d9f5a5611c2c9f419d9f" },
|
||||
{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
||||
"57edf4a22be3c955ac49da2e2107b67a" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *f;
|
||||
int i, j;
|
||||
char output[33];
|
||||
md_context ctx;
|
||||
uchar buf[1000];
|
||||
uchar md5sum[MD5_DIGEST_LEN];
|
||||
|
||||
if (argc < 2) {
|
||||
printf("\nMD5 Validation Tests:\n\n");
|
||||
|
||||
for (i = 0; tests[i].str; i++) {
|
||||
char *str = tests[i].str;
|
||||
char *chk = tests[i].md5;
|
||||
|
||||
printf(" Test %d ", i + 1);
|
||||
|
||||
get_md5(md5sum, str, strlen(str));
|
||||
|
||||
for (j = 0; j < MD5_DIGEST_LEN; j++)
|
||||
sprintf(output + j * 2, "%02x", md5sum[j]);
|
||||
|
||||
if (memcmp(output, chk, 32)) {
|
||||
printf("failed!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("passed.\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (--argc) {
|
||||
if (!(f = fopen(*++argv, "rb"))) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
md5_begin(&ctx);
|
||||
|
||||
while ((i = fread(buf, 1, sizeof buf, f)) > 0)
|
||||
md5_update(&ctx, buf, i);
|
||||
|
||||
md5_result(&ctx, md5sum);
|
||||
|
||||
for (j = 0; j < MD5_DIGEST_LEN; j++)
|
||||
printf("%02x", md5sum[j]);
|
||||
|
||||
printf(" %s\n", *argv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
246
rsync/lib/mdfour.c
Normal file
246
rsync/lib/mdfour.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Unix SMB/Netbios implementation.
|
||||
* Version 1.9.
|
||||
* An implementation of MD4 designed for use in the SMB authentication protocol.
|
||||
*
|
||||
* Copyright (C) 1997-1998 Andrew Tridgell
|
||||
* Copyright (C) 2005-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
/* NOTE: This code makes no attempt to be fast!
|
||||
*
|
||||
* It assumes that a int is at least 32 bits long. */
|
||||
|
||||
static md_context *m;
|
||||
|
||||
#define MASK32 (0xffffffff)
|
||||
|
||||
#define F(X,Y,Z) ((((X)&(Y)) | ((~(X))&(Z))))
|
||||
#define G(X,Y,Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))))
|
||||
#define H(X,Y,Z) (((X)^(Y)^(Z)))
|
||||
#define lshift(x,s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
|
||||
|
||||
#define ROUND1(a,b,c,d,k,s) a = lshift((a + F(b,c,d) + M[k])&MASK32, s)
|
||||
#define ROUND2(a,b,c,d,k,s) a = lshift((a + G(b,c,d) + M[k] + 0x5A827999)&MASK32,s)
|
||||
#define ROUND3(a,b,c,d,k,s) a = lshift((a + H(b,c,d) + M[k] + 0x6ED9EBA1)&MASK32,s)
|
||||
|
||||
/* this applies md4 to 64 byte chunks */
|
||||
static void mdfour64(uint32 *M)
|
||||
{
|
||||
uint32 AA, BB, CC, DD;
|
||||
uint32 A,B,C,D;
|
||||
|
||||
A = m->A; B = m->B; C = m->C; D = m->D;
|
||||
AA = A; BB = B; CC = C; DD = D;
|
||||
|
||||
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
|
||||
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
|
||||
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
|
||||
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
|
||||
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
|
||||
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
|
||||
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
|
||||
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
|
||||
|
||||
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
|
||||
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
|
||||
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
|
||||
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
|
||||
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
|
||||
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
|
||||
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
|
||||
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
|
||||
|
||||
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
|
||||
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
|
||||
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
|
||||
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
|
||||
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
|
||||
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
|
||||
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
|
||||
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
|
||||
|
||||
A += AA; B += BB;
|
||||
C += CC; D += DD;
|
||||
|
||||
A &= MASK32; B &= MASK32;
|
||||
C &= MASK32; D &= MASK32;
|
||||
|
||||
m->A = A; m->B = B; m->C = C; m->D = D;
|
||||
}
|
||||
|
||||
static void copy64(uint32 *M, const uchar *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MD4_DIGEST_LEN; i++) {
|
||||
M[i] = (in[i*4+3] << 24) | (in[i*4+2] << 16)
|
||||
| (in[i*4+1] << 8) | (in[i*4+0] << 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void copy4(uchar *out,uint32 x)
|
||||
{
|
||||
out[0] = x&0xFF;
|
||||
out[1] = (x>>8)&0xFF;
|
||||
out[2] = (x>>16)&0xFF;
|
||||
out[3] = (x>>24)&0xFF;
|
||||
}
|
||||
|
||||
void mdfour_begin(md_context *md)
|
||||
{
|
||||
md->A = 0x67452301;
|
||||
md->B = 0xefcdab89;
|
||||
md->C = 0x98badcfe;
|
||||
md->D = 0x10325476;
|
||||
md->totalN = 0;
|
||||
md->totalN2 = 0;
|
||||
}
|
||||
|
||||
static void mdfour_tail(const uchar *in, uint32 length)
|
||||
{
|
||||
uchar buf[128];
|
||||
uint32 M[16];
|
||||
extern int protocol_version;
|
||||
|
||||
/*
|
||||
* Count total number of bits, modulo 2^64
|
||||
*/
|
||||
m->totalN += length << 3;
|
||||
if (m->totalN < (length << 3))
|
||||
m->totalN2++;
|
||||
m->totalN2 += length >> 29;
|
||||
|
||||
memset(buf, 0, 128);
|
||||
if (length)
|
||||
memcpy(buf, in, length);
|
||||
buf[length] = 0x80;
|
||||
|
||||
if (length <= 55) {
|
||||
copy4(buf+56, m->totalN);
|
||||
/*
|
||||
* Prior to protocol version 27 only the number of bits
|
||||
* modulo 2^32 was included. MD4 requires the number
|
||||
* of bits modulo 2^64, which was fixed starting with
|
||||
* protocol version 27.
|
||||
*/
|
||||
if (protocol_version >= 27)
|
||||
copy4(buf+60, m->totalN2);
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
} else {
|
||||
copy4(buf+120, m->totalN);
|
||||
/*
|
||||
* Prior to protocol version 27 only the number of bits
|
||||
* modulo 2^32 was included. MD4 requires the number
|
||||
* of bits modulo 2^64, which was fixed starting with
|
||||
* protocol version 27.
|
||||
*/
|
||||
if (protocol_version >= 27)
|
||||
copy4(buf+124, m->totalN2);
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
copy64(M, buf+64);
|
||||
mdfour64(M);
|
||||
}
|
||||
}
|
||||
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length)
|
||||
{
|
||||
uint32 M[16];
|
||||
|
||||
m = md;
|
||||
|
||||
if (length == 0)
|
||||
mdfour_tail(in, length);
|
||||
|
||||
while (length >= 64) {
|
||||
copy64(M, in);
|
||||
mdfour64(M);
|
||||
in += 64;
|
||||
length -= 64;
|
||||
m->totalN += 64 << 3;
|
||||
if (m->totalN < 64 << 3)
|
||||
m->totalN2++;
|
||||
}
|
||||
|
||||
if (length)
|
||||
mdfour_tail(in, length);
|
||||
}
|
||||
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN])
|
||||
{
|
||||
m = md;
|
||||
|
||||
copy4(digest, m->A);
|
||||
copy4(digest+4, m->B);
|
||||
copy4(digest+8, m->C);
|
||||
copy4(digest+12, m->D);
|
||||
}
|
||||
|
||||
void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length)
|
||||
{
|
||||
md_context md;
|
||||
mdfour_begin(&md);
|
||||
mdfour_update(&md, in, length);
|
||||
mdfour_result(&md, digest);
|
||||
}
|
||||
|
||||
#ifdef TEST_MDFOUR
|
||||
int protocol_version = 28;
|
||||
|
||||
static void file_checksum1(char *fname)
|
||||
{
|
||||
int fd, i, was_multiple_of_64 = 1;
|
||||
md_context md;
|
||||
uchar buf[64*1024], sum[MD4_DIGEST_LEN];
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("fname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mdfour_begin(&md);
|
||||
|
||||
while (1) {
|
||||
int n = read(fd, buf, sizeof buf);
|
||||
if (n <= 0)
|
||||
break;
|
||||
was_multiple_of_64 = !(n % 64);
|
||||
mdfour_update(&md, buf, n);
|
||||
}
|
||||
if (was_multiple_of_64 && protocol_version >= 27)
|
||||
mdfour_update(&md, buf, 0);
|
||||
|
||||
close(fd);
|
||||
|
||||
mdfour_result(&md, sum);
|
||||
|
||||
for (i = 0; i < MD4_DIGEST_LEN; i++)
|
||||
printf("%02X", sum[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
while (--argc)
|
||||
file_checksum1(*++argv);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
26
rsync/lib/mdigest.h
Normal file
26
rsync/lib/mdigest.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* The include file for both the MD4 and MD5 routines. */
|
||||
|
||||
#define MD4_DIGEST_LEN 16
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
typedef struct {
|
||||
uint32 A, B, C, D;
|
||||
uint32 totalN; /* bit count, lower 32 bits */
|
||||
uint32 totalN2; /* bit count, upper 32 bits */
|
||||
uchar buffer[CSUM_CHUNK];
|
||||
} md_context;
|
||||
|
||||
void mdfour_begin(md_context *md);
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length);
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]);
|
||||
|
||||
void get_mdfour(uchar digest[MD4_DIGEST_LEN], const uchar *in, int length);
|
||||
|
||||
void md5_begin(md_context *ctx);
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length);
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]);
|
||||
|
||||
void get_md5(uchar digest[MD5_DIGEST_LEN], const uchar *input, int n);
|
65
rsync/lib/permstring.c
Normal file
65
rsync/lib/permstring.c
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* A single utility routine.
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
/* Produce a string representation of Unix mode bits like that used by ls(1).
|
||||
* The "buf" buffer must be at least 11 characters. */
|
||||
void permstring(char *perms, mode_t mode)
|
||||
{
|
||||
static const char *perm_map = "rwxrwxrwx";
|
||||
int i;
|
||||
|
||||
strlcpy(perms, "----------", 11);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
if (mode & (1 << i))
|
||||
perms[9-i] = perm_map[8-i];
|
||||
}
|
||||
|
||||
/* Handle setuid/sticky bits. You might think the indices are
|
||||
* off by one, but remember there's a type char at the
|
||||
* start. */
|
||||
if (mode & S_ISUID)
|
||||
perms[3] = (mode & S_IXUSR) ? 's' : 'S';
|
||||
|
||||
if (mode & S_ISGID)
|
||||
perms[6] = (mode & S_IXGRP) ? 's' : 'S';
|
||||
|
||||
#ifdef S_ISVTX
|
||||
if (mode & S_ISVTX)
|
||||
perms[9] = (mode & S_IXOTH) ? 't' : 'T';
|
||||
#endif
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
perms[0] = 'd';
|
||||
else if (S_ISLNK(mode))
|
||||
perms[0] = 'l';
|
||||
else if (S_ISBLK(mode))
|
||||
perms[0] = 'b';
|
||||
else if (S_ISCHR(mode))
|
||||
perms[0] = 'c';
|
||||
else if (S_ISSOCK(mode))
|
||||
perms[0] = 's';
|
||||
else if (S_ISFIFO(mode))
|
||||
perms[0] = 'p';
|
||||
}
|
3
rsync/lib/permstring.h
Normal file
3
rsync/lib/permstring.h
Normal file
@ -0,0 +1,3 @@
|
||||
#define PERMSTRING_SIZE 11
|
||||
|
||||
void permstring(char *perms, mode_t mode);
|
268
rsync/lib/pool_alloc.3
Normal file
268
rsync/lib/pool_alloc.3
Normal file
@ -0,0 +1,268 @@
|
||||
.ds d \-\^\-
|
||||
.ds o \fR[\fP
|
||||
.ds c \fR]\fP
|
||||
.ds | \fR|\fP
|
||||
.de D
|
||||
\\.B \*d\\$1
|
||||
..
|
||||
.de DI
|
||||
\\.BI \*d\\$1 \\$2
|
||||
..
|
||||
.de DR
|
||||
\\.BR \*d\\$1 \\$2
|
||||
..
|
||||
.de Di
|
||||
\\.BI \*d\\$1 " \\$2"
|
||||
..
|
||||
.de Db
|
||||
\\.B \*d\\$1 " \\$2"
|
||||
..
|
||||
.de Df
|
||||
\\.B \*d\*ono\*c\\$1
|
||||
..
|
||||
.de See
|
||||
See \fB\\$1\fP for details.
|
||||
..
|
||||
.de SeeIn
|
||||
See \fB\\$1\fP in \fB\\$2\fP for details.
|
||||
..
|
||||
.TH POOL_ALLOC 3
|
||||
.SH NAME
|
||||
pool_alloc, pool_free, pool_free_old, pool_talloc, pool_tfree, pool_create, pool_destroy, pool_boundary
|
||||
\- Allocate and free memory in managed allocation pools.
|
||||
.SH SYNOPSIS
|
||||
.B #include "pool_alloc.h"
|
||||
|
||||
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char *), int \fIflags\fB);
|
||||
|
||||
\fBvoid pool_destroy(struct alloc_pool *\fIpool\fB);
|
||||
|
||||
\fBvoid *pool_alloc(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, char *\fImsg\fB);
|
||||
|
||||
\fBvoid pool_free(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid pool_free_old(struct alloc_pool *\fIpool\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid *pool_talloc(struct alloc_pool *\fIpool\fB, \fItype\fB), int \fIcount\fB, char *\fImsg\fB);
|
||||
|
||||
\fBvoid pool_tfree(struct alloc_pool *\fIpool\fB, \fItype\fB, int \fIcount\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid pool_boundary(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB);
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
The pool allocation routines use
|
||||
.B malloc()
|
||||
for underlying memory management.
|
||||
What allocation pools do is cause memory within a given pool
|
||||
to be allocated in large contiguous blocks
|
||||
(called extents) that will be reusable when freed. Unlike
|
||||
.BR malloc() ,
|
||||
the allocations are not managed individually.
|
||||
Instead, each extent tracks the total free memory within the
|
||||
extent. Each extent can either be used to allocate memory
|
||||
or to manage the freeing of memory within that extent.
|
||||
When an extent has less free memory than a given
|
||||
allocation request, the current extent ceases to be used
|
||||
for allocation. See also the
|
||||
.B pool_boundary()
|
||||
function.
|
||||
.P
|
||||
This form of memory management is suited to large numbers of small
|
||||
related allocations that are held for a while
|
||||
and then freed as a group.
|
||||
Because the
|
||||
underlying allocations are done in large contiguous extents,
|
||||
when an extent is freed, it can release a large enough
|
||||
contiguous block of memory to allow the memory to be returned
|
||||
to the OS for use by whatever program needs it.
|
||||
You can allocate from one or more memory pools and/or
|
||||
.B malloc()
|
||||
all at the same time without interfering with how pools work.
|
||||
.P
|
||||
.B pool_create()
|
||||
Creates an allocation pool for subsequent calls to the pool
|
||||
allocation functions.
|
||||
When an extent is created for allocations it will be
|
||||
.I size
|
||||
bytes.
|
||||
Allocations from the pool have their sizes rounded up to a
|
||||
multiple of
|
||||
.I quantum
|
||||
bytes in length.
|
||||
Specifying
|
||||
.B 0
|
||||
for
|
||||
.I quantum
|
||||
will produce a quantum that should meet maximal alignment
|
||||
on most platforms.
|
||||
Unless
|
||||
.B POOL_NO_QALIGN
|
||||
is set in the
|
||||
.IR flags ,
|
||||
allocations will be aligned to addresses that are a
|
||||
multiple of
|
||||
.IR quantum .
|
||||
A
|
||||
.B NULL
|
||||
may be specified for the
|
||||
.I bomb
|
||||
function pointer if it is not needed. (See the
|
||||
.B pool_alloc()
|
||||
function for how it is used.)
|
||||
If
|
||||
.B POOL_CLEAR
|
||||
is set in the
|
||||
.IR flags ,
|
||||
all allocations from the pool will be initialized to zeros.
|
||||
If either
|
||||
.B POOL_PREPEND
|
||||
or
|
||||
.B POOL_INTERN
|
||||
is specified in the
|
||||
.IR flags ,
|
||||
each extent's data structure will be allocated at the start of the
|
||||
.IR size -length
|
||||
buffer (rather than as a separate, non-pool allocation), with the
|
||||
former extending the
|
||||
.I size
|
||||
to hold the structure, and the latter subtracting the structure's
|
||||
length from the indicated
|
||||
.IR size .
|
||||
.P
|
||||
.B pool_destroy()
|
||||
destroys an allocation
|
||||
.I pool
|
||||
and frees all its associated memory.
|
||||
.P
|
||||
.B pool_alloc()
|
||||
allocates
|
||||
.I size
|
||||
bytes from the specified
|
||||
.IR pool .
|
||||
If
|
||||
.I size
|
||||
is
|
||||
.BR 0 ,
|
||||
.I quantum
|
||||
bytes will be allocated.
|
||||
If the pool has been created without
|
||||
.BR POOL_NO_QALIGN ,
|
||||
every chunk of memory that is returned will be suitably aligned.
|
||||
You can use this with the default
|
||||
.I quantum
|
||||
size to ensure that all memory can store a variable of any type.
|
||||
If the requested memory cannot be allocated, the
|
||||
.I bomb()
|
||||
function will be called with
|
||||
.I msg
|
||||
as its sole argument (if the function was defined at the time
|
||||
the pool was created), and then a
|
||||
.B NULL
|
||||
address is returned (assuming that the bomb function didn't exit).
|
||||
.P
|
||||
.B pool_free()
|
||||
frees
|
||||
.I size
|
||||
bytes pointed to by an
|
||||
.I addr
|
||||
that was previously allocated in the specified
|
||||
.IR pool .
|
||||
If
|
||||
.I size
|
||||
is
|
||||
.BR 0 ,
|
||||
.I quantum
|
||||
bytes will be freed.
|
||||
The memory freed within an extent will not be reusable until
|
||||
all of the memory in that extent has been freed with one
|
||||
exception: the most recent pool allocation may be freed back
|
||||
into the pool prior to making any further allocations.
|
||||
If enough free calls are made to indicate that an extent has no
|
||||
remaining allocated objects (as computed by the total freed size for
|
||||
an extent), its memory will be completely freed back to the system.
|
||||
If
|
||||
.I addr
|
||||
is
|
||||
.BR NULL ,
|
||||
no memory will be freed, but subsequent allocations will come
|
||||
from a new extent.
|
||||
.P
|
||||
.B pool_free_old()
|
||||
takes a boundary
|
||||
.I addr
|
||||
value that was returned by
|
||||
.B pool_boundary()
|
||||
and frees up any extents in the
|
||||
.I pool
|
||||
that have data allocated from that point backward in time.
|
||||
NOTE: you must NOT mix calls to both
|
||||
.B pool_free
|
||||
and
|
||||
.B pool_free_old
|
||||
on the same pool!
|
||||
.P
|
||||
.B pool_boundary()
|
||||
asks for a boundary value that can be sent to
|
||||
.B pool_free_old()
|
||||
at a later time to free up all memory allocated prior to a particular
|
||||
moment in time.
|
||||
If the extent that holds the boundary point has allocations from after the
|
||||
boundary point, it will not be freed until a future
|
||||
.B pool_free_old()
|
||||
call encompasses the entirety of the extent's data.
|
||||
If
|
||||
.I len
|
||||
is non-zero, the call will also check if the active extent has at least
|
||||
that much free memory available in it, and if not, it will mark the
|
||||
extent as inactive, forcing a new extent to be used for future allocations.
|
||||
(You can specify -1 for
|
||||
.I len
|
||||
if you want to force a new extent to start.)
|
||||
.P
|
||||
.B pool_talloc()
|
||||
is a macro that takes a
|
||||
.I type
|
||||
and a
|
||||
.I count
|
||||
instead of a
|
||||
.IR size .
|
||||
It casts the return value to the correct pointer type.
|
||||
.P
|
||||
.B pool_tfree
|
||||
is a macro that calls
|
||||
.B pool_free
|
||||
on memory that was allocated by
|
||||
.BR pool_talloc() .
|
||||
.SH RETURN VALUE
|
||||
.B pool_create()
|
||||
returns a pointer to
|
||||
.BR "struct alloc_pool" .
|
||||
.P
|
||||
.B pool_alloc()
|
||||
and
|
||||
.B pool_talloc()
|
||||
return pointers to the allocated memory,
|
||||
or NULL if the request fails.
|
||||
The return type of
|
||||
.B pool_alloc()
|
||||
will normally require casting to the desired type but
|
||||
.B pool_talloc()
|
||||
will returns a pointer of the requested
|
||||
.IR type .
|
||||
.P
|
||||
.B pool_boundary()
|
||||
returns a pointer that should only be used in a call to
|
||||
.BR pool_free_old() .
|
||||
.P
|
||||
.BR pool_free() ,
|
||||
.BR pool_free_old() ,
|
||||
.B pool_tfree()
|
||||
and
|
||||
.B pool_destroy()
|
||||
return no value.
|
||||
.SH SEE ALSO
|
||||
.nf
|
||||
malloc(3)
|
||||
.SH AUTHOR
|
||||
pool_alloc was created by J.W. Schultz of Pegasystems Technologies.
|
||||
.SH BUGS AND ISSUES
|
376
rsync/lib/pool_alloc.c
Normal file
376
rsync/lib/pool_alloc.c
Normal file
@ -0,0 +1,376 @@
|
||||
#include "rsync.h"
|
||||
|
||||
#define POOL_DEF_EXTENT (32 * 1024)
|
||||
|
||||
#define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */
|
||||
|
||||
struct alloc_pool
|
||||
{
|
||||
size_t size; /* extent size */
|
||||
size_t quantum; /* allocation quantum */
|
||||
struct pool_extent *extents; /* top extent is "live" */
|
||||
void (*bomb)(); /* function to call if
|
||||
* malloc fails */
|
||||
int flags;
|
||||
|
||||
/* statistical data */
|
||||
unsigned long e_created; /* extents created */
|
||||
unsigned long e_freed; /* extents destroyed */
|
||||
int64 n_allocated; /* calls to alloc */
|
||||
int64 n_freed; /* calls to free */
|
||||
int64 b_allocated; /* cum. bytes allocated */
|
||||
int64 b_freed; /* cum. bytes freed */
|
||||
};
|
||||
|
||||
struct pool_extent
|
||||
{
|
||||
struct pool_extent *next;
|
||||
void *start; /* starting address */
|
||||
size_t free; /* free bytecount */
|
||||
size_t bound; /* trapped free bytes */
|
||||
};
|
||||
|
||||
struct align_test {
|
||||
uchar foo;
|
||||
union {
|
||||
int64 i;
|
||||
void *p;
|
||||
} bar;
|
||||
};
|
||||
|
||||
#define MINALIGN offsetof(struct align_test, bar)
|
||||
|
||||
/* Temporarily cast a void* var into a char* var when adding an offset (to
|
||||
* keep some compilers from complaining about the pointer arithmetic). */
|
||||
#define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
|
||||
|
||||
alloc_pool_t
|
||||
pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
|
||||
{
|
||||
struct alloc_pool *pool;
|
||||
|
||||
if (!(pool = new0(struct alloc_pool)))
|
||||
return NULL;
|
||||
|
||||
if ((MINALIGN & (MINALIGN - 1)) != 0) {
|
||||
if (bomb)
|
||||
(*bomb)("Compiler error: MINALIGN is not a power of 2\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!size)
|
||||
size = POOL_DEF_EXTENT;
|
||||
if (!quantum)
|
||||
quantum = MINALIGN;
|
||||
|
||||
if (flags & POOL_INTERN) {
|
||||
if (size <= sizeof (struct pool_extent))
|
||||
size = quantum;
|
||||
else
|
||||
size -= sizeof (struct pool_extent);
|
||||
flags |= POOL_PREPEND;
|
||||
}
|
||||
|
||||
if (quantum <= 1)
|
||||
flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2;
|
||||
else if (!(flags & POOL_NO_QALIGN)) {
|
||||
if (size % quantum)
|
||||
size += quantum - size % quantum;
|
||||
/* If quantum is a power of 2, we'll avoid using modulus. */
|
||||
if (!(quantum & (quantum - 1)))
|
||||
flags |= POOL_QALIGN_P2;
|
||||
}
|
||||
|
||||
pool->size = size;
|
||||
pool->quantum = quantum;
|
||||
pool->bomb = bomb;
|
||||
pool->flags = flags;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
void
|
||||
pool_destroy(alloc_pool_t p)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur, *next;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
for (cur = pool->extents; cur; cur = next) {
|
||||
next = cur->next;
|
||||
if (pool->flags & POOL_PREPEND)
|
||||
free(PTR_ADD(cur->start, -sizeof (struct pool_extent)));
|
||||
else {
|
||||
free(cur->start);
|
||||
free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
free(pool);
|
||||
}
|
||||
|
||||
void *
|
||||
pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
if (!len)
|
||||
len = pool->quantum;
|
||||
else if (pool->flags & POOL_QALIGN_P2) {
|
||||
if (len & (pool->quantum - 1))
|
||||
len += pool->quantum - (len & (pool->quantum - 1));
|
||||
} else if (!(pool->flags & POOL_NO_QALIGN)) {
|
||||
if (len % pool->quantum)
|
||||
len += pool->quantum - len % pool->quantum;
|
||||
}
|
||||
|
||||
if (len > pool->size)
|
||||
goto bomb_out;
|
||||
|
||||
if (!pool->extents || len > pool->extents->free) {
|
||||
void *start;
|
||||
size_t asize;
|
||||
struct pool_extent *ext;
|
||||
|
||||
asize = pool->size;
|
||||
if (pool->flags & POOL_PREPEND)
|
||||
asize += sizeof (struct pool_extent);
|
||||
|
||||
if (!(start = new_array(char, asize)))
|
||||
goto bomb_out;
|
||||
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(start, 0, asize);
|
||||
|
||||
if (pool->flags & POOL_PREPEND) {
|
||||
ext = start;
|
||||
start = PTR_ADD(start, sizeof (struct pool_extent));
|
||||
} else if (!(ext = new(struct pool_extent)))
|
||||
goto bomb_out;
|
||||
ext->start = start;
|
||||
ext->free = pool->size;
|
||||
ext->bound = 0;
|
||||
ext->next = pool->extents;
|
||||
pool->extents = ext;
|
||||
|
||||
pool->e_created++;
|
||||
}
|
||||
|
||||
pool->n_allocated++;
|
||||
pool->b_allocated += len;
|
||||
|
||||
pool->extents->free -= len;
|
||||
|
||||
return PTR_ADD(pool->extents->start, pool->extents->free);
|
||||
|
||||
bomb_out:
|
||||
if (pool->bomb)
|
||||
(*pool->bomb)(bomb_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This function allows you to declare memory in the pool that you are done
|
||||
* using. If you free all the memory in a pool's extent, that extent will
|
||||
* be freed. */
|
||||
void
|
||||
pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *)p;
|
||||
struct pool_extent *cur, *prev;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
if (!addr) {
|
||||
/* A NULL addr starts a fresh extent for new allocations. */
|
||||
if ((cur = pool->extents) != NULL && cur->free != pool->size) {
|
||||
cur->bound += cur->free;
|
||||
cur->free = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
len = pool->quantum;
|
||||
else if (pool->flags & POOL_QALIGN_P2) {
|
||||
if (len & (pool->quantum - 1))
|
||||
len += pool->quantum - (len & (pool->quantum - 1));
|
||||
} else if (!(pool->flags & POOL_NO_QALIGN)) {
|
||||
if (len % pool->quantum)
|
||||
len += pool->quantum - len % pool->quantum;
|
||||
}
|
||||
|
||||
pool->n_freed++;
|
||||
pool->b_freed += len;
|
||||
|
||||
for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
|
||||
if (addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
break;
|
||||
}
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
if (!prev) {
|
||||
/* The "live" extent is kept ready for more allocations. */
|
||||
if (cur->free + cur->bound + len >= pool->size) {
|
||||
if (pool->flags & POOL_CLEAR) {
|
||||
memset(PTR_ADD(cur->start, cur->free), 0,
|
||||
pool->size - cur->free);
|
||||
}
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
} else if (addr == PTR_ADD(cur->start, cur->free)) {
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, len);
|
||||
cur->free += len;
|
||||
} else
|
||||
cur->bound += len;
|
||||
} else {
|
||||
cur->bound += len;
|
||||
|
||||
if (cur->free + cur->bound >= pool->size) {
|
||||
prev->next = cur->next;
|
||||
if (pool->flags & POOL_PREPEND)
|
||||
free(PTR_ADD(cur->start, -sizeof (struct pool_extent)));
|
||||
else {
|
||||
free(cur->start);
|
||||
free(cur);
|
||||
}
|
||||
pool->e_freed++;
|
||||
} else if (prev != pool->extents) {
|
||||
/* Move the extent to be the first non-live extent. */
|
||||
prev->next = cur->next;
|
||||
cur->next = pool->extents->next;
|
||||
pool->extents->next = cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This allows you to declare that the given address marks the edge of some
|
||||
* pool memory that is no longer needed. Any extents that hold only data
|
||||
* older than the boundary address are freed. NOTE: You MUST NOT USE BOTH
|
||||
* pool_free() and pool_free_old() on the same pool!! */
|
||||
void
|
||||
pool_free_old(alloc_pool_t p, void *addr)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *)p;
|
||||
struct pool_extent *cur, *prev, *next;
|
||||
|
||||
if (!pool || !addr)
|
||||
return;
|
||||
|
||||
for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
|
||||
if (addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
break;
|
||||
}
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
if (addr == PTR_ADD(cur->start, cur->free)) {
|
||||
if (prev) {
|
||||
prev->next = NULL;
|
||||
next = cur;
|
||||
} else {
|
||||
/* The most recent live extent can just be reset. */
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, pool->size - cur->free);
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
next = cur->next;
|
||||
cur->next = NULL;
|
||||
}
|
||||
} else {
|
||||
next = cur->next;
|
||||
cur->next = NULL;
|
||||
}
|
||||
|
||||
while ((cur = next) != NULL) {
|
||||
next = cur->next;
|
||||
if (pool->flags & POOL_PREPEND)
|
||||
free(PTR_ADD(cur->start, -sizeof (struct pool_extent)));
|
||||
else {
|
||||
free(cur->start);
|
||||
free(cur);
|
||||
}
|
||||
pool->e_freed++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the current extent doesn't have "len" free space in it, mark it as full
|
||||
* so that the next alloc will start a new extent. If len is (size_t)-1, this
|
||||
* bump will always occur. The function returns a boundary address that can
|
||||
* be used with pool_free_old(), or a NULL if no memory is allocated. */
|
||||
void *
|
||||
pool_boundary(alloc_pool_t p, size_t len)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *)p;
|
||||
struct pool_extent *cur;
|
||||
|
||||
if (!pool || !pool->extents)
|
||||
return NULL;
|
||||
|
||||
cur = pool->extents;
|
||||
|
||||
if (cur->free < len) {
|
||||
cur->bound += cur->free;
|
||||
cur->free = 0;
|
||||
}
|
||||
|
||||
return PTR_ADD(cur->start, cur->free);
|
||||
}
|
||||
|
||||
#define FDPRINT(label, value) \
|
||||
do { \
|
||||
int len = snprintf(buf, sizeof buf, label, value); \
|
||||
if (write(fd, buf, len) != len) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
|
||||
#define FDEXTSTAT(ext) \
|
||||
do { \
|
||||
int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \
|
||||
(long)ext->free, (long)ext->bound); \
|
||||
if (write(fd, buf, len) != len) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur;
|
||||
char buf[BUFSIZ];
|
||||
int ret = 0;
|
||||
|
||||
if (!pool)
|
||||
return ret;
|
||||
|
||||
FDPRINT(" Extent size: %12ld\n", (long) pool->size);
|
||||
FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
|
||||
FDPRINT(" Extents created: %12ld\n", pool->e_created);
|
||||
FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
|
||||
FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
|
||||
FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
|
||||
FDPRINT(" Bytes allocated: %12.0f\n", (double) pool->b_allocated);
|
||||
FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed);
|
||||
|
||||
if (summarize)
|
||||
return ret;
|
||||
|
||||
if (!pool->extents)
|
||||
return ret;
|
||||
|
||||
if (write(fd, "\n", 1) != 1)
|
||||
ret = -1;
|
||||
|
||||
for (cur = pool->extents; cur; cur = cur->next)
|
||||
FDEXTSTAT(cur);
|
||||
|
||||
return ret;
|
||||
}
|
21
rsync/lib/pool_alloc.h
Normal file
21
rsync/lib/pool_alloc.h
Normal file
@ -0,0 +1,21 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#define POOL_CLEAR (1<<0) /* zero fill allocations */
|
||||
#define POOL_NO_QALIGN (1<<1) /* don't align data to quanta */
|
||||
#define POOL_INTERN (1<<2) /* Allocate extent structures */
|
||||
#define POOL_PREPEND (1<<3) /* or prepend to extent data */
|
||||
|
||||
typedef void *alloc_pool_t;
|
||||
|
||||
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags);
|
||||
void pool_destroy(alloc_pool_t pool);
|
||||
void *pool_alloc(alloc_pool_t pool, size_t size, const char *bomb_msg);
|
||||
void pool_free(alloc_pool_t pool, size_t size, void *addr);
|
||||
void pool_free_old(alloc_pool_t pool, void *addr);
|
||||
void *pool_boundary(alloc_pool_t pool, size_t size);
|
||||
|
||||
#define pool_talloc(pool, type, count, bomb_msg) \
|
||||
((type *)pool_alloc(pool, sizeof(type) * count, bomb_msg))
|
||||
|
||||
#define pool_tfree(pool, type, count, addr) \
|
||||
(pool_free(pool, sizeof(type) * count, addr))
|
1512
rsync/lib/snprintf.c
Normal file
1512
rsync/lib/snprintf.c
Normal file
File diff suppressed because it is too large
Load Diff
2796
rsync/lib/sysacls.c
Normal file
2796
rsync/lib/sysacls.c
Normal file
File diff suppressed because it is too large
Load Diff
305
rsync/lib/sysacls.h
Normal file
305
rsync/lib/sysacls.h
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Unix SMB/Netbios implementation.
|
||||
* Version 2.2.x
|
||||
* Portable SMB ACL interface
|
||||
* Copyright (C) Jeremy Allison 2000
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
|
||||
#ifdef HAVE_SYS_ACL_H
|
||||
#include <sys/acl.h>
|
||||
#endif
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
#include <acl/libacl.h>
|
||||
#endif
|
||||
|
||||
#define SMB_MALLOC(cnt) new_array(char, cnt)
|
||||
#define SMB_MALLOC_P(obj) new_array(obj, 1)
|
||||
#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt)
|
||||
#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt)
|
||||
#define slprintf snprintf
|
||||
|
||||
#if defined HAVE_POSIX_ACLS /*-----------------------------------------------*/
|
||||
|
||||
/* This is an identity mapping (just remove the SMB_). */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACL_USER
|
||||
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
|
||||
#define SMB_ACL_GROUP ACL_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
|
||||
#define SMB_ACL_OTHER ACL_OTHER
|
||||
#define SMB_ACL_MASK ACL_MASK
|
||||
|
||||
#define SMB_ACL_T acl_t
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
|
||||
#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_TRU64_ACLS /*---------------------------------------------*/
|
||||
|
||||
/* This is for DEC/Compaq Tru64 UNIX */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACL_USER
|
||||
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
|
||||
#define SMB_ACL_GROUP ACL_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
|
||||
#define SMB_ACL_OTHER ACL_OTHER
|
||||
#define SMB_ACL_MASK ACL_MASK
|
||||
|
||||
#define SMB_ACL_T acl_t
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS /*-------------*/
|
||||
|
||||
/* Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
|
||||
* Modified by Toomas Soome <tsoome@ut.ee> for Solaris. */
|
||||
|
||||
/* SVR4.2 ES/MP ACLs */
|
||||
typedef int SMB_ACL_TAG_T;
|
||||
typedef int SMB_ACL_TYPE_T;
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER USER
|
||||
#define SMB_ACL_USER_OBJ USER_OBJ
|
||||
#define SMB_ACL_GROUP GROUP
|
||||
#define SMB_ACL_GROUP_OBJ GROUP_OBJ
|
||||
#define SMB_ACL_OTHER OTHER_OBJ
|
||||
#define SMB_ACL_MASK CLASS_OBJ
|
||||
|
||||
typedef struct SMB_ACL_T {
|
||||
int size;
|
||||
int count;
|
||||
int next;
|
||||
struct acl acl[1];
|
||||
} *SMB_ACL_T;
|
||||
|
||||
typedef struct acl *SMB_ACL_ENTRY_T;
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS 0
|
||||
#define SMB_ACL_TYPE_DEFAULT 1
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#define SMB_ACL_LOSES_SPECIAL_MODE_BITS
|
||||
#endif
|
||||
|
||||
#elif defined HAVE_HPUX_ACLS /*----------------------------------------------*/
|
||||
|
||||
/* Based on the Solaris & UnixWare code. */
|
||||
|
||||
#undef GROUP
|
||||
#include <sys/aclv.h>
|
||||
|
||||
/* SVR4.2 ES/MP ACLs */
|
||||
typedef int SMB_ACL_TAG_T;
|
||||
typedef int SMB_ACL_TYPE_T;
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER USER
|
||||
#define SMB_ACL_USER_OBJ USER_OBJ
|
||||
#define SMB_ACL_GROUP GROUP
|
||||
#define SMB_ACL_GROUP_OBJ GROUP_OBJ
|
||||
#define SMB_ACL_OTHER OTHER_OBJ
|
||||
#define SMB_ACL_MASK CLASS_OBJ
|
||||
|
||||
typedef struct SMB_ACL_T {
|
||||
int size;
|
||||
int count;
|
||||
int next;
|
||||
struct acl acl[1];
|
||||
} *SMB_ACL_T;
|
||||
|
||||
typedef struct acl *SMB_ACL_ENTRY_T;
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS 0
|
||||
#define SMB_ACL_TYPE_DEFAULT 1
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_IRIX_ACLS /*----------------------------------------------*/
|
||||
|
||||
/* IRIX ACLs */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACL_USER
|
||||
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
|
||||
#define SMB_ACL_GROUP ACL_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
|
||||
#define SMB_ACL_OTHER ACL_OTHER_OBJ
|
||||
#define SMB_ACL_MASK ACL_MASK
|
||||
|
||||
typedef struct SMB_ACL_T {
|
||||
int next;
|
||||
BOOL freeaclp;
|
||||
struct acl *aclp;
|
||||
} *SMB_ACL_T;
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_AIX_ACLS /*-----------------------------------------------*/
|
||||
|
||||
/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
|
||||
|
||||
#include "/usr/include/acl.h"
|
||||
|
||||
struct acl_entry_link{
|
||||
struct acl_entry_link *prevp;
|
||||
struct new_acl_entry *entryp;
|
||||
struct acl_entry_link *nextp;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct new_acl_entry{
|
||||
unsigned short ace_len;
|
||||
unsigned short ace_type;
|
||||
unsigned int ace_access;
|
||||
struct ace_id ace_id[1];
|
||||
};
|
||||
|
||||
#define SMB_ACL_ENTRY_T struct new_acl_entry*
|
||||
#define SMB_ACL_T struct acl_entry_link*
|
||||
|
||||
#define SMB_ACL_TAG_T unsigned short
|
||||
#define SMB_ACL_TYPE_T int
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACEID_USER
|
||||
#define SMB_ACL_USER_OBJ 3
|
||||
#define SMB_ACL_GROUP ACEID_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ 4
|
||||
#define SMB_ACL_OTHER 5
|
||||
#define SMB_ACL_MASK 6
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 1
|
||||
#define SMB_ACL_NEXT_ENTRY 2
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS 0
|
||||
#define SMB_ACL_TYPE_DEFAULT 1
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
|
||||
|
||||
/* Special handling for OS X ACLs */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
#define SMB_ACL_T acl_t
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_USER 1
|
||||
#define SMB_ACL_GROUP 2
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
|
||||
#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_EXTENDED
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS ((1<<25)-1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS 0
|
||||
|
||||
/*#undef SMB_ACL_NEED_SORT*/
|
||||
|
||||
#else /*---------------------------------------------------------------------*/
|
||||
|
||||
/* Unknown platform. */
|
||||
|
||||
#error Cannot handle ACLs on this platform!
|
||||
|
||||
#endif
|
||||
|
||||
int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
|
||||
int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
|
||||
int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p);
|
||||
SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
|
||||
SMB_ACL_T sys_acl_get_fd(int fd);
|
||||
SMB_ACL_T sys_acl_init(int count);
|
||||
int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
|
||||
int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype, uint32 bits, id_t u_g_id);
|
||||
int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits);
|
||||
int sys_acl_valid(SMB_ACL_T theacl);
|
||||
int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
|
||||
int sys_acl_set_fd(int fd, SMB_ACL_T theacl);
|
||||
int sys_acl_delete_def_file(const char *name);
|
||||
int sys_acl_free_acl(SMB_ACL_T the_acl);
|
||||
int no_acl_syscall_error(int err);
|
||||
|
||||
#endif /* SUPPORT_ACLS */
|
300
rsync/lib/sysxattrs.c
Normal file
300
rsync/lib/sysxattrs.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Extended attribute support for rsync.
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Written by Jay Fenlason.
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "sysxattrs.h"
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
|
||||
#ifdef HAVE_OSX_XATTRS
|
||||
#define GETXATTR_FETCH_LIMIT (64*1024*1024)
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LINUX_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return lgetxattr(path, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(filedes, name, value, size);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
return lsetxattr(path, name, value, size, 0);
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
return lremovexattr(path, name);
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
return llistxattr(path, list, size);
|
||||
}
|
||||
|
||||
#elif HAVE_OSX_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
ssize_t len = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
|
||||
/* If we're retrieving data, handle resource forks > 64MB specially */
|
||||
if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) {
|
||||
/* getxattr will only return 64MB of data at a time, need to call again with a new offset */
|
||||
u_int32_t offset = len;
|
||||
size_t data_retrieved = len;
|
||||
while (data_retrieved < size) {
|
||||
len = getxattr(path, name, value + offset, size - data_retrieved, offset, XATTR_NOFOLLOW);
|
||||
if (len <= 0)
|
||||
break;
|
||||
data_retrieved += len;
|
||||
offset += (u_int32_t)len;
|
||||
}
|
||||
len = data_retrieved;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(filedes, name, value, size, 0, 0);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
return removexattr(path, name, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
return listxattr(path, list, size, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
#elif HAVE_FREEBSD_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
return extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
return extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name);
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
unsigned char keylen;
|
||||
ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
|
||||
|
||||
if (len <= 0 || (size_t)len > size)
|
||||
return len;
|
||||
|
||||
/* FreeBSD puts a single-byte length before each string, with no '\0'
|
||||
* terminator. We need to change this into a series of null-terminted
|
||||
* strings. Since the size is the same, we can simply transform the
|
||||
* output in place. */
|
||||
for (off = 0; off < len; off += keylen + 1) {
|
||||
keylen = ((unsigned char*)list)[off];
|
||||
if (off + keylen >= len) {
|
||||
/* Should be impossible, but kernel bugs happen! */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
memmove(list+off, list+off+1, keylen);
|
||||
list[off+keylen] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#elif HAVE_SOLARIS_XATTRS
|
||||
|
||||
static ssize_t read_xattr(int attrfd, void *buf, size_t buflen)
|
||||
{
|
||||
STRUCT_STAT sb;
|
||||
ssize_t ret;
|
||||
|
||||
if (fstat(attrfd, &sb) < 0)
|
||||
ret = -1;
|
||||
else if (sb.st_size > SSIZE_MAX) {
|
||||
errno = ERANGE;
|
||||
ret = -1;
|
||||
} else if (buflen == 0)
|
||||
ret = sb.st_size;
|
||||
else if (sb.st_size > buflen) {
|
||||
errno = ERANGE;
|
||||
ret = -1;
|
||||
} else {
|
||||
size_t bufpos;
|
||||
for (bufpos = 0; bufpos < sb.st_size; ) {
|
||||
ssize_t cnt = read(attrfd, buf + bufpos, sb.st_size - bufpos);
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0 && errno == EINTR)
|
||||
continue;
|
||||
bufpos = -1;
|
||||
break;
|
||||
}
|
||||
bufpos += cnt;
|
||||
}
|
||||
ret = bufpos;
|
||||
}
|
||||
|
||||
close(attrfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
int attrfd;
|
||||
|
||||
if ((attrfd = attropen(path, name, O_RDONLY)) < 0) {
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_xattr(attrfd, value, size);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
int attrfd;
|
||||
|
||||
if ((attrfd = openat(filedes, name, O_RDONLY|O_XATTR, 0)) < 0) {
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_xattr(attrfd, value, size);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
int attrfd;
|
||||
size_t bufpos;
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
|
||||
|
||||
if ((attrfd = attropen(path, name, O_CREAT|O_TRUNC|O_WRONLY, mode)) < 0)
|
||||
return -1;
|
||||
|
||||
for (bufpos = 0; bufpos < size; ) {
|
||||
ssize_t cnt = write(attrfd, value+bufpos, size);
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0 && errno == EINTR)
|
||||
continue;
|
||||
bufpos = -1;
|
||||
break;
|
||||
}
|
||||
bufpos += cnt;
|
||||
}
|
||||
|
||||
close(attrfd);
|
||||
|
||||
return bufpos > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
int attrdirfd;
|
||||
int ret;
|
||||
|
||||
if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
ret = unlinkat(attrdirfd, name, 0);
|
||||
|
||||
close(attrdirfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
int attrdirfd;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
ssize_t ret = 0;
|
||||
|
||||
if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((dirp = fdopendir(attrdirfd)) == NULL) {
|
||||
close(attrdirfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp))) {
|
||||
int len = strlen(dp->d_name);
|
||||
|
||||
if (dp->d_name[0] == '.' && (len == 1 || (len == 2 && dp->d_name[1] == '.')))
|
||||
continue;
|
||||
if (len == 11 && dp->d_name[0] == 'S' && strncmp(dp->d_name, "SUNWattr_r", 10) == 0
|
||||
&& (dp->d_name[10] == 'o' || dp->d_name[10] == 'w'))
|
||||
continue;
|
||||
|
||||
if ((ret += len+1) > size) {
|
||||
if (size == 0)
|
||||
continue;
|
||||
ret = -1;
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
memcpy(list, dp->d_name, len+1);
|
||||
list += len+1;
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
close(attrdirfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error You need to create xattr compatibility functions.
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SUPPORT_XATTRS */
|
26
rsync/lib/sysxattrs.h
Normal file
26
rsync/lib/sysxattrs.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifdef SUPPORT_XATTRS
|
||||
|
||||
#if defined HAVE_ATTR_XATTR_H
|
||||
#include <attr/xattr.h>
|
||||
#elif defined HAVE_SYS_XATTR_H
|
||||
#include <sys/xattr.h>
|
||||
#elif defined HAVE_SYS_EXTATTR_H
|
||||
#include <sys/extattr.h>
|
||||
#endif
|
||||
|
||||
/* Linux 2.4 does not define this as a distinct errno value: */
|
||||
#ifndef ENOATTR
|
||||
#define ENOATTR ENODATA
|
||||
#endif
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size);
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size);
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size);
|
||||
int sys_lremovexattr(const char *path, const char *name);
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size);
|
||||
|
||||
#else
|
||||
|
||||
/* No xattrs available */
|
||||
|
||||
#endif
|
368
rsync/lib/wildmatch.c
Normal file
368
rsync/lib/wildmatch.c
Normal file
@ -0,0 +1,368 @@
|
||||
/*
|
||||
** Do shell-style pattern matching for ?, \, [], and * characters.
|
||||
** It is 8bit clean.
|
||||
**
|
||||
** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
|
||||
** Rich $alz is now <rsalz@bbn.com>.
|
||||
**
|
||||
** Modified by Wayne Davison to special-case '/' matching, to make '**'
|
||||
** work differently than '*', and to fix the character-class code.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
/* What character marks an inverted character class? */
|
||||
#define NEGATE_CLASS '!'
|
||||
#define NEGATE_CLASS2 '^'
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define ABORT_ALL -1
|
||||
#define ABORT_TO_STARSTAR -2
|
||||
|
||||
#define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
|
||||
&& *(class) == *(litmatch) \
|
||||
&& strncmp((char*)class, litmatch, len) == 0)
|
||||
|
||||
#if defined STDC_HEADERS || !defined isascii
|
||||
# define ISASCII(c) 1
|
||||
#else
|
||||
# define ISASCII(c) isascii(c)
|
||||
#endif
|
||||
|
||||
#ifdef isblank
|
||||
# define ISBLANK(c) (ISASCII(c) && isblank(c))
|
||||
#else
|
||||
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
|
||||
#endif
|
||||
|
||||
#ifdef isgraph
|
||||
# define ISGRAPH(c) (ISASCII(c) && isgraph(c))
|
||||
#else
|
||||
# define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c))
|
||||
#endif
|
||||
|
||||
#define ISPRINT(c) (ISASCII(c) && isprint(c))
|
||||
#define ISDIGIT(c) (ISASCII(c) && isdigit(c))
|
||||
#define ISALNUM(c) (ISASCII(c) && isalnum(c))
|
||||
#define ISALPHA(c) (ISASCII(c) && isalpha(c))
|
||||
#define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
|
||||
#define ISLOWER(c) (ISASCII(c) && islower(c))
|
||||
#define ISPUNCT(c) (ISASCII(c) && ispunct(c))
|
||||
#define ISSPACE(c) (ISASCII(c) && isspace(c))
|
||||
#define ISUPPER(c) (ISASCII(c) && isupper(c))
|
||||
#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
|
||||
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
int wildmatch_iteration_count;
|
||||
#endif
|
||||
|
||||
static int force_lower_case = 0;
|
||||
|
||||
/* Match pattern "p" against the a virtually-joined string consisting
|
||||
* of "text" and any strings in array "a". */
|
||||
static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
|
||||
{
|
||||
uchar p_ch;
|
||||
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count++;
|
||||
#endif
|
||||
|
||||
for ( ; (p_ch = *p) != '\0'; text++, p++) {
|
||||
int matched, special;
|
||||
uchar t_ch, prev_ch;
|
||||
while ((t_ch = *text) == '\0') {
|
||||
if (*a == NULL) {
|
||||
if (p_ch != '*')
|
||||
return ABORT_ALL;
|
||||
break;
|
||||
}
|
||||
text = *a++;
|
||||
}
|
||||
if (force_lower_case && ISUPPER(t_ch))
|
||||
t_ch = tolower(t_ch);
|
||||
switch (p_ch) {
|
||||
case '\\':
|
||||
/* Literal match with following character. Note that the test
|
||||
* in "default" handles the p[1] == '\0' failure case. */
|
||||
p_ch = *++p;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (t_ch != p_ch)
|
||||
return FALSE;
|
||||
continue;
|
||||
case '?':
|
||||
/* Match anything but '/'. */
|
||||
if (t_ch == '/')
|
||||
return FALSE;
|
||||
continue;
|
||||
case '*':
|
||||
if (*++p == '*') {
|
||||
while (*++p == '*') {}
|
||||
special = TRUE;
|
||||
} else
|
||||
special = FALSE;
|
||||
if (*p == '\0') {
|
||||
/* Trailing "**" matches everything. Trailing "*" matches
|
||||
* only if there are no more slash characters. */
|
||||
if (!special) {
|
||||
do {
|
||||
if (strchr((char*)text, '/') != NULL)
|
||||
return FALSE;
|
||||
} while ((text = *a++) != NULL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
while (1) {
|
||||
if (t_ch == '\0') {
|
||||
if ((text = *a++) == NULL)
|
||||
break;
|
||||
t_ch = *text;
|
||||
continue;
|
||||
}
|
||||
if ((matched = dowild(p, text, a)) != FALSE) {
|
||||
if (!special || matched != ABORT_TO_STARSTAR)
|
||||
return matched;
|
||||
} else if (!special && t_ch == '/')
|
||||
return ABORT_TO_STARSTAR;
|
||||
t_ch = *++text;
|
||||
}
|
||||
return ABORT_ALL;
|
||||
case '[':
|
||||
p_ch = *++p;
|
||||
#ifdef NEGATE_CLASS2
|
||||
if (p_ch == NEGATE_CLASS2)
|
||||
p_ch = NEGATE_CLASS;
|
||||
#endif
|
||||
/* Assign literal TRUE/FALSE because of "matched" comparison. */
|
||||
special = p_ch == NEGATE_CLASS? TRUE : FALSE;
|
||||
if (special) {
|
||||
/* Inverted character class. */
|
||||
p_ch = *++p;
|
||||
}
|
||||
prev_ch = 0;
|
||||
matched = FALSE;
|
||||
do {
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
if (p_ch == '\\') {
|
||||
p_ch = *++p;
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
if (t_ch == p_ch)
|
||||
matched = TRUE;
|
||||
} else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
|
||||
p_ch = *++p;
|
||||
if (p_ch == '\\') {
|
||||
p_ch = *++p;
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
}
|
||||
if (t_ch <= p_ch && t_ch >= prev_ch)
|
||||
matched = TRUE;
|
||||
p_ch = 0; /* This makes "prev_ch" get set to 0. */
|
||||
} else if (p_ch == '[' && p[1] == ':') {
|
||||
const uchar *s;
|
||||
int i;
|
||||
for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
i = p - s - 1;
|
||||
if (i < 0 || p[-1] != ':') {
|
||||
/* Didn't find ":]", so treat like a normal set. */
|
||||
p = s - 2;
|
||||
p_ch = '[';
|
||||
if (t_ch == p_ch)
|
||||
matched = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (CC_EQ(s,i, "alnum")) {
|
||||
if (ISALNUM(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "alpha")) {
|
||||
if (ISALPHA(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "blank")) {
|
||||
if (ISBLANK(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "cntrl")) {
|
||||
if (ISCNTRL(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "digit")) {
|
||||
if (ISDIGIT(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "graph")) {
|
||||
if (ISGRAPH(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "lower")) {
|
||||
if (ISLOWER(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "print")) {
|
||||
if (ISPRINT(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "punct")) {
|
||||
if (ISPUNCT(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "space")) {
|
||||
if (ISSPACE(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "upper")) {
|
||||
if (ISUPPER(t_ch))
|
||||
matched = TRUE;
|
||||
} else if (CC_EQ(s,i, "xdigit")) {
|
||||
if (ISXDIGIT(t_ch))
|
||||
matched = TRUE;
|
||||
} else /* malformed [:class:] string */
|
||||
return ABORT_ALL;
|
||||
p_ch = 0; /* This makes "prev_ch" get set to 0. */
|
||||
} else if (t_ch == p_ch)
|
||||
matched = TRUE;
|
||||
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
|
||||
if (matched == special || t_ch == '/')
|
||||
return FALSE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if (*text)
|
||||
return FALSE;
|
||||
} while ((text = *a++) != NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Match literal string "s" against the a virtually-joined string consisting
|
||||
* of "text" and any strings in array "a". */
|
||||
static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
|
||||
{
|
||||
for ( ; *s != '\0'; text++, s++) {
|
||||
while (*text == '\0') {
|
||||
if ((text = *a++) == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
if (*text != *s)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
if (*text)
|
||||
return FALSE;
|
||||
} while ((text = *a++) != NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return the last "count" path elements from the concatenated string.
|
||||
* We return a string pointer to the start of the string, and update the
|
||||
* array pointer-pointer to point to any remaining string elements. */
|
||||
static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
|
||||
{
|
||||
const uchar*const *a = *a_ptr;
|
||||
const uchar*const *first_a = a;
|
||||
|
||||
while (*a)
|
||||
a++;
|
||||
|
||||
while (a != first_a) {
|
||||
const uchar *s = *--a;
|
||||
s += strlen((char*)s);
|
||||
while (--s >= *a) {
|
||||
if (*s == '/' && !--count) {
|
||||
*a_ptr = a+1;
|
||||
return s+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
*a_ptr = a+1;
|
||||
return *a;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Match the "pattern" against the "text" string. */
|
||||
int wildmatch(const char *pattern, const char *text)
|
||||
{
|
||||
static const uchar *nomore[1]; /* A NULL pointer. */
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
|
||||
}
|
||||
|
||||
/* Match the "pattern" against the forced-to-lower-case "text" string. */
|
||||
int iwildmatch(const char *pattern, const char *text)
|
||||
{
|
||||
static const uchar *nomore[1]; /* A NULL pointer. */
|
||||
int ret;
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
force_lower_case = 1;
|
||||
ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
|
||||
force_lower_case = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Match pattern "p" against the a virtually-joined string consisting
|
||||
* of all the pointers in array "texts" (which has a NULL pointer at the
|
||||
* end). The int "where" can be 0 (normal matching), > 0 (match only
|
||||
* the trailing N slash-separated filename components of "texts"), or < 0
|
||||
* (match the "pattern" at the start or after any slash in "texts"). */
|
||||
int wildmatch_array(const char *pattern, const char*const *texts, int where)
|
||||
{
|
||||
const uchar *p = (const uchar*)pattern;
|
||||
const uchar*const *a = (const uchar*const*)texts;
|
||||
const uchar *text;
|
||||
int matched;
|
||||
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
|
||||
if (where > 0)
|
||||
text = trailing_N_elements(&a, where);
|
||||
else
|
||||
text = *a++;
|
||||
if (!text)
|
||||
return FALSE;
|
||||
|
||||
if ((matched = dowild(p, text, a)) != TRUE && where < 0
|
||||
&& matched != ABORT_ALL) {
|
||||
while (1) {
|
||||
if (*text == '\0') {
|
||||
if ((text = (uchar*)*a++) == NULL)
|
||||
return FALSE;
|
||||
continue;
|
||||
}
|
||||
if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
|
||||
&& matched != ABORT_TO_STARSTAR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return matched == TRUE;
|
||||
}
|
||||
|
||||
/* Match literal string "s" against the a virtually-joined string consisting
|
||||
* of all the pointers in array "texts" (which has a NULL pointer at the
|
||||
* end). The int "where" can be 0 (normal matching), or > 0 (match
|
||||
* only the trailing N slash-separated filename components of "texts"). */
|
||||
int litmatch_array(const char *string, const char*const *texts, int where)
|
||||
{
|
||||
const uchar *s = (const uchar*)string;
|
||||
const uchar*const *a = (const uchar* const*)texts;
|
||||
const uchar *text;
|
||||
|
||||
if (where > 0)
|
||||
text = trailing_N_elements(&a, where);
|
||||
else
|
||||
text = *a++;
|
||||
if (!text)
|
||||
return FALSE;
|
||||
|
||||
return doliteral(s, text, a) == TRUE;
|
||||
}
|
6
rsync/lib/wildmatch.h
Normal file
6
rsync/lib/wildmatch.h
Normal file
@ -0,0 +1,6 @@
|
||||
/* wildmatch.h */
|
||||
|
||||
int wildmatch(const char *pattern, const char *text);
|
||||
int iwildmatch(const char *pattern, const char *text);
|
||||
int wildmatch_array(const char *pattern, const char*const *texts, int where);
|
||||
int litmatch_array(const char *string, const char*const *texts, int where);
|
846
rsync/loadparm.c
Normal file
846
rsync/loadparm.c
Normal file
@ -0,0 +1,846 @@
|
||||
/*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
|
||||
* and Karl Auer. Some of the changes are:
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison <wayned@samba.org>
|
||||
*/
|
||||
|
||||
/* Load parameters.
|
||||
*
|
||||
* This module provides suitable callback functions for the params
|
||||
* module. It builds the internal table of section details which is
|
||||
* then used by the rest of the server.
|
||||
*
|
||||
* To add a parameter:
|
||||
*
|
||||
* 1) add it to the global_vars or local_vars structure definition
|
||||
* 2) add it to the parm_table
|
||||
* 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
|
||||
* 4) initialise it in the Defaults static stucture
|
||||
*
|
||||
* Notes:
|
||||
* The configuration file is processed sequentially for speed. For this
|
||||
* reason, there is a fair bit of sequence-dependent code here - ie., code
|
||||
* which assumes that certain things happen before others. In particular, the
|
||||
* code which happens at the boundary between sections is delicately poised,
|
||||
* so be careful!
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern item_list dparam_list;
|
||||
|
||||
#define strequal(a, b) (strcasecmp(a, b)==0)
|
||||
#define BOOLSTR(b) ((b) ? "Yes" : "No")
|
||||
|
||||
#ifndef LOG_DAEMON
|
||||
#define LOG_DAEMON 0
|
||||
#endif
|
||||
|
||||
#define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
|
||||
" *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg *.png" \
|
||||
" *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz"
|
||||
|
||||
/* the following are used by loadparm for option lists */
|
||||
typedef enum {
|
||||
P_BOOL, P_BOOLREV, P_CHAR, P_INTEGER,
|
||||
P_OCTAL, P_PATH, P_STRING, P_ENUM
|
||||
} parm_type;
|
||||
|
||||
typedef enum {
|
||||
P_LOCAL, P_GLOBAL, P_NONE
|
||||
} parm_class;
|
||||
|
||||
struct enum_list {
|
||||
int value;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct parm_struct {
|
||||
char *label;
|
||||
parm_type type;
|
||||
parm_class class;
|
||||
void *ptr;
|
||||
struct enum_list *enum_list;
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
#ifndef GLOBAL_NAME
|
||||
#define GLOBAL_NAME "global"
|
||||
#endif
|
||||
|
||||
/* some helpful bits */
|
||||
#define iSECTION(i) ((local_vars*)section_list.items)[i]
|
||||
#define LP_SNUM_OK(i) ((i) >= 0 && (i) < (int)section_list.count)
|
||||
#define SECTION_PTR(s, p) (((char*)(s)) + (ptrdiff_t)(((char*)(p))-(char*)&Vars.l))
|
||||
|
||||
/* This structure describes global (ie., server-wide) parameters. */
|
||||
typedef struct {
|
||||
char *bind_address;
|
||||
char *motd_file;
|
||||
char *pid_file;
|
||||
char *socket_options;
|
||||
|
||||
int listen_backlog;
|
||||
int rsync_port;
|
||||
} global_vars;
|
||||
|
||||
/* This structure describes a single section. Their order must match the
|
||||
* initializers below, which you can accomplish by keeping each sub-section
|
||||
* sorted. (e.g. in vim, just visually select each subsection and use !sort.)
|
||||
* NOTE: the char* variables MUST all remain at the start of the stuct! */
|
||||
typedef struct {
|
||||
char *auth_users;
|
||||
char *charset;
|
||||
char *comment;
|
||||
char *dont_compress;
|
||||
char *exclude;
|
||||
char *exclude_from;
|
||||
char *filter;
|
||||
char *gid;
|
||||
char *hosts_allow;
|
||||
char *hosts_deny;
|
||||
char *include;
|
||||
char *include_from;
|
||||
char *incoming_chmod;
|
||||
char *lock_file;
|
||||
char *log_file;
|
||||
char *log_format;
|
||||
char *name;
|
||||
char *outgoing_chmod;
|
||||
char *path;
|
||||
char *postxfer_exec;
|
||||
char *prexfer_exec;
|
||||
char *refuse_options;
|
||||
char *secrets_file;
|
||||
char *temp_dir;
|
||||
char *uid;
|
||||
/* NOTE: update this macro if the last char* variable changes! */
|
||||
#define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
|
||||
|
||||
int max_connections;
|
||||
int max_verbosity;
|
||||
int syslog_facility;
|
||||
int timeout;
|
||||
|
||||
BOOL fake_super;
|
||||
BOOL forward_lookup;
|
||||
BOOL ignore_errors;
|
||||
BOOL ignore_nonreadable;
|
||||
BOOL list;
|
||||
BOOL munge_symlinks;
|
||||
BOOL numeric_ids;
|
||||
BOOL read_only;
|
||||
BOOL reverse_lookup;
|
||||
BOOL strict_modes;
|
||||
BOOL transfer_logging;
|
||||
BOOL use_chroot;
|
||||
BOOL write_only;
|
||||
} local_vars;
|
||||
|
||||
/* This structure describes the global variables (g) as well as the globally
|
||||
* specified values of the local variables (l), which are used when modules
|
||||
* don't specify their own values. */
|
||||
typedef struct {
|
||||
global_vars g;
|
||||
local_vars l;
|
||||
} all_vars;
|
||||
|
||||
/* The application defaults for all the variables. "Defaults" is
|
||||
* used to re-initialize "Vars" before each config-file read.
|
||||
*
|
||||
* In order to keep these sorted in the same way as the structure
|
||||
* above, use the variable name in the leading comment, including a
|
||||
* trailing ';' (to avoid a sorting problem with trailing digits). */
|
||||
static const all_vars Defaults = {
|
||||
/* ==== global_vars ==== */
|
||||
{
|
||||
/* bind_address; */ NULL,
|
||||
/* motd_file; */ NULL,
|
||||
/* pid_file; */ NULL,
|
||||
/* socket_options; */ NULL,
|
||||
|
||||
/* listen_backlog; */ 5,
|
||||
/* rsync_port; */ 0,
|
||||
},
|
||||
|
||||
/* ==== local_vars ==== */
|
||||
{
|
||||
/* auth_users; */ NULL,
|
||||
/* charset; */ NULL,
|
||||
/* comment; */ NULL,
|
||||
/* dont_compress; */ DEFAULT_DONT_COMPRESS,
|
||||
/* exclude; */ NULL,
|
||||
/* exclude_from; */ NULL,
|
||||
/* filter; */ NULL,
|
||||
/* gid; */ NULL,
|
||||
/* hosts_allow; */ NULL,
|
||||
/* hosts_deny; */ NULL,
|
||||
/* include; */ NULL,
|
||||
/* include_from; */ NULL,
|
||||
/* incoming_chmod; */ NULL,
|
||||
/* lock_file; */ DEFAULT_LOCK_FILE,
|
||||
/* log_file; */ NULL,
|
||||
/* log_format; */ "%o %h [%a] %m (%u) %f %l",
|
||||
/* name; */ NULL,
|
||||
/* outgoing_chmod; */ NULL,
|
||||
/* path; */ NULL,
|
||||
/* postxfer_exec; */ NULL,
|
||||
/* prexfer_exec; */ NULL,
|
||||
/* refuse_options; */ NULL,
|
||||
/* secrets_file; */ NULL,
|
||||
/* temp_dir; */ NULL,
|
||||
/* uid; */ NULL,
|
||||
|
||||
/* max_connections; */ 0,
|
||||
/* max_verbosity; */ 1,
|
||||
/* syslog_facility; */ LOG_DAEMON,
|
||||
/* timeout; */ 0,
|
||||
|
||||
/* fake_super; */ False,
|
||||
/* forward_lookup; */ True,
|
||||
/* ignore_errors; */ False,
|
||||
/* ignore_nonreadable; */ False,
|
||||
/* list; */ True,
|
||||
/* munge_symlinks; */ (BOOL)-1,
|
||||
/* numeric_ids; */ (BOOL)-1,
|
||||
/* read_only; */ True,
|
||||
/* reverse_lookup; */ True,
|
||||
/* strict_modes; */ True,
|
||||
/* transfer_logging; */ False,
|
||||
/* use_chroot; */ True,
|
||||
/* write_only; */ False,
|
||||
}
|
||||
};
|
||||
|
||||
/* The currently configured values for all the variables. */
|
||||
static all_vars Vars;
|
||||
|
||||
/* Stack of "Vars" values used by the &include directive. */
|
||||
static item_list Vars_stack = EMPTY_ITEM_LIST;
|
||||
|
||||
/* The array of section values that holds all the defined modules. */
|
||||
static item_list section_list = EMPTY_ITEM_LIST;
|
||||
|
||||
static int iSectionIndex = -1;
|
||||
static BOOL bInGlobalSection = True;
|
||||
|
||||
#define NUMPARAMETERS (sizeof (parm_table) / sizeof (struct parm_struct))
|
||||
|
||||
static struct enum_list enum_facilities[] = {
|
||||
#ifdef LOG_AUTH
|
||||
{ LOG_AUTH, "auth" },
|
||||
#endif
|
||||
#ifdef LOG_AUTHPRIV
|
||||
{ LOG_AUTHPRIV, "authpriv" },
|
||||
#endif
|
||||
#ifdef LOG_CRON
|
||||
{ LOG_CRON, "cron" },
|
||||
#endif
|
||||
#ifdef LOG_DAEMON
|
||||
{ LOG_DAEMON, "daemon" },
|
||||
#endif
|
||||
#ifdef LOG_FTP
|
||||
{ LOG_FTP, "ftp" },
|
||||
#endif
|
||||
#ifdef LOG_KERN
|
||||
{ LOG_KERN, "kern" },
|
||||
#endif
|
||||
#ifdef LOG_LPR
|
||||
{ LOG_LPR, "lpr" },
|
||||
#endif
|
||||
#ifdef LOG_MAIL
|
||||
{ LOG_MAIL, "mail" },
|
||||
#endif
|
||||
#ifdef LOG_NEWS
|
||||
{ LOG_NEWS, "news" },
|
||||
#endif
|
||||
#ifdef LOG_AUTH
|
||||
{ LOG_AUTH, "security" },
|
||||
#endif
|
||||
#ifdef LOG_SYSLOG
|
||||
{ LOG_SYSLOG, "syslog" },
|
||||
#endif
|
||||
#ifdef LOG_USER
|
||||
{ LOG_USER, "user" },
|
||||
#endif
|
||||
#ifdef LOG_UUCP
|
||||
{ LOG_UUCP, "uucp" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL0
|
||||
{ LOG_LOCAL0, "local0" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL1
|
||||
{ LOG_LOCAL1, "local1" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL2
|
||||
{ LOG_LOCAL2, "local2" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL3
|
||||
{ LOG_LOCAL3, "local3" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL4
|
||||
{ LOG_LOCAL4, "local4" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL5
|
||||
{ LOG_LOCAL5, "local5" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL6
|
||||
{ LOG_LOCAL6, "local6" },
|
||||
#endif
|
||||
#ifdef LOG_LOCAL7
|
||||
{ LOG_LOCAL7, "local7" },
|
||||
#endif
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static struct parm_struct parm_table[] =
|
||||
{
|
||||
{"address", P_STRING, P_GLOBAL,&Vars.g.bind_address, NULL,0},
|
||||
{"listen backlog", P_INTEGER,P_GLOBAL,&Vars.g.listen_backlog, NULL,0},
|
||||
{"motd file", P_STRING, P_GLOBAL,&Vars.g.motd_file, NULL,0},
|
||||
{"pid file", P_STRING, P_GLOBAL,&Vars.g.pid_file, NULL,0},
|
||||
{"port", P_INTEGER,P_GLOBAL,&Vars.g.rsync_port, NULL,0},
|
||||
{"socket options", P_STRING, P_GLOBAL,&Vars.g.socket_options, NULL,0},
|
||||
|
||||
{"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
|
||||
{"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0},
|
||||
{"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0},
|
||||
{"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0},
|
||||
{"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0},
|
||||
{"exclude", P_STRING, P_LOCAL, &Vars.l.exclude, NULL,0},
|
||||
{"fake super", P_BOOL, P_LOCAL, &Vars.l.fake_super, NULL,0},
|
||||
{"filter", P_STRING, P_LOCAL, &Vars.l.filter, NULL,0},
|
||||
{"forward lookup", P_BOOL, P_LOCAL, &Vars.l.forward_lookup, NULL,0},
|
||||
{"gid", P_STRING, P_LOCAL, &Vars.l.gid, NULL,0},
|
||||
{"hosts allow", P_STRING, P_LOCAL, &Vars.l.hosts_allow, NULL,0},
|
||||
{"hosts deny", P_STRING, P_LOCAL, &Vars.l.hosts_deny, NULL,0},
|
||||
{"ignore errors", P_BOOL, P_LOCAL, &Vars.l.ignore_errors, NULL,0},
|
||||
{"ignore nonreadable",P_BOOL, P_LOCAL, &Vars.l.ignore_nonreadable, NULL,0},
|
||||
{"include from", P_STRING, P_LOCAL, &Vars.l.include_from, NULL,0},
|
||||
{"include", P_STRING, P_LOCAL, &Vars.l.include, NULL,0},
|
||||
{"incoming chmod", P_STRING, P_LOCAL, &Vars.l.incoming_chmod, NULL,0},
|
||||
{"list", P_BOOL, P_LOCAL, &Vars.l.list, NULL,0},
|
||||
{"lock file", P_STRING, P_LOCAL, &Vars.l.lock_file, NULL,0},
|
||||
{"log file", P_STRING, P_LOCAL, &Vars.l.log_file, NULL,0},
|
||||
{"log format", P_STRING, P_LOCAL, &Vars.l.log_format, NULL,0},
|
||||
{"max connections", P_INTEGER,P_LOCAL, &Vars.l.max_connections, NULL,0},
|
||||
{"max verbosity", P_INTEGER,P_LOCAL, &Vars.l.max_verbosity, NULL,0},
|
||||
{"munge symlinks", P_BOOL, P_LOCAL, &Vars.l.munge_symlinks, NULL,0},
|
||||
{"name", P_STRING, P_LOCAL, &Vars.l.name, NULL,0},
|
||||
{"numeric ids", P_BOOL, P_LOCAL, &Vars.l.numeric_ids, NULL,0},
|
||||
{"outgoing chmod", P_STRING, P_LOCAL, &Vars.l.outgoing_chmod, NULL,0},
|
||||
{"path", P_PATH, P_LOCAL, &Vars.l.path, NULL,0},
|
||||
#ifdef HAVE_PUTENV
|
||||
{"post-xfer exec", P_STRING, P_LOCAL, &Vars.l.postxfer_exec, NULL,0},
|
||||
{"pre-xfer exec", P_STRING, P_LOCAL, &Vars.l.prexfer_exec, NULL,0},
|
||||
#endif
|
||||
{"read only", P_BOOL, P_LOCAL, &Vars.l.read_only, NULL,0},
|
||||
{"refuse options", P_STRING, P_LOCAL, &Vars.l.refuse_options, NULL,0},
|
||||
{"reverse lookup", P_BOOL, P_LOCAL, &Vars.l.reverse_lookup, NULL,0},
|
||||
{"secrets file", P_STRING, P_LOCAL, &Vars.l.secrets_file, NULL,0},
|
||||
{"strict modes", P_BOOL, P_LOCAL, &Vars.l.strict_modes, NULL,0},
|
||||
{"syslog facility", P_ENUM, P_LOCAL, &Vars.l.syslog_facility, enum_facilities,0},
|
||||
{"temp dir", P_PATH, P_LOCAL, &Vars.l.temp_dir, NULL,0},
|
||||
{"timeout", P_INTEGER,P_LOCAL, &Vars.l.timeout, NULL,0},
|
||||
{"transfer logging", P_BOOL, P_LOCAL, &Vars.l.transfer_logging, NULL,0},
|
||||
{"uid", P_STRING, P_LOCAL, &Vars.l.uid, NULL,0},
|
||||
{"use chroot", P_BOOL, P_LOCAL, &Vars.l.use_chroot, NULL,0},
|
||||
{"write only", P_BOOL, P_LOCAL, &Vars.l.write_only, NULL,0},
|
||||
{NULL, P_BOOL, P_NONE, NULL, NULL,0}
|
||||
};
|
||||
|
||||
/* Initialise the Default all_vars structure. */
|
||||
static void reset_all_vars(void)
|
||||
{
|
||||
memcpy(&Vars, &Defaults, sizeof Vars);
|
||||
}
|
||||
|
||||
/* Expand %VAR% references. Any unknown vars or unrecognized
|
||||
* syntax leaves the raw chars unchanged. */
|
||||
static char *expand_vars(char *str)
|
||||
{
|
||||
char *buf, *t, *f;
|
||||
int bufsize;
|
||||
|
||||
if (strchr(str, '%') == NULL)
|
||||
return str;
|
||||
|
||||
bufsize = strlen(str) + 2048;
|
||||
if ((buf = new_array(char, bufsize+1)) == NULL) /* +1 for trailing '\0' */
|
||||
out_of_memory("expand_vars");
|
||||
|
||||
for (t = buf, f = str; bufsize && *f; ) {
|
||||
if (*f == '%' && *++f != '%') {
|
||||
char *percent = strchr(f, '%');
|
||||
if (percent) {
|
||||
char *val;
|
||||
*percent = '\0';
|
||||
val = getenv(f);
|
||||
*percent = '%';
|
||||
if (val) {
|
||||
int len = strlcpy(t, val, bufsize+1);
|
||||
if (len > bufsize)
|
||||
break;
|
||||
bufsize -= len;
|
||||
t += len;
|
||||
f = percent + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
f--;
|
||||
}
|
||||
*t++ = *f++;
|
||||
bufsize--;
|
||||
}
|
||||
*t = '\0';
|
||||
|
||||
if (*f) {
|
||||
rprintf(FLOG, "Overflowed buf in expand_vars() trying to expand: %s\n", str);
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
}
|
||||
|
||||
if (bufsize && (buf = realloc(buf, t - buf + 1)) == NULL)
|
||||
out_of_memory("expand_vars");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* In this section all the functions that are used to access the
|
||||
* parameters from the rest of the program are defined. */
|
||||
|
||||
#define FN_GLOBAL_STRING(fn_name, ptr) \
|
||||
char *fn_name(void) {return expand_vars(*(char **)(ptr) ? *(char **)(ptr) : "");}
|
||||
#define FN_GLOBAL_BOOL(fn_name, ptr) \
|
||||
BOOL fn_name(void) {return *(BOOL *)(ptr);}
|
||||
#define FN_GLOBAL_CHAR(fn_name, ptr) \
|
||||
char fn_name(void) {return *(char *)(ptr);}
|
||||
#define FN_GLOBAL_INTEGER(fn_name, ptr) \
|
||||
int fn_name(void) {return *(int *)(ptr);}
|
||||
|
||||
#define FN_LOCAL_STRING(fn_name, val) \
|
||||
char *fn_name(int i) {return expand_vars(LP_SNUM_OK(i) && iSECTION(i).val ? iSECTION(i).val : Vars.l.val ? Vars.l.val : "");}
|
||||
#define FN_LOCAL_BOOL(fn_name, val) \
|
||||
BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
|
||||
#define FN_LOCAL_CHAR(fn_name, val) \
|
||||
char fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
|
||||
#define FN_LOCAL_INTEGER(fn_name, val) \
|
||||
int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
|
||||
|
||||
FN_GLOBAL_STRING(lp_bind_address, &Vars.g.bind_address)
|
||||
FN_GLOBAL_STRING(lp_motd_file, &Vars.g.motd_file)
|
||||
FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file)
|
||||
FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options)
|
||||
|
||||
FN_GLOBAL_INTEGER(lp_listen_backlog, &Vars.g.listen_backlog)
|
||||
FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
|
||||
|
||||
FN_LOCAL_STRING(lp_auth_users, auth_users)
|
||||
FN_LOCAL_STRING(lp_charset, charset)
|
||||
FN_LOCAL_STRING(lp_comment, comment)
|
||||
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
|
||||
FN_LOCAL_STRING(lp_exclude, exclude)
|
||||
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
|
||||
FN_LOCAL_STRING(lp_filter, filter)
|
||||
FN_LOCAL_STRING(lp_gid, gid)
|
||||
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
|
||||
FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
|
||||
FN_LOCAL_STRING(lp_include, include)
|
||||
FN_LOCAL_STRING(lp_include_from, include_from)
|
||||
FN_LOCAL_STRING(lp_incoming_chmod, incoming_chmod)
|
||||
FN_LOCAL_STRING(lp_lock_file, lock_file)
|
||||
FN_LOCAL_STRING(lp_log_file, log_file)
|
||||
FN_LOCAL_STRING(lp_log_format, log_format)
|
||||
FN_LOCAL_STRING(lp_name, name)
|
||||
FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod)
|
||||
FN_LOCAL_STRING(lp_path, path)
|
||||
FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
|
||||
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
|
||||
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
|
||||
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
|
||||
FN_LOCAL_STRING(lp_temp_dir, temp_dir)
|
||||
FN_LOCAL_STRING(lp_uid, uid)
|
||||
|
||||
FN_LOCAL_INTEGER(lp_max_connections, max_connections)
|
||||
FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
|
||||
FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
|
||||
FN_LOCAL_INTEGER(lp_timeout, timeout)
|
||||
|
||||
FN_LOCAL_BOOL(lp_fake_super, fake_super)
|
||||
FN_LOCAL_BOOL(lp_forward_lookup, forward_lookup)
|
||||
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
|
||||
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks)
|
||||
FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids)
|
||||
FN_LOCAL_BOOL(lp_read_only, read_only)
|
||||
FN_LOCAL_BOOL(lp_reverse_lookup, reverse_lookup)
|
||||
FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
|
||||
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
|
||||
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
|
||||
FN_LOCAL_BOOL(lp_write_only, write_only)
|
||||
|
||||
/* Assign a copy of v to *s. Handles NULL strings. We don't worry
|
||||
* about overwriting a malloc'd string because the long-running
|
||||
* (port-listening) daemon only loads the config file once, and the
|
||||
* per-job (forked or xinitd-ran) daemon only re-reads the file at
|
||||
* the start, so any lost memory is inconsequential. */
|
||||
static inline void string_set(char **s, const char *v)
|
||||
{
|
||||
if (!v)
|
||||
*s = NULL;
|
||||
else if (!(*s = strdup(v)))
|
||||
out_of_memory("string_set");
|
||||
}
|
||||
|
||||
/* Copy the local_vars, strdup'ing any strings. NOTE: this depends on
|
||||
* the structure starting with a contiguous list of the char* variables,
|
||||
* and having an accurate count in the LOCAL_STRING_COUNT() macro. */
|
||||
static void copy_section(local_vars *psectionDest, local_vars *psectionSource)
|
||||
{
|
||||
int count = LOCAL_STRING_COUNT();
|
||||
char **strings = (char**)psectionDest;
|
||||
|
||||
memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
|
||||
while (count--) {
|
||||
if (strings[count] && !(strings[count] = strdup(strings[count])))
|
||||
out_of_memory("copy_section");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise a section to the defaults. */
|
||||
static void init_section(local_vars *psection)
|
||||
{
|
||||
memset(psection, 0, sizeof (local_vars));
|
||||
copy_section(psection, &Vars.l);
|
||||
}
|
||||
|
||||
/* Do a case-insensitive, whitespace-ignoring string compare. */
|
||||
static int strwicmp(char *psz1, char *psz2)
|
||||
{
|
||||
/* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
|
||||
/* appropriate value. */
|
||||
if (psz1 == psz2)
|
||||
return 0;
|
||||
|
||||
if (psz1 == NULL)
|
||||
return -1;
|
||||
|
||||
if (psz2 == NULL)
|
||||
return 1;
|
||||
|
||||
/* sync the strings on first non-whitespace */
|
||||
while (1) {
|
||||
while (isSpace(psz1))
|
||||
psz1++;
|
||||
while (isSpace(psz2))
|
||||
psz2++;
|
||||
if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0')
|
||||
break;
|
||||
psz1++;
|
||||
psz2++;
|
||||
}
|
||||
return *psz1 - *psz2;
|
||||
}
|
||||
|
||||
/* Find a section by name. Otherwise works like get_section. */
|
||||
static int getsectionbyname(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = section_list.count - 1; i >= 0; i--) {
|
||||
if (strwicmp(iSECTION(i).name, name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Add a new section to the sections array w/the default values. */
|
||||
static int add_a_section(char *name)
|
||||
{
|
||||
int i;
|
||||
local_vars *s;
|
||||
|
||||
/* it might already exist */
|
||||
if (name) {
|
||||
i = getsectionbyname(name);
|
||||
if (i >= 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
i = section_list.count;
|
||||
s = EXPAND_ITEM_LIST(§ion_list, local_vars, 2);
|
||||
|
||||
init_section(s);
|
||||
if (name)
|
||||
string_set(&s->name, name);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Map a parameter's string representation to something we can use.
|
||||
* Returns False if the parameter string is not recognised, else TRUE. */
|
||||
static int map_parameter(char *parmname)
|
||||
{
|
||||
int iIndex;
|
||||
|
||||
if (*parmname == '-')
|
||||
return -1;
|
||||
|
||||
for (iIndex = 0; parm_table[iIndex].label; iIndex++) {
|
||||
if (strwicmp(parm_table[iIndex].label, parmname) == 0)
|
||||
return iIndex;
|
||||
}
|
||||
|
||||
rprintf(FLOG, "Unknown Parameter encountered: \"%s\"\n", parmname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set a boolean variable from the text value stored in the passed string.
|
||||
* Returns True in success, False if the passed string does not correctly
|
||||
* represent a boolean. */
|
||||
static BOOL set_boolean(BOOL *pb, char *parmvalue)
|
||||
{
|
||||
if (strwicmp(parmvalue, "yes") == 0
|
||||
|| strwicmp(parmvalue, "true") == 0
|
||||
|| strwicmp(parmvalue, "1") == 0)
|
||||
*pb = True;
|
||||
else if (strwicmp(parmvalue, "no") == 0
|
||||
|| strwicmp(parmvalue, "False") == 0
|
||||
|| strwicmp(parmvalue, "0") == 0)
|
||||
*pb = False;
|
||||
else {
|
||||
rprintf(FLOG, "Badly formed boolean in configuration file: \"%s\".\n", parmvalue);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Process a parameter. */
|
||||
static BOOL do_parameter(char *parmname, char *parmvalue)
|
||||
{
|
||||
int parmnum, i;
|
||||
void *parm_ptr; /* where we are going to store the result */
|
||||
void *def_ptr;
|
||||
char *cp;
|
||||
|
||||
parmnum = map_parameter(parmname);
|
||||
|
||||
if (parmnum < 0) {
|
||||
rprintf(FLOG, "IGNORING unknown parameter \"%s\"\n", parmname);
|
||||
return True;
|
||||
}
|
||||
|
||||
def_ptr = parm_table[parmnum].ptr;
|
||||
|
||||
if (bInGlobalSection)
|
||||
parm_ptr = def_ptr;
|
||||
else {
|
||||
if (parm_table[parmnum].class == P_GLOBAL) {
|
||||
rprintf(FLOG, "Global parameter %s found in module section!\n", parmname);
|
||||
return True;
|
||||
}
|
||||
parm_ptr = SECTION_PTR(&iSECTION(iSectionIndex), def_ptr);
|
||||
}
|
||||
|
||||
/* now switch on the type of variable it is */
|
||||
switch (parm_table[parmnum].type) {
|
||||
case P_PATH:
|
||||
case P_STRING:
|
||||
/* delay expansion of vars */
|
||||
break;
|
||||
default:
|
||||
/* expand any %VARS% now */
|
||||
parmvalue = expand_vars(parmvalue);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (parm_table[parmnum].type) {
|
||||
case P_BOOL:
|
||||
set_boolean(parm_ptr, parmvalue);
|
||||
break;
|
||||
|
||||
case P_BOOLREV:
|
||||
set_boolean(parm_ptr, parmvalue);
|
||||
*(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
|
||||
break;
|
||||
|
||||
case P_INTEGER:
|
||||
*(int *)parm_ptr = atoi(parmvalue);
|
||||
break;
|
||||
|
||||
case P_CHAR:
|
||||
*(char *)parm_ptr = *parmvalue;
|
||||
break;
|
||||
|
||||
case P_OCTAL:
|
||||
sscanf(parmvalue, "%o", (int *)parm_ptr);
|
||||
break;
|
||||
|
||||
case P_PATH:
|
||||
string_set(parm_ptr, parmvalue);
|
||||
if ((cp = *(char**)parm_ptr) != NULL) {
|
||||
int len = strlen(cp);
|
||||
while (len > 1 && cp[len-1] == '/') len--;
|
||||
cp[len] = '\0';
|
||||
}
|
||||
break;
|
||||
|
||||
case P_STRING:
|
||||
string_set(parm_ptr, parmvalue);
|
||||
break;
|
||||
|
||||
case P_ENUM:
|
||||
for (i=0; parm_table[parmnum].enum_list[i].name; i++) {
|
||||
if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
|
||||
*(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!parm_table[parmnum].enum_list[i].name) {
|
||||
if (atoi(parmvalue) > 0)
|
||||
*(int *)parm_ptr = atoi(parmvalue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Process a new section (rsync module).
|
||||
* Returns True on success, False on failure. */
|
||||
static BOOL do_section(char *sectionname)
|
||||
{
|
||||
BOOL isglobal;
|
||||
|
||||
if (*sectionname == ']') { /* A special push/pop/reset directive from params.c */
|
||||
bInGlobalSection = 1;
|
||||
if (strcmp(sectionname+1, "push") == 0) {
|
||||
all_vars *vp = EXPAND_ITEM_LIST(&Vars_stack, all_vars, 2);
|
||||
memcpy(vp, &Vars, sizeof Vars);
|
||||
} else if (strcmp(sectionname+1, "pop") == 0
|
||||
|| strcmp(sectionname+1, "reset") == 0) {
|
||||
all_vars *vp = ((all_vars*)Vars_stack.items) + Vars_stack.count - 1;
|
||||
if (!Vars_stack.count)
|
||||
return False;
|
||||
memcpy(&Vars, vp, sizeof Vars);
|
||||
if (sectionname[1] == 'p')
|
||||
Vars_stack.count--;
|
||||
} else
|
||||
return False;
|
||||
return True;
|
||||
}
|
||||
|
||||
isglobal = strwicmp(sectionname, GLOBAL_NAME) == 0;
|
||||
|
||||
/* At the end of the global section, add any --dparam items. */
|
||||
if (bInGlobalSection && !isglobal) {
|
||||
if (!section_list.count)
|
||||
set_dparams(0);
|
||||
}
|
||||
|
||||
/* if we've just struck a global section, note the fact. */
|
||||
bInGlobalSection = isglobal;
|
||||
|
||||
/* check for multiple global sections */
|
||||
if (bInGlobalSection)
|
||||
return True;
|
||||
|
||||
#if 0
|
||||
/* If we have a current section, tidy it up before moving on. */
|
||||
if (iSectionIndex >= 0) {
|
||||
/* Add any tidy work as needed ... */
|
||||
if (problem)
|
||||
return False;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strchr(sectionname, '/') != NULL) {
|
||||
rprintf(FLOG, "Warning: invalid section name in configuration file: %s\n", sectionname);
|
||||
return False;
|
||||
}
|
||||
|
||||
if ((iSectionIndex = add_a_section(sectionname)) < 0) {
|
||||
rprintf(FLOG, "Failed to add a new module\n");
|
||||
bInGlobalSection = True;
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Load the modules from the config file. Return True on success,
|
||||
* False on failure. */
|
||||
int lp_load(char *pszFname, int globals_only)
|
||||
{
|
||||
bInGlobalSection = True;
|
||||
|
||||
reset_all_vars();
|
||||
|
||||
/* We get sections first, so have to start 'behind' to make up. */
|
||||
iSectionIndex = -1;
|
||||
return pm_process(pszFname, globals_only ? NULL : do_section, do_parameter);
|
||||
}
|
||||
|
||||
BOOL set_dparams(int syntax_check_only)
|
||||
{
|
||||
char *equal, *val, **params = dparam_list.items;
|
||||
unsigned j;
|
||||
|
||||
for (j = 0; j < dparam_list.count; j++) {
|
||||
equal = strchr(params[j], '='); /* options.c verified this */
|
||||
*equal = '\0';
|
||||
if (syntax_check_only) {
|
||||
if (map_parameter(params[j]) < 0) {
|
||||
rprintf(FERROR, "Unknown parameter \"%s\"\n", params[j]);
|
||||
*equal = '=';
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
for (val = equal+1; isSpace(val); val++) {}
|
||||
do_parameter(params[j], val);
|
||||
}
|
||||
*equal = '=';
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Return the max number of modules (sections). */
|
||||
int lp_num_modules(void)
|
||||
{
|
||||
return section_list.count;
|
||||
}
|
||||
|
||||
/* Return the number of the module with the given name, or -1 if it doesn't
|
||||
* exist. Note that this is a DIFFERENT ANIMAL from the internal function
|
||||
* getsectionbyname()! This works ONLY if all sections have been loaded,
|
||||
* and does not copy the found section. */
|
||||
int lp_number(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = section_list.count - 1; i >= 0; i--) {
|
||||
if (strcmp(lp_name(i), name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
896
rsync/log.c
Normal file
896
rsync/log.c
Normal file
@ -0,0 +1,896 @@
|
||||
/*
|
||||
* Logging and utility functions.
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
#include "inums.h"
|
||||
|
||||
extern int dry_run;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int local_server;
|
||||
extern int quiet;
|
||||
extern int module_id;
|
||||
extern int checksum_len;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int always_checksum;
|
||||
extern int preserve_times;
|
||||
extern int msgs2stderr;
|
||||
extern int stdout_format_has_i;
|
||||
extern int stdout_format_has_o_or_i;
|
||||
extern int logfile_format_has_i;
|
||||
extern int logfile_format_has_o_or_i;
|
||||
extern int receiver_symlink_times;
|
||||
extern int64 total_data_written;
|
||||
extern int64 total_data_read;
|
||||
extern mode_t orig_umask;
|
||||
extern char *auth_user;
|
||||
extern char *stdout_format;
|
||||
extern char *logfile_format;
|
||||
extern char *logfile_name;
|
||||
#ifdef ICONV_CONST
|
||||
extern iconv_t ic_chck;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_recv;
|
||||
#endif
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern char *full_module_path;
|
||||
extern unsigned int module_dirlen;
|
||||
extern char sender_file_sum[MAX_DIGEST_LEN];
|
||||
extern const char undetermined_hostname[];
|
||||
|
||||
static int log_initialised;
|
||||
static int logfile_was_closed;
|
||||
static FILE *logfile_fp;
|
||||
struct stats stats;
|
||||
|
||||
int got_xfer_error = 0;
|
||||
int output_needs_newline = 0;
|
||||
int send_msgs_to_gen = 0;
|
||||
|
||||
static int64 initial_data_written;
|
||||
static int64 initial_data_read;
|
||||
|
||||
struct {
|
||||
int code;
|
||||
char const *name;
|
||||
} const rerr_names[] = {
|
||||
{ RERR_SYNTAX , "syntax or usage error" },
|
||||
{ RERR_PROTOCOL , "protocol incompatibility" },
|
||||
{ RERR_FILESELECT , "errors selecting input/output files, dirs" },
|
||||
{ RERR_UNSUPPORTED, "requested action not supported" },
|
||||
{ RERR_STARTCLIENT, "error starting client-server protocol" },
|
||||
{ RERR_SOCKETIO , "error in socket IO" },
|
||||
{ RERR_FILEIO , "error in file IO" },
|
||||
{ RERR_STREAMIO , "error in rsync protocol data stream" },
|
||||
{ RERR_MESSAGEIO , "errors with program diagnostics" },
|
||||
{ RERR_IPC , "error in IPC code" },
|
||||
{ RERR_CRASHED , "sibling process crashed" },
|
||||
{ RERR_TERMINATED , "sibling process terminated abnormally" },
|
||||
{ RERR_SIGNAL1 , "received SIGUSR1" },
|
||||
{ RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" },
|
||||
{ RERR_WAITCHILD , "waitpid() failed" },
|
||||
{ RERR_MALLOC , "error allocating core memory buffers" },
|
||||
{ RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transferred" },
|
||||
{ RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" },
|
||||
{ RERR_TIMEOUT , "timeout in data send/receive" },
|
||||
{ RERR_CONTIMEOUT , "timeout waiting for daemon connection" },
|
||||
{ RERR_CMD_FAILED , "remote shell failed" },
|
||||
{ RERR_CMD_KILLED , "remote shell killed" },
|
||||
{ RERR_CMD_RUN , "remote command could not be run" },
|
||||
{ RERR_CMD_NOTFOUND,"remote command not found" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* Map from rsync error code to name, or return NULL.
|
||||
*/
|
||||
static char const *rerr_name(int code)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; rerr_names[i].name; i++) {
|
||||
if (rerr_names[i].code == code)
|
||||
return rerr_names[i].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void logit(int priority, const char *buf)
|
||||
{
|
||||
if (logfile_was_closed)
|
||||
logfile_reopen();
|
||||
if (logfile_fp) {
|
||||
fprintf(logfile_fp, "%s [%d] %s", timestring(time(NULL)), (int)getpid(), buf);
|
||||
fflush(logfile_fp);
|
||||
} else {
|
||||
syslog(priority, "%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void syslog_init()
|
||||
{
|
||||
static int been_here = 0;
|
||||
int options = LOG_PID;
|
||||
|
||||
if (been_here)
|
||||
return;
|
||||
been_here = 1;
|
||||
|
||||
#ifdef LOG_NDELAY
|
||||
options |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
#ifdef LOG_DAEMON
|
||||
openlog("rsyncd", options, lp_syslog_facility(module_id));
|
||||
#else
|
||||
openlog("rsyncd", options);
|
||||
#endif
|
||||
|
||||
#ifndef LOG_NDELAY
|
||||
logit(LOG_INFO, "rsyncd started\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void logfile_open(void)
|
||||
{
|
||||
mode_t old_umask = umask(022 | orig_umask);
|
||||
logfile_fp = fopen(logfile_name, "a");
|
||||
umask(old_umask);
|
||||
if (!logfile_fp) {
|
||||
int fopen_errno = errno;
|
||||
/* Rsync falls back to using syslog on failure. */
|
||||
syslog_init();
|
||||
rsyserr(FERROR, fopen_errno,
|
||||
"failed to open log-file %s", logfile_name);
|
||||
rprintf(FINFO, "Ignoring \"log file\" setting.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void log_init(int restart)
|
||||
{
|
||||
if (log_initialised) {
|
||||
if (!restart)
|
||||
return;
|
||||
if (strcmp(logfile_name, lp_log_file(module_id)) != 0) {
|
||||
if (logfile_fp) {
|
||||
fclose(logfile_fp);
|
||||
logfile_fp = NULL;
|
||||
} else
|
||||
closelog();
|
||||
logfile_name = NULL;
|
||||
} else if (*logfile_name)
|
||||
return; /* unchanged, non-empty "log file" names */
|
||||
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id))
|
||||
closelog();
|
||||
else
|
||||
return; /* unchanged syslog settings */
|
||||
} else
|
||||
log_initialised = 1;
|
||||
|
||||
/* This looks pointless, but it is needed in order for the
|
||||
* C library on some systems to fetch the timezone info
|
||||
* before the chroot. */
|
||||
timestring(time(NULL));
|
||||
|
||||
/* Optionally use a log file instead of syslog. (Non-daemon
|
||||
* rsyncs will have already set logfile_name, as needed.) */
|
||||
if (am_daemon && !logfile_name)
|
||||
logfile_name = lp_log_file(module_id);
|
||||
if (logfile_name && *logfile_name)
|
||||
logfile_open();
|
||||
else
|
||||
syslog_init();
|
||||
}
|
||||
|
||||
void logfile_close(void)
|
||||
{
|
||||
if (logfile_fp) {
|
||||
logfile_was_closed = 1;
|
||||
fclose(logfile_fp);
|
||||
logfile_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void logfile_reopen(void)
|
||||
{
|
||||
if (logfile_was_closed) {
|
||||
logfile_was_closed = 0;
|
||||
logfile_open();
|
||||
}
|
||||
}
|
||||
|
||||
static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
|
||||
{
|
||||
const char *s, *end = buf + len;
|
||||
for (s = buf; s < end; s++) {
|
||||
if ((s < end - 4
|
||||
&& *s == '\\' && s[1] == '#'
|
||||
&& isDigit(s + 2)
|
||||
&& isDigit(s + 3)
|
||||
&& isDigit(s + 4))
|
||||
|| (*s != '\t'
|
||||
&& ((use_isprint && !isPrint(s))
|
||||
|| *(uchar*)s < ' '))) {
|
||||
if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
fprintf(f, "\\#%03o", *(uchar*)s);
|
||||
buf = s + 1;
|
||||
}
|
||||
}
|
||||
if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
/* this is the underlying (unformatted) rsync debugging function. Call
|
||||
* it with FINFO, FERROR_*, FWARNING, FLOG, or FCLIENT. Note: recursion
|
||||
* can happen with certain fatal conditions. */
|
||||
void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
{
|
||||
int trailing_CR_or_NL;
|
||||
FILE *f = msgs2stderr ? stderr : stdout;
|
||||
#ifdef ICONV_OPTION
|
||||
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck;
|
||||
#else
|
||||
#ifdef ICONV_CONST
|
||||
iconv_t ic = ic_chck;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (msgs2stderr) {
|
||||
if (!am_daemon) {
|
||||
if (code == FLOG)
|
||||
return;
|
||||
goto output_msg;
|
||||
}
|
||||
if (code == FCLIENT)
|
||||
return;
|
||||
code = FLOG;
|
||||
} else if (send_msgs_to_gen) {
|
||||
assert(!is_utf8);
|
||||
/* Pass the message to our sibling in native charset. */
|
||||
send_msg((enum msgcode)code, buf, len, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == FERROR_SOCKET) /* This gets simplified for a non-sibling. */
|
||||
code = FERROR;
|
||||
else if (code == FERROR_UTF8) {
|
||||
is_utf8 = 1;
|
||||
code = FERROR;
|
||||
}
|
||||
|
||||
if (code == FCLIENT)
|
||||
code = FINFO;
|
||||
else if (am_daemon || logfile_name) {
|
||||
static int in_block;
|
||||
char msg[2048];
|
||||
int priority = code == FINFO || code == FLOG ? LOG_INFO : LOG_WARNING;
|
||||
|
||||
if (in_block)
|
||||
return;
|
||||
in_block = 1;
|
||||
if (!log_initialised)
|
||||
log_init(0);
|
||||
strlcpy(msg, buf, MIN((int)sizeof msg, len + 1));
|
||||
logit(priority, msg);
|
||||
in_block = 0;
|
||||
|
||||
if (code == FLOG || (am_daemon && !am_server))
|
||||
return;
|
||||
} else if (code == FLOG)
|
||||
return;
|
||||
|
||||
if (quiet && code == FINFO)
|
||||
return;
|
||||
|
||||
if (am_server) {
|
||||
enum msgcode msg = (enum msgcode)code;
|
||||
if (protocol_version < 30) {
|
||||
if (msg == MSG_ERROR)
|
||||
msg = MSG_ERROR_XFER;
|
||||
else if (msg == MSG_WARNING)
|
||||
msg = MSG_INFO;
|
||||
}
|
||||
/* Pass the message to the non-server side. */
|
||||
if (send_msg(msg, buf, len, !is_utf8))
|
||||
return;
|
||||
if (am_daemon) {
|
||||
/* TODO: can we send the error to the user somehow? */
|
||||
return;
|
||||
}
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
output_msg:
|
||||
switch (code) {
|
||||
case FERROR_XFER:
|
||||
got_xfer_error = 1;
|
||||
/* FALL THROUGH */
|
||||
case FERROR:
|
||||
case FERROR_UTF8:
|
||||
case FERROR_SOCKET:
|
||||
case FWARNING:
|
||||
f = stderr;
|
||||
break;
|
||||
case FLOG:
|
||||
case FINFO:
|
||||
case FCLIENT:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown logcode in rwrite(): %d [%s]\n", (int)code, who_am_i());
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (output_needs_newline) {
|
||||
fputc('\n', f);
|
||||
output_needs_newline = 0;
|
||||
}
|
||||
|
||||
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
|
||||
? buf[--len] : 0;
|
||||
|
||||
if (len && buf[0] == '\r') {
|
||||
fputc('\r', f);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
|
||||
#ifdef ICONV_CONST
|
||||
if (ic != (iconv_t)-1) {
|
||||
xbuf outbuf, inbuf;
|
||||
char convbuf[1024];
|
||||
int ierrno;
|
||||
|
||||
INIT_CONST_XBUF(outbuf, convbuf);
|
||||
INIT_XBUF(inbuf, (char*)buf, len, (size_t)-1);
|
||||
|
||||
while (inbuf.len) {
|
||||
iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT);
|
||||
ierrno = errno;
|
||||
if (outbuf.len) {
|
||||
filtered_fwrite(f, convbuf, outbuf.len, 0);
|
||||
outbuf.len = 0;
|
||||
}
|
||||
if (!ierrno || ierrno == E2BIG)
|
||||
continue;
|
||||
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
|
||||
inbuf.len--;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars);
|
||||
|
||||
if (trailing_CR_or_NL) {
|
||||
fputc(trailing_CR_or_NL, f);
|
||||
fflush(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the rsync debugging function. Call it with FINFO, FERROR_*,
|
||||
* FWARNING, FLOG, or FCLIENT. */
|
||||
void rprintf(enum logcode code, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[BIGPATHBUFLEN];
|
||||
size_t len;
|
||||
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(buf, sizeof buf, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Deal with buffer overruns. Instead of panicking, just
|
||||
* truncate the resulting string. (Note that configure ensures
|
||||
* that we have a vsnprintf() that doesn't ever return -1.) */
|
||||
if (len > sizeof buf - 1) {
|
||||
static const char ellipsis[] = "[...]";
|
||||
|
||||
/* Reset length, and zero-terminate the end of our buffer */
|
||||
len = sizeof buf - 1;
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Copy the ellipsis to the end of the string, but give
|
||||
* us one extra character:
|
||||
*
|
||||
* v--- null byte at buf[sizeof buf - 1]
|
||||
* abcdefghij0
|
||||
* -> abcd[...]00 <-- now two null bytes at end
|
||||
*
|
||||
* If the input format string has a trailing newline,
|
||||
* we copy it into that extra null; if it doesn't, well,
|
||||
* all we lose is one byte. */
|
||||
memcpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis);
|
||||
if (format[strlen(format)-1] == '\n') {
|
||||
buf[len-1] = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
rwrite(code, buf, len, 0);
|
||||
}
|
||||
|
||||
/* This is like rprintf, but it also tries to print some
|
||||
* representation of the error code. Normally errcode = errno.
|
||||
*
|
||||
* Unlike rprintf, this always adds a newline and there should not be
|
||||
* one in the format string.
|
||||
*
|
||||
* Note that since strerror might involve dynamically loading a
|
||||
* message catalog we need to call it once before chroot-ing. */
|
||||
void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[BIGPATHBUFLEN];
|
||||
size_t len;
|
||||
|
||||
strlcpy(buf, RSYNC_NAME ": ", sizeof buf);
|
||||
len = (sizeof RSYNC_NAME ": ") - 1;
|
||||
|
||||
va_start(ap, format);
|
||||
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len < sizeof buf) {
|
||||
len += snprintf(buf + len, sizeof buf - len,
|
||||
": %s (%d)\n", strerror(errcode), errcode);
|
||||
}
|
||||
if (len >= sizeof buf)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
rwrite(code, buf, len, 0);
|
||||
}
|
||||
|
||||
void rflush(enum logcode code)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (am_daemon || code == FLOG)
|
||||
return;
|
||||
|
||||
if (!am_server && (code == FINFO || code == FCLIENT))
|
||||
f = stdout;
|
||||
else
|
||||
f = stderr;
|
||||
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
void remember_initial_stats(void)
|
||||
{
|
||||
initial_data_read = total_data_read;
|
||||
initial_data_written = total_data_written;
|
||||
}
|
||||
|
||||
/* A generic logging routine for send/recv, with parameter substitiution. */
|
||||
static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
struct file_struct *file, const char *fname, int iflags,
|
||||
const char *hlink)
|
||||
{
|
||||
char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
|
||||
char *p, *s, *c;
|
||||
const char *n;
|
||||
size_t len, total;
|
||||
int64 b;
|
||||
|
||||
*fmt = '%';
|
||||
|
||||
/* We expand % codes one by one in place in buf. We don't
|
||||
* copy in the terminating null of the inserted strings, but
|
||||
* rather keep going until we reach the null of the format. */
|
||||
total = strlcpy(buf, format, sizeof buf);
|
||||
if (total > MAXPATHLEN) {
|
||||
rprintf(FERROR, "log-format string is WAY too long!\n");
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
buf[total++] = '\n';
|
||||
buf[total] = '\0';
|
||||
|
||||
for (p = buf; (p = strchr(p, '%')) != NULL; ) {
|
||||
int humanize = 0;
|
||||
s = p++;
|
||||
c = fmt + 1;
|
||||
while (*p == '\'') {
|
||||
humanize++;
|
||||
p++;
|
||||
}
|
||||
if (*p == '-')
|
||||
*c++ = *p++;
|
||||
while (isDigit(p) && c - fmt < (int)(sizeof fmt) - 8)
|
||||
*c++ = *p++;
|
||||
while (*p == '\'') {
|
||||
humanize++;
|
||||
p++;
|
||||
}
|
||||
if (!*p)
|
||||
break;
|
||||
*c = '\0';
|
||||
n = NULL;
|
||||
|
||||
/* Note for %h and %a: it doesn't matter what fd we pass to
|
||||
* client_{name,addr} because rsync_module will already have
|
||||
* forced the answer to be cached (assuming, of course, for %h
|
||||
* that lp_reverse_lookup(module_id) is true). */
|
||||
switch (*p) {
|
||||
case 'h':
|
||||
if (am_daemon) {
|
||||
n = lp_reverse_lookup(module_id)
|
||||
? client_name(0) : undetermined_hostname;
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
if (am_daemon)
|
||||
n = client_addr(0);
|
||||
break;
|
||||
case 'l':
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
do_big_num(F_LENGTH(file), humanize, NULL));
|
||||
n = buf2;
|
||||
break;
|
||||
case 'U':
|
||||
strlcat(fmt, "u", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
uid_ndx ? F_OWNER(file) : 0);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'G':
|
||||
if (!gid_ndx || file->flags & FLAG_SKIP_GROUP)
|
||||
n = "DEFAULT";
|
||||
else {
|
||||
strlcat(fmt, "u", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
F_GROUP(file));
|
||||
n = buf2;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
strlcat(fmt, "d", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, (int)getpid());
|
||||
n = buf2;
|
||||
break;
|
||||
case 'M':
|
||||
n = c = timestring(file->modtime);
|
||||
while ((c = strchr(c, ' ')) != NULL)
|
||||
*c = '-';
|
||||
break;
|
||||
case 'B':
|
||||
c = buf2 + MAXPATHLEN - PERMSTRING_SIZE - 1;
|
||||
permstring(c, file->mode);
|
||||
n = c + 1; /* skip the type char */
|
||||
break;
|
||||
case 'o':
|
||||
n = op;
|
||||
break;
|
||||
case 'f':
|
||||
if (fname) {
|
||||
c = f_name_buf();
|
||||
strlcpy(c, fname, MAXPATHLEN);
|
||||
} else
|
||||
c = f_name(file, NULL);
|
||||
if (am_sender && F_PATHNAME(file)) {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
F_PATHNAME(file), c);
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1]) {
|
||||
strlcpy(c, buf2, MAXPATHLEN);
|
||||
n = c;
|
||||
} else
|
||||
n = buf2;
|
||||
} else if (am_daemon && *c != '/') {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
curr_dir + module_dirlen, c);
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1]) {
|
||||
strlcpy(c, buf2, MAXPATHLEN);
|
||||
n = c;
|
||||
} else
|
||||
n = buf2;
|
||||
} else {
|
||||
clean_fname(c, 0);
|
||||
n = c;
|
||||
}
|
||||
if (*n == '/')
|
||||
n++;
|
||||
break;
|
||||
case 'n':
|
||||
if (fname) {
|
||||
c = f_name_buf();
|
||||
strlcpy(c, fname, MAXPATHLEN);
|
||||
} else
|
||||
c = f_name(file, NULL);
|
||||
if (S_ISDIR(file->mode))
|
||||
strlcat(c, "/", MAXPATHLEN);
|
||||
n = c;
|
||||
break;
|
||||
case 'L':
|
||||
if (hlink && *hlink) {
|
||||
n = hlink;
|
||||
strlcpy(buf2, " => ", sizeof buf2);
|
||||
} else if (S_ISLNK(file->mode) && !fname) {
|
||||
n = F_SYMLINK(file);
|
||||
strlcpy(buf2, " -> ", sizeof buf2);
|
||||
} else {
|
||||
n = "";
|
||||
if (!fmt[1])
|
||||
break;
|
||||
strlcpy(buf2, " ", sizeof buf2);
|
||||
}
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'm':
|
||||
n = lp_name(module_id);
|
||||
break;
|
||||
case 't':
|
||||
n = timestring(time(NULL));
|
||||
break;
|
||||
case 'P':
|
||||
n = full_module_path;
|
||||
break;
|
||||
case 'u':
|
||||
n = auth_user;
|
||||
break;
|
||||
case 'b':
|
||||
if (!(iflags & ITEM_TRANSFER))
|
||||
b = 0;
|
||||
else if (am_sender)
|
||||
b = total_data_written - initial_data_written;
|
||||
else
|
||||
b = total_data_read - initial_data_read;
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
do_big_num(b, humanize, NULL));
|
||||
n = buf2;
|
||||
break;
|
||||
case 'c':
|
||||
if (!(iflags & ITEM_TRANSFER))
|
||||
b = 0;
|
||||
else if (!am_sender)
|
||||
b = total_data_written - initial_data_written;
|
||||
else
|
||||
b = total_data_read - initial_data_read;
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
do_big_num(b, humanize, NULL));
|
||||
n = buf2;
|
||||
break;
|
||||
case 'C':
|
||||
if (protocol_version >= 30
|
||||
&& (iflags & ITEM_TRANSFER
|
||||
|| (always_checksum && S_ISREG(file->mode)))) {
|
||||
const char *sum = iflags & ITEM_TRANSFER
|
||||
? sender_file_sum : F_SUM(file);
|
||||
n = sum_as_hex(sum);
|
||||
} else {
|
||||
memset(buf2, ' ', checksum_len*2);
|
||||
buf2[checksum_len*2] = '\0';
|
||||
n = buf2;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
if (iflags & ITEM_DELETED) {
|
||||
n = "*deleting ";
|
||||
break;
|
||||
}
|
||||
n = c = buf2 + MAXPATHLEN - 32;
|
||||
c[0] = iflags & ITEM_LOCAL_CHANGE
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
if (S_ISLNK(file->mode)) {
|
||||
c[1] = 'L';
|
||||
c[3] = '.';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_times || !receiver_symlink_times
|
||||
|| (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
|
||||
} else {
|
||||
c[1] = S_ISDIR(file->mode) ? 'd'
|
||||
: IS_SPECIAL(file->mode) ? 'S'
|
||||
: IS_DEVICE(file->mode) ? 'D' : 'f';
|
||||
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_times ? 'T' : 't';
|
||||
}
|
||||
c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
|
||||
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
|
||||
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
|
||||
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
|
||||
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
|
||||
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
|
||||
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
|
||||
c[11] = '\0';
|
||||
|
||||
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
|
||||
char ch = iflags & ITEM_IS_NEW ? '+' : '?';
|
||||
int i;
|
||||
for (i = 2; c[i]; i++)
|
||||
c[i] = ch;
|
||||
} else if (c[0] == '.' || c[0] == 'h' || c[0] == 'c') {
|
||||
int i;
|
||||
for (i = 2; c[i]; i++) {
|
||||
if (c[i] != '.')
|
||||
break;
|
||||
}
|
||||
if (!c[i]) {
|
||||
for (i = 2; c[i]; i++)
|
||||
c[i] = ' ';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* "n" is the string to be inserted in place of this % code. */
|
||||
if (!n)
|
||||
continue;
|
||||
if (n != buf2 && fmt[1]) {
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, n);
|
||||
n = buf2;
|
||||
}
|
||||
len = strlen(n);
|
||||
|
||||
/* Subtract the length of the escape from the string's size. */
|
||||
total -= p - s + 1;
|
||||
|
||||
if (len + total >= (size_t)sizeof buf) {
|
||||
rprintf(FERROR,
|
||||
"buffer overflow expanding %%%c -- exiting\n",
|
||||
p[0]);
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
/* Shuffle the rest of the string along to make space for n */
|
||||
if (len != (size_t)(p - s + 1))
|
||||
memmove(s + len, p + 1, total - (s - buf) + 1);
|
||||
total += len;
|
||||
|
||||
/* Insert the contents of string "n", but NOT its null. */
|
||||
if (len)
|
||||
memcpy(s, n, len);
|
||||
|
||||
/* Skip over inserted string; continue looking */
|
||||
p = s + len;
|
||||
}
|
||||
|
||||
rwrite(code, buf, total, 0);
|
||||
}
|
||||
|
||||
/* Return 1 if the format escape is in the log-format string (e.g. look for
|
||||
* the 'b' in the "%9b" format escape). */
|
||||
int log_format_has(const char *format, char esc)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (!format)
|
||||
return 0;
|
||||
|
||||
for (p = format; (p = strchr(p, '%')) != NULL; ) {
|
||||
for (p++; *p == '\''; p++) {} /*SHARED ITERATOR*/
|
||||
if (*p == '-')
|
||||
p++;
|
||||
while (isDigit(p))
|
||||
p++;
|
||||
while (*p == '\'') p++;
|
||||
if (!*p)
|
||||
break;
|
||||
if (*p == esc)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Log the transfer of a file. If the code is FCLIENT, the output just goes
|
||||
* to stdout. If it is FLOG, it just goes to the log file. Otherwise we
|
||||
* output to both. */
|
||||
void log_item(enum logcode code, struct file_struct *file, int iflags, const char *hlink)
|
||||
{
|
||||
const char *s_or_r = am_sender ? "send" : "recv";
|
||||
|
||||
if (code != FLOG && stdout_format && !am_server)
|
||||
log_formatted(FCLIENT, stdout_format, s_or_r, file, NULL, iflags, hlink);
|
||||
if (code != FCLIENT && logfile_format && *logfile_format)
|
||||
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink);
|
||||
}
|
||||
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
const char *buf)
|
||||
{
|
||||
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
|
||||
int see_item = itemizing && (significant_flags || *buf
|
||||
|| stdout_format_has_i > 1 || (INFO_GTE(NAME, 2) && stdout_format_has_i));
|
||||
int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
|
||||
if (am_server) {
|
||||
if (logfile_name && !dry_run && see_item
|
||||
&& (significant_flags || logfile_format_has_i))
|
||||
log_item(FLOG, file, iflags, buf);
|
||||
} else if (see_item || local_change || *buf
|
||||
|| (S_ISDIR(file->mode) && significant_flags)) {
|
||||
enum logcode code = significant_flags || logfile_format_has_i ? FINFO : FCLIENT;
|
||||
log_item(code, file, iflags, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void log_delete(const char *fname, int mode)
|
||||
{
|
||||
static struct {
|
||||
union file_extras ex[4]; /* just in case... */
|
||||
struct file_struct file;
|
||||
} x; /* Zero-initialized due to static declaration. */
|
||||
int len = strlen(fname);
|
||||
const char *fmt;
|
||||
|
||||
x.file.mode = mode;
|
||||
|
||||
if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
|
||||
if (S_ISDIR(mode))
|
||||
len++; /* directories include trailing null */
|
||||
send_msg(MSG_DELETED, fname, len, am_generator);
|
||||
} else if (!INFO_GTE(DEL, 1) && !stdout_format)
|
||||
;
|
||||
else {
|
||||
fmt = stdout_format_has_o_or_i ? stdout_format : "deleting %n";
|
||||
log_formatted(FCLIENT, fmt, "del.", &x.file, fname, ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
if (!logfile_name || dry_run || !logfile_format)
|
||||
return;
|
||||
|
||||
fmt = logfile_format_has_o_or_i ? logfile_format : "deleting %n";
|
||||
log_formatted(FLOG, fmt, "del.", &x.file, fname, ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the transfer is interrupted for some reason.
|
||||
*
|
||||
* Code is one of the RERR_* codes from errcode.h, or terminating
|
||||
* successfully.
|
||||
*/
|
||||
void log_exit(int code, const char *file, int line)
|
||||
{
|
||||
if (code == 0) {
|
||||
rprintf(FLOG,"sent %s bytes received %s bytes total size %s\n",
|
||||
big_num(stats.total_written),
|
||||
big_num(stats.total_read),
|
||||
big_num(stats.total_size));
|
||||
} else if (am_server != 2) {
|
||||
const char *name;
|
||||
|
||||
name = rerr_name(code);
|
||||
if (!name)
|
||||
name = "unexplained error";
|
||||
|
||||
/* VANISHED is not an error, only a warning */
|
||||
if (code == RERR_VANISHED) {
|
||||
rprintf(FWARNING, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n",
|
||||
name, code, file, line, who_am_i(), RSYNC_VERSION);
|
||||
} else {
|
||||
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n",
|
||||
name, code, file, line, who_am_i(), RSYNC_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
1640
rsync/main.c
Normal file
1640
rsync/main.c
Normal file
File diff suppressed because it is too large
Load Diff
448
rsync/match.c
Normal file
448
rsync/match.c
Normal file
@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Block matching used by the file-transfer code.
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "inums.h"
|
||||
|
||||
extern int checksum_seed;
|
||||
extern int append_mode;
|
||||
extern int checksum_len;
|
||||
|
||||
int updating_basis_file;
|
||||
char sender_file_sum[MAX_DIGEST_LEN];
|
||||
|
||||
static int false_alarms;
|
||||
static int hash_hits;
|
||||
static int matches;
|
||||
static int64 data_transfer;
|
||||
|
||||
static int total_false_alarms;
|
||||
static int total_hash_hits;
|
||||
static int total_matches;
|
||||
|
||||
extern struct stats stats;
|
||||
|
||||
#define TRADITIONAL_TABLESIZE (1<<16)
|
||||
|
||||
static uint32 tablesize;
|
||||
static int32 *hash_table;
|
||||
|
||||
#define SUM2HASH2(s1,s2) (((s1) + (s2)) & 0xFFFF)
|
||||
#define SUM2HASH(sum) SUM2HASH2((sum)&0xFFFF,(sum)>>16)
|
||||
|
||||
#define BIG_SUM2HASH(sum) ((sum)%tablesize)
|
||||
|
||||
static void build_hash_table(struct sum_struct *s)
|
||||
{
|
||||
static uint32 alloc_size;
|
||||
int32 i;
|
||||
|
||||
/* Dynamically calculate the hash table size so that the hash load
|
||||
* for big files is about 80%. A number greater than the traditional
|
||||
* size must be odd or s2 will not be able to span the entire set. */
|
||||
tablesize = (uint32)(s->count/8) * 10 + 11;
|
||||
if (tablesize < TRADITIONAL_TABLESIZE)
|
||||
tablesize = TRADITIONAL_TABLESIZE;
|
||||
if (tablesize > alloc_size || tablesize < alloc_size - 16*1024) {
|
||||
if (hash_table)
|
||||
free(hash_table);
|
||||
hash_table = new_array(int32, tablesize);
|
||||
if (!hash_table)
|
||||
out_of_memory("build_hash_table");
|
||||
alloc_size = tablesize;
|
||||
}
|
||||
|
||||
memset(hash_table, 0xFF, tablesize * sizeof hash_table[0]);
|
||||
|
||||
if (tablesize == TRADITIONAL_TABLESIZE) {
|
||||
for (i = 0; i < s->count; i++) {
|
||||
uint32 t = SUM2HASH(s->sums[i].sum1);
|
||||
s->sums[i].chain = hash_table[t];
|
||||
hash_table[t] = i;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < s->count; i++) {
|
||||
uint32 t = BIG_SUM2HASH(s->sums[i].sum1);
|
||||
s->sums[i].chain = hash_table[t];
|
||||
hash_table[t] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static OFF_T last_match;
|
||||
|
||||
|
||||
/* Transmit a literal and/or match token.
|
||||
*
|
||||
* This delightfully-named function is called either when we find a
|
||||
* match and need to transmit all the unmatched data leading up to it,
|
||||
* or when we get bored of accumulating literal data and just need to
|
||||
* transmit it. As a result of this second case, it is called even if
|
||||
* we have not matched at all!
|
||||
*
|
||||
* If i >= 0, the number of a matched token. If < 0, indicates we have
|
||||
* only literal data. A -1 will send a 0-token-int too, and a -2 sends
|
||||
* only literal data, w/o any token-int. */
|
||||
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
OFF_T offset, int32 i)
|
||||
{
|
||||
int32 n = (int32)(offset - last_match); /* max value: block_size (int32) */
|
||||
int32 j;
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2) && i >= 0) {
|
||||
rprintf(FINFO,
|
||||
"match at %s last_match=%s j=%d len=%ld n=%ld\n",
|
||||
big_num(offset), big_num(last_match), i,
|
||||
(long)s->sums[i].len, (long)n);
|
||||
}
|
||||
|
||||
send_token(f, i, buf, last_match, n, i < 0 ? 0 : s->sums[i].len);
|
||||
data_transfer += n;
|
||||
|
||||
if (i >= 0) {
|
||||
stats.matched_data += s->sums[i].len;
|
||||
n += s->sums[i].len;
|
||||
}
|
||||
|
||||
for (j = 0; j < n; j += CHUNK_SIZE) {
|
||||
int32 n1 = MIN(CHUNK_SIZE, n - j);
|
||||
sum_update(map_ptr(buf, last_match + j, n1), n1);
|
||||
}
|
||||
|
||||
if (i >= 0)
|
||||
last_match = offset + s->sums[i].len;
|
||||
else
|
||||
last_match = offset;
|
||||
|
||||
if (buf && INFO_GTE(PROGRESS, 1))
|
||||
show_progress(last_match, buf->file_size);
|
||||
}
|
||||
|
||||
|
||||
static void hash_search(int f,struct sum_struct *s,
|
||||
struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
OFF_T offset, aligned_offset, end;
|
||||
int32 k, want_i, aligned_i, backup;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
schar *map;
|
||||
|
||||
/* want_i is used to encourage adjacent matches, allowing the RLL
|
||||
* coding of the output to work more efficiently. */
|
||||
want_i = 0;
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2)) {
|
||||
rprintf(FINFO, "hash search b=%ld len=%s\n",
|
||||
(long)s->blength, big_num(len));
|
||||
}
|
||||
|
||||
k = (int32)MIN(len, (OFF_T)s->blength);
|
||||
|
||||
map = (schar *)map_ptr(buf, 0, k);
|
||||
|
||||
sum = get_checksum1((char *)map, k);
|
||||
s1 = sum & 0xFFFF;
|
||||
s2 = sum >> 16;
|
||||
if (DEBUG_GTE(DELTASUM, 3))
|
||||
rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k);
|
||||
|
||||
offset = aligned_offset = aligned_i = 0;
|
||||
|
||||
end = len + 1 - s->sums[s->count-1].len;
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 3)) {
|
||||
rprintf(FINFO, "hash search s->blength=%ld len=%s count=%s\n",
|
||||
(long)s->blength, big_num(len), big_num(s->count));
|
||||
}
|
||||
|
||||
do {
|
||||
int done_csum2 = 0;
|
||||
uint32 hash_entry;
|
||||
int32 i, *prev;
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 4)) {
|
||||
rprintf(FINFO, "offset=%s sum=%04x%04x\n",
|
||||
big_num(offset), s2 & 0xFFFF, s1 & 0xFFFF);
|
||||
}
|
||||
|
||||
if (tablesize == TRADITIONAL_TABLESIZE) {
|
||||
hash_entry = SUM2HASH2(s1,s2);
|
||||
if ((i = hash_table[hash_entry]) < 0)
|
||||
goto null_hash;
|
||||
sum = (s1 & 0xffff) | (s2 << 16);
|
||||
} else {
|
||||
sum = (s1 & 0xffff) | (s2 << 16);
|
||||
hash_entry = BIG_SUM2HASH(sum);
|
||||
if ((i = hash_table[hash_entry]) < 0)
|
||||
goto null_hash;
|
||||
}
|
||||
prev = &hash_table[hash_entry];
|
||||
|
||||
hash_hits++;
|
||||
do {
|
||||
int32 l;
|
||||
|
||||
/* When updating in-place, the chunk's offset must be
|
||||
* either >= our offset or identical data at that offset.
|
||||
* Remove any bypassed entries that we can never use. */
|
||||
if (updating_basis_file && s->sums[i].offset < offset
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) {
|
||||
*prev = s->sums[i].chain;
|
||||
continue;
|
||||
}
|
||||
prev = &s->sums[i].chain;
|
||||
|
||||
if (sum != s->sums[i].sum1)
|
||||
continue;
|
||||
|
||||
/* also make sure the two blocks are the same length */
|
||||
l = (int32)MIN((OFF_T)s->blength, len-offset);
|
||||
if (l != s->sums[i].len)
|
||||
continue;
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 3)) {
|
||||
rprintf(FINFO,
|
||||
"potential match at %s i=%ld sum=%08x\n",
|
||||
big_num(offset), (long)i, sum);
|
||||
}
|
||||
|
||||
if (!done_csum2) {
|
||||
map = (schar *)map_ptr(buf,offset,l);
|
||||
get_checksum2((char *)map,l,sum2);
|
||||
done_csum2 = 1;
|
||||
}
|
||||
|
||||
if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) {
|
||||
false_alarms++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* When updating in-place, the best possible match is
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the adjacent want_i optimization. */
|
||||
if (updating_basis_file) {
|
||||
/* All the generator's chunks start at blength boundaries. */
|
||||
while (aligned_offset < offset) {
|
||||
aligned_offset += s->blength;
|
||||
aligned_i++;
|
||||
}
|
||||
if ((offset == aligned_offset
|
||||
|| (sum == 0 && l == s->blength && aligned_offset + l <= len))
|
||||
&& aligned_i < s->count) {
|
||||
if (i != aligned_i) {
|
||||
if (sum != s->sums[aligned_i].sum1
|
||||
|| l != s->sums[aligned_i].len
|
||||
|| memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0)
|
||||
goto check_want_i;
|
||||
i = aligned_i;
|
||||
}
|
||||
if (offset != aligned_offset) {
|
||||
/* We've matched some zeros in a spot that is also zeros
|
||||
* further along in the basis file, if we find zeros ahead
|
||||
* in the sender's file, we'll output enough literal data
|
||||
* to re-align with the basis file, and get back to seeking
|
||||
* instead of writing. */
|
||||
backup = (int32)(aligned_offset - last_match);
|
||||
if (backup < 0)
|
||||
backup = 0;
|
||||
map = (schar *)map_ptr(buf, aligned_offset - backup, l + backup)
|
||||
+ backup;
|
||||
sum = get_checksum1((char *)map, l);
|
||||
if (sum != s->sums[i].sum1)
|
||||
goto check_want_i;
|
||||
get_checksum2((char *)map, l, sum2);
|
||||
if (memcmp(sum2, s->sums[i].sum2, s->s2length) != 0)
|
||||
goto check_want_i;
|
||||
/* OK, we have a re-alignment match. Bump the offset
|
||||
* forward to the new match point. */
|
||||
offset = aligned_offset;
|
||||
}
|
||||
/* This identical chunk is in the same spot in the old and new file. */
|
||||
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
|
||||
want_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
check_want_i:
|
||||
/* we've found a match, but now check to see
|
||||
* if want_i can hint at a better match. */
|
||||
if (i != want_i && want_i < s->count
|
||||
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|
||||
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
|
||||
&& sum == s->sums[want_i].sum1
|
||||
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = want_i;
|
||||
}
|
||||
want_i = i + 1;
|
||||
|
||||
matched(f,s,buf,offset,i);
|
||||
offset += s->sums[i].len - 1;
|
||||
k = (int32)MIN((OFF_T)s->blength, len-offset);
|
||||
map = (schar *)map_ptr(buf, offset, k);
|
||||
sum = get_checksum1((char *)map, k);
|
||||
s1 = sum & 0xFFFF;
|
||||
s2 = sum >> 16;
|
||||
matches++;
|
||||
break;
|
||||
} while ((i = s->sums[i].chain) >= 0);
|
||||
|
||||
null_hash:
|
||||
backup = (int32)(offset - last_match);
|
||||
/* We sometimes read 1 byte prior to last_match... */
|
||||
if (backup < 0)
|
||||
backup = 0;
|
||||
|
||||
/* Trim off the first byte from the checksum */
|
||||
more = offset + k < len;
|
||||
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
|
||||
+ backup;
|
||||
s1 -= map[0] + CHAR_OFFSET;
|
||||
s2 -= k * (map[0]+CHAR_OFFSET);
|
||||
|
||||
/* Add on the next byte (if there is one) to the checksum */
|
||||
if (more) {
|
||||
s1 += map[k] + CHAR_OFFSET;
|
||||
s2 += s1;
|
||||
} else
|
||||
--k;
|
||||
|
||||
/* By matching early we avoid re-reading the
|
||||
data 3 times in the case where a token
|
||||
match comes a long way after last
|
||||
match. The 3 reads are caused by the
|
||||
running match, the checksum update and the
|
||||
literal send. */
|
||||
if (backup >= s->blength+CHUNK_SIZE && end-offset > CHUNK_SIZE)
|
||||
matched(f, s, buf, offset - s->blength, -2);
|
||||
} while (++offset < end);
|
||||
|
||||
matched(f, s, buf, len, -1);
|
||||
map_ptr(buf, len-1, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan through a origin file, looking for sections that match
|
||||
* checksums from the generator, and transmit either literal or token
|
||||
* data.
|
||||
*
|
||||
* Also calculates the MD4 checksum of the whole file, using the md
|
||||
* accumulator. This is transmitted with the file as protection
|
||||
* against corruption on the wire.
|
||||
*
|
||||
* @param s Checksums received from the generator. If <tt>s->count ==
|
||||
* 0</tt>, then there are actually no checksums for this file.
|
||||
*
|
||||
* @param len Length of the file to send.
|
||||
**/
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
hash_hits = 0;
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
if (append_mode == 2) {
|
||||
OFF_T j = 0;
|
||||
for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
|
||||
if (buf && INFO_GTE(PROGRESS, 1))
|
||||
show_progress(last_match, buf->file_size);
|
||||
sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
|
||||
CHUNK_SIZE);
|
||||
last_match = j;
|
||||
}
|
||||
if (last_match < s->flength) {
|
||||
int32 n = (int32)(s->flength - last_match);
|
||||
if (buf && INFO_GTE(PROGRESS, 1))
|
||||
show_progress(last_match, buf->file_size);
|
||||
sum_update(map_ptr(buf, last_match, n), n);
|
||||
}
|
||||
}
|
||||
last_match = s->flength;
|
||||
s->count = 0;
|
||||
}
|
||||
|
||||
if (len > 0 && s->count > 0) {
|
||||
build_hash_table(s);
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"built hash table\n");
|
||||
|
||||
hash_search(f, s, buf, len);
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"done hash search\n");
|
||||
} else {
|
||||
OFF_T j;
|
||||
/* by doing this in pieces we avoid too many seeks */
|
||||
for (j = last_match + CHUNK_SIZE; j < len; j += CHUNK_SIZE)
|
||||
matched(f, s, buf, j, -2);
|
||||
matched(f, s, buf, len, -1);
|
||||
}
|
||||
|
||||
if (sum_end(sender_file_sum) != checksum_len)
|
||||
overflow_exit("checksum_len"); /* Impossible... */
|
||||
|
||||
/* If we had a read error, send a bad checksum. We use all bits
|
||||
* off as long as the checksum doesn't happen to be that, in
|
||||
* which case we turn the last 0 bit into a 1. */
|
||||
if (buf && buf->status != 0) {
|
||||
int i;
|
||||
for (i = 0; i < checksum_len && sender_file_sum[i] == 0; i++) {}
|
||||
memset(sender_file_sum, 0, checksum_len);
|
||||
if (i == checksum_len)
|
||||
sender_file_sum[i-1]++;
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f, sender_file_sum, checksum_len);
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2)) {
|
||||
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
|
||||
false_alarms, hash_hits, matches);
|
||||
}
|
||||
|
||||
total_hash_hits += hash_hits;
|
||||
total_false_alarms += false_alarms;
|
||||
total_matches += matches;
|
||||
stats.literal_data += data_transfer;
|
||||
}
|
||||
|
||||
void match_report(void)
|
||||
{
|
||||
if (!DEBUG_GTE(DELTASUM, 1))
|
||||
return;
|
||||
|
||||
rprintf(FINFO,
|
||||
"total: matches=%d hash_hits=%d false_alarms=%d data=%s\n",
|
||||
total_matches, total_hash_hits, total_false_alarms,
|
||||
big_num(stats.literal_data));
|
||||
}
|
48
rsync/mkproto.pl
Normal file
48
rsync/mkproto.pl
Normal file
@ -0,0 +1,48 @@
|
||||
# generate prototypes for rsync
|
||||
|
||||
$old_protos = '';
|
||||
if (open(IN, 'proto.h')) {
|
||||
$old_protos = join('', <IN>);
|
||||
close IN;
|
||||
}
|
||||
|
||||
%FN_MAP = (
|
||||
BOOL => 'BOOL ',
|
||||
CHAR => 'char ',
|
||||
INTEGER => 'int ',
|
||||
STRING => 'char *',
|
||||
);
|
||||
|
||||
$inheader = 0;
|
||||
$protos = qq|/* This file is automatically generated with "make proto". DO NOT EDIT */\n\n|;
|
||||
|
||||
while (<>) {
|
||||
if ($inheader) {
|
||||
if (/[)][ \t]*$/) {
|
||||
$inheader = 0;
|
||||
s/$/;/;
|
||||
}
|
||||
$protos .= $_;
|
||||
} elsif (/^FN_(LOCAL|GLOBAL)_([^(]+)\(([^,()]+)/) {
|
||||
$ret = $FN_MAP{$2};
|
||||
$func = $3;
|
||||
$arg = $1 eq 'LOCAL' ? 'int module_id' : 'void';
|
||||
$protos .= "$ret$func($arg);\n";
|
||||
} elsif (/^static|^extern/ || /[;]/ || !/^[A-Za-z][A-Za-z0-9_]* /) {
|
||||
;
|
||||
} elsif (/[(].*[)][ \t]*$/) {
|
||||
s/$/;/;
|
||||
$protos .= $_;
|
||||
} elsif (/[(]/) {
|
||||
$inheader = 1;
|
||||
$protos .= $_;
|
||||
}
|
||||
}
|
||||
|
||||
if ($old_protos ne $protos) {
|
||||
open(OUT, '>proto.h') or die $!;
|
||||
print OUT $protos;
|
||||
close OUT;
|
||||
}
|
||||
|
||||
open(OUT, '>proto.h-tstamp') and close OUT;
|
2880
rsync/options.c
Normal file
2880
rsync/options.c
Normal file
File diff suppressed because it is too large
Load Diff
666
rsync/params.c
Normal file
666
rsync/params.c
Normal file
@ -0,0 +1,666 @@
|
||||
/* This modules is based on the params.c module from Samba, written by Karl Auer
|
||||
and much modifed by Christopher Hertel. */
|
||||
|
||||
/*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* Module name: params
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* This module performs lexical analysis and initial parsing of a
|
||||
* Windows-like parameter file. It recognizes and handles four token
|
||||
* types: section-name, parameter-name, parameter-value, and
|
||||
* end-of-file. Comments and line continuation are handled
|
||||
* internally.
|
||||
*
|
||||
* The entry point to the module is function pm_process(). This
|
||||
* function opens the source file, calls the Parse() function to parse
|
||||
* the input, and then closes the file when either the EOF is reached
|
||||
* or a fatal error is encountered.
|
||||
*
|
||||
* A sample parameter file might look like this:
|
||||
*
|
||||
* [section one]
|
||||
* parameter one = value string
|
||||
* parameter two = another value
|
||||
* [section two]
|
||||
* new parameter = some value or t'other
|
||||
*
|
||||
* The parameter file is divided into sections by section headers:
|
||||
* section names enclosed in square brackets (eg. [section one]).
|
||||
* Each section contains parameter lines, each of which consist of a
|
||||
* parameter name and value delimited by an equal sign. Roughly, the
|
||||
* syntax is:
|
||||
*
|
||||
* <file> :== { <section> } EOF
|
||||
*
|
||||
* <section> :== <section header> { <parameter line> }
|
||||
*
|
||||
* <section header> :== '[' NAME ']'
|
||||
*
|
||||
* <parameter line> :== NAME '=' VALUE '\n'
|
||||
*
|
||||
* Blank lines and comment lines are ignored. Comment lines are lines
|
||||
* beginning with either a semicolon (';') or a pound sign ('#').
|
||||
*
|
||||
* All whitespace in section names and parameter names is compressed
|
||||
* to single spaces. Leading and trailing whitespace is stipped from
|
||||
* both names and values.
|
||||
*
|
||||
* Only the first equals sign in a parameter line is significant.
|
||||
* Parameter values may contain equals signs, square brackets and
|
||||
* semicolons. Internal whitespace is retained in parameter values,
|
||||
* with the exception of the '\r' character, which is stripped for
|
||||
* historic reasons. Parameter names may not start with a left square
|
||||
* bracket, an equal sign, a pound sign, or a semicolon, because these
|
||||
* are used to identify other tokens.
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#include "itypes.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Constants...
|
||||
*/
|
||||
|
||||
#define BUFR_INC 1024
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Variables...
|
||||
*
|
||||
* bufr - pointer to a global buffer. This is probably a kludge,
|
||||
* but it was the nicest kludge I could think of (for now).
|
||||
* bSize - The size of the global buffer <bufr>.
|
||||
*/
|
||||
|
||||
static char *bufr = NULL;
|
||||
static int bSize = 0;
|
||||
static BOOL (*the_sfunc)(char *);
|
||||
static BOOL (*the_pfunc)(char *, char *);
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions...
|
||||
*/
|
||||
|
||||
static int EatWhitespace( FILE *InFile )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan past whitespace (see ctype(3C)) and return the first non-whitespace
|
||||
* character, or newline, or EOF.
|
||||
*
|
||||
* Input: InFile - Input source.
|
||||
*
|
||||
* Output: The next non-whitespace character in the input stream.
|
||||
*
|
||||
* Notes: Because the config files use a line-oriented grammar, we
|
||||
* explicitly exclude the newline character from the list of
|
||||
* whitespace characters.
|
||||
* - Note that both EOF (-1) and the nul character ('\0') are
|
||||
* considered end-of-file markers.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int c;
|
||||
|
||||
for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) )
|
||||
;
|
||||
return( c );
|
||||
} /* EatWhitespace */
|
||||
|
||||
static int EatComment( FILE *InFile )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan to the end of a comment.
|
||||
*
|
||||
* Input: InFile - Input source.
|
||||
*
|
||||
* Output: The character that marks the end of the comment. Normally,
|
||||
* this will be a newline, but it *might* be an EOF.
|
||||
*
|
||||
* Notes: Because the config files use a line-oriented grammar, we
|
||||
* explicitly exclude the newline character from the list of
|
||||
* whitespace characters.
|
||||
* - Note that both EOF (-1) and the nul character ('\0') are
|
||||
* considered end-of-file markers.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int c;
|
||||
|
||||
for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) )
|
||||
;
|
||||
return( c );
|
||||
} /* EatComment */
|
||||
|
||||
static int Continuation( char *line, int pos )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan backards within a string to discover if the last non-whitespace
|
||||
* character is a line-continuation character ('\\').
|
||||
*
|
||||
* Input: line - A pointer to a buffer containing the string to be
|
||||
* scanned.
|
||||
* pos - This is taken to be the offset of the end of the
|
||||
* string. This position is *not* scanned.
|
||||
*
|
||||
* Output: The offset of the '\\' character if it was found, or -1 to
|
||||
* indicate that it was not.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
pos--;
|
||||
while( pos >= 0 && isSpace(line + pos) )
|
||||
pos--;
|
||||
|
||||
return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
|
||||
} /* Continuation */
|
||||
|
||||
|
||||
static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan a section name, and pass the name to function sfunc().
|
||||
*
|
||||
* Input: InFile - Input source.
|
||||
* sfunc - Pointer to the function to be called if the section
|
||||
* name is successfully read.
|
||||
*
|
||||
* Output: True if the section name was read and True was returned from
|
||||
* <sfunc>. False if <sfunc> failed or if a lexical error was
|
||||
* encountered.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
int end;
|
||||
char *func = "params.c:Section() -";
|
||||
|
||||
i = 0; /* <i> is the offset of the next free byte in bufr[] and */
|
||||
end = 0; /* <end> is the current "end of string" offset. In most */
|
||||
/* cases these will be the same, but if the last */
|
||||
/* character written to bufr[] is a space, then <end> */
|
||||
/* will be one less than <i>. */
|
||||
|
||||
c = EatWhitespace( InFile ); /* We've already got the '['. Scan */
|
||||
/* past initial white space. */
|
||||
|
||||
while( (EOF != c) && (c > 0) )
|
||||
{
|
||||
|
||||
/* Check that the buffer is big enough for the next character. */
|
||||
if( i > (bSize - 2) )
|
||||
{
|
||||
bSize += BUFR_INC;
|
||||
bufr = realloc_array( bufr, char, bSize );
|
||||
if( NULL == bufr )
|
||||
{
|
||||
rprintf(FLOG, "%s Memory re-allocation failure.", func);
|
||||
return( False );
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle a single character. */
|
||||
switch( c )
|
||||
{
|
||||
case ']': /* Found the closing bracket. */
|
||||
bufr[end] = '\0';
|
||||
if( 0 == end ) /* Don't allow an empty name. */
|
||||
{
|
||||
rprintf(FLOG, "%s Empty section name in config file.\n", func );
|
||||
return( False );
|
||||
}
|
||||
if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */
|
||||
return( False );
|
||||
(void)EatComment( InFile ); /* Finish off the line. */
|
||||
return( True );
|
||||
|
||||
case '\n': /* Got newline before closing ']'. */
|
||||
i = Continuation( bufr, i ); /* Check for line continuation. */
|
||||
if( i < 0 )
|
||||
{
|
||||
bufr[end] = '\0';
|
||||
rprintf(FLOG, "%s Badly formed line in config file: %s\n",
|
||||
func, bufr );
|
||||
return( False );
|
||||
}
|
||||
end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
|
||||
c = getc( InFile ); /* Continue with next line. */
|
||||
break;
|
||||
|
||||
default: /* All else are a valid name chars. */
|
||||
if( isspace( c ) ) /* One space per whitespace region. */
|
||||
{
|
||||
bufr[end] = ' ';
|
||||
i = end + 1;
|
||||
c = EatWhitespace( InFile );
|
||||
}
|
||||
else /* All others copy verbatim. */
|
||||
{
|
||||
bufr[i++] = c;
|
||||
end = i;
|
||||
c = getc( InFile );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We arrive here if we've met the EOF before the closing bracket. */
|
||||
rprintf(FLOG, "%s Unexpected EOF in the config file: %s\n", func, bufr );
|
||||
return( False );
|
||||
} /* Section */
|
||||
|
||||
static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan a parameter name and value, and pass these two fields to pfunc().
|
||||
*
|
||||
* Input: InFile - The input source.
|
||||
* pfunc - A pointer to the function that will be called to
|
||||
* process the parameter, once it has been scanned.
|
||||
* c - The first character of the parameter name, which
|
||||
* would have been read by Parse(). Unlike a comment
|
||||
* line or a section header, there is no lead-in
|
||||
* character that can be discarded.
|
||||
*
|
||||
* Output: True if the parameter name and value were scanned and processed
|
||||
* successfully, else False.
|
||||
*
|
||||
* Notes: This function is in two parts. The first loop scans the
|
||||
* parameter name. Internal whitespace is compressed, and an
|
||||
* equal sign (=) terminates the token. Leading and trailing
|
||||
* whitespace is discarded. The second loop scans the parameter
|
||||
* value. When both have been successfully identified, they are
|
||||
* passed to pfunc() for processing.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i = 0; /* Position within bufr. */
|
||||
int end = 0; /* bufr[end] is current end-of-string. */
|
||||
int vstart = 0; /* Starting position of the parameter value. */
|
||||
char *func = "params.c:Parameter() -";
|
||||
|
||||
/* Read the parameter name. */
|
||||
while( 0 == vstart ) /* Loop until we've found the start of the value. */
|
||||
{
|
||||
|
||||
if( i > (bSize - 2) ) /* Ensure there's space for next char. */
|
||||
{
|
||||
bSize += BUFR_INC;
|
||||
bufr = realloc_array( bufr, char, bSize );
|
||||
if( NULL == bufr )
|
||||
{
|
||||
rprintf(FLOG, "%s Memory re-allocation failure.", func) ;
|
||||
return( False );
|
||||
}
|
||||
}
|
||||
|
||||
switch( c )
|
||||
{
|
||||
case '=': /* Equal sign marks end of param name. */
|
||||
if( 0 == end ) /* Don't allow an empty name. */
|
||||
{
|
||||
rprintf(FLOG, "%s Invalid parameter name in config file.\n", func );
|
||||
return( False );
|
||||
}
|
||||
bufr[end++] = '\0'; /* Mark end of string & advance. */
|
||||
i = vstart = end; /* New string starts here. */
|
||||
c = EatWhitespace(InFile);
|
||||
break;
|
||||
|
||||
case '\n': /* Find continuation char, else error. */
|
||||
i = Continuation( bufr, i );
|
||||
if( i < 0 )
|
||||
{
|
||||
bufr[end] = '\0';
|
||||
rprintf(FLOG, "%s Ignoring badly formed line in config file: %s\n",
|
||||
func, bufr );
|
||||
return( True );
|
||||
}
|
||||
end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
|
||||
c = getc( InFile ); /* Read past eoln. */
|
||||
break;
|
||||
|
||||
case '\0': /* Shouldn't have EOF within param name. */
|
||||
case EOF:
|
||||
bufr[i] = '\0';
|
||||
rprintf(FLOG, "%s Unexpected end-of-file at: %s\n", func, bufr );
|
||||
return( True );
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
/* A directive divides at the first space or tab. */
|
||||
if (*bufr == '&') {
|
||||
bufr[end++] = '\0';
|
||||
i = vstart = end;
|
||||
c = EatWhitespace(InFile);
|
||||
if (c == '=')
|
||||
c = EatWhitespace(InFile);
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
if( isspace( c ) ) /* One ' ' per whitespace region. */
|
||||
{
|
||||
bufr[end] = ' ';
|
||||
i = end + 1;
|
||||
c = EatWhitespace( InFile );
|
||||
}
|
||||
else /* All others verbatim. */
|
||||
{
|
||||
bufr[i++] = c;
|
||||
end = i;
|
||||
c = getc( InFile );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now parse the value. */
|
||||
while( (EOF !=c) && (c > 0) )
|
||||
{
|
||||
|
||||
if( i > (bSize - 2) ) /* Make sure there's enough room. */
|
||||
{
|
||||
bSize += BUFR_INC;
|
||||
bufr = realloc_array( bufr, char, bSize );
|
||||
if( NULL == bufr )
|
||||
{
|
||||
rprintf(FLOG, "%s Memory re-allocation failure.", func) ;
|
||||
return( False );
|
||||
}
|
||||
}
|
||||
|
||||
switch( c )
|
||||
{
|
||||
case '\r': /* Explicitly remove '\r' because the older */
|
||||
c = getc( InFile ); /* version called fgets_slash() which also */
|
||||
break; /* removes them. */
|
||||
|
||||
case '\n': /* Marks end of value unless there's a '\'. */
|
||||
i = Continuation( bufr, i );
|
||||
if( i < 0 )
|
||||
c = 0;
|
||||
else
|
||||
{
|
||||
for( end = i; end >= 0 && isSpace(bufr + end); end-- )
|
||||
;
|
||||
c = getc( InFile );
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* All others verbatim. Note that spaces do */
|
||||
bufr[i++] = c; /* not advance <end>. This allows trimming */
|
||||
if( !isspace( c ) ) /* of whitespace at the end of the line. */
|
||||
end = i;
|
||||
c = getc( InFile );
|
||||
break;
|
||||
}
|
||||
}
|
||||
bufr[end] = '\0'; /* End of value. */
|
||||
|
||||
return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
|
||||
} /* Parameter */
|
||||
|
||||
static int name_cmp(const void *n1, const void *n2)
|
||||
{
|
||||
return strcmp(*(char * const *)n1, *(char * const *)n2);
|
||||
}
|
||||
|
||||
static int include_config(char *include, int manage_globals)
|
||||
{
|
||||
STRUCT_STAT sb;
|
||||
char *match = manage_globals ? "*.conf" : "*.inc";
|
||||
int ret;
|
||||
|
||||
if (do_stat(include, &sb) < 0) {
|
||||
rsyserr(FLOG, errno, "unable to stat config file \"%s\"", include);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISREG(sb.st_mode)) {
|
||||
if (manage_globals && the_sfunc)
|
||||
the_sfunc("]push");
|
||||
ret = pm_process(include, the_sfunc, the_pfunc);
|
||||
if (manage_globals && the_sfunc)
|
||||
the_sfunc("]pop");
|
||||
} else if (S_ISDIR(sb.st_mode)) {
|
||||
char buf[MAXPATHLEN], **bpp;
|
||||
item_list conf_list;
|
||||
struct dirent *di;
|
||||
size_t j;
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(include))) {
|
||||
rsyserr(FLOG, errno, "unable to open config dir \"%s\"", include);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&conf_list, 0, sizeof conf_list);
|
||||
|
||||
while ((di = readdir(d)) != NULL) {
|
||||
char *dname = d_name(di);
|
||||
if (!wildmatch(match, dname))
|
||||
continue;
|
||||
bpp = EXPAND_ITEM_LIST(&conf_list, char *, 32);
|
||||
pathjoin(buf, sizeof buf, include, dname);
|
||||
*bpp = strdup(buf);
|
||||
}
|
||||
closedir(d);
|
||||
|
||||
if (!(bpp = conf_list.items))
|
||||
return 1;
|
||||
|
||||
if (conf_list.count > 1)
|
||||
qsort(bpp, conf_list.count, sizeof (char *), name_cmp);
|
||||
|
||||
for (j = 0, ret = 1; j < conf_list.count; j++) {
|
||||
if (manage_globals && the_sfunc)
|
||||
the_sfunc(j == 0 ? "]push" : "]reset");
|
||||
if ((ret = pm_process(bpp[j], the_sfunc, the_pfunc)) != 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (manage_globals && the_sfunc)
|
||||
the_sfunc("]pop");
|
||||
|
||||
for (j = 0; j < conf_list.count; j++)
|
||||
free(bpp[j]);
|
||||
free(bpp);
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_directives(char *name, char *val)
|
||||
{
|
||||
if (strcasecmp(name, "&include") == 0)
|
||||
return include_config(val, 1);
|
||||
if (strcasecmp(name, "&merge") == 0)
|
||||
return include_config(val, 0);
|
||||
rprintf(FLOG, "Unknown directive: %s.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Parse( FILE *InFile,
|
||||
BOOL (*sfunc)(char *),
|
||||
BOOL (*pfunc)(char *, char *) )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan & parse the input.
|
||||
*
|
||||
* Input: InFile - Input source.
|
||||
* sfunc - Function to be called when a section name is scanned.
|
||||
* See Section().
|
||||
* pfunc - Function to be called when a parameter is scanned.
|
||||
* See Parameter().
|
||||
*
|
||||
* Output: 1 if the file was successfully scanned, 2 if the file was
|
||||
* scanned until a section header with no section function, else 0.
|
||||
*
|
||||
* Notes: The input can be viewed in terms of 'lines'. There are four
|
||||
* types of lines:
|
||||
* Blank - May contain whitespace, otherwise empty.
|
||||
* Comment - First non-whitespace character is a ';' or '#'.
|
||||
* The remainder of the line is ignored.
|
||||
* Section - First non-whitespace character is a '['.
|
||||
* Parameter - The default case.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int c;
|
||||
|
||||
c = EatWhitespace( InFile );
|
||||
while( (EOF != c) && (c > 0) )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case '\n': /* Blank line. */
|
||||
c = EatWhitespace( InFile );
|
||||
break;
|
||||
|
||||
case ';': /* Comment line. */
|
||||
case '#':
|
||||
c = EatComment( InFile );
|
||||
break;
|
||||
|
||||
case '[': /* Section Header. */
|
||||
if (!sfunc)
|
||||
return 2;
|
||||
if( !Section( InFile, sfunc ) )
|
||||
return 0;
|
||||
c = EatWhitespace( InFile );
|
||||
break;
|
||||
|
||||
case '\\': /* Bogus backslash. */
|
||||
c = EatWhitespace( InFile );
|
||||
break;
|
||||
|
||||
case '&': /* Handle directives */
|
||||
the_sfunc = sfunc;
|
||||
the_pfunc = pfunc;
|
||||
c = Parameter( InFile, parse_directives, c );
|
||||
if (c != 1)
|
||||
return c;
|
||||
c = EatWhitespace( InFile );
|
||||
break;
|
||||
|
||||
default: /* Parameter line. */
|
||||
if( !Parameter( InFile, pfunc, c ) )
|
||||
return 0;
|
||||
c = EatWhitespace( InFile );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} /* Parse */
|
||||
|
||||
static FILE *OpenConfFile( char *FileName )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Open a config file.
|
||||
*
|
||||
* Input: FileName - The pathname of the config file to be opened.
|
||||
*
|
||||
* Output: A pointer of type (FILE *) to the opened file, or NULL if the
|
||||
* file could not be opened.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
FILE *OpenedFile;
|
||||
char *func = "params.c:OpenConfFile() -";
|
||||
|
||||
if( NULL == FileName || 0 == *FileName )
|
||||
{
|
||||
rprintf(FLOG, "%s No config filename specified.\n", func);
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
OpenedFile = fopen( FileName, "r" );
|
||||
if( NULL == OpenedFile )
|
||||
{
|
||||
rsyserr(FLOG, errno, "unable to open config file \"%s\"",
|
||||
FileName);
|
||||
}
|
||||
|
||||
return( OpenedFile );
|
||||
} /* OpenConfFile */
|
||||
|
||||
int pm_process( char *FileName,
|
||||
BOOL (*sfunc)(char *),
|
||||
BOOL (*pfunc)(char *, char *) )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Process the named parameter file.
|
||||
*
|
||||
* Input: FileName - The pathname of the parameter file to be opened.
|
||||
* sfunc - A pointer to a function that will be called when
|
||||
* a section name is discovered.
|
||||
* pfunc - A pointer to a function that will be called when
|
||||
* a parameter name and value are discovered.
|
||||
*
|
||||
* Output: 1 if the file was successfully parsed, 2 if parsing ended at a
|
||||
* section header w/o a section function, else 0.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int result;
|
||||
FILE *InFile;
|
||||
char *func = "params.c:pm_process() -";
|
||||
|
||||
InFile = OpenConfFile( FileName ); /* Open the config file. */
|
||||
if( NULL == InFile )
|
||||
return( False );
|
||||
|
||||
if( NULL != bufr ) /* If we already have a buffer */
|
||||
result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */
|
||||
/* use it. */
|
||||
|
||||
else /* If we don't have a buffer */
|
||||
{ /* allocate one, then parse, */
|
||||
bSize = BUFR_INC; /* then free. */
|
||||
bufr = new_array( char, bSize );
|
||||
if( NULL == bufr )
|
||||
{
|
||||
rprintf(FLOG, "%s memory allocation failure.\n", func);
|
||||
fclose(InFile);
|
||||
return( False );
|
||||
}
|
||||
result = Parse( InFile, sfunc, pfunc );
|
||||
free( bufr );
|
||||
bufr = NULL;
|
||||
bSize = 0;
|
||||
}
|
||||
|
||||
fclose(InFile);
|
||||
|
||||
if( !result ) /* Generic failure. */
|
||||
{
|
||||
rprintf(FLOG, "%s Failed. Error returned from params.c:parse().\n", func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* pm_process */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
180
rsync/pipe.c
Normal file
180
rsync/pipe.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Routines used to setup various kinds of inter-process pipes.
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int blocking_io;
|
||||
extern int filesfrom_fd;
|
||||
extern int munge_symlinks;
|
||||
extern char *logfile_name;
|
||||
extern int remote_option_cnt;
|
||||
extern const char **remote_options;
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
|
||||
/**
|
||||
* Create a child connected to us via its stdin/stdout.
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
* Note that in the child STDIN is set to blocking and STDOUT
|
||||
* is set to non-blocking. This is necessary as rsh relies on stdin being blocking
|
||||
* and ssh relies on stdout being non-blocking
|
||||
*
|
||||
* If blocking_io is set then use blocking io on both fds. That can be
|
||||
* used to cope with badly broken rsh implementations like the one on
|
||||
* Solaris.
|
||||
**/
|
||||
pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
{
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
|
||||
if (DEBUG_GTE(CMD, 1))
|
||||
print_child_argv("opening connection using:", command);
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO)
|
||||
close(from_child_pipe[1]);
|
||||
set_blocking(STDIN_FILENO);
|
||||
if (blocking_io > 0)
|
||||
set_blocking(STDOUT_FILENO);
|
||||
execvp(command[0], command);
|
||||
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
*f_in = from_child_pipe[0];
|
||||
*f_out = to_child_pipe[1];
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* This function forks a child which calls child_main(). First,
|
||||
* however, it has to establish communication paths to and from the
|
||||
* newborn child. It creates two socket pairs -- one for writing to
|
||||
* the child (from the parent) and one for reading from the child
|
||||
* (writing to the parent). Since that's four socket ends, each
|
||||
* process has to close the two ends it doesn't need. The remaining
|
||||
* two socket ends are retained for reading and writing. In the
|
||||
* child, the STDIN and STDOUT file descriptors refer to these
|
||||
* sockets. In the parent, the function arguments f_in and f_out are
|
||||
* set to refer to these sockets. */
|
||||
pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
int (*child_main)(int, char*[]))
|
||||
{
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
|
||||
/* The parent process is always the sender for a local rsync. */
|
||||
assert(am_sender);
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 ||
|
||||
fd_pair(from_child_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
am_sender = 0;
|
||||
am_server = 1;
|
||||
filesfrom_fd = -1;
|
||||
munge_symlinks = 0; /* Each side needs its own option. */
|
||||
chmod_modes = NULL; /* Let the sending side handle this. */
|
||||
|
||||
/* Let the client side handle this. */
|
||||
if (logfile_name) {
|
||||
logfile_name = NULL;
|
||||
logfile_close();
|
||||
}
|
||||
|
||||
if (remote_option_cnt) {
|
||||
int rc = remote_option_cnt + 1;
|
||||
const char **rv = remote_options;
|
||||
if (!parse_arguments(&rc, &rv)) {
|
||||
option_error();
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO)
|
||||
close(from_child_pipe[1]);
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 ||
|
||||
close(to_child_pipe[0]) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
*f_in = from_child_pipe[0];
|
||||
*f_out = to_child_pipe[1];
|
||||
|
||||
return pid;
|
||||
}
|
46
rsync/popt/CHANGES
Normal file
46
rsync/popt/CHANGES
Normal file
@ -0,0 +1,46 @@
|
||||
1.5 -> 1.6
|
||||
- add ability to perform callbacks for every, not just first, match.
|
||||
|
||||
1.3 -> 1.5
|
||||
- heavy dose of const's
|
||||
- poptParseArgvString() now NULL terminates the list
|
||||
|
||||
1.2.3 -> 1.3
|
||||
- added support for single -
|
||||
- misc bug fixes
|
||||
- portability improvements
|
||||
|
||||
1.2.2 -> 1.2.3
|
||||
- fixed memset() in help message generation (Dale Hawkins)
|
||||
- added extern "C" stuff to popt.h for C++ compilers (Dale Hawkins)
|
||||
- const'ified poptParseArgvString (Jeff Garzik)
|
||||
|
||||
1.2.1 -> 1.2.2
|
||||
- fixed bug in chaind alias happens which seems to have only
|
||||
affected --triggers in rpm
|
||||
- added POPT_ARG_VAL
|
||||
- popt.3 installed by default
|
||||
|
||||
1.2 -> 1.2.1
|
||||
- added POPT_ARG_INTL_DOMAIN (Elliot Lee)
|
||||
- updated Makefile's to be more GNUish (Elliot Lee)
|
||||
|
||||
1.1 -> 1.2
|
||||
- added popt.3 man page (Robert Lynch)
|
||||
- don't use mmap anymore (its lack of portability isn't worth the
|
||||
trouble)
|
||||
- added test script
|
||||
- added support for exec
|
||||
- removed support for *_POPT_ALIASES env variable -- it was a bad
|
||||
idea
|
||||
- reorganized into multiple source files
|
||||
- added automatic help generation, POPT_AUTOHELP
|
||||
- added table callbacks
|
||||
- added table inclusion
|
||||
- updated man page for new features
|
||||
- added test scripts
|
||||
|
||||
1.0 -> 1.1
|
||||
- moved to autoconf (Fred Fish)
|
||||
- added STRERROR replacement (Norbert Warmuth)
|
||||
- added const keywords (Bruce Perens)
|
22
rsync/popt/COPYING
Normal file
22
rsync/popt/COPYING
Normal file
@ -0,0 +1,22 @@
|
||||
Copyright (c) 1998 Red Hat Software
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of the X Consortium shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from the X Consortium.
|
18
rsync/popt/README
Normal file
18
rsync/popt/README
Normal file
@ -0,0 +1,18 @@
|
||||
This is the popt command line option parsing library. While it is similiar
|
||||
to getopt(3), it contains a number of enhancements, including:
|
||||
|
||||
1) popt is fully reentrant
|
||||
2) popt can parse arbitrary argv[] style arrays while
|
||||
getopt(2) makes this quite difficult
|
||||
3) popt allows users to alias command line arguments
|
||||
4) popt provides convience functions for parsing strings
|
||||
into argv[] style arrays
|
||||
|
||||
popt is used by rpm, the Red Hat install program, and many other Red Hat
|
||||
utilities, all of which provide excellent examples of how to use popt.
|
||||
Complete documentation on popt is available in popt.ps (included in this
|
||||
tarball), which is excerpted with permission from the book "Linux
|
||||
Application Development" by Michael K. Johnson and Erik Troan (availble
|
||||
from Addison Wesley in May, 1998).
|
||||
|
||||
Comments on popt should be addressed to ewt@redhat.com.
|
4
rsync/popt/README.rsync
Normal file
4
rsync/popt/README.rsync
Normal file
@ -0,0 +1,4 @@
|
||||
This is a perfectly ordinary copy of libpopt. It is only used on platforms
|
||||
that do not have a sufficiently up-to-date copy of their own. If you build
|
||||
rsync on a platform which has popt, this directory should not be used. (You
|
||||
can control that using the --with-included-popt configure flag.)
|
0
rsync/popt/dummy.in
Normal file
0
rsync/popt/dummy.in
Normal file
55
rsync/popt/findme.c
Normal file
55
rsync/popt/findme.c
Normal file
@ -0,0 +1,55 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/findme.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "findme.h"
|
||||
|
||||
const char * findProgramPath(const char * argv0)
|
||||
{
|
||||
char * path = getenv("PATH");
|
||||
char * pathbuf;
|
||||
char * start, * chptr;
|
||||
char * buf;
|
||||
size_t bufsize;
|
||||
|
||||
if (argv0 == NULL) return NULL; /* XXX can't happen */
|
||||
/* If there is a / in the argv[0], it has to be an absolute path */
|
||||
if (strchr(argv0, '/'))
|
||||
return xstrdup(argv0);
|
||||
|
||||
if (path == NULL) return NULL;
|
||||
|
||||
bufsize = strlen(path) + 1;
|
||||
start = pathbuf = alloca(bufsize);
|
||||
if (pathbuf == NULL) return NULL; /* XXX can't happen */
|
||||
strlcpy(pathbuf, path, bufsize);
|
||||
bufsize += sizeof "/" - 1 + strlen(argv0);
|
||||
buf = malloc(bufsize);
|
||||
if (buf == NULL) return NULL; /* XXX can't happen */
|
||||
|
||||
chptr = NULL;
|
||||
/*@-branchstate@*/
|
||||
do {
|
||||
if ((chptr = strchr(start, ':')))
|
||||
*chptr = '\0';
|
||||
snprintf(buf, bufsize, "%s/%s", start, argv0);
|
||||
|
||||
if (!access(buf, X_OK))
|
||||
return buf;
|
||||
|
||||
if (chptr)
|
||||
start = chptr + 1;
|
||||
else
|
||||
start = NULL;
|
||||
} while (start && *start);
|
||||
/*@=branchstate@*/
|
||||
|
||||
free(buf);
|
||||
|
||||
return NULL;
|
||||
}
|
20
rsync/popt/findme.h
Normal file
20
rsync/popt/findme.h
Normal file
@ -0,0 +1,20 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/findme.h
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#ifndef H_FINDME
|
||||
#define H_FINDME
|
||||
|
||||
/**
|
||||
* Return absolute path to executable by searching PATH.
|
||||
* @param argv0 name of executable
|
||||
* @return (malloc'd) absolute path to executable (or NULL)
|
||||
*/
|
||||
/*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0)
|
||||
/*@*/;
|
||||
|
||||
#endif
|
1283
rsync/popt/popt.c
Normal file
1283
rsync/popt/popt.c
Normal file
File diff suppressed because it is too large
Load Diff
565
rsync/popt/popt.h
Normal file
565
rsync/popt/popt.h
Normal file
@ -0,0 +1,565 @@
|
||||
/** \file popt/popt.h
|
||||
* \ingroup popt
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#ifndef H_POPT
|
||||
#define H_POPT
|
||||
|
||||
#include <stdio.h> /* for FILE * */
|
||||
|
||||
#define POPT_OPTION_DEPTH 10
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Arg type identifiers
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_ARG_NONE 0 /*!< no arg */
|
||||
#define POPT_ARG_STRING 1 /*!< arg will be saved as string */
|
||||
#define POPT_ARG_INT 2 /*!< arg will be converted to int */
|
||||
#define POPT_ARG_LONG 3 /*!< arg will be converted to long */
|
||||
#define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */
|
||||
#define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be
|
||||
set first in table; arg points
|
||||
to callback, descrip points to
|
||||
callback data to pass */
|
||||
#define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain
|
||||
for this table and any
|
||||
included tables; arg points
|
||||
to the domain string */
|
||||
#define POPT_ARG_VAL 7 /*!< arg should take value val */
|
||||
#define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */
|
||||
#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */
|
||||
|
||||
#define POPT_ARG_MASK 0x0000FFFF
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Arg modifiers
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */
|
||||
#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */
|
||||
#define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */
|
||||
#define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */
|
||||
|
||||
#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */
|
||||
#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */
|
||||
#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */
|
||||
#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */
|
||||
#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */
|
||||
#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */
|
||||
#define POPT_ARGFLAG_LOGICALOPS \
|
||||
(POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR)
|
||||
|
||||
#define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR)
|
||||
/*!< set arg bit(s) */
|
||||
#define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND)
|
||||
/*!< clear arg bit(s) */
|
||||
|
||||
#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */
|
||||
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Callback modifiers
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */
|
||||
#define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */
|
||||
#define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line,
|
||||
not the subtable */
|
||||
#define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */
|
||||
#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Error return values
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_ERROR_NOARG -10 /*!< missing argument */
|
||||
#define POPT_ERROR_BADOPT -11 /*!< unknown option */
|
||||
#define POPT_ERROR_UNWANTEDARG -12 /*!< option does not take an argument */
|
||||
#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */
|
||||
#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */
|
||||
#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */
|
||||
#define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */
|
||||
#define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */
|
||||
#define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */
|
||||
#define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */
|
||||
#define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name poptBadOption() flags
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name poptGetContext() flags
|
||||
*/
|
||||
/*@{*/
|
||||
#define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */
|
||||
#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */
|
||||
#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */
|
||||
#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
struct poptOption {
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * longName; /*!< may be NULL */
|
||||
char shortName; /*!< may be NUL */
|
||||
int argInfo;
|
||||
/*@shared@*/ /*@null@*/
|
||||
void * arg; /*!< depends on argInfo */
|
||||
int val; /*!< 0 means don't return, just update flag */
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * descrip; /*!< description for autohelp -- may be NULL */
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * argDescrip; /*!< argument description for autohelp */
|
||||
};
|
||||
|
||||
/** \ingroup popt
|
||||
* A popt alias argument for poptAddAlias().
|
||||
*/
|
||||
struct poptAlias {
|
||||
/*@owned@*/ /*@null@*/
|
||||
const char * longName; /*!< may be NULL */
|
||||
char shortName; /*!< may be NUL */
|
||||
int argc;
|
||||
/*@owned@*/
|
||||
const char ** argv; /*!< must be free()able */
|
||||
};
|
||||
|
||||
/** \ingroup popt
|
||||
* A popt alias or exec argument for poptAddItem().
|
||||
*/
|
||||
/*@-exporttype@*/
|
||||
typedef struct poptItem_s {
|
||||
struct poptOption option; /*!< alias/exec name(s) and description. */
|
||||
int argc; /*!< (alias) no. of args. */
|
||||
/*@owned@*/
|
||||
const char ** argv; /*!< (alias) args, must be free()able. */
|
||||
} * poptItem;
|
||||
/*@=exporttype@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Auto-generated help/usage
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Empty table marker to enable displaying popt alias/exec options.
|
||||
*/
|
||||
/*@-exportvar@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
extern struct poptOption poptAliasOptions[];
|
||||
/*@=exportvar@*/
|
||||
#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \
|
||||
0, "Options implemented via popt alias/exec:", NULL },
|
||||
|
||||
/**
|
||||
* Auto help table options.
|
||||
*/
|
||||
/*@-exportvar@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
extern struct poptOption poptHelpOptions[];
|
||||
/*@=exportvar@*/
|
||||
|
||||
/*@-exportvar@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
extern struct poptOption * poptHelpOptionsI18N;
|
||||
/*@=exportvar@*/
|
||||
|
||||
#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
|
||||
0, "Help options:", NULL },
|
||||
|
||||
#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
|
||||
/*@}*/
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
/*@-exporttype@*/
|
||||
typedef /*@abstract@*/ struct poptContext_s * poptContext;
|
||||
/*@=exporttype@*/
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
/*@-exporttype -typeuse@*/
|
||||
typedef struct poptOption * poptOption;
|
||||
/*@=exporttype =typeuse@*/
|
||||
#endif
|
||||
|
||||
/*@-exportconst@*/
|
||||
enum poptCallbackReason {
|
||||
POPT_CALLBACK_REASON_PRE = 0,
|
||||
POPT_CALLBACK_REASON_POST = 1,
|
||||
POPT_CALLBACK_REASON_OPTION = 2
|
||||
};
|
||||
/*@=exportconst@*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*@-type@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Table callback prototype.
|
||||
* @param con context
|
||||
* @param reason reason for callback
|
||||
* @param opt option that triggered callback
|
||||
* @param arg @todo Document.
|
||||
* @param data @todo Document.
|
||||
*/
|
||||
typedef void (*poptCallbackType) (poptContext con,
|
||||
enum poptCallbackReason reason,
|
||||
/*@null@*/ const struct poptOption * opt,
|
||||
/*@null@*/ const char * arg,
|
||||
/*@null@*/ const void * data)
|
||||
/*@globals internalState @*/
|
||||
/*@modifies internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Initialize popt context.
|
||||
* @param name context name (usually argv[0] program name)
|
||||
* @param argc no. of arguments
|
||||
* @param argv argument array
|
||||
* @param options address of popt option table
|
||||
* @param flags or'd POPT_CONTEXT_* bits
|
||||
* @return initialized popt context
|
||||
*/
|
||||
/*@only@*/ /*@null@*/
|
||||
poptContext poptGetContext(
|
||||
/*@dependent@*/ /*@keep@*/ const char * name,
|
||||
int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
|
||||
/*@dependent@*/ /*@keep@*/ const struct poptOption * options,
|
||||
int flags)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Reinitialize popt context.
|
||||
* @param con context
|
||||
*/
|
||||
/*@unused@*/
|
||||
void poptResetContext(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return value of next option found.
|
||||
* @param con context
|
||||
* @return next option val, -1 on last item, POPT_ERROR_* on error
|
||||
*/
|
||||
int poptGetNextOpt(/*@null@*/poptContext con)
|
||||
/*@globals fileSystem, internalState @*/
|
||||
/*@modifies con, fileSystem, internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return next option argument (if any).
|
||||
* @param con context
|
||||
* @return option argument, NULL if no argument is available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ /*@unused@*/
|
||||
const char * poptGetOptArg(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return next argument.
|
||||
* @param con context
|
||||
* @return next argument, NULL if no argument is available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ /*@unused@*/
|
||||
const char * poptGetArg(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Peek at current argument.
|
||||
* @param con context
|
||||
* @return current argument, NULL if no argument is available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ /*@unused@*/
|
||||
const char * poptPeekArg(/*@null@*/poptContext con)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return remaining arguments.
|
||||
* @param con context
|
||||
* @return argument array, NULL terminated
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char ** poptGetArgs(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return the option which caused the most recent error.
|
||||
* @param con context
|
||||
* @param flags
|
||||
* @return offending option
|
||||
*/
|
||||
/*@observer@*/
|
||||
const char * poptBadOption(/*@null@*/poptContext con, int flags)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Destroy context.
|
||||
* @param con context
|
||||
* @return NULL always
|
||||
*/
|
||||
/*@null@*/
|
||||
poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Add arguments to context.
|
||||
* @param con context
|
||||
* @param argv argument array, NULL terminated
|
||||
* @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure
|
||||
*/
|
||||
/*@unused@*/
|
||||
int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Add alias to context.
|
||||
* @todo Pass alias by reference, not value.
|
||||
* @deprecated Use poptAddItem instead.
|
||||
* @param con context
|
||||
* @param alias alias to add
|
||||
* @param flags (unused)
|
||||
* @return 0 on success
|
||||
*/
|
||||
/*@unused@*/
|
||||
int poptAddAlias(poptContext con, struct poptAlias alias, int flags)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Add alias/exec item to context.
|
||||
* @param con context
|
||||
* @param newItem alias/exec item to add
|
||||
* @param flags 0 for alias, 1 for exec
|
||||
* @return 0 on success
|
||||
*/
|
||||
int poptAddItem(poptContext con, poptItem newItem, int flags)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Read configuration file.
|
||||
* @param con context
|
||||
* @param fn file name to read
|
||||
* @return 0 on success, POPT_ERROR_ERRNO on failure
|
||||
*/
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
/*@globals errno, fileSystem, internalState @*/
|
||||
/*@modifies con->execs, con->numExecs,
|
||||
errno, fileSystem, internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Read default configuration from /etc/popt and $HOME/.popt.
|
||||
* @param con context
|
||||
* @param useEnv (unused)
|
||||
* @return 0 on success, POPT_ERROR_ERRNO on failure
|
||||
*/
|
||||
/*@unused@*/
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
|
||||
/*@globals fileSystem, internalState @*/
|
||||
/*@modifies con->execs, con->numExecs,
|
||||
fileSystem, internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Duplicate an argument array.
|
||||
* @note: The argument array is malloc'd as a single area, so only argv must
|
||||
* be free'd.
|
||||
*
|
||||
* @param argc no. of arguments
|
||||
* @param argv argument array
|
||||
* @retval argcPtr address of returned no. of arguments
|
||||
* @retval argvPtr address of returned argument array
|
||||
* @return 0 on success, POPT_ERROR_NOARG on failure
|
||||
*/
|
||||
int poptDupArgv(int argc, /*@null@*/ const char **argv,
|
||||
/*@null@*/ /*@out@*/ int * argcPtr,
|
||||
/*@null@*/ /*@out@*/ const char *** argvPtr)
|
||||
/*@modifies *argcPtr, *argvPtr @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Parse a string into an argument array.
|
||||
* The parse allows ', ", and \ quoting, but ' is treated the same as " and
|
||||
* both may include \ quotes.
|
||||
* @note: The argument array is malloc'd as a single area, so only argv must
|
||||
* be free'd.
|
||||
*
|
||||
* @param s string to parse
|
||||
* @retval argcPtr address of returned no. of arguments
|
||||
* @retval argvPtr address of returned argument array
|
||||
*/
|
||||
int poptParseArgvString(const char * s,
|
||||
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
|
||||
/*@modifies *argcPtr, *argvPtr @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Parses an input configuration file and returns an string that is a
|
||||
* command line. For use with popt. You must free the return value when done.
|
||||
*
|
||||
* Given the file:
|
||||
\verbatim
|
||||
# this line is ignored
|
||||
# this one too
|
||||
aaa
|
||||
bbb
|
||||
ccc
|
||||
bla=bla
|
||||
|
||||
this_is = fdsafdas
|
||||
bad_line=
|
||||
reall bad line
|
||||
reall bad line = again
|
||||
5555= 55555
|
||||
test = with lots of spaces
|
||||
\endverbatim
|
||||
*
|
||||
* The result is:
|
||||
\verbatim
|
||||
--aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces"
|
||||
\endverbatim
|
||||
*
|
||||
* Passing this to poptParseArgvString() yields an argv of:
|
||||
\verbatim
|
||||
'--aaa'
|
||||
'--bbb'
|
||||
'--ccc'
|
||||
'--bla=bla'
|
||||
'--this_is=fdsafdas'
|
||||
'--5555=55555'
|
||||
'--test=with lots of spaces'
|
||||
\endverbatim
|
||||
*
|
||||
* @bug NULL is returned if file line is too long.
|
||||
* @bug Silently ignores invalid lines.
|
||||
*
|
||||
* @param fp file handle to read
|
||||
* @param *argstrp return string of options (malloc'd)
|
||||
* @param flags unused
|
||||
* @return 0 on success
|
||||
* @see poptParseArgvString
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, *argstrp, fileSystem @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Return formatted error string for popt failure.
|
||||
* @param error popt error
|
||||
* @return error string
|
||||
*/
|
||||
/*@observer@*/
|
||||
const char * poptStrerror(const int error)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Limit search for executables.
|
||||
* @param con context
|
||||
* @param path single path to search for executables
|
||||
* @param allowAbsolute absolute paths only?
|
||||
*/
|
||||
/*@unused@*/
|
||||
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Print detailed description of options.
|
||||
* @param con context
|
||||
* @param fp ouput file handle
|
||||
* @param flags (unused)
|
||||
*/
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Print terse description of options.
|
||||
* @param con context
|
||||
* @param fp ouput file handle
|
||||
* @param flags (unused)
|
||||
*/
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Provide text to replace default "[OPTION...]" in help/usage output.
|
||||
* @param con context
|
||||
* @param text replacement text
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
void poptSetOtherOptionHelp(poptContext con, const char * text)
|
||||
/*@modifies con @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Return argv[0] from context.
|
||||
* @param con context
|
||||
* @return argv[0]
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
/*@observer@*/
|
||||
const char * poptGetInvocationName(poptContext con)
|
||||
/*@*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Shuffle argv pointers to remove stripped args, returns new argc.
|
||||
* @param con context
|
||||
* @param argc no. of args
|
||||
* @param argv arg vector
|
||||
* @return new argc
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
int poptStrippedArgv(poptContext con, int argc, char ** argv)
|
||||
/*@modifies *argv @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/**
|
||||
* Save a long, performing logical operation with value.
|
||||
* @warning Alignment check may be too strict on certain platorms.
|
||||
* @param arg integer pointer, aligned on int boundary.
|
||||
* @param argInfo logical operation (see POPT_ARGFLAG_*)
|
||||
* @param aLong value to use
|
||||
* @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
|
||||
*/
|
||||
/*@-incondefs@*/
|
||||
/*@unused@*/
|
||||
int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
|
||||
/*@modifies *arg @*/
|
||||
/*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
|
||||
/*@=incondefs@*/
|
||||
|
||||
/**
|
||||
* Save an integer, performing logical operation with value.
|
||||
* @warning Alignment check may be too strict on certain platorms.
|
||||
* @param arg integer pointer, aligned on int boundary.
|
||||
* @param argInfo logical operation (see POPT_ARGFLAG_*)
|
||||
* @param aLong value to use
|
||||
* @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
|
||||
*/
|
||||
/*@-incondefs@*/
|
||||
/*@unused@*/
|
||||
int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
|
||||
/*@modifies *arg @*/
|
||||
/*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
|
||||
/*@=incondefs@*/
|
||||
|
||||
/*@=type@*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
183
rsync/popt/poptconfig.c
Normal file
183
rsync/popt/poptconfig.c
Normal file
@ -0,0 +1,183 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/poptconfig.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "poptint.h"
|
||||
/*@access poptContext @*/
|
||||
|
||||
/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
|
||||
static void configLine(poptContext con, char * line)
|
||||
/*@modifies con @*/
|
||||
{
|
||||
size_t nameLength;
|
||||
const char * entryType;
|
||||
const char * opt;
|
||||
poptItem item = (poptItem) alloca(sizeof(*item));
|
||||
int i, j;
|
||||
|
||||
if (con->appName == NULL)
|
||||
return;
|
||||
nameLength = strlen(con->appName);
|
||||
|
||||
/*@-boundswrite@*/
|
||||
memset(item, 0, sizeof(*item));
|
||||
|
||||
if (strncmp(line, con->appName, nameLength)) return;
|
||||
|
||||
line += nameLength;
|
||||
if (*line == '\0' || !isSpace(line)) return;
|
||||
|
||||
while (*line != '\0' && isSpace(line)) line++;
|
||||
entryType = line;
|
||||
while (*line == '\0' || !isSpace(line)) line++;
|
||||
*line++ = '\0';
|
||||
|
||||
while (*line != '\0' && isSpace(line)) line++;
|
||||
if (*line == '\0') return;
|
||||
opt = line;
|
||||
while (*line == '\0' || !isSpace(line)) line++;
|
||||
*line++ = '\0';
|
||||
|
||||
while (*line != '\0' && isSpace(line)) line++;
|
||||
if (*line == '\0') return;
|
||||
|
||||
/*@-temptrans@*/ /* FIX: line alias is saved */
|
||||
if (opt[0] == '-' && opt[1] == '-')
|
||||
item->option.longName = opt + 2;
|
||||
else if (opt[0] == '-' && opt[2] == '\0')
|
||||
item->option.shortName = opt[1];
|
||||
/*@=temptrans@*/
|
||||
|
||||
if (poptParseArgvString(line, &item->argc, &item->argv)) return;
|
||||
|
||||
/*@-modobserver@*/
|
||||
item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
|
||||
for (i = 0, j = 0; i < item->argc; i++, j++) {
|
||||
const char * f;
|
||||
if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) {
|
||||
f = item->argv[i] + sizeof("--POPTdesc=");
|
||||
if (f[0] == '$' && f[1] == '"') f++;
|
||||
item->option.descrip = f;
|
||||
item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
|
||||
j--;
|
||||
} else
|
||||
if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) {
|
||||
f = item->argv[i] + sizeof("--POPTargs=");
|
||||
if (f[0] == '$' && f[1] == '"') f++;
|
||||
item->option.argDescrip = f;
|
||||
item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
|
||||
item->option.argInfo |= POPT_ARG_STRING;
|
||||
j--;
|
||||
} else
|
||||
if (j != i)
|
||||
item->argv[j] = item->argv[i];
|
||||
}
|
||||
if (j != i) {
|
||||
item->argv[j] = NULL;
|
||||
item->argc = j;
|
||||
}
|
||||
/*@=modobserver@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
/*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
|
||||
if (!strcmp(entryType, "alias"))
|
||||
(void) poptAddItem(con, item, 0);
|
||||
else if (!strcmp(entryType, "exec"))
|
||||
(void) poptAddItem(con, item, 1);
|
||||
/*@=nullstate@*/
|
||||
}
|
||||
/*@=compmempass@*/
|
||||
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
{
|
||||
const char * file, * chptr, * end;
|
||||
char * buf;
|
||||
/*@dependent@*/ char * dst;
|
||||
int fd, rc;
|
||||
off_t fileLength;
|
||||
|
||||
fd = open(fn, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
|
||||
|
||||
fileLength = lseek(fd, 0, SEEK_END);
|
||||
if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
|
||||
rc = errno;
|
||||
(void) close(fd);
|
||||
errno = rc;
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
|
||||
file = alloca(fileLength + 1);
|
||||
if (read(fd, (char *)file, fileLength) != fileLength) {
|
||||
rc = errno;
|
||||
(void) close(fd);
|
||||
errno = rc;
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
if (close(fd) == -1)
|
||||
return POPT_ERROR_ERRNO;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
dst = buf = alloca(fileLength + 1);
|
||||
|
||||
chptr = file;
|
||||
end = (file + fileLength);
|
||||
/*@-infloops@*/ /* LCL: can't detect chptr++ */
|
||||
while (chptr < end) {
|
||||
switch (*chptr) {
|
||||
case '\n':
|
||||
*dst = '\0';
|
||||
dst = buf;
|
||||
while (*dst && isSpace(dst)) dst++;
|
||||
if (*dst && *dst != '#')
|
||||
configLine(con, dst);
|
||||
chptr++;
|
||||
/*@switchbreak@*/ break;
|
||||
case '\\':
|
||||
*dst++ = *chptr++;
|
||||
if (chptr < end) {
|
||||
if (*chptr == '\n')
|
||||
dst--, chptr++;
|
||||
/* \ at the end of a line does not insert a \n */
|
||||
else
|
||||
*dst++ = *chptr++;
|
||||
}
|
||||
/*@switchbreak@*/ break;
|
||||
default:
|
||||
*dst++ = *chptr++;
|
||||
/*@switchbreak@*/ break;
|
||||
}
|
||||
}
|
||||
/*@=infloops@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
|
||||
{
|
||||
char * fn, * home;
|
||||
int rc;
|
||||
|
||||
if (con->appName == NULL) return 0;
|
||||
|
||||
rc = poptReadConfigFile(con, "/etc/popt");
|
||||
if (rc) return rc;
|
||||
|
||||
if ((home = getenv("HOME"))) {
|
||||
size_t bufsize = strlen(home) + 20;
|
||||
fn = alloca(bufsize);
|
||||
if (fn == NULL) return 0;
|
||||
snprintf(fn, bufsize, "%s/.popt", home);
|
||||
rc = poptReadConfigFile(con, fn);
|
||||
if (rc) return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
826
rsync/popt/popthelp.c
Normal file
826
rsync/popt/popthelp.c
Normal file
@ -0,0 +1,826 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
|
||||
/** \ingroup popt
|
||||
* \file popt/popthelp.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
/*#define POPT_WCHAR_HACK*/
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
#include <wchar.h> /* for mbsrtowcs */
|
||||
/*@access mbstate_t @*/
|
||||
#endif
|
||||
#include "poptint.h"
|
||||
|
||||
/*@access poptContext@*/
|
||||
|
||||
/**
|
||||
* Display arguments.
|
||||
* @param con context
|
||||
* @param foo (unused)
|
||||
* @param key option(s)
|
||||
* @param arg (unused)
|
||||
* @param data (unused)
|
||||
*/
|
||||
static void displayArgs(poptContext con,
|
||||
/*@unused@*/ UNUSED(enum poptCallbackReason foo),
|
||||
struct poptOption * key,
|
||||
/*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data))
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem@*/
|
||||
{
|
||||
if (key->shortName == '?')
|
||||
poptPrintHelp(con, stdout, 0);
|
||||
else
|
||||
poptPrintUsage(con, stdout, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#ifdef NOTYET
|
||||
/*@unchecked@*/
|
||||
static int show_option_defaults = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Empty table marker to enable displaying popt alias/exec options.
|
||||
*/
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
struct poptOption poptAliasOptions[] = {
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
/**
|
||||
* Auto help table options.
|
||||
*/
|
||||
/*@-castfcnptr@*/
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
struct poptOption poptHelpOptions[] = {
|
||||
{ NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
|
||||
{ "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
|
||||
{ "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
|
||||
POPT_TABLEEND
|
||||
} ;
|
||||
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
static struct poptOption poptHelpOptions2[] = {
|
||||
/*@-readonlytrans@*/
|
||||
{ NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
|
||||
/*@=readonlytrans@*/
|
||||
{ NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
|
||||
{ "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
|
||||
{ "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
|
||||
#ifdef NOTYET
|
||||
{ "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
|
||||
N_("Display option defaults in message"), NULL },
|
||||
#endif
|
||||
POPT_TABLEEND
|
||||
} ;
|
||||
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
|
||||
/*@=castfcnptr@*/
|
||||
|
||||
/**
|
||||
* @param table option(s)
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
/*@*/
|
||||
{
|
||||
const struct poptOption *opt;
|
||||
|
||||
if (table != NULL)
|
||||
for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
|
||||
if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
|
||||
return opt->arg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getArgDescrip(const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
|
||||
|
||||
if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
|
||||
if (opt->argDescrip) return POPT_(opt->argDescrip);
|
||||
|
||||
if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
|
||||
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
/*case POPT_ARG_NONE: return POPT_("NONE");*/ /* impossible */
|
||||
#ifdef DYING
|
||||
case POPT_ARG_VAL: return POPT_("VAL");
|
||||
#else
|
||||
case POPT_ARG_VAL: return NULL;
|
||||
#endif
|
||||
case POPT_ARG_INT: return POPT_("INT");
|
||||
case POPT_ARG_LONG: return POPT_("LONG");
|
||||
case POPT_ARG_STRING: return POPT_("STRING");
|
||||
case POPT_ARG_FLOAT: return POPT_("FLOAT");
|
||||
case POPT_ARG_DOUBLE: return POPT_("DOUBLE");
|
||||
default: return POPT_("ARG");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display default value for an option.
|
||||
* @param lineLength display positions remaining
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
* @return
|
||||
*/
|
||||
static /*@only@*/ /*@null@*/ char *
|
||||
singleOptionDefaultValue(size_t lineLength,
|
||||
const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
const char * defstr = D_(translation_domain, "default");
|
||||
size_t limit, bufsize = 4*lineLength + 1;
|
||||
char * le = malloc(bufsize);
|
||||
char * l = le;
|
||||
|
||||
if (le == NULL) return NULL; /* XXX can't happen */
|
||||
/*@-boundswrite@*/
|
||||
*le++ = '(';
|
||||
le += strlcpy(le, defstr, bufsize - 3);
|
||||
*le++ = ':';
|
||||
*le++ = ' ';
|
||||
limit = bufsize - (le - l) - 1; /* -1 for closing paren */
|
||||
if (opt->arg) /* XXX programmer error */
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_VAL:
|
||||
case POPT_ARG_INT:
|
||||
{ long aLong = *((int *)opt->arg);
|
||||
le += snprintf(le, limit, "%ld", aLong);
|
||||
} break;
|
||||
case POPT_ARG_LONG:
|
||||
{ long aLong = *((long *)opt->arg);
|
||||
le += snprintf(le, limit, "%ld", aLong);
|
||||
} break;
|
||||
case POPT_ARG_FLOAT:
|
||||
{ double aDouble = *((float *)opt->arg);
|
||||
le += snprintf(le, limit, "%g", aDouble);
|
||||
} break;
|
||||
case POPT_ARG_DOUBLE:
|
||||
{ double aDouble = *((double *)opt->arg);
|
||||
le += snprintf(le, limit, "%g", aDouble);
|
||||
} break;
|
||||
case POPT_ARG_STRING:
|
||||
{ const char * s = *(const char **)opt->arg;
|
||||
if (s == NULL) {
|
||||
le += strlcpy(le, "null", limit);
|
||||
} else {
|
||||
size_t len;
|
||||
limit -= 2; /* make room for quotes */
|
||||
*le++ = '"';
|
||||
len = strlcpy(le, s, limit);
|
||||
if (len >= limit) {
|
||||
le += limit - 3 - 1;
|
||||
*le++ = '.'; *le++ = '.'; *le++ = '.';
|
||||
} else
|
||||
le += len;
|
||||
*le++ = '"';
|
||||
}
|
||||
} break;
|
||||
case POPT_ARG_NONE:
|
||||
default:
|
||||
l = _free(l);
|
||||
return NULL;
|
||||
/*@notreached@*/ break;
|
||||
}
|
||||
*le++ = ')';
|
||||
*le = '\0';
|
||||
/*@=boundswrite@*/
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display help text for an option.
|
||||
* @param fp output file handle
|
||||
* @param maxLeftCol largest argument display width
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void singleOptionHelp(FILE * fp, size_t maxLeftCol,
|
||||
const struct poptOption * opt,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
size_t indentLength = maxLeftCol + 5;
|
||||
size_t lineLength = 79 - indentLength;
|
||||
const char * help = D_(translation_domain, opt->descrip);
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
size_t helpLength;
|
||||
char * defs = NULL;
|
||||
char * left;
|
||||
size_t lelen, limit;
|
||||
size_t nb = maxLeftCol + 1;
|
||||
int displaypad = 0;
|
||||
|
||||
/* Make sure there's more than enough room in target buffer. */
|
||||
if (opt->longName) nb += strlen(opt->longName);
|
||||
if (argDescrip) nb += strlen(argDescrip);
|
||||
|
||||
/*@-boundswrite@*/
|
||||
left = malloc(nb);
|
||||
if (left == NULL) return; /* XXX can't happen */
|
||||
left[0] = '\0';
|
||||
left[maxLeftCol] = '\0';
|
||||
|
||||
if (opt->longName && opt->shortName)
|
||||
snprintf(left, nb, "-%c, %s%s", opt->shortName,
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
else if (opt->shortName != '\0')
|
||||
snprintf(left, nb, "-%c", opt->shortName);
|
||||
else if (opt->longName)
|
||||
snprintf(left, nb, "%s%s",
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
if (!*left) goto out;
|
||||
|
||||
if (argDescrip) {
|
||||
char * le = left + strlen(left);
|
||||
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
|
||||
*le++ = '[';
|
||||
|
||||
/* Choose type of output */
|
||||
/*@-branchstate@*/
|
||||
if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
|
||||
defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
|
||||
if (defs) {
|
||||
size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs);
|
||||
char * t = malloc(bufsize);
|
||||
if (t) {
|
||||
snprintf(t, bufsize, "%s %s", help ? help : "", defs);
|
||||
defs = _free(defs);
|
||||
}
|
||||
defs = t;
|
||||
}
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
if (opt->argDescrip == NULL) {
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_NONE:
|
||||
break;
|
||||
case POPT_ARG_VAL:
|
||||
#ifdef NOTNOW /* XXX pug ugly nerdy output */
|
||||
{ long aLong = opt->val;
|
||||
int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
|
||||
int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
|
||||
|
||||
/* Don't bother displaying typical values */
|
||||
if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
|
||||
break;
|
||||
*le++ = '[';
|
||||
switch (ops) {
|
||||
case POPT_ARGFLAG_OR:
|
||||
*le++ = '|';
|
||||
/*@innerbreak@*/ break;
|
||||
case POPT_ARGFLAG_AND:
|
||||
*le++ = '&';
|
||||
/*@innerbreak@*/ break;
|
||||
case POPT_ARGFLAG_XOR:
|
||||
*le++ = '^';
|
||||
/*@innerbreak@*/ break;
|
||||
default:
|
||||
/*@innerbreak@*/ break;
|
||||
}
|
||||
*le++ = (opt->longName != NULL ? '=' : ' ');
|
||||
if (negate) *le++ = '~';
|
||||
/*@-formatconst@*/
|
||||
limit = nb - (le - left);
|
||||
lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong);
|
||||
le += lelen >= limit ? limit - 1 : lelen;
|
||||
/*@=formatconst@*/
|
||||
*le++ = ']';
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case POPT_ARG_INT:
|
||||
case POPT_ARG_LONG:
|
||||
case POPT_ARG_FLOAT:
|
||||
case POPT_ARG_DOUBLE:
|
||||
case POPT_ARG_STRING:
|
||||
*le++ = (opt->longName != NULL ? '=' : ' ');
|
||||
limit = nb - (le - left);
|
||||
lelen = strlcpy(le, argDescrip, limit);
|
||||
le += lelen >= limit ? limit - 1 : lelen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
*le++ = '=';
|
||||
limit = nb - (le - left);
|
||||
lelen = strlcpy(le, argDescrip, limit);
|
||||
if (lelen >= limit)
|
||||
lelen = limit - 1;
|
||||
le += lelen;
|
||||
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
{ const char * scopy = argDescrip;
|
||||
mbstate_t t;
|
||||
size_t n;
|
||||
|
||||
memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
|
||||
/* Determine number of characters. */
|
||||
n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
|
||||
|
||||
displaypad = (int) (lelen-n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
|
||||
*le++ = ']';
|
||||
*le = '\0';
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
if (help)
|
||||
fprintf(fp," %-*s ", (int)maxLeftCol+displaypad, left);
|
||||
else {
|
||||
fprintf(fp," %s\n", left);
|
||||
goto out;
|
||||
}
|
||||
|
||||
left = _free(left);
|
||||
/*@-branchstate@*/
|
||||
if (defs) {
|
||||
help = defs;
|
||||
defs = NULL;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
helpLength = strlen(help);
|
||||
/*@-boundsread@*/
|
||||
while (helpLength > lineLength) {
|
||||
const char * ch;
|
||||
char format[16];
|
||||
|
||||
ch = help + lineLength - 1;
|
||||
while (ch > help && !isSpace(ch)) ch--;
|
||||
if (ch == help) break; /* give up */
|
||||
while (ch > (help + 1) && isSpace(ch)) ch--;
|
||||
ch++;
|
||||
|
||||
snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
|
||||
/*@-formatconst@*/
|
||||
fprintf(fp, format, help, " ");
|
||||
/*@=formatconst@*/
|
||||
help = ch;
|
||||
while (isSpace(help) && *help) help++;
|
||||
helpLength = strlen(help);
|
||||
}
|
||||
/*@=boundsread@*/
|
||||
|
||||
if (helpLength) fprintf(fp, "%s\n", help);
|
||||
|
||||
out:
|
||||
/*@-dependenttrans@*/
|
||||
defs = _free(defs);
|
||||
/*@=dependenttrans@*/
|
||||
left = _free(left);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find display width for longest argument string.
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
* @return display width
|
||||
*/
|
||||
static size_t maxArgWidth(const struct poptOption * opt,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@*/
|
||||
{
|
||||
size_t max = 0;
|
||||
size_t len = 0;
|
||||
const char * s;
|
||||
|
||||
if (opt != NULL)
|
||||
while (opt->longName || opt->shortName || opt->arg) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
if (opt->arg) /* XXX program error */
|
||||
len = maxArgWidth(opt->arg, translation_domain);
|
||||
if (len > max) max = len;
|
||||
} else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
len = sizeof(" ")-1;
|
||||
if (opt->shortName != '\0') len += sizeof("-X")-1;
|
||||
if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
|
||||
if (opt->longName) {
|
||||
len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
|
||||
? sizeof("-")-1 : sizeof("--")-1);
|
||||
len += strlen(opt->longName);
|
||||
}
|
||||
|
||||
s = getArgDescrip(opt, translation_domain);
|
||||
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
/* XXX Calculate no. of display characters. */
|
||||
if (s) {
|
||||
const char * scopy = s;
|
||||
mbstate_t t;
|
||||
size_t n;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
|
||||
/*@=boundswrite@*/
|
||||
/* Determine number of characters. */
|
||||
n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
|
||||
len += sizeof("=")-1 + n;
|
||||
}
|
||||
#else
|
||||
if (s)
|
||||
len += sizeof("=")-1 + strlen(s);
|
||||
#endif
|
||||
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
|
||||
if (len > max) max = len;
|
||||
}
|
||||
|
||||
opt++;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display popt alias and exec help.
|
||||
* @param fp output file handle
|
||||
* @param items alias/exec array
|
||||
* @param nitems no. of alias/exec entries
|
||||
* @param left largest argument display width
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void itemHelp(FILE * fp,
|
||||
/*@null@*/ poptItem items, int nitems, size_t left,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
poptItem item;
|
||||
int i;
|
||||
|
||||
if (items != NULL)
|
||||
for (i = 0, item = items; i < nitems; i++, item++) {
|
||||
const struct poptOption * opt;
|
||||
opt = &item->option;
|
||||
if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
|
||||
singleOptionHelp(fp, left, opt, translation_domain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display help text for a table of options.
|
||||
* @param con context
|
||||
* @param fp output file handle
|
||||
* @param table option(s)
|
||||
* @param left largest argument display width
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void singleTableHelp(poptContext con, FILE * fp,
|
||||
/*@null@*/ const struct poptOption * table, size_t left,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
const struct poptOption * opt;
|
||||
const char *sub_transdom;
|
||||
|
||||
if (table == poptAliasOptions) {
|
||||
itemHelp(fp, con->aliases, con->numAliases, left, NULL);
|
||||
itemHelp(fp, con->execs, con->numExecs, left, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (table != NULL)
|
||||
for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
|
||||
singleOptionHelp(fp, left, opt, translation_domain);
|
||||
}
|
||||
|
||||
if (table != NULL)
|
||||
for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
|
||||
continue;
|
||||
sub_transdom = getTableTranslationDomain(opt->arg);
|
||||
if (sub_transdom == NULL)
|
||||
sub_transdom = translation_domain;
|
||||
|
||||
if (opt->descrip)
|
||||
fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
|
||||
|
||||
singleTableHelp(con, fp, opt->arg, left, sub_transdom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param con context
|
||||
* @param fp output file handle
|
||||
*/
|
||||
static int showHelpIntro(poptContext con, FILE * fp)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int len = 6;
|
||||
const char * fn;
|
||||
|
||||
fprintf(fp, POPT_("Usage:"));
|
||||
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
|
||||
/*@-boundsread@*/
|
||||
/*@-nullderef -type@*/ /* LCL: wazzup? */
|
||||
fn = con->optionStack->argv[0];
|
||||
/*@=nullderef =type@*/
|
||||
/*@=boundsread@*/
|
||||
if (fn == NULL) return len;
|
||||
if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
|
||||
fprintf(fp, " %s", fn);
|
||||
len += strlen(fn) + 1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
size_t leftColWidth;
|
||||
|
||||
(void) showHelpIntro(con, fp);
|
||||
if (con->otherHelp)
|
||||
fprintf(fp, " %s\n", con->otherHelp);
|
||||
else
|
||||
fprintf(fp, " %s\n", POPT_("[OPTION...]"));
|
||||
|
||||
leftColWidth = maxArgWidth(con->options, NULL);
|
||||
singleTableHelp(con, fp, con->options, leftColWidth, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display usage text for an option.
|
||||
* @param fp output file handle
|
||||
* @param cursor current display position
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static size_t singleOptionUsage(FILE * fp, size_t cursor,
|
||||
const struct poptOption * opt,
|
||||
/*@null@*/ const char *translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
size_t len = 4;
|
||||
char shortStr[2] = { '\0', '\0' };
|
||||
const char * item = shortStr;
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
|
||||
if (opt->shortName != '\0' && opt->longName != NULL) {
|
||||
len += 2;
|
||||
if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
|
||||
len += strlen(opt->longName);
|
||||
} else if (opt->shortName != '\0') {
|
||||
len++;
|
||||
shortStr[0] = opt->shortName;
|
||||
shortStr[1] = '\0';
|
||||
} else if (opt->longName) {
|
||||
len += strlen(opt->longName);
|
||||
if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
|
||||
item = opt->longName;
|
||||
}
|
||||
|
||||
if (len == 4) return cursor;
|
||||
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
/* XXX Calculate no. of display characters. */
|
||||
if (argDescrip) {
|
||||
const char * scopy = argDescrip;
|
||||
mbstate_t t;
|
||||
size_t n;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
|
||||
/*@=boundswrite@*/
|
||||
/* Determine number of characters. */
|
||||
n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
|
||||
len += sizeof("=")-1 + n;
|
||||
}
|
||||
#else
|
||||
if (argDescrip)
|
||||
len += sizeof("=")-1 + strlen(argDescrip);
|
||||
#endif
|
||||
|
||||
if ((cursor + len) > 79) {
|
||||
fprintf(fp, "\n ");
|
||||
cursor = 7;
|
||||
}
|
||||
|
||||
if (opt->longName && opt->shortName) {
|
||||
fprintf(fp, " [-%c|-%s%s%s%s]",
|
||||
opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
|
||||
opt->longName,
|
||||
(argDescrip ? " " : ""),
|
||||
(argDescrip ? argDescrip : ""));
|
||||
} else {
|
||||
fprintf(fp, " [-%s%s%s%s]",
|
||||
((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
|
||||
item,
|
||||
(argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
|
||||
(argDescrip ? argDescrip : ""));
|
||||
}
|
||||
|
||||
return cursor + len + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display popt alias and exec usage.
|
||||
* @param fp output file handle
|
||||
* @param cursor current display position
|
||||
* @param item alias/exec array
|
||||
* @param nitems no. of ara/exec entries
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static size_t itemUsage(FILE * fp, size_t cursor,
|
||||
/*@null@*/ poptItem item, int nitems,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int i;
|
||||
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (item != NULL)
|
||||
for (i = 0; i < nitems; i++, item++) {
|
||||
const struct poptOption * opt;
|
||||
opt = &item->option;
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
|
||||
translation_domain = (const char *)opt->arg;
|
||||
} else if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
|
||||
}
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of option tables already processed.
|
||||
*/
|
||||
typedef struct poptDone_s {
|
||||
int nopts;
|
||||
int maxopts;
|
||||
const void ** opts;
|
||||
} * poptDone;
|
||||
|
||||
/**
|
||||
* Display usage text for a table of options.
|
||||
* @param con context
|
||||
* @param fp output file handle
|
||||
* @param cursor current display position
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
* @param done tables already processed
|
||||
* @return
|
||||
*/
|
||||
static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
|
||||
/*@null@*/ const struct poptOption * opt,
|
||||
/*@null@*/ UNUSED(const char * translation_domain),
|
||||
/*@null@*/ poptDone done)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, done, fileSystem @*/
|
||||
{
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (opt != NULL)
|
||||
for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
|
||||
translation_domain = (const char *)opt->arg;
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
if (done) {
|
||||
int i = 0;
|
||||
for (i = 0; i < done->nopts; i++) {
|
||||
/*@-boundsread@*/
|
||||
const void * that = done->opts[i];
|
||||
/*@=boundsread@*/
|
||||
if (that == NULL || that != opt->arg)
|
||||
/*@innercontinue@*/ continue;
|
||||
/*@innerbreak@*/ break;
|
||||
}
|
||||
/* Skip if this table has already been processed. */
|
||||
if (opt->arg == NULL || i < done->nopts)
|
||||
continue;
|
||||
/*@-boundswrite@*/
|
||||
if (done->nopts < done->maxopts)
|
||||
done->opts[done->nopts++] = (const void *) opt->arg;
|
||||
/*@=boundswrite@*/
|
||||
}
|
||||
cursor = singleTableUsage(con, fp, cursor, opt->arg,
|
||||
translation_domain, done);
|
||||
} else if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
|
||||
}
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return concatenated short options for display.
|
||||
* @todo Sub-tables should be recursed.
|
||||
* @param opt option(s)
|
||||
* @param fp output file handle
|
||||
* @retval str concatenation of short options
|
||||
* @return length of display string
|
||||
*/
|
||||
static int showShortOptions(const struct poptOption * opt, FILE * fp,
|
||||
/*@null@*/ char * str)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *str, *fp, fileSystem @*/
|
||||
/*@requires maxRead(str) >= 0 @*/
|
||||
{
|
||||
/* bufsize larger then the ascii set, lazy alloca on top level call. */
|
||||
char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
|
||||
int len = 0;
|
||||
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
if (opt != NULL)
|
||||
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
|
||||
s[strlen(s)] = opt->shortName;
|
||||
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
|
||||
if (opt->arg) /* XXX program error */
|
||||
len = showShortOptions(opt->arg, fp, s);
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
/* On return to top level, print the short options, return print length. */
|
||||
if (s == str && *s != '\0') {
|
||||
fprintf(fp, " [-%s]", s);
|
||||
len = strlen(s) + sizeof(" [-]")-1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
|
||||
size_t cursor;
|
||||
|
||||
done->nopts = 0;
|
||||
done->maxopts = 64;
|
||||
cursor = done->maxopts * sizeof(*done->opts);
|
||||
/*@-boundswrite@*/
|
||||
done->opts = memset(alloca(cursor), 0, cursor);
|
||||
/*@-keeptrans@*/
|
||||
done->opts[done->nopts++] = (const void *) con->options;
|
||||
/*@=keeptrans@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
cursor = showHelpIntro(con, fp);
|
||||
cursor += showShortOptions(con->options, fp, NULL);
|
||||
cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
|
||||
cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
|
||||
cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
|
||||
|
||||
if (con->otherHelp) {
|
||||
cursor += strlen(con->otherHelp) + 1;
|
||||
if (cursor > 79) fprintf(fp, "\n ");
|
||||
fprintf(fp, " %s", con->otherHelp);
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
void poptSetOtherOptionHelp(poptContext con, const char * text)
|
||||
{
|
||||
con->otherHelp = _free(con->otherHelp);
|
||||
con->otherHelp = xstrdup(text);
|
||||
}
|
122
rsync/popt/poptint.h
Normal file
122
rsync/popt/poptint.h
Normal file
@ -0,0 +1,122 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/poptint.h
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#ifndef H_POPTINT
|
||||
#define H_POPTINT
|
||||
|
||||
/**
|
||||
* Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
|
||||
* @param p memory to free
|
||||
* @retval NULL always
|
||||
*/
|
||||
/*@unused@*/ static inline /*@null@*/ void *
|
||||
_free(/*@only@*/ /*@null@*/ const void * p)
|
||||
/*@modifies p @*/
|
||||
{
|
||||
if (p != NULL) free((void *)p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
isSpace(const char *ptr)
|
||||
{
|
||||
return isspace(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
/* Bit mask macros. */
|
||||
/*@-exporttype -redef @*/
|
||||
typedef unsigned int __pbm_bits;
|
||||
/*@=exporttype =redef @*/
|
||||
#define __PBM_NBITS (8 * sizeof (__pbm_bits))
|
||||
#define __PBM_IX(d) ((d) / __PBM_NBITS)
|
||||
#define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
|
||||
/*@-exporttype -redef @*/
|
||||
typedef struct {
|
||||
__pbm_bits bits[1];
|
||||
} pbm_set;
|
||||
/*@=exporttype =redef @*/
|
||||
#define __PBM_BITS(set) ((set)->bits)
|
||||
|
||||
#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
|
||||
#define PBM_FREE(s) _free(s);
|
||||
#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
|
||||
#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
|
||||
#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
|
||||
|
||||
struct optionStackEntry {
|
||||
int argc;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char ** argv;
|
||||
/*@only@*/ /*@null@*/
|
||||
pbm_set * argb;
|
||||
int next;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char * nextArg;
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * nextCharArg;
|
||||
/*@dependent@*/ /*@null@*/
|
||||
poptItem currAlias;
|
||||
int stuffed;
|
||||
};
|
||||
|
||||
struct poptContext_s {
|
||||
struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
|
||||
/*@dependent@*/
|
||||
struct optionStackEntry * os;
|
||||
/*@owned@*/ /*@null@*/
|
||||
const char ** leftovers;
|
||||
int numLeftovers;
|
||||
int nextLeftover;
|
||||
/*@keep@*/
|
||||
const struct poptOption * options;
|
||||
int restLeftover;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char * appName;
|
||||
/*@only@*/ /*@null@*/
|
||||
poptItem aliases;
|
||||
int numAliases;
|
||||
int flags;
|
||||
/*@owned@*/ /*@null@*/
|
||||
poptItem execs;
|
||||
int numExecs;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char ** finalArgv;
|
||||
int finalArgvCount;
|
||||
int finalArgvAlloced;
|
||||
/*@dependent@*/ /*@null@*/
|
||||
poptItem doExec;
|
||||
/*@only@*/
|
||||
const char * execPath;
|
||||
int execAbsolute;
|
||||
/*@only@*/ /*@relnull@*/
|
||||
const char * otherHelp;
|
||||
/*@null@*/
|
||||
pbm_set * arg_strip;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_GETTEXT) && !defined(__LCLINT__)
|
||||
#define _(foo) gettext(foo)
|
||||
#else
|
||||
#define _(foo) foo
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
|
||||
#define D_(dom, str) dgettext(dom, str)
|
||||
#define POPT_(foo) D_("popt", foo)
|
||||
#else
|
||||
#define D_(dom, str) str
|
||||
#define POPT_(foo) foo
|
||||
#endif
|
||||
|
||||
#define N_(foo) foo
|
||||
|
||||
#endif
|
231
rsync/popt/poptparse.c
Normal file
231
rsync/popt/poptparse.c
Normal file
@ -0,0 +1,231 @@
|
||||
/** \ingroup popt
|
||||
* \file popt/poptparse.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "poptint.h"
|
||||
|
||||
#define POPT_ARGV_ARRAY_GROW_DELTA 5
|
||||
|
||||
/*@-boundswrite@*/
|
||||
int poptDupArgv(int argc, const char **argv,
|
||||
int * argcPtr, const char *** argvPtr)
|
||||
{
|
||||
size_t nb = (argc + 1) * sizeof(*argv);
|
||||
const char ** argv2;
|
||||
char * dst;
|
||||
int i;
|
||||
|
||||
if (argc <= 0 || argv == NULL) /* XXX can't happen */
|
||||
return POPT_ERROR_NOARG;
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (argv[i] == NULL)
|
||||
return POPT_ERROR_NOARG;
|
||||
nb += strlen(argv[i]) + 1;
|
||||
}
|
||||
|
||||
dst = malloc(nb);
|
||||
if (dst == NULL) /* XXX can't happen */
|
||||
return POPT_ERROR_MALLOC;
|
||||
argv2 = (void *) dst;
|
||||
dst += (argc + 1) * sizeof(*argv);
|
||||
|
||||
/*@-branchstate@*/
|
||||
for (i = 0; i < argc; i++) {
|
||||
argv2[i] = dst;
|
||||
dst += strlcpy(dst, argv[i], nb) + 1;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
argv2[argc] = NULL;
|
||||
|
||||
if (argvPtr) {
|
||||
*argvPtr = argv2;
|
||||
} else {
|
||||
free(argv2);
|
||||
argv2 = NULL;
|
||||
}
|
||||
if (argcPtr)
|
||||
*argcPtr = argc;
|
||||
return 0;
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
/*@-bounds@*/
|
||||
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
|
||||
{
|
||||
const char * src;
|
||||
char quote = '\0';
|
||||
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
|
||||
const char ** argv = malloc(sizeof(*argv) * argvAlloced);
|
||||
int argc = 0;
|
||||
int buflen = strlen(s) + 1;
|
||||
char * buf = memset(alloca(buflen), 0, buflen);
|
||||
int rc = POPT_ERROR_MALLOC;
|
||||
|
||||
if (argv == NULL) return rc;
|
||||
argv[argc] = buf;
|
||||
|
||||
for (src = s; *src != '\0'; src++) {
|
||||
if (quote == *src) {
|
||||
quote = '\0';
|
||||
} else if (quote != '\0') {
|
||||
if (*src == '\\') {
|
||||
src++;
|
||||
if (!*src) {
|
||||
rc = POPT_ERROR_BADQUOTE;
|
||||
goto exit;
|
||||
}
|
||||
if (*src != quote) *buf++ = '\\';
|
||||
}
|
||||
*buf++ = *src;
|
||||
} else if (isSpace(src)) {
|
||||
if (*argv[argc] != '\0') {
|
||||
buf++, argc++;
|
||||
if (argc == argvAlloced) {
|
||||
argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
|
||||
argv = realloc(argv, sizeof(*argv) * argvAlloced);
|
||||
if (argv == NULL) goto exit;
|
||||
}
|
||||
argv[argc] = buf;
|
||||
}
|
||||
} else switch (*src) {
|
||||
case '"':
|
||||
case '\'':
|
||||
quote = *src;
|
||||
/*@switchbreak@*/ break;
|
||||
case '\\':
|
||||
src++;
|
||||
if (!*src) {
|
||||
rc = POPT_ERROR_BADQUOTE;
|
||||
goto exit;
|
||||
}
|
||||
/*@fallthrough@*/
|
||||
default:
|
||||
*buf++ = *src;
|
||||
/*@switchbreak@*/ break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(argv[argc])) {
|
||||
argc++, buf++;
|
||||
}
|
||||
|
||||
rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
|
||||
|
||||
exit:
|
||||
if (argv) free(argv);
|
||||
return rc;
|
||||
}
|
||||
/*@=bounds@*/
|
||||
|
||||
/* still in the dev stage.
|
||||
* return values, perhaps 1== file erro
|
||||
* 2== line to long
|
||||
* 3== umm.... more?
|
||||
*/
|
||||
int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
char line[999];
|
||||
char * argstr;
|
||||
char * p;
|
||||
char * q;
|
||||
char * x;
|
||||
int t;
|
||||
int argvlen = 0;
|
||||
size_t maxlinelen = sizeof(line);
|
||||
size_t linelen;
|
||||
int maxargvlen = 480;
|
||||
int linenum = 0;
|
||||
|
||||
*argstrp = NULL;
|
||||
|
||||
/* | this_is = our_line
|
||||
* p q x
|
||||
*/
|
||||
|
||||
if (fp == NULL)
|
||||
return POPT_ERROR_NULLARG;
|
||||
|
||||
argstr = calloc(maxargvlen, sizeof(*argstr));
|
||||
if (argstr == NULL) return POPT_ERROR_MALLOC;
|
||||
|
||||
while (fgets(line, (int)maxlinelen, fp) != NULL) {
|
||||
linenum++;
|
||||
p = line;
|
||||
|
||||
/* loop until first non-space char or EOL */
|
||||
while( *p != '\0' && isSpace(p) )
|
||||
p++;
|
||||
|
||||
linelen = strlen(p);
|
||||
if (linelen >= maxlinelen-1) {
|
||||
free(argstr);
|
||||
return POPT_ERROR_OVERFLOW; /* XXX line too long */
|
||||
}
|
||||
|
||||
if (*p == '\0' || *p == '\n') continue; /* line is empty */
|
||||
if (*p == '#') continue; /* comment line */
|
||||
|
||||
q = p;
|
||||
|
||||
while (*q != '\0' && (!isSpace(q)) && *q != '=')
|
||||
q++;
|
||||
|
||||
if (isSpace(q)) {
|
||||
/* a space after the name, find next non space */
|
||||
*q++='\0';
|
||||
while( *q != '\0' && isSpace(q) ) q++;
|
||||
}
|
||||
if (*q == '\0') {
|
||||
/* single command line option (ie, no name=val, just name) */
|
||||
q[-1] = '\0'; /* kill off newline from fgets() call */
|
||||
argvlen += (t = q - p) + (sizeof(" --")-1);
|
||||
if (argvlen >= maxargvlen) {
|
||||
maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
|
||||
argstr = realloc(argstr, maxargvlen);
|
||||
if (argstr == NULL) return POPT_ERROR_MALLOC;
|
||||
}
|
||||
strlcat(argstr, " --", maxargvlen);
|
||||
strlcat(argstr, p, maxargvlen);
|
||||
continue;
|
||||
}
|
||||
if (*q != '=')
|
||||
continue; /* XXX for now, silently ignore bogus line */
|
||||
|
||||
/* *q is an equal sign. */
|
||||
*q++ = '\0';
|
||||
|
||||
/* find next non-space letter of value */
|
||||
while (*q != '\0' && isSpace(q))
|
||||
q++;
|
||||
if (*q == '\0')
|
||||
continue; /* XXX silently ignore missing value */
|
||||
|
||||
/* now, loop and strip all ending whitespace */
|
||||
x = p + linelen;
|
||||
while (isSpace(--x))
|
||||
*x = 0; /* null out last char if space (including fgets() NL) */
|
||||
|
||||
/* rest of line accept */
|
||||
t = x - p;
|
||||
argvlen += t + (sizeof("' --='")-1);
|
||||
if (argvlen >= maxargvlen) {
|
||||
maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
|
||||
argstr = realloc(argstr, maxargvlen);
|
||||
if (argstr == NULL) return POPT_ERROR_MALLOC;
|
||||
}
|
||||
strlcat(argstr, " --", maxargvlen);
|
||||
strlcat(argstr, p, maxargvlen);
|
||||
strlcat(argstr, "=\"", maxargvlen);
|
||||
strlcat(argstr, q, maxargvlen);
|
||||
strlcat(argstr, "\"", maxargvlen);
|
||||
}
|
||||
|
||||
*argstrp = argstr;
|
||||
return 0;
|
||||
}
|
130
rsync/popt/system.h
Normal file
130
rsync/popt/system.h
Normal file
@ -0,0 +1,130 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined (__GLIBC__) && defined(__LCLINT__)
|
||||
/*@-declundef@*/
|
||||
/*@unchecked@*/
|
||||
extern __const __int32_t *__ctype_tolower;
|
||||
/*@unchecked@*/
|
||||
extern __const __int32_t *__ctype_toupper;
|
||||
/*@=declundef@*/
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if HAVE_MCHECK_H
|
||||
#include <mcheck.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#ifdef __NeXT
|
||||
/* access macros are not declared in non posix mode in unistd.h -
|
||||
don't try to use posix on NeXTstep 3.3 ! */
|
||||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
#if defined(__LCLINT__)
|
||||
/*@-declundef -incondefs @*/ /* LCL: missing annotation */
|
||||
/*@only@*/ /*@out@*/
|
||||
void * alloca (size_t __size)
|
||||
/*@ensures MaxSet(result) == (__size - 1) @*/
|
||||
/*@*/;
|
||||
/*@=declundef =incondefs @*/
|
||||
#endif
|
||||
|
||||
/* AIX requires this to be the first thing in the file. */
|
||||
#ifndef __GNUC__
|
||||
# if HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifdef HAVE_ALLOCA
|
||||
# ifndef alloca /* predefined by HP cc +Olibcalls */
|
||||
char *alloca(size_t size);
|
||||
# endif
|
||||
# else
|
||||
# ifdef alloca
|
||||
# undef alloca
|
||||
# endif
|
||||
# define alloca(sz) malloc(sz) /* Kludge this for now */
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#elif !defined(alloca)
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *d, const char *s, size_t bufsize);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
size_t strlcat(char *d, const char *s, size_t bufsize);
|
||||
#endif
|
||||
|
||||
#if HAVE_MCHECK_H && defined(__GNUC__)
|
||||
static inline char *
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
size_t memsize = strlen(s) + 1;
|
||||
char *ptr = malloc(memsize);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "virtual memory exhausted.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strlcpy(ptr, s, memsize);
|
||||
return ptr;
|
||||
}
|
||||
#else
|
||||
#define xstrdup(_str) strdup(_str)
|
||||
#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
|
||||
|
||||
#if HAVE___SECURE_GETENV && !defined(__LCLINT__)
|
||||
#define getenv(_s) __secure_getenv(_s)
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF
|
||||
#define snprintf rsync_snprintf
|
||||
int snprintf(char *str,size_t count,const char *fmt,...);
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
|
||||
#define PACKAGE "rsync"
|
||||
|
||||
#include "popt.h"
|
51
rsync/prepare-source
Executable file
51
rsync/prepare-source
Executable file
@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
# Either use autoconf and autoheader to create configure.sh and config.h.in
|
||||
# or (optionally) fetch the latest development versions of generated files.
|
||||
#
|
||||
# Specify one action or more than one to provide a fall-back:
|
||||
#
|
||||
# build build the config files [the default w/no arg]
|
||||
# fetch fetch the latest dev config files
|
||||
# fetchgen fetch all the latest dev generated files
|
||||
# fetchSRC fetch the latest dev source files [NON-GENERATED FILES]
|
||||
#
|
||||
# The script stops after the first successful action.
|
||||
|
||||
dir=`dirname $0`
|
||||
if test x"$dir" != x -a x"$dir" != x.; then
|
||||
cd "$dir"
|
||||
fi
|
||||
|
||||
if test $# = 0; then
|
||||
set -- build
|
||||
fi
|
||||
|
||||
for action in "${@}"; do
|
||||
case "$action" in
|
||||
build|make)
|
||||
make -f prepare-source.mak
|
||||
;;
|
||||
fetch)
|
||||
if perl --version >/dev/null 2>/dev/null; then
|
||||
files='c*'
|
||||
else
|
||||
files='[cp]*'
|
||||
fi
|
||||
rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/"$files" .
|
||||
;;
|
||||
fetchgen)
|
||||
rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/'*' .
|
||||
;;
|
||||
fetchSRC)
|
||||
rsync -pvrz --exclude=/.git/ rsync://rsync.samba.org/ftp/pub/unpacked/rsync/ .
|
||||
;;
|
||||
*)
|
||||
echo "Unknown action: $action"
|
||||
exit 1
|
||||
esac
|
||||
if test $? = 0; then
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
exit 1
|
7
rsync/prepare-source.mak
Normal file
7
rsync/prepare-source.mak
Normal file
@ -0,0 +1,7 @@
|
||||
conf: configure.sh config.h.in
|
||||
|
||||
configure.sh: configure.ac aclocal.m4
|
||||
autoconf -o configure.sh
|
||||
|
||||
config.h.in: configure.ac aclocal.m4
|
||||
autoheader && touch config.h.in
|
221
rsync/progress.c
Normal file
221
rsync/progress.c
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Routines to output progress information during a file transfer.
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "inums.h"
|
||||
|
||||
extern int am_server;
|
||||
extern int flist_eof;
|
||||
extern int need_unsorted_flist;
|
||||
extern int output_needs_newline;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *cur_flist;
|
||||
|
||||
#define PROGRESS_HISTORY_SECS 5
|
||||
|
||||
#ifdef GETPGRP_VOID
|
||||
#define GETPGRP_ARG
|
||||
#else
|
||||
#define GETPGRP_ARG 0
|
||||
#endif
|
||||
|
||||
struct progress_history {
|
||||
struct timeval time;
|
||||
OFF_T ofs;
|
||||
};
|
||||
|
||||
static struct progress_history ph_start;
|
||||
static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
|
||||
static int newest_hpos, oldest_hpos;
|
||||
static int current_file_index;
|
||||
|
||||
static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
|
||||
{
|
||||
return (t2->tv_sec - t1->tv_sec) * 1000L
|
||||
+ (t2->tv_usec - t1->tv_usec) / 1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ofs Current position in file
|
||||
* @param size Total size of file
|
||||
* @param is_last True if this is the last time progress will be
|
||||
* printed for this file, so we should output a newline. (Not
|
||||
* necessarily the same as all bytes being received.)
|
||||
**/
|
||||
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
int is_last)
|
||||
{
|
||||
char rembuf[64], eol[128];
|
||||
const char *units;
|
||||
unsigned long diff;
|
||||
double rate, remain;
|
||||
int pct;
|
||||
|
||||
if (is_last) {
|
||||
int len = snprintf(eol, sizeof eol,
|
||||
" (xfr#%d, %s-chk=%d/%d)\n",
|
||||
stats.xferred_files, flist_eof ? "to" : "ir",
|
||||
stats.num_files - current_file_index - 1,
|
||||
stats.num_files);
|
||||
if (INFO_GTE(PROGRESS, 2)) {
|
||||
static int last_len = 0;
|
||||
/* Drop \n and pad with spaces if line got shorter. */
|
||||
if (last_len < --len)
|
||||
last_len = len;
|
||||
eol[last_len] = '\0';
|
||||
while (last_len > len)
|
||||
eol[--last_len] = ' ';
|
||||
is_last = 0;
|
||||
}
|
||||
/* Compute stats based on the starting info. */
|
||||
if (!ph_start.time.tv_sec
|
||||
|| !(diff = msdiff(&ph_start.time, now)))
|
||||
diff = 1;
|
||||
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
|
||||
/* Switch to total time taken for our last update. */
|
||||
remain = (double) diff / 1000.0;
|
||||
} else {
|
||||
strlcpy(eol, " ", sizeof eol);
|
||||
/* Compute stats based on recent progress. */
|
||||
if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
|
||||
diff = 1;
|
||||
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
|
||||
/ diff / 1024.0;
|
||||
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
|
||||
}
|
||||
|
||||
if (rate > 1024*1024) {
|
||||
rate /= 1024.0 * 1024.0;
|
||||
units = "GB/s";
|
||||
} else if (rate > 1024) {
|
||||
rate /= 1024.0;
|
||||
units = "MB/s";
|
||||
} else {
|
||||
units = "kB/s";
|
||||
}
|
||||
|
||||
if (remain < 0)
|
||||
strlcpy(rembuf, " ??:??:??", sizeof rembuf);
|
||||
else {
|
||||
snprintf(rembuf, sizeof rembuf, "%4d:%02d:%02d",
|
||||
(int) (remain / 3600.0),
|
||||
(int) (remain / 60.0) % 60,
|
||||
(int) remain % 60);
|
||||
}
|
||||
|
||||
output_needs_newline = 0;
|
||||
pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
|
||||
rprintf(FCLIENT, "\r%15s %3d%% %7.2f%s %s%s",
|
||||
human_num(ofs), pct, rate, units, rembuf, eol);
|
||||
if (!is_last) {
|
||||
output_needs_newline = 1;
|
||||
rflush(FCLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
void set_current_file_index(struct file_struct *file, int ndx)
|
||||
{
|
||||
if (!file)
|
||||
current_file_index = cur_flist->used + cur_flist->ndx_start - 1;
|
||||
else if (need_unsorted_flist)
|
||||
current_file_index = flist_find(cur_flist, file) + cur_flist->ndx_start;
|
||||
else
|
||||
current_file_index = ndx;
|
||||
current_file_index -= cur_flist->flist_num;
|
||||
}
|
||||
|
||||
void end_progress(OFF_T size)
|
||||
{
|
||||
if (!am_server) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (INFO_GTE(PROGRESS, 2)) {
|
||||
rprint_progress(stats.total_transferred_size,
|
||||
stats.total_size, &now, True);
|
||||
} else {
|
||||
rprint_progress(size, size, &now, True);
|
||||
memset(&ph_start, 0, sizeof ph_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show_progress(OFF_T ofs, OFF_T size)
|
||||
{
|
||||
struct timeval now;
|
||||
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
|
||||
static pid_t pgrp = -1;
|
||||
pid_t tc_pgrp;
|
||||
#endif
|
||||
|
||||
if (am_server)
|
||||
return;
|
||||
|
||||
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
|
||||
if (pgrp == -1)
|
||||
pgrp = getpgrp(GETPGRP_ARG);
|
||||
#endif
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
if (INFO_GTE(PROGRESS, 2)) {
|
||||
ofs = stats.total_transferred_size - size + ofs;
|
||||
size = stats.total_size;
|
||||
}
|
||||
|
||||
if (!ph_start.time.tv_sec) {
|
||||
int i;
|
||||
|
||||
/* Try to guess the real starting time when the sender started
|
||||
* to send us data by using the time we last received some data
|
||||
* in the last file (if it was recent enough). */
|
||||
if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) {
|
||||
ph_start.time = ph_list[newest_hpos].time;
|
||||
ph_start.ofs = 0;
|
||||
} else {
|
||||
ph_start.time.tv_sec = now.tv_sec;
|
||||
ph_start.time.tv_usec = now.tv_usec;
|
||||
ph_start.ofs = ofs;
|
||||
}
|
||||
|
||||
for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
|
||||
ph_list[i] = ph_start;
|
||||
}
|
||||
else {
|
||||
if (msdiff(&ph_list[newest_hpos].time, &now) < 1000)
|
||||
return;
|
||||
|
||||
newest_hpos = oldest_hpos;
|
||||
oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
|
||||
ph_list[newest_hpos].time.tv_sec = now.tv_sec;
|
||||
ph_list[newest_hpos].time.tv_usec = now.tv_usec;
|
||||
ph_list[newest_hpos].ofs = ofs;
|
||||
}
|
||||
|
||||
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
|
||||
tc_pgrp = tcgetpgrp(STDOUT_FILENO);
|
||||
if (tc_pgrp != pgrp && tc_pgrp != -1)
|
||||
return;
|
||||
#endif
|
||||
|
||||
rprint_progress(ofs, size, &now, False);
|
||||
}
|
423
rsync/proto.h
Normal file
423
rsync/proto.h
Normal file
@ -0,0 +1,423 @@
|
||||
/* This file is automatically generated with "make proto". DO NOT EDIT */
|
||||
|
||||
int allow_access(const char *addr, const char **host_ptr, int i);
|
||||
void free_acl(stat_x *sxp);
|
||||
int get_acl(const char *fname, stat_x *sxp);
|
||||
void send_acl(int f, stat_x *sxp);
|
||||
void receive_acl(int f, struct file_struct *file);
|
||||
void cache_tmp_acl(struct file_struct *file, stat_x *sxp);
|
||||
void uncache_tmp_acls(void);
|
||||
int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode_t new_mode);
|
||||
void match_acl_ids(void);
|
||||
int default_perms_for_dir(const char *dir);
|
||||
void base64_encode(const char *buf, int len, char *out, int pad);
|
||||
char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
const char *addr, const char *leader);
|
||||
void auth_client(int fd, const char *user, const char *challenge);
|
||||
char *get_backup_name(const char *fname);
|
||||
int make_backup(const char *fname, BOOL prefer_rename);
|
||||
void write_stream_flags(int fd);
|
||||
void read_stream_flags(int fd);
|
||||
void check_batch_flags(void);
|
||||
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt);
|
||||
uint32 get_checksum1(char *buf1, int32 len);
|
||||
void get_checksum2(char *buf, int32 len, char *sum);
|
||||
void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum);
|
||||
void sum_init(int seed);
|
||||
void sum_update(const char *p, int32 len);
|
||||
int sum_end(char *sum);
|
||||
struct chmod_mode_struct *parse_chmod(const char *modestr,
|
||||
struct chmod_mode_struct **root_mode_ptr);
|
||||
int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes);
|
||||
int free_chmod_mode(struct chmod_mode_struct *chmod_modes);
|
||||
void close_all(void);
|
||||
NORETURN void _exit_cleanup(int code, const char *file, int line);
|
||||
void cleanup_disable(void);
|
||||
void cleanup_set(const char *fnametmp, const char *fname, struct file_struct *file,
|
||||
int fd_r, int fd_w);
|
||||
void cleanup_set_pid(pid_t pid);
|
||||
char *client_addr(int fd);
|
||||
char *client_name(int fd);
|
||||
void client_sockaddr(int fd,
|
||||
struct sockaddr_storage *ss,
|
||||
socklen_t *ss_len);
|
||||
int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
socklen_t ss_len,
|
||||
char *name_buf, size_t name_buf_size,
|
||||
char *port_buf, size_t port_buf_size);
|
||||
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
const struct sockaddr_storage *ss);
|
||||
int check_name(int fd,
|
||||
const struct sockaddr_storage *ss,
|
||||
char *name_buf, size_t name_buf_size);
|
||||
int start_socket_client(char *host, int remote_argc, char *remote_argv[],
|
||||
int argc, char *argv[]);
|
||||
int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]);
|
||||
int start_daemon(int f_in, int f_out);
|
||||
int daemon_main(void);
|
||||
void set_allow_inc_recurse(void);
|
||||
void setup_protocol(int f_out,int f_in);
|
||||
int claim_connection(char *fname, int max_connections);
|
||||
enum delret delete_item(char *fbuf, uint16 mode, uint16 flags);
|
||||
uint16 get_del_for_flag(uint16 mode);
|
||||
void set_filter_dir(const char *dir, unsigned int dirlen);
|
||||
void *push_local_filters(const char *dir, unsigned int dirlen);
|
||||
void pop_local_filters(void *mem);
|
||||
void change_local_filter_dir(const char *dname, int dlen, int dir_depth);
|
||||
int check_filter(filter_rule_list *listp, enum logcode code,
|
||||
const char *name, int name_is_dir);
|
||||
const filter_rule *rule_template(uint32 rflags);
|
||||
void parse_filter_str(filter_rule_list *listp, const char *rulestr,
|
||||
const filter_rule *template, int xflags);
|
||||
void parse_filter_file(filter_rule_list *listp, const char *fname, const filter_rule *template, int xflags);
|
||||
char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer,
|
||||
unsigned int *plen_ptr);
|
||||
void send_filter_list(int f_out);
|
||||
void recv_filter_list(int f_in);
|
||||
int sparse_end(int f, OFF_T size);
|
||||
int flush_write_file(int f);
|
||||
int write_file(int f, char *buf, int len);
|
||||
struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size);
|
||||
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len);
|
||||
int unmap_file(struct map_struct *map);
|
||||
void init_flist(void);
|
||||
void show_flist_stats(void);
|
||||
int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks);
|
||||
int change_pathname(struct file_struct *file, const char *dir, int dirlen);
|
||||
struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
STRUCT_STAT *stp, int flags, int filter_level);
|
||||
void unmake_file(struct file_struct *file);
|
||||
void send_extra_file_list(int f, int at_least);
|
||||
struct file_list *send_file_list(int f, int argc, char *argv[]);
|
||||
struct file_list *recv_file_list(int f);
|
||||
void recv_additional_file_list(int f);
|
||||
int flist_find(struct file_list *flist, struct file_struct *f);
|
||||
int flist_find_ignore_dirness(struct file_list *flist, struct file_struct *f);
|
||||
void clear_file(struct file_struct *file);
|
||||
struct file_list *flist_new(int flags, char *msg);
|
||||
void flist_free(struct file_list *flist);
|
||||
int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2);
|
||||
int f_name_has_prefix(const struct file_struct *f1, const struct file_struct *f2);
|
||||
char *f_name_buf(void);
|
||||
char *f_name(const struct file_struct *f, char *fbuf);
|
||||
struct file_list *get_dirlist(char *dirname, int dlen, int flags);
|
||||
int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp);
|
||||
void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statret,
|
||||
stat_x *sxp, int32 iflags, uchar fnamecmp_type,
|
||||
const char *xname);
|
||||
int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st);
|
||||
int atomic_create(struct file_struct *file, char *fname, const char *slnk, const char *hlnk,
|
||||
dev_t rdev, stat_x *sxp, int del_for_flag);
|
||||
void check_for_finished_files(int itemizing, enum logcode code, int check_redo);
|
||||
void generate_files(int f_out, const char *local_name);
|
||||
struct hashtable *hashtable_create(int size, int key64);
|
||||
void hashtable_destroy(struct hashtable *tbl);
|
||||
void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing);
|
||||
void init_hard_links(void);
|
||||
struct ht_int64_node *idev_find(int64 dev, int64 ino);
|
||||
void idev_destroy(void);
|
||||
void match_hard_links(struct file_list *flist);
|
||||
int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
int statret, stat_x *sxp, int itemizing,
|
||||
enum logcode code);
|
||||
int hard_link_one(struct file_struct *file, const char *fname,
|
||||
const char *oldname, int terse);
|
||||
void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
STRUCT_STAT *stp, int itemizing, enum logcode code,
|
||||
int alt_dest);
|
||||
int skip_hard_link(struct file_struct *file, struct file_list **flist_p);
|
||||
void reduce_iobuf_size(xbuf *out, size_t new_size);
|
||||
void restore_iobuf_size(xbuf *out);
|
||||
void noop_io_until_death(void);
|
||||
int send_msg(enum msgcode code, const char *buf, size_t len, int convert);
|
||||
void send_msg_int(enum msgcode code, int num);
|
||||
void io_set_sock_fds(int f_in, int f_out);
|
||||
void set_io_timeout(int secs);
|
||||
void increment_active_files(int ndx, int itemizing, enum logcode code);
|
||||
int get_redo_num(void);
|
||||
int get_hlink_num(void);
|
||||
void start_filesfrom_forwarding(int fd);
|
||||
int read_line(int fd, char *buf, size_t bufsiz, int flags);
|
||||
void read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
|
||||
char ***argv_p, int *argc_p, char **request_p);
|
||||
BOOL io_start_buffering_out(int f_out);
|
||||
BOOL io_start_buffering_in(int f_in);
|
||||
void io_end_buffering_in(BOOL free_buffers);
|
||||
void io_end_buffering_out(BOOL free_buffers);
|
||||
void maybe_flush_socket(int important);
|
||||
void maybe_send_keepalive(time_t now, int flags);
|
||||
void start_flist_forward(int ndx);
|
||||
void stop_flist_forward(void);
|
||||
void wait_for_receiver(void);
|
||||
unsigned short read_shortint(int f);
|
||||
int32 read_int(int f);
|
||||
int32 read_varint(int f);
|
||||
int64 read_varlong(int f, uchar min_bytes);
|
||||
int64 read_longint(int f);
|
||||
void read_buf(int f, char *buf, size_t len);
|
||||
void read_sbuf(int f, char *buf, size_t len);
|
||||
uchar read_byte(int f);
|
||||
int read_vstring(int f, char *buf, int bufsize);
|
||||
void read_sum_head(int f, struct sum_struct *sum);
|
||||
void write_sum_head(int f, struct sum_struct *sum);
|
||||
void io_flush(int flush_it_all);
|
||||
void write_shortint(int f, unsigned short x);
|
||||
void write_int(int f, int32 x);
|
||||
void write_varint(int f, int32 x);
|
||||
void write_varlong(int f, int64 x, uchar min_bytes);
|
||||
void write_longint(int f, int64 x);
|
||||
void write_bigbuf(int f, const char *buf, size_t len);
|
||||
void write_buf(int f, const char *buf, size_t len);
|
||||
void write_sbuf(int f, const char *buf);
|
||||
void write_byte(int f, uchar c);
|
||||
void write_vstring(int f, const char *str, int len);
|
||||
void write_ndx(int f, int32 ndx);
|
||||
int32 read_ndx(int f);
|
||||
int read_line_old(int fd, char *buf, size_t bufsiz, int eof_ok);
|
||||
void io_printf(int fd, const char *format, ...);
|
||||
void io_start_multiplex_out(int fd);
|
||||
void io_start_multiplex_in(int fd);
|
||||
int io_end_multiplex_in(int mode);
|
||||
int io_end_multiplex_out(int mode);
|
||||
void start_write_batch(int fd);
|
||||
void stop_write_batch(void);
|
||||
char *lp_bind_address(void);
|
||||
char *lp_motd_file(void);
|
||||
char *lp_pid_file(void);
|
||||
char *lp_socket_options(void);
|
||||
int lp_listen_backlog(void);
|
||||
int lp_rsync_port(void);
|
||||
char *lp_auth_users(int module_id);
|
||||
char *lp_charset(int module_id);
|
||||
char *lp_comment(int module_id);
|
||||
char *lp_dont_compress(int module_id);
|
||||
char *lp_exclude(int module_id);
|
||||
char *lp_exclude_from(int module_id);
|
||||
char *lp_filter(int module_id);
|
||||
char *lp_gid(int module_id);
|
||||
char *lp_hosts_allow(int module_id);
|
||||
char *lp_hosts_deny(int module_id);
|
||||
char *lp_include(int module_id);
|
||||
char *lp_include_from(int module_id);
|
||||
char *lp_incoming_chmod(int module_id);
|
||||
char *lp_lock_file(int module_id);
|
||||
char *lp_log_file(int module_id);
|
||||
char *lp_log_format(int module_id);
|
||||
char *lp_name(int module_id);
|
||||
char *lp_outgoing_chmod(int module_id);
|
||||
char *lp_path(int module_id);
|
||||
char *lp_postxfer_exec(int module_id);
|
||||
char *lp_prexfer_exec(int module_id);
|
||||
char *lp_refuse_options(int module_id);
|
||||
char *lp_secrets_file(int module_id);
|
||||
char *lp_temp_dir(int module_id);
|
||||
char *lp_uid(int module_id);
|
||||
int lp_max_connections(int module_id);
|
||||
int lp_max_verbosity(int module_id);
|
||||
int lp_syslog_facility(int module_id);
|
||||
int lp_timeout(int module_id);
|
||||
BOOL lp_fake_super(int module_id);
|
||||
BOOL lp_forward_lookup(int module_id);
|
||||
BOOL lp_ignore_errors(int module_id);
|
||||
BOOL lp_ignore_nonreadable(int module_id);
|
||||
BOOL lp_list(int module_id);
|
||||
BOOL lp_munge_symlinks(int module_id);
|
||||
BOOL lp_numeric_ids(int module_id);
|
||||
BOOL lp_read_only(int module_id);
|
||||
BOOL lp_reverse_lookup(int module_id);
|
||||
BOOL lp_strict_modes(int module_id);
|
||||
BOOL lp_transfer_logging(int module_id);
|
||||
BOOL lp_use_chroot(int module_id);
|
||||
BOOL lp_write_only(int module_id);
|
||||
int lp_load(char *pszFname, int globals_only);
|
||||
BOOL set_dparams(int syntax_check_only);
|
||||
int lp_num_modules(void);
|
||||
int lp_number(char *name);
|
||||
void log_init(int restart);
|
||||
void logfile_close(void);
|
||||
void logfile_reopen(void);
|
||||
void rwrite(enum logcode code, const char *buf, int len, int is_utf8);
|
||||
void rprintf(enum logcode code, const char *format, ...);
|
||||
void rsyserr(enum logcode code, int errcode, const char *format, ...);
|
||||
void rflush(enum logcode code);
|
||||
void remember_initial_stats(void);
|
||||
int log_format_has(const char *format, char esc);
|
||||
void log_item(enum logcode code, struct file_struct *file, int iflags, const char *hlink);
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
const char *buf);
|
||||
void log_delete(const char *fname, int mode);
|
||||
void log_exit(int code, const char *file, int line);
|
||||
pid_t wait_process(pid_t pid, int *status_ptr, int flags);
|
||||
void write_del_stats(int f);
|
||||
void read_del_stats(int f);
|
||||
int child_main(int argc, char *argv[]);
|
||||
void start_server(int f_in, int f_out, int argc, char *argv[]);
|
||||
int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]);
|
||||
RETSIGTYPE remember_children(UNUSED(int val));
|
||||
const char *get_panic_action(void);
|
||||
int main(int argc,char *argv[]);
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len);
|
||||
void match_report(void);
|
||||
void limit_output_verbosity(int level);
|
||||
void reset_output_levels(void);
|
||||
void negate_output_levels(void);
|
||||
void usage(enum logcode F);
|
||||
void option_error(void);
|
||||
int parse_arguments(int *argc_p, const char ***argv_p);
|
||||
void server_options(char **args, int *argc_p);
|
||||
char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr);
|
||||
int pm_process( char *FileName,
|
||||
BOOL (*sfunc)(char *),
|
||||
BOOL (*pfunc)(char *, char *) );
|
||||
pid_t piped_child(char **command, int *f_in, int *f_out);
|
||||
pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
int (*child_main)(int, char*[]));
|
||||
void set_current_file_index(struct file_struct *file, int ndx);
|
||||
void end_progress(OFF_T size);
|
||||
void show_progress(OFF_T ofs, OFF_T size);
|
||||
int get_tmpname(char *fnametmp, const char *fname, BOOL make_unique);
|
||||
int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file);
|
||||
int recv_files(int f_in, int f_out, char *local_name);
|
||||
void setup_iconv(void);
|
||||
int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags);
|
||||
void send_protected_args(int fd, char *args[]);
|
||||
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
|
||||
char *buf, int *len_ptr);
|
||||
void free_sums(struct sum_struct *s);
|
||||
mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
|
||||
int exists);
|
||||
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
const char *fnamecmp, int flags);
|
||||
RETSIGTYPE sig_int(int sig_num);
|
||||
int finish_transfer(const char *fname, const char *fnametmp,
|
||||
const char *fnamecmp, const char *partialptr,
|
||||
struct file_struct *file, int ok_to_set_time,
|
||||
int overwriting_basis);
|
||||
struct file_list *flist_for_ndx(int ndx, const char *fatal_error_loc);
|
||||
const char *who_am_i(void);
|
||||
void successful_send(int ndx);
|
||||
void send_files(int f_in, int f_out);
|
||||
int try_bind_local(int s, int ai_family, int ai_socktype,
|
||||
const char *bind_addr);
|
||||
int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
int af_hint);
|
||||
int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
|
||||
int af_hint);
|
||||
int is_a_socket(int fd);
|
||||
void start_accept_loop(int port, int (*fn)(int, int));
|
||||
void set_socket_options(int fd, char *options);
|
||||
int do_unlink(const char *fname);
|
||||
int do_symlink(const char *lnk, const char *fname);
|
||||
ssize_t do_readlink(const char *path, char *buf, size_t bufsiz);
|
||||
int do_link(const char *fname1, const char *fname2);
|
||||
int do_lchown(const char *path, uid_t owner, gid_t group);
|
||||
int do_mknod(const char *pathname, mode_t mode, dev_t dev);
|
||||
int do_rmdir(const char *pathname);
|
||||
int do_open(const char *pathname, int flags, mode_t mode);
|
||||
int do_chmod(const char *path, mode_t mode);
|
||||
int do_rename(const char *fname1, const char *fname2);
|
||||
int do_ftruncate(int fd, OFF_T size);
|
||||
void trim_trailing_slashes(char *name);
|
||||
int do_mkdir(char *fname, mode_t mode);
|
||||
int do_mkstemp(char *template, mode_t perms);
|
||||
int do_stat(const char *fname, STRUCT_STAT *st);
|
||||
int do_lstat(const char *fname, STRUCT_STAT *st);
|
||||
int do_fstat(int fd, STRUCT_STAT *st);
|
||||
OFF_T do_lseek(int fd, OFF_T offset, int whence);
|
||||
int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec);
|
||||
int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec);
|
||||
int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec);
|
||||
int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec));
|
||||
int do_fallocate(int fd, OFF_T offset, OFF_T length);
|
||||
int do_open_nofollow(const char *pathname, int flags);
|
||||
void set_compression(const char *fname);
|
||||
void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset,
|
||||
int32 n, int32 toklen);
|
||||
int32 recv_token(int f, char **data);
|
||||
void see_token(char *data, int32 toklen);
|
||||
char *uid_to_user(uid_t uid);
|
||||
char *gid_to_group(gid_t gid);
|
||||
int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok);
|
||||
int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok);
|
||||
uid_t match_uid(uid_t uid);
|
||||
gid_t match_gid(gid_t gid, uint16 *flags_ptr);
|
||||
const char *add_uid(uid_t uid);
|
||||
const char *add_gid(gid_t gid);
|
||||
void send_id_list(int f);
|
||||
uid_t recv_user_name(int f, uid_t uid);
|
||||
gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr);
|
||||
void recv_id_list(int f, struct file_list *flist);
|
||||
void parse_name_map(char *map, BOOL usernames);
|
||||
const char *getallgroups(uid_t uid, gid_t *gid_list, int *size_ptr);
|
||||
void set_nonblocking(int fd);
|
||||
void set_blocking(int fd);
|
||||
int fd_pair(int fd[2]);
|
||||
void print_child_argv(const char *prefix, char **cmd);
|
||||
int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode);
|
||||
int make_path(char *fname, int flags);
|
||||
int full_write(int desc, const char *ptr, size_t len);
|
||||
int copy_file(const char *source, const char *dest, int ofd, mode_t mode);
|
||||
int robust_unlink(const char *fname);
|
||||
int robust_rename(const char *from, const char *to, const char *partialptr,
|
||||
int mode);
|
||||
pid_t do_fork(void);
|
||||
void kill_all(int sig);
|
||||
int lock_range(int fd, int offset, int len);
|
||||
int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p);
|
||||
void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p);
|
||||
void strlower(char *s);
|
||||
size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2);
|
||||
size_t stringjoin(char *dest, size_t destsize, ...);
|
||||
int count_dir_elements(const char *p);
|
||||
int clean_fname(char *name, int flags);
|
||||
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,
|
||||
int flags);
|
||||
int change_dir(const char *dir, int set_path_only);
|
||||
char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr);
|
||||
char *full_fname(const char *fn);
|
||||
char *partial_dir_fname(const char *fname);
|
||||
int handle_partial_dir(const char *fname, int create);
|
||||
int unsafe_symlink(const char *dest, const char *src);
|
||||
char *timestring(time_t t);
|
||||
int cmp_time(time_t file1, time_t file2);
|
||||
int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6);
|
||||
const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr);
|
||||
uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2);
|
||||
struct bitbag *bitbag_create(int max_ndx);
|
||||
void bitbag_set_bit(struct bitbag *bb, int ndx);
|
||||
void bitbag_clear_bit(struct bitbag *bb, int ndx);
|
||||
int bitbag_check_bit(struct bitbag *bb, int ndx);
|
||||
int bitbag_next_bit(struct bitbag *bb, int after);
|
||||
void flist_ndx_push(flist_ndx_list *lp, int ndx);
|
||||
int flist_ndx_pop(flist_ndx_list *lp);
|
||||
void *expand_item_list(item_list *lp, size_t item_size,
|
||||
const char *desc, int incr);
|
||||
int msleep(int t);
|
||||
void *_new_array(unsigned long num, unsigned int size, int use_calloc);
|
||||
void *_realloc_array(void *ptr, unsigned int size, size_t num);
|
||||
const char *sum_as_hex(const char *sum);
|
||||
NORETURN void out_of_memory(const char *str);
|
||||
NORETURN void overflow_exit(const char *str);
|
||||
void free_xattr(stat_x *sxp);
|
||||
int get_xattr(const char *fname, stat_x *sxp);
|
||||
int copy_xattrs(const char *source, const char *dest);
|
||||
int send_xattr(int f, stat_x *sxp);
|
||||
int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all);
|
||||
void send_xattr_request(const char *fname, struct file_struct *file, int f_out);
|
||||
int recv_xattr_request(struct file_struct *file, int f_in);
|
||||
void receive_xattr(int f, struct file_struct *file);
|
||||
void cache_tmp_xattr(struct file_struct *file, stat_x *sxp);
|
||||
void uncache_tmp_xattrs(void);
|
||||
int set_xattr(const char *fname, const struct file_struct *file,
|
||||
const char *fnamecmp, stat_x *sxp);
|
||||
char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p);
|
||||
int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len);
|
||||
int del_def_xattr_acl(const char *fname);
|
||||
int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst);
|
||||
int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode);
|
||||
int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst);
|
||||
int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst);
|
||||
int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst);
|
||||
int sys_gettimeofday(struct timeval *tv);
|
||||
char *do_big_num(int64 num, int human_flag, const char *fract);
|
||||
char *do_big_dnum(double dnum, int human_flag, int decimal_digits);
|
0
rsync/proto.h-tstamp
Normal file
0
rsync/proto.h-tstamp
Normal file
953
rsync/receiver.c
Normal file
953
rsync/receiver.c
Normal file
@ -0,0 +1,953 @@
|
||||
/*
|
||||
* Routines only used by the receiving process.
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "inums.h"
|
||||
|
||||
extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int inc_recurse;
|
||||
extern int log_before_transfer;
|
||||
extern int stdout_format_has_i;
|
||||
extern int logfile_format_has_i;
|
||||
extern int want_xattr_optim;
|
||||
extern int csum_length;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int batch_gen_fd;
|
||||
extern int protocol_version;
|
||||
extern int relative_paths;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_xattrs;
|
||||
extern int basis_dir_cnt;
|
||||
extern int make_backups;
|
||||
extern int cleanup_got_literal;
|
||||
extern int remove_source_files;
|
||||
extern int append_mode;
|
||||
extern int sparse_files;
|
||||
extern int preallocate_files;
|
||||
extern int keep_partial;
|
||||
extern int checksum_len;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
extern int allowed_lull;
|
||||
extern int delay_updates;
|
||||
extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern char sender_file_sum[MAX_DIGEST_LEN];
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern filter_rule_list daemon_filter_list;
|
||||
|
||||
static struct bitbag *delayed_bits = NULL;
|
||||
static int phase = 0, redoing = 0;
|
||||
static flist_ndx_list batch_redo_list;
|
||||
/* We're either updating the basis file or an identical copy: */
|
||||
static int updating_basis_or_equiv;
|
||||
|
||||
#define TMPNAME_SUFFIX ".XXXXXX"
|
||||
#define TMPNAME_SUFFIX_LEN ((int)sizeof TMPNAME_SUFFIX - 1)
|
||||
#define MAX_UNIQUE_NUMBER 999999
|
||||
#define MAX_UNIQUE_LOOP 100
|
||||
|
||||
/* get_tmpname() - create a tmp filename for a given filename
|
||||
*
|
||||
* If a tmpdir is defined, use that as the directory to put it in. Otherwise,
|
||||
* the tmp filename is in the same directory as the given name. Note that
|
||||
* there may be no directory at all in the given name!
|
||||
*
|
||||
* The tmp filename is basically the given filename with a dot prepended, and
|
||||
* .XXXXXX appended (for mkstemp() to put its unique gunk in). We take care
|
||||
* to not exceed either the MAXPATHLEN or NAME_MAX, especially the last, as
|
||||
* the basename basically becomes 8 characters longer. In such a case, the
|
||||
* original name is shortened sufficiently to make it all fit.
|
||||
*
|
||||
* If the make_unique arg is True, the XXXXXX string is replaced with a unique
|
||||
* string that doesn't exist at the time of the check. This is intended to be
|
||||
* used for creating hard links, symlinks, devices, and special files, since
|
||||
* normal files should be handled by mkstemp() for safety.
|
||||
*
|
||||
* Of course, the only reason the file is based on the original name is to
|
||||
* make it easier to figure out what purpose a temp file is serving when a
|
||||
* transfer is in progress. */
|
||||
int get_tmpname(char *fnametmp, const char *fname, BOOL make_unique)
|
||||
{
|
||||
int maxname, length = 0;
|
||||
const char *f;
|
||||
char *suf;
|
||||
|
||||
if (tmpdir) {
|
||||
/* Note: this can't overflow, so the return value is safe */
|
||||
length = strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2);
|
||||
fnametmp[length++] = '/';
|
||||
}
|
||||
|
||||
if ((f = strrchr(fname, '/')) != NULL) {
|
||||
++f;
|
||||
if (!tmpdir) {
|
||||
length = f - fname;
|
||||
/* copy up to and including the slash */
|
||||
strlcpy(fnametmp, fname, length + 1);
|
||||
}
|
||||
} else
|
||||
f = fname;
|
||||
|
||||
if (!tmpdir) { /* using a tmpdir avoids the leading dot on our temp names */
|
||||
if (*f == '.') /* avoid an extra leading dot for OS X's sake */
|
||||
f++;
|
||||
fnametmp[length++] = '.';
|
||||
}
|
||||
|
||||
/* The maxname value is bufsize, and includes space for the '\0'.
|
||||
* NAME_MAX needs an extra -1 for the name's leading dot. */
|
||||
maxname = MIN(MAXPATHLEN - length - TMPNAME_SUFFIX_LEN,
|
||||
NAME_MAX - 1 - TMPNAME_SUFFIX_LEN);
|
||||
|
||||
if (maxname < 0) {
|
||||
rprintf(FERROR_XFER, "temporary filename too long: %s\n", fname);
|
||||
fnametmp[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (maxname) {
|
||||
int added = strlcpy(fnametmp + length, f, maxname);
|
||||
if (added >= maxname)
|
||||
added = maxname - 1;
|
||||
suf = fnametmp + length + added;
|
||||
|
||||
/* Trim any dangling high-bit chars if the first-trimmed char (if any) is
|
||||
* also a high-bit char, just in case we cut into a multi-byte sequence.
|
||||
* We are guaranteed to stop because of the leading '.' we added. */
|
||||
if ((int)f[added] & 0x80) {
|
||||
while ((int)suf[-1] & 0x80)
|
||||
suf--;
|
||||
}
|
||||
/* trim one trailing dot before our suffix's dot */
|
||||
if (suf[-1] == '.')
|
||||
suf--;
|
||||
} else
|
||||
suf = fnametmp + length - 1; /* overwrite the leading dot with suffix's dot */
|
||||
|
||||
if (make_unique) {
|
||||
static unsigned counter_limit;
|
||||
unsigned counter;
|
||||
|
||||
if (!counter_limit) {
|
||||
counter_limit = (unsigned)getpid() + MAX_UNIQUE_LOOP;
|
||||
if (counter_limit > MAX_UNIQUE_NUMBER || counter_limit < MAX_UNIQUE_LOOP)
|
||||
counter_limit = MAX_UNIQUE_LOOP;
|
||||
}
|
||||
counter = counter_limit - MAX_UNIQUE_LOOP;
|
||||
|
||||
/* This doesn't have to be very good because we don't need
|
||||
* to worry about someone trying to guess the values: all
|
||||
* a conflict will do is cause a device, special file, hard
|
||||
* link, or symlink to fail to be created. Also: avoid
|
||||
* using mktemp() due to gcc's annoying warning. */
|
||||
while (1) {
|
||||
snprintf(suf, TMPNAME_SUFFIX_LEN+1, ".%d", counter);
|
||||
if (access(fnametmp, 0) < 0)
|
||||
break;
|
||||
if (++counter >= counter_limit)
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
memcpy(suf, TMPNAME_SUFFIX, TMPNAME_SUFFIX_LEN+1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Opens a temporary file for writing.
|
||||
* Success: Writes name into fnametmp, returns fd.
|
||||
* Failure: Clobbers fnametmp, returns -1.
|
||||
* Calling cleanup_set() is the caller's job. */
|
||||
int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
|
||||
{
|
||||
int fd;
|
||||
mode_t added_perms;
|
||||
|
||||
if (!get_tmpname(fnametmp, fname, False))
|
||||
return -1;
|
||||
|
||||
if (am_root < 0) {
|
||||
/* For --fake-super, the file must be useable by the copying
|
||||
* user, just like it would be for root. */
|
||||
added_perms = S_IRUSR|S_IWUSR;
|
||||
} else {
|
||||
/* For a normal copy, we need to be able to tweak things like xattrs. */
|
||||
added_perms = S_IWUSR;
|
||||
}
|
||||
|
||||
/* We initially set the perms without the setuid/setgid bits or group
|
||||
* access to ensure that there is no race condition. They will be
|
||||
* correctly updated after the right owner and group info is set.
|
||||
* (Thanks to snabb@epipe.fi for pointing this out.) */
|
||||
fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS);
|
||||
|
||||
#if 0
|
||||
/* In most cases parent directories will already exist because their
|
||||
* information should have been previously transferred, but that may
|
||||
* not be the case with -R */
|
||||
if (fd == -1 && relative_paths && errno == ENOENT
|
||||
&& make_path(fnametmp, MKP_SKIP_SLASH | MKP_DROP_NAME) == 0) {
|
||||
/* Get back to name with XXXXXX in it. */
|
||||
get_tmpname(fnametmp, fname, False);
|
||||
fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fd == -1) {
|
||||
rsyserr(FERROR_XFER, errno, "mkstemp %s failed",
|
||||
full_fname(fnametmp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
const char *fname, int fd, OFF_T total_size)
|
||||
{
|
||||
static char file_sum1[MAX_DIGEST_LEN];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
int32 len;
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
int32 i;
|
||||
char *map = NULL;
|
||||
#ifdef SUPPORT_PREALLOCATION
|
||||
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
||||
OFF_T preallocated_len = 0;
|
||||
#endif
|
||||
|
||||
if (preallocate_files && fd != -1 && total_size > 0 && (!inplace || total_size > size_r)) {
|
||||
/* Try to preallocate enough space for file's eventual length. Can
|
||||
* reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
|
||||
if (do_fallocate(fd, 0, total_size) == 0) {
|
||||
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
||||
preallocated_len = total_size;
|
||||
#endif
|
||||
} else
|
||||
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname));
|
||||
}
|
||||
#endif
|
||||
|
||||
read_sum_head(f_in, &sum);
|
||||
|
||||
if (fd_r >= 0 && size_r > 0) {
|
||||
int32 read_size = MAX(sum.blength * 2, 16*1024);
|
||||
mapbuf = map_file(fd_r, size_r, read_size, sum.blength);
|
||||
if (DEBUG_GTE(DELTASUM, 2)) {
|
||||
rprintf(FINFO, "recv mapped %s of size %s\n",
|
||||
fname_r, big_num(size_r));
|
||||
}
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
OFF_T j;
|
||||
sum.flength = (OFF_T)sum.count * sum.blength;
|
||||
if (sum.remainder)
|
||||
sum.flength -= sum.blength - sum.remainder;
|
||||
if (append_mode == 2 && mapbuf) {
|
||||
for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) {
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
show_progress(offset, total_size);
|
||||
sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE),
|
||||
CHUNK_SIZE);
|
||||
offset = j;
|
||||
}
|
||||
if (offset < sum.flength) {
|
||||
int32 len = (int32)(sum.flength - offset);
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
show_progress(offset, total_size);
|
||||
sum_update(map_ptr(mapbuf, offset, len), len);
|
||||
}
|
||||
}
|
||||
offset = sum.flength;
|
||||
if (fd != -1 && (j = do_lseek(fd, offset, SEEK_SET)) != offset) {
|
||||
rsyserr(FERROR_XFER, errno, "lseek of %s returned %s, not %s",
|
||||
full_fname(fname), big_num(j), big_num(offset));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
}
|
||||
|
||||
while ((i = recv_token(f_in, &data)) != 0) {
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
show_progress(offset, total_size);
|
||||
|
||||
if (allowed_lull)
|
||||
maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH | MSK_ACTIVE_RECEIVER);
|
||||
|
||||
if (i > 0) {
|
||||
if (DEBUG_GTE(DELTASUM, 3)) {
|
||||
rprintf(FINFO,"data recv %d at %s\n",
|
||||
i, big_num(offset));
|
||||
}
|
||||
|
||||
stats.literal_data += i;
|
||||
cleanup_got_literal = 1;
|
||||
|
||||
sum_update(data, i);
|
||||
|
||||
if (fd != -1 && write_file(fd,data,i) != i)
|
||||
goto report_write_error;
|
||||
offset += i;
|
||||
continue;
|
||||
}
|
||||
|
||||
i = -(i+1);
|
||||
offset2 = i * (OFF_T)sum.blength;
|
||||
len = sum.blength;
|
||||
if (i == (int)sum.count-1 && sum.remainder != 0)
|
||||
len = sum.remainder;
|
||||
|
||||
stats.matched_data += len;
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 3)) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] of size %ld at %s offset=%s%s\n",
|
||||
i, (long)len, big_num(offset2), big_num(offset),
|
||||
updating_basis_or_equiv && offset == offset2 ? " (seek)" : "");
|
||||
}
|
||||
|
||||
if (mapbuf) {
|
||||
map = map_ptr(mapbuf,offset2,len);
|
||||
|
||||
see_token(map, len);
|
||||
sum_update(map, len);
|
||||
}
|
||||
|
||||
if (updating_basis_or_equiv) {
|
||||
if (offset == offset2 && fd != -1) {
|
||||
OFF_T pos;
|
||||
if (flush_write_file(fd) < 0)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"lseek of %s returned %s, not %s",
|
||||
full_fname(fname),
|
||||
big_num(pos), big_num(offset));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fd != -1 && map && write_file(fd, map, len) != (int)len)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (flush_write_file(fd) < 0)
|
||||
goto report_write_error;
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
/* inplace: New data could be shorter than old data.
|
||||
* preallocate_files: total_size could have been an overestimate.
|
||||
* Cut off any extra preallocated zeros from dest file. */
|
||||
if ((inplace
|
||||
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
||||
|| preallocated_len > offset
|
||||
#endif
|
||||
) && fd != -1 && do_ftruncate(fd, offset) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
end_progress(total_size);
|
||||
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
|
||||
report_write_error:
|
||||
rsyserr(FERROR_XFER, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (sum_end(file_sum1) != checksum_len)
|
||||
overflow_exit("checksum_len"); /* Impossible... */
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
read_buf(f_in, sender_file_sum, checksum_len);
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"got file_sum\n");
|
||||
if (fd != -1 && memcmp(file_sum1, sender_file_sum, checksum_len) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void discard_receive_data(int f_in, OFF_T length)
|
||||
{
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
|
||||
}
|
||||
|
||||
static void handle_delayed_updates(char *local_name)
|
||||
{
|
||||
char *fname, *partialptr;
|
||||
int ndx;
|
||||
|
||||
for (ndx = -1; (ndx = bitbag_next_bit(delayed_bits, ndx)) >= 0; ) {
|
||||
struct file_struct *file = cur_flist->files[ndx];
|
||||
fname = local_name ? local_name : f_name(file, NULL);
|
||||
if ((partialptr = partial_dir_fname(fname)) != NULL) {
|
||||
if (make_backups > 0 && !make_backup(fname, False))
|
||||
continue;
|
||||
if (DEBUG_GTE(RECV, 1)) {
|
||||
rprintf(FINFO, "renaming %s to %s\n",
|
||||
partialptr, fname);
|
||||
}
|
||||
/* We don't use robust_rename() here because the
|
||||
* partial-dir must be on the same drive. */
|
||||
if (do_rename(partialptr, fname) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"rename failed for %s (from %s)",
|
||||
full_fname(fname), partialptr);
|
||||
} else {
|
||||
if (remove_source_files
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void no_batched_update(int ndx, BOOL is_redo)
|
||||
{
|
||||
struct file_list *flist = flist_for_ndx(ndx, "no_batched_update");
|
||||
struct file_struct *file = flist->files[ndx - flist->ndx_start];
|
||||
|
||||
rprintf(FERROR_XFER, "(No batched update for%s \"%s\")\n",
|
||||
is_redo ? " resend of" : "", f_name(file, NULL));
|
||||
|
||||
if (inc_recurse && !dry_run)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
}
|
||||
|
||||
static int we_want_redo(int desired_ndx)
|
||||
{
|
||||
static int redo_ndx = -1;
|
||||
|
||||
while (redo_ndx < desired_ndx) {
|
||||
if (redo_ndx >= 0)
|
||||
no_batched_update(redo_ndx, True);
|
||||
if ((redo_ndx = flist_ndx_pop(&batch_redo_list)) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (redo_ndx == desired_ndx) {
|
||||
redo_ndx = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_wants_ndx(int desired_ndx, int flist_num)
|
||||
{
|
||||
static int next_ndx = -1;
|
||||
static int done_cnt = 0;
|
||||
static BOOL got_eof = False;
|
||||
|
||||
if (got_eof)
|
||||
return 0;
|
||||
|
||||
/* TODO: integrate gen-reading I/O into perform_io() so this is not needed? */
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
while (next_ndx < desired_ndx) {
|
||||
if (inc_recurse && flist_num <= done_cnt)
|
||||
return 0;
|
||||
if (next_ndx >= 0)
|
||||
no_batched_update(next_ndx, False);
|
||||
if ((next_ndx = read_int(batch_gen_fd)) < 0) {
|
||||
if (inc_recurse) {
|
||||
done_cnt++;
|
||||
continue;
|
||||
}
|
||||
got_eof = True;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_ndx == desired_ndx) {
|
||||
next_ndx = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* main routine for receiver process.
|
||||
*
|
||||
* Receiver process runs on the same host as the generator process. */
|
||||
int recv_files(int f_in, int f_out, char *local_name)
|
||||
{
|
||||
int fd1,fd2;
|
||||
STRUCT_STAT st;
|
||||
int iflags, xlen;
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char xname[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnamecmp, *partialptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
uchar fnamecmp_type;
|
||||
struct file_struct *file;
|
||||
int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
|
||||
enum logcode log_code = log_before_transfer ? FLOG : FINFO;
|
||||
int max_phase = protocol_version >= 29 ? 2 : 1;
|
||||
int dflt_perms = (ACCESSPERMS & ~orig_umask);
|
||||
#ifdef SUPPORT_ACLS
|
||||
const char *parent_dirname = "";
|
||||
#endif
|
||||
int ndx, recv_ok;
|
||||
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
|
||||
|
||||
if (delay_updates)
|
||||
delayed_bits = bitbag_create(cur_flist->used + 1);
|
||||
|
||||
while (1) {
|
||||
cleanup_disable();
|
||||
|
||||
/* This call also sets cur_flist. */
|
||||
ndx = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (ndx == NDX_DONE) {
|
||||
if (!am_server && INFO_GTE(PROGRESS, 2) && cur_flist) {
|
||||
set_current_file_index(NULL, 0);
|
||||
end_progress(0);
|
||||
}
|
||||
if (inc_recurse && first_flist) {
|
||||
if (read_batch) {
|
||||
ndx = first_flist->used + first_flist->ndx_start;
|
||||
gen_wants_ndx(ndx, first_flist->flist_num);
|
||||
}
|
||||
flist_free(first_flist);
|
||||
if (first_flist)
|
||||
continue;
|
||||
} else if (read_batch && first_flist) {
|
||||
ndx = first_flist->used;
|
||||
gen_wants_ndx(ndx, first_flist->flist_num);
|
||||
}
|
||||
if (++phase > max_phase)
|
||||
break;
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "recv_files phase=%d\n", phase);
|
||||
if (phase == 2 && delay_updates)
|
||||
handle_delayed_updates(local_name);
|
||||
write_int(f_out, NDX_DONE);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndx - cur_flist->ndx_start >= 0)
|
||||
file = cur_flist->files[ndx - cur_flist->ndx_start];
|
||||
else
|
||||
file = dir_flist->files[cur_flist->parent_ndx];
|
||||
fname = local_name ? local_name : f_name(file, fbuf);
|
||||
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "recv_files(%s)\n", fname);
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
|
||||
&& !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
|
||||
recv_xattr_request(file, f_in);
|
||||
#endif
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
|
||||
&& !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
|
||||
set_file_attrs(fname, file, NULL, fname, 0);
|
||||
#endif
|
||||
if (iflags & ITEM_IS_NEW) {
|
||||
stats.created_files++;
|
||||
if (S_ISREG(file->mode)) {
|
||||
/* Nothing further to count. */
|
||||
} else if (S_ISDIR(file->mode))
|
||||
stats.created_dirs++;
|
||||
#ifdef SUPPORT_LINKS
|
||||
else if (S_ISLNK(file->mode))
|
||||
stats.created_symlinks++;
|
||||
#endif
|
||||
else if (IS_DEVICE(file->mode))
|
||||
stats.created_devices++;
|
||||
else
|
||||
stats.created_specials++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (phase == 2) {
|
||||
rprintf(FERROR,
|
||||
"got transfer request in phase 2 [%s]\n",
|
||||
who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (file->flags & FLAG_FILE_SENT) {
|
||||
if (csum_length == SHORT_SUM_LENGTH) {
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = -make_backups; /* prevents double backup */
|
||||
if (append_mode)
|
||||
sparse_files = -sparse_files;
|
||||
append_mode = -append_mode;
|
||||
csum_length = SUM_LENGTH;
|
||||
redoing = 1;
|
||||
}
|
||||
} else {
|
||||
if (csum_length != SHORT_SUM_LENGTH) {
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = -make_backups;
|
||||
if (append_mode)
|
||||
sparse_files = -sparse_files;
|
||||
append_mode = -append_mode;
|
||||
csum_length = SHORT_SUM_LENGTH;
|
||||
redoing = 0;
|
||||
}
|
||||
if (iflags & ITEM_IS_NEW)
|
||||
stats.created_files++;
|
||||
}
|
||||
|
||||
if (!am_server && INFO_GTE(PROGRESS, 1))
|
||||
set_current_file_index(file, ndx);
|
||||
stats.xferred_files++;
|
||||
stats.total_transferred_size += F_LENGTH(file);
|
||||
|
||||
cleanup_got_literal = 0;
|
||||
|
||||
if (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
int wanted = redoing
|
||||
? we_want_redo(ndx)
|
||||
: gen_wants_ndx(ndx, cur_flist->flist_num);
|
||||
if (!wanted) {
|
||||
rprintf(FINFO,
|
||||
"(Skipping batched update for%s \"%s\")\n",
|
||||
redoing ? " resend of" : "",
|
||||
fname);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!log_before_transfer)
|
||||
remember_initial_stats();
|
||||
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
log_item(FCLIENT, file, iflags, NULL);
|
||||
if (read_batch)
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
continue;
|
||||
}
|
||||
if (write_batch < 0) {
|
||||
log_item(FCLIENT, file, iflags, NULL);
|
||||
if (!am_server)
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
partialptr = partial_dir ? partial_dir_fname(fname) : fname;
|
||||
|
||||
if (protocol_version >= 29) {
|
||||
switch (fnamecmp_type) {
|
||||
case FNAMECMP_FNAME:
|
||||
fnamecmp = fname;
|
||||
break;
|
||||
case FNAMECMP_PARTIAL_DIR:
|
||||
fnamecmp = partialptr;
|
||||
break;
|
||||
case FNAMECMP_BACKUP:
|
||||
fnamecmp = get_backup_name(fname);
|
||||
break;
|
||||
case FNAMECMP_FUZZY:
|
||||
if (file->dirname) {
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
} else
|
||||
fnamecmp = xname;
|
||||
break;
|
||||
default:
|
||||
if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) {
|
||||
fnamecmp_type -= FNAMECMP_FUZZY + 1;
|
||||
if (file->dirname) {
|
||||
stringjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
basis_dir[fnamecmp_type], "/", file->dirname, "/", xname, NULL);
|
||||
} else
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], xname);
|
||||
} else if (fnamecmp_type >= basis_dir_cnt) {
|
||||
rprintf(FERROR,
|
||||
"invalid basis_dir index: %d.\n",
|
||||
fnamecmp_type);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
break;
|
||||
}
|
||||
if (!fnamecmp || (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
|
||||
fnamecmp = fname;
|
||||
fnamecmp_type = FNAMECMP_FNAME;
|
||||
}
|
||||
} else {
|
||||
/* Reminder: --inplace && --partial-dir are never
|
||||
* enabled at the same time. */
|
||||
if (inplace && make_backups > 0) {
|
||||
if (!(fnamecmp = get_backup_name(fname)))
|
||||
fnamecmp = fname;
|
||||
else
|
||||
fnamecmp_type = FNAMECMP_BACKUP;
|
||||
} else if (partial_dir && partialptr)
|
||||
fnamecmp = partialptr;
|
||||
else
|
||||
fnamecmp = fname;
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd1 == -1 && protocol_version < 29) {
|
||||
if (fnamecmp != fname) {
|
||||
fnamecmp = fname;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 == -1 && basis_dir[0]) {
|
||||
/* pre-29 allowed only one alternate basis */
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
basis_dir[0], fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
updating_basis_or_equiv = inplace
|
||||
&& (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);
|
||||
|
||||
if (fd1 == -1) {
|
||||
st.st_mode = 0;
|
||||
st.st_size = 0;
|
||||
} else if (do_fstat(fd1,&st) != 0) {
|
||||
rsyserr(FERROR_XFER, errno, "fstat %s failed",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
|
||||
/* this special handling for directories
|
||||
* wouldn't be necessary if robust_rename()
|
||||
* and the underlying robust_unlink could cope
|
||||
* with directories
|
||||
*/
|
||||
rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
|
||||
close(fd1);
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
/* If we're not preserving permissions, change the file-list's
|
||||
* mode based on the local permissions and some heuristics. */
|
||||
if (!preserve_perms) {
|
||||
int exists = fd1 != -1;
|
||||
#ifdef SUPPORT_ACLS
|
||||
const char *dn = file->dirname ? file->dirname : ".";
|
||||
if (parent_dirname != dn
|
||||
&& strcmp(parent_dirname, dn) != 0) {
|
||||
dflt_perms = default_perms_for_dir(dn);
|
||||
parent_dirname = dn;
|
||||
}
|
||||
#endif
|
||||
file->mode = dest_mode(file->mode, st.st_mode,
|
||||
dflt_perms, exists);
|
||||
}
|
||||
|
||||
/* We now check to see if we are writing the file "inplace" */
|
||||
if (inplace) {
|
||||
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR_XFER, errno, "open %s failed",
|
||||
full_fname(fname));
|
||||
} else if (updating_basis_or_equiv)
|
||||
cleanup_set(NULL, NULL, file, fd1, fd2);
|
||||
} else {
|
||||
fd2 = open_tmpfile(fnametmp, fname, file);
|
||||
if (fd2 != -1)
|
||||
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
|
||||
}
|
||||
|
||||
if (fd2 == -1) {
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* log the transfer */
|
||||
if (log_before_transfer)
|
||||
log_item(FCLIENT, file, iflags, NULL);
|
||||
else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1))
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
fname, fd2, F_LENGTH(file));
|
||||
|
||||
log_item(log_code, file, iflags, NULL);
|
||||
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (close(fd2) < 0) {
|
||||
rsyserr(FERROR, errno, "close failed on %s",
|
||||
full_fname(fnametmp));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
|
||||
if (partialptr == fname)
|
||||
partialptr = NULL;
|
||||
if (!finish_transfer(fname, fnametmp, fnamecmp,
|
||||
partialptr, file, recv_ok, 1))
|
||||
recv_ok = -1;
|
||||
else if (fnamecmp == partialptr) {
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
} else if (keep_partial && partialptr) {
|
||||
if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
|
||||
rprintf(FERROR,
|
||||
"Unable to create partial-dir for %s -- discarding %s.\n",
|
||||
local_name ? local_name : f_name(file, NULL),
|
||||
recv_ok ? "completed file" : "partial file");
|
||||
do_unlink(fnametmp);
|
||||
recv_ok = -1;
|
||||
} else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
|
||||
file, recv_ok, !partial_dir))
|
||||
recv_ok = -1;
|
||||
else if (delay_updates && recv_ok) {
|
||||
bitbag_set_bit(delayed_bits, ndx);
|
||||
recv_ok = 2;
|
||||
} else
|
||||
partialptr = NULL;
|
||||
} else
|
||||
do_unlink(fnametmp);
|
||||
|
||||
cleanup_disable();
|
||||
|
||||
if (read_batch)
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
|
||||
switch (recv_ok) {
|
||||
case 2:
|
||||
break;
|
||||
case 1:
|
||||
if (remove_source_files || inc_recurse
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
break;
|
||||
case 0: {
|
||||
enum logcode msgtype = redoing ? FERROR_XFER : FWARNING;
|
||||
if (msgtype == FERROR_XFER || INFO_GTE(NAME, 1)) {
|
||||
char *errstr, *redostr, *keptstr;
|
||||
if (!(keep_partial && partialptr) && !inplace)
|
||||
keptstr = "discarded";
|
||||
else if (partial_dir)
|
||||
keptstr = "put into partial-dir";
|
||||
else
|
||||
keptstr = "retained";
|
||||
if (msgtype == FERROR_XFER) {
|
||||
errstr = "ERROR";
|
||||
redostr = "";
|
||||
} else {
|
||||
errstr = "WARNING";
|
||||
redostr = read_batch ? " (may try again)"
|
||||
: " (will try again)";
|
||||
}
|
||||
rprintf(msgtype,
|
||||
"%s: %s failed verification -- update %s%s.\n",
|
||||
errstr, local_name ? f_name(file, NULL) : fname,
|
||||
keptstr, redostr);
|
||||
}
|
||||
if (!redoing) {
|
||||
if (read_batch)
|
||||
flist_ndx_push(&batch_redo_list, ndx);
|
||||
send_msg_int(MSG_REDO, ndx);
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
} else if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
break;
|
||||
}
|
||||
case -1:
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (make_backups < 0)
|
||||
make_backups = -make_backups;
|
||||
|
||||
if (phase == 2 && delay_updates) /* for protocol_version < 29 */
|
||||
handle_delayed_updates(local_name);
|
||||
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO,"recv_files finished\n");
|
||||
|
||||
return 0;
|
||||
}
|
38
rsync/rounding.c
Normal file
38
rsync/rounding.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* A pre-compilation helper program to aid in the creation of rounding.h.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#define ARRAY_LEN (EXTRA_ROUNDING+1)
|
||||
#define SIZEOF(x) ((long int)sizeof (x))
|
||||
|
||||
struct test {
|
||||
union file_extras extras[ARRAY_LEN];
|
||||
struct file_struct file;
|
||||
};
|
||||
|
||||
#define ACTUAL_SIZE SIZEOF(struct test)
|
||||
#define EXPECTED_SIZE (SIZEOF(union file_extras) * ARRAY_LEN + SIZEOF(struct file_struct))
|
||||
|
||||
int main(UNUSED(int argc), UNUSED(char *argv[]))
|
||||
{
|
||||
static int test_array[1 - 2 * (ACTUAL_SIZE != EXPECTED_SIZE)];
|
||||
test_array[0] = 0;
|
||||
return 0;
|
||||
}
|
46
rsync/rsync-3.1.1/.gitignore
vendored
Normal file
46
rsync/rsync-3.1.1/.gitignore
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
*.[oa]
|
||||
*~
|
||||
dummy
|
||||
ID
|
||||
Makefile
|
||||
Makefile.old
|
||||
configure.sh
|
||||
configure.sh.old
|
||||
config.cache
|
||||
config.h
|
||||
config.h.in
|
||||
config.h.in.old
|
||||
config.log
|
||||
config.status
|
||||
/proto.h
|
||||
/proto.h-tstamp
|
||||
/rsync.1
|
||||
/rsyncd.conf.5
|
||||
/autom4te*.cache
|
||||
/confdefs.h
|
||||
/conftest*
|
||||
/dox
|
||||
/getgroups
|
||||
/gmon.out
|
||||
/rsync
|
||||
/rsync-ssl
|
||||
/stunnel-rsync
|
||||
/stunnel-rsyncd.conf
|
||||
/shconfig
|
||||
/testdir
|
||||
/tests-dont-exist
|
||||
/testtmp
|
||||
/tls
|
||||
/testrun
|
||||
/trimslash
|
||||
/t_unsafe
|
||||
/wildtest
|
||||
/getfsdev
|
||||
/rounding.h
|
||||
/doc/rsync.pdf
|
||||
/doc/rsync.ps
|
||||
/support/savetransfer
|
||||
/testsuite/chown-fake.test
|
||||
/testsuite/devices-fake.test
|
||||
/testsuite/xattrs-hlink.test
|
||||
/patches
|
12
rsync/rsync-ssl.in
Executable file
12
rsync/rsync-ssl.in
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# This script supports using stunnel to secure an rsync daemon connection.
|
||||
# Note that this requires at least version 4.x of stunnel.
|
||||
case "$@" in
|
||||
*rsync://*) ;;
|
||||
*::*) ;;
|
||||
*)
|
||||
echo "You must use rsync-ssl with a daemon-style hostname." 0>&1
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exec @bindir@/rsync --rsh=@bindir@/stunnel-rsync "${@}"
|
747
rsync/rsync.c
Normal file
747
rsync/rsync.c
Normal file
@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Routines common to more than one of the rsync processes.
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
*
|
||||
* 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, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
#include <libcharset.h>
|
||||
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
extern int dry_run;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_executability;
|
||||
extern int preserve_times;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_sender;
|
||||
extern int am_receiver;
|
||||
extern int am_generator;
|
||||
extern int am_starting_up;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int got_kill_signal;
|
||||
extern int inc_recurse;
|
||||
extern int inplace;
|
||||
extern int flist_eof;
|
||||
extern int file_old_total;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern struct chmod_mode_struct *daemon_chmod_modes;
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
|
||||
#ifdef ICONV_CONST
|
||||
iconv_t ic_chck = (iconv_t)-1;
|
||||
# ifdef ICONV_OPTION
|
||||
iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
|
||||
# endif
|
||||
|
||||
static const char *default_charset(void)
|
||||
{
|
||||
# if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
return locale_charset();
|
||||
# elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
return nl_langinfo(CODESET);
|
||||
# else
|
||||
return ""; /* Works with (at the very least) gnu iconv... */
|
||||
# endif
|
||||
}
|
||||
|
||||
void setup_iconv(void)
|
||||
{
|
||||
const char *defset = default_charset();
|
||||
# ifdef ICONV_OPTION
|
||||
const char *charset;
|
||||
char *cp;
|
||||
# endif
|
||||
|
||||
if (!am_server && !allow_8bit_chars) {
|
||||
/* It's OK if this fails... */
|
||||
ic_chck = iconv_open(defset, defset);
|
||||
|
||||
if (DEBUG_GTE(ICONV, 2)) {
|
||||
if (ic_chck == (iconv_t)-1) {
|
||||
rprintf(FINFO,
|
||||
"msg checking via isprint()"
|
||||
" (iconv_open(\"%s\", \"%s\") errno: %d)\n",
|
||||
defset, defset, errno);
|
||||
} else {
|
||||
rprintf(FINFO,
|
||||
"msg checking charset: %s\n",
|
||||
defset);
|
||||
}
|
||||
}
|
||||
} else
|
||||
ic_chck = (iconv_t)-1;
|
||||
|
||||
# ifdef ICONV_OPTION
|
||||
if (!iconv_opt)
|
||||
return;
|
||||
|
||||
if ((cp = strchr(iconv_opt, ',')) != NULL) {
|
||||
if (am_server) /* A local transfer needs this. */
|
||||
iconv_opt = cp + 1;
|
||||
else
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if (!*iconv_opt || (*iconv_opt == '.' && iconv_opt[1] == '\0'))
|
||||
charset = defset;
|
||||
else
|
||||
charset = iconv_opt;
|
||||
|
||||
if ((ic_send = iconv_open(UTF8_CHARSET, charset)) == (iconv_t)-1) {
|
||||
rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n",
|
||||
UTF8_CHARSET, charset);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if ((ic_recv = iconv_open(charset, UTF8_CHARSET)) == (iconv_t)-1) {
|
||||
rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n",
|
||||
charset, UTF8_CHARSET);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(ICONV, 1)) {
|
||||
rprintf(FINFO, "[%s] charset: %s\n",
|
||||
who_am_i(), *charset ? charset : "[LOCALE]");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
/* This function converts the chars in the "in" xbuf into characters in the
|
||||
* "out" xbuf. The ".len" chars of the "in" xbuf is used starting from its
|
||||
* ".pos". The ".size" of the "out" xbuf restricts how many characters can
|
||||
* be stored, starting at its ".pos+.len" position. Note that the last byte
|
||||
* of the "out" xbuf is not used, which reserves space for a trailing '\0'
|
||||
* (though it is up to the caller to store a trailing '\0', as needed).
|
||||
*
|
||||
* We return a 0 on success or a -1 on error. An error also sets errno to
|
||||
* E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0.
|
||||
* The "in" xbuf is altered to update ".pos" and ".len". The "out" xbuf has
|
||||
* data appended, and its ".len" incremented (see below for a ".size" note).
|
||||
*
|
||||
* If ICB_CIRCULAR_OUT is set in "flags", the chars going into the "out" xbuf
|
||||
* can wrap around to the start, and the xbuf may have its ".size" reduced
|
||||
* (presumably by 1 byte) if the iconv code doesn't have space to store a
|
||||
* multi-byte character at the physical end of the ".buf" (though no reducing
|
||||
* happens if ".pos" is <= 1, since there is no room to wrap around).
|
||||
*
|
||||
* If ICB_EXPAND_OUT is set in "flags", the "out" xbuf will be allocated if
|
||||
* empty, and (as long as ICB_CIRCULAR_OUT is not set) expanded if too small.
|
||||
* This prevents the return of E2BIG (except for a circular xbuf).
|
||||
*
|
||||
* If ICB_INCLUDE_BAD is set in "flags", any badly-encoded chars are included
|
||||
* verbatim in the "out" xbuf, so EILSEQ will not be returned.
|
||||
*
|
||||
* If ICB_INCLUDE_INCOMPLETE is set in "flags", any incomplete multi-byte
|
||||
* chars are included, which ensures that EINVAL is not returned.
|
||||
*
|
||||
* If ICB_INIT is set, the iconv() conversion state is initialized prior to
|
||||
* processing the characters. */
|
||||
int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
|
||||
{
|
||||
ICONV_CONST char *ibuf;
|
||||
size_t icnt, ocnt, opos;
|
||||
char *obuf;
|
||||
|
||||
if (!out->size && flags & ICB_EXPAND_OUT) {
|
||||
size_t siz = ROUND_UP_1024(in->len * 2);
|
||||
alloc_xbuf(out, siz);
|
||||
} else if (out->len+1 >= out->size) {
|
||||
/* There is no room to even start storing data. */
|
||||
if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
realloc_xbuf(out, out->size + ROUND_UP_1024(in->len * 2));
|
||||
}
|
||||
|
||||
if (flags & ICB_INIT)
|
||||
iconv(ic, NULL, 0, NULL, 0);
|
||||
|
||||
ibuf = in->buf + in->pos;
|
||||
icnt = in->len;
|
||||
|
||||
opos = out->pos + out->len;
|
||||
if (flags & ICB_CIRCULAR_OUT) {
|
||||
if (opos >= out->size) {
|
||||
opos -= out->size;
|
||||
/* We know that out->pos is not 0 due to the "no room" check
|
||||
* above, so this can't go "negative". */
|
||||
ocnt = out->pos - opos - 1;
|
||||
} else {
|
||||
/* Allow the use of all bytes to the physical end of the buffer
|
||||
* unless pos is 0, in which case we reserve our trailing '\0'. */
|
||||
ocnt = out->size - opos - (out->pos ? 0 : 1);
|
||||
}
|
||||
} else
|
||||
ocnt = out->size - opos - 1;
|
||||
obuf = out->buf + opos;
|
||||
|
||||
while (icnt) {
|
||||
while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EINVAL) {
|
||||
if (!(flags & ICB_INCLUDE_INCOMPLETE))
|
||||
goto finish;
|
||||
if (!ocnt)
|
||||
goto e2big;
|
||||
} else if (errno == EILSEQ) {
|
||||
if (!(flags & ICB_INCLUDE_BAD))
|
||||
goto finish;
|
||||
if (!ocnt)
|
||||
goto e2big;
|
||||
} else if (errno == E2BIG) {
|
||||
size_t siz;
|
||||
e2big:
|
||||
opos = obuf - out->buf;
|
||||
if (flags & ICB_CIRCULAR_OUT && out->pos > 1 && opos > out->pos) {
|
||||
/* We are in a divided circular buffer at the physical
|
||||
* end with room to wrap to the start. If iconv() refused
|
||||
* to use one or more trailing bytes in the buffer, we
|
||||
* set the size to ignore the unused bytes. */
|
||||
if (opos < out->size)
|
||||
reduce_iobuf_size(out, opos);
|
||||
obuf = out->buf;
|
||||
ocnt = out->pos - 1;
|
||||
continue;
|
||||
}
|
||||
if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) {
|
||||
errno = E2BIG;
|
||||
goto finish;
|
||||
}
|
||||
siz = ROUND_UP_1024(in->len * 2);
|
||||
realloc_xbuf(out, out->size + siz);
|
||||
obuf = out->buf + opos;
|
||||
ocnt += siz;
|
||||
continue;
|
||||
} else {
|
||||
rsyserr(FERROR, errno, "unexpected error from iconv()");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
*obuf++ = *ibuf++;
|
||||
ocnt--, icnt--;
|
||||
if (!icnt)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
finish:
|
||||
opos = obuf - out->buf;
|
||||
if (flags & ICB_CIRCULAR_OUT && opos < out->pos)
|
||||
opos += out->size;
|
||||
out->len = opos - out->pos;
|
||||
|
||||
in->len = icnt;
|
||||
in->pos = ibuf - in->buf;
|
||||
|
||||
return errno ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void send_protected_args(int fd, char *args[])
|
||||
{
|
||||
int i;
|
||||
#ifdef ICONV_OPTION
|
||||
int convert = ic_send != (iconv_t)-1;
|
||||
xbuf outbuf, inbuf;
|
||||
|
||||
if (convert)
|
||||
alloc_xbuf(&outbuf, 1024);
|
||||
#endif
|
||||
|
||||
for (i = 0; args[i]; i++) {} /* find first NULL */
|
||||
args[i] = "rsync"; /* set a new arg0 */
|
||||
if (DEBUG_GTE(CMD, 1))
|
||||
print_child_argv("protected args:", args + i + 1);
|
||||
do {
|
||||
if (!args[i][0])
|
||||
write_buf(fd, ".", 2);
|
||||
#ifdef ICONV_OPTION
|
||||
else if (convert) {
|
||||
INIT_XBUF_STRLEN(inbuf, args[i]);
|
||||
iconvbufs(ic_send, &inbuf, &outbuf,
|
||||
ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_INIT);
|
||||
outbuf.buf[outbuf.len] = '\0';
|
||||
write_buf(fd, outbuf.buf, outbuf.len + 1);
|
||||
outbuf.len = 0;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
write_buf(fd, args[i], strlen(args[i]) + 1);
|
||||
} while (args[++i]);
|
||||
write_byte(fd, 0);
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert)
|
||||
free(outbuf.buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
|
||||
char *buf, int *len_ptr)
|
||||
{
|
||||
int len, iflags = 0;
|
||||
struct file_list *flist;
|
||||
uchar fnamecmp_type = FNAMECMP_FNAME;
|
||||
int ndx;
|
||||
|
||||
read_loop:
|
||||
while (1) {
|
||||
ndx = read_ndx(f_in);
|
||||
|
||||
if (ndx >= 0)
|
||||
break;
|
||||
if (ndx == NDX_DONE)
|
||||
return ndx;
|
||||
if (ndx == NDX_DEL_STATS) {
|
||||
read_del_stats(f_in);
|
||||
if (am_sender && am_server)
|
||||
write_del_stats(f_out);
|
||||
continue;
|
||||
}
|
||||
if (!inc_recurse || am_sender) {
|
||||
int last;
|
||||
if (first_flist)
|
||||
last = first_flist->prev->ndx_start + first_flist->prev->used - 1;
|
||||
else
|
||||
last = -1;
|
||||
rprintf(FERROR,
|
||||
"Invalid file index: %d (%d - %d) [%s]\n",
|
||||
ndx, NDX_DONE, last, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (ndx == NDX_FLIST_EOF) {
|
||||
flist_eof = 1;
|
||||
if (DEBUG_GTE(FLIST, 3))
|
||||
rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
|
||||
write_int(f_out, NDX_FLIST_EOF);
|
||||
continue;
|
||||
}
|
||||
ndx = NDX_FLIST_OFFSET - ndx;
|
||||
if (ndx < 0 || ndx >= dir_flist->used) {
|
||||
ndx = NDX_FLIST_OFFSET - ndx;
|
||||
rprintf(FERROR,
|
||||
"Invalid dir index: %d (%d - %d) [%s]\n",
|
||||
ndx, NDX_FLIST_OFFSET,
|
||||
NDX_FLIST_OFFSET - dir_flist->used + 1,
|
||||
who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(FLIST, 2)) {
|
||||
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
|
||||
who_am_i(), ndx);
|
||||
}
|
||||
/* Send all the data we read for this flist to the generator. */
|
||||
start_flist_forward(ndx);
|
||||
flist = recv_file_list(f_in);
|
||||
flist->parent_ndx = ndx;
|
||||
stop_flist_forward();
|
||||
}
|
||||
|
||||
iflags = protocol_version >= 29 ? read_shortint(f_in)
|
||||
: ITEM_TRANSFER | ITEM_MISSING_DATA;
|
||||
|
||||
/* Support the protocol-29 keep-alive style. */
|
||||
if (protocol_version < 30 && ndx == cur_flist->used && iflags == ITEM_IS_NEW) {
|
||||
if (am_sender)
|
||||
maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH);
|
||||
goto read_loop;
|
||||
}
|
||||
|
||||
flist = flist_for_ndx(ndx, "read_ndx_and_attrs");
|
||||
if (flist != cur_flist) {
|
||||
cur_flist = flist;
|
||||
if (am_sender) {
|
||||
file_old_total = cur_flist->used;
|
||||
for (flist = first_flist; flist != cur_flist; flist = flist->next)
|
||||
file_old_total += flist->used;
|
||||
}
|
||||
}
|
||||
|
||||
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
|
||||
fnamecmp_type = read_byte(f_in);
|
||||
*type_ptr = fnamecmp_type;
|
||||
|
||||
if (iflags & ITEM_XNAME_FOLLOWS) {
|
||||
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else {
|
||||
*buf = '\0';
|
||||
len = -1;
|
||||
}
|
||||
*len_ptr = len;
|
||||
|
||||
if (iflags & ITEM_TRANSFER) {
|
||||
int i = ndx - cur_flist->ndx_start;
|
||||
if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) {
|
||||
rprintf(FERROR,
|
||||
"received request to transfer non-regular file: %d [%s]\n",
|
||||
ndx, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
*iflag_ptr = iflags;
|
||||
return ndx;
|
||||
}
|
||||
|
||||
/*
|
||||
free a sums struct
|
||||
*/
|
||||
void free_sums(struct sum_struct *s)
|
||||
{
|
||||
if (s->sums) free(s->sums);
|
||||
free(s);
|
||||
}
|
||||
|
||||
/* This is only called when we aren't preserving permissions. Figure out what
|
||||
* the permissions should be and return them merged back into the mode. */
|
||||
mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
|
||||
int exists)
|
||||
{
|
||||
int new_mode;
|
||||
/* If the file already exists, we'll return the local permissions,
|
||||
* possibly tweaked by the --executability option. */
|
||||
if (exists) {
|
||||
new_mode = (flist_mode & ~CHMOD_BITS) | (stat_mode & CHMOD_BITS);
|
||||
if (preserve_executability && S_ISREG(flist_mode)) {
|
||||
/* If the source file is executable, grant execute
|
||||
* rights to everyone who can read, but ONLY if the
|
||||
* file isn't already executable. */
|
||||
if (!(flist_mode & 0111))
|
||||
new_mode &= ~0111;
|
||||
else if (!(stat_mode & 0111))
|
||||
new_mode |= (new_mode & 0444) >> 2;
|
||||
}
|
||||
} else {
|
||||
/* Apply destination default permissions and turn
|
||||
* off special permissions. */
|
||||
new_mode = flist_mode & (~CHMOD_BITS | dflt_perms);
|
||||
}
|
||||
return new_mode;
|
||||
}
|
||||
|
||||
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
const char *fnamecmp, int flags)
|
||||
{
|
||||
int updated = 0;
|
||||
stat_x sx2;
|
||||
int change_uid, change_gid;
|
||||
mode_t new_mode = file->mode;
|
||||
int inherit;
|
||||
|
||||
if (!sxp) {
|
||||
if (dry_run)
|
||||
return 1;
|
||||
if (link_stat(fname, &sx2.st, 0) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
init_stat_x(&sx2);
|
||||
sxp = &sx2;
|
||||
inherit = !preserve_perms;
|
||||
} else
|
||||
inherit = !preserve_perms && file->flags & FLAG_DIR_CREATED;
|
||||
|
||||
if (inherit && S_ISDIR(new_mode) && sxp->st.st_mode & S_ISGID) {
|
||||
/* We just created this directory and its setgid
|
||||
* bit is on, so make sure it stays on. */
|
||||
new_mode |= S_ISGID;
|
||||
}
|
||||
|
||||
if (daemon_chmod_modes && !S_ISLNK(new_mode))
|
||||
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
|
||||
get_acl(fname, sxp);
|
||||
#endif
|
||||
|
||||
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
|
||||
change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
|
||||
&& sxp->st.st_gid != (gid_t)F_GROUP(file);
|
||||
#ifndef CAN_CHOWN_SYMLINK
|
||||
if (S_ISLNK(sxp->st.st_mode)) {
|
||||
;
|
||||
} else
|
||||
#endif
|
||||
if (change_uid || change_gid) {
|
||||
if (DEBUG_GTE(OWN, 1)) {
|
||||
if (change_uid) {
|
||||
rprintf(FINFO,
|
||||
"set uid of %s from %u to %u\n",
|
||||
fname, (unsigned)sxp->st.st_uid, F_OWNER(file));
|
||||
}
|
||||
if (change_gid) {
|
||||
rprintf(FINFO,
|
||||
"set gid of %s from %u to %u\n",
|
||||
fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
|
||||
}
|
||||
}
|
||||
if (am_root >= 0) {
|
||||
uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid;
|
||||
gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid;
|
||||
if (do_lchown(fname, uid, gid) != 0) {
|
||||
/* We shouldn't have attempted to change uid
|
||||
* or gid unless have the privilege. */
|
||||
rsyserr(FERROR_XFER, errno, "%s %s failed",
|
||||
change_uid ? "chown" : "chgrp",
|
||||
full_fname(fname));
|
||||
goto cleanup;
|
||||
}
|
||||
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
|
||||
rprintf(FERROR_XFER, "uid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
|
||||
if (gid == (gid_t)-1 && sxp->st.st_gid != (gid_t)-1)
|
||||
rprintf(FERROR_XFER, "gid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
|
||||
/* A lchown had been done, so we need to re-stat if
|
||||
* the destination had the setuid or setgid bits set
|
||||
* (due to the side effect of the chown call). */
|
||||
if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
|
||||
link_stat(fname, &sxp->st,
|
||||
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
|
||||
}
|
||||
}
|
||||
updated = 1;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (am_root < 0)
|
||||
set_stat_xattr(fname, file, new_mode);
|
||||
if (preserve_xattrs && fnamecmp)
|
||||
set_xattr(fname, file, fnamecmp, sxp);
|
||||
#endif
|
||||
|
||||
if (!preserve_times
|
||||
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|
||||
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
|
||||
flags |= ATTRS_SKIP_MTIME;
|
||||
if (!(flags & ATTRS_SKIP_MTIME)
|
||||
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
|
||||
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "failed to set times on %s",
|
||||
full_fname(fname));
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
else
|
||||
file->flags |= FLAG_TIME_FAILED;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
/* It's OK to call set_acl() now, even for a dir, as the generator
|
||||
* will enable owner-writability using chmod, if necessary.
|
||||
*
|
||||
* If set_acl() changes permission bits in the process of setting
|
||||
* an access ACL, it changes sxp->st.st_mode so we know whether we
|
||||
* need to chmod(). */
|
||||
if (preserve_acls && !S_ISLNK(new_mode)) {
|
||||
if (set_acl(fname, file, sxp, new_mode) > 0)
|
||||
updated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHMOD
|
||||
if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
|
||||
int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"failed to set permissions on %s",
|
||||
full_fname(fname));
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) {
|
||||
if (updated)
|
||||
rprintf(FCLIENT, "%s\n", fname);
|
||||
else
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
}
|
||||
cleanup:
|
||||
if (sxp == &sx2)
|
||||
free_stat_x(&sx2);
|
||||
return updated;
|
||||
}
|
||||
|
||||
/* This is only called for SIGINT, SIGHUP, and SIGTERM. */
|
||||
RETSIGTYPE sig_int(int sig_num)
|
||||
{
|
||||
/* KLUGE: if the user hits Ctrl-C while ssh is prompting
|
||||
* for a password, then our cleanup's sending of a SIGUSR1
|
||||
* signal to all our children may kill ssh before it has a
|
||||
* chance to restore the tty settings (i.e. turn echo back
|
||||
* on). By sleeping for a short time, ssh gets a bigger
|
||||
* chance to do the right thing. If child processes are
|
||||
* not ssh waiting for a password, then this tiny delay
|
||||
* shouldn't hurt anything. */
|
||||
msleep(400);
|
||||
|
||||
/* If we're an rsync daemon listener (not a daemon server),
|
||||
* we'll exit with status 0 if we received SIGTERM. */
|
||||
if (am_daemon && !am_server && sig_num == SIGTERM)
|
||||
exit_cleanup(0);
|
||||
|
||||
/* If the signal arrived on the server side (or for the receiver
|
||||
* process on the client), we want to try to do a controlled shutdown
|
||||
* that lets the client side (generator process) know what happened.
|
||||
* To do this, we set a flag and let the normal process handle the
|
||||
* shutdown. We only attempt this if multiplexed IO is in effect and
|
||||
* we didn't already set the flag. */
|
||||
if (!got_kill_signal && (am_server || am_receiver)) {
|
||||
got_kill_signal = sig_num;
|
||||
return;
|
||||
}
|
||||
|
||||
exit_cleanup(RERR_SIGNAL);
|
||||
}
|
||||
|
||||
/* Finish off a file transfer: renaming the file and setting the file's
|
||||
* attributes (e.g. permissions, ownership, etc.). If the robust_rename()
|
||||
* call is forced to copy the temp file and partialptr is both non-NULL and
|
||||
* not an absolute path, we stage the file into the partial-dir and then
|
||||
* rename it into place. This returns 1 on succcess or 0 on failure. */
|
||||
int finish_transfer(const char *fname, const char *fnametmp,
|
||||
const char *fnamecmp, const char *partialptr,
|
||||
struct file_struct *file, int ok_to_set_time,
|
||||
int overwriting_basis)
|
||||
{
|
||||
int ret;
|
||||
const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL;
|
||||
|
||||
if (inplace) {
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "finishing %s\n", fname);
|
||||
fnametmp = fname;
|
||||
goto do_set_file_attrs;
|
||||
}
|
||||
|
||||
if (make_backups > 0 && overwriting_basis) {
|
||||
int ok = make_backup(fname, False);
|
||||
if (!ok)
|
||||
return 1;
|
||||
if (ok == 1 && fnamecmp == fname)
|
||||
fnamecmp = get_backup_name(fname);
|
||||
}
|
||||
|
||||
/* Change permissions before putting the file into place. */
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
|
||||
/* move tmp file over real file */
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
|
||||
ret = robust_rename(fnametmp, fname, temp_copy_name, file->mode);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "%s %s -> \"%s\"",
|
||||
ret == -2 ? "copy" : "rename",
|
||||
full_fname(fnametmp), fname);
|
||||
if (!partialptr || (ret == -2 && temp_copy_name)
|
||||
|| robust_rename(fnametmp, partialptr, NULL, file->mode) < 0)
|
||||
do_unlink(fnametmp);
|
||||
return 0;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* The file was moved into place (not copied), so it's done. */
|
||||
return 1;
|
||||
}
|
||||
/* The file was copied, so tweak the perms of the copied file. If it
|
||||
* was copied to partialptr, move it into its final destination. */
|
||||
fnametmp = temp_copy_name ? temp_copy_name : fname;
|
||||
|
||||
do_set_file_attrs:
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
|
||||
if (temp_copy_name) {
|
||||
if (do_rename(fnametmp, fname) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\"",
|
||||
full_fname(fnametmp), fname);
|
||||
return 0;
|
||||
}
|
||||
handle_partial_dir(temp_copy_name, PDIR_DELETE);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct file_list *flist_for_ndx(int ndx, const char *fatal_error_loc)
|
||||
{
|
||||
struct file_list *flist = cur_flist;
|
||||
|
||||
if (!flist && !(flist = first_flist))
|
||||
goto not_found;
|
||||
|
||||
while (ndx < flist->ndx_start-1) {
|
||||
if (flist == first_flist)
|
||||
goto not_found;
|
||||
flist = flist->prev;
|
||||
}
|
||||
while (ndx >= flist->ndx_start + flist->used) {
|
||||
if (!(flist = flist->next))
|
||||
goto not_found;
|
||||
}
|
||||
return flist;
|
||||
|
||||
not_found:
|
||||
if (fatal_error_loc) {
|
||||
int first, last;
|
||||
if (first_flist) {
|
||||
first = first_flist->ndx_start - 1;
|
||||
last = first_flist->prev->ndx_start + first_flist->prev->used - 1;
|
||||
} else {
|
||||
first = 0;
|
||||
last = -1;
|
||||
}
|
||||
rprintf(FERROR,
|
||||
"File-list index %d not in %d - %d (%s) [%s]\n",
|
||||
ndx, first, last, fatal_error_loc, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
{
|
||||
if (am_starting_up)
|
||||
return am_server ? "server" : "client";
|
||||
return am_sender ? "sender"
|
||||
: am_generator ? "generator"
|
||||
: am_receiver ? "receiver"
|
||||
: "Receiver"; /* pre-forked receiver */
|
||||
}
|
1294
rsync/rsync.h
Normal file
1294
rsync/rsync.h
Normal file
File diff suppressed because it is too large
Load Diff
469
rsync/rsync3.txt
Normal file
469
rsync/rsync3.txt
Normal file
@ -0,0 +1,469 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
Notes towards a new version of rsync
|
||||
Martin Pool <mbp@samba.org>, September 2001.
|
||||
|
||||
|
||||
Good things about the current implementation:
|
||||
|
||||
- Widely known and adopted.
|
||||
|
||||
- Fast/efficient, especially for moderately small sets of files over
|
||||
slow links (transoceanic or modem.)
|
||||
|
||||
- Fairly reliable.
|
||||
|
||||
- The choice of running over a plain TCP socket or tunneling over
|
||||
ssh.
|
||||
|
||||
- rsync operations are idempotent: you can always run the same
|
||||
command twice to make sure it worked properly without any fear.
|
||||
(Are there any exceptions?)
|
||||
|
||||
- Small changes to files cause small deltas.
|
||||
|
||||
- There is a way to evolve the protocol to some extent.
|
||||
|
||||
- rdiff and rsync --write-batch allow generation of standalone patch
|
||||
sets. rsync+ is pretty cheesy, though. xdelta seems cleaner.
|
||||
|
||||
- Process triangle is creative, but seems to provoke OS bugs.
|
||||
|
||||
- "Morning-after property": you don't need to know anything on the
|
||||
local machine about the state of the remote machine, or about
|
||||
transfers that have been done in the past.
|
||||
|
||||
- You can easily push or pull simply by switching the order of
|
||||
files.
|
||||
|
||||
- The "modules" system has some neat features compared to
|
||||
e.g. Apache's per-directory configuration. In particular, because
|
||||
you can set a userid and chroot directory, there is strong
|
||||
protection between different modules. I haven't seen any calls
|
||||
for a more flexible system.
|
||||
|
||||
|
||||
Bad things about the current implementation:
|
||||
|
||||
- Persistent and hard-to-diagnose hang bugs remain
|
||||
|
||||
- Protocol is sketchily documented, tied to this implementation, and
|
||||
hard to modify/extend
|
||||
|
||||
- Both the program and the protocol assume a single non-interactive
|
||||
one-way transfer
|
||||
|
||||
- A list of all files are held in memory for the entire transfer,
|
||||
which cripples scalability to large file trees
|
||||
|
||||
- Opening a new socket for every operation causes problems,
|
||||
especially when running over SSH with password authentication.
|
||||
|
||||
- Renamed files are not handled: the old file is removed, and the
|
||||
new file created from scratch.
|
||||
|
||||
- The versioning approach assumes that future versions of the
|
||||
program know about all previous versions, and will do the right
|
||||
thing.
|
||||
|
||||
- People always get confused about ':' vs '::'
|
||||
|
||||
- Error messages can be cryptic.
|
||||
|
||||
- Default behaviour is not intuitive: in too many cases rsync will
|
||||
happily do nothing. Perhaps -a should be the default?
|
||||
|
||||
- People get confused by trailing slashes, though it's hard to think
|
||||
of another reasonable way to make this necessary distinction
|
||||
between a directory and its contents.
|
||||
|
||||
|
||||
Protocol philosophy:
|
||||
|
||||
*The* big difference between protocols like HTTP, FTP, and NFS is
|
||||
that their fundamental operations are "read this file", "delete
|
||||
this file", and "make this directory", whereas rsync is "make this
|
||||
directory like this one".
|
||||
|
||||
|
||||
Questionable features:
|
||||
|
||||
These are neat, but not necessarily clean or worth preserving.
|
||||
|
||||
- The remote rsync can be wrapped by some other program, such as in
|
||||
tridge's rsync-mail scripts. The general feature of sending and
|
||||
retrieving mail over rsync is good, but this is perhaps not the
|
||||
right way to implement it.
|
||||
|
||||
|
||||
Desirable features:
|
||||
|
||||
These don't really require architectural changes; they're just
|
||||
something to keep in mind.
|
||||
|
||||
- Synchronize ACLs and extended attributes
|
||||
|
||||
- Anonymous servers should be efficient
|
||||
|
||||
- Code should be portable to non-UNIX systems
|
||||
|
||||
- Should be possible to document the protocol in RFC form
|
||||
|
||||
- --dry-run option
|
||||
|
||||
- IPv6 support. Pretty straightforward.
|
||||
|
||||
- Allow the basis and destination files to be different. For
|
||||
example, you could use this when you have a CD-ROM and want to
|
||||
download an updated image onto a hard drive.
|
||||
|
||||
- Efficiently interrupt and restart a transfer. We can write a
|
||||
checkpoint file that says where we're up to in the filesystem.
|
||||
Alternatively, as long as transfers are idempotent, we can just
|
||||
restart the whole thing. [NFSv4]
|
||||
|
||||
- Scripting support.
|
||||
|
||||
- Propagate atimes and do not modify them. This is very ugly on
|
||||
Unix. It might be better to try to add O_NOATIME to kernels, and
|
||||
call that.
|
||||
|
||||
- Unicode. Probably just use UTF-8 for everything.
|
||||
|
||||
- Open authentication system. Can we use PAM? Is SASL an adequate
|
||||
mapping of PAM to the network, or useful in some other way?
|
||||
|
||||
- Resume interrupted transfers without the --partial flag. We need
|
||||
to leave the temporary file behind, and then know to use it. This
|
||||
leaves a risk of large temporary files accumulating, which is not
|
||||
good. Perhaps it should be off by default.
|
||||
|
||||
- tcpwrappers support. Should be trivial; can already be done
|
||||
through tcpd or inetd.
|
||||
|
||||
- Socks support built in. It's not clear this is any better than
|
||||
just linking against the socks library, though.
|
||||
|
||||
- When run over SSH, invoke with predictable command-line arguments,
|
||||
so that people can restrict what commands sshd will run. (Is this
|
||||
really required?)
|
||||
|
||||
- Comparison mode: give a list of which files are new, gone, or
|
||||
different. Set return code depending on whether anything has
|
||||
changed.
|
||||
|
||||
- Internationalized messages (gettext?)
|
||||
|
||||
- Optionally use real regexps rather than globs?
|
||||
|
||||
- Show overall progress. Pretty hard to do, especially if we insist
|
||||
on not scanning the directory tree up front.
|
||||
|
||||
|
||||
Regression testing:
|
||||
|
||||
- Support automatic testing.
|
||||
|
||||
- Have hard internal timeouts against hangs.
|
||||
|
||||
- Be deterministic.
|
||||
|
||||
- Measure performance.
|
||||
|
||||
|
||||
Hard links:
|
||||
|
||||
At the moment, we can recreate hard links, but it's a bit
|
||||
inefficient: it depends on holding a list of all files in the tree.
|
||||
Every time we see a file with a linkcount >1, we need to search for
|
||||
another known name that has the same (fsid,inum) tuple. We could do
|
||||
that more efficiently by keeping a list of only files with
|
||||
linkcount>1, and removing files from that list as all their names
|
||||
become known.
|
||||
|
||||
|
||||
Command-line options:
|
||||
|
||||
We have rather a lot at the moment. We might get more if the tool
|
||||
becomes more flexible. Do we need a .rc or configuration file?
|
||||
That wouldn't really fit with its pattern of use: cp and tar don't
|
||||
have them, though ssh does.
|
||||
|
||||
|
||||
Scripting issues:
|
||||
|
||||
- Perhaps support multiple scripting languages: candidates include
|
||||
Perl, Python, Tcl, Scheme (guile?), sh, ...
|
||||
|
||||
- Simply running a subprocess and looking at its stdout/exit code
|
||||
might be sufficient, though it could also be pretty slow if it's
|
||||
called often.
|
||||
|
||||
- There are security issues about running remote code, at least if
|
||||
it's not running in the users own account. So we can either
|
||||
disallow it, or use some kind of sandbox system.
|
||||
|
||||
- Python is a good language, but the syntax is not so good for
|
||||
giving small fragments on the command line.
|
||||
|
||||
- Tcl is broken Lisp.
|
||||
|
||||
- Lots of sysadmins know Perl, though Perl can give some bizarre or
|
||||
confusing errors. The built in stat operators and regexps might
|
||||
be useful.
|
||||
|
||||
- Sadly probably not enough people know Scheme.
|
||||
|
||||
- sh is hard to embed.
|
||||
|
||||
|
||||
Scripting hooks:
|
||||
|
||||
- Whether to transfer a file
|
||||
|
||||
- What basis file to use
|
||||
|
||||
- Logging
|
||||
|
||||
- Whether to allow transfers (for public servers)
|
||||
|
||||
- Authentication
|
||||
|
||||
- Locking
|
||||
|
||||
- Cache
|
||||
|
||||
- Generating backup path/name.
|
||||
|
||||
- Post-processing of backups, e.g. to do compression.
|
||||
|
||||
- After transfer, before replacement: so that we can spit out a diff
|
||||
of what was changed, or kick off some kind of reconciliation
|
||||
process.
|
||||
|
||||
|
||||
VFS:
|
||||
|
||||
Rather than talking straight to the filesystem, rsyncd talks through
|
||||
an internal API. Samba has one. Is it useful?
|
||||
|
||||
- Could be a tidy way to implement cached signatures.
|
||||
|
||||
- Keep files compressed on disk?
|
||||
|
||||
|
||||
Interactive interface:
|
||||
|
||||
- Something like ncFTP, or integration into GNOME-vfs. Probably
|
||||
hold a single socket connection open.
|
||||
|
||||
- Can either call us as a separate process, or as a library.
|
||||
|
||||
- The standalone process needs to produce output in a form easily
|
||||
digestible by a calling program, like the --emacs feature some
|
||||
have. Same goes for output: rpm outputs a series of hash symbols,
|
||||
which are easier for a GUI to handle than "\r30% complete"
|
||||
strings.
|
||||
|
||||
- Yow! emacs support. (You could probably build that already, of
|
||||
course.) I'd like to be able to write a simple script on a remote
|
||||
machine that rsyncs it to my workstation, edits it there, then
|
||||
pushes it back up.
|
||||
|
||||
|
||||
Pie-in-the-sky features:
|
||||
|
||||
These might have a severe impact on the protocol, and are not
|
||||
clearly in our core requirements. It looks like in many of them
|
||||
having scripting hooks will allow us
|
||||
|
||||
- Transport over UDP multicast. The hard part is handling multiple
|
||||
destinations which have different basis files. We can look at
|
||||
multicast-TFTP for inspiration.
|
||||
|
||||
- Conflict resolution. Possibly general scripting support will be
|
||||
sufficient.
|
||||
|
||||
- Integrate with locking. It's hard to see a good general solution,
|
||||
because Unix systems have several locking mechanisms, and grabbing
|
||||
the lock from programs that don't expect it could cause deadlocks,
|
||||
timeouts, or other problems. Scripting support might help.
|
||||
|
||||
- Replicate in place, rather than to a temporary file. This is
|
||||
dangerous in the case of interruption, and it also means that the
|
||||
delta can't refer to blocks that have already been overwritten.
|
||||
On the other hand we could semi-trivially do this at first by
|
||||
simply generating a delta with no copy instructions.
|
||||
|
||||
- Replicate block devices. Most of the difficulties here are to do
|
||||
with replication in place, though on some systems we will also
|
||||
have to do I/O on block boundaries.
|
||||
|
||||
- Peer to peer features. Flavour of the year. Can we think about
|
||||
ways for clients to smoothly and voluntarily become servers for
|
||||
content they receive?
|
||||
|
||||
- Imagine a situation where the destination has a much faster link
|
||||
to the cloud than the source. In this case, Mojo Nation downloads
|
||||
interleaved blocks from several slower servers. The general
|
||||
situation might be a way for a master rsync process to farm out
|
||||
tasks to several subjobs. In this particular case they'd need
|
||||
different sockets. This might be related to multicast.
|
||||
|
||||
|
||||
Unlikely features:
|
||||
|
||||
- Allow remote source and destination. If this can be cleanly
|
||||
designed into the protocol, perhaps with the remote machine acting
|
||||
as a kind of echo, then it's good. It's uncommon enough that we
|
||||
don't want to shape the whole protocol around it, though.
|
||||
|
||||
In fact, in a triangle of machines there are two possibilities:
|
||||
all traffic passes from remote1 to remote2 through local, or local
|
||||
just sets up the transfer and then remote1 talks to remote2. FTP
|
||||
supports the second but it's not clearly good. There are some
|
||||
security problems with being able to instruct one machine to open
|
||||
a connection to another.
|
||||
|
||||
|
||||
In favour of evolving the protocol:
|
||||
|
||||
- Keeping compatibility with existing rsync servers will help with
|
||||
adoption and testing.
|
||||
|
||||
- We should at the very least be able to fall back to the new
|
||||
protocol.
|
||||
|
||||
- Error handling is not so good.
|
||||
|
||||
|
||||
In favour of using a new protocol:
|
||||
|
||||
- Maintaining compatibility might soak up development time that
|
||||
would better go into improving a new protocol.
|
||||
|
||||
- If we start from scratch, it can be documented as we go, and we
|
||||
can avoid design decisions that make the protocol complex or
|
||||
implementation-bound.
|
||||
|
||||
|
||||
Error handling:
|
||||
|
||||
- Errors should come back reliably, and be clearly associated with
|
||||
the particular file that caused the problem.
|
||||
|
||||
- Some errors ought to cause the whole transfer to abort; some are
|
||||
just warnings. If any errors have occurred, then rsync ought to
|
||||
return an error.
|
||||
|
||||
|
||||
Concurrency:
|
||||
|
||||
- We want to keep the CPU, filesystem, and network as full as
|
||||
possible as much of the time as possible.
|
||||
|
||||
- We can do nonblocking network IO, but not so for disk.
|
||||
|
||||
- It makes sense to on the destination be generating signatures and
|
||||
applying patches at the same time.
|
||||
|
||||
- Can structure this with nonblocking, threads, separate processes,
|
||||
etc.
|
||||
|
||||
|
||||
Uses:
|
||||
|
||||
- Mirroring software distributions:
|
||||
|
||||
- Synchronizing laptop and desktop
|
||||
|
||||
- NFS filesystem migration/replication. See
|
||||
http://www.ietf.org/proceedings/00jul/00july-133.htm#P24510_1276764
|
||||
|
||||
- Sync with PDA
|
||||
|
||||
- Network backup systems
|
||||
|
||||
- CVS filemover
|
||||
|
||||
|
||||
Conflict resolution:
|
||||
|
||||
- Requires application-specific knowledge. We want to provide
|
||||
policy, rather than mechanism.
|
||||
|
||||
- Possibly allowing two-way migration across a single connection
|
||||
would be useful.
|
||||
|
||||
|
||||
Moved files: <http://rsync.samba.org/cgi-bin/rsync.fom?file=44>
|
||||
|
||||
- There's no trivial way to detect renamed files, especially if they
|
||||
move between directories.
|
||||
|
||||
- If we had a picture of the remote directory from last time on
|
||||
either machine, then the inode numbers might give us a hint about
|
||||
files which may have been renamed.
|
||||
|
||||
- Files that are renamed and not modified can be detected by
|
||||
examining the directory listing, looking for files with the same
|
||||
size/date as the origin.
|
||||
|
||||
|
||||
Filesystem migration:
|
||||
|
||||
NFSv4 probably wants to migrate file locks, but that's not really
|
||||
our problem.
|
||||
|
||||
|
||||
Atomic updates:
|
||||
|
||||
The NFSv4 working group wants atomic migration. Most of the
|
||||
responsibility for this lies on the NFS server or OS.
|
||||
|
||||
If migrating a whole tree, then we could do a nearly-atomic rename
|
||||
at the end. This ties in to having separate basis and destination
|
||||
files.
|
||||
|
||||
There's no way in Unix to replace a whole set of files atomically.
|
||||
However, if we get them all onto the destination machine and then do
|
||||
the updates quickly it would greatly reduce the window.
|
||||
|
||||
|
||||
Scalability:
|
||||
|
||||
We should aim to work well on machines in use in a year or two.
|
||||
That probably means transfers of many millions of files in one
|
||||
batch, and gigabytes or terabytes of data.
|
||||
|
||||
For argument's sake: at the low end, we want to sync ten files for a
|
||||
total of 10kb across a 1kB/s link. At the high end, we want to sync
|
||||
1e9 files for 1TB of data across a 1GB/s link.
|
||||
|
||||
On the whole CPU usage is not normally a limiting factor, if only
|
||||
because running over SSH burns a lot of cycles on encryption.
|
||||
|
||||
Perhaps have resource throttling without relying on rlimit.
|
||||
|
||||
|
||||
Streaming:
|
||||
|
||||
A big attraction of rsync is that there are few round-trip delays:
|
||||
basically only one to get started, and then everything is
|
||||
pipelined. This is a problem with FTP, and NFS (at least up to
|
||||
v3). NFSv4 can pipeline operations, but building on that is
|
||||
probably a bit complicated.
|
||||
|
||||
|
||||
Related work:
|
||||
|
||||
- mirror.pl http://freshmeat.net/project/mirror/
|
||||
|
||||
- ProFTPd
|
||||
|
||||
- Apache
|
||||
|
||||
- http://freshmeat.net/search/?site=Freshmeat&q=mirror§ion=projects
|
||||
|
||||
- BitTorrent -- p2p mirroring
|
||||
http://bitconjurer.org/BitTorrent/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user