Function: tramp-skeleton-write-region

tramp-skeleton-write-region is a macro defined in tramp.el.gz.

Signature

(tramp-skeleton-write-region START END FILENAME APPEND VISIT LOCKNAME MUSTBENEW &rest BODY)

Documentation

Skeleton for tramp-*-handle-write-region.

BODY is the backend specific code.

Source Code

;; Defined in /usr/src/emacs/lisp/net/tramp.el.gz
(defmacro tramp-skeleton-write-region
  (start end filename append visit lockname mustbenew &rest body)
  "Skeleton for `tramp-*-handle-write-region'.
BODY is the backend specific code."
  (declare (indent 7) (debug t))
  ;; Sometimes, there is another file name handler responsible for
  ;; VISIT, for example `jka-compr-handler'.  We must respect this.
  ;; See Bug#55166.
  `(let* ((filename (expand-file-name ,filename))
	  (lockname (file-truename (or ,lockname filename)))
	  (handler (and (stringp ,visit)
			(let ((inhibit-file-name-handlers
			       `(tramp-file-name-handler
				 tramp-crypt-file-name-handler
				 . ,inhibit-file-name-handlers))
			      (inhibit-file-name-operation 'write-region))
			  (find-file-name-handler ,visit 'write-region))))
	  ;; We use this to save the value of
	  ;; `last-coding-system-used' after writing the tmp file.  At
	  ;; the end of the function, we set `last-coding-system-used'
	  ;; to this saved value.  This way, any intermediary coding
	  ;; systems used while talking to the remote shell or
	  ;; suchlike won't hose this variable.  This approach was
	  ;; snarfed from ange-ftp.el.
	  coding-system-used)
     (with-parsed-tramp-file-name filename nil
       (if handler
	   (progn
	     (tramp-message
	      v 5 "Calling handler `%s' for visiting `%s'" handler ,visit)
	     (funcall
	      handler 'write-region
	      ,start ,end filename ,append ,visit lockname ,mustbenew))

	 (when (and ,mustbenew (file-exists-p filename)
		    (or (eq ,mustbenew 'excl)
			(not
			 (y-or-n-p
			  (format
			   "File %s exists; overwrite anyway?" filename)))))
	   (tramp-error v 'file-already-exists filename))

	 (let ((file-locked (eq (file-locked-p lockname) t))
	       (uid (or (file-attribute-user-id
			 (file-attributes filename 'integer))
			(tramp-get-remote-uid v 'integer)))
	       (gid (or (file-attribute-group-id
			 (file-attributes filename 'integer))
			(tramp-get-remote-gid v 'integer)))
	       (attributes (file-extended-attributes filename))
	       (curbuf (current-buffer)))

	   ;; Lock file.
	   (when (and (not (auto-save-file-name-p
			    (file-name-nondirectory filename)))
		      (tramp-tramp-file-p lockname)
		      (not file-locked))
	     (setq file-locked t)
	     (lock-file lockname))

	   ;; The body.
	   ,@body

	   ;; We must also flush the cache of the directory, because
	   ;; `file-attributes' reads the values from there.
	   (tramp-flush-file-properties v localname)
	   ;; Set the "file-exists-p" file property, because it is
	   ;; likely that it is needed shortly after `write-region'.
	   (tramp-set-file-property v localname "file-exists-p" t)

	   (let (last-coding-system-used (need-chown t))
	     ;; Set file modification time.
	     (when-let* (((or (eq ,visit t) (stringp ,visit)))
			 (file-attr (file-attributes filename 'integer)))
	       (set-visited-file-modtime
		;; We must pass modtime explicitly, because FILENAME
		;; can be different from (buffer-file-name), f.e. if
		;; `file-precious-flag' is set.
		(or (file-attribute-modification-time file-attr)
		    (current-time)))
	       (when (and (= (file-attribute-user-id file-attr) uid)
			  (= (file-attribute-group-id file-attr) gid))
		 (setq need-chown nil)))

	     ;; Set the ownership.
             (when need-chown
               (tramp-set-file-uid-gid filename uid gid))

	     ;; Set extended attributes.  We ignore possible errors,
	     ;; because ACL strings or SELinux contexts could be incompatible.
	     (when attributes
	       (ignore-errors
		 (set-file-extended-attributes filename attributes)))

	     ;; Unlock file.
	     (when file-locked
	       (unlock-file lockname))

	     ;; Sanity check.
	     (unless (equal curbuf (current-buffer))
	       (tramp-error
		v 'file-error
		"Buffer has changed from `%s' to `%s'" curbuf (current-buffer)))

	     (when (and (null noninteractive)
			(or (eq ,visit t) (string-or-null-p ,visit)))
	       (tramp-message v 0 "Wrote %s" filename))
	     (run-hooks 'tramp-handle-write-region-hook))))

       ;; Make `last-coding-system-used' have the right value.
       (when coding-system-used
	 (setq last-coding-system-used coding-system-used)))))