11#lang racket/unit
22
33(require "sig.rkt "
4+ racket/list
5+ openssl/md5
46 "../preferences.rkt " )
57
68(import )
79(export framework:path-utils^)
810
911;; preferences initialized in main.rkt
1012
13+ (define (make-getter/ensure-exists pref-sym)
14+ (λ ()
15+ (let ([maybe-dir (preferences:get pref-sym)])
16+ (and maybe-dir
17+ (directory-exists? maybe-dir)
18+ maybe-dir))))
19+
1120(define current-backup-dir
12- (preferences:get/set 'path-utils:backup-dir ))
21+ (make-getter/ensure-exists 'path-utils:backup-dir ))
1322
1423(define current-autosave-dir
15- (preferences:get/set 'path-utils:autosave-dir ))
24+ (make-getter/ensure-exists 'path-utils:autosave-dir ))
1625
1726; generate-autosave-name : (or/c #f path-string? path-for-some-system?) -> path?
1827(define (generate-autosave-name maybe-old-path)
6271 (if (file-exists? new-name)
6372 (loop (add1 n))
6473 new-name))))
65-
74+
75+
76+ ;; generate-backup-name : path? -> path?
6677(define (generate-backup-name full-name)
6778 (define-values (pre-base old-name dir?)
6879 (split-path full-name))
92103; we should always use a complete one.
93104; Using simplify-path does that and ensures no 'up or 'same
94105; Using ! is not completely robust, but works well enough for Emacs.
106+ ; Windows has limitations on path lengths. Racket handles MAX_PATH
107+ ; by using "\\?\" paths when necessary, but individual elements must
108+ ; be shorter than lpMaximumComponentLength. If necessary, we avoid
109+ ; this by hashing the path.
95110(define (encode-as-path-element base-maybe-relative name)
96- (bytes->path-element
97- (regexp-replace* (case (system-path-convention-type)
98- [(windows) #rx#"\\\\ " ]
99- [else #rx#"/ " ])
100- (path->bytes
101- (simplify-path (build-path base-maybe-relative name)))
102- #"! " )))
111+ (define windows?
112+ (eq? 'windows (system-path-convention-type)))
113+ (define illegal-rx
114+ (if windows?
115+ #rx#"\\\\ "
116+ #rx#"/ " ))
117+ (define pth
118+ (simplify-path (build-path base-maybe-relative name)))
119+ (define legible-name-bytes
120+ (apply
121+ bytes-append
122+ (add-between
123+ (for/list ([elem (in-list (explode-path pth))])
124+ (regexp-replace* illegal-rx
125+ (path-element->bytes elem)
126+ #"! " ))
127+ #"! " )))
128+ (cond
129+ [(or (not windows?)
130+ (< (bytes-length legible-name-bytes)
131+ (lpMaximumComponentLength)))
132+ (bytes->path-element legible-name-bytes)]
133+ [else
134+ (string->path-element
135+ (regexp-replace*
136+ #rx"\\\\ " ; NOT illegal-rx : this is a string regexp
137+ (md5 (open-input-bytes (path->bytes pth)))
138+ "! " ))]))
139+
140+
141+
142+ ;; lpMaximumComponentLength : -> real?
143+ ;; Returns the maximum length of an element of a "\\?\" path on Windows.
144+ ;; For now, assuming 255, but really this should be
145+ ;; "the value returned in the lpMaximumComponentLength parameter
146+ ;; of the GetVolumeInformation function".
147+ (define (lpMaximumComponentLength)
148+ 255 )
103149
104150
151+
0 commit comments