[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

otherwise nice bugfix which doesn't work

From: Florian von Savigny
Subject: otherwise nice bugfix which doesn't work
Date: 02 Jan 2004 02:08:08 +0100
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2


I decided to post this here since it is intendend to fix a minor
annoyance for those people using Emacs under a *nix system who mount
file systems like vfat (but it should work for any fs). Under these
circumstances, Emacs is unaware that some characters will be illegal
(as distinct from when it is running under Windoze). This has become
apparent to me because my home directory is on a vfat partition, and
Emacs tries to save my "*mail*" buffers to auto save files which
contain asterisks in their names, which naturally fails, and this
causes very annoying interruptions.

Using very valuable advice from Eli Zaretskii, I wrote the below
solution, which works like a swell, but has the disadvantage of
reliably messing some things up I did not expect to be related:

- trying to find a file is sanctioned by "Wrong type argument:
  stringp, nil"

- M-x mail does swap you to a "*mail*" buffer, but it is the
  "*scratch*" buffer it puts in mail-mode (and it also inserts the
  header lines there)

There must be something very basic I don't know.

;;; alien-fs.el --- make Emacs avoid forbidden characters in filenames
;;; if creating files on alien filesystems

;; Copyright (C) 2003 Free Software Foundation, Inc.

;; Author:            Florian v. Savigny <address@hidden>
;; Credits to:        Eli Zaretskii (who made this possible)

;; This file is part of GNU Emacs.

;;; (Copyright information left out here)

;;; Commentary:

;;; There is as yet no mechanism for Emacs to behave appropriately
;;; when creating files on alien file systems; i.e. if Emacs is
;;; running under GNU/Linux and tries to create e.g. an auto-save-file
;;; on a VFAT partition, it is unaware it must not use the characters
;;; "\/:*?"<>|" for its name, and hence will fail if it happens to use
;;; one of them.

;;; This file provides two functions: one that returns the filesystem
;;; type for a given file by querying "df", and one re-definition of
;;; convert-standard-filename that uses the former to convert the
;;; filename argument only if necessary and with customisable and
;;; fine-grained rules for each filesystem type. These rules are
;;; specified in the variable filename-fs-specific-char-conversions.

;;; It can be hoped that convert-standard-filename will in the future
;;; be called by all functions that create a file. As this does not
;;; yet seem to be the case, however, this file has stolen a way of
;;; doing this for make-auto-save-file-name at least (see below) from
;;; w32-fns.el.

(defun filename-get-fs-type (filename)
  "Takes an absolute or relative filename and returns the type of file
system (in the notation used by mount(8)) that emacs will, or would,
put this file on. Whether the filename supplied is (would be) legal on
that filesystem is not tested."
  (let (fs)
     (setq filename (file-name-directory (expand-file-name filename)))
     (call-process "df" nil "*df*" nil "-T" filename)
     (set-buffer "*df*")
     (goto-char (point-min))
      "^/dev/[^         ]+[     ]+\\([^         ]+\\)[  ]" nil t)
      ; the character classes include tabs here - maybe unnecessarily.
     (setq fs (match-string 1))
     (kill-buffer "*df*")
(defvar filename-fs-specific-char-conversions
  '(("vfat" . (("\\*" . "%a") (":" . "%c") ("\\?" . "%!")
               ("\"" . "%q") ("<" . "%l") (">" . "%g") ("|" . "%p")
               ("ä" . "ae") ("ö" . "oe") ("ü" . "ue") ("ß" . "ss")))
  "List of dotted pairs the car of which is a filesystem identifier
(see mount(8) which ones are valid) and the cdr is a list of rules how
to convert filename characters for the given filesystem. Each rule is
also a dotted pair, and conversions are performed in the order the
rules are specified. Note that the car of the rule is in regexp
notation, hence you can specify character classes to be replaced all
by the same character (as in \"(\"[*?\"<]\" . \"!\")).")

(defun convert-standard-filename (filename)
  "Standard emacs function re-written to be filesystem-sensitive.  It
converts any filename to something suitable for the type of filesystem
the latter is going to be stored on. Filesystem-specific conversion
rules must be stored in `filename-fs-specific-char-conversions'. If
the latter contains no entry for the type of filesystem in question,
the filename is returned unchanged."
  (let ((int 0)
        (fs (filename-get-fs-type filename))
        (setq rules (assoc fs filename-fs-specific-char-conversions))
        ; test if there is an entry for this filesystem
        (while (setq rule (nth int (cdr rules)))
          (while (string-match (car rule) filename)
            (setq filename (replace-match (cdr rule) nil t filename)))
          (setq int (+ int 1)))
      ; this was the true part: no else part needed

;; the following is taken literally from w32-fns.el:

;; Avoid creating auto-save file names containing invalid characters.
(fset 'original-make-auto-save-file-name
      (symbol-function 'make-auto-save-file-name))

(defun make-auto-save-file-name ()
  "Return file name to use for auto-saves of current buffer.
Does not consider `auto-save-visited-file-name' as that variable is checked
before calling this function.  You can redefine this for customization.
See also `auto-save-file-name-p'."
  (convert-standard-filename (original-make-auto-save-file-name)))

;;; end of file

Any comment would be greatly appreciated, since I would very much like
to have this working. "It works like a swell" would be worded more
precisely as "the functions work as expected when trying them out in
the *scratch* buffer", i.e.


will yield sth. like 


if the above file is not loaded, but


if it is (/home/florian is on a vfat partition). On an ext2 partition,
the names will both have asterisks, no matter whether the file is
loaded or not.


Florian v. Savigny

If you are going to reply in private, please be patient, as I only
check for mail something like once a week. - Si vous allez répondre
personellement, patientez s.v.p., car je ne lis les courriels
qu'environ une fois par semaine.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]