Handle long symbolic links in apex

In many file systems, long symbolic link are stored outside of the inode
just like regular files. aosp/3382227 made a wrong assumption that all
symlinks in APEXes are short so that they are inlined in inode (aka fast
symlinks).

This CL fixes it. deapexer, when faced with a symlink, tries to read the
symlink by doing `stat` first to read the embedded target. If that
fails, it falls back to use `cat` for reading the target.

Bug: 390558705
Test: cd build/make/tools/releasetools/testdata
unzip foo.apex
debugfs -W -R "symlink long_symlink loooooooooooooooooooooooooooooooooooooooooooooooooong" apex_payload.img
debugfs -R "stat long_symlink" apex_payload.img
<shows EXTENTS: ... , not Fast link dest>
zip -u foo.apex apex_payload.img
deapexer extract foo.apex flatten
readsymlink flatten/long_symlink
<shows looooooooooooooooooooooooooooo....oooong>

Change-Id: I8d20067f99350d4b8ecd2fe7cc5ff87a08379b76
diff --git a/tools/deapexer.py b/tools/deapexer.py
index ade5945..c42724c 100755
--- a/tools/deapexer.py
+++ b/tools/deapexer.py
@@ -295,9 +295,16 @@
     # Output of stat for a symlink should have the following line:
     #   Fast link dest: \"%.*s\"
     m = re.search(r'\bFast link dest: \"(.+)\"\n', stdout)
-    if not m:
+    if m:
+      return m.group(1)
+
+    # if above match fails, it means it's a slow link. Use cat.
+    output = subprocess.check_output([self._debugfs, '-R', f'cat {entry.full_path}',
+                                      self._payload], text=True, stderr=subprocess.DEVNULL)
+
+    if not output:
       sys.exit('failed to read symlink target')
-    return m.group(1)
+    return output
 
   def write_entry(self, entry, out_dir):
     dest = os.path.normpath(os.path.join(out_dir, entry.full_path))