Merge "adb: configure /system file permission with fs_config"
diff --git a/adb/Android.mk b/adb/Android.mk
index 721b48d..155c6e5 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -130,7 +130,7 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt
+LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux
 include $(BUILD_EXECUTABLE)
 
 
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index f24f14c..c30f9fb 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -22,19 +22,32 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <utime.h>
+#include <unistd.h>
 
 #include <errno.h>
-
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
 #include "sysdeps.h"
 
 #define TRACE_TAG  TRACE_SYNC
 #include "adb.h"
 #include "file_sync_service.h"
 
+/* TODO: use fs_config to configure permissions on /data */
+static bool is_on_system(const char *name) {
+    const char *SYSTEM = "/system/";
+    return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
+}
+
 static int mkdirs(char *name)
 {
     int ret;
     char *x = name + 1;
+    unsigned int uid, gid;
+    unsigned int mode = 0775;
+    uint64_t cap = 0;
+    uid = getuid();
+    gid = getgid();
 
     if(name[0] != '/') return -1;
 
@@ -42,11 +55,21 @@
         x = adb_dirstart(x);
         if(x == 0) return 0;
         *x = 0;
-        ret = adb_mkdir(name, 0775);
+        if (is_on_system(name)) {
+            fs_config(name, 1, &uid, &gid, &mode, &cap);
+        }
+        ret = adb_mkdir(name, mode);
         if((ret < 0) && (errno != EEXIST)) {
             D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
             *x = '/';
             return ret;
+        } else if(ret == 0) {
+            ret = chown(name, uid, gid);
+            if (ret < 0) {
+                *x = '/';
+                return ret;
+            }
+            selinux_android_restorecon(name);
         }
         *x++ = '/';
     }
@@ -149,7 +172,8 @@
     return fail_message(s, strerror(errno));
 }
 
-static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
+static int handle_send_file(int s, char *path, unsigned int uid,
+        unsigned int gid, mode_t mode, char *buffer)
 {
     syncmsg msg;
     unsigned int timestamp = 0;
@@ -157,8 +181,13 @@
 
     fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
     if(fd < 0 && errno == ENOENT) {
-        mkdirs(path);
-        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+        if(mkdirs(path) != 0) {
+            if(fail_errno(s))
+                return -1;
+            fd = -1;
+        } else {
+            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+        }
     }
     if(fd < 0 && errno == EEXIST) {
         fd = adb_open_mode(path, O_WRONLY, mode);
@@ -167,6 +196,16 @@
         if(fail_errno(s))
             return -1;
         fd = -1;
+    } else {
+        if(fchown(fd, uid, gid) != 0) {
+            fail_errno(s);
+            errno = 0;
+        }
+        /* fchown clears the setuid bit - restore it if present */
+        if(fchmod(fd, mode) != 0) {
+            fail_errno(s);
+            errno = 0;
+        }
     }
 
     for(;;) {
@@ -206,6 +245,7 @@
     if(fd >= 0) {
         struct utimbuf u;
         adb_close(fd);
+        selinux_android_restorecon(path);
         u.actime = timestamp;
         u.modtime = timestamp;
         utime(path, &u);
@@ -249,7 +289,10 @@
 
     ret = symlink(buffer, path);
     if(ret && errno == ENOENT) {
-        mkdirs(path);
+        if(mkdirs(path) != 0) {
+            fail_errno(s);
+            return -1;
+        }
         ret = symlink(buffer, path);
     }
     if(ret) {
@@ -277,7 +320,7 @@
 static int do_send(int s, char *path, char *buffer)
 {
     char *tmp;
-    mode_t mode;
+    unsigned int mode;
     int is_link, ret;
 
     tmp = strrchr(path,',');
@@ -288,7 +331,7 @@
 #ifndef HAVE_SYMLINKS
         is_link = 0;
 #else
-        is_link = S_ISLNK(mode);
+        is_link = S_ISLNK((mode_t) mode);
 #endif
         mode &= 0777;
     }
@@ -307,11 +350,23 @@
 #else
     {
 #endif
+        unsigned int uid, gid;
+        uint64_t cap = 0;
+        uid = getuid();
+        gid = getgid();
+
         /* copy user permission bits to "group" and "other" permissions */
         mode |= ((mode >> 3) & 0070);
         mode |= ((mode >> 3) & 0007);
 
-        ret = handle_send_file(s, path, mode, buffer);
+        tmp = path;
+        if(*tmp == '/') {
+            tmp++;
+        }
+        if (is_on_system(path)) {
+            fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        }
+        ret = handle_send_file(s, path, uid, gid, mode, buffer);
     }
 
     return ret;