unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* get absolute path of given path
@ 2020-09-06 15:04 Zelphir Kaltstahl
  2020-09-06 15:20 ` Matt Wette
  0 siblings, 1 reply; 3+ messages in thread
From: Zelphir Kaltstahl @ 2020-09-06 15:04 UTC (permalink / raw)
  To: Guile User

Hi Guile Users!

In my explorations into making examples for web development, I came
across the question of how to get an absolute path from any given path.
This is useful for example when checking, whether a path points to
something inside a static assets directory, or perhaps sneakily tries to
escape that and access things it should not.

I found in Guile's manual the function (canonicalize-path path).
However, this function has one problem, which makes it not sufficient on
its own: It raises an exception, when a path given points to something
that does not exist. I would like to have a function, that gives me the
absolute path of any path I give as argument, not only for existing
paths. So i went ahead and wrote the following code
(https://notabug.org/ZelphirKaltstahl/guile-examples/src/14a76a6aee18a900ac9b9de2b79ede239f8cf9f0/file-system/path-handling.scm):

~~~~START~~~~
(define-module (path-handling)
  #:export (path-split
            path-join
            absolute-path?
            absolute-path))


(use-modules
 (srfi srfi-1))

;;;
;;; HELPERS
;;;


;;; LOGGING


(define displayln
  (lambda* (#:key (output-port (current-output-port)) (verbose #t) . msgs)
    (when verbose
      (display (string-append
                (string-join
                 (map (lambda (msg) (simple-format #f "~a" msg)) msgs)
                 " ") "\n")
               output-port))))


;; alias for displayln
(define debug displayln)


;;; STRINGS


(use-modules
 (ice-9 exceptions))


(define char->string
  (λ (c)
    (list->string
     (list c))))


(define string->char
  (λ (str)
    "Convert a string, which has only one single character
into a character. This is useful, because some functions
expect a characters as input instead of a string."
    (cond
     [(= (string-length str) 1)
      (car (string->list str))]
     [else
      (raise-exception
       (make-exception
        (make-non-continuable-error)
        (make-exception-with-message "trying to convert string of more than 1 character to char")
        (make-exception-with-irritants (list str))
        (make-exception-with-origin 'string->char)))])))


#;(define has-prefix?
  (λ (str prefix)
    (= (string-prefix-length str prefix)
       (string-length prefix))))


;;; LISTS


(define list-prefix?
  (λ (lst lst-prefix)
    (cond
     [(null? lst-prefix) #t]
     [(null? lst) #f]
     [else
      (cond
       [(equal? (car lst) (car lst-prefix))
        (list-prefix? (cdr lst) (cdr lst-prefix))]
       [else #f])])))


;;;
;;; PATH FUNCTIONS
;;;


(define absolute-path?
  (λ (path)
    "Check, whether the given path is an absolute path."
    ;; Guile already offers a function for this, but it is a
    ;; little bit strangely named. We only give it an alias.
    (absolute-file-name? path)))


(define path-join
  (λ (path1 . other-path-parts)
    "Join paths using the system preferred separator."
    (debug "joining path parts:" (cons path1 other-path-parts))
    (fold
     (λ (p2 p1)
       (cond
        [(null? p2) p1]
        [(absolute-path? p2) p2]
        [else
         (let ([dir-sep (car (string->list file-name-separator-string))])
           (string-append
            ;; Remove any trailing separators to make sure
            ;; there is only one separator, when the paths
            ;; are concattenated.
            (string-trim-right p1 (λ (char) (char=? char dir-sep)))
            ;; Concat the paths with the separator in the
            ;; middle.
            (char->string dir-sep)
            ;; We already know p2 is not an absolute path.
            p2))]))
     ""
     (cons path1 other-path-parts))))


(define path-split
  (λ (path)
    "Split a path by the preferred separator of the system."
    (string-split path (string->char file-name-separator-string))))


(define absolute-path
  (lambda* (path
            #:key
            (working-directory
             (dirname (or (current-filename)
                          (canonicalize-path ".")))))
    (cond
     [(absolute-path? path) path]
     [else
      ;; In case the path is not absolute already, we look
      ;; for it in the current directory.
      (let next-parent ([path-parts
                         (path-split
                          (path-join working-directory path))])
        (debug "current path-parts:" path-parts)
        (cond
         ;; WARNING: This part is not OS independent. An
         ;; absolute path does not have to start with the
         ;; separator string in all OS.
         [(null? path-parts) file-name-separator-string]
         [else
          (let ([path-str (apply path-join path-parts)])
            (debug "current path-str:" path-str)
            (with-exception-handler
                (λ (exception)
                  (debug "an exception was raised:" exception)
                  (cond
                   [(and (eq? (exception-kind exception)
                              'system-error)
                         (string=? (car (exception-irritants exception))
                                   "No such file or directory"))
                    ;; Try to check if the path to the
                    ;; parent directory exists and is an
                    ;; absolute path instead.
                    (debug "the exception is about the path not existing")
                    (apply path-join
                           (list (next-parent (drop-right path-parts 1))
                                 (last path-parts)))]
                   [else
                    (debug "unexpected exception:" exception)]))
              (λ ()
                (debug "trying to canonicalize-path" path-str)
                (canonicalize-path path-str))
              #:unwind? #t))]))])))
~~~~~END~~~~~

But then I thought about it and realized, that this is not OS
independent. Not every OS must have the convention of starting absolute
paths with the separator string.

So I wonder: Is there a function in Guile, which translates a path like
"/a/b/c" into an equivalent on the current OS?

I think in Python 3 the rule is for example to always use "/" as a
separator and Python will take care of translating that to the
underlying OS. Not sure how it handles making absolute paths, but I
could imagine, that one could use this "slash first means absolute path"
kind of path language and then Guile internally translates that to the
underlying OS' absolute path.

Regards,
Zelphir

-- 
repositories: https://notabug.org/ZelphirKaltstahl



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: get absolute path of given path
  2020-09-06 15:04 get absolute path of given path Zelphir Kaltstahl
@ 2020-09-06 15:20 ` Matt Wette
  2020-09-06 23:39   ` Zelphir Kaltstahl
  0 siblings, 1 reply; 3+ messages in thread
From: Matt Wette @ 2020-09-06 15:20 UTC (permalink / raw)
  To: guile-user


On 9/6/20 8:04 AM, Zelphir Kaltstahl wrote:
> Hi Guile Users!
>
> In my explorations into making examples for web development, I came
> across the question of how to get an absolute path from any given path.
> This is useful for example when checking, whether a path points to
> something inside a static assets directory, or perhaps sneakily tries to
> escape that and access things it should not.
>
> I found in Guile's manual the function (canonicalize-path path).
> However, this function has one problem, which makes it not sufficient on
> its own: It raises an exception, when a path given points to something
> that does not exist. I would like to have a function, that gives me the
> absolute path of any path I give as argument, not only for existing
> paths. So i went ahead and wrote the following code
> (https://notabug.org/ZelphirKaltstahl/guile-examples/src/14a76a6aee18a900ac9b9de2b79ede239f8cf9f0/file-system/path-handling.scm):
>
Maybe you would like false-if-exception.

https://www.gnu.org/software/guile/manual/html_node/Error-Reporting.html




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: get absolute path of given path
  2020-09-06 15:20 ` Matt Wette
@ 2020-09-06 23:39   ` Zelphir Kaltstahl
  0 siblings, 0 replies; 3+ messages in thread
From: Zelphir Kaltstahl @ 2020-09-06 23:39 UTC (permalink / raw)
  To: Matt Wette; +Cc: guile-user

Hi Matt!

On 06.09.20 17:20, Matt Wette wrote:
>
> On 9/6/20 8:04 AM, Zelphir Kaltstahl wrote:
>> Hi Guile Users!
>>
>> In my explorations into making examples for web development, I came
>> across the question of how to get an absolute path from any given path.
>> This is useful for example when checking, whether a path points to
>> something inside a static assets directory, or perhaps sneakily tries to
>> escape that and access things it should not.
>>
>> I found in Guile's manual the function (canonicalize-path path).
>> However, this function has one problem, which makes it not sufficient on
>> its own: It raises an exception, when a path given points to something
>> that does not exist. I would like to have a function, that gives me the
>> absolute path of any path I give as argument, not only for existing
>> paths. So i went ahead and wrote the following code
>> (https://notabug.org/ZelphirKaltstahl/guile-examples/src/14a76a6aee18a900ac9b9de2b79ede239f8cf9f0/file-system/path-handling.scm):
>>
>>
> Maybe you would like false-if-exception.
>
> https://www.gnu.org/software/guile/manual/html_node/Error-Reporting.html


This I definitely did not know and it seems like it would fit perfectly
for my use-case. Thank you!

Regards,
Zelphir

-- 
repositories: https://notabug.org/ZelphirKaltstahl




^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-09-06 23:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-06 15:04 get absolute path of given path Zelphir Kaltstahl
2020-09-06 15:20 ` Matt Wette
2020-09-06 23:39   ` Zelphir Kaltstahl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).