Today I’ve found myself confronted with the task of turning a Android /system Image into a properly flashable update.zip file for use with Clockwork-Mod recovery.

A very simple task actually, just zip up all the /system files and you are done, right? – Wrong.

You need to make sure that you reconstruct the proper linux os file permissions and ownerships, a task that can be quite difficult due to different ROM bases.

To help myself I’ve written a simple C-Program to do the task of constructing a proper Edify Permission & Symlink script for me automatically, and the nice fellow I am I thought other developers might have stumbled over the same issues, so without further beating around the bush, here is the program source.

People that need it know how to use it, for everyone else, you can simply ignore this post.

#include <stdio.h>
#include <string.h>

// Converts rwxrwxrwx Style Descriptions into Octal Display
unsigned int srwxParser(const char * s_srwx)
{
    unsigned int srwx = 0;
    if (s_srwx[0] == 'r') srwx |= 0400;
    if (s_srwx[1] == 'w') srwx |= 0200;
    if (s_srwx[2] == 'x') srwx |= 0100;
    if (s_srwx[2] == 's') srwx |= 04100;
    if (s_srwx[2] == 'S') srwx |= 04000;
    if (s_srwx[3] == 'r') srwx |= 040;
    if (s_srwx[4] == 'w') srwx |= 020;
    if (s_srwx[5] == 'x') srwx |= 010;
    if (s_srwx[5] == 's') srwx |= 02010;
    if (s_srwx[5] == 'S') srwx |= 02000;
    if (s_srwx[6] == 'r') srwx |= 04;
    if (s_srwx[7] == 'w') srwx |= 02;
    if (s_srwx[8] == 'x') srwx |= 01;
    if (s_srwx[8] == 't') srwx |= 01001;
    if (s_srwx[8] == 'T') srwx |= 01000;
    return srwx;
}

// Parses File or Directory Lines from ls -lnAR
int parseFileLine(const char * line, unsigned int * uid, unsigned int * gid, unsigned int * srwx, char * name)
{
    char type = 0;
    char s_srwx[10];
    unsigned int unk = 0;
    unsigned int size = 0;
    char month[10];
    char day[10];
    char hour[10];
    // -rwxr-xr-x 1 root 2000  67124 Apr  2 11:22 add-property-tag
    int filtered = sscanf(line, "%c%s %u %u %u %u %s %s %s %s", &type, s_srwx, &unk, uid, gid, &size, month, day, hour, name);
    //fprintf(stderr, "%s -> %u\n", line, filtered);
    if (filtered == 10)
    {
        *srwx = srwxParser(s_srwx);
        return 1;
    }
    return 0;
}

// Parses Logical Link Lines from ls -lnAR
int parseLinkLine(const char * line, unsigned int * uid, unsigned int * gid, unsigned int * srwx, char * name, char * target)
{
    char type = 0;
    char s_srwx[10];
    unsigned int unk = 0;
    unsigned int size = 0;
    char month[10];
    char day[10];
    char hour[10];
    int filtered = sscanf(line, "%c%s %u %u %u %u %s %s %s %s -> %s", &type, s_srwx, &unk, uid, gid, &size, month, day, hour, name, target);
    if (filtered == 11)
    {
        *srwx = srwxParser(s_srwx);
        return 1;
    }
    return 0;
}

// Outputs Edify set_perm Commands
void outputSetPerm(unsigned int uid, unsigned int gid, unsigned int srwx, const char * currentDirectory, const char * name)
{
    if (currentDirectory[0] != 0)
        printf("set_perm(%u, %u, %#o, \"/system/%s/%s\");\n", uid, gid, srwx, currentDirectory, name);
    else
        printf("set_perm(%u, %u, %#o, \"/system/%s\");\n", uid, gid, srwx, name);
}

// Outputs Edify symlink Commands
void outputSymlink(const char * currentDirectory, const char * name, const char * target)
{
    if (currentDirectory[0] != 0)
        printf("symlink(\"/system/%s/%s\", \"/system/%s/%s\");\n", currentDirectory, target, currentDirectory, name);
    else
        printf("symlink(\"/system/%s\", \"/system/%s\");\n", target, name);
}

// Takes ls -lnAR Input from Linux Shells and transforms the Results into Edify Permission Scripts
// ex. cd /system
//     ls -lnAR | permission-formatter > edify-script
int main(int argc, char * argv[])
{
    // Line Buffer
    char * line = NULL;
    size_t size = 0;

    // Current Directory
    char currentDirectory[1024];

    // Read Lines
    while(getline(&line, &size, stdin) != -1)
    {
        // Remove Trailing Garbage
        int i = 0; for(; i < strlen(line); i++)
        {
            if (line[i] == '\n' || line[i] == '\r')
            {
                line[i] = 0;
            }
        }

        // Directory Line
        if (line[strlen(line) - 1] == ':')
        {
            // Memorize Directory
            strcpy(currentDirectory, line + 2);
            currentDirectory[strlen(currentDirectory) - 1] = 0;
        }

        // Skip Empty Lines
        if (line[0] == 'i' || line[0] == ' ' || line[0] == '\r' || line[0] == '\n')
            continue;

        // File Information
        unsigned int uid = 0;
        unsigned int gid = 0;
        unsigned int srwx = 0;
        char name[1024];
        char target[1024];

        // File or Directory
        if (line[0] == '-' || line[0] == 'd')
        {
            // Parse ls -lnAR Line
            if (parseFileLine(line, &uid, &gid, &srwx, name))
            {
                // Output set_perm Command
                outputSetPerm(uid, gid, srwx, currentDirectory, name);
            }
        }

        // Link
        else if (line[0] == 'l')
        {
            // Parse ls -lnAR Line
            if (parseLinkLine(line, &uid, &gid, &srwx, name, target))
            {
                // Output symlink Command
                outputSymlink(currentDirectory, name, target);

                // Output set_perm Command
                outputSetPerm(uid, gid, srwx, currentDirectory, name);
            }
        }
    }
}

Android /system Image to update.zip

Leave a Reply

Your email address will not be published. Required fields are marked *