[SCM] Samba Shared Repository - branch master updated

Tim Beale timbeale at samba.org
Mon Jan 7 03:30:04 UTC 2019


The branch, master has been updated
       via  01079b50a94 tests: Run SMB Py bindings tests against testenv with SMBv1-disabled
       via  7f731d7642d tests: Avoid hardcoding domain in test
       via  c95a869e852 tests: Completely replace s4 connection in smb tests
       via  9a3e640bbaa s3:pylibsmb: Add .deltree() API to SMB py bindings
       via  ea00215d538 s3:pylibsmb: Minor refactor to py_cli_list() variables
       via  1d0d1a758ba s3:libsmb: Avoid duplicated code by making cli_read_sink() public
       via  d7c7d6203ba s3:pylibsmb: Add .loadfile() API to SMB py bindings
       via  0af78faf5c9 s3:pylibsmb: Add .savefile() API to SMB py bindings
       via  e4d1d53597a s3:pylibsmb: Free async .list() memory
       via  6bcd64a4f14 s3:pylibsmb: Make s3 and s4 listings return the same dict
       via  5f1ed29d6b7 s3:pylibsmb: Don't return '.'/'..' in .list()
       via  3ac4866d15a s3:pylibsmb: Make .list() work for SMBv2
       via  057161039f4 s3:pylibsmb: Split code out into do_listing() helper
       via  2033208a4a9 s3:pylibsmb: Split out code into list_helper()
       via  40f4e52732f s3:pylibsmb: Consolidate .readdir()/.list() py bindings API
       via  c4dee3437af s3:pylibsmb: Add .chkpath() API to SMB py bindings
       via  6a40e538df5 s3:pylibsmb: Add .mkdir(), .rmdir() APIS to SMB py bindings
       via  8096419c712 s3:pylibsmb: Add .unlink() API to SMB Py bindings
       via  6fff2c26dac s3:pylibsmb: Make lp a mandatory param for the SMB connection
      from  b7d350b45bc s3:smbd: Fix build on AIX

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 01079b50a9413d85eb8295159f036248bdd0edf2
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 14:50:53 2018 +1300

    tests: Run SMB Py bindings tests against testenv with SMBv1-disabled
    
    Sanity-check that the SMBv2 connection actually works by running it
    against a testenv with SMBv1 disabled.
    
    I've dropped 'local' from the ad_dc target, because it shouldn't be
    needed. We're trying to test the client-side SMB connection, so running
    it without 'local' is probably a better test.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Tim Beale <timbeale at samba.org>
    Autobuild-Date(master): Mon Jan  7 04:29:51 CET 2019 on sn-devel-144

commit 7f731d7642de3b1e4cbe43dcd354f0e9dc902787
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 10:04:09 2018 +1300

    tests: Avoid hardcoding domain in test
    
    Currently the sysvol domain directory is hard-coded, so the tests can
    only ever run on the ad_dc.
    
    This patch makes things marginally better by using the REALM
    environmental variable instead. This allows us to run it against other
    testenvs (like the SMBv2-only restoredc).
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c95a869e85201f836c1579e0f50021e3ffc4cbe0
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 14:42:30 2018 +1300

    tests: Completely replace s4 connection in smb tests
    
    This test now uses the s3 python bindings completely, so we can remove
    the s4 connection.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 9a3e640bbaa45f2b6cd2e9a2ff514fdfa26759d0
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 13:45:46 2018 +1300

    s3:pylibsmb: Add .deltree() API to SMB py bindings
    
    This basically re-uses the underlying functionality of existing APIs in
    order to support a .deltree() API, i.e.
    - we use the .list() functionality (i.e. do_listing()) to traverse every
      item in the given directory.
    - we then use either .unlink() (i.e. unlink_file()) or .rmdir() (i.e.
      remove_dir()) to delete the individual item.
    - sub-directories are handled recursively, by repeating the process.
    
    Note that the .deltree() API is currently only really used for testing
    (and deleting GPO files). So the recursion is never going to be
    excessive.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit ea00215d53891215e20531f75a7ec7e5dec3df5e
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 13:47:46 2018 +1300

    s3:pylibsmb: Minor refactor to py_cli_list() variables
    
    Add a define for the file attribute mask (we'll reuse it in a subsequent
    patch), and make the variable type explicit.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 1d0d1a758bacaf160f320f39156923ab4c273fd5
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Jan 3 17:48:39 2019 +1300

    s3:libsmb: Avoid duplicated code by making cli_read_sink() public
    
    cli_read_sink() and pull_helper() were essentially identical. By making
    cli_read_sink() non-static, we can delete the latter.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit d7c7d6203ba85785d23481f3926aa6ddb29a7311
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 5 15:08:09 2018 +1300

    s3:pylibsmb: Add .loadfile() API to SMB py bindings
    
    Add a .loadfile API to read a file's contents. This provides a
    convenient way to read a file and is consistent with the existing
    source4 API, which is used by things like the GPO python code and the
    ntacls backup.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 0af78faf5c9424514ba5bc0baa18701c65c884e7
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Tue Dec 11 09:34:42 2018 +1300

    s3:pylibsmb: Add .savefile() API to SMB py bindings
    
    This provides a simple API for writing a file's contents and makes the
    s3 API consistent with the s4 API.
    
    All the async APIs here support SMBv2 so we don't need to use the sync
    APIs at all.
    
    Note that we have the choice here of using either cli_write_send() or
    cli_push_send(). I chose the latter, because that's what smbclient uses.
    It also appears to handle writing a large file better (i.e. one that
    exceeds the max write size of the underlying connection).
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit e4d1d53597ac093d56ad9d528e2e580e626ab359
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 12:23:42 2018 +1300

    s3:pylibsmb: Free async .list() memory
    
    finfos was being allocated but never freed.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 6bcd64a4f14332de3259204b78c5b68988e98b6f
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Tue Dec 4 16:25:10 2018 +1300

    s3:pylibsmb: Make s3 and s4 listings return the same dict
    
    Make the python dictionary generated by the s3 .list() use the same keys
    as the current source4 dict. The reason for using the source4 dict is
    that other python code depends on these keys (e.g. ntacls.py), whereas
    the source3 API is currently unused.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 5f1ed29d6b7388e5ce0ad0023daa39cb8c4cb4dc
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Tue Dec 4 16:03:35 2018 +1300

    s3:pylibsmb: Don't return '.'/'..' in .list()
    
    The source4 .list() API wasn't doing this. This makes source3 and source4
    have *almost* equivalent functionality, so we can start usign the
    source3 API in the tests.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 3ac4866d15af3ddebdfa2d9611fc094bf357bc3e
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 12:08:24 2018 +1300

    s3:pylibsmb: Make .list() work for SMBv2
    
    In order for .list() to work on an SMBv2 connection we need to
    use the synchronous API.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 057161039f45baf4acb582a6a8e6d41e3de317bd
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 11:28:22 2018 +1300

    s3:pylibsmb: Split code out into do_listing() helper
    
    We'll want to reuse the directory listing function for the deltree API.
    This patch splits the bulk of the work out into a do_listing() helper
    function.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 2033208a4a936912343f4dcc23576687a2a82c3a
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Tue Dec 4 15:43:53 2018 +1300

    s3:pylibsmb: Split out code into list_helper()
    
    Refactor out the code so we can re-use it for the synchronous API as
    well.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 40f4e52732f73b8b7b90d3176e4a4536ef6bc678
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Tue Dec 4 09:15:30 2018 +1300

    s3:pylibsmb: Consolidate .readdir()/.list() py bindings API
    
    Rename the .readdir API to .list and make the parameters match up with
    the s4 python bindings, i.e. 'mask' is optional and separate from the
    directory parameter.
    
    Note that nothing uses the .readdir source3 API currently, so it's safe
    to rename.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c4dee3437afcf4ccba70cb3fd5848b65fd229781
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Mon Dec 3 16:33:19 2018 +1300

    s3:pylibsmb: Add .chkpath() API to SMB py bindings
    
    Note that this is checking the existence of *directories*, not *files*.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 6a40e538df5ba51355a4c4a9949e66b0893f06c0
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Mon Dec 3 16:27:07 2018 +1300

    s3:pylibsmb: Add .mkdir(), .rmdir() APIS to SMB py bindings
    
    I kept these separate from the chkpath API because it's a nice way to
    use the old s4 API in the tests to verify the new s3 API works
    correctly.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8096419c712a66ee2d577a98dfba108a3bd7d6fe
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Mon Dec 3 10:50:19 2018 +1300

    s3:pylibsmb: Add .unlink() API to SMB Py bindings
    
    Add a basic .unlink() API to the source3 bindings. This is based on the
    source4 python bindings, but uses the source3 client library APIs.
    (We use a helper function to do most of the work, because we will need
    to reuse it in order to support the deltree API).
    
    Update the source4 test to use the source3 API. We will gradually
    convert it over, and then delete the source4 python bindings.
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 6fff2c26dacb49da749a4ee8261639f518342573
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Dec 12 10:25:35 2018 +1300

    s3:pylibsmb: Make lp a mandatory param for the SMB connection
    
    Currently establishing the SMB connection relies on having initialized
    the global source3 loadparm.
    
    This patch makes the lp param mandatory, so that you always have to pass
    the parameter in when establishing the SMB connection.
    
    It also makes the source3 API more consistent with the current source4
    API, which will make it easier to replace the source4 version later.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/tests/dcerpc/raw_testcase.py   |   2 +-
 python/samba/tests/libsmb_samba_internal.py |   2 +-
 python/samba/tests/smb.py                   |  91 ++--
 selftest/knownfail.d/smb                    |   2 -
 source3/libsmb/clireadwrite.c               |   6 +-
 source3/libsmb/proto.h                      |   1 +
 source3/libsmb/pylibsmb.c                   | 623 ++++++++++++++++++++++++++--
 source4/selftest/tests.py                   |   4 +-
 8 files changed, 639 insertions(+), 92 deletions(-)
 delete mode 100644 selftest/knownfail.d/smb


Changeset truncated at 500 lines:

diff --git a/python/samba/tests/dcerpc/raw_testcase.py b/python/samba/tests/dcerpc/raw_testcase.py
index ca1b546a399..3a50ceb5330 100644
--- a/python/samba/tests/dcerpc/raw_testcase.py
+++ b/python/samba/tests/dcerpc/raw_testcase.py
@@ -42,7 +42,7 @@ class smb_pipe_socket(object):
     def __init__(self, target_hostname, pipename, creds, impersonation_level, lp):
         lp3 = s3param.get_context()
         lp3.load(lp.configfile)
-        self.smbconn = libsmb_samba_internal.Conn(target_hostname, 'IPC$',
+        self.smbconn = libsmb_samba_internal.Conn(target_hostname, 'IPC$', lp3,
                                                   credentials=creds, sign=True)
         self.smbfid = self.smbconn.create(pipename,
                                           DesiredAccess=0x12019f,
diff --git a/python/samba/tests/libsmb_samba_internal.py b/python/samba/tests/libsmb_samba_internal.py
index 8918d848ea8..ebfed948315 100644
--- a/python/samba/tests/libsmb_samba_internal.py
+++ b/python/samba/tests/libsmb_samba_internal.py
@@ -60,7 +60,7 @@ class LibsmbTestCase(samba.tests.TestCase):
         creds.set_password(os.getenv("PASSWORD"))
 
         c = libsmb_samba_internal.Conn(os.getenv("SERVER_IP"), "tmp",
-                                       creds, multi_threaded=True,
+                                       lp, creds, multi_threaded=True,
                                        force_smb1=True)
 
         mythreads = []
diff --git a/python/samba/tests/smb.py b/python/samba/tests/smb.py
index 68936473d33..9700953d57a 100644
--- a/python/samba/tests/smb.py
+++ b/python/samba/tests/smb.py
@@ -23,15 +23,18 @@ from samba import smb
 from samba import NTSTATUSError
 from samba.ntstatus import (NT_STATUS_OBJECT_NAME_NOT_FOUND,
                             NT_STATUS_OBJECT_PATH_NOT_FOUND)
+from samba.samba3 import libsmb_samba_internal
+from samba.samba3 import param as s3param
 
 PY3 = sys.version_info[0] == 3
-addom = 'addom.samba.example.com/'
+realm = os.environ.get('REALM')
+domain_dir = realm.lower() + '/'
 test_contents = 'abcd' * 256
 utf_contents = u'Süßigkeiten Äpfel ' * 128
 test_literal_bytes_embed_nulls = b'\xff\xfe\x14\x61\x00\x00\x62\x63\x64' * 256
 binary_contents = b'\xff\xfe'
 binary_contents = binary_contents + "Hello cruel world of python3".encode('utf8') * 128
-test_dir = os.path.join(addom, 'testing_%d' % random.randint(0, 0xFFFF))
+test_dir = os.path.join(domain_dir, 'testing_%d' % random.randint(0, 0xFFFF))
 test_file = os.path.join(test_dir, 'testing').replace('/', '\\')
 
 
@@ -40,22 +43,25 @@ class SMBTests(samba.tests.TestCase):
         super(SMBTests, self).setUp()
         self.server = os.environ["SERVER"]
         creds = self.insta_creds(template=self.get_credentials())
-        self.conn = smb.SMB(self.server,
-                            "sysvol",
-                            lp=self.get_loadparm(),
-                            creds=creds)
-        self.conn.mkdir(test_dir)
+
+        # create an SMB connection to the server
+        lp = s3param.get_context()
+        lp.load(os.getenv("SMB_CONF_PATH"))
+        self.smb_conn = libsmb_samba_internal.Conn(self.server, "sysvol",
+                                                   lp, creds)
+
+        self.smb_conn.mkdir(test_dir)
 
     def tearDown(self):
         super(SMBTests, self).tearDown()
         try:
-            self.conn.deltree(test_dir)
+            self.smb_conn.deltree(test_dir)
         except:
             pass
 
     def test_list(self):
         # check a basic listing returns the items we expect
-        ls = [f['name'] for f in self.conn.list(addom)]
+        ls = [f['name'] for f in self.smb_conn.list(domain_dir)]
         self.assertIn('scripts', ls,
                       msg='"scripts" directory not found in sysvol')
         self.assertIn('Policies', ls,
@@ -66,17 +72,17 @@ class SMBTests(samba.tests.TestCase):
                          msg='Current dir (.) found in directory listing')
 
         # using a '*' mask should be the same as using no mask
-        ls_wildcard = [f['name'] for f in self.conn.list(addom, "*")]
+        ls_wildcard = [f['name'] for f in self.smb_conn.list(domain_dir, "*")]
         self.assertEqual(ls, ls_wildcard)
 
         # applying a mask should only return items that match that mask
-        ls_pol = [f['name'] for f in self.conn.list(addom, "Pol*")]
+        ls_pol = [f['name'] for f in self.smb_conn.list(domain_dir, "Pol*")]
         expected = ["Policies"]
         self.assertEqual(ls_pol, expected)
 
         # each item in the listing is a has with expected keys
         expected_keys = ['attrib', 'mtime', 'name', 'short_name', 'size']
-        for item in self.conn.list(addom):
+        for item in self.smb_conn.list(domain_dir):
             for key in expected_keys:
                 self.assertIn(key, item,
                               msg="Key '%s' not in listing '%s'" % (key, item))
@@ -87,15 +93,16 @@ class SMBTests(samba.tests.TestCase):
         dirpaths = []
         empty_dirs = []
         cur_dir = test_dir
+
         for subdir in ["subdir-X", "subdir-Y", "subdir-Z"]:
             path = self.make_sysvol_path(cur_dir, subdir)
-            self.conn.mkdir(path)
+            self.smb_conn.mkdir(path)
             dirpaths.append(path)
             cur_dir = path
 
             # create another empty dir just for kicks
             path = self.make_sysvol_path(cur_dir, "another")
-            self.conn.mkdir(path)
+            self.smb_conn.mkdir(path)
             empty_dirs.append(path)
 
         # create some files in these directories
@@ -104,12 +111,12 @@ class SMBTests(samba.tests.TestCase):
             for i in range(1, 4):
                 contents = "I'm file {0} in dir {1}!".format(i, subdir)
                 path = self.make_sysvol_path(subdir, "file-{0}.txt".format(i))
-                self.conn.savefile(path, test_contents.encode('utf8'))
+                self.smb_conn.savefile(path, test_contents.encode('utf8'))
                 filepaths.append(path)
 
         # sanity-check these dirs/files exist
         for subdir in dirpaths + empty_dirs:
-            self.assertTrue(self.conn.chkpath(subdir),
+            self.assertTrue(self.smb_conn.chkpath(subdir),
                             "Failed to create {0}".format(subdir))
         for path in filepaths:
             self.assertTrue(self.file_exists(path),
@@ -117,22 +124,22 @@ class SMBTests(samba.tests.TestCase):
 
         # try using deltree to remove a single empty directory
         path = empty_dirs.pop(0)
-        self.conn.deltree(path)
-        self.assertFalse(self.conn.chkpath(path),
+        self.smb_conn.deltree(path)
+        self.assertFalse(self.smb_conn.chkpath(path),
                          "Failed to delete {0}".format(path))
 
         # try using deltree to remove a single file
         path = filepaths.pop(0)
-        self.conn.deltree(path)
+        self.smb_conn.deltree(path)
         self.assertFalse(self.file_exists(path),
                          "Failed to delete {0}".format(path))
 
         # delete the top-level dir
-        self.conn.deltree(test_dir)
+        self.smb_conn.deltree(test_dir)
 
         # now check that all the dirs/files are no longer there
         for subdir in dirpaths + empty_dirs:
-            self.assertFalse(self.conn.chkpath(subdir),
+            self.assertFalse(self.smb_conn.chkpath(subdir),
                              "Failed to delete {0}".format(subdir))
         for path in filepaths:
             self.assertFalse(self.file_exists(path),
@@ -141,7 +148,7 @@ class SMBTests(samba.tests.TestCase):
     def file_exists(self, filepath):
         """Returns whether a regular file exists (by trying to open it)"""
         try:
-            self.conn.loadfile(filepath)
+            self.smb_conn.loadfile(filepath)
             exists = True;
         except NTSTATUSError as err:
             if (err.args[0] == NT_STATUS_OBJECT_NAME_NOT_FOUND or
@@ -157,72 +164,72 @@ class SMBTests(samba.tests.TestCase):
         """
         # create the test file
         self.assertFalse(self.file_exists(test_file))
-        self.conn.savefile(test_file, binary_contents)
+        self.smb_conn.savefile(test_file, binary_contents)
         self.assertTrue(self.file_exists(test_file))
 
         # delete it and check that it's gone
-        self.conn.unlink(test_file)
+        self.smb_conn.unlink(test_file)
         self.assertFalse(self.file_exists(test_file))
 
     def test_chkpath(self):
         """Tests .chkpath determines whether or not a directory exists"""
 
-        self.assertTrue(self.conn.chkpath(test_dir))
+        self.assertTrue(self.smb_conn.chkpath(test_dir))
 
         # should return False for a non-existent directory
         bad_dir = self.make_sysvol_path(test_dir, 'dont_exist')
-        self.assertFalse(self.conn.chkpath(bad_dir))
+        self.assertFalse(self.smb_conn.chkpath(bad_dir))
 
         # should return False for files (because they're not directories)
-        self.conn.savefile(test_file, binary_contents)
-        self.assertFalse(self.conn.chkpath(test_file))
+        self.smb_conn.savefile(test_file, binary_contents)
+        self.assertFalse(self.smb_conn.chkpath(test_file))
 
         # check correct result after creating and then deleting a new dir
         new_dir = self.make_sysvol_path(test_dir, 'test-new')
-        self.conn.mkdir(new_dir)
-        self.assertTrue(self.conn.chkpath(new_dir))
-        self.conn.rmdir(new_dir)
-        self.assertFalse(self.conn.chkpath(new_dir))
+        self.smb_conn.mkdir(new_dir)
+        self.assertTrue(self.smb_conn.chkpath(new_dir))
+        self.smb_conn.rmdir(new_dir)
+        self.assertFalse(self.smb_conn.chkpath(new_dir))
 
     def test_save_load_text(self):
 
-        self.conn.savefile(test_file, test_contents.encode('utf8'))
+        self.smb_conn.savefile(test_file, test_contents.encode('utf8'))
 
-        contents = self.conn.loadfile(test_file)
+        contents = self.smb_conn.loadfile(test_file)
         self.assertEquals(contents.decode('utf8'), test_contents,
                           msg='contents of test file did not match what was written')
 
         # check we can overwrite the file with new contents
         new_contents = 'wxyz' * 128
-        self.conn.savefile(test_file, new_contents.encode('utf8'))
-        contents = self.conn.loadfile(test_file)
+        self.smb_conn.savefile(test_file, new_contents.encode('utf8'))
+        contents = self.smb_conn.loadfile(test_file)
         self.assertEquals(contents.decode('utf8'), new_contents,
                           msg='contents of test file did not match what was written')
 
     # with python2 this will save/load str type (with embedded nulls)
     # with python3 this will save/load bytes type
     def test_save_load_string_bytes(self):
-        self.conn.savefile(test_file, test_literal_bytes_embed_nulls)
+        self.smb_conn.savefile(test_file, test_literal_bytes_embed_nulls)
 
-        contents = self.conn.loadfile(test_file)
+        contents = self.smb_conn.loadfile(test_file)
         self.assertEquals(contents, test_literal_bytes_embed_nulls,
                           msg='contents of test file did not match what was written')
 
     # python3 only this will save/load unicode
     def test_save_load_utfcontents(self):
         if PY3:
-            self.conn.savefile(test_file, utf_contents.encode('utf8'))
+            self.smb_conn.savefile(test_file, utf_contents.encode('utf8'))
 
-            contents = self.conn.loadfile(test_file)
+            contents = self.smb_conn.loadfile(test_file)
             self.assertEquals(contents.decode('utf8'), utf_contents,
                               msg='contents of test file did not match what was written')
 
     # with python2 this will save/load str type
     # with python3 this will save/load bytes type
     def test_save_binary_contents(self):
-        self.conn.savefile(test_file, binary_contents)
+        self.smb_conn.savefile(test_file, binary_contents)
 
-        contents = self.conn.loadfile(test_file)
+        contents = self.smb_conn.loadfile(test_file)
         self.assertEquals(contents, binary_contents,
                           msg='contents of test file did not match what was written')
 
diff --git a/selftest/knownfail.d/smb b/selftest/knownfail.d/smb
deleted file mode 100644
index 3c6324ac7b3..00000000000
--- a/selftest/knownfail.d/smb
+++ /dev/null
@@ -1,2 +0,0 @@
-# currently savefile appends rather than overwriting
-samba.tests.smb.*samba.tests.smb.SMBTests.test_save_load_text\(ad_dc:local\)
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index e953fa5e228..da188db7c31 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -822,7 +822,11 @@ NTSTATUS cli_read_recv(struct tevent_req *req, size_t *received)
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
+/*
+ * Helper function for cli_pull(). This takes a chunk of data (buf) read from
+ * a remote file and copies it into the return buffer (priv).
+ */
+NTSTATUS cli_read_sink(char *buf, size_t n, void *priv)
 {
 	char **pbuf = (char **)priv;
 	memcpy(*pbuf, buf, n);
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index bfad4dcc011..b0cfcb5aa90 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -840,6 +840,7 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum,
 		  off_t start_offset, off_t size, size_t window_size,
 		  NTSTATUS (*sink)(char *buf, size_t n, void *priv),
 		  void *priv, off_t *received);
+NTSTATUS cli_read_sink(char *buf, size_t n, void *priv);
 struct tevent_req *cli_read_send(
 	TALLOC_CTX *mem_ctx,
 	struct tevent_context *ev,
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c
index 041d408e86e..452c30e9490 100644
--- a/source3/libsmb/pylibsmb.c
+++ b/source3/libsmb/pylibsmb.c
@@ -28,6 +28,10 @@
 #include "source4/libcli/util/pyerrors.h"
 #include "auth/credentials/pycredentials.h"
 #include "trans2.h"
+#include "libsmb/clirap.h"
+
+#define LIST_ATTRIBUTE_MASK \
+	(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
 
 static PyTypeObject *get_pytype(const char *module, const char *type)
 {
@@ -423,6 +427,7 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
 	char *host, *share;
 	PyObject *creds = NULL;
 	struct cli_credentials *cli_creds;
+	PyObject *py_lp = Py_None;
 	PyObject *py_multi_threaded = Py_False;
 	bool multi_threaded = false;
 	PyObject *py_sign = Py_False;
@@ -435,7 +440,7 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
 	int flags = 0;
 
 	static const char *kwlist[] = {
-		"host", "share", "credentials",
+		"host", "share", "lp", "credentials",
 		"multi_threaded", "sign", "force_smb1",
 		NULL
 	};
@@ -447,8 +452,8 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
 	}
 
 	ret = ParseTupleAndKeywords(
-		args, kwds, "ss|O!OOO", kwlist,
-		&host, &share,
+		args, kwds, "ssO|O!OOO", kwlist,
+		&host, &share, &py_lp,
 		py_type_Credentials, &creds,
 		&py_multi_threaded,
 		&py_sign,
@@ -740,6 +745,92 @@ static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
+struct push_state {
+	char *data;
+	off_t nread;
+	off_t total_data;
+};
+
+/*
+ * cli_push() helper to write a chunk of data to a remote file
+ */
+static size_t push_data(uint8_t *buf, size_t n, void *priv)
+{
+	struct push_state *state = (struct push_state *)priv;
+	char *curr_ptr = NULL;
+	off_t remaining;
+	size_t copied_bytes;
+
+	if (state->nread >= state->total_data) {
+		return 0;
+	}
+
+	curr_ptr = state->data + state->nread;
+	remaining = state->total_data - state->nread;
+	copied_bytes = MIN(remaining, n);
+
+	memcpy(buf, curr_ptr, copied_bytes);
+	state->nread += copied_bytes;
+	return copied_bytes;
+}
+
+/*
+ * Writes a file with the contents specified
+ */
+static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args,
+				 PyObject *kwargs)
+{
+	uint16_t fnum;
+	const char *filename = NULL;
+	char *data = NULL;
+	Py_ssize_t size = 0;
+	NTSTATUS status;
+	struct tevent_req *req = NULL;
+	struct push_state state;
+
+	if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
+			      &data, &size)) {
+		return NULL;
+	}
+
+	/* create a new file handle for writing to */
+	req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
+				FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
+				FILE_SHARE_READ|FILE_SHARE_WRITE,
+				FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
+				SMB2_IMPERSONATION_IMPERSONATION, 0);
+	if (!py_tevent_req_wait_exc(self, req)) {
+		return NULL;
+	}
+	status = cli_ntcreate_recv(req, &fnum, NULL);
+	TALLOC_FREE(req);
+	PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+	/* write the new file contents */
+	state.data = data;
+	state.nread = 0;
+	state.total_data = size;
+
+	req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
+			    push_data, &state);
+	if (!py_tevent_req_wait_exc(self, req)) {
+		return NULL;
+	}
+	status = cli_push_recv(req);
+	TALLOC_FREE(req);
+	PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+	/* close the file handle */
+	req = cli_close_send(NULL, self->ev, self->cli, fnum);
+	if (!py_tevent_req_wait_exc(self, req)) {
+		return NULL;
+	}
+	status = cli_close_recv(req);
+	PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+	Py_RETURN_NONE;
+}
+
 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
 			      PyObject *kwds)
 {
@@ -776,6 +867,125 @@ static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
 	return Py_BuildValue("K", (unsigned long long)written);
 }
 
+/*
+ * Returns the size of the given file
+ */
+static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
+				off_t *size)
+{
+	NTSTATUS status;
+
+	if (self->is_smb1) {
+		uint8_t *rdata = NULL;
+		struct tevent_req *req = NULL;
+
+		req = cli_qfileinfo_send(NULL, self->ev, self->cli, fnum,
+					 SMB_QUERY_FILE_ALL_INFO, 68,
+					 CLI_BUFFER_SIZE);
+		if (!py_tevent_req_wait_exc(self, req)) {
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+		status = cli_qfileinfo_recv(req, NULL, NULL, &rdata, NULL);
+		if (NT_STATUS_IS_OK(status)) {
+			*size = IVAL2_TO_SMB_BIG_UINT(rdata, 48);
+		}
+		TALLOC_FREE(req);
+		TALLOC_FREE(rdata);
+	} else {
+		status = cli_qfileinfo_basic(self->cli, fnum, NULL, size,
+					     NULL, NULL, NULL, NULL, NULL);
+	}
+	return status;
+}
+
+/*
+ * Loads the specified file's contents and returns it
+ */
+static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args,
+				 PyObject *kwargs)
+{
+	NTSTATUS status;
+	const char *filename = NULL;
+	struct tevent_req *req = NULL;
+	uint16_t fnum;
+	off_t size;
+	char *buf = NULL;
+	off_t nread = 0;
+	PyObject *result = NULL;
+
+	if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
+		return NULL;
+	}
+
+	/* get a read file handle */
+	req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
+				FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+				FILE_SHARE_READ, FILE_OPEN, 0,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list