Merge lp:~parthm/bzr/376388-dot-bazaar-ownership-regression-2.2 into lp:bzr/2.2

Proposed by Parth Malwankar
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 5064
Proposed branch: lp:~parthm/bzr/376388-dot-bazaar-ownership-regression-2.2
Merge into: lp:bzr/2.2
Diff against target: 60 lines (+21/-2)
2 files modified
bzrlib/config.py (+3/-1)
bzrlib/tests/test_config.py (+18/-1)
To merge this branch: bzr merge lp:~parthm/bzr/376388-dot-bazaar-ownership-regression-2.2
Reviewer Review Type Date Requested Status
Vincent Ladeuil Approve
John A Meinel Needs Fixing
Review via email: mp+29881@code.launchpad.net

Commit message

Fix for .bazaar ownership regression for bug #376388.

Description of the change

This patch fixes a regression in an earlier fix for bug #376388
A test case is also added to ensure that IniBasedConfig._write_config_file calls chown.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

Thanks for the prompt reply !
The test scope is a bit tight, but the important point is that it will fail if the implementation is changed and could be updated or tweaked then.

review: Approve
Revision history for this message
John A Meinel (jameinel) wrote :

Is this really what we want to do? It looks like we grab the info for the file from its containing directory. I think what we would really want is to have the permissions be obtained from the file that is being replaced.

Which would hint to a fix in AtomicFile itself, possibly with an optional flag.

review: Needs Fixing
Revision history for this message
Parth Malwankar (parthm) wrote :

Thanks for the review John.

> Is this really what we want to do? It looks like we grab the info for the file
> from its containing directory. I think what we would really want is to have
> the permissions be obtained from the file that is being replaced.
>

There is one specific case which requires that the ownership gets copied from the containing directory. If the config file doesn't exist and is created by bzr under sudo we need to be sure that the user has ownership.

> Which would hint to a fix in AtomicFile itself, possibly with an optional
> flag.

Revision history for this message
Vincent Ladeuil (vila) wrote :

> Is this really what we want to do?

It's what we did before.

> It looks like we grab the info for the file
> from its containing directory. I think what we would really want is to have
> the permissions be obtained from the file that is being replaced.

Isn't atomicfile ensuring the permissions are preserved ?

copy_ownership only applies when running as root anyway...

Revision history for this message
Vincent Ladeuil (vila) wrote :

> > Is this really what we want to do?
>
> It's what we did before.

To clarify: it's what we did before the regression, which isn't shown by this submission.

Revision history for this message
Vincent Ladeuil (vila) wrote :

> > Is this really what we want to do?
>
> It's what we did before.

To clarify: it's what we did before the regression, which isn't shown by this submission.

I think we should land this submission as is and address enhancements in atomicfile and/or
copy_ownership in a further submission if needed.

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Parth Malwankar wrote:
> Thanks for the review John.
>
>> Is this really what we want to do? It looks like we grab the info for the file
>> from its containing directory. I think what we would really want is to have
>> the permissions be obtained from the file that is being replaced.
>>
>
> There is one specific case which requires that the ownership gets copied from the containing directory. If the config file doesn't exist and is created by bzr under sudo we need to be sure that the user has ownership.

That is true, but if the file already exists, shouldn't we use the
permissions it already has?

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkxFy8QACgkQJdeBCYSNAAO8PQCcDpwk6fEc3MMCS7NQS3XkoMah
pl0An3s5gtO13PdV9AIFsrF+JvR3CYnr
=dFGi
-----END PGP SIGNATURE-----

Revision history for this message
Vincent Ladeuil (vila) wrote :

> > There is one specific case which requires that the ownership gets copied
> from the containing directory. If the config file doesn't exist and is created
> by bzr under sudo we need to be sure that the user has ownership.
>
> That is true, but if the file already exists, shouldn't we use the
> permissions it already has?

The patch is about ownership of the file not about its permissions. atomicfile preserve existing permissions right ?

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Vincent Ladeuil wrote:
>>> There is one specific case which requires that the ownership gets copied
>> from the containing directory. If the config file doesn't exist and is created
>> by bzr under sudo we need to be sure that the user has ownership.
>>
>> That is true, but if the file already exists, shouldn't we use the
>> permissions it already has?
>
> The patch is about ownership of the file not about its permissions. atomicfile preserve existing permissions right ?
>

Well, shouldn't we use the *ownership* it already has? (yes you are
right that AF preserves permissions.)

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkxGFxQACgkQJdeBCYSNAAMbOACgnu6fZTi9i02xG9R0ik27KPAm
BoIAoJgNO0KpmnIaAeF7X1EVwLPEBkV2
=sFss
-----END PGP SIGNATURE-----

Revision history for this message
Parth Malwankar (parthm) wrote :

So I tried to copy ownership conditionally:

=== modified file 'bzrlib/config.py'
--- bzrlib/config.py 2010-07-14 14:31:38 +0000
+++ bzrlib/config.py 2010-07-21 02:36:39 +0000
@@ -480,11 +480,13 @@

     def _write_config_file(self):
         filename = self._get_filename()
+ file_existed = os.path.isfile(filename)
         atomic_file = atomicfile.AtomicFile(filename)
         self._get_parser().write(atomic_file)
         atomic_file.commit()
         atomic_file.close()
- osutils.copy_ownership_from_path(filename)
+ if not file_existed:
+ osutils.copy_ownership_from_path(filename)

I noticed that in case of a second operation under sudo (when the file already exists) the write operation changes the ownership to root. The operation I experimented with was 'sudo bzr whoami a@b && sudo bzr whoami b@c'.
I suspect this was the reason it wasn't conditional in the first place but the original patch was created quite a few months ago.

Revision history for this message
Vincent Ladeuil (vila) wrote :

I think we still have grey areas when working under sudo, but this patch doesn't make things worse in that respect and we need to fix the regression.

A further submission may create a specific test suite that we can run under sudo (depending on a feature and/or using the test_suite_factory parameter of bt.selftest) so we can run it on a dedicated slave on babune. I've filed bug #608216 for that.

review: Approve
Revision history for this message
Vincent Ladeuil (vila) wrote :

sent to pqm by email

Revision history for this message
Vincent Ladeuil (vila) wrote :

> Well, shouldn't we use the *ownership* it already has?

Keep in mind that only root can change ownership, this code is targeted as usages under sudo, we may want to try being more fancy here like respecting the current owner if the file owner is not root nor the containing directory owner but that sounds weird.

We are talking of the user config files here and I can't see a good reason to have different owners for the config file and its containing directory.

Anyway, if we want to explore these scenarios, we need to write the corresponding tests, hence bug #608216.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/config.py'
--- bzrlib/config.py 2010-07-13 16:10:20 +0000
+++ bzrlib/config.py 2010-07-21 03:17:41 +0000
@@ -479,10 +479,12 @@
479 return self.get_user_option('nickname')479 return self.get_user_option('nickname')
480480
481 def _write_config_file(self):481 def _write_config_file(self):
482 atomic_file = atomicfile.AtomicFile(self._get_filename())482 filename = self._get_filename()
483 atomic_file = atomicfile.AtomicFile(filename)
483 self._get_parser().write(atomic_file)484 self._get_parser().write(atomic_file)
484 atomic_file.commit()485 atomic_file.commit()
485 atomic_file.close()486 atomic_file.close()
487 osutils.copy_ownership_from_path(filename)
486488
487489
488class GlobalConfig(IniBasedConfig):490class GlobalConfig(IniBasedConfig):
489491
=== modified file 'bzrlib/tests/test_config.py'
--- bzrlib/tests/test_config.py 2010-04-23 07:15:23 +0000
+++ bzrlib/tests/test_config.py 2010-07-21 03:17:41 +0000
@@ -35,6 +35,7 @@
35 trace,35 trace,
36 transport,36 transport,
37 )37 )
38from bzrlib.tests import features
38from bzrlib.util.configobj import configobj39from bzrlib.util.configobj import configobj
3940
4041
@@ -367,7 +368,7 @@
367 '/home/bogus/.cache')368 '/home/bogus/.cache')
368369
369370
370class TestIniConfig(tests.TestCase):371class TestIniConfig(tests.TestCaseInTempDir):
371372
372 def make_config_parser(self, s):373 def make_config_parser(self, s):
373 conf = config.IniBasedConfig(None)374 conf = config.IniBasedConfig(None)
@@ -393,6 +394,22 @@
393 parser = my_config._get_parser(file=config_file)394 parser = my_config._get_parser(file=config_file)
394 self.failUnless(my_config._get_parser() is parser)395 self.failUnless(my_config._get_parser() is parser)
395396
397 def _dummy_chown(self, path, uid, gid):
398 self.path, self.uid, self.gid = path, uid, gid
399
400 def test_ini_config_ownership(self):
401 """Ensure that chown is happening during _write_config_file.
402 """
403 self.requireFeature(features.chown_feature)
404 self.overrideAttr(os, 'chown', self._dummy_chown)
405 self.path = self.uid = self.gid = None
406 def get_filename():
407 return 'foo.conf'
408 conf = config.IniBasedConfig(get_filename)
409 conf._write_config_file()
410 self.assertEquals(self.path, 'foo.conf')
411 self.assertTrue(isinstance(self.uid, int))
412 self.assertTrue(isinstance(self.gid, int))
396413
397class TestGetUserOptionAs(TestIniConfig):414class TestGetUserOptionAs(TestIniConfig):
398415

Subscribers

People subscribed via source and target branches