3

Q:  How to test whether an absolute path is a root file/directory (e.g., at the first level of the hard drive)?

I see a few possibilities depending upon whether the file is on Windows or Unix/Linux. Here is my first attempt:

(equal "/bar" (concat (file-name-directory "/bar") (file-name-nondirectory "/bar")))
3
  • There are some problems with this. For instance: should it follow symlinks / hardlinks or not? And what about path like this: /foo/../bar? – wvxvw May 27 '18 at 5:29
  • @wvxvw -- thank you for taking a look at this thread. I had not contemplated those possibilities. I believe a good night sleep and a cup of coffee in the morning will be needed ... – lawlist May 27 '18 at 5:57
  • @wvxvw -- after a good night of sleep and a cup of coffee in the morning, I have decided that the feature I am implementing will be limited to simple cases until there is a need for something more complex such as dealing with symlinks / hardlinks and special paths such as /foo/../bar. Thank you for opening my eyes regarding more complex possibilities. I will place a note in the code I am writing up to consider future applications. – lawlist May 27 '18 at 16:16
4

Not sure what you're asking, but perhaps this is it (from Dired+):

(defun diredp-root-directory-p (file)
  "Return non-nil if FILE is a root directory."
  (if (fboundp 'ange-ftp-root-dir-p)
      (ange-ftp-root-dir-p (file-name-as-directory file))
    ;; This is essentially `ange-ftp-root-dir-p' applied to `file-name-as-directory'.
    ;; If `ange-ftp-root-dir-p' changes, update this code.
    (or (and (eq system-type 'windows-nt)
             (string-match-p "\\`[a-zA-Z]:[/\\]\\'" (file-name-as-directory file)))
        (string= "/" file))))

Or if you really mean a child of the root then use (diredp-root-directory-p (diredp-parent-dir FILE)). Here's diredp-parent-dir (from Dired+):

(defun diredp-parent-dir (file &optional relativep)
  "Return the parent directory of FILE, or nil if none.
Optional arg RELATIVEP non-nil means return a relative name, that is,
just the parent component."
  (let ((parent  (file-name-directory (directory-file-name (expand-file-name file))))
        relparent)
    (when relativep
      (setq relparent  (file-name-nondirectory (directory-file-name parent))))
    (and (not (equal parent file))  (or relparent  parent))))
3
  • diredp-parent-dir seems to do the job quite nicely: (equal (diredp-parent-dir "/bar") "/"). Thank you. – lawlist May 27 '18 at 5:52
  • But (equal (diredp-parent-dir "c:/bar") "/") is nil. Did you try (diredp-root-directory-p (diredp-parent-dir FILE))? That should work generally. – Drew May 27 '18 at 13:38
  • Thank you for explaining that both functions needed to be used in conjunction with each other in order to obtain the correct result on both platforms. On a Windows machine, (diredp-root-directory-p (diredp-parent-dir "c:/bar")) returns non-nil. And, on a Unix flavored machine (e.g., OSX), (diredp-root-directory-p (diredp-parent-dir "/bar")) returns non-nil. Greatly appreciated! – lawlist May 27 '18 at 16:12
0

An absolute path is a root file or directory if and only if it is not a root directory, but its parent is. A path is a root directory if and only if it is equal to its parent. So calculate the parent directory and the parent's parent and compare them.

(defun file-name-is-in-root-directory (filename)
  (setq filename (directory-file-name filename))
  (and (file-name-absolute-p filename)
       (let ((dir (directory-file-name (file-name-directory filename))))
     (and (not (equal filename dir))
          (equal dir (file-name-directory dir))))))

This is a purely textual check. It doesn't take symbolic links or .. into account. If you want that, call expand-file-name on the path first. This resolves symbolic links, simplifies .. (note that you can't do this accurately without resolving symbolic links), and also expands initial ~ abbreviations to home directories.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.