The Samba-Bugzilla – Attachment 9713 Details for
Bug 9667
smbclient tar mode should use libarchive
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
v4-1-test rebase of libarchive smbclient tarmode changes in master
clitar_libarchive_41t.patch (text/plain), 146.34 KB, created by
David Disseldorp
on 2014-02-24 11:38:56 UTC
(
hide
)
Description:
v4-1-test rebase of libarchive smbclient tarmode changes in master
Filename:
MIME Type:
Creator:
David Disseldorp
Created:
2014-02-24 11:38:56 UTC
Size:
146.34 KB
patch
obsolete
>diff --git docs-xml/manpages/smbclient.1.xml docs-xml/manpages/smbclient.1.xml >index d531390..4bc9ecd 100644 >--- docs-xml/manpages/smbclient.1.xml >+++ docs-xml/manpages/smbclient.1.xml >@@ -80,171 +80,171 @@ > <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle> > <manvolnum>7</manvolnum></citerefentry> suite.</para> > >- <para><command>smbclient</command> is a client that can >+ <para><command>smbclient</command> is a client that can > 'talk' to an SMB/CIFS server. It offers an interface > similar to that of the ftp program (see <citerefentry><refentrytitle>ftp</refentrytitle> >- <manvolnum>1</manvolnum></citerefentry>). >- Operations include things like getting files from the server >- to the local machine, putting files from the local machine to >- the server, retrieving directory information from the server >+ <manvolnum>1</manvolnum></citerefentry>). >+ Operations include things like getting files from the server >+ to the local machine, putting files from the local machine to >+ the server, retrieving directory information from the server > and so on. </para> > </refsect1> > > > <refsect1> > <title>OPTIONS</title> >- >+ > <variablelist> > <varlistentry> > <term>servicename</term> >- <listitem><para>servicename is the name of the service >+ <listitem><para>servicename is the name of the service > you want to use on the server. A service name takes the form > <filename>//server/service</filename> where <parameter>server >- </parameter> is the NetBIOS name of the SMB/CIFS server >- offering the desired service and <parameter>service</parameter> >- is the name of the service offered. Thus to connect to >+ </parameter> is the NetBIOS name of the SMB/CIFS server >+ offering the desired service and <parameter>service</parameter> >+ is the name of the service offered. Thus to connect to > the service "printer" on the SMB/CIFS server "smbserver", > you would use the servicename <filename>//smbserver/printer > </filename></para> > >- <para>Note that the server name required is NOT necessarily >- the IP (DNS) host name of the server ! The name required is >+ <para>Note that the server name required is NOT necessarily >+ the IP (DNS) host name of the server ! The name required is > a NetBIOS server name, which may or may not be the > same as the IP hostname of the machine running the server. > </para> > >- <para>The server name is looked up according to either >- the <parameter>-R</parameter> parameter to <command>smbclient</command> or >- using the name resolve order parameter in >+ <para>The server name is looked up according to either >+ the <parameter>-R</parameter> parameter to <command>smbclient</command> or >+ using the name resolve order parameter in > the <citerefentry><refentrytitle>smb.conf</refentrytitle> >- <manvolnum>5</manvolnum></citerefentry> file, >- allowing an administrator to change the order and methods >+ <manvolnum>5</manvolnum></citerefentry> file, >+ allowing an administrator to change the order and methods > by which server names are looked up. </para></listitem> > </varlistentry> > > <varlistentry> > <term>password</term> >- <listitem><para>The password required to access the specified >- service on the specified server. If this parameter is >- supplied, the <parameter>-N</parameter> option (suppress >+ <listitem><para>The password required to access the specified >+ service on the specified server. If this parameter is >+ supplied, the <parameter>-N</parameter> option (suppress > password prompt) is assumed. </para> > >- <para>There is no default password. If no password is supplied >- on the command line (either by using this parameter or adding >- a password to the <parameter>-U</parameter> option (see >- below)) and the <parameter>-N</parameter> option is not >- specified, the client will prompt for a password, even if >- the desired service does not require one. (If no password is >+ <para>There is no default password. If no password is supplied >+ on the command line (either by using this parameter or adding >+ a password to the <parameter>-U</parameter> option (see >+ below)) and the <parameter>-N</parameter> option is not >+ specified, the client will prompt for a password, even if >+ the desired service does not require one. (If no password is > required, simply press ENTER to provide a null password.) > </para> > >- <para>Note: Some servers (including OS/2 and Windows for >- Workgroups) insist on an uppercase password. Lowercase >- or mixed case passwords may be rejected by these servers. >+ <para>Note: Some servers (including OS/2 and Windows for >+ Workgroups) insist on an uppercase password. Lowercase >+ or mixed case passwords may be rejected by these servers. > </para> > > <para>Be cautious about including passwords in scripts. > </para></listitem> > </varlistentry> >- >+ > <varlistentry> > <term>-R|--name-resolve <name resolve order></term> >- <listitem><para>This option is used by the programs in the Samba >- suite to determine what naming services and in what order to resolve >- host names to IP addresses. The option takes a space-separated >+ <listitem><para>This option is used by the programs in the Samba >+ suite to determine what naming services and in what order to resolve >+ host names to IP addresses. The option takes a space-separated > string of different name resolution options.</para> > >- <para>The options are :"lmhosts", "host", "wins" and "bcast". They >+ <para>The options are :"lmhosts", "host", "wins" and "bcast". They > cause names to be resolved as follows:</para> > > <itemizedlist> >- <listitem><para><constant>lmhosts</constant>: Lookup an IP >- address in the Samba lmhosts file. If the line in lmhosts has >- no name type attached to the NetBIOS name (see >+ <listitem><para><constant>lmhosts</constant>: Lookup an IP >+ address in the Samba lmhosts file. If the line in lmhosts has >+ no name type attached to the NetBIOS name (see > the <citerefentry><refentrytitle>lmhosts</refentrytitle> > <manvolnum>5</manvolnum></citerefentry> for details) then > any name type matches for lookup.</para> > </listitem> >- >- <listitem><para><constant>host</constant>: Do a standard host >+ >+ <listitem><para><constant>host</constant>: Do a standard host > name to IP address resolution, using the system <filename>/etc/hosts >- </filename>, NIS, or DNS lookups. This method of name resolution >- is operating system dependent, for instance on IRIX or Solaris this >- may be controlled by the <filename>/etc/nsswitch.conf</filename> >- file). Note that this method is only used if the NetBIOS name >- type being queried is the 0x20 (server) name type, otherwise >+ </filename>, NIS, or DNS lookups. This method of name resolution >+ is operating system dependent, for instance on IRIX or Solaris this >+ may be controlled by the <filename>/etc/nsswitch.conf</filename> >+ file). Note that this method is only used if the NetBIOS name >+ type being queried is the 0x20 (server) name type, otherwise > it is ignored.</para> > </listitem> >- >- <listitem><para><constant>wins</constant>: Query a name with >+ >+ <listitem><para><constant>wins</constant>: Query a name with > the IP address listed in the <parameter>wins server</parameter> >- parameter. If no WINS server has >+ parameter. If no WINS server has > been specified this method will be ignored.</para> > </listitem> >- >- <listitem><para><constant>bcast</constant>: Do a broadcast on >- each of the known local interfaces listed in the >+ >+ <listitem><para><constant>bcast</constant>: Do a broadcast on >+ each of the known local interfaces listed in the > <parameter>interfaces</parameter> >- parameter. This is the least reliable of the name resolution >- methods as it depends on the target host being on a locally >+ parameter. This is the least reliable of the name resolution >+ methods as it depends on the target host being on a locally > connected subnet.</para> > </listitem> > </itemizedlist> > >- <para>If this parameter is not set then the name resolve order >+ <para>If this parameter is not set then the name resolve order > defined in the <citerefentry><refentrytitle>smb.conf</refentrytitle> >- <manvolnum>5</manvolnum></citerefentry> file parameter >+ <manvolnum>5</manvolnum></citerefentry> file parameter > (name resolve order) will be used. </para> > >- <para>The default order is lmhosts, host, wins, bcast and without >+ <para>The default order is lmhosts, host, wins, bcast and without > this parameter or any entry in the <parameter>name resolve order > </parameter> parameter of the <citerefentry><refentrytitle>smb.conf</refentrytitle> > <manvolnum>5</manvolnum></citerefentry> file the name resolution > methods will be attempted in this order. </para></listitem> > </varlistentry> >- >- >+ >+ > <varlistentry> > <term>-M|--message NetBIOS name</term> >- <listitem><para>This options allows you to send messages, using >- the "WinPopup" protocol, to another computer. Once a connection is >- established you then type your message, pressing ^D (control-D) to >+ <listitem><para>This options allows you to send messages, using >+ the "WinPopup" protocol, to another computer. Once a connection is >+ established you then type your message, pressing ^D (control-D) to > end. </para> > >- <para>If the receiving computer is running WinPopup the user will >- receive the message and probably a beep. If they are not running >- WinPopup the message will be lost, and no error message will >+ <para>If the receiving computer is running WinPopup the user will >+ receive the message and probably a beep. If they are not running >+ WinPopup the message will be lost, and no error message will > occur. </para> > >- <para>The message is also automatically truncated if the message >- is over 1600 bytes, as this is the limit of the protocol. >+ <para>The message is also automatically truncated if the message >+ is over 1600 bytes, as this is the limit of the protocol. > </para> > > <para> >- One useful trick is to pipe the message through <command>smbclient</command>. >- For example: smbclient -M FRED < mymessage.txt will send the >- message in the file <filename>mymessage.txt</filename> to the >+ One useful trick is to pipe the message through <command>smbclient</command>. >+ For example: smbclient -M FRED < mymessage.txt will send the >+ message in the file <filename>mymessage.txt</filename> to the > machine FRED. > </para> > >- <para>You may also find the <parameter>-U</parameter> and >- <parameter>-I</parameter> options useful, as they allow you to >+ <para>You may also find the <parameter>-U</parameter> and >+ <parameter>-I</parameter> options useful, as they allow you to > control the FROM and TO parts of the message. </para> > > <para>See the <parameter>message command</parameter> parameter in the <citerefentry><refentrytitle>smb.conf</refentrytitle> >- <manvolnum>5</manvolnum></citerefentry> for a description of how to handle incoming >+ <manvolnum>5</manvolnum></citerefentry> for a description of how to handle incoming > WinPopup messages in Samba. </para> > >- <para><emphasis>Note</emphasis>: Copy WinPopup into the startup group >- on your WfWg PCs if you want them to always be able to receive >+ <para><emphasis>Note</emphasis>: Copy WinPopup into the startup group >+ on your WfWg PCs if you want them to always be able to receive > messages. </para></listitem> > </varlistentry> > > <varlistentry> > <term>-p|--port port</term> >- <listitem><para>This number is the TCP port number that will be used >+ <listitem><para>This number is the TCP port number that will be used > when making connections to the server. The standard (well-known) >- TCP port number for an SMB/CIFS server is 139, which is the >+ TCP port number for an SMB/CIFS server is 139, which is the > default. </para></listitem> > </varlistentry> > >@@ -281,40 +281,40 @@ > <listitem><para><replaceable>IP address</replaceable> is the address of the server to connect to. > It should be specified in standard "a.b.c.d" notation. </para> > >- <para>Normally the client would attempt to locate a named >- SMB/CIFS server by looking it up via the NetBIOS name resolution >- mechanism described above in the <parameter>name resolve order</parameter> >+ <para>Normally the client would attempt to locate a named >+ SMB/CIFS server by looking it up via the NetBIOS name resolution >+ mechanism described above in the <parameter>name resolve order</parameter> > parameter above. Using this parameter will force the client >- to assume that the server is on the machine with the specified IP >- address and the NetBIOS name component of the resource being >+ to assume that the server is on the machine with the specified IP >+ address and the NetBIOS name component of the resource being > connected to will be ignored. </para> > >- <para>There is no default for this parameter. If not supplied, >- it will be determined automatically by the client as described >+ <para>There is no default for this parameter. If not supplied, >+ it will be determined automatically by the client as described > above. </para></listitem> > </varlistentry> >- >+ > <varlistentry> > <term>-E|--stderr</term> >- <listitem><para>This parameter causes the client to write messages >- to the standard error stream (stderr) rather than to the standard >+ <listitem><para>This parameter causes the client to write messages >+ to the standard error stream (stderr) rather than to the standard > output stream. </para> >- >- <para>By default, the client writes messages to standard output >+ >+ <para>By default, the client writes messages to standard output > - typically the user's tty. </para></listitem> > </varlistentry> >- >+ > <varlistentry> > <term>-L|--list</term> >- <listitem><para>This option allows you to look at what services >- are available on a server. You use it as <command>smbclient -L >+ <listitem><para>This option allows you to look at what services >+ are available on a server. You use it as <command>smbclient -L > host</command> and a list should appear. The <parameter>-I >- </parameter> option may be useful if your NetBIOS names don't >- match your TCP/IP DNS host names or if you are trying to reach a >+ </parameter> option may be useful if your NetBIOS names don't >+ match your TCP/IP DNS host names or if you are trying to reach a > host on another network. </para></listitem> > </varlistentry> >- >- <varlistentry> >+ >+ <varlistentry> > <term>-b|--send-buffer buffersize</term> > <listitem><para> > When sending or receiving files, smbclient uses an >@@ -328,7 +328,7 @@ > using the <command>iosize</command> command inside smbclient. > </para></listitem> > </varlistentry> >- >+ > <varlistentry> > <term>-B|--browse</term> > <listitem><para>Browse SMB servers using DNS.</para> >@@ -340,7 +340,7 @@ > &popt.common.credentials; > &popt.common.connection; > &popt.autohelp; >- >+ > <varlistentry> > <term>-t|--timeout <timeout-seconds></term> > <listitem><para>This allows the user to tune the default >@@ -357,144 +357,142 @@ > <term>-T|--tar tar options</term> > <listitem><para>smbclient may be used to create <command>tar(1) > </command> compatible backups of all the files on an SMB/CIFS >- share. The secondary tar flags that can be given to this option >- are : </para> >- >+ share. The secondary tar flags that can be given to this option >+ are:</para> >+ > <itemizedlist> >- <listitem><para><parameter>c</parameter> - Create a tar file on UNIX. >- Must be followed by the name of a tar file, tape device >- or "-" for standard output. If using standard output you must >- turn the log level to its lowest value -d0 to avoid corrupting >- your tar file. This flag is mutually exclusive with the >+ <listitem><para><parameter>c</parameter> - Create a tar >+ backup archive on the local system. Must be followed by >+ the name of a tar file, tape device or "-" for standard >+ output. If using standard output you must turn the log >+ level to its lowest value -d0 to avoid corrupting your tar >+ file. This flag is mutually exclusive with the > <parameter>x</parameter> flag. </para></listitem> >- >- <listitem><para><parameter>x</parameter> - Extract (restore) a local >- tar file back to a share. Unless the -D option is given, the tar >- files will be restored from the top level of the share. Must be >- followed by the name of the tar file, device or "-" for standard >- input. Mutually exclusive with the <parameter>c</parameter> flag. >+ >+ <listitem><para><parameter>x</parameter> - Extract (restore) a local >+ tar file back to a share. Unless the -D option is given, the tar >+ files will be restored from the top level of the share. Must be >+ followed by the name of the tar file, device or "-" for standard >+ input. Mutually exclusive with the <parameter>c</parameter> flag. > Restored files have their creation times (mtime) set to the >- date saved in the tar file. Directories currently do not get >+ date saved in the tar file. Directories currently do not get > their creation dates restored properly. </para></listitem> >- >- <listitem><para><parameter>I</parameter> - Include files and directories. >- Is the default behavior when filenames are specified above. Causes >- files to be included in an extract or create (and therefore >- everything else to be excluded). See example below. Filename globbing >- works in one of two ways. See <parameter>r</parameter> below. </para></listitem> >- >- <listitem><para><parameter>X</parameter> - Exclude files and directories. >- Causes files to be excluded from an extract or create. See >- example below. Filename globbing works in one of two ways now. >+ >+ <listitem><para><parameter>I</parameter> - Include files and directories. >+ Is the default behavior when filenames are specified above. Causes >+ files to be included in an extract or create (and therefore >+ everything else to be excluded). See example below. Filename globbing >+ works in one of two ways. See <parameter>r</parameter> below. </para></listitem> >+ >+ <listitem><para><parameter>X</parameter> - Exclude files and directories. >+ Causes files to be excluded from an extract or create. See >+ example below. Filename globbing works in one of two ways. > See <parameter>r</parameter> below. </para></listitem> >- >+ > <listitem><para><parameter>F</parameter> - File containing a list of files and directories. > The <parameter>F</parameter> causes the name following the tarfile to >- create to be read as a filename that contains a list of files and directories to >+ create to be read as a filename that contains a list of files and directories to > be included in an extract or create (and therefore everything else to be excluded). > See example below. Filename globbing works in one of two ways. > See <parameter>r</parameter> below. > </para></listitem> >- >- <listitem><para><parameter>b</parameter> - Blocksize. Must be followed >- by a valid (greater than zero) blocksize. Causes tar file to be >- written out in blocksize*TBLOCK (usually 512 byte) blocks. >+ >+ <listitem><para><parameter>b</parameter> - Blocksize. Must be followed >+ by a valid (greater than zero) blocksize. Causes tar file to be >+ written out in blocksize*TBLOCK (512 byte) blocks. > </para></listitem> >- >- <listitem><para><parameter>g</parameter> - Incremental. Only back up >- files that have the archive bit set. Useful only with the >+ >+ <listitem><para><parameter>g</parameter> - Incremental. Only back up >+ files that have the archive bit set. Useful only with the > <parameter>c</parameter> flag. </para></listitem> > >- <listitem><para><parameter>q</parameter> - Quiet. Keeps tar from printing >- diagnostics as it works. This is the same as tarmode quiet. >+ <listitem><para><parameter>q</parameter> - Quiet. Keeps tar from printing >+ diagnostics as it works. This is the same as tarmode quiet. > </para></listitem> >- >- <listitem><para><parameter>r</parameter> - Regular expression include >- or exclude. Uses regular expression matching for >- excluding or excluding files if compiled with HAVE_REGEX_H. >- However this mode can be very slow. If not compiled with >- HAVE_REGEX_H, does a limited wildcard match on '*' and '?'. >+ >+ <listitem><para><parameter>r</parameter> - Use wildcard >+ matching to include or exclude. Deprecated. > </para></listitem> >- >- <listitem><para><parameter>N</parameter> - Newer than. Must be followed >- by the name of a file whose date is compared against files found >- on the share during a create. Only files newer than the file >- specified are backed up to the tar file. Useful only with the >+ >+ <listitem><para><parameter>N</parameter> - Newer than. Must be followed >+ by the name of a file whose date is compared against files found >+ on the share during a create. Only files newer than the file >+ specified are backed up to the tar file. Useful only with the > <parameter>c</parameter> flag. </para></listitem> >- >- <listitem><para><parameter>a</parameter> - Set archive bit. Causes the >- archive bit to be reset when a file is backed up. Useful with the >- <parameter>g</parameter> and <parameter>c</parameter> flags. >+ >+ <listitem><para><parameter>a</parameter> - Set archive bit. Causes the >+ archive bit to be reset when a file is backed up. Useful with the >+ <parameter>g</parameter> and <parameter>c</parameter> flags. > </para></listitem> > </itemizedlist> >- >+ > <para><emphasis>Tar Long File Names</emphasis></para> >- >- <para><command>smbclient</command>'s tar option now supports long >- file names both on backup and restore. However, the full path >- name of the file must be less than 1024 bytes. Also, when >- a tar archive is created, <command>smbclient</command>'s tar option places all >- files in the archive with relative names, not absolute names. >+ >+ <para><command>smbclient</command>'s tar option now supports long >+ file names both on backup and restore. However, the full path >+ name of the file must be less than 1024 bytes. Also, when >+ a tar archive is created, <command>smbclient</command>'s tar option places all >+ files in the archive with relative names, not absolute names. > </para> > > <para><emphasis>Tar Filenames</emphasis></para> >- >- <para>All file names can be given as DOS path names (with '\\' >- as the component separator) or as UNIX path names (with '/' as >+ >+ <para>All file names can be given as DOS path names (with '\\' >+ as the component separator) or as UNIX path names (with '/' as > the component separator). </para> >- >+ > <para><emphasis>Examples</emphasis></para> >- >- <para>Restore from tar file <filename>backup.tar</filename> into myshare on mypc >+ >+ <para>Restore from tar file <filename>backup.tar</filename> into myshare on mypc > (no password on share). </para> >- >+ > <para><command>smbclient //mypc/myshare "" -N -Tx backup.tar > </command></para> >- >+ > <para>Restore everything except <filename>users/docs</filename> > </para> >- >- <para><command>smbclient //mypc/myshare "" -N -TXx backup.tar >+ >+ <para><command>smbclient //mypc/myshare "" -N -TXx backup.tar > users/docs</command></para> >- >+ > <para>Create a tar file of the files beneath <filename> > users/docs</filename>. </para> >- >+ > <para><command>smbclient //mypc/myshare "" -N -Tc > backup.tar users/docs </command></para> >- >- <para>Create the same tar file as above, but now use >+ >+ <para>Create the same tar file as above, but now use > a DOS path name. </para> >- >+ > <para><command>smbclient //mypc/myshare "" -N -Tc backup.tar > users\edocs </command></para> >- >+ > <para>Create a tar file of the files listed in the file <filename>tarlist</filename>.</para> >- >+ > <para><command>smbclient //mypc/myshare "" -N -TcF > backup.tar tarlist</command></para> >- >- <para>Create a tar file of all the files and directories in >+ >+ <para>Create a tar file of all the files and directories in > the share. </para> >- >+ > <para><command>smbclient //mypc/myshare "" -N -Tc backup.tar * > </command></para> > </listitem> > </varlistentry> >- >+ > <varlistentry> > <term>-D|--directory initial directory</term> >- <listitem><para>Change to initial directory before starting. Probably >+ <listitem><para>Change to initial directory before starting. Probably > only of any use with the tar -T option. </para></listitem> > </varlistentry> >- >+ > <varlistentry> > <term>-c|--command command string</term> >- <listitem><para>command string is a semicolon-separated list of >+ <listitem><para>command string is a semicolon-separated list of > commands to be executed instead of prompting from stdin. <parameter> > -N</parameter> is implied by <parameter>-c</parameter>.</para> > >- <para>This is particularly useful in scripts and for printing stdin >+ <para>This is particularly useful in scripts and for printing stdin > to the server, e.g. <command>-c 'print -'</command>. </para></listitem> > </varlistentry> > >@@ -505,35 +503,35 @@ > <refsect1> > <title>OPERATIONS</title> > >- <para>Once the client is running, the user is presented with >+ <para>Once the client is running, the user is presented with > a prompt : </para> > > <para><prompt>smb:\> </prompt></para> > >- <para>The backslash ("\\") indicates the current working directory >- on the server, and will change if the current working directory >+ <para>The backslash ("\\") indicates the current working directory >+ on the server, and will change if the current working directory > is changed. </para> > >- <para>The prompt indicates that the client is ready and waiting to >- carry out a user command. Each command is a single word, optionally >- followed by parameters specific to that command. Command and parameters >+ <para>The prompt indicates that the client is ready and waiting to >+ carry out a user command. Each command is a single word, optionally >+ followed by parameters specific to that command. Command and parameters > are space-delimited unless these notes specifically >- state otherwise. All commands are case-insensitive. Parameters to >- commands may or may not be case sensitive, depending on the command. >+ state otherwise. All commands are case-insensitive. Parameters to >+ commands may or may not be case sensitive, depending on the command. > </para> > >- <para>You can specify file names which have spaces in them by quoting >+ <para>You can specify file names which have spaces in them by quoting > the name with double quotes, for example "a long file name". </para> > >- <para>Parameters shown in square brackets (e.g., "[parameter]") are >- optional. If not given, the command will use suitable defaults. Parameters >+ <para>Parameters shown in square brackets (e.g., "[parameter]") are >+ optional. If not given, the command will use suitable defaults. Parameters > shown in angle brackets (e.g., "<parameter>") are required. > </para> > > >- <para>Note that all commands operating on the server are actually >- performed by issuing a request to the server. Thus the behavior may >- vary from server to server, depending on how the server was implemented. >+ <para>Note that all commands operating on the server are actually >+ performed by issuing a request to the server. Thus the behavior may >+ vary from server to server, depending on how the server was implemented. > </para> > > <para>The commands available are given here in alphabetical order. </para> >@@ -778,8 +776,8 @@ > <varlistentry> > <term>lowercase</term> > <listitem><para>Toggle lowercasing of filenames for the get and >- mget commands. >- </para> >+ mget commands. >+ </para> > > <para>When lowercasing is toggled ON, local filenames are converted > to lowercase when using the get and mget commands. This is >@@ -994,7 +992,7 @@ > > <varlistentry> > <term>rmdir <directory name></term> >- <listitem><para>Remove the specified directory (user access >+ <listitem><para>Remove the specified directory (user access > privileges permitting) from the server. </para></listitem> > </varlistentry> > >@@ -1038,29 +1036,44 @@ > > <varlistentry> > <term>tar <c|x>[IXbgNa]</term> >- <listitem><para>Performs a tar operation - see the <parameter>-T >- </parameter> command line option above. Behavior may be affected >- by the tarmode command (see below). Using g (incremental) and N >- (newer) will affect tarmode settings. Note that using the "-" option >- with tar x may not work - use the command line option instead. >- </para></listitem> >+ <listitem><para>Performs a tar operation - see the >+ <parameter>-T</parameter> command line option above. Behavior >+ may be affected by the tarmode command (see below). Using g >+ (incremental) and N (newer) will affect tarmode settings. Note >+ that using the "-" option with tar x may not work - use the >+ command line option instead.</para></listitem> > </varlistentry> > > <varlistentry> > <term>blocksize <blocksize></term> > <listitem><para>Blocksize. Must be followed by a valid (greater > than zero) blocksize. Causes tar file to be written out in >- <replaceable>blocksize</replaceable>*TBLOCK (usually 512 byte) blocks. </para></listitem> >+ <replaceable>blocksize</replaceable>*TBLOCK (512 byte) blocks. </para></listitem> > </varlistentry> > > <varlistentry> >- <term>tarmode <full|inc|reset|noreset></term> >- <listitem><para>Changes tar's behavior with regard to archive >- bits. In full mode, tar will back up everything regardless of the >- archive bit setting (this is the default mode). In incremental mode, >- tar will only back up files with the archive bit set. In reset mode, >- tar will reset the archive bit on all files it backs up (implies >- read/write share). </para></listitem> >+ <term>tarmode <full|inc|reset|noreset|system|nosystem|hidden|nohidden></term> >+ <listitem><para>Changes tar's behavior with regard to DOS >+ attributes. There are 4 modes which can be turned on or >+ off.</para> >+ >+ <para>Incremental mode (default off). When off (using >+ <command>full</command>) tar will back up everything >+ regardless of the <emphasis>archive</emphasis> bit >+ setting. When on (using <command>inc</command>), tar will only >+ back up files with the archive bit set.</para> >+ >+ <para>Reset mode (default off). When on (using >+ <command>reset</command>), tar will remove the archive bit on >+ all files it backs up (implies read/write share). Use >+ <command>noreset</command> to turn off.</para> >+ >+ <para>System mode (default on). When off, tar will not backup >+ system files. Use <command>nosystem</command> to turn off.</para> >+ >+ <para>Hidden mode (default on). When off, tar will not backup >+ hidden files. Use <command>nohidden</command> to turn off.</para> >+ </listitem> > </varlistentry> > > <varlistentry> >@@ -1135,52 +1148,52 @@ > on a valid NetBIOS name being used, so you need to supply a valid > name that would be known to the server.</para> > >- <para>smbclient supports long file names where the server >+ <para>smbclient supports long file names where the server > supports the LANMAN2 protocol or above. </para> > </refsect1> > > <refsect1> > <title>ENVIRONMENT VARIABLES</title> > >- <para>The variable <envar>USER</envar> may contain the >- username of the person using the client. This information is >- used only if the protocol level is high enough to support >+ <para>The variable <envar>USER</envar> may contain the >+ username of the person using the client. This information is >+ used only if the protocol level is high enough to support > session-level passwords.</para> > > >- <para>The variable <envar>PASSWD</envar> may contain >- the password of the person using the client. This information is >- used only if the protocol level is high enough to support >+ <para>The variable <envar>PASSWD</envar> may contain >+ the password of the person using the client. This information is >+ used only if the protocol level is high enough to support > session-level passwords. </para> > >- <para>The variable <envar>LIBSMB_PROG</envar> may contain >- the path, executed with system(), which the client should connect >- to instead of connecting to a server. This functionality is primarily >- intended as a development aid, and works best when using a LMHOSTS >- file</para> >+ <para>The variable <envar>LIBSMB_PROG</envar> may contain >+ the path, executed with system(), which the client should connect >+ to instead of connecting to a server. This functionality is primarily >+ intended as a development aid, and works best when using a LMHOSTS >+ file</para> > </refsect1> > > > <refsect1> > <title>INSTALLATION</title> > >- <para>The location of the client program is a matter for >+ <para>The location of the client program is a matter for > individual system administrators. The following are thus > suggestions only. </para> > > <para>It is recommended that the smbclient software be installed > in the <filename>/usr/local/samba/bin/</filename> or <filename> >- /usr/samba/bin/</filename> directory, this directory readable >- by all, writeable only by root. The client program itself should >- be executable by all. The client should <emphasis>NOT</emphasis> be >+ /usr/samba/bin/</filename> directory, this directory readable >+ by all, writeable only by root. The client program itself should >+ be executable by all. The client should <emphasis>NOT</emphasis> be > setuid or setgid! </para> > >- <para>The client log files should be put in a directory readable >+ <para>The client log files should be put in a directory readable > and writeable only by the user. </para> > >- <para>To test the client, you will need to know the name of a >+ <para>To test the client, you will need to know the name of a > running SMB/CIFS server. It is possible to run <citerefentry><refentrytitle>smbd</refentrytitle> >- <manvolnum>8</manvolnum></citerefentry> as an ordinary user - running that server as a daemon >+ <manvolnum>8</manvolnum></citerefentry> as an ordinary user - running that server as a daemon > on a user-accessible port (typically any port number over 1024) > would provide a suitable test server. </para> > </refsect1> >@@ -1189,12 +1202,12 @@ > <refsect1> > <title>DIAGNOSTICS</title> > >- <para>Most diagnostics issued by the client are logged in a >- specified log file. The log file name is specified at compile time, >+ <para>Most diagnostics issued by the client are logged in a >+ specified log file. The log file name is specified at compile time, > but may be overridden on the command line. </para> > >- <para>The number and nature of diagnostics available depends >- on the debug level used by the client. If you have problems, >+ <para>The number and nature of diagnostics available depends >+ on the debug level used by the client. If you have problems, > set the debug level to 3 and peruse the log files. </para> > </refsect1> > >@@ -1208,17 +1221,17 @@ > > <refsect1> > <title>AUTHOR</title> >- >- <para>The original Samba software and related utilities >+ >+ <para>The original Samba software and related utilities > were created by Andrew Tridgell. Samba is now developed >- by the Samba Team as an Open Source project similar >+ by the Samba Team as an Open Source project similar > to the way the Linux kernel is developed.</para> >- >- <para>The original Samba man pages were written by Karl Auer. >- The man page sources were converted to YODL format (another >+ >+ <para>The original Samba man pages were written by Karl Auer. >+ The man page sources were converted to YODL format (another > excellent piece of Open Source software, available at <ulink url="ftp://ftp.icce.rug.nl/pub/unix/"> >- ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0 >- release by Jeremy Allison. The conversion to DocBook for >+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0 >+ release by Jeremy Allison. The conversion to DocBook for > Samba 2.2 was done by Gerald Carter. The conversion to DocBook XML 4.2 for Samba 3.0 > was done by Alexander Bokovoy.</para> > </refsect1> >diff --git source3/client/client.c source3/client/client.c >index afa5847..e04b4b2 100644 >--- source3/client/client.c >+++ source3/client/client.c >@@ -26,6 +26,7 @@ > #include "popt_common.h" > #include "rpc_client/cli_pipe.h" > #include "client/client_proto.h" >+#include "client/clitar_proto.h" > #include "../librpc/gen_ndr/ndr_srvsvc_c.h" > #include "../lib/util/select.h" > #include "system/readline.h" >@@ -46,7 +47,6 @@ > extern int do_smb_browse(void); /* mDNS browsing */ > > extern bool override_logfile; >-extern char tar_type; > > static int port = 0; > static char *service; >@@ -75,12 +75,6 @@ static int archive_level = 0; > static bool translation = false; > static bool have_ip; > >-/* clitar bits insert */ >-extern int blocksize; >-extern bool tar_inc; >-extern bool tar_reset; >-/* clitar bits end */ >- > static bool prompt = true; > > static bool recurse = false; >@@ -4642,7 +4636,7 @@ static struct { > {COMPL_NONE,COMPL_NONE}}, > {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}}, > {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}}, >- {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}}, >+ {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}}, > {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}}, > {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}}, > {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}}, >@@ -4666,14 +4660,14 @@ static struct { > {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}}, > {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}}, > {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}}, >- {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}}, >+ {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}}, > {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, > {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, > {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}}, > {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}}, > {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}}, > {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}}, >- {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}}, >+ {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}}, > {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}}, > {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}}, > {"notify",cmd_notify,"<file>Get notified of dir changes",{COMPL_REMOTE,COMPL_NONE}}, >@@ -4685,7 +4679,7 @@ static struct { > {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}}, > {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}}, > {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}}, >- {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}}, >+ {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}}, > {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}}, > {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}}, > {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}}, >@@ -4693,13 +4687,13 @@ static struct { > {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}}, > {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}}, > {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}}, >- {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}}, >+ {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}}, > {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}}, > {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}}, > {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}}, > {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, > {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_REMOTE,COMPL_NONE}}, >- {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}}, >+ {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}}, > {"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file", > {COMPL_REMOTE, COMPL_LOCAL}}, > {"setmode",cmd_setmode,"<file name> <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}}, >@@ -5325,7 +5319,8 @@ static int do_host_query(const char *query_host) > > static int do_tar_op(const char *base_directory) > { >- int ret; >+ struct tar *tar_ctx = tar_get_ctx(); >+ int ret = 0; > > /* do we already have a connection? */ > if (!cli) { >@@ -5336,26 +5331,27 @@ static int do_tar_op(const char *base_directory) > service, auth_info, true, smb_encrypt, > max_protocol, port, name_type, &cli); > if (!NT_STATUS_IS_OK(status)) { >- return 1; >+ ret = 1; >+ goto out; > } > cli_set_timeout(cli, io_timeout*1000); > } > >- recurse=true; >+ recurse = true; > > if (base_directory && *base_directory) { > ret = do_cd(base_directory); > if (ret) { >- cli_shutdown(cli); >- return ret; >+ goto out_cli; > } > } > >- ret=process_tar(); >+ ret = tar_process(tar_ctx); > >+ out_cli: > cli_shutdown(cli); >- >- return(ret); >+ out: >+ return ret; > } > > /**************************************************************************** >@@ -5385,7 +5381,7 @@ static int do_message_op(struct user_auth_info *a_info) > main program > ****************************************************************************/ > >- int main(int argc,char *argv[]) >+int main(int argc,char *argv[]) > { > const char **const_argv = discard_const_p(const char *, argv); > char *base_directory = NULL; >@@ -5398,6 +5394,8 @@ static int do_message_op(struct user_auth_info *a_info) > int rc = 0; > bool tar_opt = false; > bool service_opt = false; >+ struct tar *tar_ctx = tar_get_ctx(); >+ > struct poptOption long_options[] = { > POPT_AUTOHELP > >@@ -5409,7 +5407,7 @@ static int do_message_op(struct user_auth_info *a_info) > { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" }, > { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" }, > { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" }, >- { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, >+ { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, > { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" }, > { "timeout", 't', POPT_ARG_INT, &io_timeout, 'b', "Changes the per-operation timeout", "SECONDS" }, > { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" }, >@@ -5514,12 +5512,14 @@ static int do_message_op(struct user_auth_info *a_info) > * position of the -T option in the raw argv[]. */ > { > int i; >+ > for (i = 1; i < argc; i++) { > if (strncmp("-T", argv[i],2)==0) > break; > } > i++; >- if (!tar_parseargs(argc, argv, poptGetOptArg(pc), i)) { >+ if (tar_parse_args(tar_ctx, poptGetOptArg(pc), >+ const_argv + i, argc - i)) { > poptPrintUsage(pc, stderr, 0); > exit(1); > } >@@ -5612,7 +5612,7 @@ static int do_message_op(struct user_auth_info *a_info) > if(new_name_resolve_order) > lp_set_cmdline("name resolve order", new_name_resolve_order); > >- if (!tar_type && !query_host && !service && !message) { >+ if (!tar_to_process(tar_ctx) && !query_host && !service && !message) { > poptPrintUsage(pc, stderr, 0); > exit(1); > } >@@ -5627,7 +5627,7 @@ static int do_message_op(struct user_auth_info *a_info) > > max_protocol = lp_cli_maxprotocol(); > >- if (tar_type) { >+ if (tar_to_process(tar_ctx)) { > if (cmdstr) > process_command_string(cmdstr); > rc = do_tar_op(base_directory); >diff --git source3/client/client_proto.h source3/client/client_proto.h >index d119014..3e91ff0 100644 >--- source3/client/client_proto.h >+++ source3/client/client_proto.h >@@ -38,15 +38,6 @@ NTSTATUS do_list(const char *mask, > bool dirs); > int cmd_iosize(void); > >-/* The following definitions come from client/clitar.c */ >- >-int cmd_block(void); >-int cmd_tarmode(void); >-int cmd_setmode(void); >-int cmd_tar(void); >-int process_tar(void); >-int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind); >- > /* The following definitions come from client/dnsbrowse.c */ > > int do_smb_browse(void); >diff --git source3/client/clitar.c source3/client/clitar.c >index 7bbd6ad..e4d391a 100644 >--- source3/client/clitar.c >+++ source3/client/clitar.c >@@ -1,8 +1,7 @@ > /* > Unix SMB/CIFS implementation. >- Tar Extensions >- Copyright (C) Ricky Poulten 1995-1998 >- Copyright (C) Richard Sharpe 1998 >+ Tar backup command extension >+ Copyright (C) Aurélien Aptel 2013 > > 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 >@@ -17,1972 +16,1954 @@ > You should have received a copy of the GNU General Public License > along with this program. If not, see <http://www.gnu.org/licenses/>. > */ >-/* The following changes developed by Richard Sharpe for Canon Information >- Systems Research Australia (CISRA) >- >- 1. Restore can now restore files with long file names >- 2. Save now saves directory information so that we can restore >- directory creation times >- 3. tar now accepts both UNIX path names and DOS path names. I prefer >- those lovely /'s to those UGLY \'s :-) >- 4. the files to exclude can be specified as a regular expression by adding >- an r flag to the other tar flags. Eg: >- >- -TcrX file.tar "*.(obj|exe)" >- >- will skip all .obj and .exe files >-*/ > >+/** >+ * # General overview of the tar extension >+ * >+ * All tar_xxx() functions work on a `struct tar` which store most of >+ * the context of the backup process. >+ * >+ * The current tar context can be accessed via the global variable >+ * `tar_ctx`. It's publicly exported as an opaque handle via >+ * tar_get_ctx(). >+ * >+ * A tar context is first configured through tar_parse_args() which >+ * can be called from either the CLI (in client.c) or the interactive >+ * session (via the cmd_tar() callback). >+ * >+ * Once the configuration is done (successfully), the context is ready >+ * for processing and tar_to_process() returns true. >+ * >+ * The next step is to call tar_process() which dispatch the >+ * processing to either tar_create() or tar_extract(), depending on >+ * the context. >+ * >+ * ## Archive creation >+ * >+ * tar_create() creates an archive using the libarchive API then >+ * >+ * - iterates on the requested paths if the context is in inclusion >+ * mode with tar_create_from_list() >+ * >+ * - or iterates on the whole share (starting from the current dir) if >+ * in exclusion mode or if no specific path were requested >+ * >+ * The do_list() function from client.c is used to list recursively >+ * the share. In particular it takes a DOS path mask (eg. \mydir\*) >+ * and a callback function which will be called with each file name >+ * and attributes. The tar callback function is get_file_callback(). >+ * >+ * The callback function checks whether the file should be skipped >+ * according the the configuration via tar_create_skip_path(). If it's >+ * not skipped it's downloaded and written to the archive in >+ * tar_get_file(). >+ * >+ * ## Archive extraction >+ * >+ * tar_extract() opens the archive and iterates on each file in >+ * it. For each file tar_extract_skip_path() checks whether it should >+ * be skipped according to the config. If it's not skipped it's >+ * uploaded on the server in tar_send_file(). >+ */ > > #include "includes.h" > #include "system/filesys.h" >-#include "clitar.h" > #include "client/client_proto.h" >+#include "client/clitar_proto.h" > #include "libsmb/libsmb.h" > >-static int clipfind(char **aret, int ret, char *tok); >- >-typedef struct file_info_struct file_info2; >- >-struct file_info_struct { >- off_t size; >- uint16 mode; >- uid_t uid; >- gid_t gid; >- /* These times are normally kept in GMT */ >- struct timespec mtime_ts; >- struct timespec atime_ts; >- struct timespec ctime_ts; >- char *name; /* This is dynamically allocated */ >- file_info2 *next, *prev; /* Used in the stack ... */ >-}; >- >-typedef struct { >- file_info2 *top; >- int items; >-} stack; >- >-#define SEPARATORS " \t\n\r" >-extern time_t newer_than; >-extern struct cli_state *cli; >- >-/* These defines are for the do_setrattr routine, to indicate >- * setting and reseting of file attributes in the function call */ >-#define ATTRSET 1 >-#define ATTRRESET 0 >- >-static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; >- >- >-static char *tarbuf, *buffer_p; >-static int tp, ntarf, tbufsiz; >-static double ttarf; >-/* Incremental mode */ >-static bool tar_inc=False; >-/* Reset archive bit */ >-static bool tar_reset=False; >-/* Include / exclude mode (true=include, false=exclude) */ >-static bool tar_excl=True; >-/* use regular expressions for search on file names */ >-static bool tar_re_search=False; >-/* Do not dump anything, just calculate sizes */ >-static bool dry_run=False; >-/* Dump files with System attribute */ >-static bool tar_system=True; >-/* Dump files with Hidden attribute */ >-static bool tar_hidden=True; >-/* Be noisy - make a catalogue */ >-static bool tar_noisy=True; >-static bool tar_real_noisy=False; /* Don't want to be really noisy by default */ >- >-char tar_type='\0'; >-static char **cliplist=NULL; >-static int clipn=0; >-static bool must_free_cliplist = False; >-extern char *cmd_ptr; >- >-extern bool lowercase; >-extern int get_total_time_ms; >-extern int get_total_size; >- >-static int blocksize=20; >-static int tarhandle; >- >-static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime, >- const char *amode, unsigned char ftype); >-static NTSTATUS do_atar(const char *rname_in, char *lname, >- struct file_info *finfo1); >-static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo, >- const char *dir); >-static void oct_it(uint64_t value, int ndgs, char *p); >-static void fixtarname(char *tptr, const char *fp, size_t l); >-static int dotarbuf(int f, char *b, int n); >-static void dozerobuf(int f, int n); >-static void dotareof(int f); >-static void initarbuf(void); >- >-/* restore functions */ >-static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix); >-static long unoct(char *p, int ndgs); >-static void do_tarput(void); >-static void unfixtarname(char *tptr, char *fp, int l, bool first); >+#ifdef HAVE_LIBARCHIVE > >-/* >- * tar specific utitlities >- */ >+#include <archive.h> >+#include <archive_entry.h> > >-/**************************************************************************** >-Write a tar header to buffer >-****************************************************************************/ >- >-static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime, >- const char *amode, unsigned char ftype) >-{ >- union hblock hb; >- int i, chk, l; >- char *jp; >+/* prepend module name and line number to debug messages */ >+#define DBG(a, b) (DEBUG(a, ("tar:%-4d ", __LINE__)), DEBUG(a, b)) > >- DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname)); >+/* preprocessor magic to stringify __LINE__ (int) */ >+#define STR1(x) #x >+#define STR2(x) STR1(x) > >- memset(hb.dummy, 0, sizeof(hb.dummy)); >+/** >+ * Number of byte in a block unit. >+ */ >+#define TAR_BLOCK_UNIT 512 > >- l=strlen(aname); >- /* We will be prepending a '.' in fixtarheader so use +2 to >- * take care of the . and terminating zero. JRA. >- */ >- if (l+2 >= NAMSIZ) { >- /* write a GNU tar style long header */ >- char *b; >- b = (char *)SMB_MALLOC(l+TBLOCK+100); >- if (!b) { >- DEBUG(0,("out of memory\n")); >- exit(1); >- } >- writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L'); >- memset(b, 0, l+TBLOCK+100); >- fixtarname(b, aname, l+2); >- i = strlen(b)+1; >- DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b))); >- dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1)); >- SAFE_FREE(b); >- } >- >- fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2); >- >- if (lowercase) >- (void)strlower_m(hb.dbuf.name); >- >- /* write out a "standard" tar format header */ >- >- hb.dbuf.name[NAMSIZ-1]='\0'; >- strlcpy(hb.dbuf.mode, amode ? amode : "", sizeof(hb.dbuf.mode)); >- oct_it((uint64_t)0, 8, hb.dbuf.uid); >- oct_it((uint64_t)0, 8, hb.dbuf.gid); >- oct_it((uint64_t) size, 13, hb.dbuf.size); >- if (size > (uint64_t)077777777777LL) { >- /* This is a non-POSIX compatible extention to store files >- greater than 8GB. */ >- >- memset(hb.dbuf.size, 0, 4); >- hb.dbuf.size[0]=128; >- for (i = 8; i; i--) { >- hb.dbuf.size[i+3] = size & 0xff; >- size >>= 8; >- } >- } >- oct_it((uint64_t) mtime, 13, hb.dbuf.mtime); >- memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum)); >- memset(hb.dbuf.linkname, 0, NAMSIZ); >- hb.dbuf.linkflag=ftype; >+/** >+ * Default tar block size in TAR_BLOCK_UNIT. >+ */ >+#define TAR_DEFAULT_BLOCK_SIZE 20 > >- for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) >- chk+=(0xFF & *jp++); >+/** >+ * Maximum value for the blocksize field >+ */ >+#define TAR_MAX_BLOCK_SIZE 0xffff > >- oct_it((uint64_t) chk, 8, hb.dbuf.chksum); >- hb.dbuf.chksum[6] = '\0'; >+/** >+ * Size of the buffer used when downloading a file >+ */ >+#define TAR_CLI_READ_SIZE 0xff00 > >- (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy)); >-} >+#define TAR_DO_LIST_ATTR (FILE_ATTRIBUTE_DIRECTORY \ >+ | FILE_ATTRIBUTE_SYSTEM \ >+ | FILE_ATTRIBUTE_HIDDEN) > >-/**************************************************************************** >-Read a tar header into a hblock structure, and validate >-***************************************************************************/ > >-static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix) >-{ >- long chk, fchk; >- int i; >- char *jp; >+enum tar_operation { >+ TAR_NO_OPERATION, >+ TAR_CREATE, /* c flag */ >+ TAR_EXTRACT, /* x flag */ >+}; > >- /* >- * read in a "standard" tar format header - we're not that interested >- * in that many fields, though >- */ >+enum tar_selection { >+ TAR_NO_SELECTION, >+ TAR_INCLUDE, /* I and F flag, default */ >+ TAR_EXCLUDE, /* X flag */ >+}; > >- /* check the checksum */ >- for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) >- chk+=(0xFF & *jp++); >+enum { >+ ATTR_UNSET, >+ ATTR_SET, >+}; > >- if (chk == 0) >- return chk; >+struct tar { >+ TALLOC_CTX *talloc_ctx; >+ >+ /* in state that needs/can be processed? */ >+ bool to_process; >+ >+ /* flags */ >+ struct tar_mode { >+ enum tar_operation operation; /* create, extract */ >+ enum tar_selection selection; /* include, exclude */ >+ int blocksize; /* size in TAR_BLOCK_UNIT of a tar file block */ >+ bool hidden; /* backup hidden file? */ >+ bool system; /* backup system file? */ >+ bool incremental; /* backup _only_ archived file? */ >+ bool reset; /* unset archive bit? */ >+ bool dry; /* don't write tar file? */ >+ bool regex; /* XXX: never actually using regex... */ >+ bool verbose; /* XXX: ignored */ >+ } mode; >+ >+ /* nb of bytes received */ >+ uint64_t total_size; >+ >+ /* path to tar archive name */ >+ char *tar_path; >+ >+ /* list of path to include or exclude */ >+ char **path_list; >+ int path_list_size; >+ >+ /* archive handle */ >+ struct archive *archive; >+}; > >- /* compensate for blanks in chksum header */ >- for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;) >- chk-=(0xFF & *jp++); >+/** >+ * Global context imported in client.c when needed. >+ * >+ * Default options. >+ */ >+struct tar tar_ctx = { >+ .mode.selection = TAR_INCLUDE, >+ .mode.blocksize = TAR_DEFAULT_BLOCK_SIZE, >+ .mode.hidden = true, >+ .mode.system = true, >+ .mode.incremental = false, >+ .mode.reset = false, >+ .mode.dry = false, >+ .mode.regex = false, >+ .mode.verbose = false, >+}; > >- chk += ' ' * sizeof(hb->dbuf.chksum); >+/* tar, local function */ >+static int tar_create(struct tar* t); >+static int tar_create_from_list(struct tar *t); >+static int tar_extract(struct tar *t); >+static int tar_read_inclusion_file(struct tar *t, const char* filename); >+static int tar_send_file(struct tar *t, struct archive_entry *entry); >+static int tar_set_blocksize(struct tar *t, int size); >+static int tar_set_newer_than(struct tar *t, const char *filename); >+static NTSTATUS tar_add_selection_path(struct tar *t, const char *path); >+static void tar_dump(struct tar *t); >+static NTSTATUS tar_extract_skip_path(struct tar *t, >+ struct archive_entry *entry, >+ bool *_skip); >+static TALLOC_CTX *tar_reset_mem_context(struct tar *t); >+static void tar_free_mem_context(struct tar *t); >+static NTSTATUS tar_create_skip_path(struct tar *t, >+ const char *fullpath, >+ const struct file_info *finfo, >+ bool *_skip); >+ >+static NTSTATUS tar_path_in_list(struct tar *t, const char *path, >+ bool reverse, bool *_is_in_list); >+ >+static int tar_get_file(struct tar *t, >+ const char *full_dos_path, >+ struct file_info *finfo); >+ >+static NTSTATUS get_file_callback(struct cli_state *cli, >+ struct file_info *finfo, >+ const char *dir); >+ >+/* utilities */ >+static char *fix_unix_path(char *path, bool removeprefix); >+static NTSTATUS path_base_name(TALLOC_CTX *ctx, const char *path, char **_base); >+static const char* skip_useless_char_in_path(const char *p); >+static int make_remote_path(const char *full_path); >+static int max_token (const char *str); >+static NTSTATUS is_subpath(const char *sub, const char *full, >+ bool *_subpath_match); >+static int set_remote_attr(const char *filename, uint16 new_attr, int mode); > >- fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum)); >+/** >+ * tar_get_ctx - retrieve global tar context handle >+ */ >+struct tar *tar_get_ctx() >+{ >+ return &tar_ctx; >+} > >- DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n", >- chk, fchk, hb->dbuf.chksum)); >+/** >+ * cmd_block - interactive command to change tar blocksize >+ * >+ * Read a size from the client command line and update the current >+ * blocksize. >+ */ >+int cmd_block(void) >+{ >+ /* XXX: from client.c */ >+ const extern char *cmd_ptr; >+ char *buf; >+ int err = 0; >+ bool ok; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; >+ } > >- if (fchk != chk) { >- DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk)); >- dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3); >- return -1; >+ ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL); >+ if (!ok) { >+ DBG(0, ("blocksize <n>\n")); >+ err = 1; >+ goto out; > } > >- if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) { >- DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name)); >- return(-1); >+ ok = tar_set_blocksize(&tar_ctx, atoi(buf)); >+ if (ok) { >+ DBG(0, ("invalid blocksize\n")); >+ err = 1; >+ goto out; > } > >- strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4); >+ DBG(2, ("blocksize is now %d\n", tar_ctx.mode.blocksize)); >+ >+out: >+ talloc_free(ctx); >+ return err; >+} > >- /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */ >- unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name, >- strlen(hb->dbuf.name) + 1, True); >+/** >+ * cmd_tarmode - interactive command to change tar behaviour >+ * >+ * Read one or more modes from the client command line and update the >+ * current tar mode. >+ */ >+int cmd_tarmode(void) >+{ >+ const extern char *cmd_ptr; >+ char *buf; >+ int i; >+ TALLOC_CTX *ctx; >+ >+ struct { >+ const char *cmd; >+ bool *p; >+ bool value; >+ } table[] = { >+ {"full", &tar_ctx.mode.incremental, false}, >+ {"inc", &tar_ctx.mode.incremental, true }, >+ {"reset", &tar_ctx.mode.reset, true }, >+ {"noreset", &tar_ctx.mode.reset, false}, >+ {"system", &tar_ctx.mode.system, true }, >+ {"nosystem", &tar_ctx.mode.system, false}, >+ {"hidden", &tar_ctx.mode.hidden, true }, >+ {"nohidden", &tar_ctx.mode.hidden, false}, >+ {"verbose", &tar_ctx.mode.verbose, true }, >+ {"noquiet", &tar_ctx.mode.verbose, true }, >+ {"quiet", &tar_ctx.mode.verbose, false}, >+ {"noverbose", &tar_ctx.mode.verbose, false}, >+ }; >+ >+ ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; >+ } > >- /* can't handle some links at present */ >- if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) { >- if (hb->dbuf.linkflag == 0) { >- DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n", >- finfo->name)); >- } else { >- if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */ >- /* Do nothing here at the moment. do_tarput will handle this >- as long as the longlink gets back to it, as it has to advance >- the buffer pointer, etc */ >- } else { >- DEBUG(0, ("this tar file appears to contain some kind \ >-of link other than a GNUtar Longlink - ignoring\n")); >- return -2; >+ while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) { >+ for (i = 0; i < ARRAY_SIZE(table); i++) { >+ if (strequal(table[i].cmd, buf)) { >+ *table[i].p = table[i].value; >+ break; > } > } >- } > >- if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) || >- (*(finfo->name+strlen(finfo->name)-1) == '\\')) { >- finfo->mode=FILE_ATTRIBUTE_DIRECTORY; >- } else { >- finfo->mode=0; /* we don't care about mode at the moment, we'll >- * just make it a regular file */ >+ if (i == ARRAY_SIZE(table)) >+ DBG(0, ("tarmode: unrecognised option %s\n", buf)); > } > >- /* >- * Bug fix by richard@sj.co.uk >- * >- * REC: restore times correctly (as does tar) >- * We only get the modification time of the file; set the creation time >- * from the mod. time, and the access time to current time >- */ >- finfo->mtime_ts = finfo->ctime_ts = >- convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8)); >- finfo->atime_ts = convert_time_t_to_timespec(time(NULL)); >- if ((hb->dbuf.size[0] & 0xff) == 0x80) { >- /* This is a non-POSIX compatible extention to extract files >- greater than 8GB. */ >- finfo->size = 0; >- for (i = 0; i < 8; i++) { >- finfo->size <<= 8; >- finfo->size |= hb->dbuf.size[i+4] & 0xff; >- } >- } else { >- finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size)); >- } >+ DBG(0, ("tarmode is now %s, %s, %s, %s, %s\n", >+ tar_ctx.mode.incremental ? "incremental" : "full", >+ tar_ctx.mode.system ? "system" : "nosystem", >+ tar_ctx.mode.hidden ? "hidden" : "nohidden", >+ tar_ctx.mode.reset ? "reset" : "noreset", >+ tar_ctx.mode.verbose ? "verbose" : "quiet")); > >- return True; >+ talloc_free(ctx); >+ return 0; > } > >-/**************************************************************************** >-Write out the tar buffer to tape or wherever >-****************************************************************************/ >- >-static int dotarbuf(int f, char *b, int n) >+/** >+ * cmd_tar - interactive command to start a tar backup/restoration >+ * >+ * Check presence of argument, parse them and handle the request. >+ */ >+int cmd_tar(void) > { >- int fail=1, writ=n; >- >- if (dry_run) { >- return writ; >- } >- /* This routine and the next one should be the only ones that do write()s */ >- if (tp + n >= tbufsiz) { >- int diff; >- >- diff=tbufsiz-tp; >- memcpy(tarbuf + tp, b, diff); >- fail=fail && (1+sys_write(f, tarbuf, tbufsiz)); >- n-=diff; >- b+=diff; >- tp=0; >- >- while (n >= tbufsiz) { >- fail=fail && (1 + sys_write(f, b, tbufsiz)); >- n-=tbufsiz; >- b+=tbufsiz; >- } >+ const extern char *cmd_ptr; >+ const char *flag; >+ const char **val; >+ char *buf; >+ int maxtok = max_token(cmd_ptr); >+ int i = 0; >+ int err = 0; >+ bool ok; >+ int rc; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; > } > >- if (n>0) { >- memcpy(tarbuf+tp, b, n); >- tp+=n; >+ ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL); >+ if (!ok) { >+ DBG(0, ("tar <c|x>[IXFbganN] [options] <tar file> [path list]\n")); >+ err = 1; >+ goto out; > } > >- return(fail ? writ : 0); >-} >- >-/**************************************************************************** >-Write zeros to buffer / tape >-****************************************************************************/ >+ flag = buf; >+ val = talloc_array(ctx, const char *, maxtok); >+ if (val == NULL) { >+ err = 1; >+ goto out; >+ } > >-static void dozerobuf(int f, int n) >-{ >- /* short routine just to write out n zeros to buffer - >- * used to round files to nearest block >- * and to do tar EOFs */ >- >- if (dry_run) >- return; >- >- if (n+tp >= tbufsiz) { >- memset(tarbuf+tp, 0, tbufsiz-tp); >- if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) { >- DEBUG(0, ("dozerobuf: sys_write fail\n")); >- return; >- } >- memset(tarbuf, 0, (tp+=n-tbufsiz)); >- } else { >- memset(tarbuf+tp, 0, n); >- tp+=n; >+ while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) { >+ val[i++] = buf; > } >-} > >-/**************************************************************************** >-Malloc tape buffer >-****************************************************************************/ >+ rc = tar_parse_args(&tar_ctx, flag, val, i); >+ if (rc != 0) { >+ DBG(0, ("parse_args failed\n")); >+ err = 1; >+ goto out; >+ } > >-static void initarbuf(void) >-{ >- /* initialize tar buffer */ >- tbufsiz=blocksize*TBLOCK; >- tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */ >+ rc = tar_process(&tar_ctx); >+ if (rc != 0) { >+ DBG(0, ("tar_process failed\n")); >+ err = 1; >+ goto out; >+ } > >- /* reset tar buffer pointer and tar file counter and total dumped */ >- tp=0; ntarf=0; ttarf=0; >+out: >+ talloc_free(ctx); >+ return err; > } > >-/**************************************************************************** >-Write two zero blocks at end of file >-****************************************************************************/ >- >-static void dotareof(int f) >+/** >+ * cmd_setmode - interactive command to set DOS attributes >+ * >+ * Read a filename and mode from the client command line and update >+ * the file DOS attributes. >+ */ >+int cmd_setmode(void) > { >- SMB_STRUCT_STAT stbuf; >- /* Two zero blocks at end of file, write out full buffer */ >- >- if (dry_run) >- return; >+ const extern char *cmd_ptr; >+ char *buf; >+ char *fname = NULL; >+ uint16 attr[2] = {0}; >+ int mode = ATTR_SET; >+ int err = 0; >+ bool ok; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; >+ } > >- (void) dozerobuf(f, TBLOCK); >- (void) dozerobuf(f, TBLOCK); >+ ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL); >+ if (!ok) { >+ DBG(0, ("setmode <filename> <[+|-]rsha>\n")); >+ err = 1; >+ goto out; >+ } > >- if (sys_fstat(f, &stbuf, false) == -1) { >- DEBUG(0, ("Couldn't stat file handle\n")); >- return; >+ fname = talloc_asprintf(ctx, >+ "%s%s", >+ client_get_cur_dir(), >+ buf); >+ if (fname == NULL) { >+ err = 1; >+ goto out; > } > >- /* Could be a pipe, in which case S_ISREG should fail, >- * and we should write out at full size */ >- if (tp > 0) { >- size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz; >- if (sys_write(f, tarbuf, towrite) != towrite) { >- DEBUG(0,("dotareof: sys_write fail\n")); >+ while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) { >+ const char *s = buf; >+ >+ while (*s) { >+ switch (*s++) { >+ case '+': >+ mode = ATTR_SET; >+ break; >+ case '-': >+ mode = ATTR_UNSET; >+ break; >+ case 'r': >+ attr[mode] |= FILE_ATTRIBUTE_READONLY; >+ break; >+ case 'h': >+ attr[mode] |= FILE_ATTRIBUTE_HIDDEN; >+ break; >+ case 's': >+ attr[mode] |= FILE_ATTRIBUTE_SYSTEM; >+ break; >+ case 'a': >+ attr[mode] |= FILE_ATTRIBUTE_ARCHIVE; >+ break; >+ default: >+ DBG(0, ("setmode <filename> <perm=[+|-]rsha>\n")); >+ err = 1; >+ goto out; >+ } > } > } >-} > >-/**************************************************************************** >-(Un)mangle DOS pathname, make nonabsolute >-****************************************************************************/ >+ if (attr[ATTR_SET] == 0 && attr[ATTR_UNSET] == 0) { >+ DBG(0, ("setmode <filename> <[+|-]rsha>\n")); >+ err = 1; >+ goto out; >+ } > >-static void fixtarname(char *tptr, const char *fp, size_t l) >-{ >- /* add a '.' to start of file name, convert from ugly dos \'s in path >- * to lovely unix /'s :-} */ >- *tptr++='.'; >- l--; >+ DBG(2, ("perm set %d %d\n", attr[ATTR_SET], attr[ATTR_UNSET])); > >- StrnCpy(tptr, fp, l-1); >- string_replace(tptr, '\\', '/'); >+ /* ignore return value: server might not store DOS attributes */ >+ set_remote_attr(fname, attr[ATTR_SET], ATTR_SET); >+ set_remote_attr(fname, attr[ATTR_UNSET], ATTR_UNSET); >+out: >+ talloc_free(ctx); >+ return err; > } > >-/**************************************************************************** >-Convert from decimal to octal string >-****************************************************************************/ >- >-static void oct_it (uint64_t value, int ndgs, char *p) >+/** >+ * tar_parse_args - parse and set tar command line arguments >+ * @flag: string pointing to tar options >+ * @val: number of tar arguments >+ * @valsize: table of arguments after the flags (number of element in val) >+ * >+ * tar arguments work in a weird way. For each flag f that takes a >+ * value v, the user is supposed to type: >+ * >+ * on the CLI: >+ * -Tf1f2f3 v1 v2 v3 TARFILE PATHS... >+ * >+ * in the interactive session: >+ * tar f1f2f3 v1 v2 v3 TARFILE PATHS... >+ * >+ * @flag has only flags (eg. "f1f2f3") and @val has the arguments >+ * (values) following them (eg. ["v1", "v2", "v3", "TARFILE", "PATH1", >+ * "PATH2"]). >+ * >+ * There are only 2 flags that take an arg: b and N. The other flags >+ * just change the semantic of PATH or TARFILE. >+ * >+ * PATH can be a list of included/excluded paths, the path to a file >+ * containing a list of included/excluded paths to use (F flag). If no >+ * PATH is provided, the whole share is used (/). >+ */ >+int tar_parse_args(struct tar* t, >+ const char *flag, >+ const char **val, >+ int valsize) > { >- /* Converts long to octal string, pads with leading zeros */ >- >- /* skip final null, but do final space */ >- --ndgs; >- p[--ndgs] = ' '; >- >- /* Loop does at least one digit */ >- do { >- p[--ndgs] = '0' + (char) (value & 7); >- value >>= 3; >- } while (ndgs > 0 && value != 0); >- >- /* Do leading zeros */ >- while (ndgs > 0) >- p[--ndgs] = '0'; >-} >- >-/**************************************************************************** >-Convert from octal string to long >-***************************************************************************/ >+ TALLOC_CTX *ctx; >+ bool do_read_list = false; >+ /* index of next value to use */ >+ int ival = 0; >+ int rc; >+ >+ if (t == NULL) { >+ DBG(0, ("Invalid tar context\n")); >+ return 1; >+ } > >-static long unoct(char *p, int ndgs) >-{ >- long value=0; >- /* Converts octal string to long, ignoring any non-digit */ >+ ctx = tar_reset_mem_context(t); >+ if (ctx == NULL) { >+ return 1; >+ } >+ /* >+ * Reset back some options - could be from interactive version >+ * all other modes are left as they are >+ */ >+ t->mode.operation = TAR_NO_OPERATION; >+ t->mode.selection = TAR_NO_SELECTION; >+ t->mode.dry = false; >+ t->to_process = false; >+ t->total_size = 0; >+ >+ while (flag[0] != '\0') { >+ switch(flag[0]) { >+ /* operation */ >+ case 'c': >+ if (t->mode.operation != TAR_NO_OPERATION) { >+ printf("Tar must be followed by only one of c or x.\n"); >+ return 1; >+ } >+ t->mode.operation = TAR_CREATE; >+ break; >+ case 'x': >+ if (t->mode.operation != TAR_NO_OPERATION) { >+ printf("Tar must be followed by only one of c or x.\n"); >+ return 1; >+ } >+ t->mode.operation = TAR_EXTRACT; >+ break; > >- while (--ndgs) { >- if (isdigit((int)*p)) >- value = (value << 3) | (long) (*p - '0'); >+ /* selection */ >+ case 'I': >+ if (t->mode.selection != TAR_NO_SELECTION) { >+ DBG(0,("Only one of I,X,F must be specified\n")); >+ return 1; >+ } >+ t->mode.selection = TAR_INCLUDE; >+ break; >+ case 'X': >+ if (t->mode.selection != TAR_NO_SELECTION) { >+ DBG(0,("Only one of I,X,F must be specified\n")); >+ return 1; >+ } >+ t->mode.selection = TAR_EXCLUDE; >+ break; >+ case 'F': >+ if (t->mode.selection != TAR_NO_SELECTION) { >+ DBG(0,("Only one of I,X,F must be specified\n")); >+ return 1; >+ } >+ t->mode.selection = TAR_INCLUDE; >+ do_read_list = true; >+ break; > >- p++; >- } >+ /* blocksize */ >+ case 'b': >+ if (ival >= valsize) { >+ DBG(0, ("Option b must be followed by a blocksize\n")); >+ return 1; >+ } > >- return value; >-} >+ if (tar_set_blocksize(t, atoi(val[ival]))) { >+ DBG(0, ("Option b must be followed by a valid blocksize\n")); >+ return 1; >+ } > >-/**************************************************************************** >-Compare two strings in a slash insensitive way, allowing s1 to match s2 >-if s1 is an "initial" string (up to directory marker). Thus, if s2 is >-a file in any subdirectory of s1, declare a match. >-***************************************************************************/ >+ ival++; >+ break; > >-static int strslashcmp(char *s1, char *s2) >-{ >- char *s1_0=s1; >+ /* incremental mode */ >+ case 'g': >+ t->mode.incremental = true; >+ break; > >- while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) || >- (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) { >- s1++; s2++; >- } >+ /* newer than */ >+ case 'N': >+ if (ival >= valsize) { >+ DBG(0, ("Option N must be followed by valid file name\n")); >+ return 1; >+ } > >- /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" >- string of s2. >- */ >- if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) >- return 0; >+ if (tar_set_newer_than(t, val[ival])) { >+ DBG(0,("Error setting newer-than time\n")); >+ return 1; >+ } > >- /* ignore trailing slash on s1 */ >- if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) >- return 0; >+ ival++; >+ break; > >- /* check for s1 is an "initial" string of s2 */ >- if ((*s2 == '/' || *s2 == '\\') && !*s1) >- return 0; >+ /* reset mode */ >+ case 'a': >+ t->mode.reset = true; >+ break; > >- return *s1-*s2; >-} >+ /* verbose */ >+ case 'q': >+ t->mode.verbose = true; >+ break; > >-/**************************************************************************** >-Ensure a remote path exists (make if necessary) >-***************************************************************************/ >+ /* regex match */ >+ case 'r': >+ t->mode.regex = true; >+ break; > >-static bool ensurepath(const char *fname) >-{ >- /* *must* be called with buffer ready malloc'ed */ >- /* ensures path exists */ >- >- char *partpath, *ffname; >- size_t fnamelen = strlen(fname)+1; >- const char *p=fname; >- char *basehack; >- char *saveptr; >- NTSTATUS status; >+ /* dry run mode */ >+ case 'n': >+ if (t->mode.operation != TAR_CREATE) { >+ DBG(0, ("n is only meaningful when creating a tar-file\n")); >+ return 1; >+ } > >- DEBUG(5, ( "Ensurepath called with: %s\n", fname)); >+ t->mode.dry = true; >+ DBG(0, ("dry_run set\n")); >+ break; > >- partpath = SMB_MALLOC(fnamelen); >- ffname = SMB_MALLOC(fnamelen); >+ default: >+ DBG(0,("Unknown tar option\n")); >+ return 1; >+ } > >- if ((partpath == NULL) || (ffname == NULL)){ >- DEBUG(0, ("Out of memory in ensurepath: %s\n", fname)); >- SAFE_FREE(partpath); >- SAFE_FREE(ffname); >- return(False); >+ flag++; > } > >- *partpath = 0; >+ /* no selection given? default selection is include */ >+ if (t->mode.selection == TAR_NO_SELECTION) { >+ t->mode.selection = TAR_INCLUDE; >+ } > >- /* fname copied to ffname so can strtok_r */ >+ if (valsize - ival < 1) { >+ DBG(0, ("No tar file given.\n")); >+ return 1; >+ } > >- strlcpy(ffname, fname, fnamelen); >+ /* handle TARFILE */ >+ t->tar_path = talloc_strdup(ctx, val[ival]); >+ if (t->tar_path == NULL) { >+ return 1; >+ } >+ ival++; > >- /* do a `basename' on ffname, so don't try and make file name directory */ >- if ((basehack=strrchr_m(ffname, '\\')) == NULL) { >- SAFE_FREE(partpath); >- SAFE_FREE(ffname); >- return True; >- } else { >- *basehack='\0'; >+ /* >+ * Make sure that dbf points to stderr if we are using stdout for >+ * tar output >+ */ >+ if (t->mode.operation == TAR_CREATE && strequal(t->tar_path, "-")) { >+ setup_logging("smbclient", DEBUG_STDERR); > } > >- p=strtok_r(ffname, "\\", &saveptr); >+ /* handle PATHs... */ > >- while (p) { >- strlcat(partpath, p, fnamelen); >+ /* flag F -> read file list */ >+ if (do_read_list) { >+ if (valsize - ival != 1) { >+ DBG(0,("Option F must be followed by exactly one filename.\n")); >+ return 1; >+ } > >- status = cli_chkpath(cli, partpath); >- if (!NT_STATUS_IS_OK(status)) { >- status = cli_mkdir(cli, partpath); >+ rc = tar_read_inclusion_file(t, val[ival]); >+ if (rc != 0) { >+ return 1; >+ } >+ ival++; >+ /* otherwise store all the PATHs on the command line */ >+ } else { >+ int i; >+ for (i = ival; i < valsize; i++) { >+ NTSTATUS status; >+ status = tar_add_selection_path(t, val[i]); > if (!NT_STATUS_IS_OK(status)) { >- SAFE_FREE(partpath); >- SAFE_FREE(ffname); >- DEBUG(0, ("Error mkdir %s\n", nt_errstr(status))); >- return False; >- } else { >- DEBUG(3, ("mkdirhiering %s\n", partpath)); >+ return 1; > } > } >- >- strlcat(partpath, "\\", fnamelen); >- p = strtok_r(NULL, "/\\", &saveptr); > } > >- SAFE_FREE(partpath); >- SAFE_FREE(ffname); >- return True; >+ t->to_process = true; >+ tar_dump(t); >+ return 0; > } > >-static int padit(char *buf, uint64_t bufsize, uint64_t padsize) >+/** >+ * tar_process - start processing archive >+ * >+ * The talloc context of the fields is freed at the end of the call. >+ */ >+int tar_process(struct tar *t) > { >- int berr= 0; >- int bytestowrite; >+ int rc = 0; >+ >+ if (t == NULL) { >+ DBG(0, ("Invalid tar context\n")); >+ return 1; >+ } > >- DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize)); >- memset(buf, 0, (size_t)bufsize); >- while( !berr && padsize > 0 ) { >- bytestowrite= (int)MIN(bufsize, padsize); >- berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite; >- padsize -= bytestowrite; >+ switch(t->mode.operation) { >+ case TAR_EXTRACT: >+ rc = tar_extract(t); >+ break; >+ case TAR_CREATE: >+ rc = tar_create(t); >+ break; >+ default: >+ DBG(0, ("Invalid tar state\n")); >+ rc = 1; > } > >- return berr; >+ t->to_process = false; >+ tar_free_mem_context(t); >+ DBG(5, ("tar_process done, err = %d\n", rc)); >+ return rc; > } > >-static void do_setrattr(char *name, uint16 attr, int set) >+/** >+ * tar_create - create archive and fetch files >+ */ >+static int tar_create(struct tar* t) > { >- uint16 oldattr; >+ int r; >+ int err = 0; > NTSTATUS status; >+ const char *mask; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; >+ } >+ >+ t->archive = archive_write_new(); >+ >+ if (!t->mode.dry) { >+ const int bsize = t->mode.blocksize * TAR_BLOCK_UNIT; >+ r = archive_write_set_bytes_per_block(t->archive, bsize); >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Can't use a block size of %d bytes", bsize)); >+ err = 1; >+ goto out; >+ } >+ >+ /* >+ * Use PAX restricted format which is not the most >+ * conservative choice but has useful extensions and is widely >+ * supported >+ */ >+ r = archive_write_set_format_pax_restricted(t->archive); >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Can't use pax restricted format: %s\n", >+ archive_error_string(t->archive))); >+ err = 1; >+ goto out; >+ } >+ >+ if (strequal(t->tar_path, "-")) { >+ r = archive_write_open_fd(t->archive, STDOUT_FILENO); >+ } else { >+ r = archive_write_open_filename(t->archive, t->tar_path); >+ } > >- if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) { >- return; >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Can't open %s: %s\n", t->tar_path, >+ archive_error_string(t->archive))); >+ err = 1; >+ goto out_close; >+ } > } > >- if (set == ATTRSET) { >- attr |= oldattr; >+ /* >+ * In inclusion mode, iterate on the inclusion list >+ */ >+ if (t->mode.selection == TAR_INCLUDE && t->path_list_size > 0) { >+ if (tar_create_from_list(t)) { >+ err = 1; >+ goto out_close; >+ } > } else { >- attr = oldattr & ~attr; >+ mask = talloc_asprintf(ctx, "%s\\*", client_get_cur_dir()); >+ if (mask == NULL) { >+ err = 1; >+ goto out_close; >+ } >+ DBG(5, ("tar_process do_list with mask: %s\n", mask)); >+ status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0, ("do_list fail %s\n", nt_errstr(status))); >+ err = 1; >+ goto out_close; >+ } > } > >- status = cli_setatr(cli, name, attr, 0); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(1, ("setatr failed: %s\n", nt_errstr(status))); >+out_close: >+ DBG(0, ("Total bytes received: %" PRIu64 "\n", t->total_size)); >+ >+ if (!t->mode.dry) { >+ r = archive_write_close(t->archive); >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Fatal: %s\n", archive_error_string(t->archive))); >+ err = 1; >+ goto out; >+ } > } >+out: >+ archive_write_free(t->archive); >+ talloc_free(ctx); >+ return err; > } > >-/**************************************************************************** >-append one remote file to the tar file >-***************************************************************************/ >- >-static NTSTATUS do_atar(const char *rname_in, char *lname, >- struct file_info *finfo1) >+/** >+ * tar_create_from_list - fetch from path list in include mode >+ */ >+static int tar_create_from_list(struct tar *t) > { >- uint16_t fnum = (uint16_t)-1; >- uint64_t nread=0; >- char ftype; >- file_info2 finfo; >- bool shallitime=True; >- char *data = NULL; >- int read_size = 65520; >- size_t datalen=0; >- char *rname = NULL; >- TALLOC_CTX *ctx = talloc_stackframe(); >- NTSTATUS status = NT_STATUS_OK; >- struct timespec tp_start; >- >- clock_gettime_mono(&tp_start); >+ int err = 0; >+ NTSTATUS status; >+ char *base; >+ const char *path, *mask, *start_dir; >+ int i; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; >+ } > >- data = SMB_MALLOC_ARRAY(char, read_size); >- if (!data) { >- DEBUG(0,("do_atar: out of memory.\n")); >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >+ start_dir = talloc_strdup(ctx, client_get_cur_dir()); >+ if (start_dir == NULL) { >+ err = 1; >+ goto out; > } > >- ftype = '0'; /* An ordinary file ... */ >+ for (i = 0; i < t->path_list_size; i++) { >+ path = t->path_list[i]; >+ base = NULL; >+ status = path_base_name(ctx, path, &base); >+ if (!NT_STATUS_IS_OK(status)) { >+ err = 1; >+ goto out; >+ } >+ mask = talloc_asprintf(ctx, "%s\\%s", >+ client_get_cur_dir(), path); >+ if (mask == NULL) { >+ err = 1; >+ goto out; >+ } >+ >+ DBG(5, ("incl. path='%s', base='%s', mask='%s'\n", >+ path, base ? base : "NULL", mask)); > >- ZERO_STRUCT(finfo); >+ if (base != NULL) { >+ base = talloc_asprintf(ctx, "%s%s\\", >+ client_get_cur_dir(), base); >+ if (base == NULL) { >+ err = 1; >+ goto out; >+ } >+ DBG(5, ("cd '%s' before do_list\n", base)); >+ client_set_cur_dir(base); >+ } >+ status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true); >+ if (base != NULL) { >+ client_set_cur_dir(start_dir); >+ } >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0, ("do_list failed on %s (%s)\n", path, nt_errstr(status))); >+ err = 1; >+ goto out; >+ } >+ } > >- finfo.size = finfo1 -> size; >- finfo.mode = finfo1 -> mode; >- finfo.uid = finfo1 -> uid; >- finfo.gid = finfo1 -> gid; >- finfo.mtime_ts = finfo1 -> mtime_ts; >- finfo.atime_ts = finfo1 -> atime_ts; >- finfo.ctime_ts = finfo1 -> ctime_ts; >+out: >+ talloc_free(ctx); >+ return err; >+} > >- if (dry_run) { >- DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name, >- (double)finfo.size)); >- shallitime=0; >- ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK); >- ntarf++; >- goto cleanup; >+/** >+ * get_file_callback - do_list callback >+ * >+ * Callback for client.c do_list(). Called for each file found on the >+ * share matching do_list mask. Recursively call do_list() with itself >+ * as callback when the current file is a directory. >+ */ >+static NTSTATUS get_file_callback(struct cli_state *cli, >+ struct file_info *finfo, >+ const char *dir) >+{ >+ NTSTATUS status = NT_STATUS_OK; >+ char *remote_name; >+ const char *initial_dir = client_get_cur_dir(); >+ bool skip = false; >+ int rc; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return NT_STATUS_NO_MEMORY; > } > >- rname = clean_name(ctx, rname_in); >- if (!rname) { >+ remote_name = talloc_asprintf(ctx, "%s%s", initial_dir, finfo->name); >+ if (remote_name == NULL) { > status = NT_STATUS_NO_MEMORY; >- goto cleanup; >+ goto out; > } > >- status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum); >+ if (strequal(finfo->name, "..") || strequal(finfo->name, ".")) { >+ goto out; >+ } >+ >+ status = tar_create_skip_path(&tar_ctx, remote_name, finfo, &skip); > if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0,("%s opening remote file %s (%s)\n", >- nt_errstr(status),rname, client_get_cur_dir())); >- goto cleanup; >+ goto out; > } > >- finfo.name = smb_xstrdup(rname); >- if (finfo.name == NULL) { >- DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n")); >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >+ if (skip) { >+ DBG(5, ("--- %s\n", remote_name)); >+ status = NT_STATUS_OK; >+ goto out; > } > >- DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode)); >+ if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) { >+ char *old_dir; >+ char *new_dir; >+ char *mask; >+ >+ old_dir = talloc_strdup(ctx, initial_dir); >+ new_dir = talloc_asprintf(ctx, "%s%s\\", >+ initial_dir, finfo->name); >+ if ((old_dir == NULL) || (new_dir == NULL)) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ mask = talloc_asprintf(ctx, "%s*", new_dir); >+ if (mask == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ >+ rc = tar_get_file(&tar_ctx, remote_name, finfo); >+ if (rc != 0) { >+ status = NT_STATUS_UNSUCCESSFUL; >+ goto out; >+ } > >- if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) { >- DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name)); >- shallitime=0; >- } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) { >- DEBUG(4, ("skipping %s - system bit is set\n", finfo.name)); >- shallitime=0; >- } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) { >- DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name)); >- shallitime=0; >+ client_set_cur_dir(new_dir); >+ do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true); >+ client_set_cur_dir(old_dir); > } else { >- bool wrote_tar_header = False; >- >- DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s", >- finfo.name, (double)finfo.size, lname)); >+ rc = tar_get_file(&tar_ctx, remote_name, finfo); >+ if (rc != 0) { >+ status = NT_STATUS_UNSUCCESSFUL; >+ goto out; >+ } >+ } > >- do { >- >- DEBUG(3,("nread=%.0f\n",(double)nread)); >- >- status = cli_read(cli, fnum, data, nread, >- read_size, &datalen); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0,("Error reading file %s : %s\n", >- rname, nt_errstr(status))); >- break; >- } >- >- nread += datalen; >- >- /* Only if the first read succeeds, write out the tar header. */ >- if (!wrote_tar_header) { >- /* write a tar header, don't bother with mode - just set to 100644 */ >- writetarheader(tarhandle, rname, finfo.size, >- finfo.mtime_ts.tv_sec, "100644 \0", ftype); >- wrote_tar_header = True; >- } >- >- /* if file size has increased since we made file size query, truncate >- read so tar header for this file will be correct. >- */ >- >- if (nread > finfo.size) { >- datalen -= nread - finfo.size; >- DEBUG(0,("File size change - truncating %s to %.0f bytes\n", >- finfo.name, (double)finfo.size)); >- } >- >- /* add received bits of file to buffer - dotarbuf will >- * write out in 512 byte intervals */ >- >- if (dotarbuf(tarhandle,data,datalen) != datalen) { >- DEBUG(0,("Error writing to tar file - %s\n", strerror(errno))); >- status = map_nt_error_from_unix(errno); >- break; >- } >- >- if ( (datalen == 0) && (finfo.size != 0) ) { >- status = NT_STATUS_UNSUCCESSFUL; >- DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname)); >- break; >- } >- >- datalen=0; >- } while ( nread < finfo.size ); >- >- if (wrote_tar_header) { >- /* pad tar file with zero's if we couldn't get entire file */ >- if (nread < finfo.size) { >- DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n", >- (double)finfo.size, (int)nread)); >- if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) { >- status = map_nt_error_from_unix(errno); >- DEBUG(0,("Error writing tar file - %s\n", strerror(errno))); >- } >- } >- >- /* round tar file to nearest block */ >- if (finfo.size % TBLOCK) >- dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK)); >+out: >+ talloc_free(ctx); >+ return status; >+} > >- ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK); >- ntarf++; >- } else { >- DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name)); >- shallitime=0; >- status = NT_STATUS_UNSUCCESSFUL; >- } >+/** >+ * tar_get_file - fetch a remote file to the local archive >+ * @full_dos_path: path to the file to fetch >+ * @finfo: attributes of the file to fetch >+ */ >+static int tar_get_file(struct tar *t, >+ const char *full_dos_path, >+ struct file_info *finfo) >+{ >+ extern struct cli_state *cli; >+ NTSTATUS status; >+ struct archive_entry *entry; >+ char *full_unix_path; >+ char buf[TAR_CLI_READ_SIZE]; >+ size_t len; >+ uint64_t off = 0; >+ uint16_t remote_fd = (uint16_t)-1; >+ int err = 0, r; >+ const bool isdir = finfo->mode & FILE_ATTRIBUTE_DIRECTORY; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; > } > >- cli_close(cli, fnum); >- fnum = -1; >+ DBG(5, ("+++ %s\n", full_dos_path)); > >- if (shallitime) { >- struct timespec tp_end; >- int this_time; >+ t->total_size += finfo->size; > >- /* if shallitime is true then we didn't skip */ >- if (tar_reset && !dry_run) >- (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET); >- >- clock_gettime_mono(&tp_end); >- this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000; >- get_total_time_ms += this_time; >- get_total_size += finfo.size; >- >- if (tar_noisy) { >- DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n", >- (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)), >- finfo.name)); >- } >- >- /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */ >- DEBUG(3,("(%g kb/s) (average %g kb/s)\n", >- finfo.size / MAX(0.001, (1.024*this_time)), >- get_total_size / MAX(0.001, (1.024*get_total_time_ms)))); >+ if (t->mode.dry) { >+ goto out; > } > >- cleanup: >- >- if (fnum != (uint16_t)-1) { >- cli_close(cli, fnum); >- fnum = -1; >+ if (t->mode.reset) { >+ /* ignore return value: server might not store DOS attributes */ >+ set_remote_attr(full_dos_path, FILE_ATTRIBUTE_ARCHIVE, ATTR_UNSET); > } >- TALLOC_FREE(ctx); >- SAFE_FREE(data); >- return status; >-} >- >-/**************************************************************************** >-Append single file to tar file (or not) >-***************************************************************************/ >- >-static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo, >- const char *dir) >-{ >- TALLOC_CTX *ctx = talloc_stackframe(); >- NTSTATUS status = NT_STATUS_OK; > >- if (strequal(finfo->name,"..") || strequal(finfo->name,".")) { >- status = NT_STATUS_OK; >- goto cleanup; >+ full_unix_path = talloc_asprintf(ctx, ".%s", full_dos_path); >+ if (full_unix_path == NULL) { >+ err = 1; >+ goto out; >+ } >+ string_replace(full_unix_path, '\\', '/'); >+ entry = archive_entry_new(); >+ archive_entry_copy_pathname(entry, full_unix_path); >+ archive_entry_set_filetype(entry, isdir ? AE_IFDIR : AE_IFREG); >+ archive_entry_set_atime(entry, >+ finfo->atime_ts.tv_sec, >+ finfo->atime_ts.tv_nsec); >+ archive_entry_set_mtime(entry, >+ finfo->mtime_ts.tv_sec, >+ finfo->mtime_ts.tv_nsec); >+ archive_entry_set_ctime(entry, >+ finfo->ctime_ts.tv_sec, >+ finfo->ctime_ts.tv_nsec); >+ archive_entry_set_perm(entry, isdir ? 0755 : 0644); >+ /* >+ * check if we can safely cast unsigned file size to libarchive >+ * signed size. Very unlikely problem (>9 exabyte file) >+ */ >+ if (finfo->size > INT64_MAX) { >+ DBG(0, ("Remote file %s too big\n", full_dos_path)); >+ goto out_entry; > } > >- /* Is it on the exclude list ? */ >- if (!tar_excl && clipn) { >- char *exclaim; >- >- DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir()))); >- >- exclaim = talloc_asprintf(ctx, >- "%s\\%s", >- client_get_cur_dir(), >- finfo->name); >- if (!exclaim) { >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >- } >+ archive_entry_set_size(entry, (int64_t)finfo->size); > >- DEBUG(5, ("...tar_re_search: %d\n", tar_re_search)); >+ r = archive_write_header(t->archive, entry); >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Fatal: %s\n", archive_error_string(t->archive))); >+ err = 1; >+ goto out_entry; >+ } > >- if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) || >- (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) { >- DEBUG(3,("Skipping file %s\n", exclaim)); >- TALLOC_FREE(exclaim); >- status = NT_STATUS_OK; >- goto cleanup; >- } >- TALLOC_FREE(exclaim); >+ if (isdir) { >+ DBG(5, ("get_file skip dir %s\n", full_dos_path)); >+ goto out_entry; > } > >- if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) { >- char *saved_curdir = NULL; >- char *new_cd = NULL; >- char *mtar_mask = NULL; >+ status = cli_open(cli, full_dos_path, O_RDONLY, DENY_NONE, &remote_fd); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0,("%s opening remote file %s\n", >+ nt_errstr(status), full_dos_path)); >+ goto out_entry; >+ } > >- saved_curdir = talloc_strdup(ctx, client_get_cur_dir()); >- if (!saved_curdir) { >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >+ do { >+ status = cli_read(cli, remote_fd, buf, off, sizeof(buf), &len); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0,("Error reading file %s : %s\n", >+ full_dos_path, nt_errstr(status))); >+ err = 1; >+ goto out_close; > } > >- DEBUG(5, ("strlen(cur_dir)=%d, \ >-strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", >- (int)strlen(saved_curdir), >- (int)strlen(finfo->name), finfo->name, saved_curdir)); >+ off += len; > >- new_cd = talloc_asprintf(ctx, >- "%s%s\\", >- client_get_cur_dir(), >- finfo->name); >- if (!new_cd) { >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >+ r = archive_write_data(t->archive, buf, len); >+ if (r < 0) { >+ DBG(0, ("Fatal: %s\n", archive_error_string(t->archive))); >+ err = 1; >+ goto out_close; > } >- client_set_cur_dir(new_cd); > >- DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir())); >+ } while (off < finfo->size); > >- /* write a tar directory, don't bother with mode - just >- * set it to 40755 */ >- writetarheader(tarhandle, client_get_cur_dir(), 0, >- finfo->mtime_ts.tv_sec, "040755 \0", '5'); >- if (tar_noisy) { >- DEBUG(0,(" directory %s\n", >- client_get_cur_dir())); >- } >- ntarf++; /* Make sure we have a file on there */ >- mtar_mask = talloc_asprintf(ctx, >- "%s*", >- client_get_cur_dir()); >- if (!mtar_mask) { >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >- } >- DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask)); >- do_list(mtar_mask, attribute, do_tar, False, True); >- client_set_cur_dir(saved_curdir); >- TALLOC_FREE(saved_curdir); >- TALLOC_FREE(new_cd); >- TALLOC_FREE(mtar_mask); >- } else { >- char *rname = talloc_asprintf(ctx, >- "%s%s", >- client_get_cur_dir(), >- finfo->name); >- if (!rname) { >- status = NT_STATUS_NO_MEMORY; >- goto cleanup; >- } >- status = do_atar(rname,finfo->name,finfo); >- TALLOC_FREE(rname); >- } >+out_close: >+ cli_close(cli, remote_fd); > >- cleanup: >- TALLOC_FREE(ctx); >- return status; >-} >+out_entry: >+ archive_entry_free(entry); > >-/**************************************************************************** >-Convert from UNIX to DOS file names >-***************************************************************************/ >+out: >+ talloc_free(ctx); >+ return err; >+} > >-static void unfixtarname(char *tptr, char *fp, int l, bool first) >+/** >+ * tar_extract - open archive and send files. >+ */ >+static int tar_extract(struct tar *t) > { >- /* remove '.' from start of file name, convert from unix /'s to >- * dos \'s in path. Kill any absolute path names. But only if first! >- */ >+ int err = 0; >+ int r; >+ struct archive_entry *entry; >+ const size_t bsize = t->mode.blocksize * TAR_BLOCK_UNIT; >+ int rc; >+ >+ t->archive = archive_read_new(); >+ archive_read_support_format_all(t->archive); >+ archive_read_support_filter_all(t->archive); >+ >+ if (strequal(t->tar_path, "-")) { >+ r = archive_read_open_fd(t->archive, STDIN_FILENO, bsize); >+ } else { >+ r = archive_read_open_filename(t->archive, t->tar_path, bsize); >+ } > >- DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l)); >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Can't open %s : %s\n", t->tar_path, >+ archive_error_string(t->archive))); >+ err = 1; >+ goto out; >+ } > >- if (first) { >- if (*fp == '.') { >- fp++; >- l--; >+ for (;;) { >+ NTSTATUS status; >+ bool skip; >+ r = archive_read_next_header(t->archive, &entry); >+ if (r == ARCHIVE_EOF) { >+ break; > } >- if (*fp == '\\' || *fp == '/') { >- fp++; >- l--; >+ if (r == ARCHIVE_WARN) { >+ DBG(0, ("Warning: %s\n", archive_error_string(t->archive))); > } >- if (l <= 0) { >- return; >+ if (r == ARCHIVE_FATAL) { >+ DBG(0, ("Fatal: %s\n", archive_error_string(t->archive))); >+ err = 1; >+ goto out; > } >- } > >- strlcpy(tptr, fp, l); >- string_replace(tptr, '/', '\\'); >-} >- >-/**************************************************************************** >-Move to the next block in the buffer, which may mean read in another set of >-blocks. FIXME, we should allow more than one block to be skipped. >-****************************************************************************/ >- >-static int next_block(char *ltarbuf, char **bufferp, int bufsiz) >-{ >- int bufread, total = 0; >- >- DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp)); >- *bufferp += TBLOCK; >- total = TBLOCK; >- >- if (*bufferp >= (ltarbuf + bufsiz)) { >- >- DEBUG(5, ("Reading more data into ltarbuf ...\n")); >- >- /* >- * Bugfix from Bob Boehmer <boehmer@worldnet.att.net> >- * Fixes bug where read can return short if coming from >- * a pipe. >- */ >- >- bufread = read(tarhandle, ltarbuf, bufsiz); >- total = bufread; >- >- while (total < bufsiz) { >- if (bufread < 0) { /* An error, return false */ >- return (total > 0 ? -2 : bufread); >- } >- if (bufread == 0) { >- if (total <= 0) { >- return -2; >- } >- break; >- } >- bufread = read(tarhandle, <arbuf[total], bufsiz - total); >- total += bufread; >+ status = tar_extract_skip_path(t, entry, &skip); >+ if (!NT_STATUS_IS_OK(status)) { >+ err = 1; >+ goto out; >+ } >+ if (skip) { >+ DBG(5, ("--- %s\n", archive_entry_pathname(entry))); >+ continue; > } > >- DEBUG(5, ("Total bytes read ... %i\n", total)); >- >- *bufferp = ltarbuf; >- } >- >- return(total); >-} >- >-/* Skip a file, even if it includes a long file name? */ >-static int skip_file(int skipsize) >-{ >- int dsize = skipsize; >- >- DEBUG(5, ("Skiping file. Size = %i\n", skipsize)); >- >- /* FIXME, we should skip more than one block at a time */ >+ DBG(5, ("+++ %s\n", archive_entry_pathname(entry))); > >- while (dsize > 0) { >- if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) { >- DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); >- return(False); >+ rc = tar_send_file(t, entry); >+ if (rc != 0) { >+ err = 1; >+ goto out; > } >- dsize -= TBLOCK; > } > >- return(True); >+out: >+ r = archive_read_free(t->archive); >+ if (r != ARCHIVE_OK) { >+ DBG(0, ("Can't close %s : %s\n", t->tar_path, >+ archive_error_string(t->archive))); >+ err = 1; >+ } >+ return err; > } > >-/************************************************************* >- Get a file from the tar file and store it. >- When this is called, tarbuf already contains the first >- file block. This is a bit broken & needs fixing. >-**************************************************************/ >- >-static int get_file(file_info2 finfo) >+/** >+ * tar_send_file - send @entry to the remote server >+ * @entry: current archive entry >+ * >+ * Handle the creation of the parent directories and transfer the >+ * entry to a new remote file. >+ */ >+static int tar_send_file(struct tar *t, struct archive_entry *entry) > { >- uint16_t fnum = (uint16_t) -1; >- int dsize = 0, bpos = 0; >- uint64_t rsize = 0, pos = 0; >+ extern struct cli_state *cli; >+ char *dos_path; >+ char *full_path; > NTSTATUS status; >+ uint16_t remote_fd = (uint16_t) -1; >+ int err = 0; >+ int flags = O_RDWR | O_CREAT | O_TRUNC; >+ mode_t mode = archive_entry_filetype(entry); >+ int rc; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; >+ } > >- DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size)); >+ dos_path = talloc_strdup(ctx, archive_entry_pathname(entry)); >+ if (dos_path == NULL) { >+ err = 1; >+ goto out; >+ } >+ fix_unix_path(dos_path, true); > >- if (!ensurepath(finfo.name)) { >- DEBUG(0, ("abandoning restore\n")); >- return False; >+ full_path = talloc_strdup(ctx, client_get_cur_dir()); >+ if (full_path == NULL) { >+ err = 1; >+ goto out; >+ } >+ full_path = talloc_strdup_append(full_path, dos_path); >+ if (full_path == NULL) { >+ err = 1; >+ goto out; > } > >- status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0, ("abandoning restore\n")); >- return False; >+ if (mode != AE_IFREG && mode != AE_IFDIR) { >+ DBG(0, ("Skipping non-dir & non-regular file %s\n", full_path)); >+ goto out; > } > >- /* read the blocks from the tar file and write to the remote file */ >+ rc = make_remote_path(full_path); >+ if (rc != 0) { >+ err = 1; >+ goto out; >+ } > >- rsize = finfo.size; /* This is how much to write */ >+ if (mode == AE_IFDIR) { >+ goto out; >+ } > >- while (rsize > 0) { >+ status = cli_open(cli, full_path, flags, DENY_NONE, &remote_fd); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0, ("Error opening remote file %s: %s\n", >+ full_path, nt_errstr(status))); >+ err = 1; >+ goto out; >+ } > >- /* We can only write up to the end of the buffer */ >- dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */ >- dsize = MIN(dsize, rsize); /* Should be only what is left */ >- DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos)); >+ for (;;) { >+ const void *buf; >+ size_t len; >+ off_t off; >+ int r; > >- status = cli_writeall(cli, fnum, 0, >- (uint8_t *)(buffer_p + bpos), pos, >- dsize, NULL); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0, ("Error writing remote file: %s\n", >- nt_errstr(status))); >- return 0; >+ r = archive_read_data_block(t->archive, &buf, &len, &off); >+ if (r == ARCHIVE_EOF) { >+ break; > } >- >- rsize -= dsize; >- pos += dsize; >- >- /* Now figure out how much to move in the buffer */ >- >- /* FIXME, we should skip more than one block at a time */ >- >- /* First, skip any initial part of the part written that is left over */ >- /* from the end of the first TBLOCK */ >- >- if ((bpos) && ((bpos + dsize) >= TBLOCK)) { >- dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */ >- bpos = 0; >- >- if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */ >- DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); >- return False; >- } >+ if (r == ARCHIVE_WARN) { >+ DBG(0, ("Warning: %s\n", archive_error_string(t->archive))); >+ } >+ if (r == ARCHIVE_FATAL) { >+ DBG(0, ("Fatal: %s\n", archive_error_string(t->archive))); >+ err = 1; >+ goto close_out; > } > >- /* >- * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>. >- * If the file being extracted is an exact multiple of >- * TBLOCK bytes then we don't want to extract the next >- * block from the tarfile here, as it will be done in >- * the caller of get_file(). >- */ >- >- while (((rsize != 0) && (dsize >= TBLOCK)) || >- ((rsize == 0) && (dsize > TBLOCK))) { >- >- if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { >- DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); >- return False; >- } >- >- dsize -= TBLOCK; >+ status = cli_writeall(cli, remote_fd, 0, buf, off, len, NULL); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0, ("Error writing remote file %s: %s\n", >+ full_path, nt_errstr(status))); >+ err = 1; >+ goto close_out; > } >- bpos = dsize; > } > >- /* Now close the file ... */ >- status = cli_close(cli, fnum); >+close_out: >+ status = cli_close(cli, remote_fd); > if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0, ("Error %s closing remote file\n", >- nt_errstr(status))); >- return(False); >+ DBG(0, ("Error losing remote file %s: %s\n", >+ full_path, nt_errstr(status))); >+ err = 1; > } > >- /* Now we update the creation date ... */ >- DEBUG(5, ("Updating creation date on %s\n", finfo.name)); >+out: >+ talloc_free(ctx); >+ return err; >+} > >- if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) { >- if (tar_real_noisy) { >- DEBUG(0, ("Could not set time on file: %s\n", finfo.name)); >- /*return(False); */ /* Ignore, as Win95 does not allow changes */ >+/** >+ * tar_add_selection_path - add a path to the path list >+ * @path: path to add >+ */ >+static NTSTATUS tar_add_selection_path(struct tar *t, const char *path) >+{ >+ const char **list; >+ TALLOC_CTX *ctx = t->talloc_ctx; >+ if (!t->path_list) { >+ t->path_list = str_list_make_empty(ctx); >+ if (t->path_list == NULL) { >+ return NT_STATUS_NO_MEMORY; > } >+ t->path_list_size = 0; >+ } >+ >+ /* cast to silence gcc const-qual warning */ >+ list = str_list_add((void *)t->path_list, path); >+ if (list == NULL) { >+ return NT_STATUS_NO_MEMORY; > } >+ t->path_list = discard_const_p(char *, list); >+ t->path_list_size++; >+ fix_unix_path(t->path_list[t->path_list_size - 1], true); > >- ntarf++; >- DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size)); >- return(True); >+ return NT_STATUS_OK; > } > >-/* Create a directory. We just ensure that the path exists and return as there >- is no file associated with a directory >-*/ >-static int get_dir(file_info2 finfo) >+/** >+ * tar_set_blocksize - set block size in TAR_BLOCK_UNIT >+ */ >+static int tar_set_blocksize(struct tar *t, int size) > { >- DEBUG(0, ("restore directory %s\n", finfo.name)); >- >- if (!ensurepath(finfo.name)) { >- DEBUG(0, ("Problems creating directory\n")); >- return(False); >+ if (size <= 0 || size > TAR_MAX_BLOCK_SIZE) { >+ return 1; > } >- ntarf++; >- return(True); >+ >+ t->mode.blocksize = size; >+ >+ return 0; > } > >-/* Get a file with a long file name ... first file has file name, next file >- has the data. We only want the long file name, as the loop in do_tarput >- will deal with the rest. >-*/ >-static char *get_longfilename(file_info2 finfo) >+/** >+ * tar_set_newer_than - set date threshold of saved files >+ * @filename: local path to a file >+ * >+ * Only files newer than the modification time of @filename will be >+ * saved. >+ * >+ * Note: this function set the global variable newer_than from >+ * client.c. Thus the time is not a field of the tar structure. See >+ * cmd_newer() to change its value from an interactive session. >+ */ >+static int tar_set_newer_than(struct tar *t, const char *filename) > { >- /* finfo.size here is the length of the filename as written by the "/./@LongLink" name >- * header call. */ >- int namesize = finfo.size + strlen(client_get_cur_dir()) + 2; >- char *longname = (char *)SMB_MALLOC(namesize); >- int offset = 0, left = finfo.size; >- bool first = True; >- >- DEBUG(5, ("Restoring a long file name: %s\n", finfo.name)); >- DEBUG(5, ("Len = %.0f\n", (double)finfo.size)); >+ extern time_t newer_than; >+ SMB_STRUCT_STAT stbuf; >+ int rc; > >- if (longname == NULL) { >- DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize)); >- return(NULL); >+ rc = sys_stat(filename, &stbuf, false); >+ if (rc != 0) { >+ DBG(0, ("Error setting newer-than time\n")); >+ return 1; > } > >- /* First, add cur_dir to the long file name */ >+ newer_than = convert_timespec_to_time_t(stbuf.st_ex_mtime); >+ DBG(1, ("Getting files newer than %s\n", time_to_asc(newer_than))); >+ return 0; >+} > >- if (strlen(client_get_cur_dir()) > 0) { >- strncpy(longname, client_get_cur_dir(), namesize); >- offset = strlen(client_get_cur_dir()); >+/** >+ * tar_read_inclusion_file - set path list from file >+ * @filename: path to the list file >+ * >+ * Read and add each line of @filename to the path list. >+ */ >+static int tar_read_inclusion_file(struct tar *t, const char* filename) >+{ >+ char *line; >+ int err = 0; >+ int fd; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { >+ return 1; > } > >- /* Loop through the blocks picking up the name */ >+ fd = open(filename, O_RDONLY); >+ if (fd < 0) { >+ DBG(0, ("Can't open inclusion file '%s': %s\n", filename, strerror(errno))); >+ err = 1; >+ goto out; >+ } > >- while (left > 0) { >- if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) { >- DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); >- SAFE_FREE(longname); >- return(NULL); >+ for (line = afdgets(fd, ctx, 0); >+ line != NULL; >+ line = afdgets(fd, ctx, 0)) { >+ NTSTATUS status; >+ status = tar_add_selection_path(t, line); >+ if (!NT_STATUS_IS_OK(status)) { >+ err = 1; >+ goto out; > } >- >- unfixtarname(longname + offset, buffer_p, >- namesize - offset, first--); >- DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p)); >- >- offset += TBLOCK; >- left -= TBLOCK; > } > >- return(longname); >+ close(fd); >+ >+out: >+ talloc_free(ctx); >+ return err; > } > >-static void do_tarput(void) >+/** >+ * tar_path_in_list - check whether @path is in the path list >+ * @path: path to find >+ * @reverse: when true also try to find path list element in @path >+ * @_is_in_list: set if @path is in the path list >+ * >+ * Look at each path of the path list and set @_is_in_list if @path is a >+ * subpath of one of them. >+ * >+ * If you want /path to be in the path list (path/a/, path/b/) set >+ * @reverse to true to try to match the other way around. >+ */ >+static NTSTATUS tar_path_in_list(struct tar *t, const char *path, >+ bool reverse, bool *_is_in_list) > { >- file_info2 finfo; >- struct timespec tp_start; >- char *longfilename = NULL, linkflag; >- int skip = False; >+ int i; >+ const char *p; >+ const char *pattern; > >- ZERO_STRUCT(finfo); >+ if (path == NULL || path[0] == '\0') { >+ *_is_in_list = false; >+ return NT_STATUS_OK; >+ } > >- clock_gettime_mono(&tp_start); >- DEBUG(5, ("RJS do_tarput called ...\n")); >+ p = skip_useless_char_in_path(path); > >- buffer_p = tarbuf + tbufsiz; /* init this to force first read */ >+ for (i = 0; i < t->path_list_size; i++) { >+ bool is_in_list; >+ NTSTATUS status; > >- /* Now read through those files ... */ >- while (True) { >- /* Get us to the next block, or the first block first time around */ >- if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) { >- DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno))); >- SAFE_FREE(longfilename); >- return; >+ pattern = skip_useless_char_in_path(t->path_list[i]); >+ status = is_subpath(p, pattern, &is_in_list); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; > } >+ if (reverse && !is_in_list) { >+ status = is_subpath(pattern, p, &is_in_list); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ } >+ if (is_in_list) { >+ *_is_in_list = true; >+ return NT_STATUS_OK; >+ } >+ } > >- DEBUG(5, ("Reading the next header ...\n")); >- >- switch (readtarheader((union hblock *) buffer_p, >- &finfo, client_get_cur_dir())) { >- case -2: /* Hmm, not good, but not fatal */ >- DEBUG(0, ("Skipping %s...\n", finfo.name)); >- if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) { >- DEBUG(0, ("Short file, bailing out...\n")); >- SAFE_FREE(longfilename); >- return; >- } >- break; >+ *_is_in_list = false; >+ return NT_STATUS_OK; >+} > >- case -1: >- DEBUG(0, ("abandoning restore, -1 from read tar header\n")); >- SAFE_FREE(longfilename); >- return; >+/** >+ * tar_extract_skip_path - check if @entry should be skipped >+ * @entry: current tar entry >+ * @_skip: set true if path should be skipped, otherwise false >+ * >+ * Skip predicate for tar extraction (archive to server) only. >+ */ >+static NTSTATUS tar_extract_skip_path(struct tar *t, >+ struct archive_entry *entry, >+ bool *_skip) >+{ >+ const char *fullpath = archive_entry_pathname(entry); >+ bool in = true; > >- case 0: /* chksum is zero - looks like an EOF */ >- DEBUG(0, ("tar: restored %d files and directories\n", ntarf)); >- SAFE_FREE(longfilename); >- return; /* Hmmm, bad here ... */ >+ if (t->path_list_size <= 0) { >+ *_skip = false; >+ return NT_STATUS_OK; >+ } > >- default: >- /* No action */ >- break; >+ if (t->mode.regex) { >+ in = mask_match_list(fullpath, t->path_list, t->path_list_size, true); >+ } else { >+ NTSTATUS status = tar_path_in_list(t, fullpath, false, &in); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; > } >+ } > >- /* Now, do we have a long file name? */ >- if (longfilename != NULL) { >- SAFE_FREE(finfo.name); /* Free the space already allocated */ >- finfo.name = longfilename; >- longfilename = NULL; >- } >+ if (t->mode.selection == TAR_EXCLUDE) { >+ *_skip = in; >+ } else { >+ *_skip = !in; >+ } > >- /* Well, now we have a header, process the file ... */ >- /* Should we skip the file? We have the long name as well here */ >- skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) || >- (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True))); >+ return NT_STATUS_OK; >+} > >- DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name)); >- if (skip) { >- skip_file(finfo.size); >- continue; >+/** >+ * tar_create_skip_path - check if @fullpath shoud be skipped >+ * @fullpath: full remote path of the current file >+ * @finfo: remote file attributes >+ * @_skip: returned skip not >+ * >+ * Skip predicate for tar creation (server to archive) only. >+ */ >+static NTSTATUS tar_create_skip_path(struct tar *t, >+ const char *fullpath, >+ const struct file_info *finfo, >+ bool *_skip) >+{ >+ /* syntaxic sugar */ >+ const mode_t mode = finfo->mode; >+ const bool isdir = mode & FILE_ATTRIBUTE_DIRECTORY; >+ const bool exclude = t->mode.selection == TAR_EXCLUDE; >+ bool in = true; >+ >+ if (!isdir) { >+ >+ /* 1. if we dont want X and we have X, skip */ >+ if (!t->mode.system && (mode & FILE_ATTRIBUTE_SYSTEM)) { >+ *_skip = true; >+ return NT_STATUS_OK; > } > >- /* We only get this far if we should process the file */ >- linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag; >- switch (linkflag) { >- case '0': /* Should use symbolic names--FIXME */ >- /* >- * Skip to the next block first, so we can get the file, FIXME, should >- * be in get_file ... >- * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net> >- * Fixes bug where file size in tarfile is zero. >- */ >- if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) { >- DEBUG(0, ("Short file, bailing out...\n")); >- return; >- } >- if (!get_file(finfo)) { >- DEBUG(0, ("Abandoning restore\n")); >- return; >- } >- break; >- case '5': >- if (!get_dir(finfo)) { >- DEBUG(0, ("Abandoning restore \n")); >- return; >- } >- break; >- case 'L': >- SAFE_FREE(longfilename); >- longfilename = get_longfilename(finfo); >- if (!longfilename) { >- DEBUG(0, ("abandoning restore\n")); >- return; >- } >- DEBUG(5, ("Long file name: %s\n", longfilename)); >- break; >+ if (!t->mode.hidden && (mode & FILE_ATTRIBUTE_HIDDEN)) { >+ *_skip = true; >+ return NT_STATUS_OK; >+ } > >- default: >- skip_file(finfo.size); /* Don't handle these yet */ >- break; >+ /* 2. if we only want archive and it's not, skip */ >+ >+ if (t->mode.incremental && !(mode & FILE_ATTRIBUTE_ARCHIVE)) { >+ *_skip = true; >+ return NT_STATUS_OK; > } > } >-} > >-/* >- * samba interactive commands >- */ >+ /* 3. is it in the selection list? */ > >-/**************************************************************************** >-Blocksize command >-***************************************************************************/ >+ /* >+ * tar_create_from_list() use the include list as a starting >+ * point, no need to check >+ */ >+ if (!exclude) { >+ *_skip = false; >+ return NT_STATUS_OK; >+ } > >-int cmd_block(void) >-{ >- TALLOC_CTX *ctx = talloc_tos(); >- char *buf; >- int block; >+ /* we are now in exclude mode */ > >- if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) { >- DEBUG(0, ("blocksize <n>\n")); >- return 1; >+ /* no matter the selection, no list => include everything */ >+ if (t->path_list_size <= 0) { >+ *_skip = false; >+ return NT_STATUS_OK; > } > >- block=atoi(buf); >- if (block < 0 || block > 65535) { >- DEBUG(0, ("blocksize out of range")); >- return 1; >+ if (t->mode.regex) { >+ in = mask_match_list(fullpath, t->path_list, t->path_list_size, true); >+ } else { >+ bool reverse = isdir && !exclude; >+ NTSTATUS status = tar_path_in_list(t, fullpath, reverse, &in); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } > } >+ *_skip = in; > >- blocksize=block; >- DEBUG(2,("blocksize is now %d\n", blocksize)); >- return 0; >+ return NT_STATUS_OK; > } > >-/**************************************************************************** >-command to set incremental / reset mode >-***************************************************************************/ >- >-int cmd_tarmode(void) >+/** >+ * tar_to_process - return true if @t is ready to be processed >+ * >+ * @t is ready if it properly parsed command line arguments. >+ */ >+bool tar_to_process(struct tar *t) > { >- TALLOC_CTX *ctx = talloc_tos(); >- char *buf; >+ if (t == NULL) { >+ DBG(0, ("Invalid tar context\n")); >+ return false; >+ } >+ return t->to_process; >+} > >- while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) { >- if (strequal(buf, "full")) >- tar_inc=False; >- else if (strequal(buf, "inc")) >- tar_inc=True; >- else if (strequal(buf, "reset")) >- tar_reset=True; >- else if (strequal(buf, "noreset")) >- tar_reset=False; >- else if (strequal(buf, "system")) >- tar_system=True; >- else if (strequal(buf, "nosystem")) >- tar_system=False; >- else if (strequal(buf, "hidden")) >- tar_hidden=True; >- else if (strequal(buf, "nohidden")) >- tar_hidden=False; >- else if (strequal(buf, "verbose") || strequal(buf, "noquiet")) >- tar_noisy=True; >- else if (strequal(buf, "quiet") || strequal(buf, "noverbose")) >- tar_noisy=False; >+/** >+ * skip_useless_char_in_path - skip leading slashes/dots >+ * >+ * Skip leading slashes, backslashes and dot-slashes. >+ */ >+static const char* skip_useless_char_in_path(const char *p) >+{ >+ while (p) { >+ if (*p == '/' || *p == '\\') { >+ p++; >+ } >+ else if (p[0] == '.' && (p[1] == '/' || p[1] == '\\')) { >+ p += 2; >+ } > else >- DEBUG(0, ("tarmode: unrecognised option %s\n", buf)); >- TALLOC_FREE(buf); >+ return p; > } >- >- DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n", >- tar_inc ? "incremental" : "full", >- tar_system ? "system" : "nosystem", >- tar_hidden ? "hidden" : "nohidden", >- tar_reset ? "reset" : "noreset", >- tar_noisy ? "verbose" : "quiet")); >- return 0; >+ return p; > } > >-/**************************************************************************** >-Feeble attrib command >-***************************************************************************/ >- >-int cmd_setmode(void) >+/** >+ * is_subpath - check if the path @sub is a subpath of @full. >+ * @sub: path to test >+ * @full: container path >+ * @_subpath_match: set true if @sub is a subpath of @full, otherwise false >+ * >+ * String comparaison is case-insensitive. >+ */ >+static NTSTATUS is_subpath(const char *sub, const char *full, >+ bool *_subpath_match) > { >- TALLOC_CTX *ctx = talloc_tos(); >- char *q; >- char *buf; >- char *fname = NULL; >- uint16 attra[2]; >- int direct=1; >+ NTSTATUS status = NT_STATUS_OK; >+ int len = 0; >+ char *f, *s; >+ TALLOC_CTX *tmp_ctx = talloc_new(NULL); >+ if (tmp_ctx == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } > >- attra[0] = attra[1] = 0; >+ f = strlower_talloc(tmp_ctx, full); >+ if (f == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out_ctx_free; >+ } >+ string_replace(f, '\\', '/'); >+ s = strlower_talloc(tmp_ctx, sub); >+ if (f == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out_ctx_free; >+ } >+ string_replace(s, '\\', '/'); > >- if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) { >- DEBUG(0, ("setmode <filename> <[+|-]rsha>\n")); >- return 1; >+ /* find the point where sub and full diverge */ >+ while ((*f != '\0') && (*s != '\0') && (*f == *s)) { >+ f++; >+ s++; >+ len++; > } > >- fname = talloc_asprintf(ctx, >- "%s%s", >- client_get_cur_dir(), >- buf); >- if (!fname) { >- return 1; >+ if ((*f == '\0') && (*s == '\0')) { >+ *_subpath_match = true; /* sub and full match */ >+ goto out_ctx_free; > } > >- while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) { >- q=buf; >- >- while(*q) { >- switch (*q++) { >- case '+': >- direct=1; >- break; >- case '-': >- direct=0; >- break; >- case 'r': >- attra[direct]|=FILE_ATTRIBUTE_READONLY; >- break; >- case 'h': >- attra[direct]|=FILE_ATTRIBUTE_HIDDEN; >- break; >- case 's': >- attra[direct]|=FILE_ATTRIBUTE_SYSTEM; >- break; >- case 'a': >- attra[direct]|=FILE_ATTRIBUTE_ARCHIVE; >- break; >- default: >- DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n")); >- return 1; >- } >- } >+ if ((*f == '\0') && (len > 0) && (*(f - 1) == '/')) { >+ /* sub diverges from full at path separator */ >+ *_subpath_match = true; >+ goto out_ctx_free; > } > >- if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) { >- DEBUG(0, ("setmode <filename> <[+|-]rsha>\n")); >- return 1; >+ if ((*s == '\0') && (strcmp(f, "/") == 0)) { >+ /* full diverges from sub with trailing slash only */ >+ *_subpath_match = true; >+ goto out_ctx_free; > } > >- DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET])); >- do_setrattr(fname, attra[ATTRSET], ATTRSET); >- do_setrattr(fname, attra[ATTRRESET], ATTRRESET); >- return 0; >+ if ((*s == '/') && (*f == '\0')) { >+ /* sub diverges from full with extra path component */ >+ *_subpath_match = true; >+ goto out_ctx_free; >+ } >+ *_subpath_match = false; >+ >+out_ctx_free: >+ talloc_free(tmp_ctx); >+out: >+ return status; > } > > /** >- Convert list of tokens to array; dependent on above routine. >- Uses the global cmd_ptr from above - bit of a hack. >-**/ >- >-static char **toktocliplist(int *ctok, const char *sep) >+ * set_remote_attr - set DOS attributes of a remote file >+ * @filename: path to the file name >+ * @new_attr: attribute bit mask to use >+ * @mode: one of ATTR_SET or ATTR_UNSET >+ * >+ * Update the file attributes with the one provided. >+ */ >+static int set_remote_attr(const char *filename, uint16 new_attr, int mode) > { >- char *s=(char *)cmd_ptr; >- int ictok=0; >- char **ret, **iret; >- >- if (!sep) >- sep = " \t\n\r"; >+ extern struct cli_state *cli; >+ uint16 old_attr; >+ NTSTATUS status; > >- while(*s && strchr_m(sep,*s)) >- s++; >+ status = cli_getatr(cli, filename, &old_attr, NULL, NULL); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0, ("cli_getatr failed: %s\n", nt_errstr(status))); >+ return 1; >+ } > >- /* nothing left? */ >- if (!*s) >- return(NULL); >+ if (mode == ATTR_SET) { >+ new_attr |= old_attr; >+ } else { >+ new_attr = old_attr & ~new_attr; >+ } > >- do { >- ictok++; >- while(*s && (!strchr_m(sep,*s))) >- s++; >- while(*s && strchr_m(sep,*s)) >- *s++=0; >- } while(*s); >- >- *ctok=ictok; >- s=(char *)cmd_ptr; >- >- if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1))) >- return NULL; >- >- while(ictok--) { >- *iret++=s; >- if (ictok > 0) { >- while(*s++) >- ; >- while(!*s) >- s++; >- } >+ status = cli_setatr(cli, filename, new_attr, 0); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(1, ("cli_setatr failed: %s\n", nt_errstr(status))); >+ return 1; > } > >- ret[*ctok] = NULL; >- return ret; >+ return 0; > } > >-/**************************************************************************** >-Principal command for creating / extracting >-***************************************************************************/ > >-int cmd_tar(void) >+/** >+ * make_remote_path - recursively make remote dirs >+ * @full_path: full hierarchy to create >+ * >+ * Create @full_path and each parent directories as needed. >+ */ >+static int make_remote_path(const char *full_path) > { >- TALLOC_CTX *ctx = talloc_tos(); >- char *buf; >- char **argl = NULL; >- int argcl = 0; >- int ret; >- >- if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) { >- DEBUG(0,("tar <c|x>[IXbgan] <filename>\n")); >+ extern struct cli_state *cli; >+ char *path; >+ char *subpath; >+ char *state; >+ char *last_backslash; >+ char *p; >+ int len; >+ NTSTATUS status; >+ int err = 0; >+ TALLOC_CTX *ctx = talloc_new(NULL); >+ if (ctx == NULL) { > return 1; > } > >- argl=toktocliplist(&argcl, NULL); >- if (!tar_parseargs(argcl, argl, buf, 0)) { >- SAFE_FREE(argl); >- return 1; >+ subpath = talloc_strdup(ctx, full_path); >+ if (subpath == NULL) { >+ err = 1; >+ goto out; >+ } >+ path = talloc_strdup(ctx, full_path); >+ if (path == NULL) { >+ err = 1; >+ goto out; > } >+ len = talloc_get_size(path) - 1; > >- ret = process_tar(); >- SAFE_FREE(argl); >- return ret; >-} >+ last_backslash = strrchr_m(path, '\\'); >+ if (last_backslash == NULL) { >+ goto out; >+ } > >-/**************************************************************************** >-Command line (option) version >-***************************************************************************/ >+ *last_backslash = 0; > >-int process_tar(void) >-{ >- TALLOC_CTX *ctx = talloc_tos(); >- int rc = 0; >- initarbuf(); >- switch(tar_type) { >- case 'x': >+ subpath[0] = 0; >+ p = strtok_r(path, "\\", &state); > >-#if 0 >- do_tarput2(); >-#else >- do_tarput(); >-#endif >- SAFE_FREE(tarbuf); >- close(tarhandle); >- break; >- case 'r': >- case 'c': >- if (clipn && tar_excl) { >- int i; >- char *tarmac = NULL; >- >- for (i=0; i<clipn; i++) { >- DEBUG(5,("arg %d = %s\n", i, cliplist[i])); >- >- if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') { >- *(cliplist[i]+strlen(cliplist[i])-1)='\0'; >- } >- >- if (strrchr_m(cliplist[i], '\\')) { >- char *p; >- char saved_char; >- char *saved_dir = talloc_strdup(ctx, >- client_get_cur_dir()); >- if (!saved_dir) { >- return 1; >- } >- >- if (*cliplist[i]=='\\') { >- tarmac = talloc_strdup(ctx, >- cliplist[i]); >- } else { >- tarmac = talloc_asprintf(ctx, >- "%s%s", >- client_get_cur_dir(), >- cliplist[i]); >- } >- if (!tarmac) { >- return 1; >- } >- /* >- * Strip off the last \\xxx >- * xxx element of tarmac to set >- * it as current directory. >- */ >- p = strrchr_m(tarmac, '\\'); >- if (!p) { >- return 1; >- } >- saved_char = p[1]; >- p[1] = '\0'; >- >- client_set_cur_dir(tarmac); >- >- /* >- * Restore the character we >- * just replaced to >- * put the pathname >- * back as it was. >- */ >- p[1] = saved_char; >- >- DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac)); >- do_list(tarmac,attribute,do_tar, False, True); >- >- client_set_cur_dir(saved_dir); >- >- TALLOC_FREE(saved_dir); >- TALLOC_FREE(tarmac); >- } else { >- tarmac = talloc_asprintf(ctx, >- "%s%s", >- client_get_cur_dir(), >- cliplist[i]); >- if (!tarmac) { >- return 1; >- } >- DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac)); >- do_list(tarmac,attribute,do_tar, False, True); >- TALLOC_FREE(tarmac); >- } >- } >- } else { >- char *mask = talloc_asprintf(ctx, >- "%s\\*", >- client_get_cur_dir()); >- if (!mask) { >- return 1; >- } >- DEBUG(5, ("process_tar, do_list with mask: %s\n", mask)); >- do_list(mask,attribute,do_tar,False, True); >- TALLOC_FREE(mask); >+ while (p != NULL) { >+ strlcat(subpath, p, len); >+ status = cli_chkpath(cli, subpath); >+ if (!NT_STATUS_IS_OK(status)) { >+ status = cli_mkdir(cli, subpath); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG(0, ("Can't mkdir %s: %s\n", subpath, nt_errstr(status))); >+ err = 1; >+ goto out; > } >+ DBG(3, ("mkdir %s\n", subpath)); >+ } > >- if (ntarf) { >- dotareof(tarhandle); >- } >- close(tarhandle); >- SAFE_FREE(tarbuf); >+ strlcat(subpath, "\\", len); >+ p = strtok_r(NULL, "/\\", &state); > >- DEBUG(0, ("tar: dumped %d files and directories\n", ntarf)); >- DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf)); >- break; > } > >- if (must_free_cliplist) { >- int i; >- for (i = 0; i < clipn; ++i) { >- SAFE_FREE(cliplist[i]); >- } >- SAFE_FREE(cliplist); >- cliplist = NULL; >- clipn = 0; >- must_free_cliplist = False; >- } >- return rc; >+out: >+ talloc_free(ctx); >+ return err; > } > >-/**************************************************************************** >-Find a token (filename) in a clip list >-***************************************************************************/ >- >-static int clipfind(char **aret, int ret, char *tok) >+/** >+ * tar_reset_mem_context - reset talloc context associated with @t >+ * >+ * At the start of the program the context is NULL so a new one is >+ * allocated. On the following runs (interactive session only), simply >+ * free the children. >+ */ >+static TALLOC_CTX *tar_reset_mem_context(struct tar *t) > { >- if (aret==NULL) >- return 0; >- >- /* ignore leading slashes or dots in token */ >- while(strchr_m("/\\.", *tok)) >- tok++; >- >- while(ret--) { >- char *pkey=*aret++; >- >- /* ignore leading slashes or dots in list */ >- while(strchr_m("/\\.", *pkey)) >- pkey++; >+ tar_free_mem_context(t); >+ t->talloc_ctx = talloc_new(NULL); >+ return t->talloc_ctx; >+} > >- if (!strslashcmp(pkey, tok)) >- return 1; >+/** >+ * tar_free_mem_context - free talloc context associated with @t >+ */ >+static void tar_free_mem_context(struct tar *t) >+{ >+ if (t->talloc_ctx) { >+ talloc_free(t->talloc_ctx); >+ t->talloc_ctx = NULL; >+ t->path_list_size = 0; >+ t->path_list = NULL; >+ t->tar_path = NULL; > } >- return 0; > } > >-/**************************************************************************** >-Read list of files to include from the file and initialize cliplist >-accordingly. >-***************************************************************************/ >+#define XSET(v) [v] = #v >+#define XTABLE(v, t) DBG(2, ("DUMP:%-20.20s = %s\n", #v, t[v])) >+#define XBOOL(v) DBG(2, ("DUMP:%-20.20s = %d\n", #v, v ? 1 : 0)) >+#define XSTR(v) DBG(2, ("DUMP:%-20.20s = %s\n", #v, v ? v : "NULL")) >+#define XINT(v) DBG(2, ("DUMP:%-20.20s = %d\n", #v, v)) >+#define XUINT64(v) DBG(2, ("DUMP:%-20.20s = %" PRIu64 "\n", #v, v)) > >-static int read_inclusion_file(char *filename) >+/** >+ * tar_dump - dump tar structure on stdout >+ */ >+static void tar_dump(struct tar *t) > { >- XFILE *inclusion = NULL; >- char buf[PATH_MAX + 1]; >- char *inclusion_buffer = NULL; >- int inclusion_buffer_size = 0; >- int inclusion_buffer_sofar = 0; >- char *p; >- char *tmpstr; > int i; >- int error = 0; >+ const char* op[] = { >+ XSET(TAR_NO_OPERATION), >+ XSET(TAR_CREATE), >+ XSET(TAR_EXTRACT), >+ }; >+ >+ const char* sel[] = { >+ XSET(TAR_NO_SELECTION), >+ XSET(TAR_INCLUDE), >+ XSET(TAR_EXCLUDE), >+ }; >+ >+ XBOOL(t->to_process); >+ XTABLE(t->mode.operation, op); >+ XTABLE(t->mode.selection, sel); >+ XINT(t->mode.blocksize); >+ XBOOL(t->mode.hidden); >+ XBOOL(t->mode.system); >+ XBOOL(t->mode.incremental); >+ XBOOL(t->mode.reset); >+ XBOOL(t->mode.dry); >+ XBOOL(t->mode.verbose); >+ XUINT64(t->total_size); >+ XSTR(t->tar_path); >+ XINT(t->path_list_size); >+ >+ for (i = 0; t->path_list && t->path_list[i]; i++) { >+ DBG(2, ("DUMP: t->path_list[%2d] = %s\n", i, t->path_list[i])); >+ } >+ >+ DBG(2, ("DUMP:t->path_list @ %p (%d elem)\n", t->path_list, i)); >+} >+#undef XSET >+#undef XTABLE >+#undef XBOOL >+#undef XSTR >+#undef XINT > >- clipn = 0; >- buf[PATH_MAX] = '\0'; /* guarantee null-termination */ >- if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) { >- /* XXX It would be better to include a reason for failure, but without >- * autoconf, it's hard to use strerror, sys_errlist, etc. >- */ >- DEBUG(0,("Unable to open inclusion file %s\n", filename)); >+/** >+ * max_token - return upper limit for the number of token in @str >+ * >+ * The result is not exact, the actual number of token might be less >+ * than what is returned. >+ */ >+static int max_token(const char *str) >+{ >+ const char *s; >+ int nb = 0; >+ >+ if (str == NULL) { > return 0; > } > >- while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) { >- if (inclusion_buffer == NULL) { >- inclusion_buffer_size = 1024; >- if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) { >- DEBUG(0,("failure allocating buffer to read inclusion file\n")); >- error = 1; >- break; >- } >+ s = str; >+ while (s[0] != '\0') { >+ if (isspace((int)s[0])) { >+ nb++; > } >+ s++; >+ } > >- if (buf[strlen(buf)-1] == '\n') { >- buf[strlen(buf)-1] = '\0'; >- } >+ nb++; > >- if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) { >- inclusion_buffer_size *= 2; >- inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size); >- if (!inclusion_buffer) { >- DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n", >- inclusion_buffer_size)); >- error = 1; >- break; >- } >- } >+ return nb; >+} >+ >+/** >+ * fix_unix_path - convert @path to a DOS path >+ * @path: path to convert >+ * @removeprefix: if true, remove leading ./ or /. >+ */ >+static char *fix_unix_path(char *path, bool do_remove_prefix) >+{ >+ char *from = path, *to = path; > >- strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar); >- inclusion_buffer_sofar += strlen(buf) + 1; >- clipn++; >+ if (path == NULL || path[0] == '\0') { >+ return path; > } >- x_fclose(inclusion); > >- if (! error) { >- /* Allocate an array of clipn + 1 char*'s for cliplist */ >- cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1); >- if (cliplist == NULL) { >- DEBUG(0,("failure allocating memory for cliplist\n")); >- error = 1; >- } else { >- cliplist[clipn] = NULL; >- p = inclusion_buffer; >- for (i = 0; (! error) && (i < clipn); i++) { >- /* set current item to NULL so array will be null-terminated even if >- * malloc fails below. */ >- cliplist[i] = NULL; >- if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) { >- DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i)); >- error = 1; >- } else { >- unfixtarname(tmpstr, p, strlen(p) + 1, True); >- cliplist[i] = tmpstr; >- if ((p = strchr_m(p, '\000')) == NULL) { >- DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n")); >- abort(); >- } >- } >- ++p; >- } >- must_free_cliplist = True; >+ /* remove prefix: >+ * ./path => path >+ * /path => path >+ */ >+ if (do_remove_prefix) { >+ /* /path */ >+ if (path[0] == '/' || path[0] == '\\') { >+ from += 1; >+ } >+ >+ /* ./path */ >+ if (path[1] != '\0' && path[0] == '.' && (path[1] == '/' || path[1] == '\\')) { >+ from += 2; > } > } > >- SAFE_FREE(inclusion_buffer); >- if (error) { >- if (cliplist) { >- char **pp; >- /* We know cliplist is always null-terminated */ >- for (pp = cliplist; *pp; ++pp) { >- SAFE_FREE(*pp); >- } >- SAFE_FREE(cliplist); >- cliplist = NULL; >- must_free_cliplist = False; >+ /* replace / with \ */ >+ while (from[0] != '\0') { >+ if (from[0] == '/') { >+ to[0] = '\\'; >+ } else { >+ to[0] = from[0]; > } >- return 0; >+ >+ from++; >+ to++; > } >+ to[0] = '\0'; > >- /* cliplist and its elements are freed at the end of process_tar. */ >- return 1; >+ return path; > } > >-/**************************************************************************** >-Parse tar arguments. Sets tar_type, tar_excl, etc. >-***************************************************************************/ >- >-int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind) >+/** >+ * path_base_name - return @path basename >+ * >+ * If @path doesn't contain any directory separator return NULL. >+ */ >+static NTSTATUS path_base_name(TALLOC_CTX *ctx, const char *path, char **_base) > { >- int newOptind = Optind; >- char tar_clipfl='\0'; >+ char *base = NULL; >+ int last = -1; >+ int i; > >- /* Reset back to defaults - could be from interactive version >- * reset mode and archive mode left as they are though >- */ >- tar_type='\0'; >- tar_excl=True; >- dry_run=False; >- >- while (*Optarg) { >- switch(*Optarg++) { >- case 'c': >- tar_type='c'; >- break; >- case 'x': >- if (tar_type=='c') { >- printf("Tar must be followed by only one of c or x.\n"); >- return 0; >- } >- tar_type='x'; >- break; >- case 'b': >- if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) { >- DEBUG(0,("Option b must be followed by valid blocksize\n")); >- return 0; >- } else { >- Optind++; >- newOptind++; >- } >- break; >- case 'g': >- tar_inc=True; >- break; >- case 'N': >- if (Optind>=argc) { >- DEBUG(0,("Option N must be followed by valid file name\n")); >- return 0; >- } else { >- SMB_STRUCT_STAT stbuf; >- >- if (sys_stat(argv[Optind], &stbuf, >- false) == 0) { >- newer_than = convert_timespec_to_time_t( >- stbuf.st_ex_mtime); >- DEBUG(1,("Getting files newer than %s", >- time_to_asc(newer_than))); >- newOptind++; >- Optind++; >- } else { >- DEBUG(0,("Error setting newer-than time\n")); >- return 0; >- } >- } >- break; >- case 'a': >- tar_reset=True; >- break; >- case 'q': >- tar_noisy=False; >- break; >- case 'I': >- if (tar_clipfl) { >- DEBUG(0,("Only one of I,X,F must be specified\n")); >- return 0; >- } >- tar_clipfl='I'; >- break; >- case 'X': >- if (tar_clipfl) { >- DEBUG(0,("Only one of I,X,F must be specified\n")); >- return 0; >- } >- tar_clipfl='X'; >- break; >- case 'F': >- if (tar_clipfl) { >- DEBUG(0,("Only one of I,X,F must be specified\n")); >- return 0; >- } >- tar_clipfl='F'; >- break; >- case 'r': >- DEBUG(0, ("tar_re_search set\n")); >- tar_re_search = True; >- break; >- case 'n': >- if (tar_type == 'c') { >- DEBUG(0, ("dry_run set\n")); >- dry_run = True; >- } else { >- DEBUG(0, ("n is only meaningful when creating a tar-file\n")); >- return 0; >- } >- break; >- default: >- DEBUG(0,("Unknown tar option\n")); >- return 0; >+ for (i = 0; path[i]; i++) { >+ if (path[i] == '\\' || path[i] == '/') { >+ last = i; > } > } > >- if (!tar_type) { >- printf("Option T must be followed by one of c or x.\n"); >- return 0; >- } >- >- /* tar_excl is true if cliplist lists files to be included. >- * Both 'I' and 'F' mean include. */ >- tar_excl=tar_clipfl!='X'; >- >- if (tar_clipfl=='F') { >- if (argc-Optind-1 != 1) { >- DEBUG(0,("Option F must be followed by exactly one filename.\n")); >- return 0; >- } >- newOptind++; >- /* Optind points at the tar output file, Optind+1 at the inclusion file. */ >- if (! read_inclusion_file(argv[Optind+1])) { >- return 0; >- } >- } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */ >- char *tmpstr; >- char **tmplist; >- int clipcount; >- >- cliplist=argv+Optind+1; >- clipn=argc-Optind-1; >- clipcount = clipn; >- >- if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) { >- DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn)); >- return 0; >+ if (last >= 0) { >+ base = talloc_strdup(ctx, path); >+ if (base == NULL) { >+ return NT_STATUS_NO_MEMORY; > } > >- for (clipcount = 0; clipcount < clipn; clipcount++) { >+ base[last] = 0; >+ } > >- DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount])); >+ *_base = base; >+ return NT_STATUS_OK; >+} > >- if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) { >- DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount)); >- SAFE_FREE(tmplist); >- return 0; >- } >+#else > >- unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True); >- tmplist[clipcount] = tmpstr; >- DEBUG(5, ("Processed an item, %s\n", tmpstr)); >+#define NOT_IMPLEMENTED DEBUG(0, ("tar mode not compiled. build with --with-libarchive\n")) > >- DEBUG(5, ("Cliplist is: %s\n", cliplist[0])); >- } >+int cmd_block(void) >+{ >+ NOT_IMPLEMENTED; >+ return 1; >+} > >- cliplist = tmplist; >- must_free_cliplist = True; >+int cmd_tarmode(void) >+{ >+ NOT_IMPLEMENTED; >+ return 1; >+} > >- newOptind += clipn; >- } >+int cmd_setmode(void) >+{ >+ NOT_IMPLEMENTED; >+ return 1; >+} > >- if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') { >- /* Doing regular expression seaches not from an inclusion file. */ >- clipn=argc-Optind-1; >- cliplist=argv+Optind+1; >- newOptind += clipn; >- } >+int cmd_tar(void) >+{ >+ NOT_IMPLEMENTED; >+ return 1; >+} > >- if (Optind>=argc || !strcmp(argv[Optind], "-")) { >- /* Sets tar handle to either 0 or 1, as appropriate */ >- tarhandle=(tar_type=='c'); >- /* >- * Make sure that dbf points to stderr if we are using stdout for >- * tar output >- */ >- if (tarhandle == 1) { >- setup_logging("smbclient", DEBUG_STDERR); >- } >- if (!argv[Optind]) { >- DEBUG(0,("Must specify tar filename\n")); >- return 0; >- } >- if (!strcmp(argv[Optind], "-")) { >- newOptind++; >- } >+int tar_process(struct tar* tar) >+{ >+ NOT_IMPLEMENTED; >+ return 1; >+} > >- } else { >- if (tar_type=='c' && dry_run) { >- tarhandle=-1; >- } else if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY, 0)) == -1) >- || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0)) { >- DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno))); >- return(0); >- } >- newOptind++; >- } >+int tar_parse_args(struct tar *tar, const char *flag, const char **val, int valsize) >+{ >+ NOT_IMPLEMENTED; >+ return 1; >+} > >- return newOptind; >+bool tar_to_process(struct tar *tar) >+{ >+ return false; >+} >+ >+struct tar *tar_get_ctx() >+{ >+ return NULL; > } >+ >+#endif >diff --git source3/client/clitar_proto.h source3/client/clitar_proto.h >new file mode 100644 >index 0000000..6520476 >--- /dev/null >+++ source3/client/clitar_proto.h >@@ -0,0 +1,34 @@ >+/* >+ * Unix SMB/CIFS implementation. >+ * Tar backup command extension >+ * Copyright (C) Aurélien Aptel 2013 >+ * >+ * 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/>. >+ */ >+ >+#ifndef _CLITAR_PROTO_H_ >+#define _CLITAR_PROTO_H_ >+ >+struct tar; >+ >+int cmd_block(void); >+int cmd_tarmode(void); >+int cmd_setmode(void); >+int cmd_tar(void); >+int tar_process(struct tar* tar); >+int tar_parse_args(struct tar *tar, const char *flag, const char **val, int valsize); >+bool tar_to_process(struct tar *tar); >+struct tar *tar_get_ctx(void); >+ >+#endif /* _CLITAR_PROTO_H_ */ >diff --git source3/include/clitar.h source3/include/clitar.h >deleted file mode 100644 >index 69267fb..0000000 >--- source3/include/clitar.h >+++ /dev/null >@@ -1,40 +0,0 @@ >-/* >- * Unix SMB/CIFS implementation. >- * clitar file format >- * Copyright (C) Andrew Tridgell 2000 >- * >- * 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/>. >- */ >- >-#ifndef _CLITAR_H >-#define _CLITAR_H >- >-#define TBLOCK 512 >-#define NAMSIZ 100 >-union hblock { >- char dummy[TBLOCK]; >- struct header { >- char name[NAMSIZ]; >- char mode[8]; >- char uid[8]; >- char gid[8]; >- char size[12]; >- char mtime[12]; >- char chksum[8]; >- char linkflag; >- char linkname[NAMSIZ]; >- } dbuf; >-}; >- >-#endif /* _CLITAR_H */ >diff --git source3/selftest/tests.py source3/selftest/tests.py >index 85d67d6..c2bedaf 100755 >--- source3/selftest/tests.py >+++ source3/selftest/tests.py >@@ -197,8 +197,39 @@ for env in ["s3dc"]: > # encrypted > plantestsuite("samba3.blackbox.smbclient_s3.crypt (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_s3.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$USERID', '$LOCAL_PATH', '$PREFIX', smbclient3, wbinfo, net, configuration, "-e"]) > >- # Test smbclient/tarmode >- plantestsuite("samba3.blackbox.smbclient_tarmode (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_tarmode.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', '$PREFIX', smbclient3, configuration]) >+ >+ # >+ # tar command tests >+ # >+ >+ # find config.h >+ try: >+ config_h = os.environ["CONFIG_H"] >+ except KeyError: >+ config_h = os.path.join(samba4bindir, "default/include/config.h") >+ >+ # see if libarchive is supported >+ f = open(config_h, 'r') >+ try: >+ have_libarchive = ("HAVE_LIBARCHIVE 1" in f.read()) >+ finally: >+ f.close() >+ >+ # tar command enabled only if built with libarchive >+ if have_libarchive: >+ # Test smbclient/tarmode >+ plantestsuite("samba3.blackbox.smbclient_tarmode (%s)" % env, env, >+ [os.path.join(samba3srcdir, "script/tests/test_smbclient_tarmode.sh"), >+ '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', >+ '$LOCAL_PATH', '$PREFIX', smbclient3, configuration]) >+ >+ # Test suite for new smbclient/tar with libarchive (GSoC 13) >+ plantestsuite("samba3.blackbox.smbclient_tar (%s)" % env, env, >+ [os.path.join(samba3srcdir, "script/tests/test_smbclient_tarmode.pl"), >+ '-n', '$SERVER', '-i', '$SERVER_IP', '-s', 'tmp', >+ '-u', '$USERNAME', '-p', '$PASSWORD', '-l', '$LOCAL_PATH', >+ '-d', '$PREFIX', '-b', smbclient3, >+ '--subunit', '--', configuration]) > > #TODO encrypted against member, with member creds, and with DC creds > plantestsuite("samba3.blackbox.net.misc", "s3dc:local", >diff --git source3/wscript source3/wscript >index 271314d..fba0133 100644 >--- source3/wscript >+++ source3/wscript >@@ -43,6 +43,7 @@ def set_options(opt): > opt.SAMBA3_ADD_OPTION('dmapi', default=None) # None means autodetection > opt.SAMBA3_ADD_OPTION('fam', default=None) # None means autodetection > opt.SAMBA3_ADD_OPTION('profiling-data', default=False) >+ opt.SAMBA3_ADD_OPTION('libarchive', default=None) > > opt.SAMBA3_ADD_OPTION('cluster-support', default=None) > >@@ -193,6 +194,17 @@ main() { > elif check_for_fam: > Logs.warn('no suitable FAM library found') > >+ # check for libarchive (tar command in smbclient) >+ # None means autodetect, True/False means enable/disable >+ conf.env['archive_lib'] = '' >+ if Options.options.with_libarchive is not False: >+ libarchive_mandatory = Options.options.with_libarchive == True >+ Logs.info("Checking for libarchive existence") >+ if conf.CHECK_BUNDLED_SYSTEM('libarchive', minversion='3.1.2'): >+ conf.env['archive_lib'] = 'libarchive' >+ elif libarchive_mandatory: >+ conf.fatal('libarchive support requested, but no suitable pkgconfig found') >+ > # check for DMAPI libs > Logs.info("Checking for DMAPI library existence") > conf.env['dmapi_lib'] = '' >diff --git source3/wscript_build source3/wscript_build >index e0432bf..9943bbe 100755 >--- source3/wscript_build >+++ source3/wscript_build >@@ -1261,7 +1261,8 @@ bld.SAMBA3_BINARY('client/smbclient', > libsmb > msrpc3 > RPC_NDR_SRVSVC >- cli_smb_common''') >+ cli_smb_common >+ ''' + bld.env['archive_lib']) > > bld.SAMBA3_BINARY('net', > source=NET_SRC,
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 9667
: 9713 |
9714