ijar: Avoid running past the end of a static buffer.

```
INFO: From Compiling third_party/ijar/zip_main.cc:
In file included from /usr/include/string.h:495,
                 from third_party/ijar/zip_main.cc:28:
In function 'char* strncpy(char*, const char*, size_t)',
    inlined from 'int devtools_ijar::extract(char*, char*, char**, bool, bool, bool)' at third_party/ijar/zip_main.cc:159:12:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:106:34: warning: 'char* __builtin_strncpy(char*, const char*, long unsigned int)' specified bound 4096 equals destination size [-Wstringop-truncation]
  106 |   return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
      |          ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

Closes #12292.

PiperOrigin-RevId: 341446599
diff --git a/third_party/ijar/zip_main.cc b/third_party/ijar/zip_main.cc
index b375da3..ba33a8b 100644
--- a/third_party/ijar/zip_main.cc
+++ b/third_party/ijar/zip_main.cc
@@ -80,21 +80,26 @@
 };
 
 // Concatene 2 path, path1 and path2, using / as a directory separator and
-// puting the result in "out". "size" specify the size of the output buffer
-void concat_path(char* out, const size_t size,
-                 const char *path1, const char *path2) {
+// putting the result in "out". "size" specify the size of the output buffer. If
+// the result would overflow the output buffer, print an error message and
+// return false.
+bool concat_path(char *out, const size_t size, const char *path1,
+                 const char *path2) {
   int len1 = strlen(path1);
   size_t l = len1;
   strncpy(out, path1, size - 1);
-  out[size-1] = 0;
+  out[size - 1] = 0;
   if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') {
     out[l] = '/';
     l++;
     out[l] = 0;
   }
-  if (l < size - 1) {
-    strncat(out, path2, size - 1 - l);
+  if (l >= size - 1) {
+    fprintf(stderr, "paths too long to concat: %s + %s", path1, path2);
+    return false;
   }
+  strncat(out, path2, size - 1 - l);
+  return true;
 }
 
 void UnzipProcessor::Process(const char* filename, const u4 attr,
@@ -123,8 +128,8 @@
   }
   if (extract_) {
     char path[PATH_MAX];
-    concat_path(path, PATH_MAX, output_root_, output_file_name);
-    if (!make_dirs(path, perm) ||
+    if (!concat_path(path, sizeof(path), output_root_, output_file_name) ||
+        !make_dirs(path, perm) ||
         (!isdir && !write_file(path, perm, data, size))) {
       abort();
     }
@@ -140,8 +145,8 @@
   } else {
     pointer++;  // Skip the leading slash.
   }
-  strncpy(output, pointer, output_size);
-  output[output_size-1] = 0;
+  strncpy(output, pointer, output_size - 1);
+  output[output_size - 1] = 0;
 }
 
 // Execute the extraction (or just listing if just v is provided)
@@ -152,11 +157,16 @@
     return -1;
   }
 
-  char output_root[PATH_MAX];
+  char output_root[PATH_MAX + 1];
   if (exdir != NULL) {
-    concat_path(output_root, PATH_MAX, cwd.c_str(), exdir);
+    if (!concat_path(output_root, sizeof(output_root), cwd.c_str(), exdir)) {
+      return -1;
+    }
+  } else if (cwd.length() >= sizeof(output_root)) {
+    fprintf(stderr, "current working directory path too long");
+    return -1;
   } else {
-    strncpy(output_root, cwd.c_str(), PATH_MAX);
+    memcpy(output_root, cwd.c_str(), cwd.length() + 1);
   }
 
   UnzipProcessor processor(output_root, files, verbose, extract, flatten);