On Oct 22, 2012, at 4:47 PM, was <skylog...@btconnect.com> wrote:
> As I'm not familiar with unix permissions, is there a way of changing the 
> permissions for the App.AppName folder?

Yes: with the chmod(2) system call [0, 1]. (Insert rant about how C# actually 
allows you to do things like this, while it's not easy in Java w/o using JNI).

> I looked at using permission: MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE, 
> but these aren't available in the MfA 4.2.6 Required Permissions list.

1. They're not permissions, they're integer constants for use with e.g. 
Context.OpenFileOutput().
2. MODE_WORLD_READABLE is mapped to the 
Android.Content.FileCreationMode.WorldReadable enum value [2].

> I'm also not sure they would fix the problem anyway.

Using FileCerationMode.WorldReadable would workaround the problem: 
Context.OpenFileOutput() allows you to specify the FileCreationMode, which sets 
the Unix mode for that specific file (at creation time, iirc):

        using (var o = new StreamWriter(OpenFileOutput("foo.txt", 
FileCreationMode.WorldReadable)))
                o.WriteLine ("Hello, world!"); 

The file created in that fashion will be in a directory that by default can't 
be listed:

        $ adb shell ls -l /data/data/Scratch.PublicFiles/files
        opendir failed, Permission denied 

However, if you know the name of the file you can read it:

        $ adb shell cat /data/data/Scratch.PublicFiles/files/foo.txt
        Hello, world!

This may in fact be suitable for your purposes, and has an added "security" 
benefit (obfuscation) that the names of the files aren't determined easily.

There is another interesting Context method that takes a FileCreationMode: 
Context.GetDir(string, FileCreationMode) [3]. This will create a new directory, 
but what's interesting is two things:

1. The directory it creates isn't a child of Context.FilesDir:

        var d = GetDir ("foo", FileCreationMode.WorldReadable | 
FileCreationMode.WorldWriteable);
        Console.WriteLine ("Created: {0}", d.AbsolutePath);
        // Created: /data/data/Scratch.PublicFiles/app_foo

Notice that the directory name gets an "app_" prefix.

2. The only way (that I've found) to create a file with a specific set of 
permissions is Context.OpenFileOutput(), and Context.OpenFileOutput() doesn't 
allow you to specify sub-directories. Consequently the only way to use the 
above "app_foo" directory is via normal System.IO methods, which creates files 
with the default process umask, which is no good here:

        // C# code
        var bar = Path.Combine (d.AbsolutePath, "bar.txt");
        using (var o = File.AppendText (bar))
                o.WriteLine ("managed foo/bar.txt contents");

        # verification...
        $ adb shell ls -l /data/data/Scratch.PublicFiles/app_foo
        -rw------- u0_a62   u0_a62         58 2012-10-23 21:50 bar.txt

We can't do anything with that file; the "other" permissions are "---", aka 
"nothing".

This makes Context.GetDir() + create-file rather worthless unless you 
subsequently change the file's permissions:

                int p666 = LinuxUtils.Syscall.S_IRUSR | 
LinuxUtils.Syscall.S_IWUSR | \
                        LinuxUtils.Syscall.S_IRGRP | LinuxUtils.Syscall.S_IWGRP 
| \
                        LinuxUtils.Syscall.S_IROTH | LinuxUtils.Syscall.S_IWOTH;
                LinuxUtils.Syscall.chmod (bar, p666);

Given that the above is (1) ugly, and (2) requires a bit of support code ([0]), 
the easiest path is to accept the inability to use `ls`, use 
Context.OpenFileOutput(), and just "know" which files you can read or write.

 - Jon

[0] 
        namespace LinuxUtils {
                using System.Runtime.InteropServices;

                static class Syscall {

                        public const int S_IRWXU = 0x1C0; // 00700
                        public const int S_IRUSR = 0x100; // 00400
                        public const int S_IWUSR = 0x080; // 00200
                        public const int S_IXUSR = 0x040; // 00100

                        public const int S_IRWXG = 0x038; // 00070
                        public const int S_IRGRP = 0x020; // 00040
                        public const int S_IWGRP = 0x010; // 00020
                        public const int S_IXGRP = 0x008; // 00010

                        public const int S_IRWXO = 0x007; // 00007
                        public const int S_IROTH = 0x004; // 00004
                        public const int S_IWOTH = 0x002; // 00002
                        public const int S_IXOTH = 0x001; // 00001

                        [DllImport ("c")]
                        public static extern int chmod (string path, int mode);
                }
        }

[1] This will change the permissions of /data/data/@PACKAGE_NAME@/files so that 
it's world readable and world writable, using [0]:

        LinuxUtils.Syscall.chmod (FilesDir.AbsolutePath, 
LinuxUtils.Syscall.S_IRWXU | LinuxUtils.Syscall.S_IRWXG | 
LinuxUtils.Syscall.S_IRWXO); 

[2] http://androidapi.xamarin.com/?link=T:Android.Content.FileCreationMode

[3] 
http://androidapi.xamarin.com/monodoc.ashx?link=M%3aAndroid.Content.Context.GetDir(System.String%2cAndroid.Content.FileCreationMode)

_______________________________________________
Monodroid mailing list
Monodroid@lists.ximian.com

UNSUBSCRIBE INFORMATION:
http://lists.ximian.com/mailman/listinfo/monodroid

Reply via email to