#lang mzscheme (require mzlib/etc mzlib/foreign) (unsafe!) (define kernel32 (delay (and (eq? 'windows (system-type)) (ffi-lib "kernel32")))) (define (delay-ffi-obj name lib type) (delay (get-ffi-obj name lib type))) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; gethostbyname (define BUFFER-SIZE 1024) (define (extract-terminated-string proc) (let ([s (make-bytes BUFFER-SIZE)]) (if (proc s BUFFER-SIZE) (bytes->string/utf-8 (car (regexp-match #rx#"^[^\0]*" s))) (error 'gethostname "could not get hostname")))) (define unix-gethostname (delay-ffi-obj "gethostname" #f (_fun _bytes _int -> _int))) (define windows-getcomputername (delay-ffi-obj "GetComputerNameExA" (force kernel32) (_fun #:abi 'stdcall _int _bytes _cvector -> _int))) (define (gethostname) (case (system-type) [(unix macosx) (let ([ghn (force unix-gethostname)]) (extract-terminated-string (lambda (s sz) (zero? (ghn s sz)))))] [(windows) (let ([gcn (force windows-getcomputername)] [DNS_FULLY_QUALIFIED 3]) (extract-terminated-string (lambda (s sz) (let ([sz_ptr (cvector _int sz)]) (and (not (zero? (gcn DNS_FULLY_QUALIFIED s sz_ptr))) (let ([sz (cvector-ref sz_ptr 0)]) (when (sz . < . (bytes-length s)) (bytes-set! s sz 0)) #t))))))] [else #f])) (provide gethostname) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; getpid (define unix-getpid (delay-ffi-obj "getpid" #f (_fun -> _int))) (define windows-getpid (delay-ffi-obj "GetCurrentProcessId" (force kernel32) (_fun #:abi 'stdcall -> _int))) (define (getpid) ((force (case (system-type) [(macosx unix) unix-getpid] [(windows) windows-getpid] [else (error 'getpid "unknown platform ~e" (system-type))])))) (provide getpid) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; truncate-file ;; From fcntl.h (define O_RDONLY #x0000) (define O_WRONLY #x0001) (define O_RDWR #x0002) (define O_APPEND #x0008) (define O_CREAT #x0100) (define O_TRUNC #x0200) (define O_EXCL #x0400) ;; winize : string -> string (define (winize fn-name) (if (eq? 'windows (system-type)) (string-append "_" fn-name) fn-name)) ;; open : string int -> int (define open (delay-ffi-obj (winize "open") #f (_fun #:save-errno 'posix _string _int -> _int))) ;; close : int -> int (define close (delay-ffi-obj (winize "close") #f (_fun #:save-errno 'posix _int -> _int))) ;; ftruncate : int int -> int (define ftruncate (if (eq? 'windows (system-type)) (delay-ffi-obj "_chsize" #f (_fun #:save-errno 'posix _int _llong -> _int)) (delay-ffi-obj "ftruncate" #f (_fun #:save-errno 'posix _int _llong -> _int)))) ;; on-c-fail : int (-> X) int or X (define (on-c-fail thunk fail-k) (let ([val (thunk)]) (cond [(> val -1) val] [(= (saved-errno) (lookup-errno 'EINTR)) ;; interrupted by a signal; retry (on-c-fail thunk fail-k)] [else (fail-k)]))) (define scheme_security_check_file (delay-ffi-obj "scheme_security_check_file" #f (_fun _string _string _int -> _void))) (define SCHEME_GUARD_FILE_WRITE #x2) ;; truncate-file : path int -> void (define truncate-file (opt-lambda (file [size 0]) (when (not (path-string? file)) (error 'truncate-file "expects argument of type or ; given ~s" file)) (when (not (integer? size)) (error 'truncate-file "expects argument of type ; given ~s" size)) ((force scheme_security_check_file) "truncate-file" (if (path? file) (path->string file) file) SCHEME_GUARD_FILE_WRITE) (let ([fd (on-c-fail (lambda () ((force open) file O_WRONLY)) (lambda () (error 'truncate-file "could not open file")))]) (on-c-fail (lambda () ((force ftruncate) fd size)) (lambda () ((force close) fd) (error 'truncate-file "could not truncate file"))) (on-c-fail (lambda () ((force close) fd)) void) (void)))) (provide truncate-file)