Merge remote-tracking branch 'toybox/master' into HEAD

Change-Id: I034440bdeecc2a804f6b2a431307807dc707dacf
diff --git a/generated/flags.h b/generated/flags.h
index c95a5de..0357387 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -711,12 +711,14 @@
 #undef FLAG_C
 #endif
 
-// file <1 <1
+// file <1hL[!hL] <1hL[!hL]
 #undef OPTSTR_file
-#define OPTSTR_file "<1"
+#define OPTSTR_file "<1hL[!hL]"
 #ifdef CLEANUP_file
 #undef CLEANUP_file
 #undef FOR_file
+#undef FLAG_L
+#undef FLAG_h
 #endif
 
 // find ?^HL[-HL] ?^HL[-HL]
@@ -3754,6 +3756,8 @@
 #ifndef TT
 #define TT this.file
 #endif
+#define FLAG_L (1<<0)
+#define FLAG_h (1<<1)
 #endif
 
 #ifdef FOR_find
diff --git a/generated/help.h b/generated/help.h
index 3e3c339..cd5ade7 100644
--- a/generated/help.h
+++ b/generated/help.h
@@ -534,7 +534,7 @@
 
 #define HELP_find "usage: find [-HL] [DIR...] [<options>]\n\nSearch directories for matching files.\nDefault: search \".\" match all -print all matches.\n\n-H  Follow command line symlinks         -L  Follow all symlinks\n\nMatch filters:\n-name  PATTERN  filename with wildcards   -iname      case insensitive -name\n-path  PATTERN  path name with wildcards  -ipath      case insensitive -path\n-user  UNAME    belongs to user UNAME     -nouser     user ID not known\n-group GROUP    belongs to group GROUP    -nogroup    group ID not known\n-perm  [-/]MODE permissions (-=min /=any) -prune      ignore contents of dir\n-size  N[c]     512 byte blocks (c=bytes) -xdev       only this filesystem\n-links N        hardlink count            -atime N    accessed N days ago\n-ctime N        created N days ago        -mtime N    modified N days ago\n-newer FILE     newer mtime than FILE     -mindepth # at least # dirs down\n-depth          ignore contents of dir    -maxdepth # at most # dirs down\n-inum  N        inode number N            -empty      empty files and dirs\n-type [bcdflps] (block, char, dir, file, symlink, pipe, socket)\n\nNumbers N may be prefixed by a - (less than) or + (greater than):\n\nCombine matches with:\n!, -a, -o, ( )    not, and, or, group expressions\n\nActions:\n-print   Print match with newline  -print0    Print match with null\n-exec    Run command with path     -execdir   Run command in file's dir\n-ok      Ask before exec           -okdir     Ask before execdir\n-delete  Remove matching file/dir\n\nCommands substitute \"{}\" with matched file. End with \";\" to run each file,\nor \"+\" (next argument after \"{}\") to collect and run with multiple files.\n\n"
 
-#define HELP_file "usage: file [file...]\n\nExamine the given files and describe their content types.\n\n"
+#define HELP_file "usage: file [-hL] [file...]\n\nExamine the given files and describe their content types.\n\n-h	don't follow symlinks (default)\n-L	follow symlinks\n\n"
 
 #define HELP_false "Return nonzero.\n\n"
 
diff --git a/generated/newtoys.h b/generated/newtoys.h
index edca9c9..4dfb112 100644
--- a/generated/newtoys.h
+++ b/generated/newtoys.h
@@ -65,7 +65,7 @@
 USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
 USE_FDISK(NEWTOY(fdisk, "C#<0H#<0S#<0b#<512ul", TOYFLAG_SBIN))
 USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
-USE_FILE(NEWTOY(file, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FILE(NEWTOY(file, "<1hL[!hL]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_FLOCK(NEWTOY(flock, "<1>1nsux[-sux]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/tests/file.test b/tests/file.test
index 234282f..4c7f001 100644
--- a/tests/file.test
+++ b/tests/file.test
@@ -10,6 +10,7 @@
 echo "#!  /usr/bin/env python" > env.python.script
 echo "Hello, world!" > ascii
 echo "cafebabe000000310000" | xxd -r -p > java.class
+ln -s java.class symlink
 
 testing "empty" "file empty" "empty: empty\n" "" ""
 testing "bash.script" "file bash.script" "bash.script: /bin/bash script\n" "" ""
@@ -17,5 +18,8 @@
 testing "env python script" "file env.python.script" "env.python.script: python script\n" "" ""
 testing "ascii" "file ascii" "ascii: ASCII text\n" "" ""
 testing "java class" "file java.class" "java.class: Java class file, version 49.0\n" "" ""
+testing "symlink" "file symlink" "symlink: symbolic link\n" "" ""
+testing "symlink -h" "file -h symlink" "symlink: symbolic link\n" "" ""
+testing "symlink -L" "file -L symlink" "symlink: Java class file, version 49.0\n" "" ""
 
 rm empty bash.script bash.script2 env.python.script ascii java.class
diff --git a/toys/posix/file.c b/toys/posix/file.c
index 27b4c0c..4827f8f 100644
--- a/toys/posix/file.c
+++ b/toys/posix/file.c
@@ -3,18 +3,19 @@
  * Copyright 2016 The Android Open Source Project
  *
  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/file.html
- *
- * TODO: ar
 
-USE_FILE(NEWTOY(file, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FILE(NEWTOY(file, "<1hL[!hL]", TOYFLAG_USR|TOYFLAG_BIN))
 
 config FILE
   bool "file"
   default y
   help
-    usage: file [file...]
+    usage: file [-hL] [file...]
 
     Examine the given files and describe their content types.
+
+    -h	don't follow symlinks (default)
+    -L	follow symlinks
 */
 
 #define FOR_file
@@ -176,6 +177,7 @@
   if (len<0) perror_msg("%s", name);
 
   if (len>40 && strstart(&s, "\177ELF")) do_elf_file(fd, sb);
+  else if (len>=8 && strstart(&s, "!<arch>\n")) xprintf("ar archive\n");
   else if (len>28 && strstart(&s, "\x89PNG\x0d\x0a\x1a\x0a")) {
     // PNG is big-endian: https://www.w3.org/TR/PNG/#7Integers-and-byte-order
     int chunk_length = peek_be(s, 4);
@@ -281,7 +283,7 @@
 
     xprintf("%s: %*s", name, (int)(TT.max_name_len - strlen(name)), "");
 
-    if (fd || !lstat(name, &sb)) {
+    if (fd || !((toys.optflags & FLAG_L) ? stat : lstat)(name, &sb)) {
       if (fd || S_ISREG(sb.st_mode)) {
         if (!sb.st_size) what = "empty";
         else if ((fd = openro(name, O_RDONLY)) != -1) {
diff --git a/toys/posix/ls.c b/toys/posix/ls.c
index 5d1e060..b052eac 100644
--- a/toys/posix/ls.c
+++ b/toys/posix/ls.c
@@ -463,7 +463,7 @@
         printf("% *d,% 4d", totals[5]-4, dev_major(st->st_rdev),
           dev_minor(st->st_rdev));
       else {
-        print_with_h(tmp, st->st_size, 0);
+        print_with_h(tmp, st->st_size, 1);
         printf("%*s", totals[5]+1, tmp);
       }