Closed Bug 919771 Opened 11 years ago Closed 2 years ago

[OS.File] Preserve permissions when moving/copying files between volumes

Categories

(Toolkit Graveyard :: OS.File, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED WONTFIX

People

(Reporter: marco, Assigned: marco)

References

Details

(Whiteboard: [Async:ready])

Attachments

(1 file, 4 obsolete files)

In bug 749826 I'd need to move a directory (and its contents) from the temporary directory.
I need to preserve permissions even if I'm moving files from a volume to another (on Linux /tmp is usually on another volume).
Blocks: 749826
Attached file moveDirectory.js (obsolete) —
This is the function I've written to move the directory, I wonder if we can add it to OS.File so that we don't need to re-implement it every time we need it.
(In reply to Marco Castelluccio [:marco] from comment #1)
> Created attachment 808844 [details]
> moveDirectory.js
> 
> This is the function I've written to move the directory, I wonder if we can
> add it to OS.File so that we don't need to re-implement it every time we
> need it.

Well, that won't work if the directory contains subdirectories.
Under Unix, to preserve permissions of a single file:
- if the move stays on the same volume, permissions are already preserved;
- if the move crosses volume boundaries, we actually copy the file and lose permission – we will need to add a call to stat() and a call to chmod().

Under Windows, to preserve permissions of a single file:
- if the move stays on the same volume, permissions are already preserved;
- if the move crosses volume boundaries, Windows itself actually copies the file and loses permissions – we will need to replace our call to MoveFile() by a call to MoveFileEx() to instruct Windows to not do this, then call CopyFile(), then add a call to GetFileSecurity() and a call to SetFileSecurity().

I would like to avoid doing this for directories just yet.
Summary: Preserve permissions when moving files between volumes → [OS.File] Preserve permissions when moving files between volumes
Marco, I don't have time to work on this right now, but if you wish to pick up the bug, I'll be glad to mentor you along.
(In reply to David Rajchenbach Teller [:Yoric] from comment #2)
> Well, that won't work if the directory contains subdirectories.

Sorry, I misread your patch. Let's handle this in another bug, though.
(In reply to David Rajchenbach Teller [:Yoric] from comment #4)
> Marco, I don't have time to work on this right now, but if you wish to pick
> up the bug, I'll be glad to mentor you along.

Ok, sure, I'd need also other things in OS.File so it'd be good to start gaining some knowledge about its internals.
Blocks: 756315
No longer blocks: 749826
Attached patch Patch (obsolete) — Splinter Review
I'm not sure we need the Windows counterpart, do we?
Attachment #813577 - Flags: feedback?(dteller)
Attachment #813577 - Attachment is obsolete: true
Attachment #813577 - Flags: feedback?(dteller)
Attached patch Patch (obsolete) — Splinter Review
I'm not sure how to test this.
Attachment #813619 - Flags: feedback?(dteller)
Attachment #808844 - Attachment is obsolete: true
Comment on attachment 813619 [details] [diff] [review]
Patch

Review of attachment 813619 [details] [diff] [review]:
-----------------------------------------------------------------

If you only implement it for Unix, please call this unixPreservePermissions.
Unfortunately, I don't think we can test it yet on Try. You'll have to do this locally.

::: toolkit/components/osfile/modules/osfile_unix_front.jsm
@@ +542,5 @@
>             source = File.open(sourcePath);
> +
> +           let openOptions = {};
> +           if (options.preservePermissions) {
> +             let info = File.stat(sourcePath);

Calling |fstat| should be faster.

@@ +550,2 @@
>             if (options.noOverwrite) {
> +             dest = File.open(destPath, {create:true}, openOptions);

Could you take the opportunity to add a whitespace after ":"?

@@ +553,5 @@
> +             if (options.preservePermissions) {
> +               File.remove(destPath);
> +             }
> +
> +             dest = File.open(destPath, {trunc:true}, openOptions);

With |trunc: true|, I'm almost sure that |openOptions| will be ignored. Therefore, if preservePermissions is set, you should call File.remove(destPath, {ignoreAbsent: true}) and then |dest = File.open(destPath, {create: true}, openOptions)|.
Attachment #813619 - Flags: feedback?(dteller) → feedback+
By the way, under Linux (only), we can test on Try, by moving the file to /dev/shm.
I've managed to write a test for Linux, I'm not sure how to use that trick for Mac OS X.

What should we do for copy and move in the case of single volume when |unixPreservePermissions=false|?
At the moment we're preserving the permissions in the case of move, not preserving in the case of copy.
(In reply to Marco Castelluccio [:marco] from comment #12)
> What should we do for copy and move in the case of single volume when
> |unixPreservePermissions=false|?
> At the moment we're preserving the permissions in the case of move, not
> preserving in the case of copy.

In that case, we do whatever is simplest.
Attached patch Patch v2 (obsolete) — Splinter Review
The tests are working on Linux, I'm not sure how to create automated tests for Mac.
Attachment #813619 - Attachment is obsolete: true
Attachment #815169 - Flags: feedback?(dteller)
Comment on attachment 815169 [details] [diff] [review]
Patch v2

Review of attachment 815169 [details] [diff] [review]:
-----------------------------------------------------------------

Could you please apply the suggestions I made in my previous feedback?

::: toolkit/components/osfile/modules/osfile_unix_front.jsm
@@ +545,5 @@
> +           if (options.preservePermissions) {
> +             let statData = new OS.Shared.Type.stat.implementation();
> +             let statDataPtr = statData.address();
> +             throw_on_negative("stat", UnixFile.fstat(source.fd, statDataPtr));
> +             openOptions.unixMode = exports.OS.Shared.Type.mode_t.importFromC(statData.st_mode & MODE_MASK);

I meant |source.stat()| (which uses |fstat|), but that should work, too.
Attachment #815169 - Flags: feedback?(dteller)
(In reply to David Rajchenbach Teller [:Yoric] from comment #15)
> Comment on attachment 815169 [details] [diff] [review]
> Patch v2
> 
> Review of attachment 815169 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> Could you please apply the suggestions I made in my previous feedback?

Ah, I forgot to change the name!
I didn't apply the other suggestion because looks like the options aren't ignored with |trunc:true|, http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/modules/osfile_unix_front.jsm#219
Let me know if you want me to modify that anyways.
(In reply to Marco Castelluccio [:marco] from comment #16)
> Ah, I forgot to change the name!
> I didn't apply the other suggestion because looks like the options aren't
> ignored with |trunc:true|,
> http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/
> modules/osfile_unix_front.jsm#219
> Let me know if you want me to modify that anyways.

I'm pretty sure that they are ignored by the lower-level C API.

(In reply to Marco Castelluccio [:marco] from comment #12)
> I've managed to write a test for Linux, I'm not sure how to use that trick
> for Mac OS X.

You'll need to write a script and execute it with nsIProcess.
(In reply to David Rajchenbach Teller [:Yoric] from comment #17)
> (In reply to Marco Castelluccio [:marco] from comment #16)
> > Ah, I forgot to change the name!
> > I didn't apply the other suggestion because looks like the options aren't
> > ignored with |trunc:true|,
> > http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/
> > modules/osfile_unix_front.jsm#219
> > Let me know if you want me to modify that anyways.
> 
> I'm pretty sure that they are ignored by the lower-level C API.
> 
> (In reply to Marco Castelluccio [:marco] from comment #12)
> > I've managed to write a test for Linux, I'm not sure how to use that trick
> > for Mac OS X.
> 
> You'll need to write a script and execute it with nsIProcess.

Will that work on our try servers? Doesn't something like that need admin privileges on Mac?
Anyway I don't own a Mac, so I'll get back to this bug if I manage to build a Mac virtual machine.
It is my understanding that this script doesn't require admin privileges.
Whiteboard: [Async] → [Async:ready]
Attached patch Patch v3Splinter Review
Implemented tests for Mac.
The try run is green: https://tbpl.mozilla.org/?tree=Try&rev=ece15e2f014e
Assignee: nobody → mar.castelluccio
Attachment #815169 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #8375611 - Flags: review?(dteller)
Summary: [OS.File] Preserve permissions when moving files between volumes → [OS.File] Preserve permissions when moving/copying files between volumes
Comment on attachment 8375611 [details] [diff] [review]
Patch v3

Review of attachment 8375611 [details] [diff] [review]:
-----------------------------------------------------------------

The core patch looks good, for Unix. Don't you need a Windows version, too?

Also, I'd prefer if you could make the test a xpcshell-test, this makes it easier to launch independently.

::: toolkit/components/osfile/modules/osfile_unix_front.jsm
@@ +624,5 @@
> +             if (options.unixPreservePermissions) {
> +               File.remove(destPath);
> +             }
> +
> +             dest = File.open(destPath, {trunc: true, append: false}, openOptions);

If you remove the file, you don't need |trunc|, so you can merge the two |dest = File.open(...)|.

::: toolkit/components/osfile/tests/mochi/create_volume.sh
@@ +1,5 @@
> +#!/bin/bash
> +
> +NumSectors=$((2*1024))
> +
> +DeviceName=`hdid -nomount ram://$NumSectors`

Ok, that should work on MacOS X. Do you have ideas on how to extend this to other OSes?
Attachment #8375611 - Flags: review?(dteller) → feedback+
I was thinking that for my use case it's probably better to explicitly change the permissions than copying the permissions of the source file (it's better not to rely on the assumption that the source file will always have the right permissions).

Can we add a function to OS.File to change file permissions?
> Can we add a function to OS.File to change file permissions?

Fine with me.

I guess it should look like:
OS.File.setPermissions(path, {unixMode: ..., winSecurity: ...})

Do you know how you intend this to work on Windows?

OSFIle is being replaced with IOUtils and PathUtils.

Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → WONTFIX
Product: Toolkit → Toolkit Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: