Function: tramp-smb-read-file-entry

tramp-smb-read-file-entry is a byte-compiled function defined in tramp-smb.el.gz.

Signature

(tramp-smb-read-file-entry SHARE)

Documentation

Parse entry in SMB output buffer.

If SHARE is result, entries are of type dir. Otherwise, shares are listed. Result is the list (LOCALNAME MODE SIZE MTIME).

Source Code

;; Defined in /usr/src/emacs/lisp/net/tramp-smb.el.gz
;; Return either a share name (if SHARE is nil), or a file name.
;;
;; If shares are listed, the following format is expected:
;;
;; Disk|                                  - leading spaces
;; [^|]+|                                 - share name, 14 char
;; .*                                     - comment
;;
;; Entries provided by smbclient DIR aren't fully regular.
;; They should have the format
;;
;; \s-\{2,2\}                             - leading spaces
;; \S-\(.*\S-\)\s-*                       - file name, 30 chars, left bound
;; \s-+[ADHRSV]*                          - permissions, 7 chars, right bound
;; \s-                                    - space delimiter
;; \s-+[[:digit:]]+                       - size, 8 chars, right bound
;; \s-\{2,2\}                             - space delimiter
;; \w\{3,3\}                              - weekday
;; \s-                                    - space delimiter
;; \w\{3,3\}                              - month
;; \s-                                    - space delimiter
;; [ 12][[:digit:]]                       - day
;; \s-                                    - space delimiter
;; [[:digit:]]\{2,2\}:[[:digit:]]\{2,2\}:[[:digit:]]\{2,2\} - time
;; \s-                                    - space delimiter
;; [[:digit:]]\{4,4\}                     - year
;;
;; samba/src/client.c (http://samba.org/doxygen/samba/client_8c-source.html)
;; has function display_finfo:
;;
;;   d_printf("  %-30s%7.7s %8.0f  %s",
;;            finfo->name,
;;            attrib_string(finfo->mode),
;;            (double)finfo->size,
;;            asctime(LocalTime(&t)));
;;
;; in Samba 1.9, there's the following code:
;;
;;   DEBUG(0,("  %-30s%7.7s%10d  %s",
;;         CNV_LANG(finfo->name),
;;	   attrib_string(finfo->mode),
;;	   finfo->size,
;;	   asctime(LocalTime(&t))));
;;
;; Problems:
;; * Modern regexp constructs, like spy groups and counted repetitions, aren't
;;   available in older Emacsen.
;; * The length of constructs (file name, size) might exceed the default.
;; * File names might contain spaces.
;; * Permissions might be empty.
;;
;; So we try to analyze backwards.
(defun tramp-smb-read-file-entry (share)
  "Parse entry in SMB output buffer.
If SHARE is result, entries are of type dir.  Otherwise, shares
are listed.  Result is the list (LOCALNAME MODE SIZE MTIME)."
;; We are called from `tramp-smb-get-file-entries', which sets the
;; current buffer.
  (let ((line (buffer-substring (point) (point-at-eol)))
	localname mode size month day hour min sec year mtime)

    (if (not share)

	;; Read share entries.
	(when (string-match "^Disk|\\([^|]+\\)|" line)
	  (setq localname (match-string 1 line)
		mode "dr-xr-xr-x"
		size 0))

      ;; Real listing.
      (cl-block nil

	;; year.
	(if (string-match "\\([[:digit:]]+\\)$" line)
	    (setq year (string-to-number (match-string 1 line))
		  line (substring line 0 -5))
	  (cl-return))

	;; time.
	(if (string-match
	     "\\([[:digit:]]+\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)$" line)
	    (setq hour (string-to-number (match-string 1 line))
		  min  (string-to-number (match-string 2 line))
		  sec  (string-to-number (match-string 3 line))
		  line (substring line 0 -9))
	  (cl-return))

	;; day.
	(if (string-match "\\([[:digit:]]+\\)$" line)
	    (setq day  (string-to-number (match-string 1 line))
		  line (substring line 0 -3))
	  (cl-return))

	;; month.
	(if (string-match "\\(\\w+\\)$" line)
	    (setq month (match-string 1 line)
		  line  (substring line 0 -4))
	  (cl-return))

	;; weekday.
	(if (string-match-p "\\(\\w+\\)$" line)
	    (setq line (substring line 0 -5))
	  (cl-return))

	;; size.
	(if (string-match "\\([[:digit:]]+\\)$" line)
	    (let ((length (- (max 10 (1+ (length (match-string 1 line)))))))
	      (setq size (string-to-number (match-string 1 line)))
	      (when (string-match
		     "\\([ACDEHNORrsSTV]+\\)" (substring line length))
		(setq length (+ length (match-end 0))))
	      (setq line (substring line 0 length)))
	  (cl-return))

	;; mode: ARCHIVE, COMPRESSED, DIRECTORY, ENCRYPTED, HIDDEN,
	;;       NONINDEXED, NORMAL, OFFLINE, READONLY,
	;;       REPARSE_POINT, SPARSE, SYSTEM, TEMPORARY, VOLID.

	(if (string-match "\\([ACDEHNORrsSTV]+\\)?$" line)
	    (setq
	     mode (or (match-string 1 line) "")
	     mode (format
		    "%s%s"
		    (if (tramp-compat-string-search "D" mode) "d" "-")
		    (mapconcat
		     (lambda (_x) "") "    "
		     (format
		      "r%sx"
		      (if (tramp-compat-string-search "R" mode) "-" "w"))))
	     line (substring line 0 -6))
	  (cl-return))

	;; localname.
	(if (string-match "^\\s-+\\(\\S-\\(.*\\S-\\)?\\)\\s-*$" line)
	    (setq localname (match-string 1 line))
	  (cl-return))))

    (when (and localname mode size)
      (setq mtime
	    (if (and sec min hour day month year)
		(encode-time
		 sec min hour day
		 ;; `parse-time-months' could be customized by the
		 ;; user, so we take its default value.
		 (cdr
		  (assoc
		   (downcase month)
		   (default-toplevel-value 'parse-time-months)))
		 year)
	      tramp-time-dont-know))
      (list localname mode size mtime))))