[Droid RAZR M General] cernekee:
Some of my recent development work has involved frequent changes between stock ROMs and custom ROMs on a Droid Razr M, and I quickly grew weary of dealing with RSD Lite and Windows. So I put together a procedure for converting the .xml.zip ROM into an "update.zip" which is flashable via TWRP.

1) Download the .xml.zip file. I used VZW_XT907_4.1.1-9.8.1Q-27-2-4_1FF.xml.zip from here.

2) Unzip the file into a temporary directory.

3) Extract the system.img sparse ext4 filesystem using simg2img from AOSP (or simg2img.py). Note that the Motorola images have an extra header which needs to be removed with "dd":

dd if=system.img of=simg bs=131072 skip=1
simg2img simg raw.img
sudo mount -o loop raw.img /mnt

If all goes well, you should see the /system contents under /mnt:

$ ls -l /mnt
total 72
drwxr-xr-x 2 root root 12288 Oct 21 2012 app/
drwxr-xr-x 2 root 2000 8192 Oct 21 2012 bin/
-rw-r--r-- 1 root root 7562 Oct 21 2012 build.prop
drwxr-xr-x 16 root root 4096 Oct 21 2012 etc/
drwxr-xr-x 2 root root 4096 Oct 21 2012 fonts/
drwxr-xr-x 2 root root 4096 Oct 21 2012 framework/
drwxr-xr-x 9 root root 12288 Oct 21 2012 lib/
drwxr-xr-x 4 root root 4096 Oct 21 2012 media/
drwxr-xr-x 3 root root 4096 Oct 21 2012 tts/
drwxr-xr-x 8 root root 4096 Oct 21 2012 usr/
drwxr-xr-x 5 root 2000 4096 Oct 21 2012 vendor/
drwxr-xr-x 2 root 2000 4096 Oct 21 2012 xbin/

4) Make a new directory for your update.zip contents.

A minimal update.zip contains the system/ partition contents, plus three files:

boot.img - kernel image

META-INF/com/google/android/update-binary - I copied this from a CM 10.1 zip

META-INF/com/google/android/updater-script - see below

Copy boot.img (from the .xml.zip file) and update-binary (from another ROM) into the appropriate locations.

5) Create a new updater-script. A bare bones script for XT907 looks like:

assert(getprop("ro.product.device") == "xt907" || getprop("ro.product.device") == "scorpion_mini");
format("ext4", "EMMC", "/dev/block/platform/msm_sdcc.1/by-name/system", "0", "/system");
mount("ext4", "EMMC", "/dev/block/platform/msm_sdcc.1/by-name/system", "/system");
package_extract_dir("system", "/system");
[i][file permissions - see below][/i]
package_extract_file("boot.img", "/dev/block/platform/msm_sdcc.1/by-name/boot");
unmount("/system");

6) Fill in the file permissions section.

To generate the file permission commands, I wrote a perl script "dumpperms.pl" which traverses the loopback-mounted /system partition and prints a "set_perm" or "symlink" command for each entry that requires it. This looks something like:

$ dumpperms.pl /mnt
set_perm_recursive(0, 0, 0755, 0644, "/system");
set_perm(0, 2000, 0755, "/system/bin");
set_perm(0, 2000, 0755, "/system/bin/ATFWD-daemon");
set_perm(0, 2000, 0755, "/system/bin/RescueServer");
set_perm(0, 2000, 0755, "/system/bin/RescueStarter");
[...]
set_perm(1002, 1002, 0440, "/system/etc/bluetooth/network.conf");
set_perm(1014, 2000, 0550, "/system/etc/dhcpcd/dhcpcd-run-hooks");
symlink("/data/misc/audio/wcd9310_anc.bin", "/system/etc/firmware/wcd9310/wcd9310_anc.bin");
symlink("/data/misc/audio/mbhc.bin", "/system/etc/firmware/wcd9310/wcd9310_mbhc.bin");
[...]

The output from this script should be pasted into the permissions section of updater-script.

7) Create the new update.zip file. boot.img, system/, and META-INF/ should be at the top level:

$ ls
boot.img META-INF/ system/
$ rm -f /tmp/update.zip ; zip -r /tmp/update.zip .
zip warning: name not matched: system/lib/modules/wlan.ko
zip warning: name not matched: system/vendor/firmware
zip warning: name not matched: system/etc/firmware/wcd9310/wcd9310_anc.bin
zip warning: name not matched: system/etc/firmware/wcd9310/wcd9310_mbhc.bin
zip warning: name not matched: system/etc/firmware/wlan/prima/WCNSS_qcom_wlan_nv.bin
zip warning: name not matched: system/etc/firmware/wlan/prima/WCNSS_qcom_cfg.ini
adding: boot.img (deflated 49%)
adding: system/ (stored 0%)
adding: system/media/ (stored 0%)
adding: system/media/KnowYourDevice/ (stored 0%)
[...]

The file should now be ready for flashing / sideloading. The provided template does not clear /data or /cache, so that can be done by hand or added to the updater-script.