unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Tino Calancha <tino.calancha@gmail.com>
To: 27952@debbugs.gnu.org
Cc: stefan monnier <monnier@iro.umontreal.ca>
Subject: bug#27952: 26.0.50; Combine archive-int-to-mode and tar-grind-file-mode
Date: Wed, 16 Aug 2017 20:43:17 +0900	[thread overview]
Message-ID: <87efsb7n6y.fsf@calancha-pc> (raw)
In-Reply-To: <8760e3zf6v.fsf@calancha-pc> (Tino Calancha's message of "Fri, 04 Aug 2017 21:32:24 +0900")

Tino Calancha <tino.calancha@gmail.com> writes:

> These functions are almost identical; archive-int-to-mode has a FIXME
> suggesting merging it with tar-grind-file-mode.
*)  Updated the patch after Bug#28092 has being fixed.
**) Now `archive-int-to-mode' also shows the sticky bit info as
    `tar-grind-file-mode' does:
     (archive-int-to-mode 996)
     => "-rwxr--r-T"
     (archive-int-to-mode 997)
     => "-rwxr--r-t"
     (tar-grind-file-mode 996)
     => "rwxr--r-T"
     (tar-grind-file-mode 997)
     => "rwxr--r-t"
     ;; `archive-int-to-mode' already was showing the 's' bit info, so
     ;; the fact that wasn't showing the sticky bit must be a mistake.

***) Added new tests.

Please, let me know if you want to have this patch in.
Tino

--8<-----------------------------cut here---------------start------------->8---
commit 74d1a07379a88f62fdb0e497111fdf4845723806
Author: Tino Calancha <tino.calancha@gmail.com>
Date:   Wed Aug 16 20:23:34 2017 +0900

    Combine archive-int-to-mode and tar-grind-file-mode
    
    These functions are almost identical.  Extract a new function
    'file-modes-number-to-symbolic' from them; use it to define
    'archive-int-to-mode' and 'tar-grind-file-mode' (Bug#27952).
    * lisp/files.el (file-modes-number-to-symbolic-1):
    New defun extracted from 'archive-int-to-mode' and 'tar-grind-file-mode'.
    (file-modes-number-to-symbolic):
    New defun;  like `file-modes-number-to-symbolic-1' with 2 optional arguments:
    'detailed' and 'from'.
    
    * lisp/tar-mode.el (tar-grind-file-mode)
    * lisp/arc-mode.el (archive-int-to-mode):
    Use file-modes-number-to-symbolic in its definition.
    
    * test/lisp/arc-mode-tests.el (arc-mode-test-archive-int-to-mode):
    Update test.
    
    * test/lisp/files-tests.el (file-modes-symbolic-to-number)
    (file-modes-number-to-symbolic)
    (file-modes-number-to-symbolic-inverse): Add tests.

diff --git a/lisp/arc-mode.el b/lisp/arc-mode.el
index 938c143b8e..c1987ee774 100644
--- a/lisp/arc-mode.el
+++ b/lisp/arc-mode.el
@@ -550,25 +550,10 @@ archive-l-e
     result))
 
 (defun archive-int-to-mode (mode)
-  "Turn an integer like 0700 (i.e., 448) into a mode string like -rwx------."
-  ;; FIXME: merge with tar-grind-file-mode.
-  (string
-    (if (zerop (logand  8192 mode))
-	(if (zerop (logand 16384 mode)) ?- ?d)
-      ?c) ; completeness
-    (if (zerop (logand   256 mode)) ?- ?r)
-    (if (zerop (logand   128 mode)) ?- ?w)
-    (if (zerop (logand    64 mode))
-	(if (zerop (logand  2048 mode)) ?- ?S)
-      (if (zerop (logand  2048 mode)) ?x ?s))
-    (if (zerop (logand    32 mode)) ?- ?r)
-    (if (zerop (logand    16 mode)) ?- ?w)
-    (if (zerop (logand     8 mode))
-	(if (zerop (logand  1024 mode)) ?- ?S)
-      (if (zerop (logand  1024 mode)) ?x ?s))
-    (if (zerop (logand     4 mode)) ?- ?r)
-    (if (zerop (logand     2 mode)) ?- ?w)
-    (if (zerop (logand     1 mode)) ?- ?x)))
+  "Construct a `-rw-r--r--' string indicating MODE.
+MODE should be an integer which is a file mode value.
+For instance, if mode is 448, then it produces `-rwx------'."
+  (file-modes-number-to-symbolic mode))
 
 (defun archive-calc-mode (oldmode newmode &optional error)
   "From the integer OLDMODE and the string NEWMODE calculate a new file mode.
diff --git a/lisp/files.el b/lisp/files.el
index b05d453b0e..664ea943d9 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -7143,6 +7143,95 @@ file-modes-rights-to-number
 	      op char-right)))
     num-rights))
 
+(defun file-modes-number-to-symbolic-1 (mode)
+  (string
+   (if (zerop (logand  8192 mode))
+       (if (zerop (logand 16384 mode)) ?- ?d)
+     ?c) ; completeness
+   (if (zerop (logand   256 mode)) ?- ?r)
+   (if (zerop (logand   128 mode)) ?- ?w)
+   (if (zerop (logand    64 mode))
+       (if (zerop (logand  2048 mode)) ?- ?S)
+     (if (zerop (logand  2048 mode)) ?x ?s))
+   (if (zerop (logand    32 mode)) ?- ?r)
+   (if (zerop (logand    16 mode)) ?- ?w)
+   (if (zerop (logand     8 mode))
+       (if (zerop (logand  1024 mode)) ?- ?S)
+     (if (zerop (logand  1024 mode)) ?x ?s))
+   (if (zerop (logand     4 mode)) ?- ?r)
+   (if (zerop (logand     2 mode)) ?- ?w)
+   (if (zerop (logand 512 mode))
+       (if (zerop (logand   1 mode)) ?- ?x)
+     (if (zerop (logand   1 mode)) ?T ?t))))
+
+(defun file-modes-number-to-symbolic (mode &optional detailed from)
+  "Turn an integer like 0700 (i.e., 448) into a mode string like -rwx------.
+If optional arg DETAILED is non-nil, then use the format 'u=rwx,g=,o='.
+If optional argument FROM is non-nil, then it's the original file mode
+ to compare with MODE.  FROM is ignored unless DETAILED is non-nil.
+
+For instance, if MODE is 448, DETAILED is non-nil, and FROM is 400,
+the output is 'u+x,g-w'.
+
+Note: This is not the inverse of `file-modes-symbolic-to-number';
+The reason is that this function might return an string containing 'S'
+or 'T' i.e., not valid characters for `file-modes-symbolic-to-number'.
+For example, (file-modes-symbolic-to-number \"o=t\") returns 512;
+and (file-modes-number-to-symbolic 512 t) returns \"o=T\"."
+  (let ((mode (file-modes-number-to-symbolic-1 mode))
+        (from (and from (substring (file-modes-number-to-symbolic-1 from) 1))))
+    (if (not detailed)
+        mode
+      (let ((replace-fn (lambda (x)
+                          (replace-regexp-in-string
+                           ",\\`" ""
+                           (replace-regexp-in-string
+                            "u=," ""
+                            (replace-regexp-in-string
+                             "g=," ""
+                             (replace-regexp-in-string
+                              "o=\\'" "" x)))))))
+        (setq mode (substring mode 1))
+        (cond (from
+               (let* ((res "u")
+                      (special-bit-fn (lambda (x y c C &optional inv) ; c or C in (x y)
+                                        (cond ((eq x c) ; xc
+                                               (cond ((eq y ?-) (string (if inv ?- ?+) ?x c))
+                                                     ((eq y ?x) (string (if inv ?- ?+) c))
+                                                     ((eq y C) (string (if inv ?- ?+) ?x))))
+                                              ((eq x C) ; just c
+                                               (cond ((eq y ?-) (string (if inv ?- ?+) c))
+                                                     ((eq y ?x) (if inv (string ?+ ?x c) (string ?- ?x ?+ c)))
+                                                     ((eq y c) (string (if inv ?+ ?-) ?x))))
+                                              (t nil))))
+                      (compare-fn (lambda (x y)
+                                    (cond ((eq x y) "")
+                                          ;; sticky bit or setuid setgid changes.
+                                          ((or (eq x ?t) (eq x ?T) (eq y ?t) (eq y ?T)
+                                               (eq x ?s) (eq x ?S) (eq y ?s) (eq y ?S))
+                                           (if (or (eq x ?t) (eq x ?T) (eq y ?t) (eq y ?T))
+                                               (or (funcall special-bit-fn x y ?t ?T)
+                                                   (funcall special-bit-fn y x ?t ?T 'inv))
+                                             (or (funcall special-bit-fn x y ?s ?S)
+                                                 (funcall special-bit-fn y x ?s ?S 'inv))))
+                                          ((eq x ?-) (string ?- y))
+                                          ((eq y ?-) (string ?+ x))))))
+                 (dotimes (i (length mode))
+                   (let ((x (aref mode i))
+                         (y (aref from i)))
+                     (when (= i 3) (setq res (concat res ",g")))
+                     (when (= i 6) (setq res (concat res ",o")))
+                     (setq res (concat res (funcall compare-fn x y)))))
+                 (funcall replace-fn res)))
+              (t
+               (funcall replace-fn
+                        (replace-regexp-in-string
+                         "-" ""
+                         (format "u=%s,g=%s,o=%s"
+                                 (substring mode 0 3)
+                                 (substring mode 3 6)
+                                 (substring mode 6))))))))))
+
 (defun file-modes-symbolic-to-number (modes &optional from)
   "Convert symbolic file modes to numeric file modes.
 MODES is the string to convert, it should match
diff --git a/lisp/tar-mode.el b/lisp/tar-mode.el
index b0d3177694..1843cfcc4a 100644
--- a/lisp/tar-mode.el
+++ b/lisp/tar-mode.el
@@ -470,23 +470,9 @@ tar-clip-time-string
 
 (defun tar-grind-file-mode (mode)
   "Construct a `rw-r--r--' string indicating MODE.
-MODE should be an integer which is a file mode value."
-  (string
-   (if (zerop (logand 256 mode)) ?- ?r)
-   (if (zerop (logand 128 mode)) ?- ?w)
-   (if (zerop (logand 2048 mode))
-       (if (zerop (logand  64 mode)) ?- ?x)
-     (if (zerop (logand  64 mode)) ?S ?s))
-   (if (zerop (logand  32 mode)) ?- ?r)
-   (if (zerop (logand  16 mode)) ?- ?w)
-   (if (zerop (logand 1024 mode))
-       (if (zerop (logand   8 mode)) ?- ?x)
-     (if (zerop (logand   8 mode)) ?S ?s))
-   (if (zerop (logand   4 mode)) ?- ?r)
-   (if (zerop (logand   2 mode)) ?- ?w)
-   (if (zerop (logand 512 mode))
-       (if (zerop (logand   1 mode)) ?- ?x)
-     (if (zerop (logand   1 mode)) ?T ?t))))
+MODE should be an integer which is a file mode value.
+For instance, if mode is 448, then it produces `rwx------'."
+  (substring (file-modes-number-to-symbolic mode) 1))
 
 (defun tar-header-block-summarize (tar-hblock &optional mod-p)
   "Return a line similar to the output of `tar -vtf'."
diff --git a/test/lisp/arc-mode-tests.el b/test/lisp/arc-mode-tests.el
index 8c8465d366..f136becf55 100644
--- a/test/lisp/arc-mode-tests.el
+++ b/test/lisp/arc-mode-tests.el
@@ -26,7 +26,7 @@
   (let ((alist (list (cons 448 "-rwx------")
                      (cons 420 "-rw-r--r--")
                      (cons 292 "-r--r--r--")
-                     (cons 512 "----------")
+                     (cons 512 "---------T")
                      (cons 1024 "------S---") ; Bug#28092
                      (cons 2048 "---S------"))))
     (dolist (x alist)
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index a2f2b74312..fc3017027d 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -344,6 +344,71 @@ files-tests--with-temp-file
         (cdr path-res)
         (insert-directory-wildcard-in-dir-p (car path-res)))))))
 
+(ert-deftest file-modes-symbolic-to-number ()
+  (let ((alist '(("a=rwx" . 511)
+                 ("o=t" . 512)
+                 ("o=xt" . 513)
+                 ("o=tx" . 513) ; Order doesn't matter.
+                 ("u=rwx,g=rx,o=rx" . 493)
+                 ("u=rwx,g=,o=" . 448)
+                 ("u=rwx" . 448) ; Empty permissions can be ignored.
+                 ("u=rw,g=r,o=r" . 420)
+                 ("u=rw,g=r,o=t" . 928)
+                 ("u=rw,g=r,o=xt" . 929)
+                 ("u=rwxs,g=rs,o=xt" . 4065)
+                 ("u=rws,g=rs,o=t" . 4000)
+                 ("u=rws,g=rs,o=r" . 3492)
+                 ("a=r" . 292)
+                 ("u=S")
+                 ("u=T")
+                 ("u=Z"))))
+    (dolist (x alist)
+      (if (cdr-safe x)
+          (equal (cdr-safe x) (file-modes-symbolic-to-number (car x)))
+        (should-error (file-modes-symbolic-to-number (car x)))))))
+
+(ert-deftest file-modes-number-to-symbolic ()
+  (let ((from 644)
+        (fn #'file-modes-number-to-symbolic)
+        ;; Alist of the form (MODE RES1 RES2 RES3),
+        ;; MODE is the first argument of FN.
+        ;; RES1, the result of calling FN with 1 argument.
+        ;; RES2, the result of calling FN with 2nd arg non-nil.
+        ;; RES3, the result of calling FN with 2nd arg non-nil and 3rd arg FROM.
+        (alist '((493 "-rwxr-xr-x" "u=rwx,g=rx,o=rx" "u+r+x,g+r+x,o+xt")
+                 (448 "-rwx------" "u=rwx,g=,o=" "u+r+x,o-r-t")
+                 (420 "-rw-r--r--" "u=rw,g=r,o=r" "u+r,g+r,o-t")
+                 (928 "-rw-r----T" "u=rw,g=rx,o=r" "u+r,g+r,o-r")
+                 (929 "-rw-r----t" "u=rw,g=rx,o=rx" "u+r,g+r,o-r+x")
+                 (4065 "-rwsr-S--t" "u=rws,g=rS,o=t" "u+r+xs,g+r+s,o-r+x")
+                 (4000 "-rwSr-S--T" "u=rwS,g=rS,o=T" "u+r+s,g+r+s,o-r")
+                 (3492 "-rwSr-Sr--" "u=rwS,g=rS,o=r" "u+r+s,g+r+s,o-t")
+                 (292 "-r--r--r--" "u=r,g=r,o=r" "u+r-w,g+r,o-t")
+                 ("u=S")
+                 ("u=T")
+                 ("u=Z"))))
+    (dolist (x alist)
+      (cond ((cdr-safe x)
+             (let ((res1 (cadr x)) (res2 (caddr x)) (res3 (cadddr x)))
+               (equal res1 (funcall fn (car x)))
+               ;; FROM is ignored when DETAILED is nil.
+               (equal res1 (funcall fn (car x) nil from))
+               (equal res2 (funcall fn (car x) 'detailed))
+               (equal res3 (funcall fn (car x) 'detailed from))))
+            (t (should-error (funcall fn (car x))))))))
+
+(ert-deftest file-modes-number-to-symbolic-inverse ()
+  (dotimes (i 4096) ; from 0 to 7777 in octal.
+    ;; If neithr sticky bit nor set_uid not set_gid are set, then
+    ;; `file-modes-symbolic-to-number' is the inverse of
+    ;; `file-modes-number-to-symbolic'.
+    (when (and (zerop (logand i 512))
+               (zerop (logand i 1024))
+               (zerop (logand i 2048)))
+      (should
+       (= i
+          (file-modes-symbolic-to-number
+           (file-modes-number-to-symbolic i t)))))))
 
 (provide 'files-tests)
 ;;; files-tests.el ends here

--8<-----------------------------cut here---------------end--------------->8---
In GNU Emacs 26.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.11)
 of 2017-08-16
Repository revision: 400934b694087f4fe94755d78cbd1569efdb1fa8





  reply	other threads:[~2017-08-16 11:43 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-04 12:32 bug#27952: 26.0.50; Combine archive-int-to-mode and tar-grind-file-mode Tino Calancha
2017-08-16 11:43 ` Tino Calancha [this message]
2017-08-16 12:00   ` npostavs
2017-08-16 13:13     ` Tino Calancha
2017-08-16 12:08   ` Andreas Schwab
2017-08-16 13:10     ` Tino Calancha
2019-06-24 20:35 ` Lars Ingebrigtsen
2019-06-24 20:42   ` Tino Calancha
2019-11-11  3:07     ` Stefan Kangas
2019-11-13 16:58       ` Tino Calancha
2020-05-04 11:55         ` Stefan Kangas
2020-05-08 19:53           ` Tino Calancha
2020-05-08 20:06             ` Stefan Monnier
2020-05-08 20:20               ` Tino Calancha
2020-05-14 16:47               ` Tino Calancha
2020-05-14 17:23                 ` Eli Zaretskii
2020-05-14 20:08                   ` Tino Calancha
2020-05-15  6:22                     ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87efsb7n6y.fsf@calancha-pc \
    --to=tino.calancha@gmail.com \
    --cc=27952@debbugs.gnu.org \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).