aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorIvan Shmakov2015-01-27 21:25:56 +0000
committerIvan Shmakov2015-01-27 21:56:57 +0000
commita56eab8259568ea1389e972623e46359e73c0233 (patch)
tree9ab9bc4810a6543f0a6f51c1659c3c374c1751ab /lisp
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
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog10
-rw-r--r--lisp/tar-mode.el115
2 files changed, 121 insertions, 4 deletions
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."