Closed Bug 974225 Opened 11 years ago Closed 11 years ago

[mozfile] remove() fails with '[Errno 1] Operation not permitted' when trying to update permissions for a symlink to a system folder

Categories

(Testing :: Mozbase, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED
mozilla30

People

(Reporter: mcomella, Assigned: whimboo)

References

Details

Attachments

(2 files, 2 obsolete files)

Attached file Debug output
This causes an attempted removal of /usr/include/python2.7, but mach exits before completing this.
Caused by 949600 which has been backed out.
Status: NEW → RESOLVED
Closed: 11 years ago
Resolution: --- → DUPLICATE
Actually lets morph this bug because that's a problem with mozfile and not mach. It will block the next merge try.
Blocks: 949600
Status: RESOLVED → REOPENED
Component: mach → Mozbase
OS: Linux → All
Product: Core → Testing
QA Contact: hskupin
Hardware: x86_64 → All
Resolution: DUPLICATE → ---
Summary: `mach clobber` attempts to remove what symlinks point to → [mozfile] remove() attempts to modify/remove what symlinks point to
Blocks: 974226
Assignee: nobody → hskupin
Status: REOPENED → ASSIGNED
Actually this is pretty easy to reproduce on Linux: $ ln -s /usr/share/ to_delete $ python -c 'import mozfile; mozfile.remove("_delete")' I will have a patch soon and will also try to find a test for that, so we do not regress again.
Summary: [mozfile] remove() attempts to modify/remove what symlinks point to → [mozfile] remove() fails with '[Errno 1] Operation not permitted' when trying to remove a symlink to a system folder
Well, actually the permission change call fails because chmod itself fails when calling it directly: $ chmod 0700 _delete chmod: changing permissions of ‘_delete’: Operation not permitted So it looks like you cannot change the permission of a symlink, and we should simply return early in _update_permissions.
Summary: [mozfile] remove() fails with '[Errno 1] Operation not permitted' when trying to remove a symlink to a system folder → [mozfile] remove() fails with '[Errno 1] Operation not permitted' when trying to update permissions for a symlink to a system folder
Attached patch Patch v1 (obsolete) — Splinter Review
Silly mistakes! So what does this patch change: * We do no longer call os.chmod() on symlinks as mentioned above. There is nothing it would change because they already have all the needed permissions * We call os.stat() for each file and dir we check, and not only once for the path passed into remove(). So all the files/dirs should get the right permissions assigned to.
Attachment #8378293 - Flags: review?(ahalberstadt)
Comment on attachment 8378293 [details] [diff] [review] Patch v1 Review of attachment 8378293 [details] [diff] [review]: ----------------------------------------------------------------- Looks good! One optional readability improvement suggested. ::: mozfile/mozfile/mozfile.py @@ +184,1 @@ > mode = dir_mode if os.path.isdir(path) else file_mode This would probably be better as: if os.path.isdir(path): mode = ... else: mode = ...
Attachment #8378293 - Flags: review?(ahalberstadt) → review+
Comment on attachment 8378293 [details] [diff] [review] Patch v1 Review of attachment 8378293 [details] [diff] [review]: ----------------------------------------------------------------- ::: mozfile/mozfile/mozfile.py @@ +184,1 @@ > mode = dir_mode if os.path.isdir(path) else file_mode There's a lot of system calls here! We need to keep the system calls in check because they can degrade performance on Windows. e.g. the |os.path.isdir(path)| is equivalent to |stat.S_ISDIR(path_stats.st_mode)| but the latter doesn't perform a system call. I'd file a follow-up to optimize this code for common case (no permissions adjustment needed - just attempt delete, catch exception and adjust permissions and retry) and minimizes the number of system calls.
(In reply to Andrew Halberstadt [:ahal] from comment #6) > This would probably be better as: > > if os.path.isdir(path): > mode = ... > else: > mode = ... Yes, that was what I mentioned on IRC. I will do that. (In reply to Gregory Szorc [:gps] from comment #7) > There's a lot of system calls here! We need to keep the system calls in > check because they can degrade performance on Windows. > > e.g. the |os.path.isdir(path)| is equivalent to > |stat.S_ISDIR(path_stats.st_mode)| but the latter doesn't perform a system > call. > > I'd file a follow-up to optimize this code for common case (no permissions > adjustment needed - just attempt delete, catch exception and adjust > permissions and retry) and minimizes the number of system calls. Very good point. I will get this addressed. There shouldn't be a need for a follow-up bug. It's an easy change.
(In reply to Henrik Skupin (:whimboo) from comment #8) > > I'd file a follow-up to optimize this code for common case (no permissions > > adjustment needed - just attempt delete, catch exception and adjust > > permissions and retry) and minimizes the number of system calls. > > Very good point. I will get this addressed. There shouldn't be a need for a > follow-up bug. It's an easy change. Looks like I have some trouble with stat.S_ISLNK() and that it doesn't really detect a symlink. So I would say, lets get this really addressed in a follow-up bug.
Attached patch Patch v2 (obsolete) — Splinter Review
Updated patch, and with 3 new tests included now.
Attachment #8378293 - Attachment is obsolete: true
Attachment #8378433 - Flags: review?(gps)
Attachment #8378433 - Flags: review?(ahalberstadt)
It looks like that os.geteuid() is not available on Windows. So I have to find another way to skip the sympath test for root users.
Attached patch Patch v2.1Splinter Review
Fixed the skipIf() issue with a single call. All runs fine across platforms.
Attachment #8378433 - Attachment is obsolete: true
Attachment #8378433 - Flags: review?(gps)
Attachment #8378433 - Flags: review?(ahalberstadt)
Attachment #8378447 - Flags: review?(gps)
Attachment #8378447 - Flags: review?(ahalberstadt)
Comment on attachment 8378447 [details] [diff] [review] Patch v2.1 Review of attachment 8378447 [details] [diff] [review]: ----------------------------------------------------------------- Looks good. ::: mozfile/tests/test_remove.py @@ +137,5 @@ > mozfile.remove(filepath) > > self.assertFalse(os.path.exists(filepath)) > + > + @unittest.skipIf(mozinfo.isWin, "Symlinks are not supported on Windows") Instead of mozinfo.isWin you could do "not hasattr(os, 'symlink')"
Attachment #8378447 - Flags: review?(ahalberstadt) → review+
Comment on attachment 8378447 [details] [diff] [review] Patch v2.1 Talked with Andrew on IRC and it should be enough to have a single reviewer here.
Attachment #8378447 - Flags: review?(gps)
Status: ASSIGNED → RESOLVED
Closed: 11 years ago11 years ago
Flags: in-testsuite+
Resolution: --- → FIXED
Target Milestone: --- → mozilla30
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: