How do i set extended user attributes on android files?
Asked Answered
S

1

16

Is there a way for my android app to retrieve and set extended user attributes of files? Is there a way to use java.nio.file.Files on android? Is there any way to use setfattr and getfattr from my dalvik app? I know that android use the ext4 file system, so i guess it should be possible. Any suggestions?

Synonymous answered 22/7, 2013 at 9:35 Comment(0)
E
13

The Android Java library and the bionic C library do not support it. So you have to use native code with Linux syscalls for that.

Here is some sample code to get you started, tested on Android 4.2 and Android 4.4.

XAttrNative.java

package com.appfour.example;

import java.io.IOException;

public class XAttrNative {
    static {
        System.loadLibrary("xattr");
    }

    public static native void setxattr(String path, String key, String value) throws IOException;
}

xattr.c

#include <string.h>
#include <jni.h>
#include <asm/unistd.h>
#include <errno.h>

void Java_com_appfour_example_XAttrNative_setxattr(JNIEnv* env, jclass clazz,
        jstring path, jstring key, jstring value) {
    char* pathChars = (*env)->GetStringUTFChars(env, path, NULL);
    char* keyChars = (*env)->GetStringUTFChars(env, key, NULL);
    char* valueChars = (*env)->GetStringUTFChars(env, value, NULL);

    int res = syscall(__NR_setxattr, pathChars, keyChars, valueChars,
            strlen(valueChars), 0);

    if (res != 0) {
        jclass exClass = (*env)->FindClass(env, "java/io/IOException");
        (*env)->ThrowNew(env, exClass, strerror(errno));
    }

    (*env)->ReleaseStringUTFChars(env, path, pathChars);
    (*env)->ReleaseStringUTFChars(env, key, keyChars);
    (*env)->ReleaseStringUTFChars(env, value, valueChars);
}

This works fine on internal storage but not on (emulated) external storage which uses the sdcardfs filesystem or other kernel functions to disable features not supported by the FAT filesystem such as symlinks and extended attributes. Arguably they do this because external storage can be accessed by connecting the device to a PC and the users expects that copying files back and forth preserves all information.

So this works:

File dataFile = new File(getFilesDir(),"test");
dataFile.createNewFile();
XAttrNative.setxattr(dataFile.getPath(), "user.testkey", "testvalue");

while this throws IOException with the error message: "Operation not supported on transport endpoint":

File externalStorageFile = new File(getExternalFilesDir(null),"test");
externalStorageFile.createNewFile();
XAttrNative.setxattr(externalStorageFile.getPath(), "user.testkey", "testvalue");
Exteriorize answered 24/6, 2014 at 9:41 Comment(8)
why the second one throws an exception?Ashmead
Because Google does not want any functionality which goes beyond that supported by FAT to work on external storage - emulated or not. That includes symlinks, extended attributes, ... They enforce this with sdcardfs and other kernel functionality. Arguably they do this because external storage can be accessed by connecting the device to a PC and the users expects that copying files back and forth preserves all information.Exteriorize
well actually this should be part of your answerAshmead
Wow nice answer. So just to verify, it generally isn't possible to use extended attributes on external storage, it will only work via this native code for "local" files?Toughie
@Toughie Yes, it will only work for files on "internal storage". Here is an overview over the storage options.Exteriorize
@HansKratz : just one point, all of this require root, isn’t it ?Mulch
@Mulch Nope, that works fine without root (at least on Android 4.4).Exteriorize
You should be able to set xattrs on a file on Android before moving it into the external storage. Isn't this the case ?Gretchengrete

© 2022 - 2024 — McMap. All rights reserved.