Tolerate non-simple strings when checking arguments to CERROR.
[sbcl.git] / src / code / win32.lisp
blobc7847ae756354c8586782cd4de61f4d98de1da05
1 ;;;; This file contains Win32 support routines that SBCL needs to
2 ;;;; implement itself, in addition to those that apply to Win32 in
3 ;;;; unix.lisp. In theory, some of these functions might someday be
4 ;;;; useful to the end user.
6 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; more information.
8 ;;;;
9 ;;;; This software is derived from the CMU CL system, which was
10 ;;;; written at Carnegie Mellon University and released into the
11 ;;;; public domain. The software is in the public domain and is
12 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
13 ;;;; files for more information.
15 (in-package "SB!WIN32")
17 ;;; Alien definitions for commonly used Win32 types. Woe unto whoever
18 ;;; tries to untangle this someday for 64-bit Windows.
19 ;;;
20 ;;; FIXME: There used to be many more here, which are now groveled,
21 ;;; but groveling HANDLE makes it unsigned, which currently breaks the
22 ;;; build. --NS 2006-06-18
23 (define-alien-type handle int-ptr)
25 (define-alien-type lispbool (boolean 32))
27 (define-alien-type system-string
28 #!-sb-unicode c-string
29 #!+sb-unicode (c-string :external-format :ucs-2))
31 (define-alien-type tchar #!-sb-unicode char
32 #!+sb-unicode (unsigned 16))
34 (defconstant default-environment-length 1024)
36 ;;; HANDLEs are actually pointers, but an invalid handle is -1 cast
37 ;;; to a pointer.
38 (defconstant invalid-handle -1)
40 (defconstant file-attribute-readonly #x1)
41 (defconstant file-attribute-hidden #x2)
42 (defconstant file-attribute-system #x4)
43 (defconstant file-attribute-directory #x10)
44 (defconstant file-attribute-archive #x20)
45 (defconstant file-attribute-device #x40)
46 (defconstant file-attribute-normal #x80)
47 (defconstant file-attribute-temporary #x100)
48 (defconstant file-attribute-sparse #x200)
49 (defconstant file-attribute-reparse-point #x400)
50 (defconstant file-attribute-reparse-compressed #x800)
51 (defconstant file-attribute-reparse-offline #x1000)
52 (defconstant file-attribute-not-content-indexed #x2000)
53 (defconstant file-attribute-encrypted #x4000)
55 (defconstant file-flag-overlapped #x40000000)
56 (defconstant file-flag-sequential-scan #x8000000)
58 ;; Possible results of GetFileType.
59 (defconstant file-type-disk 1)
60 (defconstant file-type-char 2)
61 (defconstant file-type-pipe 3)
62 (defconstant file-type-remote 4)
63 (defconstant file-type-unknown 0)
65 (defconstant invalid-file-attributes (mod -1 (ash 1 32)))
67 ;;;; File Type Introspection by handle
68 (define-alien-routine ("GetFileType" get-file-type) dword
69 (handle handle))
71 ;;;; Error Handling
73 ;;; Retrieve the calling thread's last-error code value. The
74 ;;; last-error code is maintained on a per-thread basis.
75 (define-alien-routine ("GetLastError" get-last-error) dword)
77 ;;; Get the operating system handle for a C file descriptor. Returns
78 ;;; INVALID-HANDLE on failure.
79 (define-alien-routine ("_get_osfhandle" get-osfhandle) handle
80 (fd int))
82 (define-alien-routine ("_close" crt-close) int
83 (fd int))
85 ;;; Read data from a file handle into a buffer. This may be used
86 ;;; synchronously or with "overlapped" (asynchronous) I/O.
87 (define-alien-routine ("ReadFile" read-file) bool
88 (file handle)
89 (buffer (* t))
90 (bytes-to-read dword)
91 (bytes-read (* dword))
92 (overlapped (* t)))
94 ;;; Write data from a buffer to a file handle. This may be used
95 ;;; synchronously or with "overlapped" (asynchronous) I/O.
96 (define-alien-routine ("WriteFile" write-file) bool
97 (file handle)
98 (buffer (* t))
99 (bytes-to-write dword)
100 (bytes-written (* dword))
101 (overlapped (* t)))
103 ;;; Copy data from a named or anonymous pipe into a buffer without
104 ;;; removing it from the pipe. BUFFER, BYTES-READ, BYTES-AVAIL, and
105 ;;; BYTES-LEFT-THIS-MESSAGE may be NULL if no data is to be read.
106 ;;; Return TRUE on success, FALSE on failure.
107 (define-alien-routine ("PeekNamedPipe" peek-named-pipe) bool
108 (pipe handle)
109 (buffer (* t))
110 (buffer-size dword)
111 (bytes-read (* dword))
112 (bytes-avail (* dword))
113 (bytes-left-this-message (* dword)))
115 ;;; Flush the console input buffer if HANDLE is a console handle.
116 ;;; Returns true on success, false if the handle does not refer to a
117 ;;; console.
118 (define-alien-routine ("FlushConsoleInputBuffer" flush-console-input-buffer) bool
119 (handle handle))
121 ;;; Read data from the console input buffer without removing it,
122 ;;; without blocking. Buffer should be large enough for LENGTH *
123 ;;; INPUT-RECORD-SIZE bytes.
124 (define-alien-routine ("PeekConsoleInputA" peek-console-input) bool
125 (handle handle)
126 (buffer (* t))
127 (length dword)
128 (nevents (* dword)))
130 (define-alien-routine "socket_input_available" int
131 (socket handle))
133 (define-alien-routine "console_handle_p" boolean
134 (handle handle))
136 ;;; Listen for input on a Windows file handle. Unlike UNIX, there
137 ;;; isn't a unified interface to do this---we have to know what sort
138 ;;; of handle we have. Of course, there's no way to actually
139 ;;; introspect it, so we have to try various things until we find
140 ;;; something that works. Returns true if there could be input
141 ;;; available, or false if there is not.
142 (defun handle-listen (handle)
143 (cond ((console-handle-p handle)
144 (alien-funcall (extern-alien "win32_tty_listen"
145 (function boolean handle))
146 handle))
148 (with-alien ((avail dword))
150 (unless (zerop (peek-named-pipe handle nil 0 nil (addr avail) nil))
151 (return-from handle-listen (plusp avail))))
152 (let ((res (socket-input-available handle)))
153 (unless (zerop res)
154 (return-from handle-listen (= res 1))))
155 t)))
157 ;;; Clear all available input from a file handle.
158 (defun handle-clear-input (handle)
159 (flush-console-input-buffer handle)
160 (with-alien ((buf (array char 1024))
161 (count dword))
162 (loop
163 (unless (handle-listen handle)
164 (return))
165 (when (zerop (read-file handle (cast buf (* t)) 1024 (addr count) nil))
166 (return))
167 (when (< count 1024)
168 (return)))))
170 ;;;; System Functions
172 #!-sb-thread
173 (define-alien-routine ("Sleep" millisleep) void
174 (milliseconds dword))
176 #!+sb-thread
177 (defun sb!unix:nanosleep (sec nsec)
178 (let ((*allow-with-interrupts* *interrupts-enabled*))
179 (without-interrupts
180 (let ((timer (sb!impl::os-create-wtimer)))
181 (sb!impl::os-set-wtimer timer sec nsec)
182 (unwind-protect
183 (do () ((with-local-interrupts
184 (zerop (sb!impl::os-wait-for-wtimer timer)))))
185 (sb!impl::os-close-wtimer timer))))))
187 (define-alien-routine ("win32_wait_object_or_signal" wait-object-or-signal)
188 dword
189 (handle handle))
191 #!+sb-unicode
192 (progn
193 (defvar *ansi-codepage* nil)
194 (defvar *oem-codepage* nil)
195 (defvar *codepage-to-external-format* (make-hash-table)))
197 #!+sb-unicode
198 (dolist
199 (cp '(;;037 IBM EBCDIC - U.S./Canada
200 (437 :CP437) ;; OEM - United States
201 ;;500 IBM EBCDIC - International
202 ;;708 Arabic - ASMO 708
203 ;;709 Arabic - ASMO 449+, BCON V4
204 ;;710 Arabic - Transparent Arabic
205 ;;720 Arabic - Transparent ASMO
206 ;;737 OEM - Greek (formerly 437G)
207 ;;775 OEM - Baltic
208 (850 :CP850) ;; OEM - Multilingual Latin I
209 (852 :CP852) ;; OEM - Latin II
210 (855 :CP855) ;; OEM - Cyrillic (primarily Russian)
211 (857 :CP857) ;; OEM - Turkish
212 ;;858 OEM - Multilingual Latin I + Euro symbol
213 (860 :CP860) ;; OEM - Portuguese
214 (861 :CP861) ;; OEM - Icelandic
215 (862 :CP862) ;; OEM - Hebrew
216 (863 :CP863) ;; OEM - Canadian-French
217 (864 :CP864) ;; OEM - Arabic
218 (865 :CP865) ;; OEM - Nordic
219 (866 :CP866) ;; OEM - Russian
220 (869 :CP869) ;; OEM - Modern Greek
221 ;;870 IBM EBCDIC - Multilingual/ROECE (Latin-2)
222 (874 :CP874) ;; ANSI/OEM - Thai (same as 28605, ISO 8859-15)
223 ;;875 IBM EBCDIC - Modern Greek
224 (932 :CP932) ;; ANSI/OEM - Japanese, Shift-JIS
225 ;;936 ANSI/OEM - Simplified Chinese (PRC, Singapore)
226 ;;949 ANSI/OEM - Korean (Unified Hangul Code)
227 ;;950 ANSI/OEM - Traditional Chinese (Taiwan; Hong Kong SAR, PRC)
228 ;;1026 IBM EBCDIC - Turkish (Latin-5)
229 ;;1047 IBM EBCDIC - Latin 1/Open System
230 ;;1140 IBM EBCDIC - U.S./Canada (037 + Euro symbol)
231 ;;1141 IBM EBCDIC - Germany (20273 + Euro symbol)
232 ;;1142 IBM EBCDIC - Denmark/Norway (20277 + Euro symbol)
233 ;;1143 IBM EBCDIC - Finland/Sweden (20278 + Euro symbol)
234 ;;1144 IBM EBCDIC - Italy (20280 + Euro symbol)
235 ;;1145 IBM EBCDIC - Latin America/Spain (20284 + Euro symbol)
236 ;;1146 IBM EBCDIC - United Kingdom (20285 + Euro symbol)
237 ;;1147 IBM EBCDIC - France (20297 + Euro symbol)
238 ;;1148 IBM EBCDIC - International (500 + Euro symbol)
239 ;;1149 IBM EBCDIC - Icelandic (20871 + Euro symbol)
240 (1200 :UCS-2LE) ;; Unicode UCS-2 Little-Endian (BMP of ISO 10646)
241 (1201 :UCS-2BE) ;; Unicode UCS-2 Big-Endian
242 (1250 :CP1250) ;; ANSI - Central European
243 (1251 :CP1251) ;; ANSI - Cyrillic
244 (1252 :CP1252) ;; ANSI - Latin I
245 (1253 :CP1253) ;; ANSI - Greek
246 (1254 :CP1254) ;; ANSI - Turkish
247 (1255 :CP1255) ;; ANSI - Hebrew
248 (1256 :CP1256) ;; ANSI - Arabic
249 (1257 :CP1257) ;; ANSI - Baltic
250 (1258 :CP1258) ;; ANSI/OEM - Vietnamese
251 ;;1361 Korean (Johab)
252 ;;10000 MAC - Roman
253 ;;10001 MAC - Japanese
254 ;;10002 MAC - Traditional Chinese (Big5)
255 ;;10003 MAC - Korean
256 ;;10004 MAC - Arabic
257 ;;10005 MAC - Hebrew
258 ;;10006 MAC - Greek I
259 (10007 :X-MAC-CYRILLIC) ;; MAC - Cyrillic
260 ;;10008 MAC - Simplified Chinese (GB 2312)
261 ;;10010 MAC - Romania
262 ;;10017 MAC - Ukraine
263 ;;10021 MAC - Thai
264 ;;10029 MAC - Latin II
265 ;;10079 MAC - Icelandic
266 ;;10081 MAC - Turkish
267 ;;10082 MAC - Croatia
268 ;;12000 Unicode UCS-4 Little-Endian
269 ;;12001 Unicode UCS-4 Big-Endian
270 ;;20000 CNS - Taiwan
271 ;;20001 TCA - Taiwan
272 ;;20002 Eten - Taiwan
273 ;;20003 IBM5550 - Taiwan
274 ;;20004 TeleText - Taiwan
275 ;;20005 Wang - Taiwan
276 ;;20105 IA5 IRV International Alphabet No. 5 (7-bit)
277 ;;20106 IA5 German (7-bit)
278 ;;20107 IA5 Swedish (7-bit)
279 ;;20108 IA5 Norwegian (7-bit)
280 ;;20127 US-ASCII (7-bit)
281 ;;20261 T.61
282 ;;20269 ISO 6937 Non-Spacing Accent
283 ;;20273 IBM EBCDIC - Germany
284 ;;20277 IBM EBCDIC - Denmark/Norway
285 ;;20278 IBM EBCDIC - Finland/Sweden
286 ;;20280 IBM EBCDIC - Italy
287 ;;20284 IBM EBCDIC - Latin America/Spain
288 ;;20285 IBM EBCDIC - United Kingdom
289 ;;20290 IBM EBCDIC - Japanese Katakana Extended
290 ;;20297 IBM EBCDIC - France
291 ;;20420 IBM EBCDIC - Arabic
292 ;;20423 IBM EBCDIC - Greek
293 ;;20424 IBM EBCDIC - Hebrew
294 ;;20833 IBM EBCDIC - Korean Extended
295 ;;20838 IBM EBCDIC - Thai
296 (20866 :KOI8-R) ;; Russian - KOI8-R
297 ;;20871 IBM EBCDIC - Icelandic
298 ;;20880 IBM EBCDIC - Cyrillic (Russian)
299 ;;20905 IBM EBCDIC - Turkish
300 ;;20924 IBM EBCDIC - Latin-1/Open System (1047 + Euro symbol)
301 ;;20932 JIS X 0208-1990 & 0121-1990
302 ;;20936 Simplified Chinese (GB2312)
303 ;;21025 IBM EBCDIC - Cyrillic (Serbian, Bulgarian)
304 ;;21027 (deprecated)
305 (21866 :KOI8-U) ;; Ukrainian (KOI8-U)
306 (28591 :LATIN-1) ;; ISO 8859-1 Latin I
307 (28592 :ISO-8859-2) ;; ISO 8859-2 Central Europe
308 (28593 :ISO-8859-3) ;; ISO 8859-3 Latin 3
309 (28594 :ISO-8859-4) ;; ISO 8859-4 Baltic
310 (28595 :ISO-8859-5) ;; ISO 8859-5 Cyrillic
311 (28596 :ISO-8859-6) ;; ISO 8859-6 Arabic
312 (28597 :ISO-8859-7) ;; ISO 8859-7 Greek
313 (28598 :ISO-8859-8) ;; ISO 8859-8 Hebrew
314 (28599 :ISO-8859-9) ;; ISO 8859-9 Latin 5
315 (28605 :LATIN-9) ;; ISO 8859-15 Latin 9
316 ;;29001 Europa 3
317 (38598 :ISO-8859-8) ;; ISO 8859-8 Hebrew
318 ;;50220 ISO 2022 Japanese with no halfwidth Katakana
319 ;;50221 ISO 2022 Japanese with halfwidth Katakana
320 ;;50222 ISO 2022 Japanese JIS X 0201-1989
321 ;;50225 ISO 2022 Korean
322 ;;50227 ISO 2022 Simplified Chinese
323 ;;50229 ISO 2022 Traditional Chinese
324 ;;50930 Japanese (Katakana) Extended
325 ;;50931 US/Canada and Japanese
326 ;;50933 Korean Extended and Korean
327 ;;50935 Simplified Chinese Extended and Simplified Chinese
328 ;;50936 Simplified Chinese
329 ;;50937 US/Canada and Traditional Chinese
330 ;;50939 Japanese (Latin) Extended and Japanese
331 (51932 :EUC-JP) ;; EUC - Japanese
332 ;;51936 EUC - Simplified Chinese
333 ;;51949 EUC - Korean
334 ;;51950 EUC - Traditional Chinese
335 ;;52936 HZ-GB2312 Simplified Chinese
336 ;;54936 Windows XP: GB18030 Simplified Chinese (4 Byte)
337 ;;57002 ISCII Devanagari
338 ;;57003 ISCII Bengali
339 ;;57004 ISCII Tamil
340 ;;57005 ISCII Telugu
341 ;;57006 ISCII Assamese
342 ;;57007 ISCII Oriya
343 ;;57008 ISCII Kannada
344 ;;57009 ISCII Malayalam
345 ;;57010 ISCII Gujarati
346 ;;57011 ISCII Punjabi
347 ;;65000 Unicode UTF-7
348 (65001 :UTF8))) ;; Unicode UTF-8
349 (setf (gethash (car cp) *codepage-to-external-format*) (cadr cp)))
351 #!+sb-unicode
352 ;; FIXME: Something odd here: why are these two #+SB-UNICODE, whereas
353 ;; the console just behave differently?
354 (progn
355 (declaim (ftype (function () keyword) ansi-codepage))
356 (defun ansi-codepage ()
357 (or *ansi-codepage*
358 (setq *ansi-codepage*
359 (gethash (alien-funcall (extern-alien "GetACP" (function UINT)))
360 *codepage-to-external-format*
361 :latin-1))))
363 (declaim (ftype (function () keyword) oem-codepage))
364 (defun oem-codepage ()
365 (or *oem-codepage*
366 (setq *oem-codepage*
367 (gethash (alien-funcall (extern-alien "GetOEMCP" (function UINT)))
368 *codepage-to-external-format*
369 :latin-1)))))
371 ;; http://msdn.microsoft.com/library/en-us/dllproc/base/getconsolecp.asp
372 (declaim (ftype (function () keyword) console-input-codepage))
373 (defun console-input-codepage ()
374 (or #!+sb-unicode
375 (gethash (alien-funcall (extern-alien "GetConsoleCP" (function UINT)))
376 *codepage-to-external-format*)
377 :latin-1))
379 ;; http://msdn.microsoft.com/library/en-us/dllproc/base/getconsoleoutputcp.asp
380 (declaim (ftype (function () keyword) console-output-codepage))
381 (defun console-output-codepage ()
382 (or #!+sb-unicode
383 (gethash (alien-funcall
384 (extern-alien "GetConsoleOutputCP" (function UINT)))
385 *codepage-to-external-format*)
386 :latin-1))
388 (define-alien-routine ("LocalFree" local-free) void
389 (lptr (* t)))
391 (defmacro cast-and-free (value &key (type 'system-string)
392 (free-function 'free-alien))
393 `(prog1 (cast ,value ,type)
394 (,free-function ,value)))
396 (eval-when (:compile-toplevel :load-toplevel :execute)
397 (defmacro with-funcname ((name description) &body body)
398 `(let
399 ((,name (etypecase ,description
400 (string ,description)
401 (cons (destructuring-bind (s &optional c) ,description
402 (format nil "~A~A" s
403 (if c #!-sb-unicode "A" #!+sb-unicode "W" "")))))))
404 ,@body)))
406 (defmacro make-system-buffer (x)
407 `(make-alien char #!+sb-unicode (ash ,x 1) #!-sb-unicode ,x))
409 (defmacro with-handle ((var initform
410 &key (close-operator 'close-handle))
411 &body body)
412 `(without-interrupts
413 (block nil
414 (let ((,var ,initform))
415 (unwind-protect
416 (with-local-interrupts
417 ,@body)
418 (,close-operator ,var))))))
420 (define-alien-type pathname-buffer
421 (array char #.(ash (1+ max_path) #!+sb-unicode 1 #!-sb-unicode 0)))
423 (define-alien-type long-pathname-buffer
424 #!+sb-unicode (array char 65536)
425 #!-sb-unicode pathname-buffer)
427 (defmacro decode-system-string (alien)
428 `(cast (cast ,alien (* char)) system-string))
430 ;;; FIXME: The various FOO-SYSCALL-BAR macros, and perhaps some other
431 ;;; macros in this file, are only used in this file, and could be
432 ;;; implemented using SB!XC:DEFMACRO wrapped in EVAL-WHEN.
434 (defmacro syscall ((name ret-type &rest arg-types) success-form &rest args)
435 (with-funcname (sname name)
436 `(locally
437 (declare (optimize (sb!c::float-accuracy 0)))
438 (let ((result (alien-funcall
439 (extern-alien ,sname
440 (function ,ret-type ,@arg-types))
441 ,@args)))
442 (declare (ignorable result))
443 ,success-form))))
445 ;;; This is like SYSCALL, but if it fails, signal an error instead of
446 ;;; returning error codes. Should only be used for syscalls that will
447 ;;; never really get an error.
448 (defmacro syscall* ((name &rest arg-types) success-form &rest args)
449 (with-funcname (sname name)
450 `(locally
451 (declare (optimize (sb!c::float-accuracy 0)))
452 (let ((result (alien-funcall
453 (extern-alien ,sname (function bool ,@arg-types))
454 ,@args)))
455 (when (zerop result)
456 (win32-error ,sname))
457 ,success-form))))
459 (defmacro with-sysfun ((func name ret-type &rest arg-types) &body body)
460 (with-funcname (sname name)
461 `(with-alien ((,func (function ,ret-type ,@arg-types)
462 :extern ,sname))
463 ,@body)))
465 (defmacro void-syscall* ((name &rest arg-types) &rest args)
466 `(syscall* (,name ,@arg-types) (values t 0) ,@args))
468 (defun format-system-message (err)
469 "http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/retrieving_the_last_error_code.asp"
470 (let ((message
471 (with-alien ((amsg (* char)))
472 (syscall (("FormatMessage" t)
473 dword dword dword dword dword (* (* char)) dword dword)
474 (cast-and-free amsg :free-function local-free)
475 (logior format-message-allocate-buffer
476 format-message-from-system
477 format-message-max-width-mask
478 format-message-ignore-inserts)
479 0 err 0 (addr amsg) 0 0))))
480 (and message (string-right-trim '(#\Space) message))))
482 (defmacro win32-error (func-name &optional err)
483 `(let ((err-code ,(or err `(get-last-error))))
484 (declare (type (unsigned-byte 32) err-code))
485 (error "~%Win32 Error [~A] - ~A~%~A"
486 ,func-name
487 err-code
488 (format-system-message err-code))))
490 (defun get-folder-namestring (csidl)
491 "http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/shgetfolderpath.asp"
492 (with-alien ((apath pathname-buffer))
493 (syscall (("SHGetFolderPath" t) int handle int handle dword (* char))
494 (concatenate 'string (decode-system-string apath) "\\")
495 0 csidl 0 0 (cast apath (* char)))))
497 (defun get-folder-pathname (csidl)
498 (parse-native-namestring (get-folder-namestring csidl)))
500 (defun sb!unix:posix-getcwd ()
501 (with-alien ((apath pathname-buffer))
502 (with-sysfun (afunc ("GetCurrentDirectory" t) dword dword (* char))
503 (let ((ret (alien-funcall afunc (1+ max_path) (cast apath (* char)))))
504 (when (zerop ret)
505 (win32-error "GetCurrentDirectory"))
506 (if (> ret (1+ max_path))
507 (with-alien ((apath (* char) (make-system-buffer ret)))
508 (alien-funcall afunc ret apath)
509 (cast-and-free apath))
510 (decode-system-string apath))))))
512 (defun sb!unix:unix-mkdir (name mode)
513 (declare (type sb!unix:unix-pathname name)
514 (type sb!unix:unix-file-mode mode)
515 (ignore mode))
516 (syscall (("CreateDirectory" t) lispbool system-string (* t))
517 (values result (if result 0 (get-last-error)))
518 name nil))
520 (defun sb!unix:unix-rename (name1 name2)
521 (declare (type sb!unix:unix-pathname name1 name2))
522 (syscall (("MoveFile" t) lispbool system-string system-string)
523 (values result (if result 0 (get-last-error)))
524 name1 name2))
526 (defun sb!unix::posix-getenv (name)
527 (declare (type simple-string name))
528 (with-alien ((aenv (* char) (make-system-buffer default-environment-length)))
529 (with-sysfun (afunc ("GetEnvironmentVariable" t)
530 dword system-string (* char) dword)
531 (let ((ret (alien-funcall afunc name aenv default-environment-length)))
532 (when (> ret default-environment-length)
533 (free-alien aenv)
534 (setf aenv (make-system-buffer ret))
535 (alien-funcall afunc name aenv ret))
536 (if (> ret 0)
537 (cast-and-free aenv)
538 (free-alien aenv))))))
540 ;; GET-CURRENT-PROCESS
541 ;; The GetCurrentProcess function retrieves a pseudo handle for the current
542 ;; process.
544 ;; http://msdn.microsoft.com/library/en-us/dllproc/base/getcurrentprocess.asp
545 (declaim (inline get-current-process))
546 (define-alien-routine ("GetCurrentProcess" get-current-process) handle)
548 ;;;; Process time information
550 (defconstant 100ns-per-internal-time-unit
551 (/ 10000000 sb!xc:internal-time-units-per-second))
553 ;; FILETIME
554 ;; The FILETIME structure is a 64-bit value representing the number of
555 ;; 100-nanosecond intervals since January 1, 1601 (UTC).
557 ;; http://msdn.microsoft.com/library/en-us/sysinfo/base/filetime_str.asp?
558 (define-alien-type FILETIME (unsigned 64))
560 ;; FILETIME definition above is almost correct (on little-endian systems),
561 ;; except for the wrong alignment if used in another structure: the real
562 ;; definition is a struct of two dwords.
563 ;; Let's define FILETIME-MEMBER for that purpose; it will be useful with
564 ;; GetFileAttributesEx and FindFirstFileExW.
566 (define-alien-type FILETIME-MEMBER
567 (struct nil (low dword) (high dword)))
569 (defmacro with-process-times ((creation-time exit-time kernel-time user-time)
570 &body forms)
571 `(with-alien ((,creation-time filetime)
572 (,exit-time filetime)
573 (,kernel-time filetime)
574 (,user-time filetime))
575 (syscall* (("GetProcessTimes") handle (* filetime) (* filetime)
576 (* filetime) (* filetime))
577 (progn ,@forms)
578 (get-current-process)
579 (addr ,creation-time)
580 (addr ,exit-time)
581 (addr ,kernel-time)
582 (addr ,user-time))))
584 (declaim (inline system-internal-real-time))
586 (let ((epoch 0))
587 (declare (unsigned-byte epoch))
588 ;; FIXME: For optimization ideas see the unix implementation.
589 (defun reinit-internal-real-time ()
590 (setf epoch 0
591 epoch (get-internal-real-time)))
592 (defun get-internal-real-time ()
593 (- (with-alien ((system-time filetime))
594 (syscall (("GetSystemTimeAsFileTime") void (* filetime))
595 (values (floor system-time 100ns-per-internal-time-unit))
596 (addr system-time)))
597 epoch)))
599 (defun system-internal-run-time ()
600 (with-process-times (creation-time exit-time kernel-time user-time)
601 (values (floor (+ user-time kernel-time) 100ns-per-internal-time-unit))))
603 (define-alien-type hword (unsigned 16))
605 (define-alien-type systemtime
606 (struct systemtime
607 (year hword)
608 (month hword)
609 (weekday hword)
610 (day hword)
611 (hour hword)
612 (minute hword)
613 (second hword)
614 (millisecond hword)))
616 ;; Obtained with, but the XC can't deal with that -- but
617 ;; it's not like the value is ever going to change...
618 ;; (with-alien ((filetime filetime)
619 ;; (epoch systemtime))
620 ;; (setf (slot epoch 'year) 1970
621 ;; (slot epoch 'month) 1
622 ;; (slot epoch 'day) 1
623 ;; (slot epoch 'hour) 0
624 ;; (slot epoch 'minute) 0
625 ;; (slot epoch 'second) 0
626 ;; (slot epoch 'millisecond) 0)
627 ;; (syscall (("SystemTimeToFileTime" 8) void
628 ;; (* systemtime) (* filetime))
629 ;; filetime
630 ;; (addr epoch)
631 ;; (addr filetime)))
632 (defconstant +unix-epoch-filetime+ 116444736000000000)
633 (defconstant +filetime-unit+ (* 100ns-per-internal-time-unit
634 internal-time-units-per-second))
635 (defconstant +common-lisp-epoch-filetime-seconds+ 9435484800)
637 #!-sb-fluid
638 (declaim (inline get-time-of-day))
639 (defun get-time-of-day ()
640 "Return the number of seconds and microseconds since the beginning of the
641 UNIX epoch: January 1st 1970."
642 (with-alien ((system-time filetime))
643 (syscall (("GetSystemTimeAsFileTime") void (* filetime))
644 (multiple-value-bind (sec 100ns)
645 (floor (- system-time +unix-epoch-filetime+)
646 (* 100ns-per-internal-time-unit
647 internal-time-units-per-second))
648 (values sec (floor 100ns 10)))
649 (addr system-time))))
651 ;; Data for FindFirstFileExW and GetFileAttributesEx
652 (define-alien-type find-data
653 (struct nil
654 (attributes dword)
655 (ctime filetime-member)
656 (atime filetime-member)
657 (mtime filetime-member)
658 (size-low dword)
659 (size-high dword)
660 (reserved0 dword)
661 (reserved1 dword)
662 (long-name (array tchar #.max_path))
663 (short-name (array tchar 14))))
665 (define-alien-type file-attributes
666 (struct nil
667 (attributes dword)
668 (ctime filetime-member)
669 (atime filetime-member)
670 (mtime filetime-member)
671 (size-low dword)
672 (size-high dword)))
674 (define-alien-routine ("FindClose" find-close) lispbool
675 (handle handle))
677 (defun attribute-file-kind (dword)
678 (if (logtest file-attribute-directory dword)
679 :directory :file))
681 (defun native-file-write-date (native-namestring)
682 "Return file write date, represented as CL universal time."
683 (with-alien ((file-attributes file-attributes))
684 (syscall (("GetFileAttributesEx" t) lispbool
685 system-string int file-attributes)
686 (and result
687 (- (floor (deref (cast (slot file-attributes 'mtime)
688 (* filetime)))
689 +filetime-unit+)
690 +common-lisp-epoch-filetime-seconds+))
691 native-namestring 0 file-attributes)))
693 (defun native-probe-file-name (native-namestring)
694 "Return truename \(using GetLongPathName\) as primary value,
695 File kind as secondary.
697 Unless kind is false, null truename shouldn't be interpreted as error or file
698 absense."
699 (with-alien ((file-attributes file-attributes)
700 (buffer long-pathname-buffer))
701 (syscall (("GetFileAttributesEx" t) lispbool
702 system-string int file-attributes)
703 (values
704 (syscall (("GetLongPathName" t) dword
705 system-string long-pathname-buffer dword)
706 (and (plusp result) (decode-system-string buffer))
707 native-namestring buffer 32768)
708 (and result
709 (attribute-file-kind
710 (slot file-attributes 'attributes))))
711 native-namestring 0 file-attributes)))
713 (defun native-delete-file (native-namestring)
714 (syscall (("DeleteFile" t) lispbool system-string)
715 result native-namestring))
717 (defun native-delete-directory (native-namestring)
718 (syscall (("RemoveDirectory" t) lispbool system-string)
719 result native-namestring))
721 (defun native-call-with-directory-iterator (function namestring errorp)
722 (declare (type (or null string) namestring)
723 (function function))
724 (when namestring
725 (with-alien ((find-data find-data))
726 (with-handle (handle (syscall (("FindFirstFile" t) handle
727 system-string find-data)
728 (if (eql result invalid-handle)
729 (if errorp
730 (win32-error "FindFirstFile")
731 (return))
732 result)
733 (concatenate 'string
734 namestring "*.*")
735 find-data)
736 :close-operator find-close)
737 (let ((more t))
738 (dx-flet ((one-iter ()
739 (tagbody
740 :next
741 (when more
742 (let ((name (decode-system-string
743 (slot find-data 'long-name)))
744 (attributes (slot find-data 'attributes)))
745 (setf more
746 (syscall (("FindNextFile" t) lispbool
747 handle find-data) result
748 handle find-data))
749 (cond ((equal name ".") (go :next))
750 ((equal name "..") (go :next))
752 (return-from one-iter
753 (values name
754 (attribute-file-kind
755 attributes))))))))))
756 (funcall function #'one-iter)))))))
758 ;; SETENV
759 ;; The SetEnvironmentVariable function sets the contents of the specified
760 ;; environment variable for the current process.
762 ;; http://msdn.microsoft.com/library/en-us/dllproc/base/setenvironmentvariable.asp
763 (defun setenv (name value)
764 (declare (type (or null simple-string) value))
765 (if value
766 (void-syscall* (("SetEnvironmentVariable" t) system-string system-string)
767 name value)
768 (void-syscall* (("SetEnvironmentVariable" t) system-string int-ptr)
769 name 0)))
771 ;; Let SETENV be an accessor for POSIX-GETENV.
773 ;; DFL: Merged this function because it seems useful to me. But
774 ;; shouldn't we then define it on actual POSIX, too?
775 (defun (setf sb!unix::posix-getenv) (new-value name)
776 (if (setenv name new-value)
777 new-value
778 (posix-getenv name)))
780 (defmacro c-sizeof (s)
781 "translate alien size (in bits) to c-size (in bytes)"
782 `(/ (alien-size ,s) 8))
784 ;; OSVERSIONINFO
785 ;; The OSVERSIONINFO data structure contains operating system version
786 ;; information. The information includes major and minor version numbers,
787 ;; a build number, a platform identifier, and descriptive text about
788 ;; the operating system. This structure is used with the GetVersionEx function.
790 ;; http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
791 (define-alien-type nil
792 (struct OSVERSIONINFO
793 (dwOSVersionInfoSize dword)
794 (dwMajorVersion dword)
795 (dwMinorVersion dword)
796 (dwBuildNumber dword)
797 (dwPlatformId dword)
798 (szCSDVersion (array char #!-sb-unicode 128 #!+sb-unicode 256))))
800 (defun get-version-ex ()
801 (with-alien ((info (struct OSVERSIONINFO)))
802 (setf (slot info 'dwOSVersionInfoSize) (c-sizeof (struct OSVERSIONINFO)))
803 (syscall* (("GetVersionEx" t) (* (struct OSVERSIONINFO)))
804 (values (slot info 'dwMajorVersion)
805 (slot info 'dwMinorVersion)
806 (slot info 'dwBuildNumber)
807 (slot info 'dwPlatformId)
808 (cast (slot info 'szCSDVersion) system-string))
809 (addr info))))
811 ;; GET-COMPUTER-NAME
812 ;; The GetComputerName function retrieves the NetBIOS name of the local
813 ;; computer. This name is established at system startup, when the system
814 ;; reads it from the registry.
816 ;; http://msdn.microsoft.com/library/en-us/sysinfo/base/getcomputername.asp
817 (declaim (ftype (function () simple-string) get-computer-name))
818 (defun get-computer-name ()
819 (with-alien ((aname (* char) (make-system-buffer (1+ MAX_COMPUTERNAME_LENGTH)))
820 (length dword (1+ MAX_COMPUTERNAME_LENGTH)))
821 (with-sysfun (afunc ("GetComputerName" t) bool (* char) (* dword))
822 (when (zerop (alien-funcall afunc aname (addr length)))
823 (let ((err (get-last-error)))
824 (unless (= err ERROR_BUFFER_OVERFLOW)
825 (win32-error "GetComputerName" err))
826 (free-alien aname)
827 (setf aname (make-system-buffer length))
828 (alien-funcall afunc aname (addr length))))
829 (cast-and-free aname))))
831 (define-alien-routine ("SetFilePointerEx" set-file-pointer-ex) lispbool
832 (handle handle)
833 (offset long-long)
834 (new-position long-long :out)
835 (whence dword))
837 (defun lseeki64 (handle offset whence)
838 (let ((type (get-file-type handle)))
839 (if (or (= type file-type-char)
840 (= type file-type-disk))
841 (multiple-value-bind (moved to-place)
842 (set-file-pointer-ex handle offset whence)
843 (if moved
844 (values to-place 0)
845 (values -1 (get-last-error))))
846 (values -1 0))))
848 ;; File mapping support routines
849 (define-alien-routine (#!+sb-unicode "CreateFileMappingW"
850 #!-sb-unicode "CreateFileMappingA"
851 create-file-mapping)
852 handle
853 (handle handle)
854 (security-attributes (* t))
855 (protection dword)
856 (maximum-size-high dword)
857 (maximum-size-low dword)
858 (name system-string))
860 (define-alien-routine ("MapViewOfFile" map-view-of-file)
861 system-area-pointer
862 (file-mapping handle)
863 (desired-access dword)
864 (offset-high dword)
865 (offset-low dword)
866 (size dword))
868 (define-alien-routine ("UnmapViewOfFile" unmap-view-of-file) bool
869 (address (* t)))
871 (define-alien-routine ("FlushViewOfFile" flush-view-of-file) bool
872 (address (* t))
873 (length dword))
875 ;; Constants for CreateFile `disposition'.
876 (defconstant file-create-new 1)
877 (defconstant file-create-always 2)
878 (defconstant file-open-existing 3)
879 (defconstant file-open-always 4)
880 (defconstant file-truncate-existing 5)
882 ;; access rights
883 (defconstant access-generic-read #x80000000)
884 (defconstant access-generic-write #x40000000)
885 (defconstant access-generic-execute #x20000000)
886 (defconstant access-generic-all #x10000000)
887 (defconstant access-file-append-data #x4)
888 (defconstant access-delete #x00010000)
890 ;; share modes
891 (defconstant file-share-delete #x04)
892 (defconstant file-share-read #x01)
893 (defconstant file-share-write #x02)
895 ;; CreateFile (the real file-opening workhorse).
896 (define-alien-routine (#!+sb-unicode "CreateFileW"
897 #!-sb-unicode "CreateFileA"
898 create-file)
899 handle
900 (name (c-string #!+sb-unicode #!+sb-unicode :external-format :ucs-2))
901 (desired-access dword)
902 (share-mode dword)
903 (security-attributes (* t))
904 (creation-disposition dword)
905 (flags-and-attributes dword)
906 (template-file handle))
908 ;; GetFileSizeEx doesn't work with block devices :[
909 (define-alien-routine ("GetFileSizeEx" get-file-size-ex)
910 bool
911 (handle handle) (file-size (signed 64) :in-out))
913 ;; GetFileAttribute is like a tiny subset of fstat(),
914 ;; enough to distinguish directories from anything else.
915 (define-alien-routine (#!+sb-unicode "GetFileAttributesW"
916 #!-sb-unicode "GetFileAttributesA"
917 get-file-attributes)
918 dword
919 (name (c-string #!+sb-unicode #!+sb-unicode :external-format :ucs-2)))
921 (define-alien-routine ("CloseHandle" close-handle) bool
922 (handle handle))
924 (define-alien-routine ("_open_osfhandle" open-osfhandle)
926 (handle handle)
927 (flags int))
929 ;; Intended to be an imitation of sb!unix:unix-open based on
930 ;; CreateFile, as complete as possibly.
931 ;; FILE_FLAG_OVERLAPPED is a must for decent I/O.
933 (defun unixlike-open (path flags &key revertable
934 overlapped)
935 (declare (type sb!unix:unix-pathname path)
936 (type fixnum flags))
937 (let* ((disposition-flags
938 (logior
939 (if (logtest sb!unix:o_creat flags) #b100 0)
940 (if (logtest sb!unix:o_excl flags) #b010 0)
941 (if (logtest sb!unix:o_trunc flags) #b001 0)))
942 (create-disposition
943 ;; there are 8 combinations of creat|excl|trunc, some of
944 ;; them are equivalent. Case stmt below maps them to 5
945 ;; dispositions (see CreateFile manual).
946 (case disposition-flags
947 ((#b110 #b111) file-create-new)
948 ((#b001 #b011) file-truncate-existing)
949 ((#b000 #b010) file-open-existing)
950 (#b100 file-open-always)
951 (#b101 file-create-always))))
952 (let ((handle
953 (create-file path
954 (logior
955 (if revertable #x10000 0)
956 (if (logtest sb!unix:o_append flags)
957 access-file-append-data
959 (ecase (logand 3 flags)
960 (0 FILE_GENERIC_READ)
961 (1 FILE_GENERIC_WRITE)
962 ((2 3) (logior FILE_GENERIC_READ
963 FILE_GENERIC_WRITE))))
964 (logior FILE_SHARE_READ
965 FILE_SHARE_WRITE)
967 create-disposition
968 (if overlapped
969 file-flag-overlapped
970 file-attribute-normal)
971 0)))
972 (cond ((eql handle invalid-handle)
973 (values nil (get-last-error)))
975 ;; FIXME: seeking to the end is not enough for real APPEND
976 ;; semantics, but it's better than nothing.
977 ;; -- AK
979 ;; On the other hand, the CL spec implies the "better than
980 ;; nothing" seek-once semantics implemented here, and our
981 ;; POSIX backend is incorrect in implementing :APPEND as
982 ;; O_APPEND. Other CL implementations get this right across
983 ;; platforms.
985 ;; Of course, it would be nice if we had :IF-EXISTS
986 ;; :ATOMICALLY-APPEND separately as an extension, and in
987 ;; that case, we will have to worry about supporting it
988 ;; here after all.
990 ;; I've tested this only very briefly (on XP and Windows 7),
991 ;; but my impression is that WriteFile (without documenting
992 ;; it?) is like ZwWriteFile, i.e. if we pass in -1 as the
993 ;; offset in our overlapped structure, WriteFile seeks to the
994 ;; end for us. Should we depend on that? How do we communicate
995 ;; our desire to do so to the runtime?
996 ;; -- DFL
998 (set-file-pointer-ex handle 0 (if (logtest sb!unix::o_append flags) 2 0))
999 (values handle 0))))))
1001 (define-alien-routine ("closesocket" close-socket) int (handle handle))
1002 (define-alien-routine ("shutdown" shutdown-socket) int (handle handle)
1003 (how int))
1005 (define-alien-routine ("DuplicateHandle" duplicate-handle) lispbool
1006 (from-process handle)
1007 (from-handle handle)
1008 (to-process handle)
1009 (to-handle handle :out)
1010 (access dword)
1011 (inheritp lispbool)
1012 (options dword))
1014 (defconstant +handle-flag-inherit+ 1)
1015 (defconstant +handle-flag-protect-from-close+ 2)
1017 (define-alien-routine ("SetHandleInformation" set-handle-information) lispbool
1018 (handle handle)
1019 (mask dword)
1020 (flags dword))
1022 (define-alien-routine ("GetHandleInformation" get-handle-information) lispbool
1023 (handle handle)
1024 (flags dword :out))
1026 (define-alien-routine getsockopt int
1027 (handle handle)
1028 (level int)
1029 (opname int)
1030 (dataword int-ptr :in-out)
1031 (socklen int :in-out))
1033 (defconstant sol_socket #xFFFF)
1034 (defconstant so_type #x1008)
1036 (defun socket-handle-p (handle)
1037 (zerop (getsockopt handle sol_socket so_type 0 (alien-size int :bytes))))
1039 (defconstant ebadf 9)
1041 ;;; For sockets, CloseHandle first and closesocket() afterwards is
1042 ;;; legal: winsock tracks its handles separately (that's why we have
1043 ;;; the problem with simple _close in the first place).
1045 ;;; ...Seems to be the problem on some OSes, though. We could
1046 ;;; duplicate a handle and attempt close-socket on a duplicated one,
1047 ;;; but it also have some problems...
1049 (defun unixlike-close (fd)
1050 (if (or (zerop (close-socket fd))
1051 (close-handle fd))
1052 t (values nil ebadf)))
1054 (defconstant +std-input-handle+ -10)
1055 (defconstant +std-output-handle+ -11)
1056 (defconstant +std-error-handle+ -12)
1058 (defun get-std-handle-or-null (identity)
1059 (let ((handle (alien-funcall
1060 (extern-alien "GetStdHandle" (function handle dword))
1061 (logand (1- (ash 1 (alien-size dword))) identity))))
1062 (and (/= handle invalid-handle)
1063 (not (zerop handle))
1064 ;;When a gui process is launched in windows (subsystem WINDOWS)
1065 ;;it inherits the parent process' handles, which may very well be
1066 ;;invalid unless properly orchestrated by the parent process.
1067 ;;Win32 io will fail on these handles and there is no meaningful
1068 ;;way to make use of them.
1069 ;;So we can call GetFileType to verify the validity of the std handle
1070 ;;which returns FILE_TYPE_UNKNOWN if the handle is invalid
1071 ;;Technically it also returns FILE_TYPE_UNKNOWN if the function fails
1072 ;;but I can't think of a reason we'd care, nor what to do about it
1073 (not (zerop (get-file-type handle)))
1074 handle)))
1076 (defun get-std-handles ()
1077 (values (get-std-handle-or-null +std-input-handle+)
1078 (get-std-handle-or-null +std-output-handle+)
1079 (get-std-handle-or-null +std-error-handle+)))
1081 (defconstant +duplicate-same-access+ 2)
1083 (defun duplicate-and-unwrap-fd (fd &key inheritp)
1084 (let ((me (get-current-process)))
1085 (multiple-value-bind (duplicated handle)
1086 (duplicate-handle me (get-osfhandle fd)
1087 me 0 inheritp +duplicate-same-access+)
1088 (if duplicated
1089 (prog1 handle (crt-close fd))
1090 (win32-error 'duplicate-and-unwrap-fd)))))
1092 (define-alien-routine ("CreatePipe" create-pipe) lispbool
1093 (read-pipe handle :out)
1094 (write-pipe handle :out)
1095 (security-attributes (* t))
1096 (buffer-size dword))
1098 (defun windows-pipe ()
1099 (multiple-value-bind (created read-handle write-handle)
1100 (create-pipe nil 256)
1101 (if created (values read-handle write-handle)
1102 (win32-error 'create-pipe))))
1104 (defun windows-isatty (handle)
1105 (if (= file-type-char (get-file-type handle))
1106 1 0))
1108 (defun inheritable-handle-p (handle)
1109 (multiple-value-bind (got flags)
1110 (get-handle-information handle)
1111 (if got (plusp (logand flags +handle-flag-inherit+))
1112 (win32-error 'inheritable-handle-p))))
1114 (defun (setf inheritable-handle-p) (allow handle)
1115 (if (set-handle-information handle
1116 +handle-flag-inherit+
1117 (if allow +handle-flag-inherit+ 0))
1118 allow
1119 (win32-error '(setf inheritable-handle-p))))
1121 (defun sb!unix:unix-dup (fd)
1122 (let ((me (get-current-process)))
1123 (multiple-value-bind (duplicated handle)
1124 (duplicate-handle me fd me 0 t +duplicate-same-access+)
1125 (if duplicated
1126 (values handle 0)
1127 (values nil (get-last-error))))))
1129 (defun call-with-crt-fd (thunk handle &optional (flags 0))
1130 (multiple-value-bind (duplicate errno)
1131 (sb!unix:unix-dup handle)
1132 (if duplicate
1133 (let ((fd (open-osfhandle duplicate flags)))
1134 (unwind-protect (funcall thunk fd)
1135 (crt-close fd)))
1136 (values nil errno))))
1138 ;;; random seeding
1140 (define-alien-routine ("CryptGenRandom" %crypt-gen-random) lispbool
1141 (handle handle)
1142 (length dword)
1143 (buffer (* t)))
1145 (define-alien-routine (#!-sb-unicode "CryptAcquireContextA"
1146 #!+sb-unicode "CryptAcquireContextW"
1147 %crypt-acquire-context) lispbool
1148 (handle handle :out)
1149 (container system-string)
1150 (provider system-string)
1151 (provider-type dword)
1152 (flags dword))
1154 (define-alien-routine ("CryptReleaseContext" %crypt-release-context) lispbool
1155 (handle handle)
1156 (flags dword))
1158 (defun crypt-gen-random (length)
1159 (multiple-value-bind (ok context)
1160 (%crypt-acquire-context nil nil prov-rsa-full
1161 (logior crypt-verifycontext crypt-silent))
1162 (unless ok
1163 (return-from crypt-gen-random (values nil (get-last-error))))
1164 (unwind-protect
1165 (let ((data (make-array length :element-type '(unsigned-byte 8))))
1166 (with-pinned-objects (data)
1167 (if (%crypt-gen-random context length (vector-sap data))
1168 data
1169 (values nil (get-last-error)))))
1170 (unless (%crypt-release-context context 0)
1171 (win32-error '%crypt-release-context)))))