aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Shmakov2015-01-27 21:25:56 +0000
committerIvan Shmakov2015-01-27 21:56:57 +0000
commita56eab8259568ea1389e972623e46359e73c0233 (patch)
tree9ab9bc4810a6543f0a6f51c1659c3c374c1751ab
parentbd7a1e1564d04d7ea9c7f6587ffcf02ef8975512 (diff)
downloademacs-a56eab8259568ea1389e972623e46359e73c0233.tar.gz
emacs-a56eab8259568ea1389e972623e46359e73c0233.zip
Allow for adding new members to Tar archives.
* lisp/tar-mode.el: Allow for adding new archive members. (tar-new-regular-file-header, tar--pad-to, tar--put-at) (tar-header-serialize): New functions. (tar-current-position): Split from tar-current-descriptor. (tar-current-descriptor): Use it. (tar-new-entry): New command. (tar-mode-map): Bind it. * doc/emacs/files.texi (File Archives): Document "I" for tar-new-entry. * etc/NEWS: Mention the new tar-new-entry command. Fixes: debbugs:19274
-rw-r--r--doc/emacs/ChangeLog5
-rw-r--r--doc/emacs/files.texi7
-rw-r--r--etc/ChangeLog4
-rw-r--r--etc/NEWS4
-rw-r--r--lisp/ChangeLog10
-rw-r--r--lisp/tar-mode.el115
6 files changed, 141 insertions, 4 deletions
diff --git a/doc/emacs/ChangeLog b/doc/emacs/ChangeLog
index a90c58725f8..b7853a7f118 100644
--- a/doc/emacs/ChangeLog
+++ b/doc/emacs/ChangeLog
@@ -1,3 +1,8 @@
12015-01-27 Ivan Shmakov <ivan@siamics.net>
2
3 * files.texi (File Archives): Document "I" for tar-new-entry.
4 (Bug#19274)
5
12014-12-31 Paul Eggert <eggert@cs.ucla.edu> 62014-12-31 Paul Eggert <eggert@cs.ucla.edu>
2 7
3 Less 'make' chatter for Emacs doc 8 Less 'make' chatter for Emacs doc
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 196c6bb0092..b12b28f9c17 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -1689,6 +1689,13 @@ likewise. @kbd{v} extracts a file into a buffer in View mode
1689another window, so you could edit the file and operate on the archive 1689another window, so you could edit the file and operate on the archive
1690simultaneously. 1690simultaneously.
1691 1691
1692 The @kbd{I} key adds a new (regular) file to the archive. The file
1693is initially empty, but can readily be edited using the commands
1694above. The command inserts the new file before the current one, so
1695that using it on the topmost line of the Tar buffer makes the new file
1696the first one in the archive, and using it at the end of the buffer
1697makes it the last one.
1698
1692 @kbd{d} marks a file for deletion when you later use @kbd{x}, and 1699 @kbd{d} marks a file for deletion when you later use @kbd{x}, and
1693@kbd{u} unmarks a file, as in Dired. @kbd{C} copies a file from the 1700@kbd{u} unmarks a file, as in Dired. @kbd{C} copies a file from the
1694archive to disk and @kbd{R} renames a file within the archive. 1701archive to disk and @kbd{R} renames a file within the archive.
diff --git a/etc/ChangeLog b/etc/ChangeLog
index b31e8a99383..0677e441b83 100644
--- a/etc/ChangeLog
+++ b/etc/ChangeLog
@@ -1,3 +1,7 @@
12015-01-27 Ivan Shmakov <ivan@siamics.net>
2
3 * NEWS: Mention the new tar-new-entry command. (Bug#19274)
4
12015-01-27 Thomas Fitzsimmons <fitzsim@fitzsim.org> 52015-01-27 Thomas Fitzsimmons <fitzsim@fitzsim.org>
2 6
3 * NEWS: Document EUDC improvements. 7 * NEWS: Document EUDC improvements.
diff --git a/etc/NEWS b/etc/NEWS
index 755277854b7..4b0a268d8f2 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -527,6 +527,10 @@ to avoid interfering with the kill ring.
527allow overriding the regular expression that recognizes the ldapsearch 527allow overriding the regular expression that recognizes the ldapsearch
528command line's password prompt. 528command line's password prompt.
529 529
530+++
531** tar-mode: new `tar-new-entry' command, allowing for new members to
532be added to the archive.
533
530** Obsolete packages 534** Obsolete packages
531 535
532--- 536---
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 80dfeef3750..182d7705bb6 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,13 @@
12015-01-27 Ivan Shmakov <ivan@siamics.net>
2
3 * tar-mode.el: Allow for adding new archive members. (Bug#19274)
4 (tar-new-regular-file-header, tar--pad-to, tar--put-at)
5 (tar-header-serialize): New functions.
6 (tar-current-position): Split from tar-current-descriptor.
7 (tar-current-descriptor): Use it.
8 (tar-new-entry): New command.
9 (tar-mode-map): Bind it.
10
12015-01-27 Sam Steingold <sds@gnu.org> 112015-01-27 Sam Steingold <sds@gnu.org>
2 12
3 * progmodes/python.el (python-check-custom-command): Buffer local 13 * progmodes/python.el (python-check-custom-command): Buffer local
diff --git a/lisp/tar-mode.el b/lisp/tar-mode.el
index 1ee54515bea..6c7f7553f82 100644
--- a/lisp/tar-mode.el
+++ b/lisp/tar-mode.el
@@ -50,9 +50,6 @@
50;; 50;;
51;; o chmod should understand "a+x,og-w". 51;; o chmod should understand "a+x,og-w".
52;; 52;;
53;; o It's not possible to add a NEW file to a tar archive; not that
54;; important, but still...
55;;
56;; o The code is less efficient that it could be - in a lot of places, I 53;; o The code is less efficient that it could be - in a lot of places, I
57;; pull a 512-character string out of the buffer and parse it, when I could 54;; pull a 512-character string out of the buffer and parse it, when I could
58;; be parsing it in place, not garbaging a string. Should redo that. 55;; be parsing it in place, not garbaging a string. Should redo that.
@@ -369,6 +366,80 @@ write-date, checksum, link-type, and link-name."
369 string) 366 string)
370 (tar-parse-octal-integer string)) 367 (tar-parse-octal-integer string))
371 368
369(defun tar-new-regular-file-header (filename &optional size time)
370 "Return a Tar header for a regular file.
371The header will lack a proper checksum; use `tar-header-block-checksum'
372to compute one, or request `tar-header-serialize' to do that.
373
374Other tar-mode facilities may also require the data-start header
375field to be set to a valid value.
376
377If SIZE is not given or nil, it defaults to 0.
378If TIME is not given or nil, assume now."
379 (make-tar-header
380 nil
381 filename
382 #o644 0 0 (or size 0)
383 (or time (current-time))
384 nil ; checksum
385 nil nil
386 nil nil nil nil nil))
387
388(defun tar--pad-to (pos)
389 (make-string (+ pos (- (point)) (point-min)) 0))
390
391(defun tar--put-at (pos val &optional fmt mask)
392 (when val
393 (insert (tar--pad-to pos)
394 (if fmt
395 (format fmt (if mask (logand mask val) val))
396 val))))
397
398(defun tar-header-serialize (header &optional update-checksum)
399 "Return the serialization of a Tar HEADER as a string.
400This function calls `tar-header-block-check-checksum' to ensure the
401checksum is correct.
402
403If UPDATE-CHECKSUM is non-nil, update HEADER with the newly-computed
404checksum before doing the check."
405 (with-temp-buffer
406 (set-buffer-multibyte nil)
407 (let ((encoded-name
408 (encode-coding-string (tar-header-name header)
409 tar-file-name-coding-system)))
410 (unless (< (length encoded-name) 99)
411 ;; FIXME: Implement it.
412 (error "Long file name support is not implemented"))
413 (insert encoded-name))
414 (tar--put-at tar-mode-offset (tar-header-mode header) "%6o\0 " #o777777)
415 (tar--put-at tar-uid-offset (tar-header-uid header) "%6o\0 " #o777777)
416 (tar--put-at tar-gid-offset (tar-header-gid header) "%6o\0 " #o777777)
417 (tar--put-at tar-size-offset (tar-header-size header) "%11o ")
418 (insert (tar--pad-to tar-time-offset)
419 (tar-octal-time (tar-header-date header))
420 " ")
421 ;; Omit tar-header-checksum (tar-chk-offset) for now.
422 (tar--put-at tar-linkp-offset (tar-header-link-type header))
423 (tar--put-at tar-link-offset (tar-header-link-name header))
424 (when (tar-header-magic header)
425 (tar--put-at tar-magic-offset (tar-header-magic header))
426 (tar--put-at tar-uname-offset (tar-header-uname header))
427 (tar--put-at tar-gname-offset (tar-header-gname header))
428 (tar--put-at tar-dmaj-offset (tar-header-dmaj header) "%7o\0" #o7777777)
429 (tar--put-at tar-dmin-offset (tar-header-dmin header) "%7o\0" #o7777777))
430 (tar--put-at 512 "")
431 (let ((ck (tar-header-block-checksum (buffer-string))))
432 (goto-char (+ (point-min) tar-chk-offset))
433 (delete-char 8)
434 (insert (format "%6o\0 " ck))
435 (when update-checksum
436 (setf (tar-header-checksum header) ck))
437 (tar-header-block-check-checksum (buffer-string)
438 (tar-header-checksum header)
439 (tar-header-name header)))
440 ;; .
441 (buffer-string)))
442
372 443
373(defun tar-header-block-checksum (string) 444(defun tar-header-block-checksum (string)
374 "Compute and return a tar-acceptable checksum for this block." 445 "Compute and return a tar-acceptable checksum for this block."
@@ -547,6 +618,7 @@ MODE should be an integer which is a file mode value."
547 (define-key map "p" 'tar-previous-line) 618 (define-key map "p" 'tar-previous-line)
548 (define-key map "\^P" 'tar-previous-line) 619 (define-key map "\^P" 'tar-previous-line)
549 (define-key map [up] 'tar-previous-line) 620 (define-key map [up] 'tar-previous-line)
621 (define-key map "I" 'tar-new-entry)
550 (define-key map "R" 'tar-rename-entry) 622 (define-key map "R" 'tar-rename-entry)
551 (define-key map "u" 'tar-unflag) 623 (define-key map "u" 'tar-unflag)
552 (define-key map "v" 'tar-view) 624 (define-key map "v" 'tar-view)
@@ -731,10 +803,14 @@ tar-file's buffer."
731 (interactive "p") 803 (interactive "p")
732 (tar-next-line (- arg))) 804 (tar-next-line (- arg)))
733 805
806(defun tar-current-position ()
807 "Return the `tar-parse-info' index for the current line."
808 (count-lines (point-min) (line-beginning-position)))
809
734(defun tar-current-descriptor (&optional noerror) 810(defun tar-current-descriptor (&optional noerror)
735 "Return the tar-descriptor of the current line, or signals an error." 811 "Return the tar-descriptor of the current line, or signals an error."
736 ;; I wish lines had plists, like in ZMACS... 812 ;; I wish lines had plists, like in ZMACS...
737 (or (nth (count-lines (point-min) (line-beginning-position)) 813 (or (nth (tar-current-position)
738 tar-parse-info) 814 tar-parse-info)
739 (if noerror 815 (if noerror
740 nil 816 nil
@@ -948,6 +1024,37 @@ the current tar-entry."
948 (write-region start end to-file nil nil nil t))) 1024 (write-region start end to-file nil nil nil t)))
949 (message "Copied tar entry %s to %s" name to-file))) 1025 (message "Copied tar entry %s to %s" name to-file)))
950 1026
1027(defun tar-new-entry (filename &optional index)
1028 "Insert a new empty regular file before point."
1029 (interactive "*sFile name: ")
1030 (let* ((buffer (current-buffer))
1031 (index (or index (tar-current-position)))
1032 (d-list (and (not (zerop index))
1033 (nthcdr (+ -1 index) tar-parse-info)))
1034 (pos (if d-list
1035 (tar-header-data-end (car d-list))
1036 (point-min)))
1037 (new-descriptor
1038 (tar-new-regular-file-header filename)))
1039 ;; Update the data buffer; fill the missing descriptor fields.
1040 (with-current-buffer tar-data-buffer
1041 (goto-char pos)
1042 (insert (tar-header-serialize new-descriptor t))
1043 (setf (tar-header-data-start new-descriptor)
1044 (copy-marker (point) nil)))
1045 ;; Update tar-parse-info.
1046 (if d-list
1047 (setcdr d-list (cons new-descriptor (cdr d-list)))
1048 (setq tar-parse-info (cons new-descriptor tar-parse-info)))
1049 ;; Update the listing buffer.
1050 (save-excursion
1051 (goto-char (point-min))
1052 (forward-line index)
1053 (let ((inhibit-read-only t))
1054 (insert (tar-header-block-summarize new-descriptor) ?\n)))
1055 ;; .
1056 index))
1057
951(defun tar-flag-deleted (p &optional unflag) 1058(defun tar-flag-deleted (p &optional unflag)
952 "In Tar mode, mark this sub-file to be deleted from the tar file. 1059 "In Tar mode, mark this sub-file to be deleted from the tar file.
953With a prefix argument, mark that many files." 1060With a prefix argument, mark that many files."