Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <>2002-09-22 16:04:17 +0400
committercvs2svn <>2002-09-22 16:04:17 +0400
commite8038acb1b5f441fe7b2570c9448cf73b2038477 (patch)
tree9bc675d4928360fc4998eb5a43727fd1a4ce427d
parent9783ce28caf426c5ab39d1d6aefa31cfdb1b8234 (diff)
This commit was manufactured by cvs2svn to create tagZ-cygwin_daemon_merge_HEAD
'Z-cygwin_daemon_merge_HEAD'. Sprout from cygwin_daemon 2002-01-02 00:06:36 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.' Cherrypick from cygwin_daemon 2002-02-25 17:47:52 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/how-spawn-works.txt winsup/cygwin/wsock_event.h Cherrypick from cygwin_daemon 2002-06-06 15:35:10 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/include/netinet/udp.h winsup/cygwin/stackdump.sgml Cherrypick from cygwin_daemon 2002-01-17 10:39:38 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/libc/fnmatch.c Cherrypick from cygwin_daemon 2002-07-03 20:31:40 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/include/sys/statfs.h Cherrypick from cygwin_daemon 2002-09-04 15:17:25 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.': winsup/cygwin/how-autoload-works.txt Cherrypick from master 2002-09-22 12:04:15 UTC Conrad Scott <conrad.scott@dsl.pipex.com> '2002-09-22 Conrad Scott <conrad.scott@dsl.pipex.com>': winsup/cygserver/threaded_queue.cc winsup/cygserver/woutsup.h winsup/cygwin/CYGWIN_LICENSE winsup/cygwin/ChangeLog winsup/cygwin/ChangeLog-1998 winsup/cygwin/ChangeLog-1999 winsup/cygwin/ChangeLog-2000 winsup/cygwin/Makefile.in winsup/cygwin/assert.cc winsup/cygwin/autoload.cc winsup/cygwin/child_info.h winsup/cygwin/configure winsup/cygwin/configure.in winsup/cygwin/cygerrno.h winsup/cygwin/cygheap.cc winsup/cygwin/cygheap.h winsup/cygwin/cygmagic winsup/cygwin/cygmalloc.h winsup/cygwin/cygrun.c winsup/cygwin/cygserver.cc winsup/cygwin/cygserver_client.cc winsup/cygwin/cygserver_ipc.h winsup/cygwin/cygserver_process.cc winsup/cygwin/cygserver_shm.cc winsup/cygwin/cygserver_shm.h winsup/cygwin/cygserver_transport.cc winsup/cygwin/cygserver_transport_pipes.cc winsup/cygwin/cygserver_transport_sockets.cc winsup/cygwin/cygthread.cc winsup/cygwin/cygthread.h winsup/cygwin/cygwin.din winsup/cygwin/cygwin.sc winsup/cygwin/dcrt0.cc winsup/cygwin/debug.cc winsup/cygwin/debug.h winsup/cygwin/dir.cc winsup/cygwin/dlfcn.cc winsup/cygwin/dll_init.cc winsup/cygwin/dll_init.h winsup/cygwin/dlmalloc.c winsup/cygwin/dtable.cc winsup/cygwin/dtable.h winsup/cygwin/environ.cc winsup/cygwin/environ.h winsup/cygwin/errno.cc winsup/cygwin/exceptions.cc winsup/cygwin/exec.cc winsup/cygwin/external.cc winsup/cygwin/fcntl.cc winsup/cygwin/fhandler.cc winsup/cygwin/fhandler.h winsup/cygwin/fhandler_clipboard.cc winsup/cygwin/fhandler_console.cc winsup/cygwin/fhandler_disk_file.cc winsup/cygwin/fhandler_dsp.cc winsup/cygwin/fhandler_floppy.cc winsup/cygwin/fhandler_mem.cc winsup/cygwin/fhandler_proc.cc winsup/cygwin/fhandler_process.cc winsup/cygwin/fhandler_random.cc winsup/cygwin/fhandler_raw.cc winsup/cygwin/fhandler_registry.cc winsup/cygwin/fhandler_serial.cc winsup/cygwin/fhandler_socket.cc winsup/cygwin/fhandler_tape.cc winsup/cygwin/fhandler_termios.cc winsup/cygwin/fhandler_tty.cc winsup/cygwin/fhandler_virtual.cc winsup/cygwin/fhandler_windows.cc winsup/cygwin/fhandler_zero.cc winsup/cygwin/fork.cc winsup/cygwin/glob.c winsup/cygwin/gmon.c winsup/cygwin/grp.cc winsup/cygwin/heap.cc winsup/cygwin/heap.h winsup/cygwin/hires.h winsup/cygwin/how-cygheap-works.txt winsup/cygwin/how-fhandlers-work.txt winsup/cygwin/how-signals-work.txt winsup/cygwin/how-to-debug-cygwin.txt winsup/cygwin/include/cygwin/acl.h winsup/cygwin/include/cygwin/cygserver.h winsup/cygwin/include/cygwin/cygserver_process.h winsup/cygwin/include/cygwin/cygserver_transport.h winsup/cygwin/include/cygwin/cygserver_transport_pipes.h winsup/cygwin/include/cygwin/cygserver_transport_sockets.h winsup/cygwin/include/cygwin/grp.h winsup/cygwin/include/cygwin/if.h winsup/cygwin/include/cygwin/ipc.h winsup/cygwin/include/cygwin/msg.h winsup/cygwin/include/cygwin/mtio.h winsup/cygwin/include/cygwin/sem.h winsup/cygwin/include/cygwin/shm.h winsup/cygwin/include/cygwin/socket.h winsup/cygwin/include/cygwin/stat.h winsup/cygwin/include/cygwin/types.h winsup/cygwin/include/cygwin/version.h winsup/cygwin/include/fnmatch.h winsup/cygwin/include/getopt.h winsup/cygwin/include/glob.h winsup/cygwin/include/limits.h winsup/cygwin/include/netdb.h winsup/cygwin/include/netinet/ip.h winsup/cygwin/include/netinet/tcp.h winsup/cygwin/include/pthread.h winsup/cygwin/include/sys/cygwin.h winsup/cygwin/include/sys/ioctl.h winsup/cygwin/include/sys/mount.h winsup/cygwin/include/sys/resource.h winsup/cygwin/include/sys/socket.h winsup/cygwin/include/sys/soundcard.h winsup/cygwin/include/sys/strace.h winsup/cygwin/include/sys/sysmacros.h winsup/cygwin/include/sys/termios.h winsup/cygwin/include/sys/uio.h winsup/cygwin/include/sys/un.h winsup/cygwin/include/sys/vfs.h winsup/cygwin/init.cc winsup/cygwin/ioctl.cc winsup/cygwin/ipc.cc winsup/cygwin/lib/cygwin_crt0.c winsup/cygwin/lib/dll_main.cc winsup/cygwin/lib/getopt.c winsup/cygwin/localtime.cc winsup/cygwin/malloc.cc winsup/cygwin/malloc_wrapper.cc winsup/cygwin/miscfuncs.cc winsup/cygwin/mkvers.sh winsup/cygwin/mmap.cc winsup/cygwin/msg.cc winsup/cygwin/net.cc winsup/cygwin/ntdll.h winsup/cygwin/ntea.cc winsup/cygwin/passwd.cc winsup/cygwin/path.cc winsup/cygwin/path.h winsup/cygwin/perthread.h winsup/cygwin/pinfo.cc winsup/cygwin/pinfo.h winsup/cygwin/pipe.cc winsup/cygwin/poll.cc winsup/cygwin/pthread.cc winsup/cygwin/pwdgrp.h winsup/cygwin/regex/regcomp.c winsup/cygwin/registry.cc winsup/cygwin/resource.cc winsup/cygwin/safe_memory.h winsup/cygwin/sched.cc winsup/cygwin/sec_acl.cc winsup/cygwin/sec_helper.cc winsup/cygwin/security.cc winsup/cygwin/security.h winsup/cygwin/select.cc winsup/cygwin/sem.cc winsup/cygwin/shared.cc winsup/cygwin/shared_info.h winsup/cygwin/shm.cc winsup/cygwin/signal.cc winsup/cygwin/sigproc.cc winsup/cygwin/sigproc.h winsup/cygwin/smallprint.c winsup/cygwin/spawn.cc winsup/cygwin/speclib winsup/cygwin/strace.cc winsup/cygwin/sync.cc winsup/cygwin/sync.h winsup/cygwin/syscalls.cc winsup/cygwin/sysconf.cc winsup/cygwin/syslog.cc winsup/cygwin/termios.cc winsup/cygwin/thread.cc winsup/cygwin/thread.h winsup/cygwin/threaded_queue.cc winsup/cygwin/threaded_queue.h winsup/cygwin/times.cc winsup/cygwin/tty.cc winsup/cygwin/tty.h winsup/cygwin/uinfo.cc winsup/cygwin/uname.cc winsup/cygwin/wait.cc winsup/cygwin/winbase.h winsup/cygwin/wincap.cc winsup/cygwin/wincap.h winsup/cygwin/window.cc winsup/cygwin/winsup.h winsup/cygwin/winver.rc winsup/cygwin/woutsup.h Delete: winsup/cygwin/include/cygwin/ip.h winsup/cygwin/include/sys/ipc.h winsup/cygwin/include/sys/shm.h winsup/cygwin/include/wchar.h winsup/cygwin/lib/_cygwin_S_IEXEC.cc winsup/cygwin/regexp/regerror.c winsup/cygwin/regexp/regexp.3 winsup/cygwin/regexp/regexp.c winsup/cygwin/regexp/regsub.c winsup/cygwin/shortcut.c winsup/cygwin/shortcut.h winsup/cygwin/test.c
-rw-r--r--winsup/cygserver/threaded_queue.cc503
-rw-r--r--winsup/cygserver/woutsup.h110
-rw-r--r--winsup/cygwin/CYGWIN_LICENSE18
-rw-r--r--winsup/cygwin/ChangeLog8521
-rw-r--r--winsup/cygwin/ChangeLog-199812
-rw-r--r--winsup/cygwin/ChangeLog-199942
-rw-r--r--winsup/cygwin/ChangeLog-200048
-rw-r--r--winsup/cygwin/Makefile.in226
-rw-r--r--winsup/cygwin/assert.cc9
-rw-r--r--winsup/cygwin/autoload.cc65
-rw-r--r--winsup/cygwin/child_info.h43
-rwxr-xr-xwinsup/cygwin/configure132
-rw-r--r--winsup/cygwin/configure.in2
-rw-r--r--winsup/cygwin/cygerrno.h5
-rw-r--r--winsup/cygwin/cygheap.cc157
-rw-r--r--winsup/cygwin/cygheap.h177
-rwxr-xr-xwinsup/cygwin/cygmagic18
-rw-r--r--winsup/cygwin/cygmalloc.h29
-rw-r--r--winsup/cygwin/cygrun.c41
-rwxr-xr-xwinsup/cygwin/cygserver.cc964
-rwxr-xr-xwinsup/cygwin/cygserver_client.cc572
-rw-r--r--winsup/cygwin/cygserver_ipc.h84
-rwxr-xr-xwinsup/cygwin/cygserver_process.cc663
-rwxr-xr-xwinsup/cygwin/cygserver_shm.cc1258
-rw-r--r--winsup/cygwin/cygserver_shm.h190
-rwxr-xr-xwinsup/cygwin/cygserver_transport.cc95
-rwxr-xr-xwinsup/cygwin/cygserver_transport_pipes.cc390
-rwxr-xr-xwinsup/cygwin/cygserver_transport_sockets.cc414
-rw-r--r--winsup/cygwin/cygthread.cc261
-rw-r--r--winsup/cygwin/cygthread.h38
-rw-r--r--winsup/cygwin/cygwin.din190
-rw-r--r--winsup/cygwin/cygwin.sc6
-rw-r--r--winsup/cygwin/dcrt0.cc311
-rw-r--r--winsup/cygwin/debug.cc299
-rw-r--r--winsup/cygwin/debug.h38
-rw-r--r--winsup/cygwin/dir.cc321
-rw-r--r--winsup/cygwin/dlfcn.cc14
-rw-r--r--winsup/cygwin/dll_init.cc11
-rw-r--r--winsup/cygwin/dll_init.h12
-rw-r--r--winsup/cygwin/dlmalloc.c24
-rw-r--r--winsup/cygwin/dtable.cc485
-rw-r--r--winsup/cygwin/dtable.h16
-rw-r--r--winsup/cygwin/environ.cc378
-rw-r--r--winsup/cygwin/environ.h30
-rw-r--r--winsup/cygwin/errno.cc28
-rw-r--r--winsup/cygwin/exceptions.cc125
-rw-r--r--winsup/cygwin/exec.cc152
-rw-r--r--winsup/cygwin/external.cc93
-rw-r--r--winsup/cygwin/fcntl.cc17
-rw-r--r--winsup/cygwin/fhandler.cc923
-rw-r--r--winsup/cygwin/fhandler.h617
-rw-r--r--winsup/cygwin/fhandler_clipboard.cc25
-rw-r--r--winsup/cygwin/fhandler_console.cc176
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc505
-rw-r--r--winsup/cygwin/fhandler_dsp.cc47
-rw-r--r--winsup/cygwin/fhandler_floppy.cc50
-rw-r--r--winsup/cygwin/fhandler_mem.cc54
-rw-r--r--winsup/cygwin/fhandler_proc.cc509
-rw-r--r--winsup/cygwin/fhandler_process.cc743
-rw-r--r--winsup/cygwin/fhandler_random.cc24
-rw-r--r--winsup/cygwin/fhandler_raw.cc86
-rw-r--r--winsup/cygwin/fhandler_registry.cc673
-rw-r--r--winsup/cygwin/fhandler_serial.cc157
-rw-r--r--winsup/cygwin/fhandler_socket.cc919
-rw-r--r--winsup/cygwin/fhandler_tape.cc49
-rw-r--r--winsup/cygwin/fhandler_termios.cc67
-rw-r--r--winsup/cygwin/fhandler_tty.cc234
-rw-r--r--winsup/cygwin/fhandler_virtual.cc226
-rw-r--r--winsup/cygwin/fhandler_windows.cc15
-rw-r--r--winsup/cygwin/fhandler_zero.cc28
-rw-r--r--winsup/cygwin/fork.cc121
-rw-r--r--winsup/cygwin/glob.c76
-rw-r--r--winsup/cygwin/gmon.c7
-rw-r--r--winsup/cygwin/grp.cc323
-rw-r--r--winsup/cygwin/heap.cc23
-rw-r--r--winsup/cygwin/heap.h2
-rw-r--r--winsup/cygwin/hires.h47
-rw-r--r--winsup/cygwin/how-autoload-works.txt66
-rw-r--r--winsup/cygwin/how-cygheap-works.txt2
-rw-r--r--winsup/cygwin/how-fhandlers-work.txt10
-rw-r--r--winsup/cygwin/how-signals-work.txt6
-rw-r--r--winsup/cygwin/how-spawn-works.txt32
-rw-r--r--winsup/cygwin/how-to-debug-cygwin.txt175
-rw-r--r--winsup/cygwin/include/cygwin/acl.h24
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver.h213
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_process.h168
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_transport.h43
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_transport_pipes.h66
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_transport_sockets.h55
-rw-r--r--winsup/cygwin/include/cygwin/grp.h48
-rw-r--r--winsup/cygwin/include/cygwin/if.h40
-rw-r--r--winsup/cygwin/include/cygwin/ip.h1
-rw-r--r--winsup/cygwin/include/cygwin/ipc.h53
-rw-r--r--winsup/cygwin/include/cygwin/msg.h92
-rw-r--r--winsup/cygwin/include/cygwin/mtio.h8
-rw-r--r--winsup/cygwin/include/cygwin/sem.h95
-rw-r--r--winsup/cygwin/include/cygwin/shm.h94
-rw-r--r--winsup/cygwin/include/cygwin/socket.h6
-rw-r--r--winsup/cygwin/include/cygwin/stat.h88
-rw-r--r--winsup/cygwin/include/cygwin/types.h44
-rw-r--r--winsup/cygwin/include/cygwin/version.h50
-rw-r--r--winsup/cygwin/include/fnmatch.h63
-rw-r--r--winsup/cygwin/include/getopt.h34
-rw-r--r--winsup/cygwin/include/glob.h9
-rw-r--r--winsup/cygwin/include/limits.h15
-rw-r--r--winsup/cygwin/include/netinet/ip.h203
-rw-r--r--winsup/cygwin/include/netinet/tcp.h146
-rw-r--r--winsup/cygwin/include/netinet/udp.h51
-rw-r--r--winsup/cygwin/include/pthread.h27
-rw-r--r--winsup/cygwin/include/sys/cygwin.h33
-rw-r--r--winsup/cygwin/include/sys/ioctl.h4
-rw-r--r--winsup/cygwin/include/sys/ipc.h52
-rw-r--r--winsup/cygwin/include/sys/mount.h8
-rw-r--r--winsup/cygwin/include/sys/resource.h20
-rw-r--r--winsup/cygwin/include/sys/shm.h89
-rw-r--r--winsup/cygwin/include/sys/socket.h13
-rw-r--r--winsup/cygwin/include/sys/soundcard.h82
-rw-r--r--winsup/cygwin/include/sys/statfs.h11
-rw-r--r--winsup/cygwin/include/sys/strace.h10
-rw-r--r--winsup/cygwin/include/sys/sysmacros.h8
-rw-r--r--winsup/cygwin/include/sys/termios.h28
-rw-r--r--winsup/cygwin/include/sys/uio.h9
-rw-r--r--winsup/cygwin/include/sys/un.h2
-rw-r--r--winsup/cygwin/include/sys/vfs.h2
-rw-r--r--winsup/cygwin/include/wchar.h28
-rw-r--r--winsup/cygwin/init.cc30
-rw-r--r--winsup/cygwin/ioctl.cc34
-rw-r--r--winsup/cygwin/ipc.cc10
-rw-r--r--winsup/cygwin/lib/_cygwin_S_IEXEC.cc21
-rw-r--r--winsup/cygwin/lib/cygwin_crt0.c3
-rw-r--r--winsup/cygwin/lib/dll_main.cc2
-rw-r--r--winsup/cygwin/lib/getopt.c14
-rw-r--r--winsup/cygwin/libc/fnmatch.c230
-rw-r--r--winsup/cygwin/localtime.cc19
-rw-r--r--winsup/cygwin/malloc.cc5582
-rw-r--r--winsup/cygwin/malloc_wrapper.cc229
-rw-r--r--winsup/cygwin/miscfuncs.cc148
-rwxr-xr-xwinsup/cygwin/mkvers.sh2
-rw-r--r--winsup/cygwin/mmap.cc186
-rw-r--r--winsup/cygwin/msg.cc48
-rw-r--r--winsup/cygwin/net.cc1380
-rw-r--r--winsup/cygwin/ntdll.h246
-rw-r--r--winsup/cygwin/ntea.cc11
-rw-r--r--winsup/cygwin/passwd.cc193
-rw-r--r--winsup/cygwin/path.cc1227
-rw-r--r--winsup/cygwin/path.h85
-rw-r--r--winsup/cygwin/perthread.h41
-rw-r--r--winsup/cygwin/pinfo.cc78
-rw-r--r--winsup/cygwin/pinfo.h31
-rw-r--r--winsup/cygwin/pipe.cc98
-rw-r--r--winsup/cygwin/poll.cc105
-rw-r--r--winsup/cygwin/pthread.cc59
-rw-r--r--winsup/cygwin/pwdgrp.h92
-rw-r--r--winsup/cygwin/regex/regcomp.c2
-rw-r--r--winsup/cygwin/regexp/regerror.c28
-rw-r--r--winsup/cygwin/regexp/regexp.3321
-rw-r--r--winsup/cygwin/regexp/regexp.c1321
-rw-r--r--winsup/cygwin/regexp/regsub.c87
-rw-r--r--winsup/cygwin/registry.cc5
-rw-r--r--winsup/cygwin/resource.cc24
-rw-r--r--winsup/cygwin/safe_memory.h53
-rw-r--r--winsup/cygwin/sched.cc1
-rw-r--r--winsup/cygwin/sec_acl.cc123
-rw-r--r--winsup/cygwin/sec_helper.cc145
-rw-r--r--winsup/cygwin/security.cc1161
-rw-r--r--winsup/cygwin/security.h147
-rw-r--r--winsup/cygwin/select.cc566
-rw-r--r--winsup/cygwin/sem.cc41
-rw-r--r--winsup/cygwin/shared.cc179
-rw-r--r--winsup/cygwin/shared_info.h32
-rw-r--r--winsup/cygwin/shm.cc1024
-rw-r--r--winsup/cygwin/shortcut.c170
-rw-r--r--winsup/cygwin/shortcut.h28
-rw-r--r--winsup/cygwin/signal.cc34
-rw-r--r--winsup/cygwin/sigproc.cc217
-rw-r--r--winsup/cygwin/sigproc.h21
-rw-r--r--winsup/cygwin/smallprint.c20
-rw-r--r--winsup/cygwin/spawn.cc242
-rwxr-xr-xwinsup/cygwin/speclib15
-rw-r--r--winsup/cygwin/stackdump.sgml13
-rw-r--r--winsup/cygwin/strace.cc87
-rw-r--r--winsup/cygwin/sync.cc15
-rw-r--r--winsup/cygwin/sync.h29
-rw-r--r--winsup/cygwin/syscalls.cc1547
-rw-r--r--winsup/cygwin/sysconf.cc14
-rw-r--r--winsup/cygwin/syslog.cc33
-rw-r--r--winsup/cygwin/termios.cc182
-rw-r--r--winsup/cygwin/test.c165
-rw-r--r--winsup/cygwin/thread.cc1543
-rw-r--r--winsup/cygwin/thread.h318
-rwxr-xr-xwinsup/cygwin/threaded_queue.cc503
-rwxr-xr-xwinsup/cygwin/threaded_queue.h142
-rw-r--r--winsup/cygwin/times.cc248
-rw-r--r--winsup/cygwin/tty.cc52
-rw-r--r--winsup/cygwin/tty.h3
-rw-r--r--winsup/cygwin/uinfo.cc510
-rw-r--r--winsup/cygwin/uname.cc26
-rw-r--r--winsup/cygwin/wait.cc3
-rw-r--r--winsup/cygwin/winbase.h7
-rw-r--r--winsup/cygwin/wincap.cc91
-rw-r--r--winsup/cygwin/wincap.h18
-rw-r--r--winsup/cygwin/window.cc61
-rw-r--r--winsup/cygwin/winsup.h77
-rw-r--r--winsup/cygwin/winver.rc2
-rw-r--r--winsup/cygwin/woutsup.h110
-rw-r--r--winsup/cygwin/wsock_event.h32
206 files changed, 31511 insertions, 17320 deletions
diff --git a/winsup/cygserver/threaded_queue.cc b/winsup/cygserver/threaded_queue.cc
index 5fb22b191..ba0fe4178 100644
--- a/winsup/cygserver/threaded_queue.cc
+++ b/winsup/cygserver/threaded_queue.cc
@@ -1,249 +1,408 @@
/* threaded_queue.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+#include "woutsup.h"
+
+#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
-#include <windows.h>
#include <sys/types.h>
-#include "wincap.h"
+#include <stdlib.h>
#include "threaded_queue.h"
-#define DEBUG 1
-#define debug_printf if (DEBUG) printf
+
+/*****************************************************************************/
+
+/* queue_request */
+
+queue_request::~queue_request ()
+{}
+
+/*****************************************************************************/
/* threaded_queue */
-DWORD WINAPI
-worker_function (LPVOID LpParam)
+threaded_queue::threaded_queue (const size_t initial_workers)
+ : _workers_count (0),
+ _running (false),
+ _submitters_head (NULL),
+ _requests_count (0),
+ _requests_head (NULL),
+ _requests_sem (NULL)
{
- class threaded_queue *queue = (class threaded_queue *) LpParam;
- class queue_request *request;
- /* FIXME use a threadsafe pop instead for speed? */
- while (queue->active)
+ InitializeCriticalSection (&_queue_lock);
+
+ // This semaphore's count is the number of requests on the queue.
+ // The maximum count (129792) is calculated as MAXIMUM_WAIT_OBJECTS
+ // multiplied by max. threads per process (2028?), which is (a few)
+ // more requests than could ever be pending with the current design.
+
+ _requests_sem = CreateSemaphore (NULL, // SECURITY_ATTRIBUTES
+ 0, // Initial count
+ 129792, // Maximum count
+ NULL); // Anonymous
+
+ if (!_requests_sem)
{
- EnterCriticalSection (&queue->queuelock);
- while (!queue->request && queue->active)
- {
- LeaveCriticalSection (&queue->queuelock);
- DWORD rc = WaitForSingleObject (queue->event, INFINITE);
- if (rc == WAIT_FAILED)
- {
- printf ("Wait for event failed\n");
- queue->running--;
- ExitThread (0);
- }
- EnterCriticalSection (&queue->queuelock);
- }
- if (!queue->active)
- {
- queue->running--;
- LeaveCriticalSection (&queue->queuelock);
- ExitThread (0);
- }
- /* not needed, but it is efficient */
- request =
- (class queue_request *) InterlockedExchangePointer (&queue->request,
- queue->request->
- next);
- LeaveCriticalSection (&queue->queuelock);
- request->process ();
- delete request;
+ system_printf (("failed to create the request queue semaphore, "
+ "error = %lu"),
+ GetLastError ());
+ abort ();
}
- queue->running--;
- ExitThread (0);
+
+ create_workers (initial_workers);
}
-void
-threaded_queue::create_workers ()
+threaded_queue::~threaded_queue ()
{
- InitializeCriticalSection (&queuelock);
- if ((event = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL)
+ if (_running)
+ stop ();
+
+ debug_printf ("deleting all pending queue requests");
+ queue_request *reqptr = _requests_head;
+ while (reqptr)
{
- printf ("Failed to create event queue (%lu), terminating\n",
- GetLastError ());
- exit (1);
+ queue_request *const ptr = reqptr;
+ reqptr = reqptr->_next;
+ safe_delete (ptr);
}
- active = true;
- /* FIXME: Use a stack pair and create threads on the fly whenever
- * we have to to service a request.
- */
- for (unsigned int i = 0; i < initial_workers; i++)
+ DeleteCriticalSection (&_queue_lock);
+ if (_requests_sem)
+ (void) CloseHandle (_requests_sem);
+}
+
+/* FIXME: return success or failure rather than quitting */
+void
+threaded_queue::add_submission_loop (queue_submission_loop *const submitter)
+{
+ assert (this);
+ assert (submitter);
+ assert (submitter->_queue == this);
+ assert (!submitter->_next);
+
+ submitter->_next =
+ TInterlockedExchangePointer (&_submitters_head, submitter);
+
+ if (_running)
+ submitter->start ();
+}
+
+bool
+threaded_queue::start ()
+{
+ EnterCriticalSection (&_queue_lock);
+ const bool was_running = _running;
+ _running = true;
+ queue_submission_loop *loopptr = _submitters_head;
+ LeaveCriticalSection (&_queue_lock);
+
+ if (!was_running)
{
- HANDLE hThread;
- DWORD tid;
- hThread = CreateThread (NULL, 0, worker_function, this, 0, &tid);
- if (hThread == NULL)
+ debug_printf ("starting all queue submission loops");
+
+ while (loopptr)
{
- printf ("Failed to create thread (%lu), terminating\n",
- GetLastError ());
- exit (1);
+ queue_submission_loop *const ptr = loopptr;
+ loopptr = loopptr->_next;
+ ptr->start ();
}
- CloseHandle (hThread);
- running++;
}
+
+ return was_running;
}
-void
-threaded_queue::cleanup ()
+bool
+threaded_queue::stop ()
{
- /* harvest the threads */
- active = false;
- /* kill the request processing loops */
- queue_process_param *reqloop;
- /* make sure we don't race with a incoming request creation */
- EnterCriticalSection (&queuelock);
- reqloop =
- (queue_process_param *) InterlockedExchangePointer (&process_head, NULL);
- while (reqloop)
+ EnterCriticalSection (&_queue_lock);
+ const bool was_running = _running;
+ _running = false;
+ queue_submission_loop *loopptr = _submitters_head;
+ LeaveCriticalSection (&_queue_lock);
+
+ if (was_running)
{
- queue_process_param *t = reqloop;
- reqloop = reqloop->next;
- delete t;
+ debug_printf ("stopping all queue submission loops");
+ while (loopptr)
+ {
+ queue_submission_loop *const ptr = loopptr;
+ loopptr = loopptr->_next;
+ ptr->stop ();
+ }
+
+ ReleaseSemaphore (_requests_sem, _workers_count, NULL);
+ while (_workers_count)
+ {
+ debug_printf (("waiting for worker threads to terminate: "
+ "%lu still running"),
+ _workers_count);
+ Sleep (1000);
+ }
+ debug_printf ("all worker threads have terminated");
}
- LeaveCriticalSection (&queuelock);
- if (!running)
- return;
- printf ("Waiting for current queue threads to terminate\n");
- for (int n = running; n; n--)
- PulseEvent (event);
- while (running)
- sleep (1);
- DeleteCriticalSection (&queuelock);
- CloseHandle (event);
+
+ return was_running;
}
/* FIXME: return success or failure */
void
-threaded_queue::add (queue_request * therequest)
+threaded_queue::add (queue_request *const therequest)
{
- /* safe to not "Try" because workers don't hog this, they wait on the event
- */
- EnterCriticalSection (&queuelock);
- if (!running)
+ assert (this);
+ assert (therequest);
+ assert (!therequest->_next);
+
+ if (!_workers_count)
{
- printf ("No worker threads to handle request!\n");
+ system_printf ("warning: no worker threads to handle request!");
+ // FIXME: And then what?
}
- if (!request)
- request = therequest;
+
+ EnterCriticalSection (&_queue_lock);
+ if (!_requests_head)
+ _requests_head = therequest;
else
{
- /* add to the queue end. */
- queue_request *listrequest = request;
- while (listrequest->next)
- listrequest = listrequest->next;
- listrequest->next = therequest;
+ /* Add to the queue end. */
+ queue_request *reqptr = _requests_head;
+ for (; reqptr->_next; reqptr = reqptr->_next)
+ {}
+ assert (reqptr);
+ assert (!reqptr->_next);
+ reqptr->_next = therequest;
}
- PulseEvent (event);
- LeaveCriticalSection (&queuelock);
+
+ _requests_count += 1;
+ assert (_requests_count > 0);
+ LeaveCriticalSection (&_queue_lock);
+
+ (void) ReleaseSemaphore (_requests_sem, 1, NULL);
}
-/* FIXME: return success or failure rather than quitting */
+/*static*/ DWORD WINAPI
+threaded_queue::start_routine (const LPVOID lpParam)
+{
+ class threaded_queue *const queue = (class threaded_queue *) lpParam;
+ assert (queue);
+
+ queue->worker_loop ();
+
+ const long count = InterlockedDecrement (&queue->_workers_count);
+ assert (count >= 0);
+
+ if (queue->_running)
+ debug_printf ("worker loop has exited; thread about to terminate");
+
+ return 0;
+}
+
+/* Called from the constructor: so no need to be thread-safe until the
+ * worker threads start to be created; thus the interlocked increment
+ * of the `_workers_count' field.
+ */
+
void
-threaded_queue::process_requests (queue_process_param * params,
- threaded_queue_thread_function *
- request_loop)
+threaded_queue::create_workers (const size_t initial_workers)
{
- if (params->start (request_loop, this) == false)
- exit (1);
- params->next =
- (queue_process_param *) InterlockedExchangePointer (&process_head,
- params);
+ assert (initial_workers > 0);
+
+ for (unsigned int i = 0; i != initial_workers; i++)
+ {
+ const long count = InterlockedIncrement (&_workers_count);
+ assert (count > 0);
+
+ DWORD tid;
+ const HANDLE hThread =
+ CreateThread (NULL, 0, start_routine, this, 0, &tid);
+
+ if (!hThread)
+ {
+ system_printf ("failed to create thread, error = %lu",
+ GetLastError ());
+ abort ();
+ }
+
+ (void) CloseHandle (hThread);
+ }
}
-/* queue_process_param */
-/* How does a constructor return an error? */
-queue_process_param::queue_process_param (bool ninterruptible):running (false), shutdown (false),
-interruptible
-(ninterruptible)
+void
+threaded_queue::worker_loop ()
{
- if (!interruptible)
- return;
- debug_printf ("creating an interruptible processing thread\n");
- if ((interrupt = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL)
+ while (true)
{
- printf ("Failed to create interrupt event (%lu), terminating\n",
- GetLastError ());
- exit (1);
+ const DWORD rc = WaitForSingleObject (_requests_sem, INFINITE);
+ if (rc == WAIT_FAILED)
+ {
+ system_printf ("wait for request semaphore failed, error = %lu",
+ GetLastError ());
+ return;
+ }
+ assert (rc == WAIT_OBJECT_0);
+
+ EnterCriticalSection (&_queue_lock);
+ if (!_running)
+ {
+ LeaveCriticalSection (&_queue_lock);
+ return;
+ }
+
+ assert (_requests_head);
+ queue_request *const reqptr = _requests_head;
+ _requests_head = reqptr->_next;
+
+ _requests_count -= 1;
+ assert (_requests_count >= 0);
+ LeaveCriticalSection (&_queue_lock);
+
+ assert (reqptr);
+ reqptr->process ();
+ safe_delete (reqptr);
+ }
+}
+
+/*****************************************************************************/
+
+/* queue_submission_loop */
+
+queue_submission_loop::queue_submission_loop (threaded_queue *const queue,
+ const bool ninterruptible)
+ : _running (false),
+ _interrupt_event (NULL),
+ _queue (queue),
+ _interruptible (ninterruptible),
+ _hThread (NULL),
+ _tid (0),
+ _next (NULL)
+{
+ if (_interruptible)
+ {
+ // verbose: debug_printf ("creating an interruptible processing thread");
+
+ _interrupt_event = CreateEvent (NULL, // SECURITY_ATTRIBUTES
+ FALSE, // Auto-reset
+ FALSE, // Initially non-signalled
+ NULL); // Anonymous
+
+ if (!_interrupt_event)
+ {
+ system_printf ("failed to create interrupt event, error = %lu",
+ GetLastError ());
+ abort ();
+ }
}
}
-queue_process_param::~queue_process_param ()
+queue_submission_loop::~queue_submission_loop ()
{
- if (running)
+ if (_running)
stop ();
- if (!interruptible)
- return;
- CloseHandle (interrupt);
+ if (_interrupt_event)
+ (void) CloseHandle (_interrupt_event);
+ if (_hThread)
+ (void) CloseHandle (_hThread);
}
bool
- queue_process_param::start (threaded_queue_thread_function * request_loop,
- threaded_queue * thequeue)
+queue_submission_loop::start ()
{
- queue = thequeue;
- hThread = CreateThread (NULL, 0, request_loop, this, 0, &tid);
- if (hThread)
+ assert (this);
+ assert (!_hThread);
+
+ const bool was_running = _running;
+
+ if (!was_running)
{
- running = true;
- return true;
+ _running = true;
+
+ _hThread = CreateThread (NULL, 0, start_routine, this, 0, &_tid);
+ if (!_hThread)
+ {
+ system_printf ("failed to create thread, error = %lu",
+ GetLastError ());
+ abort ();
+ }
}
- printf ("Failed to create thread (%lu), terminating\n", GetLastError ());
- return false;
+
+ return was_running;
}
-void
-queue_process_param::stop ()
+bool
+queue_submission_loop::stop ()
{
- if (interruptible)
+ assert (this);
+ assert (_hThread && _hThread != INVALID_HANDLE_VALUE);
+
+ const bool was_running = _running;
+
+ if (_running)
{
- InterlockedExchange (&shutdown, true);
- PulseEvent (interrupt);
- /* Wait up to 50 ms for the thread to exit. If it doesn't _and_ we get
- * scheduled again, we print an error and exit. We _should_ loop or
- * try resignalling. We don't want to hand here though...
- */
- int n = 5;
- while (n-- && WaitForSingleObject (hThread, 1000) == WAIT_TIMEOUT);
- if (!n)
+ _running = false;
+
+ if (_interruptible)
{
- printf ("Process thread didn't shutdown cleanly after 200ms!\n");
- exit (1);
+ assert (_interrupt_event
+ && _interrupt_event != INVALID_HANDLE_VALUE);
+
+ SetEvent (_interrupt_event);
+
+ if (WaitForSingleObject (_hThread, 1000) == WAIT_TIMEOUT)
+ {
+ system_printf (("request loop thread %lu failed to shutdown "
+ "when asked politely: about to get heavy"),
+ _tid);
+
+ if (!TerminateThread (_hThread, 0))
+ {
+ system_printf (("failed to kill request loop thread %lu"
+ ", error = %lu"),
+ _tid, GetLastError ());
+ abort ();
+ }
+ }
}
else
- running = false;
- }
- else
- {
- printf ("killing request loop thread %ld\n", tid);
- int rc;
- if (!(rc = TerminateThread (hThread, 0)))
{
- printf ("error shutting down request loop worker thread\n");
+ // FIXME: could wait to see if the request loop notices that
+ // the submission loop is no longer running and shuts down
+ // voluntarily.
+
+ debug_printf ("killing request loop thread %lu", _tid);
+
+ if (!TerminateThread (_hThread, 0))
+ system_printf (("failed to kill request loop thread %lu"
+ ", error = %lu"),
+ _tid, GetLastError ());
}
- running = false;
}
- CloseHandle (hThread);
-}
-/* queue_request */
-queue_request::queue_request ():next (NULL)
-{
+ return was_running;
}
-void
-queue_request::process (void)
+/*static*/ DWORD WINAPI
+queue_submission_loop::start_routine (const LPVOID lpParam)
{
- printf ("\n**********************************************\n"
- "Oh no! we've hit the base queue_request process() function, and this indicates a coding\n"
- "fault !!!\n" "***********************************************\n");
+ class queue_submission_loop *const submission_loop =
+ (class queue_submission_loop *) lpParam;
+ assert (submission_loop);
+
+ submission_loop->request_loop ();
+
+ debug_printf ("submission loop has exited; thread about to terminate");
+
+ submission_loop->stop ();
+
+ return 0;
}
+
+/*****************************************************************************/
diff --git a/winsup/cygserver/woutsup.h b/winsup/cygserver/woutsup.h
new file mode 100644
index 000000000..c048f1c19
--- /dev/null
+++ b/winsup/cygserver/woutsup.h
@@ -0,0 +1,110 @@
+/* woutsup.h: for Cygwin code compiled outside the DLL (i.e. cygserver).
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef __INSIDE_CYGWIN__
+#error "woutsup.h is not for code being compiled inside the dll"
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#if _WIN32_WINNT < 0x0500
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#define _WINGDI_H
+#define _WINUSER_H
+#define _WINNLS_H
+#define _WINVER_H
+#define _WINNETWK_H
+#define _WINSVC_H
+#include <windows.h>
+#include <wincrypt.h>
+#include <lmcons.h>
+#undef _WINGDI_H
+#undef _WINUSER_H
+#undef _WINNLS_H
+#undef _WINVER_H
+#undef _WINNETWK_H
+#undef _WINSVC_H
+
+#include "wincap.h"
+
+/* The one function we use from winuser.h most of the time */
+extern "C" DWORD WINAPI GetLastError (void);
+
+extern int cygserver_running;
+
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
+#define NEW_MACRO_VARARGS
+#endif
+
+/*
+ * A reproduction of the <sys/strace.h> macros. This allows code that
+ * runs both inside and outside the Cygwin DLL to use the same macros
+ * for logging messages.
+ */
+
+extern "C" void __cygserver__printf (const char *, const char *, ...);
+
+#ifdef NEW_MACRO_VARARGS
+
+#define system_printf(...) \
+ do \
+ { \
+ __cygserver__printf (__PRETTY_FUNCTION__, __VA_ARGS__); \
+ } while (false)
+
+#define __noop_printf(...) do {;} while (false)
+
+#else /* !NEW_MACRO_VARARGS */
+
+#define system_printf(args...) \
+ do \
+ { \
+ __cygserver__printf (__PRETTY_FUNCTION__, ## args); \
+ } while (false)
+
+#define __noop_printf(args...) do {;} while (false)
+
+#endif /* !NEW_MACRO_VARARGS */
+
+#ifdef DEBUGGING
+#define debug_printf system_printf
+#define paranoid_printf system_printf
+#define select_printf system_printf
+#define sigproc_printf system_printf
+#define syscall_printf system_printf
+#define termios_printf system_printf
+#define wm_printf system_printf
+#define minimal_printf system_printf
+#define malloc_printf system_printf
+#define thread_printf system_printf
+#else
+#define debug_printf __noop_printf
+#define paranoid_printf __noop_printf
+#define select_printf __noop_printf
+#define sigproc_printf __noop_printf
+#define syscall_printf __noop_printf
+#define termios_printf __noop_printf
+#define wm_printf __noop_printf
+#define minimal_printf __noop_printf
+#define malloc_printf __noop_printf
+#define thread_printf __noop_printf
+#endif
+
+#include "safe_memory.h"
diff --git a/winsup/cygwin/CYGWIN_LICENSE b/winsup/cygwin/CYGWIN_LICENSE
index f10b01f56..53369a297 100644
--- a/winsup/cygwin/CYGWIN_LICENSE
+++ b/winsup/cygwin/CYGWIN_LICENSE
@@ -16,7 +16,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*** NOTE ***
-In accordance with section 10 of the GPL, Cygnus permits programs whose
+In accordance with section 10 of the GPL, Red Hat permits programs whose
sources are distributed under a license that complies with the Open
Source definition to be linked with libcygwin.a without libcygwin.a
itself causing the resulting program to be covered by the GNU GPL.
@@ -31,16 +31,8 @@ for the cygwin DLL.
See http://www.opensource.org/osd.html for the precise Open Source
Definition referenced above.
-If you have questions about any of the above or would like to arrange
-for other licensing terms, please contact Cygnus using the information
-given below:
+Red Hat sells a special Cygwin License for customers who are unable to
+provide their application in open source code form. For more
+information, please see: http://www.redhat.com/software/tools/cygwin/,
+or call 866-2REDHAT ext. 3007
- Cygnus Solutions
- 1325 Chesapeake Terrace
- Sunnyvale, CA 94089
- USA
-
- +1 408 542 9600
- hotline: +1 408 542 9601
- email: info@cygnus.com
- fax: +1 408 542 9699
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 59a42075d..eaf19dff0 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,4328 +1,5267 @@
-Mon Oct 8 7:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * cygserver.cc (server_request::process): Rename client_request_shm_get to
- client_request_shm.
- * cygserver_process.cc (process_cache::add): Rename to add_task.
- Use process_cleanup instead of process_request.
- (process_cache::remove_process): New method.
- (process::process): Initialize new members.
- (process::~process): New member.
- (process::cleanup): New method.
- (process::add_cleanup_routine): New method.
- (process_request::process): Rename to process_cleanup.
- Call the process object's cleanup method and then delete it.
- (process_process_param::request_loop): Remove the signalling process.
- * cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm.
- (client_request_shm_get::serve): Handle attach request counting.
- * cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm.
- (class shm_cleanup): New class.
- * shm.cc: Globally rename client_request_shm_get to client_request_shm.
- (client_request_shm::client_request_shm): New constructor for attach requests.
- (shmat): Use it.
- * include/cygwin/cygserver_process.h (class process_request): Rename to
- process_cleanup.
- (class cleanup_routine): New class.
- (class process): New members and methods to allow calling back when the process
- terminates.
-
-Thu Oct 4 14:12:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * cygserver.cc (request_loop): Make static.
- (main): Use new cache constructor syntax.
- Start cache worker threads.
- Cleanup the cache at shutdown.
- * cygserver_process.cc: Run indent.
- (process_cache::process_cache): Add a trigger to use when adding a process.
- (process_cache::process): Move process_entry to process.
- Insert at the end of the list.
- Trigger the request loop when new process's inserted.
- (process_cache::process_requests): Do it.
- (process_cache::add): New method.
- (process_cache::handle_snapshot): New method.
- (process::process): Merge in the process_entry fields.
- (process::handle): Make a stub function.
- (process::exit_code): New method.
- (process_request::process): New method.
- (process_process_param::request_loop): New method.
- * cygserver_shm.cc: New header dependency - threaded_queue.h.
- * threaded_queue.cc (threaded_queue::cleanup): Clearer messages.
- (queue_process_param::stop): Short spinlock on interruptible threads.
- * threaded_queue.h (class threaded_queue): New constructor.
- * include/cygwin/cygserver_process.h (process_request): New class.
- (process_entry): Remove.
- (process): Merge in process_entry.
- (process_cache): Inherit from threaded_queue.
-
-Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * cygserver.cc (class server_process_param): Use new constructor syntax.
- * cygserver_process.cc (process_cache::~process_cache): New function.
- * threaded_queue.cc: Define condition debug_printf.
- Run indent.
- (threaded_queue::cleanup): Move queue_process_param guts to a method.
- (threaded_queue::process_requests): Ditto.
- (queue_process_param::queue_process_param): New method.
- (queue_process_param::~queue_process_param): Ditto.
- (queue_process_param::start): Ditto.
- (queue_process_param::stop): Ditto.
- * threaded_queue.h (class queue_process_param): Add support for
- interruptible request loops.
- * cygwin/include/cygwin/cygserver_process.h (class process_cache): Add
- destructor.
+2002-09-22 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ GNUify non-GNU formatted functions calls throughout.
+
+2002-09-22 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (with_strerr): Remove macro.
+ (server_shmmgr::segment_t::~segment_t): Remove calls to with_strerr.
+ (server_shmmgr::segment_t::attach): Ditto.
+ (server_shmmgr::new_segment): Ditto.
+ * shm.cc (with_strerr): Remove macro.
+ (client_shmmgr::shmdt): Remove calls to with_strerr.
+ (client_shmmgr::attach): Ditto.
+
+2002-09-21 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/sys/ipc.h: Move to "include/cygwin/ipc.h".
+ * include/sys/msg.h: Move to "include/cygwin/msg.h".
+ * include/sys/sem.h: Move to "include/cygwin/sem.h".
+ * include/sys/shm.h: Move to "include/cygwin/shm.h".
+ * include/cygwin/ipc.h: New file.
+ * include/cygwin/msg.h: Ditto.
+ * include/cygwin/sem.h: Ditto.
+ * include/cygwin/shm.h: Ditto.
+ * cygserver_shm.h: Update includes.
+ * msg.cc: Ditto.
+ * sem.cc: Ditto.
+
+2002-09-21 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * safe_memory.h (safe_delete): Make a templated function.
+ * cygserver.cc (~server_request): Update use of safe_delete.
+ (main): Ditto.
+ * cygserver_client.cc (client_request::handle_request): Ditto.
+ (client_request::make_request): Ditto.
+ * cygserver_process.cc (~process_cleanup): Ditto.
+ (process::remove): Ditto.
+ (process::cleanup): Ditto.
+ (process_cache::process): Ditto.
+ * cygserver_shm.cc (server_shmmgr::segment_t::detach): Ditto.
+ (server_shmmgr::delete_segment): Ditto.
+ * shm.cc (client_shmmgr::shmdt): Ditto.
+ * threaded_queue.cc (~threaded_queue): Ditto.
+ (threaded_queue::worker_loop): Ditto.
+
+2002-08-29 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * safe_memory.h: Replace #include <new> with an explicit
+ definition of the placement new operator.
+ (safe_delete): Remove unnecessary ## operator.
+
+2002-07-28 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (class server_shmmgr): Remove `cleanup_t'
+ friend declaration.
+ (cleanup_t::cleanup_t): Use the segment's shmid as the key rather
+ than the segment pointer itself.
+ (cleanup_t::segptr): Remove method.
+ (cleanup_t::shmid): New method.
+ (cleanup_t::cleanup): Update for new key value.
+ (server_shmmgr::find (segment_t *)): Remove method.
+ * include/cygwin/cygserver_process.h (cleanup_routine::key): Make
+ method const.
+
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver_process.h
+ (cleanup_routine::_key): New field.
+ (cleanup_routine::cleanup_routine): Initialise new field with new
+ argument.
+ (cleanup_routine::operator==): New method.
+ (cleanup_routine::key): New method.
+ (cleanup_routine::cleanup): Make argument non-const.
+ (process::is_active): New method.
+ (process::remove): Ditto.
+ (process::check_exit_code): Rename method.
+ * cygserver_process.cc (process::add): Reorganize code.
+ (process::remove): New method.
+ (process::check_exit_code): Rename method.
+ (process::cleanup): Use new `process::is_active' method.
+ (process_cache::process): Ditto.
+ (process_cache::sync_wait_array): Ditto.
+ (process_cache::check_and_remove_process): Ditto.
+ * cygserver_shm.cc (server_shmmgr): Make `cleanup_t' a friend.
+ (segment_t::detach): Make argument non-const. Remove cleanup
+ object from client if appropriate.
+ (cleanup_t::_segptr): Remove field.
+ (cleanup_t::cleanup_t): Initialise parent explicitly. Remove
+ field.
+ (cleanup_t::segptr): New method.
+ (cleanup_t::cleanup): Add error checking and reporting.
+ (server_shmmgr::shmdt): Make argument non-const.
+ (server_shmmgr::find (segment_t *)): New method.
-Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
- * cygserver_client.cc: New flag allow_daemon to disable the daemon completely.
- (cygserver_request): Check it.
- (cygserver_init): Ditto.
- * environ.cc (parse_thing): Add (no)daemon option.
+ * cygserver.cc (client_request_shutdown::client_request_shutdown):
+ Comment out verbose tracing statement.
+ * cygserver_client.cc
+ (client_request_get_version::client_request_get_version): Ditto.
+ (client_request_attach_tty::client_request_attach_tty): Ditto.
+ * cygserver_shm.cc (client_request_shm::client_request_shm):
+ Ditto.
-Tue Oct 2 23:00:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
- * shm.cc: Update to handle include changes from HEAD.
+ * cygserver_transport_pipes.cc (transport_layer_pipes::listen):
+ Set `_is_listening_endpoint' appropriately.
-Tue Oct 2 16:06:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
- * Makefile.in: Remove cygserver_shm.o from cygwin1.dll.
- Rename cygserver_shm_outside.o to cygserver_shm.o.
- * cygserver.cc (server_request::process): Use the new client_request
- constructor.
- * cygserver_client.cc: Remove the #ifdef's stubs for the server method
- within cygwin.
- (client_request_attach_tty::client_request_attach_tty): Use the new
- client_request constructor.
- (client_request_shutdown::client_request_shutdown): Ditto.
- (client_request::client_request): Ditto.
- * cygserver_shm.cc (client_request_shm_get::serve): Remove the
- #ifdef'd stub for in-cygwin builds.
- (client_request_shm_get::client_request_shm_get): Use the new
- client_request constructor, and remove the in-cygwin variants.
- * cygserver_shm.h (class client_request_shm_get): #ifndef test the
- serve method - it's only used in cygserver.
- * shm.cc (client_request_shm_get::client_request_shm_get): New function.
- * include/cygwin/cygserver.h (request_header): New constructor.
- (class client_request): Use it.
- New constructor accepting the header size.
- #ifndef test the server method - it's only used within cygserver.
- (client_request_get_version): #ifdef test the server method.
- (client_request_shutdown): Ditto.
- (client_request_attach_tty): Ditto.
-
-Tue Oct 2 9:57:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * Makefile.in: add threaded_queue.o to cygserver.exe.
- * cygserver.cc: Include threaded_queue.h
- (class server_request): Inherit from queue_request.
- (class server_process_param): Inherit from queue_process_param.
- (class server_request_queue): Inherit from threaded_queue.
- (request_loop): Adjust for new types.
- (server_request_queue::process_requests): Remove guts to
- threaded_queue::process_requests.
- (server_request::server_request): Adjust for new types.
- (worker_function): Delete.
- (server_request_queue::create_workers): Delete.
- (server_request_queue::cleanup): Delete.
- (server_request_queue::add): Move guts to threaded_queue::add.
- * threaded_queue.cc: New file.
- * threaded_queue.h: New file.
-
-Mon Oct 1 12:38:00 2001 Robert Collins <rbtcollins@hotmail.com>
+ * include/cygwin/cygserver_transport.h
+ (transport_layer_base::listen): Change return type.
+ (transport_layer_base::connect): Ditto.
+ * include/cygwin/cygserver_transport_pipes.h
+ (transport_layer_pipes::listen): Change return type.
+ (transport_layer_pipes::connect): Ditto.
+ (transport_layer_pipes::_sec_none_nih): Remove unused field.
+ (transport_layer_pipes::_is_listening_endpoint): New field.
+ * cygserver_transport_pipes.cc: Synchronize with sockets code.
+ (transport_layer_pipes::transport_layer_pipes): Initialise new
+ field. Separate out asserts.
+ (transport_layer_pipes::listen): Change return type. Add asserts.
+ (transport_layer_pipes::accept): Add asserts.
+ (transport_layer_pipes::read): Change conditional to an assert.
+ Add assert.
+ (transport_layer_pipes::write): Ditto.
+ (transport_layer_pipes::connect): Change return type. Change
+ conditional to an assert. Add asserts. Rationalize error code
+ slightly.
+ (transport_layer_pipes::impersonate_client): Add asserts.
+ * include/cygwin/cygserver_transport_sockets.h
+ (transport_layer_sockets::listen): Change return type.
+ (transport_layer_sockets::connect): Ditto.
+ (transport_layer_sockets::_addr): Change type of field.
+ (transport_layer_sockets::_addr_len): Ditto.
+ (transport_layer_sockets::_is_accepted_endpoint): New field.
+ (transport_layer_sockets::_is_listening_endpoint): Ditto.
+ * cygserver_transport_sockets.cc
+ (MAX_CONNECT_RETRY): New constant.
+ (transport_layer_sockets::transport_layer_sockets): Initialise new
+ fields. Only initialise the socket address where necessary.
+ (transport_layer_sockets::listen): Change return type. Rewrite.
+ (transport_layer_sockets::accept): Add asserts. Add tracing
+ statements. Use a local variable to hold the accepted address.
+ (transport_layer_sockets::close): Add tracing statements. Unlink
+ the UNIX domain socket file as appropriate. Close the socket
+ cleanly.
+ (transport_layer_sockets::read): Rewrite method.
+ (transport_layer_sockets::write): Ditto.
+ (transport_layer_sockets::connect): Change return type. Rewrite.
+ * cygserver.cc (server_submission_loop::request_loop): Run the
+ listening thread at high priority with special handling for
+ shutdown.
+ (main): Print the request error code rather than errno in shutdown
+ request code. Install signal handlers with sigaction(2) to avoid
+ setting SA_RESTART. Check value of the listen method call, now it
+ has one.
+ * cygserver_client.cc (client_request::make_request): Check new
+ return value on connect method call.
+
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver_transport_pipes.h
+ (cygserver_transport_pipes::_sd): Rename field.
+ (cygserver_transport_pipes::_sec_none_nih): Ditto.
+ (cygserver_transport_pipes::_sec_all_nih): Ditto.
+ (cygserver_transport_pipes::_pipe_name): Ditto.
+ (cygserver_transport_pipes::_hPipe): Ditto.
+ (cygserver_transport_pipes::_is_accepted_endpoint): Ditto.
+ * cygserver_transport_pipes.cc
+ (transport_layer_pipes::transport_layer_pipes): Rename fields.
+ (transport_layer_pipes::init_security): Ditto.
+ (transport_layer_pipes::listen): Ditto.
+ (transport_layer_pipes::accept): Ditto.
+ (transport_layer_pipes::close): Ditto.
+ (transport_layer_pipes::read): Ditto.
+ (transport_layer_pipes::write): Ditto.
+ (transport_layer_pipes::connect): Ditto.
+ (transport_layer_pipes::impersonate_client): Ditto.
+ (transport_layer_pipes::revert_to_self): Ditto.
+ * include/cygwin/cygserver_transport_sockets.h
+ (cygserver_transport_sockets::_fd): Rename field.
+ (cygserver_transport_sockets::_addr): Ditto.
+ (cygserver_transport_sockets::_addr_len): Ditto.
+ * cygserver_transport_sockets.cc
+ (transport_layer_sockets::transport_layer_sockets): Rename fields.
+ (transport_layer_sockets::listen): Ditto.
+ (transport_layer_sockets::accept): Ditto.
+ (transport_layer_sockets::close): Ditto.
+ (transport_layer_sockets::read): Ditto.
+ (transport_layer_sockets::write): Ditto.
+ (transport_layer_sockets::connect): Ditto.
+
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (with_strerr): Fix use of %p format.
+ * shm.cc (client_shmmgr::shmat): Ditto.
+ (client_shmmgr::shmctl): Ditto.
+ (client_shmmgr::shmdt): Ditto.
+ (client_shmmgr::attach): Ditto.
+
+2002-07-14 Christopher Faylor <cgf@redhat.com>
+
+ * woutsup.h (system_printf): Remove extraneous semicolon from macro
+ definition.
- * cygserver.cc (client_request::serve): New function.
- * cygserver_process.cc: Inlude <pthread.h> for pthread_once.
- (process_cache::process_cache): Initialise a crtiical section for write access.
- (process_cache::process): Use the critical section. Also add missing entries to
- the cache.
- (do_process_init): New function to initalise class process static variables.
- (process::process): Ensure that the process access critical section is initialised.
- (process::handle): Close the handle of old process's when they have terminated
- and we are returning the handle for a process with the same pid.
- * cygserver_shm.cc: Run indent.
- Include cygserver_process.h to allow process cache functionality.
- (client_request_shm_get::serve): New parameter for process cache support.
- Use the process cache, not OpenProcess to get a handle to the originating process.
- Fix a handle leak with token_handle.
- * cygserver_shm.h (class client_request_shm_get): Update ::serve for process cache support.
- * cygserver_transport_pipes.cc: Redefine debug_printf to be conditional on DEBUG.
- * include/cygwin/cygserver.h: Do not implement client_request::serve in the header.
- * include/cygwin/cygserver_process.h (class process_cache): Add a write access critical section to prevent races when requests from a multithreaded application arrive.
+2002-07-14 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_transport_pipes.cc
+ (transport_layer_pipes::connect): Use ProtectHandle in DLL code.
+ (transport_layer_pipes::close): Use ForceCloseHandle in DLL code.
+
+2002-07-13 Nicholas Wourms <nwourms@netscape.com>
+
+ * threaded_queue.h (class queue_submission_loop): Correct friend
+ declaration for GCC 3.1.1.
+ * include/cygwin/cygserver_process.h (class process): Ditto.
+ (class process_cache): Ditto.
+
+2002-07-12 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (server_shmmgr::shmdt): Only call
+ delete_segment if the segment exists [sic].
+
+2002-07-12 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * safe_memory.h: Include <new> rather than <new.h> for gcc 3.
+
+2002-07-11 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * safe_memory.h: New file extracted from "woutsup.h".
+ * woutsup.h: Move the "safe" new/delete macros into the new
+ "safe_memory.h" header file and include that here.
+ * cygserver_client.cc: Explicitly include "safe_memory.h" for
+ client-side code.
+ (client_request::make_request): Use the "safe" new/delete macros
+ unconditionally, i.e. use them on the client side as well as on
+ the server side.
+ * cygserver_transport.cc: Explicitly include "safe_memory.h" for
+ client-side code.
+ (create_server_transport): Use the "safe" new/delete macros
+ unconditionally, i.e. use them on the client side as well as on
+ the server side.
+ * shm.cc: Include "safe_memory.h".
+ (client_shmmgr::instance): Use the "safe" new/delete macros.
+ (client_shmmgr::shmdt): Ditto.
+ (client_shmmgr::new_segment): Ditto.
+
+2002-07-11 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_process (process::process): Add the client's cygpid
+ and winpid to all tracing statements as appropriate.
+ (process::exit_code): Ditto.
+ (process_cache::check_and_remove_process): Ditto.
+ * cygserver_shm.cc (server_shmmgr::shmat): Ditto.
+ (server_shmmgr::shmdt): Ditto.
+ (server_shmmgr::shmctl): Add a process object argument and remove
+ the explicit cygpid argument. Add the client's cygpid and winpid
+ to all tracing statements as appropriate.
+ (server_shmmgr::shmget): Ditto.
+ (client_request_shm::serve): Update for the new signature of the
+ shmctl and shmget methods.
+
+2002-07-11 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc (client_request_shutdown::serve): Don't set the
+ shutdown flag directly, but send a SIGINT, as the signal handler
+ sets the flag and the signal breaks the pause(2) in the main loop.
+ (print_usage): Add new options.
+ (main): Add new --cleanup-threads and --request-threads options to
+ set the number of threads used by the daemon. Use pause(2) rather
+ the win32 Sleep in the main loop.
+ * shm.cc (shmat): Add sigframe.
+ (shmctl): Ditto.
+ (shmdt): Ditto.
+ (shmget): Ditto.
+
+2002-07-11 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc: Automatically detach processes from any
+ segments they are attached to at exit.
+ (class server_shmmgr::attach_t): New class.
+ (server_shmmgr::segment_t::IS_DELETED): Rename and make private.
+ (server_shmmgr::segment_t::_sequence): Make private.
+ (server_shmmgr::segment_t::_flg): Ditto.
+ (server_shmmgr::segment_t::_hFileMap): Ditto.
+ (server_shmmgr::segment_t::_attach_head): New private field.
+ (server_shmmgr::segment_t::segment_t): Initialise new fields.
+ Make non-inline.
+ (server_shmmgr::segment_t::~segment_t): New method.
+ (server_shmmgr::segment_t::is_deleted): Ditto.
+ (server_shmmgr::segment_t::is_pending_delete): Ditto.
+ (server_shmmgr::segment_t::mark_deleted): Ditto.
+ (server_shmmgr::segment_t::attach): Ditto.
+ (server_shmmgr::segment_t::detach): Ditto.
+ (server_shmmgr::segment_t::find): Ditto.
+ (class server_shmmgr::cleanup_t): New class.
+ (server_shmmgr::_shm_atts): New private field.
+ (server_shmmgr::shmat): Add a process object argument to replace
+ the removed process_cache, cygpid and winpid arguments. Remove
+ the process_cache manipulations. Move body of code to the
+ segment_t::attach method. Increment _shm_atts when required.
+ Update tracing statements.
+ (server_shmmgr::shmdt): Add a process object argument to replace
+ the removed cygpid argument. Move body of code to the
+ segment_t::detach method. Decrement _shm_atts when required.
+ Update tracing statements.
+ (server_shmmgr::shmget): Use the new segment_t::is_deleted method.
+ (server_shmmgr::server_shmmgr): Initialise the new _shm_atts
+ field.
+ (server_shmmgr::delete_segment): Remove the CloseHandle code, as
+ this is now done in the segment_t destructor.
+ (client_request_shm::serve): Look up the client's process object
+ and pass to the server_shmmgr::shmat and server_shmmgr::shmdt
+ methods rather than passing the cache, winpid and cygpid.
+ * cygserver_process.h: Add a cygpid to the process object to make
+ it more useful and then pass process objects rather than winpids
+ where possible.
+ (cleanup_routine::cleanup): Change argument to be a pointer to a
+ process object.
+ (class process): Re-order fields for no discernible reason.
+ (process::_cygpid): New field.
+ (process::process): Add a cygpid argument.
+ (process::winpid): New method.
+ (process::cygpid): Ditto.
+ (process::add): Make public, as it always should have been.
+ (process_cache::process): Add a cygpid argument.
+ * cygserver_process.cc (process::process): Add a cygpid argument
+ and use it to initialise the `_cygpid' field. Re-order
+ initialisers to match new field order.
+ (process::cleanup): Pass `this' rather than just the winpid to
+ cleanup_routine::cleanup.
+ (process_cache::process): Add a cygpid argument and pass it to the
+ process object constructor.
+ * include/sys/shm.h (shmatt_t): Make unsigned as per SUSv3.
+ (shm_info::shm_atts): New field.
+
+2002-07-11 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (class server_shmmgr::segment_t): Add `_'
+ prefix to the names of all fields.
+
+2002-07-10 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * msg.cc: New file of stub functions, no functionality.
+ * sem.cc: Ditto.
+ * shm.cc (client_shmmgr::shmctl): Add support for an out shm_info
+ buffer for the SHM_INFO command.
+ (client_shmmgr::shmget): Use %X to print keys.
+ * include/sys/ipc.h: Comment all fields and values.
+ (IPC_PRIVATE): Change to be non-negative.
+ * include/sys/msg.h: New file with SUSv3 and ipcs(8) interfaces.
+ * include/sys/sem.h: Ditto.
+ * include/sys/shm.h: Comment all fields and values.
+ (struct shm_info): New struct.
+ * cygserver_shm.h (client_request_shm::shminfo): Rename.
+ (client_request_shm::shm_info): New method.
+ (client_request_shm::_parameters.out.hFileMap): Move into union.
+ (client_request_shm::_parameters.out.shminfo): Rename.
+ (client_request_shm::_parameters.out.shm_info): New field.
+ * cygserver_shm.cc (server_shmmgr::_shm_ids): Rename.
+ (server_shmmgr::_shm_tot): New field.
+ (server_shmmgr::shmctl): Rename `out_shminfo' argument. Add
+ `out_shm_info' argument. Fill in the `out_shm_info' argument in
+ the SHM_INFO command.
+ (server_shmmgr::shmget): Check `shmflg' against the mode of
+ existing segments as per Stevens 1990, p. 123.
+ (server_shmmgr::server_shmmgr): Initialise the new `_shm_tot'
+ field.
+ (server_shmmgr::new_segment): Set ENOMEM if CreateFileMapping
+ fails. Pass `size' to new_segment.
+ (server_shmmgr::new_segment): Add size argument and use it to
+ check against and update the new `_shm_tot' field.
+ (server_shmmgr::delete_segment): Update the new `_shm_tot' field.
+ * Makefile.in (DLL_OFILES): Add new DLL object files.
+
+2002-07-09 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_transport_pipes.cc: The main change is to make the
+ client try harder to connect to the server if it's previously
+ connected, and so has good grounds for believing that the server
+ is running.
+ (MAX_WAIT_NAMED_PIPE_RETRY): Change to be an enumerator.
+ (WAIT_NAMED_PIPE_TIMEOUT): Ditto.
+ (transport_layer_pipes::accept): Use interlocked operators on
+ `pipe_instance'.
+ (transport_layer_pipes::close): Rearrange so that FlushFileBuffers
+ and DisconnectNamedPipe are only called for accepted endpoints.
+ Use interlocked operators on `pipe_instance'.
+ (transport_layer_pipes::read): Use set_errno where required.
+ (transport_layer_pipes::write): Ditto.
+ (transport_layer_pipes::connect): Add local static variable
+ `assume_cygserver'. Set it if a connection is made to cygserver,
+ clear it if a connection is not made even after retrying. If set,
+ ignore all errors from CreateFile and retry the connection. Catch
+ the situation where WaitNamedPipe fails to wait [sic] and add a
+ `Sleep (0)' so that the server gets a chance to run.
+
+2002-07-03 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * dcrt0.cc: Only check for cygserver if and when required.
+ (dll_crt0_1): Remove call to `cygserver_init ()'.
+ * fhandler_tty.cc (fhandler_tty_slave::open): Change the cygserver
+ logic to allow for the fact that `cygserver_init ()' may not yet
+ have been called.
+ (fhandler_tty_slave::cygserver_attach_tty): Tweak the cygserver
+ request logic to conform to the practice elsewhere in the code.
+ * tty.cc (tty::common_init): Add an explicit call to
+ `cygserver_init ()' if it hasn't already been called.
+ * include/cygwin/cygserver.h (CYGSERVER_UNAVAIL): Rename from
+ `CYGSERVER_DEAD'.
+ (client_request_get_version::check_version): Make available in
+ cygserver as well the DLL.
+ (check_cygserver_available): Ditto. Remove `check_version_too'
+ argument.
+ (cygserver_init): Ditto. And likewise.
+ * cygserver_client.cc (client_request_get_version::check_version):
+ Make available in cygserver as well the DLL.
+ (client_request::make_request): This may now be called without
+ `cygserver_init ()' having been called first. Detect this and
+ call it as required. Add tracing.
+ (check_cygserver_available): Make available in cygserver as well
+ the DLL. Remove `check_version_too' argument and always check the
+ version information. And since this is called from within
+ `cygserver_init ()', force `cygserver_running' before calling
+ `client_request::make_request ()'.
+ (cygserver_init): Make available in cygserver as well the DLL.
+ Remove `check_version_too' argument.
+
+2002-07-03 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc: Implement the ipcs(8) interfaces, IPC_INFO,
+ SHM_STAT and SHM_INFO.
+ (server_shmmgr::segment_t::sequence): New static field.
+ (server_shmmgr::segment_t::key): Remove field, use the new
+ ds.shm_perm.key field instead.
+ (server_shmmgr::segment_t::shmid): Remove field.
+ (server_shmmgr::segment_t::intid): New field.
+ (server_shmmgr::segment_t::segment_t): Use the `key' argument to
+ initialise `ds.shm_perm.key'. Change from using `shmid' to
+ `intid'.
+ (server_shmmgr::_shmseg_cnt): Renamed from `_shmid_cnt'.
+ (server_shmmgr::_intid_max): Renamed from `_shmid_max.
+ (server_shmmgr::shmat): Move the out arguments to the start of the
+ argument list. Rename the `pid' argument as `cygpid'. Add
+ tracing. Pass an intid to `find ()', not a shmid.
+ (server_shmmgr::shmctl): Add separate out arguments. Rename the
+ `pid' argument as `cygpid'. Add support for the ipcs(8)
+ interfaces. Add tracing. Pass an intid to `find ()', not a
+ shmid.
+ (server_shmmgr::shmdt): Rename the `pid' argument as `cygpid'.
+ Add tracing. Pass an intid to `find ()', not a shmid.
+ (server_shmmgr::shmget): Add a separate out arguments. Rename the
+ `pid' argument as `cygpid'. Add tracing.
+ (server_shmmgr::server_shmmgr): Update for new field names.
+ (server_shmmgr::find_by_key): Update for the new `ds.shm_perm.key'
+ field.
+ (server_shmmgr::find): Update to use the new `segment_t::intid'
+ field.
+ (server_shmmgr::new_segment): Rename the `pid' argument as
+ `cygpid'. Check that the requested size is within bounds. Handle
+ new error result from `new_segment (key, HANDLE)'.
+ (server_shmmgr::new_segment): Work with intids, not shmids. Check
+ that the new intid is within bounds. Update for new field names.
+ (server_shmmgr::delete_segment): Pass an intid to `find ()', not a
+ shmid. Update for new field names.
+ (client_request_shm::serve): Check that the incoming message
+ length is the size of the `_parameters.in' struct, not of the
+ whole in/out parameter union. Likewise, set the outgoing message
+ length to the size of the `_parameters.out' struct. Update for
+ the new server_shmmgr interfaces.
+ * include/sys/ipc.h (ipc_perm::key): New field.
+ * include/sys/shm.h (SHM_INFO): New constant.
+ * cygserver_ipc.h (IPCMNI): New constant.
+ (ipc_int2ext): Add `sequence' argument and munge this into the
+ external ipc id.
+ (ipc_ext2int_subsys): Unmunge the sequence number from the
+ external ipc id.
+ (ipc_ext2int): Ditto.
+ (ipc_inc_id): Remove.
+ (ipc_dec_id): Remove.
+ * cygserver_shm.h (SHMMAX): New constant.
+ (SHMMIN): Ditto.
+ (SHMMNI): Ditto.
+ (SHMSEG): Ditto.
+ (SHMALL): Ditto.
+ (client_request_shm::_parameters): Re-arrange as a union of two
+ separate structs, one for in arguments, the other for out.
+ (client_request_shm::shmid): Update for the new parameter layout.
+ (client_request_shm::ds): Ditto.
+ (client_request_shm::info): New method.
+ * shm.cc (client_shmmgr::_shmat_cnt): New static field.
+ (client_shmmgr::shmat): Add locking. Add tracing.
+ (client_shmmgr::shmctl): Update for ipcs(8) commands. Add
+ tracing. Add more argument checking.
+ (client_shmmgr::shmdt): Add locking. Add tracing. Update the new
+ `_shmat_cnt' field.
+ (client_shmmgr::shmget): Add tracing.
+ (client_shmmgr::fixup_shms_after_fork): Add tracing. Add
+ consistency checking.
+ (client_shmmgr::attach): Add more tracing.
+ (client_shmmgr::new_segment): Update the new `_shmat_cnt' field.
+ (client_request_shm::client_request_shm): Update for the new
+ parameter layout. Set the outgoing message length to the size of
+ the `_parameters.in' struct, not of the whole in/out parameter
+ union.
+
+2002-07-02 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * shm.cc: Remove the use of a static client_shmmgr object.
+ (client_shmmgr::_instance): New static variable.
+ (client_shmmgr::instance): Allocate a new shmmgr on the heap,
+ rather than using a local static object.
+
+2002-07-01 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_transport.cc (create_server_transport): Fix
+ cut-and-paste error.
+
+2002-06-30 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_client.cc (client_request::handle_request): Don't
+ bother with the client request activity marker when compiled with
+ debugging output.
+
+2002-06-30 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_transport_pipes.cc
+ (MAX_WAIT_NAMED_PIPE_RETRY): New constant.
+ (WAIT_NAMED_PIPE_TIMEOUT): Ditto.
+ (transport_layer_pipes::close): The `pipe' field is now either
+ NULL or a valid handle, and it should never have the value
+ `INVALID_HANDLE_VALUE'.
+ (transport_layer_pipes::read): Ditto.
+ (transport_layer_pipes::write): Ditto.
+ (transport_layer_pipes::connect): Ditto.
+ (transport_layer_pipes::impersonate_client): Ditto.
+ (transport_layer_pipes::connect): Ditto. New, but still bogus,
+ retry logic.
+
+2002-06-30 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (server_shmmgr::server_shmmgr): All fields have
+ to be initialized now that the singleton is no longer static.
+
+2002-06-30 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc (server_shmmgr::_instance): New static field.
+ (server_shmmgr::_instance_once): Ditto.
+ (server_shmmgr::initialise_instance): New static method.
+ (server_shmmgr::instance): Use a pthread_once_t rather than
+ relying on a local static variable.
+
+2002-06-30 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * woutsup.h: Remove all uses of the C++ new and delete operators
+ throughout cygserver until they are fully thread-safe.
+ (safe_new0): New macro to replace the C++ new operator.
+ (safe_new): Ditto.
+ (safe_delete): New macro to replace the C++ delete operator.
+ * cygserver_client.cc (client_request::handle_request): Replace
+ all uses of the C++ new and delete operators with the new macros
+ from "woutsup.h".
+ (client_request::make_request): Ditto.
+ * cygserver_process.cc (~process_cleanup): Ditto.
+ (process::cleanup): Ditto.
+ (process_cache::process): Ditto.
+ (process_cache::check_and_remove_process): Ditto.
+ * cygserver_shm.cc (server_shmmgr::new_segment): Ditto.
+ (server_shmmgr::delete_segment): Ditto.
+ * cygserver_transport.cc (create_server_transport): Ditto.
+ * cygserver_transport_pipes.cc
+ (transport_layer_pipes::accept): Ditto.
+ * cygserver_transport_sockets.cc
+ (transport_layer_sockets::accept): Ditto.
+ * threaded_queue.cc (~threaded_queue): Ditto.
+ (threaded_queue::worker_loop): Ditto.
+ (threaded_queue::stop): Replace sleep(3) with win32 Sleep.
+ * cygserver.cc (~server_request): Replace all uses of the C++ new
+ and delete operators with the new macros from "woutsup.h".
+ (server_submission_loop::request_loop): Ditto.
+ (main): Ditto. Replace sleep(3) with win32 Sleep. Replace
+ iostreams with FILEs.
+ (print_usage): Replace iostreams with FILEs.
+ (print_version): Ditto.
+
+2002-06-30 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_transport_sockets.cc
+ (transport_layer_sockets::accept): Rename local variable
+ `accept_fd' to avoid shadowing the `fd' field.
+
+2002-06-29 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygwin_ipc.h: Moved (back) to "include/sys/ipc.h".
+ * cygwin_shm.h: Moved (back) to "include/sys/shm.h".
+ * include/sys/ipc.h: New file.
+ * include/sys/shm.h: New file.
+ * cygserver_shm.h: Update for new header file locations.
+ * ipc.cc: Ditto.
-Sun Sep 30 23:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-06-28 Conrad Scott <conrad.scott@dsl.pipex.com>
- * Makefile.in: Add cygserver_process.o to cygserver.exe.
- * cygserver.cc: Include signal.h and cygwin_version.h.
- Define debug_printf as a macro.
- Define DEBUG to a value.
- (client_request_attach_tty::serve): Add beginning of process cache support.
- Change from #ifdef DEBUG to work with new DEBUG style.
- (client_request_get_version::serve): Add beginning of process cache support.
- (class server_request): New prototype for support of process cache.
- (class queue_process_param): New class to allow request loop threading.
- (class server_request_queue): Add beginning of process cache support.
- Allow request loop threading.
- (request_loop): Thread function for request loops.
- (server_request_queue::process_requests): Initiator for threaded request loops.
- (client_request_shutdown::serve): Add beginning of process cache support.
- (server_request::server_request): Ditto.
- (server_request::process): Use debug_printf. Add beginning of process cache support.
- (server_request_queue::cleanup): Kill off any request loop threads.
- (server_request_queue::add): Add beginning of process cache support.
- (handle_signal): Trigger a shutdown.
- (main): Print out some useful info at startup - version, date time.
- Add process cache support.
- Spawn a separate thread for the transport request loop, thus allowing concurrent
- support for multiple transports.
- * cygserver_client.cc (client_request_get_version::serve): Add process cache support.
- (client_request_attach_tty::serve): Add process cache support.
- (client_request_shutdown::serve): Add process cache support.
- * cygsserver_process.cc: New file with the process cache support.
- * cygserver_shm.cc: Redefine debug_printf to allow conditional output.
- * cygwin.din: Export shmdt().
- * shm.cc: Run indent.
- Update FIXME's.
- (shmdt): New function.
- * include/cygwin/cygserver.h (class client_request): Add process cache support.
+ * cygserver_client.cc (client_request::make_request): Comment out
+ a verbose tracing statement.
+ * cygserver_process.cc (process_cache::sync_wait_array): Fix
+ broken assert.
+ * include/cygwin/cygserver.h (class client_request): Remove excess
+ use of `class' qualifier in declarations.
(class client_request_get_version): Ditto.
(class client_request_shutdown): Ditto.
(class client_request_attach_tty): Ditto.
- * include/cygwin/cygserver_process.h: New header for process cache support.
-Sun Sep 30 8:52:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-06-28 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_ipc.h: New file.
+ * cygserver_shm.h: Re-written from scratch.
+ * cygserver_shm.cc: Ditto.
+ * shm.cc: Ditto.
+
+2002-06-28 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * threaded_queue.h (class queue_request): Re-write.
+ (threaded_queue_thread_function): Remove.
+ (class queue_process_param): Remove.
+ (class threaded_queue): Re-write.
+ (class queue_submission_loop): New version of the old
+ `queue_process_param' class.
+ (TInterlockedExchangePointer): New templated function.
+ (TInterlockedCompareExchangePointer): Ditto.
+ * threaded_queue.cc (worker_function): Remove.
+ (class threaded_queue): Re-write.
+ (class queue_process_param): Remove.
+ (class queue_submission_loop): New version of the old
+ `queue_process_param' class.
+ * include/cygwin/cygserver_process.h (process_cleanup): Re-write.
+ (class process_process_param): Remove.
+ (class cleanup_routine): Re-write.
+ (class process): Re-write.
+ (class process_cache): Re-write.
+ * cygserver_process.cc (process_cleanup): Re-write.
+ (class process_process_param): Remove.
+ (class cleanup_routine): Re-write.
+ (class process): Re-write.
+ (class process_cache): Re-write.
+ * cygserver.cc (request_count): Remove unused variable.
+ (class server_request): Move methods inline.
+ (class server_process_param): Remove.
+ (class server_request_queue): Remove.
+ (request_queue): Move into `main ()' and change type to
+ `threaded_queue'.
+ (request_loop): Remove.
+ (class server_submission_loop): New version of the old
+ `server_process_param' class.
+ (shutdown_server): New variable.
+ (client_request_shutdown::serve): Set `shutdown_server' to trigger
+ shutdown.
+ (handle_signal): Ditto.
+ (main): Install signal handler for SIGINT rather than SIGQUIT.
+ Use new interfaces for the `request_queue' and the `cache'.
+ Create a `server_submission_loop' and add to the `request_queue'.
+ Add check for the `shutdown_server' variable to the main loop.
+ * cygserver_shm.cc (client_request_shm::serve): Release the
+ process object after use.
+
+2002-06-27 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_client.cc (client_request::handle_request): Correct
+ tracing statement.
+ * cygserver_transport_pipes.cc: Remove local definition of
+ FILE_FLAG_FIRST_PIPE_INSTANCE constant.
+ * cygwin_ipc.h: Update copyright notice.
+ * cygwin_shm.h: Ditto.
+ * woutsup.h: Add definition of _WIN32_WINNT.
+
+2002-06-24 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_client (client_request::make_request): Replace my
+ inappropriate use of set_errno () with error_code () throughout.
+
+2002-06-24 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver.h: Add forward declarations of class
+ transport_layer_base and class process_cache to reduce
+ dependencies between header files.
+ * include/cygwin/cygserver_process.h: Add include of
+ "threaded_queue.h".
+ * cygserver.cc: Remove unnecessary cygserver header files.
+ * cygserver_client.cc: Ditto.
+ * cygserver_process.cc: Ditto.
+ * cygserver_shm.cc: Ditto.
+ * cygserver_shm.h: Ditto.
+ * cygserver_transport_pipes.cc: Ditto.
+ * dcrt0.cc: Ditto.
+ * fhandler_tty.cc: Ditto.
+ * tty.cc: Ditto.
- * include/cygwin/cygserver_transport.h: Add copyright header.
- * include/cygwin/cygserver_transport_pipes.h: Ditto.
+2002-06-24 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.h: Replace <sys/shm.h> with "cygwin_shm.h" after
+ merge from HEAD.
+ * cygwin_ipc.h: Update with changes to include/sys/ipc.h lost in
+ merge from HEAD.
+ * cygwin_shm.h: Ditto.
+
+2002-06-21 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc: The tests for a duplicate server instance are now
+ the responsibility of the transport layer.
+ (request_loop): Use new `recoverable' flag in call to
+ `cygserver_transport::accept ()' and shutdown on an unrecoverable
+ error.
+ (main): Never call `cygserver_init ()'. Fake `cygserver_running'
+ just for sending a shutdown request.
+ * cygserver_client.cc (client_request::send): Comment out
+ message-size tracing statements as verbose.
+ (client_request::handle): Ditto.
+ (client_request_get_version::check_version): #ifdef as DLL-only.
+ (check_cygserver_available): Ditto.
+ (cygserver_init): Ditto.
+ * include/cygwin/cygserver.h
+ (client_request_get_version::check_version): #ifdef as DLL-only.
+ (check_cygserver_available): Ditto.
+ (cygserver_init): Ditto.
+ * include/cygwin/cygserver_transport.h
+ (transport_layer_base::impersonate_client): #ifdef as
+ cygserver-only.
+ (transport_layer_base::revert_to_self): Ditto.
+ (transport_layer_base::listen): Ditto.
+ (transport_layer_base::accept): Ditto. Add a `recoverable' out
+ flag for error handling.
* include/cygwin/cygserver_transport_sockets.h: Ditto.
+ * include/cygwin/cygserver_transport_pipes.h: Ditto.
+ (transport_layer_pipes): Change type of the `pipe_name' field.
+ Remove the `inited' field, as unnecessary. Add new
+ `is_accepted_endpoint' field.
+ * include/cygwin/cygserver_transport.cc
+ (transport_layer_base::impersonate_client): #ifdef as
+ cygserver-only.
+ (transport_layer_base::revert_to_self): Ditto.
+ * include/cygwin/cygserver_transport_sockets.cc
+ (transport_layer_sockets::listen): #ifdef as cygserver-only.
+ (transport_layer_sockets::accept): #ifdef as cygserver-only.
+ Analyse any errno from `accept ()' and set `recoverable' as
+ appropriate.
+ * cygserver_transport_pipes.cc: Add local #define of
+ `FILE_FLAG_FIRST_PIPE_INSTANCE'.
+ (pipe_instance_lock_once): New variable.
+ (pipe_instance_lock): Ditto.
+ (pipe_instance): Ditto.
+ (initialise_pipe_instance_lock): New function.
+ (transport_layer_pipes::transport_layer_pipes): Change
+ initialization of `pipe_name'. Initialize `is_accepted_endpoint'
+ as appropriate. Remove use of `inited'.
+ (transport_layer_pipes::impersonate_client): #ifdef as
+ cygserver-only.
+ (transport_layer_pipes::revert_to_self): Ditto.
+ (transport_layer_pipes::listen): Ditto.
+ (transport_layer_pipes::accept): Ditto. Keep track of how often
+ many named pipes have been created, in the `pipe_instance'
+ variable, and pass the `FILE_FLAG_FIRST_PIPE_INSTANCE' flag on the
+ open of the first instance. Analyse the error code from
+ `CreateNamedPipe ()' and set the `recoverable' flag as
+ appropriate.
+ (transport_layer_pipes::close): Update the `pipe_instance' count.
-Sat Sep 29 20:40:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-06-18 Conrad Scott <conrad.scott@dsl.pipex.com>
- * Makefile.in: Add cygserver_transport_sockets.o to DLL_OFILES.
- Add cygserver_transport_sockets_outside.o to cygserver.exe.
- * cygserver.cc: Include new include files.
+ * woutsup.h (cygserver_running): Add declaration.
+ (api_fatal): Eliminate.
+ * include/cygwin/cygserver.h
+ (client_request_get_version::check_version): Change return type to
+ bool.
+ (check_cygserver_available): New function.
+ (cygserver_init): Add check_version_too argument.
+ * cygserver_client.cc (allow_daemon): Make a bool.
+ (client_request_get_version::make_request): See errno on error.
+ Remove special case for CYGSERVER_REQUEST_GET_VERSION; this is now
+ handled in cygserver_init().
+ (client_request_get_version::check_version): Use syscall_printf()
+ instead of api_fatal(). Return true if cygserver version is
+ compatible.
+ (check_cygserver_available): New function; code moved here from
+ cygserver_init().
+ (cygserver_init): Move some code into check_cygserver_available().
+ * cygserver.cc (__set_errno): Copy from debug.cc so that
+ set_errno() can be used when __OUTSIDE_CYGWIN__.
+ (main): Call cygserver_init() to set up cygserver_running and add
+ checks against this to (try and) prevent multiple copies of
+ cygserver running simultaneously. Remember to delete all
+ transport connections so that (one day) the transport classes can
+ tidy up on cygserver shutdown.
+
+2002-06-17 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc (main): Adjust tracing output for a cleaner display
+ when compiled without --enable-debugging.
+ * threaded_queue.cc (threaded_queue::cleanup): Ditto.
+ (queue_process_param::stop): Ditto.
+ * include/cygwin/cygserver.h
+ (client_request::make_request): Make non-virtual.
+ (client_request::send): Make virtual and protected, not private.
+ (client_request_attach_tty::send): New virtual method.
+ * cygserver_client.cc: Use the `msglen()' accessor rather than
+ `_header.msglen' throughout.
+ (client_request_attach_tty::send): New method.
+ (client_request::make_request): Remove the explicit close of
+ `transport' as it is closed on deletion.
+
+2002-06-17 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver.h: Change the client_request classes to
+ give greater encapsulation and to allow variable length requests
+ and replies.
+ (enum cygserver_request_code): Now client_request::request_code_t.
+ (class request_header): Now client_request::header_t. Make a
+ union of the request_code and the error_code. The `cb' field,
+ which was the buffer length, is now the `size_t msglen' field.
+ (struct request_get_version): Now
+ client_request_get_version::request_get_version.
+ (struct request_shutdown): Remove unused type.
+ (struct request_attach_tty): Now
+ client_request_attach_tty::request_attach_tty.
+ (client_request::_buf): Make field const.
+ (client_request::_buflen): New const private field.
+ (client_request::request_code): New accessor.
+ (client_request::error_code): Ditto.
+ (client_request::msglen): Ditto.
+ (client_request::handle_request): New static method.
+ (client_request::make_request): New virtual method.
+ (client_request::handle): New method.
+ (client_request::send): Make private.
+ (client_request_get_version::check_version): New method.
+ (client_request_get_version::serve): Make private.
+ (client_request_get_version::version): Ditto.
+ (client_request_shutdown::serve): Ditto.
+ (client_request_attach_tty::req): Ditto.
+ (client_request_attach_tty::serve): Ditto.
+ (client_request_attach_tty::from_master): Make method const.
+ (client_request_attach_tty::from_master): Ditto.
+ * cygserver_client.cc
+ (client_request_get_version::client_request_get_version): Track
+ changes to the client_request classes.
+ (client_request_attach_tty::client_request_attach_tty): Ditto.
+ (client_request_get_version::check_version): New method to
+ encapsulate code from cygserver_init().
+ (client_request_shutdown::client_request_shutdown): Move into
+ "cygserver.cc".
+ (client_request::send): Track changes to the client_request
+ classes. Add more error checking.
+ (client_request::handle_request): New static method containing the
+ first half of the old server_request::process() code.
+ (client_request::make_request): New method to replace the old
+ cygserver_request() function.
+ (client_request::handle): New method containing the second half of
+ the old server_request::process() code.
+ (cygserver_init): Track changes to the client_request classes. In
+ particular, some code moved into the
+ client_request_get_version::check_version() method.
+ * cygserver.cc (client_request_attach_tty::serve): Track changes
+ to the client_request classes. In particular, only return a reply
+ body if some handles are successfully duplicated for the client.
+ And remove goto's.
+ (client_request_get_version::serve): Track changes to the
+ client_request classes.
+ (client_request_shutdown::serve): Ditto.
+ (class client_request_invalid): Dead, and so young too.
+ (server_request::request_buffer): Remove unnecessary field.
+ (client_request_shutdown::client_request_shutdown): Moved here
+ from "cygserver_client.cc".
+ (server_request::process): Implementation moved into the new
+ client_request::handle_request() and client_request::handle()
+ methods.
+ * cygserver_shm.h (class client_request_shm): Put client- and
+ server-specific interfaces inside #ifdef/#ifndef __INSIDE_CYGWIN__
+ guards.
+ (client_request_shm::serve): Make private.
+ * cygserver_shm.cc
+ (client_request_shm::client_request_shm): Track changes to the
+ client_request classes.
+ (client_request_shm::serve): Ditto
+ * shm.cc (client_request_shm::client_request_shm): Ditto. Use
+ alloc_sd() rather than set_security_attribute() to get access to
+ the SECURITY_DESCRIPTOR length, so that we can use it to set the
+ request body length.
+ (shmat): Track changes to the client_request classes. In
+ particular, allocate client_request objects on the stack rather
+ than on the heap, and use the client_request::make_request()
+ method rather than the old cygserver_request() function.
+ (shmdt): Ditto.
+ (shmctl): Ditto.
+ (shmget): Ditto.
+ * fhandler_tty.cc (fhandler_tty_slave::cygserver_attach_tty): Ditto.
+
+2002-06-17 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver_transport.h
+ (cygserver_transport::read): Change buffer type to void *.
+ (cygserver_transport::write): Ditto.
+ * include/cygwin/cygserver_transport_sockets.h
+ (cygserver_transport_sockets::read): Ditto.
+ (cygserver_transport_sockets::write): Ditto.
+ * include/cygwin/cygserver_transport_pipes.h
+ (cygserver_transport_pipes::read): Ditto.
+ (cygserver_transport_pipes::write): Ditto.
+ * cygserver_transport_sockets.cc
+ (cygserver_transport_sockets::read): Ditto.
+ (cygserver_transport_sockets::write): Ditto.
+ * cygserver_transport_pipes.cc
+ (cygserver_transport_pipes::read): Ditto. Set errno on error, to
+ match behaviour of cygserver_transport_sockets class.
+ (cygserver_transport_pipes::write): Ditto.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc (version): New static variable.
+ (server_request_queue::add_connection): Remove my gratuitous use
+ of studly caps.
+ (setup_privileges): Declare static.
+ (handle_signal): Ditto.
+ (longopts): Make a local variable of main().
+ (opts): Ditto.
+ (print_usage): New function.
+ (print_version): Ditto (tip of the hat to Joshua Daniel Franklin
+ for inspiration here).
+ (main): More argument checking. Add --help and --version options.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver.h (client_request::serve): Make pure
+ virtual.
+ * cygserver.cc (client_request::serve): Remove definition of pure
+ virtual method.
+ (class client_request_invalid): New class.
+ (server_request::process): Use new client_request_invalid
+ class. And remove goto's.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc (class server_request): Add virtual destructor.
+ (server_request_queue::addConnection): New method to replace bad
+ virtual add() method.
+ (request_loop): Replace call to queue->add() with call to
+ queue->addConnection().
+ (server_request::server_request): Use field initialization.
+ (server_request::~server_request): New virtual destructor.
+ (server_request::process): Remove close and delete of
+ transport_layer_base object. It is deleted by the server_request's
+ own destructor and closed by its own destructor.
+ * include/cygwin/cygserver.h
+ (client_request::operator request_header): Remove unused method.
* cygserver_client.cc: Ditto.
- * cygserver_shm.h: No need to include <sys/socket.h> now.
- * cygerver_transport.cc: Include new include files.
- (transport_layer_base::transport_layer_base): Strip back to a stub.
- (transport_layer_base::listen): Ditto.
+ * include/cygwin/cygserver_process.h
+ (class cleanup_routine): Add virtual destructor.
+ (cleanup_routine::cleanup): Make pure virtual.
+ (class process_cache): Make destructor non-virtual.
+ (process_cache::add): Ditto.
+ * cygserver_process.cc
+ (cleanup_routine::~cleanup_routine): New virtual destructor.
+ * include/cygwin/cygserver_transport.h
+ (class transport_layer_base): Add virtual destructor.
+ * cygserver_transport.cc
+ (transport_layer_base::~transport_layer_base): New virtual
+ destructor.
+ * include/cygwin/cygserver_transport_pipes.h
+ (class transport_layer_pipes): Add virtual destructor.
+ * cygserver_transport_pipes.cc
+ (transport_layer_pipes::~transport_layer_pipes): New virtual
+ destructor.
+ (transport_layer_pipes::close): Null out handle after closing.
+ * include/cygwin/cygserver_transport_sockets.h
+ (class transport_layer_sockets): Add virtual destructor.
+ * cygserver_transport_sockets.cc
+ (transport_layer_sockets::~transport_layer_sockets): New virtual
+ destructor.
+ (transport_layer_sockets::close): Null out fd after closing.
+ * threaded_queue.h (class queue_request): Add virtual destructor.
+ (queue_request::process): Make pure virtual.
+ * threaded_queue.cc (~queue_request): New virtual destructor.
+ (queue_request::process): Remove definition of pure virtual
+ method.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver.h (client_request::send): Make
+ non-virtual.
+ (class client_request_attach_tty): Put client- and server-specific
+ interfaces inside #ifdef/#ifndef __INSIDE_CYGWIN__ guards.
+ * cygserver_client.cc: Ditto.
+ (cygserver_init): Fix error handling.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc: Throughout the code, check and correct level of
+ the XXX_printf() functions used. Comment out several of the
+ debug_printf() calls with "// verbose:". Reformat and correct
+ typos of some of the XXX_printf() formats.
+ * cygserver_process.cc: Ditto.
+ * cygserver_shm.cc: Ditto.
+ * cygserver_transport_pipes.cc: Ditto.
+ * cygserver_transport_sockets.cc: Ditto.
+ * shm.cc (hi_ulong): New function to allow printing of a 64-bit
+ key with current small_printf implementation.
+ (lo_ulong): Ditto.
+ (client_request_shm::client_request_shm): Use hi_ulong() and
+ lo_ulong() in call to debug_printf().
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver_shm.cc: Remove #define __INSIDE_CYGWIN__ from around
+ <sys/shm.h> as it no longer contains any internal code.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/sys/ipc.h (IPC_PRIVATE): Add cast to key_t.
+ (IPC_INFO): New flag for ipcs(8).
+ (IPC_RMID IPC_SET IPC_STAT): Renumber.
+ * include/sys/shm.h (SHM_RDONLY SHM_RND): Renumber with distinct
+ values [sic].
+ (class _shmattach): Internal type moved to "cygserver_shm.h".
+ (class shmnode): Ditto.
+ (class shmid_ds): Ditto.
+ (struct shmid_ds): Add spare fields.
+ (struct shminfo): New type for IPC_INFO interface.
+ * cygserver_shm.h: Remove obsolete #if 0 ... #endif block.
+ (class shm_cleanup): Remove unused class.
+ (struct _shmattach): Internal type moved from <sys/shm.h>.
+ (struct shmnode): Ditto.
+ (struct int_shmid_ds): Ditto. Renamed to avoid name clash with
+ public interface struct shmid_ds. Use the shmid_bs structure as a
+ field.
+ * cygserver_shm.cc: Remove obsolete #if 0 ... #endif block.
+ (client_request_shm::serve): Update for redefinition of
+ int_shmid_ds structure.
+ * shm.cc (build_inprocess_shmds): Ditto.
+ (fixup_shms_after_fork): Ditto.
+ (shmctl): Ditto.
+ (shmget): Ditto. Remove obsolete #if 0 ... #endif code.
+
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * include/cygwin/cygserver_transport.h
+ (transport_layer_base::transport_layer_base): Remove since it is
+ now redundant.
+ (transport_layer_base::listen): Make a pure virtual method.
+ (transport_layer_base::accept): Ditto.
+ (transport_layer_base::close): Ditto.
+ (transport_layer_base::read): Ditto.
+ (transport_layer_base::write): Ditto.
+ (transport_layer_base::connect): Ditto.
+ * cygserver_transport.cc
+ (transport_layer_base::transport_layer_base): Remove since it is
+ now redundant.
+ (transport_layer_base::listen): Remove since it is now a pure
+ virtual method.
(transport_layer_base::accept): Ditto.
(transport_layer_base::close): Ditto.
(transport_layer_base::read): Ditto.
(transport_layer_base::write): Ditto.
(transport_layer_base::connect): Ditto.
- * cygserver_transport_pipes.cc: Include new header
- "cygwin/cygserver_transport_pipes.h".
- * cygserver_transport_sockets.cc: New file.
- * dcrt0.cc: No need to include <sys/socket.h> now.
- * fhandler_tty.cc: Ditto.
- * tty.cc: Ditto.
- * include/cygwin/cygserver_transport.h: Strip the base class to a stub.
- Remove the cygserver_transport_pipes class.
- * include/cygwin/cygserver_transport_pipes.h: New file.
- * include/cygwin/cygserver_transport_sockets.h: New file.
-
-Tue Sep 25 16:22:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * autoload.cc: Add dynamic load statement for 'ImpersonateNamedPipeClient'.
- * Makefile.in: Add new object files, and build instructions for cygserver.exe.
- * cygwin.din: Export ftok, shmat, shmctl and shmget.
- * dcrt0.cc: Additional includes for cygserver support.
- (dll_crt0_1): Initialise the cygserver client.
- * fhandler.h (fhandler_tty): New method cygserver_attach_tty.
- * fhandler_tty.cc: Additional includes for cygserver support.
- (fhandler_tty_slave::open): Attempt to use the cygserver when obtaining
- handles from the parent process. On failure or 9x use the current method.
- (fhandler_tty_slave::cygserver_attach_tty): New function.
- * fork.cc (fork_child): Fixup shm memory mapped areas.
- * pinfo.h: Declare fixup_shms_after_fork().
- * security.h: Declare alloc_sd().
- * tty.cc: Additonal includes to support cygserver.
- (tty::common_init): Don't allow others to open us if the cygserver is running.
- * winsup.h: Declare cygserver_running.
- * cygserver.cc: New file.
- * cygserver_client.cc: New file.
- * cygserver_shm.cc: New file.
- * cygserver_shm.h: New file.
- * cygserver_transport.cc: New file.
- * cygserver_transport_pipes.cc: New file.
- * ipc.cc: New file.
- * shm.cc: New file.
- * include/cygwin/cygserver.h: New file.
- * include/cygwin/cygserver_transport.h: New file.
- * include/sys/ipc.h: New file.
- * include/sys/shm.h: New file.
-
-Mon Oct 1 16:52:23 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dtable.h (dtable::build_fhandler): Make path_conv parameter
- non-optional.
- (dtable::init_std_file_from_handle): Eliminate name parameter.
- * dtable.cc (stdio_init): Don't pass bogus name to
- init_std_file_from_handle. The function will figure out the name
- itself.
- (dtable::init_std_file_from_handle): Eliminate name parameter. Assume
- that we're always called with an appropriate fd. Pass name as NULL if
- we can't simply figure it out from context.
- (cygwin_attach_handle_to_fd): Pass path_conv argument to
- build_fhandler.
- (dtable::build_fhandler): Make path_conv argument mandatory. Eliminate
- specific call to get_device_number. With unknown device names, set
- name from handle context for parsing by path_conv.
- (dtable::build_fhandler): Pass path_conv argument to build_fhandler.
- * path.h (path_conv::set_isdisk): Set disk device type.
- (path_conv::is_device): Don't consider FH_DISK a "device".
- * syscalls.cc (_open): Pass path_conv argument by reference.
- (stat_worker): Ditto.
- (_rename): Use path_conv operators. Add bounds to DeleteFile/MoveFile
- for loop.
-
-Mon Oct 1 14:25:00 2001 Charles Wilson <cwilson@ece.gatech.edu>
-
- * cygwin.din: export strtoll and strtoull
-Sun Sep 30 22:51:41 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-16 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygserver.cc (check_and_dup_handle): Only use security code if
+ running on NT, i.e. if wincap.has_security().
+ (client_request_attach_tty::serve): Add check for has_security().
+ * cygserver_process.cc (process_cache::process): Use DWORD winpid
+ throughout to avoid win32 vs. cygwin pid confusion.
+ (process::process): Ditto.
+ * cygserver_shm.cc (client_request_shm::serve): Only use security
+ code if running on NT, i.e. if wincap.has_security().
+ * cygserver_shm.h (client_request_shm::parameters.in): Replace the
+ ambiguous pid field with cygpid and winpid fields.
+ (client_request_shm::client_request_shm): Reduce to only two
+ client-side constructors: one for SHM_CREATE, another for all the
+ other requests.
+ * shm.cc (client_request_shm::client_request_shm):
+ Ditto. Initialize cygpid and winpid fields here. On NT initialize
+ sd_buf here using set_security_attribute() to make use of the euid
+ and egid.
+ (shmat): Use new client_request_shm constructor.
+ (shmdt): Ditto.
+ (shmctl): Ditto.
+ (shmget): Ditto. Remove security code, now performed in the
+ relevant client_request_shm constructor.
+ * include/cygwin/cygserver_process.h: (class cleanup_routine):
+ Change winpid type to DWORD.
+ (class process): Ditto.
+
+2002-06-15 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * woutsup.h: New file.
+ * cygserver.cc: Use "woutsup.h" and new XXX_printf macros.
+ (getfunc): New function, copied verbatim from "strace.cc".
+ (__cygserver__printf): New function.
+ * cygserver_client.cc: Use "woutsup.h" and new XXX_printf macros.
+ * cygserver_process.cc: Ditto.
+ * cygserver_shm.cc: Ditto.
+ * cygserver_transport.cc: Ditto.
+ * cygserver_transport_pipes.cc: Ditto.
+ * cygserver_transport_sockets.cc: Ditto.
+ * threaded_queue.cc: Ditto.
+ * shm.cc: Remove trailing \n from XXX_printf format strings.
+ * Makefile.in: Remove special __OUTSIDE_CYGWIN__ case for
+ cygserver_shm.cc.
+
+2002-09-21 Christopher Faylor <cgf@redhat.com>
+
+ * init.cc (dll_entry): Temporarily disable thread detach code.
+
+2002-09-21 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler.cc (fhandler_base::dup): Don't set handle on failure.
+ Caller has already taken care of that.
+ * fhandler_console.cc (fhandler_console::open): Initialize handles to
+ NULL.
+ (fhandler_console::close): Ditto.
+
+2002-09-21 Christopher Faylor <cgf@redhat.com>
+
+ GNUify non-GNU formatted functions calls throughout.
+
+2002-09-21 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * cygwin_ipc.h: Move to "include/cygwin/ipc.h".
+ * cygwin_shm.h: Move to "include/cygwin/shm.h".
+ * include/cygwin/ipc.h: New file.
+ * include/cygwin/shm.h: New file.
+ * ipc.c:c Update <cygwin/ipc.h> include.
+ * cygserver_shm.cc: Update <cygwin/shm.h> include.
+ * shm.cc: Ditto.
+
+2002-09-21 Robert Collins <rbtcollins@hotmail.com>
+
+ * pthread.cc: Use class::call for converted pthread and semaphore
+ calls.
+ * thread.cc: Convert various __pthread_call and __sem_call to
+ pthread::call and sem::call throughout.
+ * pthread.h (__pthread_cancel): Convert to pthread::cancel.
+ (__pthread_join): Convert to pthread::join.
+ (__pthread_detach): Convert to pthread::detach.
+ (__pthread_create): Convert to pthread::create.
+ (__pthread_once): Convert to pthread::once.
+ (__pthread_atfork): Convert to pthread::atfork.
+ (__pthread_suspend): Convert to pthread::suspend.
+ (__pthread_continue): Convert to pthread::resume.
+ (__sem_init): Convert to semaphore::init.
+ (__sem_destroy): Convert to semaphore::destroy.
+ (__sem_wait): Convert to semaphore::wait.
+ (__sem_trywait): Convert to semaphore::trywait.
+ (__sem_post): Convert to semaphore::post.
+
+2002-09-21 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc: Finish the removal of the separate pthread_key
+ destructor list.
+ Remove all pthread_key_destructor and pthread_key_destructor_list
+ references throughout.
+ (pthread::exit): Call the new pthread_key interface to activate
+ destructors.
+ (pthread_key::keys): Change into a list.
+ (pthread_key::saveAKey): New method, used via forEach.
+ (pthread_key::restoreAKey): Ditto.
+ (pthread_key::destroyAKey): Ditto.
+ (pthread_key::fixup_before_fork): Use the List::forEach functionality.
+ (pthread_key::fixup_after_fork): Ditto.
+ (pthread_key::runAllDestructors): New method implementation.
+ (pthread_key::pthread_key): Use List::Insert rather than custom list
+ code.
+ (pthread_key::~pthread_key): Use List::Remove for the same reason.
+ * thread.h: Remove all pthread_key_destructor and
+ pthread_key_destructor_list references throughout.
+ (List): Move the interface above pthread_key in the header.
+ Use atomic operations during insert and delete.
+ (List::forEach): A generic interface for doing something on each node.
+ (pthread_key::runAllDestructors): New method, run all destructors.
+ (pthread_key::fork_buf): Make private.
+ (pthread_key::run_destructor): Ditto.
+ (pthread_key::saveAKey): New method for clearer source.
+ (pthread_key::restoreAKey): Ditto.
+ (pthread_key::destroyAKey): Ditto.
+ (MTinterface::destructors): Remove.
+
+2002-09-21 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc: Partial refactoring of pthread_key destructor
+ handling. Loosely based on Thomas Pfaff's work.
+ (pthread_key_destructor_list::Insert): Remove.
+ (pthread_key_destructor_list::Pop): Remove.
+ (pthread_key_destructor_list::IterateNull): Call the key's
+ run_destructor method.
+ (pthread_key::pthread_key): Initialize new member.
+ (pthread_key::get): Mark as const for correctness.
+ (pthread_key::run_destructor): Implement.
+ * thread.h (pthread_key::get): Mark as const for correctness.
+ (pthread_key::run_destructor): Declare.
+ (List): New template class that implements a generic list.
+ (pthread_key_destructor_list): Inherit from List, and remove
+ now duplicate functions.
+
+2002-09-21 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc: Change verifyable_object_isvalid calls with
+ PTHREAD_CONDATTR_MAGIC, PTHREAD_MUTEXATTR_MAGIC, PTHREAD_COND_MAGIC,
+ SEM_MAGIC to objecttype::isGoodObject() calls throughout.
+ (pthread_condattr::isGoodObject): Implement.
+ (pthread_mutex::isGoodInitializer): Implement.
+ (pthread_mutex::isGoodInitializerOrObject): Minor bugfix in the
+ check for verifyable_object_isvalid result.
+ (pthread_mutexattr::isGoodObject): Implement.
+ (pthread_cond::isGoodObject): Ditto.
+ (pthread_cond::isGoodInitializer): Ditto.
+ (pthread_cond::isGoodInitializerOrObject): Ditto.
+ (semaphore::isGoodObject): Ditto.
+ * thread.h (pthread_mutex::isGoodInitializer): Declare.
+ (pthread_condattr::isGoodObject): Ditto.
+ (pthread_cond::isGoodObject): Const correctness.
+ (pthread_cond::isGoodInitializer): Declare.
+ (pthread_cond::isGoodInitializerOrObject): Ditto.
+ (semaphore::isGoodObject): Const correctness.
+
+2002-09-21 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc: Change verifyable_object_isvalid calls with
+ PTHREAD_MUTEX_MAGIC and PTHREAD_KEY_MAGIC and PTHREAD_ATTR_MAGIC to
+ ::isGoodObject() calls throughout.
+ (MTinterface::Init): Remove dead code.
+ (pthread_attr::isGoodObject): Implement.
+ (pthread_key::isGoodObject): Implement.
+ (pthread_mutex::isGoodObject): Implement.
+ (pthread_mutex::isGoodInitializerOrObject): Implement.
+ (pthread::isGoodObject): Update signature.
+ * thread.h (pthread_key::isGoodObject): Declare.
+ (pthread_attr::isGoodObject): Ditto.
+ (pthread_mutex::isGoodObject): Ditto.
+ (pthread_mutex::isGoodInitializerOrObject): Ditto.
+ (pthread::isGoodObject): Change to a const parameter for const
+ correctness.
+ (pthread_mutexattr::isGoodObject): Declare.
+ (pthread_condattr::isGoodObject): Ditto.
+ (pthread_cond::isGoodObject): Ditto.
+ (semaphore::isGoodObject): Ditto.
+
+2002-09-19 Christopher Faylor <cgf@redhat.com>
+
+ Cleanup calls to CreateFile throughout.
+ * dcrt0.cc (__api_fatal): Correctly check for failing return from CreateFile.
+ * assert.cc (__assert): Don't check return value from CreateFile for NULL.
+ * fhandler_console.cc (set_console_state_for_spawn): Ditto.
+ * fork.cc (fork_parent): Ditto.
- Add "path.h" include throughout, where needed. Use new path_conv
- methods and operators to simplify testing for directory and attributes,
- throughout.
- * path.h (path_conv::exists): New method.
- (path_conv::has_attribute): Ditto.
- (path_conv::isdir): Ditto.
- (path_conv::DWORD &): New operator.
- (path_conv::int &): Ditto.
- * dir.cc (rmdir): Eliminate a goto.
- * dtable.cc (dtable::build_fhandler): Accept opt and suffix info for
- path_conv.check. Return fh == NULL on path_conv error. Pass unit to
- set_name as appropriate.
- (dtable::reset_unix_path_name): New method.
- * dtable.h (dtable): Declare new method. Reflect arg changes to
- build_fhandler.
- * fhandler.cc (fhandler_disk_dummy_name): Eliminate.
- (fhandler_base::set_name): Expect paths to be NULL. Build
- unix_path_name from win32_path_name when it is a device.
- (fhandler_base::reset_unix_path_name): New method.
- (fhandler_base::raw_read): Report EISDIR when ERROR_INVALID_FUNCTION
- or ERROR_INVALID_PARAMETER and reading a directory.
- (fhandler_disk_file::fstat): Don't call stat_dev since we should now
- never be calling fhandler_disk_file methods with devices.
- (fhandler_base::fhandler_base): Clear {unix,win32}_path_name.
- (fhandler_base::~fhandler_base): Always free {unix,win32}_path_name.
- (fhandler_disk_file::fhandler_disk_file): Remove set_no_free_names
- kludge.
- (fhandler_disk_file::open): Ditto.
- * fhandler.h (fhandler_base::no_free_names): Eliminate.
- (fhandler_base::set_no_free_names): Ditto.
- * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Don't set
- unix_path_name here.
- * path.cc (fchdir): Lock fd table throughout. Use new
- dtable::reset_unix_path_name method to reset path.
- * syscalls.cc (stat_worker): Reorganize to always call fstat method.
- Pass path_conv method to fhandler_*::open.
- (chroot): Elminate a goto.
-
-Sun Sep 30 17:37:43 2001 Christopher Faylor <cgf@cygnus.com>
-
- * environ.cc (winenv): Allocate exact amount of space needed for forced
- windows environment variable rather than just using MAX_PATH.
-
-Sun Sep 30 17:10:18 2001 Christopher Faylor <cgf@cygnus.com>
-
- * Makefile.in: Depend on stamp to ensure rebuilding. Remove stamp file
- when we've just built the DLL.
-
-Mon Oct 1 00:34:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.cc (pthread_cond_dowait): Hopefully eliminate a race on multiple thread
- wakeups.
-
-Sat Sep 29 18:26:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * pthread.cc (pthread_cond_timedwait): Deleted - exported from thread.cc.
- (pthread_cond_wait): Deleted - exported from thread.cc.
- * thread.cc (pthread_cond::BroadCast): Update to use the new syntax for
- verifyable_object_isvalid ().
- (pthread_cond::Signal): Ditto. Also attempt to fix the lost signal race
- with pthread_cond::TimedWait().
- (check_valid_pointer): Change definiton to void const *.
- (verifyable_object_isvalid): Add new parameter to allow identification of
- static initializers, and return a enum rather than magic numbers.
- (__pthread_create): Ditto.
- (__pthread_cleanup): Ditto.
- (__pthread_attr_init): Ditto.
- (__pthread_attr_getinheritsched): Ditto.
- (__pthread_attr_getschedparam): Ditto.
- (__pthread_attr_getschedpolicy): Ditto.
- (__pthread_attr_getscope): Ditto.
- (__pthread_attr_setdetachstate): Ditto.
- (__pthread_attr_getdetachstate): Ditto.
- (__pthread_attr_setinheritsched): Ditto.
- (__pthread_attr_setschedparam): Ditto.
- (__pthread_attr_setschedpolicy): Ditto.
- (__pthread_attr_setscope): Ditto.
- (__pthread_attr_setstacksize): Ditto.
- (__pthread_attr_getstacksize): Ditto.
- (__pthread_attr_destroy): Ditto.
- (__pthread_join): Ditto.
- (__pthread_detach): Ditto.
- (__pthread_suspend): Ditto.
- (__pthread_continue): Ditto.
- (__pthread_getschedparam): Ditto.
- (__pthread_getsequence_np): Ditto.
- (__pthread_key_create): Ditto.
- (__pthread_key_delete): Ditto.
- (__pthread_setschedparam): Ditto.
- (__pthread_setspecific): Ditto.
- (__pthread_getspecific): Ditto.
- (__pthread_cond_destroy): Ditto.
- (__pthread_cond_init): Ditto.
- (__pthread_cond_broadcast): Ditto.
- (__pthread_cond_signal): Ditto.
- (__pthread_condattr_init): Ditto.
- (__pthread_condattr_getpshared): Ditto.
- (__pthread_condattr_setpshared): Ditto.
- (__pthread_condattr_destroy): Ditto.
- (__pthread_kill): Ditto.
- (__pthread_mutex_init): Ditto.
- (__pthread_mutex_getprioceiling): Ditto.
- (__pthread_mutex_lock): Ditto.
- (__pthread_mutex_trylock): Ditto.
- (__pthread_mutex_unlock): Ditto.
- (__pthread_mutex_destroy): Ditto.
- (__pthread_mutex_setprioceiling): Ditto.
- (__pthread_mutexattr_getprotocol): Ditto.
- (__pthread_mutexattr_getpshared): Ditto.
- (__pthread_mutexattr_gettype): Ditto.
- (__pthread_mutexattr_init): Ditto.
- (__pthread_mutexattr_destroy): Ditto.
- (__pthread_mutexattr_setprotocol): Ditto.
- (__pthread_mutexattr_setprioceiling): Ditto.
- (__pthread_mutexattr_getprioceiling): Ditto.
- (__pthread_mutexattr_setpshared): Ditto.
- (__pthread_mutexattr_settype): Ditto.
- (__sem_init): Ditto.
- (__sem_destroy): Ditto.
- (__sem_wait): Ditto.
- (__sem_trywait): Ditto.
- (__sem_post): Ditto.
- (__pthread_cond_dowait): New function, contains core logic from
- __pthread_cond_wait and __pthread_cond_timedwait. Decrement (*cond)->waiting
- before reentering the cond access mutex to allow detection of lost signals.
- (__pthread_cond_timedwait): Rename to pthread_cond_timedwait, and call
- __pthread_cond_dowait after calculating the wait length.
- (__pthread_cond_wait): Rename to pthread_cond_wait, and call
- __pthread_cond_dowait.
- * thread.h: New enum for use with verifyable_object_isvalid.
- Remove the extern exporting of __pthread_cond_timedwait and __pthread_cond_wait.
-
-Fri Sep 28 21:18:50 2001 Christopher Faylor <cgf@cygnus.com>
-
- * pipe.cc (fhandler_pipe::fixup_after_fork): New method.
- * fhandler.h (fhandler_pipe::fixup_after_fork): Declare new method.
-
-Fri Sep 28 03:23:04 2001 Christopher Faylor <cgf@cygnus.com>
-
- * passwd.cc (read_etc_passwd): Bother with unlocking when not
- in cygwin initialization.
- * grp.cc (read_etc_group): Ditto.
-
-Fri Sep 28 02:57:03 2001 Christopher Faylor <cgf@cygnus.com>
-
- * passwd.cc (read_etc_passwd): Don't bother with locking when
- in cygwin initialization since there is only one thread.
- * grp.cc (read_etc_group): Ditto.
-
-Fri Sep 28 01:50:09 2001 Christopher Faylor <cgf@cygnus.com>
-
- * pipe.cc (fhandler_pipe::hit_eof): Return correct value when there is
- no EOF event available.
-
-Sat Sep 28 00:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * mmap.cc (mmap): Move setting the access after evaluating fd.
- Remove useless comment. Explain copy-on-write problem of 9x
- more detailed. Don't set access to FILE_MAP_COPY on 9x only
- when anonymous mapping is requested.
- (fhandler_disk_file::mmap): Remove useless device check.
- Add debug output.
-
-Fri Sep 27 07:35:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * Makefile.in: Only stamp winver_stamp on success.
-
-Wed Sep 26 16:02:35 2001 Christopher Faylor <cgf@cygnus.com>
-
- * select.cc (peek_pipe): REALLY only grab mutex when we actually got
- something from the pipe.
-
-Tue Sep 25 21:25:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.cc (pthread_cond::BroadCast): Use address with verifyable_object_isvalid().
- (pthread_cond::Signal): Ditto.
- (__pthread_create): Ditto.
- (__pthread_cleanup): Ditto.
- (__pthread_attr_init): Ditto.
- (__pthread_attr_getinheritsched): Ditto.
- (__pthread_attr_getschedparam): Ditto.
- (__pthread_attr_getschedpolicy): Ditto.
- (__pthread_attr_getscope): Ditto.
- (__pthread_attr_setdetachstate): Ditto.
- (__pthread_attr_getdetachstate): Ditto.
- (__pthread_attr_setinheritsched): Ditto.
- (__pthread_attr_setschedparam): Ditto.
- (__pthread_attr_setschedpolicy): Ditto.
- (__pthread_attr_setscope): Ditto.
- (__pthread_attr_setstacksize): Ditto.
- (__pthread_attr_getstacksize): Ditto.
- (__pthread_attr_destroy): Ditto.
+2002-09-18 Christopher Faylor <cgf@redhat.com>
+
+ * cygthread.cc (cygthread::initialized): Avoid copying on fork or some
+ threads may not end up in the pool.
+ (cygthread::new): Avoid race when checking for initialized. Add
+ debugging code.
+
+2002-09-18 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * fhandler.cc (fhandler_base::raw_read): Add case for
+ ERROR_INVALID_HANDLE due to Win95 directories.
+ (fhandler_base::open): Handle errors due to Win95 directories.
+ (fhandler_base::close): Add get_nohandle () test.
+ (fhandler_base::set_close_on_exec): Ditto.
+ (fhandler_base::fork_fixup): Ditto.
+ (fhandler_base::lock): Change error code to Posix EINVAL.
+ (fhandler_base::dup): If get_nohandle (), set new value to
+ INVALID_HANDLE_VALUE instead of NULL.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat): Call fstat_by_name
+ if get_nohandle (). Remove extraneous element from strpbrk.
+ (fhandler_disk_file::open): Remove test for Win95 directory.
+
+ * fhandler_random.cc (fhandler_dev_random::open): Add set_nohandle ().
+ * fhandler_clipboard.cc (fhandler_dev_clipboard::open): Ditto.
+ * fhandler_zero.cc (fhandler_dev_zero::open): Ditto.
+ (fhandler_dev_zero::close): Delete.
+ * fhandler.h (class fhandler_dev_zero): Ditto.
+
+2002-09-17 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc (pthread_key::set): Preserve GetLastError(). Reported
+ by Thomas Pffaf.
+
+2002-09-17 Robert Collins <rbtcollins@hotmail.com>
+
+ This work inspires by Thomas Pfaff's pthread_fork patch (1).
+ * fork.cc (fork_child): Remove MTinterface fixup call, it's
+ adsorbed by pthread::atforkchild.
+ Rename __pthread_atforkchild to pthread::atforkchild to give
+ access to private members.
+ (fork_parent): Rename __pthread_atforkparent to
+ pthread::atforkparent to give it access to private members.
+ Ditto for __pthread_atforkprepare.
+ * thread.cc: Fix some formatting problems throughout.
+ (MTinterface::fixup_before_fork): Implement.
+ (MTinterface::fixup_after_fork): Fix pthread_keys.
+ (pthread_key::keys): Implement.
+ (pthread_key::fixup_before_fork): Ditto.
+ (pthread_key::fixup_after_fork): Ditto.
+ (pthread_key::pthread_key): Add to pthread_key::keys.
+ (pthread_key::~pthread_key): Remove from pthread_key::keys.
+ (pthread_key::saveKeyToBuffer): Implement.
+ (pthread_key::recreateKeyFromBuffer): Ditto.
+ (pthread::atforkprepare): Prepare all MT classes for fork.
+ (pthread::atforkchild): And fix them up afterwards.
+ * thread.h (pthread_key): Buffer the key value during
+ fork in fork_buf.
+ List the keys needing to be fixed up in a linked list with
+ head pthread_key::keys.
+ (pthread): Move atfork cygwin internal calls into the class.
+ (MTInterface): Provide a fixup_before_fork for objecst that
+ need to save state.
+ (__pthread_atforkprepare): Remove.
+ (__pthread_atforkparent): Remove.
+ (__pthread_atforkchild): Remove.
+
+2002-09-16 Christopher Faylor <cgf@redhat.com>
+
+ * init.cc: Cleanup slightly and remove obsolete code.
+
+2002-09-11 Robert Collins <rbtcollins@hotmail.com>
+
+ * init.cc (dll_entry): On thread detach, if the thread hasn't
+ exit()ed, do so.
+ * pthread.cc (pthread_getsequence_np): Remove the
+ __pthread_getsequence_np wrapper. This requires errno.h.
+ * thread.cc (pthread::self): Instantiate a new pthread object
+ when called and none exists. return a NULL object if instantiation
+ fails.
+ (pthread::precreate): Factor out common code.
+ (pthread::postcreate): Ditto.
+ (pthread::create): Ditto.
+ (pthread::exit): Remove the TLS value when we exit to prevent
+ double exits.
+ (MTinterface::Init): Bugfix - don't mark the TLS index as created
+ if one was not allocated.
+ Apply Extract Method to move pthread specific initialisation into
+ pthread.
+ (pthread::initMainThread): Extracted method from MTinterface::Init.
+ (pthread::setTlsSelfPointer): Extracted method from various pthread
+ calls, to make reading those functions easier.
+ (pthread::setThreadIdtoCurrent): Ditto.
+ (pthread::cancel_self): Bring into the .cc file, it's only used
+ within the class.
+ (pthread::getThreadId): Ditto.
+ (pthread::thread_init_wrapper): Apply Extract Method to the TLS
+ setting logic.
+ (pthread::isGoodObject): Extracted method from various pthread
+ wrapper calls, for clarity of reading.
+ (pthread::getsequence_np): Converted from __pthread_getsquence_np.
+ (__pthread_create): Apply Extract Method to the object validation.
+ (__pthread_cancel): Ditto.
(__pthread_join): Ditto.
(__pthread_detach): Ditto.
(__pthread_suspend): Ditto.
(__pthread_continue): Ditto.
(__pthread_getschedparam): Ditto.
- (__pthread_getsequence_np): Ditto.
- (__pthread_key_create): Ditto.
- (__pthread_key_delete): Ditto.
- (__pthread_setschedparam): Ditto.
- (__pthread_setspecific): Ditto.
- (__pthread_getspecific): Ditto.
- (__pthread_cond_destroy): Ditto.
- (__pthread_cond_init): Ditto.
- (__pthread_cond_broadcast): Ditto.
- (__pthread_cond_signal): Ditto.
- (__pthread_cond_timedwait): Ditto.
- (__pthread_cond_wait): Ditto.
- (__pthread_condattr_init): Ditto.
- (__pthread_condattr_getpshared): Ditto.
- (__pthread_condattr_setpshared): Ditto.
- (__pthread_condattr_destroy): Ditto.
- (__pthread_kill): Ditto.
- (__pthread_mutex_init): Ditto.
- (__pthread_mutex_getprioceiling): Ditto.
- (__pthread_mutex_lock): Ditto.
- (__pthread_mutex_trylock): Ditto.
- (__pthread_mutex_unlock): Ditto.
- (__pthread_mutex_destroy): Ditto.
- (__pthread_mutex_setprioceiling): Ditto.
- (__pthread_mutexattr_getprotocol): Ditto.
- (__pthread_mutexattr_getpshared): Ditto.
- (__pthread_mutexattr_gettype): Ditto.
- (__pthread_mutexattr_init): Ditto.
- (__pthread_mutexattr_destroy): Ditto.
- (__pthread_mutexattr_setprotocol): Ditto.
- (__pthread_mutexattr_setprioceiling): Ditto.
- (__pthread_mutexattr_getprioceiling): Ditto.
- (__pthread_mutexattr_setpshared): Ditto.
- (__pthread_mutexattr_settype): Ditto.
- (__sem_init): Ditto.
- (__sem_destroy): Ditto.
- (__sem_wait): Ditto.
- (__sem_trywait): Ditto.
- (__sem_post): Ditto.
- (verifyable_object_isvalid): Recieve a pointer to a pointer for verification.
- (__pthread_mutexattr_getprotocol): Fix typo in magic number.
- (__pthread_mutexattr_getpshared): Ditto.
- (__pthread_mutexattr_gettype): Ditto.
- * thread.h (verifyable_object_isvalid): Change prototype to recieve a pointer to a
- pointer for verification.
- * include/pthread.h: Fix typo for __cleanup_routine_type typedef. (Contrib from Net).
-
-Tue Sep 25 02:09:42 2001 Christopher Faylor <cgf@redhat.com>
-
- * select.cc (fhandler_tty_common::ready_for_read): Rewrite to correctly
- call peek_pipe.
-
-Mon Sep 24 18:46:39 2001 Christopher Faylor <cgf@cygnus.com>
-
- * select.cc (peek_pipe): Only grab mutex when we actually got something
- from the pipe.
-
-Mon Sep 24 17:41:03 2001 Christopher Faylor <cgf@redhat.com>
-
- * fhandler.h (fhandler_pipe::hit_eof): New method.
- (writepipe_exists): New class element.
- (orig_pid): Ditto.
- (id): Ditto.
- (is_slow): Eliminate.
- * pipe.cc (fhandler_pipe::set_close_on_exec): Set inheritance on
- writepipe_exists, if it exists.
- (fhandler_pipe::hit_eof): New method, modelled after tty.
- (fhandler_pipe::dup): Duplicate writepipe_exists, if it exists.
- (make_pipe): Set up a dummy event for pipes on windows 9x. The
- nonexistence of this event means that the write side of the
- pipe has closed.
- (_dup): Move to syscalls.cc
- (_dup2): Ditto.
-
- * dtable.cc (dtable::build_fhandler): Fill out set_names here, if
- appropriate.
- * syscalls.cc (_open): Call set_names in build_fhandler.
-
+ (__pthread_getsequence_np): Remove.
+ (__pthread_setschedparam): Apply Extract Method to the object
+ validation.
+ (pthreadNull::getNullpthread): New method, return the pthreadNull
+ object.
+ (pthreadNull::pthreadNull): Private constructor to prevent accidental
+ use.
+ (pthreadNull::~pthreadNull): Prevent compile warnings.
+ (pthreadNull::create): Override pthread behaviour.
+ (pthreadNull::exit): Ditto.
+ (pthreadNull::cancel): Ditto.
+ (pthreadNull::testcancel): Ditto.
+ (pthreadNull::setcancelstate): Ditto.
+ (pthreadNull::setcanceltype): Ditto.
+ (pthreadNull::push_cleanup_handler): Ditto.
+ (pthreadNull::pop_cleanup_handler): Ditto.
+ (pthreadNull::getsequence_np): Ditto.
+ (pthreadNull::_instance): Ditto.
+ * thread.h (pthread): Declare pre- and post-create.
+ Move GetThreadId to private scope and rename to getThreadId.
+ Move setThreadIdtoCurrent to private scope.
+ Make create virtual.
+ Make ~pthread virtual.
+ Declare initMainThread.
+ Declare isGoodObject.
+ Make exit virtual.
+ Make cancel virtual.
+ Make testcancel virtual.
+ Make setcancelstate virtual.
+ Make setcanceltype virtual.
+ Make push_cleanup_handler virtual.
+ Make pop_cleanup_handler virtual.
+ Declare getsequence_np.
+ Declare setTlsSelfPointer.
+ (pthreadNull): New null object class for pthread.
+ (__pthread_getsequence_np): Remove.
+
+2002-09-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * syscalls.cc (seteuid32): Treat ILLEGAL_UID invalid.
+ (setegid32): Treat ILLEGAL_GID invalid.
+
+2002-09-10 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * grp.cc (initgroups): Call groups::clear_supp to free the
+ supplementary group sids that may have been set by setgroups.
+ * security.cc (cygsidlist::free_sids): Also zero the class members.
+ * security.h (groups::clear_supp): New.
+ Rename cygsidlist_unknown to cygsidlist_empty.
+
+2002-09-08 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_tty.cc (fhandler_tty_slave::open): Don't protect
+ input/output handles since they are not properly manipulated later.
+ * tty.cc (tty::make_pipes): Ditto.
+
+2002-09-06 Christopher Faylor <cgf@redhat.com>
+
+ * winsup.h (_WIN32_WINNT): Protect.
+
+2002-09-06 Christopher Faylor <cgf@redhat.com>
+
+ * winsup.h (_WIN32_WINNT): Define.
+
+2002-09-03 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in (DLL_OFILES): Drop shortcut.o.
+ * path.cc: Move all shortcut functions from shortcut.c to here.
+ (check_shortcut): Implement without using COM interface.
+ * path.h: Move definition of SHORTCUT_HDR_SIZE to here.
+ * shortcut.c: Remove.
+ * shortcut.h: Ditto.
+
+2002-09-03 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler.h (fhandler_socket::read): Remove method.
+ (fhandler_socket::write): Ditto.
+ (fhandler_socket::readv): New method.
+ (fhandler_socket::writev): Ditto.
+ (fhandler_socket::recvmsg): Add new optional argument.
+ (fhandler_socket::sendmsg): Ditto.
+ * fhandler.cc (fhandler_socket::read): Remove method.
+ (fhandler_socket::write): Ditto.
+ (fhandler_socket::readv): New method.
+ (fhandler_socket::writev): Ditto.
+ (fhandler_socket::recvmsg): Use win32's scatter/gather IO where
+ possible.
+ (fhandler_socket::sendmsg): Ditto.
+ * net.cc (cygwin_recvmsg): Check the msghdr's iovec fields.
+ (cygwin_sendmsg): Ditto. Add omitted sigframe.
+
+2002-09-02 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
+
+ * cygwin.din: Revert exporting new wchar functions.
+ * include/cygwin/version.h: Change comment for API minor 62.
+
+2002-09-02 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (dll_crt0_1): Remove getpagesize() call.
+ * shared.cc (memory_init): Move it here.
+
+2002-08-31 Christopher January <chris@atomice.net>
+
+ * fhandler_proc.cc: Add <sys/param.h> include.
+ (format_proc_uptime): Use KernelTime and UserTime only as they include
+ the other counters.
+ (format_proc_stat): KernelTime includes IdleTime, so subtract IdleTime
+ from KernelTime. Make number of 'jiffies' per second same as HZ define.
+ * fhandler_process.cc: Add <sys/param.h> include.
+ (format_process_stat): Make number of 'jiffies' per second same as
+ HZ define. Use KernelTime and UserTime only to calculate start_time.
-Sun Sep 23 16:55:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-08-30 Christopher Faylor <cgf@redhat.com>
- * syscalls.cc (_open): Set name in fhandler object after successful
- creation.
- (stat_dev): Set device type to block device in FH_FLOPPY case.
-
-Sun Sep 23 11:15:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * dtable.cc (dtable::build_fhandler): Initialize unit when using
- optional path_conv argument.
-
-Sat Sep 22 17:33:45 2001 Christopher Faylor <cgf@cygnus.com>
- Corinna Vinschen <corinna@vinschen.de>
-
- * dtable.cc (dtable::build_fhandler): Accept an optional path_conv
- argument. If available, use this to calculate path name and device
- number.
- * dtable.h (dtable): Reflect above change.
- * fhandler.h (fhandler_base): Declare virtual method which accepts
- path_conv rather than path string as first argument.
- * fhandler.cc (fhandler_base::open): Define above new method.
- * syscalls.cc (_open): Set aside a path_conv variable for use in
- build_fhandler and subsequent call to open.
-
-Sat Sep 22 12:44:57 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (setup_handler): Always relinquish lock after we've
- interrupted.
- * fhandler.cc: Move pipe methods to pipe.cc.
- * fhandler.h (fhandler_pipe): Add new methods.
- * fork.cc (sync_with_parent): Make error messages more informative.
- * pipe.cc (fhandler_pipe::fhandler_pipe): Move here from fhandler.cc.
- (fhandler_pipe::lseek): Ditto.
- (fhandler_pipe::set_close_on_exec): New method.
- (fhandler_pipe::read): Ditto.
- (fhandler_pipe::close): Ditto.
- (fhandler_pipe::dup): Ditto.
- (make_pipe): Create the guard mutex on the read side of the pipe.
- * select.cc (peek_pipe): Use guard_mutex to discover if we have the
- right to read on this pipe.
- (fhandler_pipe::readh_for_read): Pass the read pipe guard mutex to
- peek_pipe.
- * syscalls.cc (_read): Always detect signal catchers, for now.
-
- * debug.cc (makethread): Eliminate hack to make thread inheritable.
- * sigproc.cc (subproc_init): Don't use hack to make thread inheritable.
-
-Thu Sep 20 16:48:44 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler.cc (fhandler_base::set_inheritance): Just use
- DUPLICATE_CLOSE_SOURCE to change inheritance. Eliminate all other
- logic dealing with closed handles.
- * fhandler.h (fhandler_base::set_inheritance): Reflect above change.
- * fhandler_tty.cc (fhandler_tty_common::set_close_on_exec): Ditto.
-
-Thu Sep 20 13:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::fixup_after_exec): Close
- socket only when not using Winsock2.
-
-Thu Sep 20 13:20:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler.h (fhandler_socket::fixup_after_exec): Remove inline
- implementation.
- (fhandler_dev_raw::fixup_after_exec): Ditto.
- * fhandler_raw.cc (fhandler_dev_raw::fixup_after_fork): Don't
- duplicate buffer on fork to avoid memory leak.
- (fhandler_dev_raw::fixup_after_exec): New implementation equal to
- former fixup_after_fork() implementation.
- * fhandler_socket.cc (fhandler_socket::fixup_after_fork): Do
- nothing when not using Winsock2.
- (fhandler_socket::fixup_after_exec): New implementation.
- (fhandler_socket::set_close_on_exec): Never call set_inheritance().
-
-Thu Sep 20 9:55:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler.cc (fhandler_base::set_inheritance): If available,
- use SetHandleInformation() to set inheritance.
- * wincap.cc: Set flag has_set_handle_information_on_console_handles
- appropriately.
- * wincap.h: Add flag has_set_handle_information_on_console_handles.
+ (inspired by a patch from Egor Duda)
+ * select.cc (fhandler_tty_slave::ready_for_read): Remove.
+ * fhandler.h (fhandler_tty_slave::ready_for_read): Remove declaration.
+ * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Set "don't
+ need ready for read" flag.
+ (fhandler_tty_slave::read): Don't do anything special with vtime when
+ vmin == 0.
-Wed Sep 19 12:24:09 2001 Christopher Faylor <cgf@cygnus.com>
+2002-08-30 Egor Duda <deo@logos-m.ru>
- * lib/getopt.c (__progname): Don't declare if not compiling for cygwin.
+ * autoload.cc (GetConsoleWindow): Correct parameter count.
-Wed Sep 19 18:07:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-08-30 Christopher January <chris@atomice.net>
+ Christopher Faylor <cgf@redhat.com>
- * lib/getopt.c (getopt_long): Avoid compiler warning.
+ * tty.cc (tty_list::allocate_tty): Use GetConsoleWindow, if available.
+ Call FindWindow in a loop.
+ * autoload.cc (GetConsoleWindow): Export
-Wed Sep 19 11:52:42 2001 Christopher Faylor <cgf@cygnus.com>
+2002-08-30 Christopher Faylor <cgf@redhat.com>
- * lib/getopt.c: Use __progname==__argv[0] when not compiling for cygwin.
+ * miscfuncs.cc (check_iovec_for_read): Don't check buffer when zero
+ length iov_len.
+ (check_iovec_for_write): Ditto.
- * scandir.cc (scandir): Use correct default when compar == NULL.
+2002-08-27 Conrad Scott <conrad.scott@dsl.pipex.com>
-Wed Sep 19 17:49:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * fhandler.h (fhandler_base::readv): New method.
+ (fhandler_base::writev): Ditto.
+ * fhandler.cc (fhandler_base::readv): New method.
+ (fhandler_base::writev): Ditto.
+ * syscalls.cc (_read): Delegate to readv(2).
+ (_write): Ditto, mutatis mutandi.
+ (readv): Rewrite, based on the old _read code, to use the new
+ fhandler_base::readv method. Improve access mode handling and ensure
+ all calls reach the final strace statement.
+ (writev): Ditto, mutatis mutandi.
+ * include/sys/uio.h (struct iovec): Change field types to match SUSv3.
+ * winsup.h (check_iovec_for_read): New function.
+ (check_iovec_for_write): Ditto.
+ * miscfuncs.cc (check_iovec_for_read): Ditto.
+ (check_iovec_for_write): Ditto.
- * fhandler_socket.cc (fhandler_socket::fhandler_socket): Revert
- memory allocation to use cmalloc again.
+2002-08-30 Corinna Vinschen <corinna@vinschen.de>
-Tue Sep 18 21:04:26 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygwin.din: Add more prototypes for new wchar functions in newlib.
- * cygwin.din (__argv): Export.
- (__argc): Ditto.
- (__progname): Ditto.
- * include/getopt.h (getopt_long): constify arguments.
- * lib/getopt.c: Import new file from NetBSD.
+2002-08-30 Corinna Vinschen <corinna@vinschen.de>
-Tue Sep 18 18:21:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * cygwin.din: Add prototypes for new wchar functions in newlib.
+ * include/cygwin/version.h: Bump API minor number.
- * mmap.cc (mmap): Don't reuse anonymous memory in MAP_FIXED case.
+2002-08-29 Boris Schaeling <boriss@web.de>
+ Corinna Vinschen <corinna@vinschen.de>
-Mon Sep 17 17:29:25 2001 Christopher Faylor <cgf@cygnus.com>
+ * poll.cc (poll): Peek sockets ready for read to see if there's
+ actually data.
- * include/io.h: Add access declaration.
+2002-08-28 Christopher Faylor <cgf@redhat.com>
-Mon Sep 17 14:04:27 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygthread.cc (hthreads): Remove unneeded global.
+ (cygthread::simplestub): New static member function.
+ (cygthread::runner): Don't set hthreads.
+ (cygthread::freerange): New member function.
+ (cygthread::operator new): Call freerange if all cygwin slots are used
+ up.
+ (cygthread::exit_thread): Don't mess with event if freerange thread.
+ (cygthread::detach): Ditto.
+ * cygthread.h (class cygthread): Declare new member functions and
+ variables.
- * syscalls.cc (rmdir): Set cwd to some other location if attempting to
- rmdir current working directory.
+2002-08-28 Christopher Faylor <cgf@redhat.com>
-Sun Sep 16 23:04:31 2001 Christopher Faylor <cgf@cygnus.com>
+ * malloc.cc: Protect some definitions to avoid a compile time warning.
- * dtable.h (not_open): Assure inline.
- * fhandler.h (operator []): Make const.
+2002-08-27 Nicholas Wourms <nwourms@netscape.net>
-Sun Sep 16 23:02:57 2001 Robert Collins <rbtcollins@hotmail.com>
+ * cygwin.din: Export getc_unlocked, getchar_unlocked,
+ putc_unlocked, putchar_unlocked functions.
+ * include/cygwin/version.h: Bump api minor.
- * sync.cc (muto::~muto): Fix typo which stopped muto event handle from
- ever being closed.
+2002-08-28 Corinna Vinschen <corinna@vinschen.de>
-2001-09-16 Egor Duda <deo@logos-m.ru>
+ * fhandler_socket.cc (fhandler_socket::recvfrom): Eliminate flags
+ not understood by WinSock.
+ (fhandler_socket::sendto): Ditto. If WinSock sendto() returns
+ WSAESHUTDOWN, change errno to EPIPE and raise SIGPIPE if MSG_NOSIGNAL
+ isn't set in flags.
+ * include/cygwin/socket.h: Define MSG_WINMASK and MSG_NOSIGNAL.
+ * include/cygwin/version.h: Bump API minor number.
- * path.cc (symlink): Check arguments for validity.
- (getcwd): Ditto.
- * syscalls.cc (ftruncate): Ditto.
- * times.cc (times): Ditto.
- * uname.cc (uname): Ditto.
+2002-08-28 Corinna Vinschen <corinna@vinschen.de>
+
+ * poll.cc (poll): Eliminate erroneous POLLERR conditional.
+
+2002-08-26 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler_socket.cc (fhandler_socket::check_peer_secret_event):
+ Fix strace message.
+ (fhandler_socket::connect): Remove sigframe.
+ (fhandler_socket::accept): Ditto.
+ (fhandler_socket::getsockname): Ditto.
+ (fhandler_socket::getpeername): Ditto.
+ (fhandler_socket::recvfrom): Ditto.
+ (fhandler_socket::recvmsg): Ditto.
+ (fhandler_socket::sendto): Ditto.
+ (fhandler_socket::sendmsg): Ditto.
+ (fhandler_socket::close): Ditto.
+ (fhandler_socket::ioctl): Ditto.
+ * ioctl.cc (ioctl): Add sigframe.
+ *net.cc (cygwin_sendto): Ditto.
+ (cygwin_recvfrom): Ditto.
+ (cygwin_recvfrom): Ditto.
+ (cygwin_connect): Ditto.
+ (cygwin_shutdown): Ditto.
+ (cygwin_getpeername): Ditto.
+ (cygwin_accept): Ditto. Improve strace message.
+ (cygwin_getsockname): Ditto. Ditto.
+ (cygwin_recvmsg): Ditto. Ditto.
+ (cygwin_sendmsg): Fix strace message.
+
+2002-08-27 Christopher Faylor <cgf@redhat.com>
+
+ * child_info.h: Add _PROC_WHOOPS enum value.
+ (CURR_CHILD_INFO_MAGIC): Update.
+ (child_info::magic): Make 'long'.
+ * cygheap.h: Export _cygheap_start.
+ * cygheap.cc: Don't declare _cygheap_start.
+ * cygmagic: Use cksum to produce checksums. Append 'U' to end of
+ checksum.
+ * dcrt0.cc (initial_env): Calculate sleep ms before reusing buffer.
+ (_dll_crt0): Detect cygheap mismatch as indicative of different cygwin
+ version. Set child_proc_info to NULL when _PROC_WHOOPS.
+ (multiple_cygwin_problem): If child_info specific problem, then set
+ child_proc_info type to _PROC_WHOOPS.
+ * shared_info.h (CURR_MOUNT_MAGIC): Update.
+ (CURR_SHARED_MAGIC): Ditto.
+
+2002-08-25 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler.h (fhandler_socket::recvfrom): Fix prototype.
+ (fhandler_socket::sendto): Ditto.
+ * fhandler_socket.cc (fhandler_socket::recvfrom): Ditto.
+ (fhandler_socket::sendto): Ditto.
+ * include/sys/socket.h (recv): Fix prototype.
+ (recvfrom): Ditto.
+ (send): Ditto.
+ (sendto): Ditto.
+ * net.cc (cygwin_sendto): Ditto. Improve strace message
+ (cygwin_recvfrom): Ditto. Ditto.
+ (cygwin_setsockopt): Improve strace message.
+ (cygwin_getsockopt): Ditto.
+ (cygwin_connect): Ditto.
+ (cygwin_accept): Ditto.
+ (cygwin_bind): Ditto.
+ (cygwin_getsockname): Ditto.
+ (cygwin_getpeername): Ditto.
+ (cygwin_recv): Fix prototype.
+ (cygwin_send): Ditto.
+ (cygwin_recvmsg): Improve strace message.
+ (cygwin_sendmsg): Ditto.
-Sat Sep 15 22:54:49 2001 Christopher Faylor <cgf@cygnus.com>
+2002-08-25 Pierre Humblet <Pierre.Humblet@ieee.org>
- * net.cc (dup_servent_ptr): Detect old Windows 95 misaligned structure
- and realign appropriately.
+ * sec_acl.cc (getacl): Check ace_sid == well_known_world_sid
+ before owner_sid and group_sid so that well_known_world_sid
+ means "other" even when owner_sid and/or group_sid are Everyone.
+ * security.cc (get_attribute_from_acl): Created from code common
+ to get_nt_attribute() and get_nt_object_attribute(), with same
+ reordering as in getacl() above.
+ (get_nt_attribute): Call get_attribute_from_acl().
+ (get_nt_object_attribute): Ditto.
+
+2002-08-26 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (cygrunk.exe): Make a -mno-cygwin program.
+ * cygrun.c (main): Export CYGWIN=ntsec unless otherwise set.
+
+ * shared.cc (shared_name): Only add build date to shared name when
+ *testing*.
+
+2002-08-24 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (DLL_IMPORTS): Move libuuid.a and libshell32.a to list
+ rather than referring to them via -l. Add DLL imports last in link
+ line for new-cygwin.dll and cygrun.exe.
-Sat Sep 15 00:28:40 2001 Christopher Faylor <cgf@cygnus.com>
+2002-08-19 Christopher Faylor <cgf@redhat.com>
- * Makefile.in: Generate libcygwin.a during the link pass rather than as
- a separate dlltool step.
- * dcrt0.cc (_dll_crt0): pppid_handle could be NULL. Don't close it if
- so.
+ * pinfo.h (pinfo::remember): Arrange for destructor call if
+ proc_subproc returns error.
+ * sigproc.cc (zombies): Store 1 + total zombies since proc_subproc uses
+ NZOMBIES element.
-Fri Sep 14 20:48:18 2001 Christopher Faylor <cgf@cygnus.com>
+2002-08-19 Corinna Vinschen <corinna@vinschen.de>
+
+ * pwdgrp.h (pwdgrp_read::pwdgrp_read): Remove.
+ (pwdgrp_read::~pwdgrp_read): Ditto.
+ (pwdgrp_read::open): Reset fh to NULL instead of INVALID_HANDLE_VALUE.
+ (pwdgrp_read::close): Ditto.
+
+2002-08-19 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler.h (fhandler_console::send_winch_maybe): New method.
+ * fhandler_console.cc (set_console_state_for_spawn): Remove if 0'ed
+ code.
+ (fhandler_console::send_winch_maybe): Define new method.
+ (fhandler_console::read): Use send_winch_maybe where appropriate.
+ (fhandler_console::init): Just call all tcsetattr rather than
+ output_tcsetattr.
+ * select.cc (peek_console): Reorganize so that send_winch_maybe is
+ called for everything but keyboard input.
+
+2002-08-18 Christopher Faylor <cgf@redhat.com>
+
+ * perthread.h (vfork_save): Add ctty, sid, pgid, exitval fields.
+ (vfork_save::restore_pid): New method.
+ (vfork_save::restore_exit): New method.
+ * fork.cc (vfork): Save ctty, sid, pgid and restore them when returning
+ to "parent". Use exitval field if exiting but never created a new
+ process.
+ * syscalls.cc (setsid): Detect when in "vfork" and force an actual fork
+ so that pid will be allocated (UGLY!).
+ (getsid): New function.
+ * dcrt0.cc (do_exit): Use vfork_save::restore_exit method for returning
+ from a vfork.
+ * spawn.cc (spawnve): Use vfork_save::{restore_pid,restore_exit}
+ methods for returning from vfork.
+ * cygwin.din: Export getsid.
+ * include/cygwin/version.h: Bump api minor number.
+
+ * malloc.cc: #ifdef sYSTRIm for when MORECORE_CANNOT_TRIM is true.
+
+2002-08-18 Christopher Faylor <cgf@redhat.com>
+
+ * cygmalloc.h (MORECORE_CANNOT_TRIM): Define.
+
+2002-08-18 Christopher Faylor <cgf@redhat.com>
+
+ * sigproc.cc (sigCONT): Define.
+ * sigproc.h (sigCONT): Declare.
+ (wait_sig): Create sigCONT event here.
+ * exceptions.cc (sig_handle_tty_stop): Wait for sigCONT event rather
+ than stopping thread.
+ (sig_handle): Set sigCONT event as appropriate on SIGCONT rather than
+ calling ResumeThread.
+
+2002-08-17 Christopher Faylor <cgf@redhat.com>
+
+ * malloc.cc: Update to 2.7.2.
+ * malloc_wrapper.cc (malloc_init): Call user level mallocs to determine
+ if the malloc routines have been overridden.
+
+2002-08-16 Christopher Faylor <cgf@redhat.com>
+
+ * winsup.h: Remove malloc_*lock functions.
+
+2002-08-16 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Add support for new malloc.o and renamed
+ malloc_wrapper.o. Use -fomit-frame-pointer for malloc.o compilation.
+ * malloc_wrapper.cc: New file. Rename from malloc.cc. Add support for
+ more malloc functions. Eliminate export_* calls. Just use straight
+ malloc names. Remove unused argument from malloc lock functions.
+ * cygwin.din: Just export straight malloc names. Add malloc_stats,
+ malloc_trim, malloc_usable_size, mallopt, memalign, valloc.
+ * dcrt0.cc (__cygwin_user): Eliminate export_* malloc entries.
+ * fork.cc (fork_parent): Remove unused argument from malloc_lock
+ argument.
+ * malloc.cc: New file. Doug Lea's malloc v2.7.1.
+ * cygmalloc.h: New file.
+ * include/cygwin/version.h: Bump API_MINOR.
- * dcrt0.cc (dll_crt0_1): Create vfork main storage here so that it can
- be queried in waitsig later.
- * sigproc.cc (wait_sig): Don't deliver a signal if in a vfork.
- * sigproc.h (sigframe::init): New method.
- (sigframe): Use init.
- * perthread.h: Declare main_vfork.
- * fork.cc (vfork): Deliver all signals on parent return from vfork.
+ * sync.h (muto::acquire): Use appropriate number for regparm attribute.
+ (muto::reset): Ditto.
+ (muto::release): Ditto.
+
+2002-08-16 Pavel Tsekov <ptsekov@gmx.net>
+
+ * exceptions.cc (interrupt_setup): Ensure that the previous signal mask
+ is properly saved.
+
+2002-08-15 Thomas Pfaff <tpfaff@gmx.net>
+
+ * dcrt0.cc: Modify define for CYGWIN_GUARD.
+ (alloc_stack_hard_way): Just use CYGWIN_GUARD in VirtualAlloc call.
+
+2002-08-11 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler.h (fhandler_socket::recv): Remove method.
+ (fhandler_socket::send): Ditto.
+ * fhandler_socket.cc (fhandler_socket::recv): Ditto.
+ (fhandler_socket::send): Ditto.
+ (fhandler_socket::read): Delegate to fhandler_socket::recvfrom.
+ (fhandler_socket::write): Delegate to fhandler_socket::sendto.
+ (fhandler_socket::sendto): Check for null `to' address.
+ * net.cc (cygwin_sendto): Check for zero request length.
+ (cygwin_recvfrom): Ditto. Fix signature, use void *buf.
+ (cygwin_recv): Delegate to cygwin_recvfrom.
+ (cygwin_send): Delegate to cygwin_sendto.
+
+2002-08-11 Christopher Faylor <cgf@redhat.com>
+
+ * cygthread.cc (cygthread::cygthread): Close another race.
+
+2002-08-11 Christopher Faylor <cgf@redhat.com>
+
+ * assert.cc (__assert): Call debugger on assertion failure if
+ debugging.
+ * dcrt0.cc (dll_crt0_1): Just wait for signal thread to go live rather
+ than going through the overhead of invoking it.
+ * fork.cc (fork_child): Ditto.
+ * exceptions.cc (signal_fixup_after_fork): Call sigproc_init here.
+ * sigproc.cc (proc_can_be_signalled): Assume that the signal thread is
+ live.
+ (sig_dispatch): Ditto.
+ (sig_send): Ditto.
+ (wait_for_sigthread): Rename from "wait_for_me". Assume that
+ wait_sig_inited has been set and that this function is only called from
+ the main thread.
+ * sigproc.h (wait_for_sigthread): Declare new function.
+
+2002-08-08 Christopher Faylor <cgf@redhat.com>
-Fri Sep 14 10:21:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * environ.cc (parse_options): Remember the "no" part of any options for
+ later export.
- * dcrt0.cc (_dll_crt0()): Don't call wincap.init() here.
+2002-08-07 Conrad Scott <conrad.scott@dsl.pipex.com>
-Fri Sep 14 00:37:54 2001 Christopher Faylor <cgf@cygnus.com>
+ * winsup.h (__check_null_invalid_struct): Make ptr argument non-const.
+ (__check_null_invalid_struct_errno): Ditto.
+ * miscfuncs.cc (__check_null_invalid_struct): Ditto.
+ (__check_null_invalid_struct_errno): Ditto.
+ (__check_invalid_read_ptr_errno): Remove superfluous cast.
+ * net.cc (get): Set appropriate errno if fd is not a socket.
+ (cygwin_sendto): Fix parameter checking.
+ (cygwin_recvfrom): Ditto.
+ (cygwin_setsockopt): Ditto.
+ (cygwin_getsockopt): Ditto.
+ (cygwin_connect): Ditto.
+ (cygwin_gethostbyaddr): Ditto.
+ (cygwin_accept): Ditto.
+ (cygwin_bind): Ditto.
+ (cygwin_getsockname): Ditto.
+ (cygwin_listen): Ditto.
+ (cygwin_getpeername): Ditto.
+ (cygwin_send): Ditto.
+ (cygwin_shutdown): Ditto. Move sigframe to fhandler_socket.
+ (cygwin_recvmsg): Fix parameter checking. Add tracing.
+ (cygwin_sendmsg): Ditto.
+ * fhandler_socket.cc (fhandler_socket::shutdown): Add sigframe.
+ * resource.cc (setrlimit): Fix parameter checking.
- * fork.cc (vfork): Avoid recursive vforks.
+2002-08-08 Joe Buehler <jbuehler@hekimian.com
-Fri Sep 14 00:18:52 2001 Christopher Faylor <cgf@cygnus.com>
+ * sec_helper.cc (sec_acl): remove extraneous arg to debug_printf.
- * fhandler.h (fhandler_pipe::is_slow): Return true only if pipes are
- reliable (i.e., not Win9x).
- * wincap.cc: Make statics NO_COPY to avoid fork overhead.
+2002-08-07 Conrad Scott <conrad.scott@dsl.pipex.com>
-Thu Sep 13 23:01:00 2001 Christopher Faylor <cgf@cygnus.com>
+ * fhandler_socket.cc (fhandler_socket::accept): Fix FIONBIO call.
- * grp.cc (read_etc_group): Just reuse group_buf storage for subsequent
- reread of /etc/group.
- * passwd.cc (read_etc_passwd): Just reuse passwd_buf storage for
- subsequent reread of /etc/passwd.
+2002-08-06 Christopher Faylor <cgf@redhat.com>
-Thu Sep 13 20:46:05 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygheap.cc (_csbrk): Avoid !cygheap considerations.
+ (cygheap_init): Deal with unintialized cygheap issues here.
+ (cheap_init): Move cygheap_max setting here.
- * cygheap.cc (dup_now): New function.
- (cygheap_setup_for_child): Accept new argument controlling whether to
- delay copying of cygheap to shared memory region.
- (cygheap_setup_for_child_cleanup): Accept new arguments controlling
- whether to copy cygheap at this point.
- * cygheap.h: Reflect above changes.
- * fork.cc (fork_parent): Break copying of cygheap into two parts when
- fork_fixup is required so that the child can see the parent's changes.
- (vfork): Do stack cleanup prior to forcing a fork error.
- * spawn.cc (spawn_guts): Ditto.
+2002-08-06 Christopher Faylor <cgf@redhat.com>
+ Conrad Scott <conrad.scott@dsl.pipex.com
-Thu Sep 13 17:14:59 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygheap.cc (_csbrk): Allocate some slop initially. Don't erroneously
+ add sbrk amount to returned value in initial case.
- * cygheap.cc (ccalloc): Pass correct length to creturn so that
- cygheap_max is correctly calculated.
+2002-08-06 Christopher Faylor <cgf@redhat.com>
-Wed Sep 12 21:06:38 2001 Christopher Faylor <cgf@cygnus.com>
+ * spawn.cc (spawn_guts): Don't set mount_h here.
+ * sigproc.cc (init_child_info): Set it here instead.
+ * shared.cc (cygwin_mount_h): Make NO_COPY.
- * sync.cc (muto::acquire): Fix while/if typo.
+2002-08-06 Christopher Faylor <cgf@redhat.com>
-Wed Sep 12 23:06:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * cygthread.cc (cygthread::stub): Accept flag to pass info structure to
+ thread function.
+ (cygthread::operator new): Add defensive debugging output.
+ (cygthread::cygthread): Add debugging output. Set name after thread
+ has been awakened to avoid a race.
+ (cygthread::exit_thread): Use handle operator rather than using ev
+ directly.
+ (cygthread::exit_thread): Reorganize to provide debugging. Set __name
+ to NULL.
+ * cygthread.h (cygself): Define.
+ * fhandler_tty.cc (fhandler_tty_master::init): Use cygself as argument
+ so that invoked thread can access its own info.
+ (process_output): Derive cygthread info of thread from thread argument.
+ * sigproc.cc (sigproc_init): Use cygself as argument so that invoked
+ thread can access its own info.
+ (wait_sig): Derive cygthread info of thread from thread argument.
- * wincap.cc (wincapc::init): Simplify W2K/XP case.
+2002-08-06 Conrad Scott <conrad.scott@dsl.pipex.com>
-Wed Sep 12 23:02:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * debug.h (handle_list::allocated): Remove field.
+ * debug.cc (newh): Don't malloc extra entries.
+ (add_handle): Downgrade strace message level.
+ (delete_handle): Remove case for `allocated' entries.
- * wincap.cc (wincapc::init): Set os name to "NT" on XP, too.
+2002-08-05 Christopher Faylor <cgf@redhat.com>
-Wed Sep 12 19:00:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * cygthread.cc (cygthread::stub): Change event creation to manual
+ reset. Set __name after calling SetEvent to prevent races.
+ (cygthread::detach): Always reset event here to prevent races.
- * Makefile.in: Build wincap.o.
- * wincap.cc: New file.
- * wincap.h: Ditto.
- * autoload.cc: Add dynamic load statement for `CreateHardLinkA'.
- * dcrt0.cc (os_being_run): Eliminated.
- (osname): Ditto.
- (iswinnt): Ditto.
- (set_os_type): Ditto.
- (dll_crt0_1): Call wincap.init() instead of set_os_type().
- (_dll_crt0): Ditto.
- * environ.cc (set_chunksize): New function.
- (parse_thing): `forkchunk' setting now invokes function `set_chunksize'.
- * fork.cc (chunksize): Eliminated. Moved to be member of wincap.
- * host_dependent.h: Removed.
- * syscalls.cc (_link): Try using `CreateHardLinkA' first, if available.
- * cygheap.cc, dcrt0.cc, delqueue.cc, dir.cc,
- environ.cc, fhandler.cc, fhandler.h, fhandler_console.cc,
- fhandler_mem.cc, fork.cc, mmap.cc, net.cc, pinfo.cc, pinfo.h,
- security.cc, syscalls.cc, sysconf.cc, syslog.cc, thread.cc,
- times.cc, tty.cc, uinfo.cc, uname.cc, winsup.h: Use new wincap
- capability check throughout.
- * winsup.h: Include wincap.h. Eliminate extern declarations of
- `os_being_run' and `iswinnt'. Eliminate `os_type" definition.
- * include/cygwin/version.h: Bump version to 1.3.4.
-
-Wed Sep 12 01:03:36 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (call_signal_handler_now): Add additional guard against
- inappropriately calling signal handler.
- * syscalls.cc (_read): Reset errno if not exiting due to signal.
-
-Wed Sep 12 13:03:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * autoload.cc (LoadDLLfuncEx): Auto load TryEnterCriticalSection - it's
- an NT only call.
- * thread.cc (pthread_cond::TimedWait): Use critical sections for NT.
- (pthread_cond::fixup_after_fork): Don't detect bad apps.
- (pthread_mutex::pthread_mutex): Use critical sections for NT.
- (pthread_mutex::~pthread_mutex): Ditto.
- (pthread_mutex::Lock): Ditto.
- (pthread_mutex::TryLock): Ditto.
- (pthread_mutex::UnLock): Ditto.
- (pthread_mutex::fixup_after_fork): Ditto. Also do not detect bad apps.
- (__pthread_mutex_trylock): Move WIN32 specific test into the class
- method.
- (__pthread_mutex_destroy): Prevent dereferencing passed pointer without
- valid address.
- * thread.h (pthread_mutex): Use critical sections for NT.
+2002-08-03 Conrad Scott <conrad.scott@dsl.pipex.com>
-Tue Sep 11 21:55:37 2001 Christopher Faylor <cgf@cygnus.com>
+ * debug.h (WaitForMultipleObjects): Correct typo.
- * sigproc.h (sigframe::unregister): Return true/false whether this
- frame is capable of responding to signals.
- * exceptions.cc (sigframe::call_signal_handler): Don't call signal
- handler if it is not armed for this thread.
+2002-08-01 Pierre Humblet <Pierre.Humblet@ieee.org>
-Tue Sep 11 11:23:10 2001 Christopher Faylor <cgf@cygnus.com>
+ * security.cc (verify_token): Do not reject a token just because
+ the supplementary group list is missing Everyone or a groupsid
+ equal to usersid, or because the primary group is not in the token,
+ as long as it is equal to the usersid.
+ * syscalls.cc (seteuid32): Use common code for all successful returns.
+ * grp.cc (getgroups32): Never includes Everyone in the output.
- * cygwin.din: Remove cygwin_getshared.
- * shared.cc: Ditto.
- * include/cygwin/version.h: Bump API minor number.
+2002-08-01 Christopher Faylor <cgf@redhat.com>
-Tue Sep 11 11:14:11 2001 Dmitry Timoshkov <dmitry@baikal.ru>
-
- * dtable.cc (dtable::build_fhandler): Fix incorrect test for socket.
-
-Tue Sep 11 21:22:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.cc (pthread_cond::~pthread_cond): Fix incorrect use of
- InterlockExchangePointer.
- (pthread_mutex::~pthread_mutex): Ditto.
- (semaphore::~semaphore): Ditto.
-
-Tue Sep 11 18:15:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * dcrt0.cc (cygwin_finished_initializing): Copy _mtinterf on fork.
- * fork.cc (fork_child): Fixup thread-related structures after fork.
- * thread.cc (MTinterface::Init): Initialise the new mutex, condition
- and semaphore lists.
- (MTinterface::fixup_after_fork): Iterate through each list and fixup
- the objects.
- (pthread_cond::pthread_cond): Add this to the condition list.
- (pthread_cond::~pthread_cond): Remove this from the condition list.
- (pthread_cond::fixup_after_fork): Recreate as best we can the pre-fork
- state.
- (pthread_mutex::pthread_mutex): Add this to the mutex list.
- (pthread_mutex::~pthread_mutex): Remove this from the mutex list.
- (pthread_mutex::fixup_after_fork): Recreate as best we can the pre-fork
- state.
- (semaphore::semaphore): Store the initial value, and add this to the
- semaphore list.
- (semaphore::~semaphore): Remove this from the semaphore list.
- (semaphore::Post): Increment the current semaphore value.
- (semaphore::TryWait): Decrement the current semaphore value.
- (semaphore::Wait): Ditto.
- (semaphore::fixup_after_fork): Recreate the pre-fork state as best we
- can.
- * thread.h (pthread_mutex): New members to allow fixup_after_fork.
- (pthread_cond): Ditto.
- (semaphore): Ditto.
- (MTinterface): New list heads for tracking conds and semaphores.
-
-Sun Sep 9 22:11:27 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dtable.cc (dtable::fixup_after_fork): Use SetStdHandle appropriately
- on inherited fds.
-
-Sun Sep 9 20:09:11 2001 Christopher Faylor <cgf@cygnus.com>
-
- * sigproc.cc (NZOMBIES): Reduce substantially to minimize memory use.
-
-Mon Sep 10 08:28:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.h (MT_Interface): Remove pshared mutex array. Add a
- threadsafe list for mutex tracking (for fixup after fork).
- * thread.cc (MTInterface::Init): Remove pshared mutex array.
- (pthread_mutex::pthread_mutex): Remove pshared mutex functionality.
- Fail with EINVAL on attempts to use pshared functionality.
- (__pthread_mutex_getpshared): Remove.
- (__pthread_cond_timedwait): Remove pshared mutex functionality.
- (__pthread_cond_wait): Ditto.
- (__pthread_mutex_init): Ditto.
- (__pthread_mutex_getprioceiling): Ditto.
- (__pthread_mutex_lock): Ditto.
- (__pthread_mutex_trylock): Ditto.
- (__pthread_mutex_unlock): Ditto.
- (__pthread_mutex_destroy): Ditto.
- (__pthread_mutex_setprioceiling): Ditto.
- (__pthread_mutexattr_setpshared): Ditto.
-
-Sun Sep 9 23:09:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * pwdgrp.h (pwdgrp_check::set_last_modified): Call GetFileTime()
- instead of GetFileInformationByHandle().
-
-Sun Sep 9 15:59:53 2001 Christopher Faylor <cgf@cygnus.com>
-
- * heap.h (inheap): Rewrite macro to accomodate removal of brk macros
- below.
+ * cygthread.cc (cygthread::exit_thread): Define new method.
+ * cygthread.h (cygthread::exit_thread): Declare new method.
+ * fhandler.h (fhandler_tty_master::hThread): Delete.
+ (fhandler_tty_master::output_thread): Define.
+ * fhandler_tty.cc (fhandler_tty_master::fhandler_tty_master): Adjust
+ constructor.
+ (fhandler_tty_master::init): Use cygthread rather than handle.
+ (process_output): Use cygthread method to exit.
+ (fhandler_tty_master::fixup_after_fork): Set output_thread to NULL
+ after fork.
+ (fhandler_tty_master::fixup_after_exec): Set output_thread to NULL
+ after spawn/exec.
+ * tty.cc (tty_list::terminate): Detach from output_thread using
+ cygthread method.
+
+2002-08-01 Christopher Faylor <cgf@redhat.com>
+
+ * syscalls.cc (_link): Revert previous change and just always
+ dereference the oldpath.
+
+2002-08-01 Christopher Faylor <cgf@redhat.com>
+
+ * syscalls.cc (link): Properly deal with a link to a symlink.
+
+2002-08-01 Christopher Faylor <cgf@redhat.com>
+
+ * cygthread.cc: Remove cruft.
+
+2002-08-01 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (DLL_OFILES): Add cygthread.o.
+ * dcrt0.cc (dll_crt0_1): Eliminate various thread initialization
+ functions in favor of new cygthread class.
+ * debug.cc: Remove thread manipulation functions.
+ * debug.h: Ditto.
+ * external.cc (cygwin_internal): Use cygthread method for determining
+ thread name. Remove capability for setting thread name.
+ * fhandler_console.cc (fhandler_console::read): Use cygthread method
+ rather than iscygthread function.
+ * fhandler_tty.cc (fhandler_tty_master::fhandler_tty_master): Use
+ cygthread methods to create threads.
+ (fhandler_tty_common::__acquire_output_mutex): Use cygthread method to
+ retrieve thread name.
+ * select.cc (pipeinf): Use cygthread pointer rather than handle.
+ (start_thread_pipe): Ditto.
+ (pipe_cleanup): Ditto.
+ (serialinf): Ditto.
+ (start_thread_serial): Ditto.
+ (serial_cleanup): Ditto.
+ (socketinf): Ditto.
+ (start_thread_socket): Ditto.
+ (socket_cleanup): Ditto.
+ * sigproc.cc (hwait_sig): Ditto.
+ (hwait_subproc): Ditto.
+ (proc_terminate): Ditto.
+ (sigproc_terminate): Ditto.
+ (sigproc_init): Initialize cygthread hwait_sig pointer.
+ (subproc_init): Initialize cygthread hwait_subproc pointer.
+ (wait_sig): Rely on cygthread HANDLE operator.
+ * strace.cc (strace::vsprntf): Use cygthread::name rather than threadname.
+ * window.cc (gethwnd): Use cygthread method to initialize thread.
-Sun Sep 9 15:02:44 2001 Christopher Faylor <cgf@cygnus.com>
+2002-07-31 Conrad Scott <conrad.scott@dsl.pipex.com>
- * cygheap.cc (cygheap_fixup_in_child): Clear cygheap->base so that heap
- is not forced to start at the same place in execed process.
- * heap.cc: Remove brk* macros for clarity throughout.
- * heap.h: Ditto.
- * shared.cc (shared_info::initialize): Move heap_chunk test into
- heap_chunk_size().
- (heap_chunk_size): Check for chunk size here. Don't go to registry if
- heap_chunk_in_mb is already set.
+ * fhandler.h (fhandler_base::get_r_no_interrupt): Make non-virtual.
+ * net.cc (fdsock): Call set_r_no_interrupt.
- * smallprint.c (console_printf): Add Windows 95 concessions.
+2002-07-30 Christopher Faylor <cgf@redhat.com>
-Sun Sep 9 13:01:06 2001 Christopher Faylor <cgf@cygnus.com>
+ * syscalls.cc (_read): Clarify debugging output.
- * child_info.h (PROC_MAGIC): Bump magic number.
+2002-07-30 Christopher Faylor <cgf@redhat.com>
-Sun Sep 9 18:36:00 2001 Corinna Vinschen <corinna@vinschen.de>
- Christopher Faylor <cgf@cygnus.com>
+ * fhandler.h (fhandler_base::get_r_no_interrupt): Make virtual.
- * cygheap.cc (init_cygheap::etc_changed): New method to signal
- a change in /etc.
- * cygheap.h (struct init_cygheap): Add member `etc_changed_h'
- and method `etc_changed'.
- * grp.cc (enum grp_state): Eliminate.
- (class grp_check): Ditto.
- (group_state): Define as `class pwdgrp_check'.
- (parse_grp): Remeber path and modification time of /etc/group file.
- * passwd.cc (enum_pwd_state): Eliminate.
- (class pwd_check): Ditto.
- (passwd_state): Define as `class pwdgrp_check'.
- (read_etc_passwd): Remember path and modification time of /etc/passwd
- file.
- * pwdgrp.h: New file.
- (enum pwdgrp_state): Substitutes `pwd_state' and `grp_state'.
- (class pwdgrp_check): Substitutes `pwd_check' and `grp_check'.
+2002-07-30 Christopher Faylor <cgf@redhat.com>
-Sun Sep 9 14:31:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * fhandler_disk_file.cc (fhandler_cygdrive::set_drives): Incorporate .
+ and .. processing here.
+ (fhandler_cygdrive::readdir): Assume . and .. are already in pdrive.
+ (fhandler_cygdrive::seekdir): Ditto.
- * include/cygwin/version.h: Bump API minor version to 45 according
- to adding the gamm*_r functions.
+2002-07-29 Christopher Faylor <cgf@redhat.com>
-Sat Sep 8 23:32:18 2001 Christopher Faylor <cgf@cygnus.com>
+ * dcrt0.cc (dll_crt0_1): Move debug_fixup_after_fork_exec.
+ * cygheap.cc (cygheap_fixup_in_child): Call debug_fixup_after_fork_exec
+ immediately after cygheap has been set up.
- * fork.cc (fork_parent): Stop malloc activity while fork is in control
- of the heap.
- * sigproc.cc (NZOMBIES): Rename from ZOMBIEMAX for clarity.
- (zombies): Revert to original behavior. Allocating zombie array
- resulted in performance hit.
- * winsup.h: Declare malloc lock routines.
+2002-07-29 Corinna Vinschen <corinna@vinschen.de>
-Fri Sep 7 21:35:35 2001 Christopher Faylor <cgf@cygnus.com>
+ * security.cc: Change some formatting.
+ * include/cygwin/version.h: Bump API minor version.
- * cygwin.din: Add gamm*_r function exports.
+2002-07-28 Pierre Humblet <Pierre.Humblet@ieee.org>
-Fri Sep 7 17:11:11 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygheap.h (class cygheap_user): Add member groups.
+ * security.h (class cygsidlist): Add members type and maxcount, methods
+ position, addfromgr, alloc_sids and free_sids and operator+= (const
+ PSID psid). Modify contains () to call position () and optimize add ()
+ to use maxcount.
+ (class user_groups): Create. Update declarations of verify_token and
+ create_token.
+ * security.cc (cygsidlist::alloc_sids): New.
+ (cygsidlist::free_sids): New.
+ (get_token_group_sidlist): Create from get_group_sidlist.
+ (get_initgroups_sidlist): Create from get_group_sidlist.
+ (get_group_sidlist): Suppress.
+ (get_setgroups_sidlist): Create.
+ (verify_token): Modify arguments. Add setgroups case.
+ (create_token): Modify arguments. Call get_initgroups_sidlist and
+ get_setgroups_sidlist as needed. Set SE_GROUP_LOGON_ID from auth_pos
+ outside of the loop. Rename the various group sid lists consistently.
+ * syscalls.cc (seteuid32): Modify to use cygheap->user.groups.
+ (setegid32): Call cygheap->user.groups.update_pgrp.
+ * grp.cc (setgroups): Create.
+ (setgroups32): Create.
+ * uinfo.cc (internal_getlogin): Initialize and update
+ user.groups.pgsid.
+ * cygwin.din: Add setgroups and setgroups32.
- * cygheap.h (init_cygheap): Move heap pointers here.
- * include/sys/cygwin.h (perprocess): Remove heap pointers.
- * dcrt0.cc (__cygwin_user_data): Reflect obsolete perprocess stuff.
- (_dll_crt0): Don't initialize heap pointers.
- (cygwin_dll_init): Ditto.
- (release_upto): Use heap pointers from cygheap.
- * heap.h: Ditto.
- * fork.cc (fork_parent): Ditto. Don't set heap pointers in ch.
- (fork_child): Remove obsolete sigproc_fixup_after_fork.
- * shared.cc (memory_init): Reorganize so that cygheap initialization is
- called prior to regular heap since regular heap uses cygheap now.
- * sigproc.cc (proc_subproc): Eliminate zombies allocation.
- (sigproc_init): Move zombies alloation here. Don't free up array on
- fork, just reuse it.
- (sigproc_fixup_after_fork): Eliminate.
- * sigproc.h: Ditto.
- * include/cygwin/version.h: Reflect change to perprocess structure.
+2002-07-28 Christopher Faylor <cgf@redhat.com>
-Fri Sep 7 10:53:34 2001 Jason Tishler <jason@tishler.net>
+ * fhandler_console.cc (fhandler_console::read): Use appropriate
+ kill_pgrp method.
+ * select.cc (peek_console): Ditto.
+ * fhandler_termios.cc (fhandler_termios::bg_check): Send "stopped"
+ signal to entire process group as dictated by SUSv3.
+ * termios.cc (tcsetattr): Detect when stopped signal sent and force a
+ stop before setting anything.
+
+2002-07-26 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/version.h: Bump API version to indicate that ntsec is
+ on by default now.
+
+2002-07-26 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler_registry.cc (fhandler_registry::close): Return any error
+ result to the caller.
+ * syscalls.cc (_close): Return result of fhandler::close to the caller.
+
+2002-07-25 Christopher Faylor <cgf@redhat.com>
- * poll.cc (poll): Change implementation to only call select() when no
- invalid file descriptors are specified.
+ * security.cc (allow_ntsec): Default to on.
+ (allow_smbntsec): Default to off.
-Fri Sep 7 10:27:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-24 David MacMahon <davidm@smartsc.com>
- * include/limits.h: Define PIPE_BUF.
- * syscalls.cc (fpathconf): Use PIPE_BUF instead of numerical constant.
- (pathconf): Ditto.
+ * times.cc (to_time_t): Always round time_t down to nearest second.
-Thu Sep 6 20:04:05 2001 Christopher Faylor <cgf@cygnus.com>
+2002-07-25 Egor Duda <deo@logos-m.ru>
- * fhandler_socket.cc (fhandler_socket::fhandler_socket): Ensure that
- prot_info_ptr is zeroed for later use.
+ * Makefile.in: Check if API version is updated when exports are
+ changed and stop if not so.
-Thu Sep 6 14:03:49 2001 Christopher Faylor <cgf@cygnus.com>
+2002-07-24 Egor Duda <deo@logos-m.ru>
- * cygheap.cc (cygheap_fixup_in_child): Don't consider a NULL bucket as
- a candidate for deletion. It is actually the end of a linked list
- chain.
+ * include/cygwin/version.h: Bump minor API version.
- * exceptions.cc (open_stackdumpfile): Default to "unknown" program name
- if myself->progname hasn't been filled out yet.
+2002-07-24 Corinna Vinschen <corinna@vinschen.de>
-Thu Sep 6 01:16:44 2001 Christopher Faylor <cgf@cygnus.com>
+ * fhandler_serial.cc: Change 'must_init_serial_line capability'
+ to 'supports_reading_modem_output_lines' throughout (negated meaning).
+ * wincap.cc: Ditto.
+ * wincap.h: Ditto.
- Move appropriate variables to NO_COPY segment, throughout.
+2002-07-23 Nicholas Wourms <nwourms@netscape.net>
-Thu Sep 6 00:40:35 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygwin.din (fcloseall): Add symbol for export.
+ (fcloseall_r): Ditto.
- Remove initialization of static or global values to zero, throughout.
- This just needlessly grows the size of the DLL.
- * tty.cc (tty::alive): Make inuse handle non-inheriting on open, just
- for thread safety.
+2002-07-24 Christopher Faylor <cgf@redhat.com>
-Wed Sep 5 23:36:03 2001 Christopher Faylor <cgf@cygnus.com>
+ * path.cc (path_conv::check): Always set fileattr when component == 0.
+ (readlink): Use path_conv method rather than field.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_helper): Ditto,
+ throughout.
+ * path.h (path_conv): Make fileattr private.
+ * exceptions.cc (try_to_debug): Default to idle priority when looping.
- * cygheap.h (init_cygheap): Move bucket array here from cygheap.cc.
- * cygheap.cc: Throughout use bucket array from cygheap.
+2002-07-23 Corinna Vinschen <corinna@vinschen.de>
- * sigproc.cc (proc_subproc): Dynamically allocate zombie buffer to save
- DLL space.
- (sigproc_fixup_after_fork): Free zombie array after a fork.
- * sigproc.h (sigproc_fixup_after_fork): Declare.
+ * fhandler_serial.cc: Use must_init_serial_line capability throughout.
+ * wincap.cc: Set flag must_init_serial_line appropriately.
+ * wincap.h: Add flag must_init_serial_line.
-2001-09-06 Egor Duda <deo@logos-m.ru>
+2002-07-23 Corinna Vinschen <corinna@vinschen.de>
- * dir.cc (mkdir): Expand buffer for security descriptor to 4K to avoid
- stack corruption.
- * fhandler.cc (fhandler_base::open): Ditto.
- * path.cc (symlink): Ditto.
+ * security.cc (get_group_sidlist): Create group list from /etc files
+ even if DC is available but access fails.
-Wed Sep 5 21:35:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-22 Christopher Faylor <cgf@redhat.com>
- * winver.rc: Change copyright to include 2001.
+ * fhandler_serial.cc: Fix formatting problems introduced by below
+ changes.
-Wed Sep 5 12:12:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-22 Jacek Trzcinski <jacek@certum.pl>
- * fhandler_floppy.cc (fhandler_floppy::lseek): Remove iswinnt check.
+ * fhandler.h (class fhandler_serial): Add new members of the class -
+ rts,dtr and method ioctl(). Variables rts and dtr important for Win 9x
+ only.
+ * fhandler_serial.cc (fhandler_serial::open): Add initial setting of
+ dtr and rts. Important for Win 9x only.
+ (fhandler_serial::ioctl): New function. Implements commands TIOCMGET,
+ TIOCMSET and TIOCINQ.
+ (fhandler_serial::tcflush): Fix found error.
+ (fhandler_serial::tcsetattr): Add settings of rts and dtr. Important
+ for Win 9x only.
+ * termios.h: Add new defines as a support for ioctl() function on
+ serial device.
+
+2002-07-20 Christopher Faylor <cgf@redhat.com>
+
+ * autoload.cc (LoadDLLprime): Add jmp call to allow streamlining of
+ later jmp rewrite.
+ (doit): Avoid use of cx register. Just change one word to avoid races.
+
+2002-07-18 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * security.cc (get_unix_group_sidlist): Create.
+ (get_supplementary_group_sidlist): Evolve into get_unix_group_sidlist.
+ (get_user_local_groups): Add check for duplicates.
+ (get_user_primary_group): Suppress.
+ (get_group_sidlist): Silently ignore PDC unavailability.
+ Call get_unix_group_sidlist() before get_user_local_groups().
+ Remove call to get_supplementary_group_sidlist(). Never call
+ get_user_primary_group() as the passwd group is always included.
+ Add well_known_authenticated_users_sid in only one statement.
+
+2002-07-19 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_serial.cc (fhandler_serial::tcflush): Fix typo.
+
+2002-07-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * security.cc (get_group_sidlist): Fix formatting.
+
+2002-07-14 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (initial_env): Force path and CYGWIN_DEBUG contents to lower
+ case.
+ * exceptions.cc (error_start_init): Use the name derived from
+ GetModuleName rather than myself->progname.
+
+2002-07-14 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (dll_crt0_1): Move debug_init call back to here. Avoid a
+ compiler warning.
+ * shared.cc (memory_init): Remove debug_init call.
+ * debug.h (handle_list): Change "clexec" to "inherited".
+ * debug.cc: Remove a spurious declaration.
+ (setclexec): Conditionalize away since it is currently unused.
+ (add_handle): Use inherited field rather than clexec.
+ (debug_fixup_after_fork_exec): Ditto. Move debugging output to
+ delete_handle.
+ (delete_handle): Add debugging output.
+ * fhandler.cc (fhandler_base::set_inheritance): Don't bother setting
+ inheritance in debugging table since the handle was never protected
+ anyway.
+ (fhandler_base::fork_fixup): Ditto.
+
+ * exceptions.cc (debugger_command): Revert.
+
+2002-07-14 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * debug.cc (clexec): Add missing `hl = hl->next'.
+
+2002-07-14 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (cygrun.exe): Add a -lcygwin on the end.
+
+2002-07-14 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (cygserver.exe): Add -lstdc++.
+ (cygrun.exe): Move -lgcc last.
+
+2002-07-13 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (dll_crt0_1): Delay closing of some handles until cygheap
+ has been set up.
+ (break_here): New function, for debugging.
+ (initial_env): Add program name to "Sleeping" message. Implement new
+ "CYGWIN_DEBUG" environment variable option.
+ * exceptions.cc (debugger_command): Add argument to dumper call.
+ * strace.cc (strace::hello): Use winpid if cygwin pid is unavailable.
+ (strace::vsprntf): Ditto.
+
+2002-07-13 Christopher Faylor <cgf@redhat.com>
+
+ * debug.h (handle_list): Move here from debug.cc. Add "inherit" flag
+ functionality.
+ * cygheap.cc (init_cheap): Move cygheap_max calculation to _csbrk.
+ (_csbrk): Reorganize to not assume first allocation is <= 1 page.
+ (cygheap_setup_for_child): Mark protected handle as inheritable.
+ * cygheap.h (cygheap_debug): New struct.
+ (init_cygheap): Add new structure when debugging.
+ * dcrt0.cc (dll_crt0_1): Remove call to debug_init. Close ppid_handle
+ here, if appropriate. Don't protect subproc_ready, since it is already
+ protected in the parent. Call memory_init prior to ProtectHandle to
+ ensure that cygheap is set up. Call debug_fixup_after_fork_exec when
+ appropriate.
+ (_dll_crt0): Don't close ppid_handle here.
+ * debug.cc: Use cygheap debug structure rather than static elements
+ throughout.
+ (add_handle): Don't issue a warning if attempt to protect handle in
+ exactly the same way from exactly the same place. Add pid info to
+ warning output. Accept additional argument controlling whether handle
+ is to be inherited. Add pid to stored information.
+ (debug_fixup_after_fork_exec): Renamed from debug_fixup_after_fork.
+ Reorganize to avoid erroneously skipping handles.
+ (mark_closed): Add pid info to warning output.
+ (setclexec): Rename from setclexec_pid.
+ * fhandler.cc (fhandler_base::get_default_fmode): Minor reorg.
+ (fhandler_base::fstat): Add debugging output.
+ (fhandler_base::set_inheritance): Call setclexec rather than
+ setclexec_pid.
+ (fhandler_base::fork_fixup): Ditto.
+ * fhandler_console.cc (get_tty_stuff): Mark protected handle as
+ inheritable.
+ * fhandler_tty.cc (fhandler_tty_slave::open): Ditto.
+ * tty.cc (tty::make_pipes): Ditto.
+ (tty::common_init): Ditto.
+ * fork.cc (fork_parent): Ditto.
+ (fork_child): Close protected handles with correct name. Remove
+ debug_fixup_after_fork call.
+ * fhandler_socket.cc (fhandler_socket::create_secret_event): Mark
+ protected handle as inheritable/non-inheritable, as appropriate.
+ * shared.cc (memory_init): Mark protected handle as inheritable.
+ Call debug_init here.
+ * sigproc.cc (wait_sig): Close protected handle with correct name.
+ * spawn.cc (spawn_guts): Rename spr to subproc_ready and mark it as
+ inheritable.
+
+ * exceptions.cc (debugger_command): Try to run dumper.exe, if found.
+
+ * syscalls.cc (fstat64): Don't follow symlinks for path_conv lookup
+ since path is already resolved.
+
+2002-07-12 Christopher Faylor <cgf@redhat.com>
+
+ * cygwin.din: Change erroneous entries.
-Wed Sep 5 11:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-11 Pavel Tsekov <ptsekov@gmx.net>
+
+ * fhandler_disk_file.cc (fhandler_disk_file::open): Don't
+ move the file pointer to the end of file if O_APPEND is
+ specified in the open flags.
- * fhandler_socket.cc (fhandler_socket::close): Change 2MSL value
- according to MSDN.
+2002-07-09 Christopher Faylor <cgf@redhat.com>
-Wed Sep 5 10:14:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * debug.cc: Avoid explicit zeroing of globals.
+ (lock_debug): Make locker a static member. Avoid unlocking when
+ already unlocked (from Conrad Scott).
+ (debug_init): Initialize lock_debug::locker here.
+ * fork.cc (fork_child): Fix up fdtab earlier to avoid some (but not
+ all) confusion with close-on-exec craziness.
- * net.cc (cygwin_connect): Add WSAEALREADY and WSAEINVAL handling
- for non-blocking sockets.
+2002-07-05 Corinna Vinschen <corinna@vinschen.de>
-Tue Sep 4 22:42:13 2001 Christopher Faylor <cgf@cygnus.com>
+ * fhandler.h (fhandler_socket::is_unconnected): Constify.
+ (fhandler_socket::is_connect_pending): Ditto.
+ (fhandler_socket::is_connected): Ditto.
+ (fhandler_socket::set_connect_state): New method.
+ (struct select_record): Add member `except_on_write'.
+ (select_record::select_record): Initialize all bool values to `false'.
+ * fhandler_socket.cc: Use set_connect_state() method throughout.
+ (fhandler_socket::connect): Set state always to connected if connection
+ isn't pending.
+ * net.cc (cygwin_getsockopt): Revert erroneous previous patch.
+ * select.cc (set_bits): Check for `except_on_write'. Set fd in
+ write_fds if set. Set connect state to connected if fd has been
+ returned by WINSOCK_SELECT.
+ (peek_socket): Check for `except_on_write'.
+ (start_thread_socket): Ditto.
+ (fhandler_socket::select_write): Don't set `write_ready' if connect
+ is pending. Set `except_on_write' if connect is pending.
- * exceptions.cc (ctrl_c_handler): Only send SIGINT when we have a
- controlling terminal and we are the head of the process group.
+2002-07-05 Christopher Faylor <cgf@redhat.com>
-Tue Sep 4 16:48:14 2001 Christopher Faylor <cgf@cygnus.com>
+ * ntdll.h (_SYSTEM_PROCESSOR_TIMES): Force eight byte alignment.
+ (_SYSTEM_TIME_OF_DAY_INFORMATION): Ditto.
- * thread.cc (InterlockedExchangePointer): Don't define if it already
- exists.
+ * path.cc (suffix_scan::has): Reorganize to eliminate double scanning
+ for for .exe (in the typical case).
-Tue Sep 4 22:14:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-05 Corinna Vinschen <corinna@vinschen.de>
- * uname.cc (uname): Eliminate os specific retrieving of x86
- processor type.
+ * fhandler.h (UNCONNECTED): New define.
+ (CONNECT_PENDING): Ditto.
+ (CONNECTED): Ditto.
+ (class fhandler_socket): Add member `had_connect_or_listen'.
+ Add member functions `is_unconnected', `is_connect_pending' and
+ `is_connected'.
+ * fhandler_socket.cc (fhandler_socket::connect): Set member
+ `had_connect_or_listen' according to return code of WinSock
+ call.
+ (fhandler_socket::listen): Ditto.
+ * net.cc (cygwin_getsockopt): Modify SO_ERROR return value in
+ case of socket with pending connect().
+ * select.cc (peek_socket): Only add socket to matching fd_set
+ if it's not "ready". Call WINSOCK_SELECT only if at least one
+ socket is in one of the fd_sets.
+ (start_thread_socket): Only add socket to matching fd_set
+ if it's not "ready".
+ (fhandler_socket::select_write): Set write_ready to true also
+ if socket isn't connected or listening.
-2001-09-04 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
+2002-07-04 Corinna Vinschen <corinna@vinschen.de>
- * fhandler_console.cc (fhandler_console::char_command): Save the cursor
- position relative to the top of the window.
- * fhandler_cc (fhandler_console::write): Ditto.
+ * fhandler_socket.cc (fhandler_socket::set_sun_path): Don't free
+ memory here. Allow NULL parameter.
-Mon Sep 3 21:06:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-04 Corinna Vinschen <corinna@vinschen.de>
- * dir.cc (opendir): Write version information to __d_dirent->d_version.
+ * fhandler_socket.cc (fhandler_socket::dup): Add missing copy operation
+ on sun_path.
-Mon Sep 3 18:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-07-03 Christopher Faylor <cgf@redhat.com>
- * cygwin.din: Add `dirfd'.
- * dir.cc (dirfd): New function.
- (opendir): Open a directory file descriptor and save it in
- __d_dirent->d_fd.
- (closedir): Close directory file descriptor.
- * include/cygwin/version.h: Bump API minor version to 44.
+ * include/cygwin/version.h: Bump DLL minor number.
-Sun Sep 2 22:09:31 2001 Christopher Faylor <cgf@cygnus.com>
+2002-07-03 Christopher Faylor <cgf@redhat.com>
- * child_info.h: Modify magic number.
- * dcrt0.cc (_cygwin_testing): Define.
- (_dll_crt0): Set _cygwin_testing if CYGWIN_TESTING environment variable
- exists. Don't issue "conflicting versions" error if _cygwin_testing is
- true.
- * shared.cc (shared_name): Use _cygwin_testing global rather than
- testing the environment.
- * syscalls.cc (_write): Remove debugging info.
+ * include/sys/statfs.h: New header file.
-Sat Sep 1 01:37:13 2001 Christopher Faylor <cgf@cygnus.com>
+2002-07-03 Christopher Faylor <cgf@redhat.com>
- * tty.cc (tty::create_inuse): Eliminate unneeded argument.
- * tty.h: Reflect above change.
- * fhandler_tty.cc: Reflect argument reduction in tty::create_inuse,
- throughout. Always make inuse inheritable.
+ * dtable.cc (cygwin_attach_handle_to_fd): Default to implicit bin mode
+ if none specified.
+ * fhandler.cc (fhandler_base::init): Make bin argument a guarantee
+ rather than a suggestion.
+ * path.cc (path_conv::check): Load flag returned from
+ cygwin_conv_to_win32_path into path_flags.
-Sat Sep 1 01:10:07 2001 Christopher Faylor <cgf@cygnus.com>
+2002-07-03 Conrad Scott <conrad.scott@dsl.pipex.com>
- * debug.cc (mark_closed): Rename from debug_mark_closed and make
- static.
- (setclexec_pid): New function for marking saved handle as
- close-on-exec.
- (delete_handle): New function.
- (debug_fixup_after_fork): New function.
- * debug.h: Declare new functions, remove obsolete ones.
- * fork.cc (debug_fixup_after_fork): Call to cleanup close-on-exec
- handles.
+ * tty.cc (tty::common_init): Reverse logic of cygserver check in
+ call to SetKernelObjectSecurity.
- * fhandler.cc (fhandler_disk_file::close): Minor reorg.
- (fhandler_base::set_inheritance): Set flag appropriately for debugging
- when close-on-exec so forked process can delete closed handles.
- * tty.h (open_output_mutex): Eliminate unneeded argument.
- (open_input_mutex): Ditto.
- * fhandler_tty.cc (fhandler_tty_slave::open): reflect open_*_mutex
- argument changes.
- * fhandler.h (fhandler_socket): Make saw_shutdown_* functions type
- bool.
- * tty.cc (tty::get_event): Eliminate unneeded argument.
- (tty::common_init): Reflect change to get_event. Events should always
- be inherited.
-
-Fri Aug 31 21:39:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * security.cc (create_token): Change initialization of `exp' to comply
- with new LARGE_INTEGER definition in winnt.h.
-
-Fri Aug 31 13:58:51 2001 Christopher Faylor <cgf@cygnus.com>
-
- * cygwin.sc: Revert to previous NO_COPY behavior.
- * winsup.h: Ditto.
- * sigproc.cc: Ditto.
- * autoload.cc: Ditto.
-
-Fri Aug 31 00:56:26 2001 Christopher Faylor <cgf@cygnus.com>
-
- * cygwin.sc: New file -- linker script for building cygwin DLL.
- * Makefile.in: Use linker script to control location of cygheap.
- * cygheap.cc (buckets): Make static.
- (init_cheap): Remove special iswinnt handling. Allocate cygheap at a
- fixed location. Display more info when allocation fails.
- (cygheap_fixup_in_child): Try harder to move cygheap to correct
- location. Display more info when allocation fails.
- * fhandler.h (fhandler_socket): Add macros for tracking socket shutdown
- state.
- * net.cc (cygwin_shutdown): Set appropriate shutdown value for future
- use.
- * select.cc (select_stuff::cleanup): New method.
- (cygwin_select): Call cleanup explicitly to avoid a race.
- (select_stuff:~select_stuff): Call cleanup chain via cleanup method.
- (fhandler_socket::select_read): Set *_ready when shutdown has been
- called on the socket.
- (fhandler_socket::select_write): Ditto.
- (fhandler_socket::select_except): Ditto.
-
- * winsup.h: Move NO_COPY to "COMMON" section.
- * autoload.cc (wsock_started): Avoid initializing NO_COPY value.
- * sigproc.cc: Remove initialization from NO_COPY variables.
- (sigproc_init): Initialize sig_loop_wait here, rather than via
- initialization.
- (subproc_init): Initialize proc_loop_wait here, rather than via
- initialization.
-
-Thu Aug 30 10:19:00 2001 Christopher Faylor <cgf@cygnus.com>
-
- * select.cc (select_read): Add setting read_ready flag.
- (select_write): Add setting write_ready flag.
-
-Wed Aug 29 00:40:42 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (path_conv::check): Avoid splitting off leading '/' in path
- component when building a symlink.
-
-Wed Aug 29 0:45:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * resource.cc (getrlimit): Return actual values on RLIMIT_STACK.
-
-Tue Aug 28 16:37:17 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dir.cc (rmdir): Report ENOENT when file doesn't exist rather than
- ENOTDIR.
-
-Mon Aug 27 11:58:19 2001 Christopher Faylor <cgf@cygnus.com>
-
- * select.cc (cygwin_select): Ensure that arguments are zeroed on
- timeout.
- (select_stuff::wait): Ditto.
-
-2001-08-24 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * syscalls.cc (check_tty_fds): New function. Check whether there is a
- fd referring to pty slave.
- (setsid): Don't detach console if the process has a pty slave.
-
-Fri Aug 24 8:54:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (free_addr_list): Add define for symmetry.
- (free_hostent_ptr): Use free_addr_list to free h_addr_list element.
-
-Thu Aug 23 16:00:09 2001 Jason Tishler <jason@tishler.net>
-
- * net.cc (dup_addr_list): New static function.
- (dup_hostent_ptr): Use dup_addr_list instead of dup_char_list in order
- to handle embedded null characters.
-
-Wed Aug 22 22:23:14 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dtable.cc (dtable::dup2): Allow extension of fd table by dup2.
- * syscalls.cc: Minor code cleanup.
- (fpathconf): Check for bad fd before doing anything else.
- * termios.cc (tcsetattr): Don't convert to new termios if bad fd.
- (tcgetattr): Minor debugging tweak.
-
-Wed Aug 22 23:41:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (cygwin_inet_ntoa): Rearrange previous patch to use
- thread local buffer space when compiled thread safe.
- (cygwin_getprotobyname): Ditto.
- (cygwin_getprotobynumber): Ditto.
- (cygwin_getservbyname): Ditto.
- (cygwin_getservbyport): Ditto.
- (cygwin_gethostbyname): Ditto.
- (cygwin_gethostbyaddr): Ditto. Move near to cygwin_gethostbyname.
- * thread.h (struct _winsup_t): Add pointers for above used buffer space.
- * passwd.cc (getpwduid): Remove initializing passwd.
- (setpwent): Ditto.
- (endpwent): Ditto.
- (setpassent): Ditto.
-
-Wed Aug 22 13:41:09 2001 Christopher Faylor <cgf@cygnus.com>
-
- * smallprint.c (console_printf): New function.
- * dcrt0.cc (dll_crt0_1): Use console_printf for debugging output.
- * debug.cc (debug_mark_closed): New function.
- (close_handle): Use debug_mark_closed.
- * debug.h: Declare new functions.
- * dtable.cc (dtable::build_fhandler): Remove unneeded extern.
- * spawn.cc: Cosmetic changes.
- * winsup.h: Define NO_COPY for C files, too. Declare a global.
-
-Wed Aug 22 17:31:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (free_char_list): New static function.
- (dup_char_list): Ditto.
- (free_protoent_ptr): Ditto.
- (dup_protoent_ptr): Ditto.
- (free_servent_ptr): Ditto.
- (dup_servent_ptr): Ditto.
- (free_hostent_ptr): Ditto.
- (dup_hostent_ptr): Ditto.
- (cygwin_inet_ntoa): Use local static buffer to allow propagating of
- the result to child processes.
- (cygwin_getprotobyname): Ditto.
- (cygwin_getprotobynumber): Ditto.
- (cygwin_getservbyname): Ditto.
- (cygwin_getservbyport): Ditto.
- (cygwin_gethostbyname): Ditto.
- (cygwin_gethostbyaddr): Ditto.
+2002-07-03 Thomas Pfaff <tpfaff@gmx.net>
-Mon Aug 20 11:56:19 2001 Christopher Faylor <cgf@cygnus.com>
+ * autoload.cc (WSAEventSelect): Define new autoload function.
+ (WSAEnumNetworkEvents): Ditto.
+ * fhandler_socket.cc (fhandler_socket::accept): If socket is
+ in blocking mode wait for incoming connection and signal.
- * cygheap.cc (init_cheap): Allocate cygheap in shared memory for Windows NT.
+2002-07-02 Christopher Faylor <cgf@redhat.com>
-Thu Aug 16 09:38:59 2001 Jason Tishler <jason@tishler.net>
+ * cygheap.cc (init_cheap): Rearrange error message.
+ (cygheap_fixup_in_child): Ditto.
+ * dtable.cc: Remove if 0'ed code.
+ * fhandler_dsp.cc (fhandler_dev_dsp::open): Force binmode.
+ * sec_helper.cc (cygsid::get_id): Use system_printf for error message.
+ * tty.cc (tty::common_init): Ditto.
- * fhandler_socket.cc (fhandler_socket::create_secret_event): Relax
- security of secret_event so AF_UNIX socket clients can connect to
- servers even if running under a different user account.
- (fhandler_socket::check_peer_secret_event): Ditto.
+2002-07-02 Christopher Faylor <cgf@redhat.com>
-Thu Aug 16 16:26:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * net.cc (cygwin_getpeername): Defend against NULL pointer dereference.
- * resource.cc (getrlimit): Return getdtablesize () as current limit
- on RLIMIT_NOFILE.
- * syscalls.cc (getdtablesize): Return OPEN_MAX if current dtable size
- is less than OPEN_MAX, the current dtable size otherwise.
- * sysconf.cc (sysconf): Return getdtablesize () on _SC_OPEN_MAX.
+2002-07-02 Egor Duda <deo@logos-m.ru>
-Thu Aug 16 16:17:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * include/cygwin/version.h: Bump API minor version.
- * resource.cc (getrlimit): Return OPEN_MAX as current limit
- on RLIMIT_NOFILE.
- * syscalls.cc (getdtablesize): Return OPEN_MAX.
- * sysconf.cc (sysconf): Return OPEN_MAX on _SC_OPEN_MAX.
- * include/limits.h (OPEN_MAX): Define as 256.
+2002-07-01 Pierre Humblet <pierre.humblet@ieee.org>
-Wed Aug 15 12:43:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * security.cc (get_logon_server): Interpret a zero length
+ domain as the local domain.
+ (get_group_sidlist): Add authenticated users SID to SYSTEM's group
+ list instead of SYSTEM itself.
+ (verify_token): Accept the primary group sid if it equals
+ the token user sid.
- * times.cc (utimes): Revert previous change. Just open the
- file using FILE_WRITE_ATTRIBUTES instead of GENERIC_WRITE
- on NT/W2K.
+2002-07-02 Corinna Vinschen <corinna@vinschen.de>
-Wed Aug 15 12:18:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * cygwin.din (__fpclassifyd): Add symbol.
+ (__fpclassifyf): Ditto.
+ (__signbitd): Ditto.
+ (__signbitf): Ditto.
- * security.cc (set_nt_attribute): Return always -1 in case of
- a failure.
- * times.cc (utimes): On NTFS with ntsec ON, change the file's
- security descriptor temporarily to acquire write access if
- opening the file failed.
+2002-07-02 Corinna Vinschen <corinna@vinschen.de>
-Wed Aug 15 9:42:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * security.h (DONT_INHERIT): Eliminate definition.
+ (INHERIT_ALL): Ditto.
+ (INHERIT_ONLY): Ditto.
+ * sec_acl.cc: Use appropriate defines from accctrl.h instead of the
+ above throughout.
+ * security.cc: Ditto.
- * fhandler.cc (fhandler_base::is_nonblocking): New method.
- (fhandler_base::set_nonblocking): Ditto.
- * fhandler.h (fhandler_base): Declare new methods `is_nonblocking' and
- `set_nonblocking'.
- * fhandler_socket.cc (fhandler_socket::ioctl): Use `set_nonblocking'.
- * fhandler_tty.cc (fhandler_pty_master::process_slave_output):
- Use `is_nonblocking'.
- (fhandler_tty_slave::read): Ditto.
- (fhandler_tty_slave::ioctl): Use `set_nonblocking'.
- (fhandler_pty_master::ioctl): Ditto.
- * net.cc (cygwin_sendto): Fallback to winsock 1 functionality
- in case of nonblocking IO.
- (cygwin_recvfrom): Ditto.
- (cygwin_recv): Ditto.
- (cygwin_send): Ditto.
- * syscalls.cc (_read): Use `is_nonblocking'.
+2002-07-01 Pierre Humblet <pierre.humblet@ieee.org>
-Tue Aug 14 11:05:26 2001 Christopher Faylor <cgf@cygnus.com>
+ * syscalls.c (seteuid32): Return immediately if the program is not
+ impersonated and both uid and gid are original.
+ (setegid32): Return immediately if the new gid is the current egid.
- * include/cygwin/version.h: Bump API version.
+2002-07-01 Christopher Faylor <cgf@redhat.com>
-2001-08-14 Egor Duda <deo@logos-m.ru>
+ * syscalls.cc (seteuid32): Fix incorrect placement of Pierre's patch
+ below.
- * spawn.cc (spawn_guts): Enable appropriate privilege before
- loading user's registry hive.
+2002-07-01 Christopher Faylor <cgf@redhat.com>
-Mon Aug 13 22:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * syscalls.cc (seteuid32): Fix incorrect use of system_printf.
- * fhandler.cc (fhandler_base::fcntl): Use new O_NONBLOCK_MASK define.
- * fhandler.h: Move definitions of O_NOSYMLINK, O_DIROPEN and
- OLD_O_NDELAY from winsup.h to here. Add O_NONBLOCK_MASK define.
- * fhandler_socket.cc (fhandler_socket::close): Add hack to allow
- a graceful shutdown even if shutdown() hasn't been called by the
- application. Add debug output.
- (fhandler_socket::ioctl): Set fhandler's NONBLOCK flag according
- to FIONBIO setting.
- (fhandler_socket::fcntl): Use new O_NONBLOCK_MASK define. Actually
- set `request' before using it.
- * fhandler_tty.cc: Use new O_NONBLOCK_MASK define throughout.
- (fhandler_tty_slave::ioctl): Set fhandler's NONBLOCK flag according
- to FIONBIO setting.
- (fhandler_pty_master::ioctl): Ditto.
- * net.cc (wsock_event::prepare): Compare WSACreateEvent return code
- with `WSA_INVALID_EVENT' according to MSDN.
- * syscalls.cc (_read): Use new O_NONBLOCK_MASK define.
+2002-07-02 Christopher January <chris@atomice.net>
-Wed Aug 8 15:24:59 2001 Christopher Faylor <cgf@cygnus.com>
+ * autoload.cc (GetSecurityInfo): Define new autoload function.
+ (RegQueryInfoKeyA): Ditto.
+ * fhandler.h (fhandler_virtual::fill_filebuf): Change return type to
+ bool.
+ (fhandler_proc::fill_filebuf): Ditto.
+ (fhandler_registry::fill_filebuf): Ditto.
+ (fhandler_process::fill_filebuf): Ditto.
+ (fhandler_registry::value_name): Add new member.
+ (fhandler_registry::close): Add new method.
+ (fhandler_process::p): Remove member.
+ * fhandler_proc.cc (fhandler_proc::open): Add set_nohandle after
+ calling superclass method. Check return value of fill_filebuf.
+ (fhandler_proc::fill_filebuf): Change return type to bool. Add return
+ statement.
+ * fhandler_process.cc (fhandler_process::open): Add set_nohandle after
+ calling superclass method. Remove references to p. Check return value
+ of fill_filebuf.
+ (fhandler_process::fill_filebuf): Change return type to bool. Don't
+ use dereference operator on p. Add return statement.
+ (fhandler_process::format_process_stat): Fix typo.
+ * fhandler_registry.cc: Add static open_key declaration.
+ (fhandler_registry::exists): Assume path is already normalised. Try
+ opening the path as a key in its own right first, before reverting to
+ enumerating subkeys and values of the parent key.
+ (fhandler_registry::fstat): Add additional code to return more relevant
+ information about the registry key/value.
+ (fhandler_registry::readdir): Explicitly set desired access when
+ opening registry key. Remove output of buf from debug_printf format
+ string.
+ (fhandler_registry::open): Use set_io_handle to store registry key
+ handle. Set value_name member. Move code to read a value from the
+ registry to fill_filebuf. Add call to fill_filebuf.
+ (fhandler_registry::close): New method.
+ (fhandler_registry::fill_filebuf): Change return type to bool. Add
+ code to read a value from registry.
+ (fhandler_registry::open_key): Make function static. Use KEY_READ as
+ desired access unless this is the last path component. Check the
+ return value of RegOpenKeyEx for an error instead of hKey.
+ * fhandler_virtual.cc (fhandler_virtual::lseek): Check the return value
+ of fill_filebuf.
+ (fhandler_virtual::open): Remove call to set_nohandle.
+ (fhandler_virtual::fill_filebuf): Change return type to bool. Add
+ return statement.
+ * security.cc (get_nt_object_attribute): New function.
+ (get_object_attribute): New function.
+ * security.h (get_object_attribute): New function declaration.
+
+2002-07-01 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * syscalls.c (seteuid32): Do not return an error when the token cannot
+ be created only because of a problem with the gid.
+
+2002-07-01 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_clipboard.c (fhandler_dev_clipboard::open): Force text mode.
+ * fhandler_console.cc (fhandler_console::open): *Really* force binary
+ mode rather than make it optional.
+ * fhandler_proc.cc (fhandler_proc::open): Ditto.
+ * fhandler_process.cc (fhandler_process::open): Ditto.
+ * fhandler_random.cc (fhandler_dev_random::fhandler_dev_random): Ditto.
+ * fhandler_raw.cc (fhandler_dev_raw::open): Ditto.
+ * fhandler_registry.cc (fhandler_registry::open): Ditto.
+ * fhandler_tty.cc (fhandler_tty_slave::open): Ditto.
+ * fhandler_virtual.cc (fhandler_virtual::open): Ditto.
+ * fhandler_windows.cc (fhandler_windows::open): Ditto.
+ * fhandler_zero.cc (fhandler_dev_zero::open): Ditto.
+ * net.cc (fdsock): Ditto.
+ * path.cc (set_flags): Add more debugging.
+
+2002-07-01 Christopher Faylor <cgf@redhat.com>
+
+ * debug.cc (threads): Avoid initialization.
+ * uinfo.cc (cygheap_user::ontherange): (from Corinna Vinschen) Actually
+ make below changes work.
+
+2002-07-01 Christopher Faylor <cgf@redhat.com>
+
+ * uinfo.cc (cygheap_user::ontherange): Make cygwin root the last resort
+ for HOMEPATH/HOMEDRIVE for consistency with HOME.
+
+2002-07-01 Corinna Vinschen <corinna@vinschen.de>
+
+ * shared.cc (sec_none): Move to sec_helper.cc.
+ (sec_none_nih): Ditto.
+ (sec_all): Ditto.
+ (sec_all_nih): Ditto.
+ (get_null_sd): Ditto.
+ (sec_acl): Ditto.
+ (__sec_user): Ditto.
+ * sec_helper.cc (sec_none): Move from shared.cc to here.
+ (sec_none_nih): Ditto.
+ (sec_all): Ditto.
+ (sec_all_nih): Ditto.
+ (get_null_sd): Ditto.
+ (sec_acl): Ditto.
+ (__sec_user): Ditto.
+
+2002-06-30 Christopher Faylor <cgf@redhat.com>
+
+ * uinfo.cc (cygheap_user::ontherange): Potentially set HOME from
+ existing homepath and homedrive cygheap_user fields (not currently used
+ yet). Set HOME to / if no other alternative.
+ (cygheap_user::test_uid): Simplify.
+
+2002-06-30 Christopher Faylor <cgf@redhat.com>
+
+ * environ.cc (parse_options): Use setenv to potentially replace CYGWIN
+ value on export. Fixes broken behavior since November 2000 changes.
+ (regopt): Return indication of whether or not something has been parsed
+ from the registry.
+ (environ_init): Only attempt to export CYGWIN variable when values were
+ set from the registry. It is exported automatically otherwise.
+
+2002-06-30 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler.h (fhandler_process::pid): New field.
+ (fhandler_process::fstat): Remove unneeded array. Set pid element.
+ (fhandler_process::open): Ditto.
+ (fhandler_process::fill_filebuf): Handle case where 'p' field is NULL.
+
+2002-06-30 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler.h (fhandler_process::p): New field.
+ (fhandler_process:fill_filebuf): Revert to same definition as virtual
+ in parent class.
+ (fhandler_process::open): Fill out p field rather than passing as an
+ argument.
+ (fhandler_process::fill_filebuf): Use p pointer rather than argument.
+
+2002-06-29 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * security.cc (extract_nt_dom_user): Check for all buffer overflows.
+ Call LookupAccountSid after trying to get domain & user from passwd.
+ (get_group_sidlist): Obtain the domain and user by calling
+ extract_nt_dom_user instead of LookupAccountSid.
+
+2002-06-29 Christopher Faylor <cgf@redhat.com>
+
+ * uinfo.cc (cygheap_user::test_uid): Use standard issetuid test.
+
+2002-06-29 Christopher Faylor <cgf@redhat.com>
+
+ * autoload.cc (NetGetDCName): Change to make this an optional load
+ function.
+ * cygheap.h (cygheap_user::logsrv): Return NULL when operation fails.
+ (cygheap_user::winname): Ditto.
+ (cygheap_user::domain): Ditto.
+ * uinfo.cc (cygheap_user::env_logsrv): Save results in temp variable.
+ (cygheap_user::env_userprofile): Ditto.
- * include/wchar.h: Define __need_wint_t.
+2002-06-29 Christopher Faylor <cgf@redhat.com>
-Wed Aug 8 11:46:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * environ.cc (spenv::retrieve): Detect return of env_dontadd from
+ cygheap_user methods.
+ (build_env): Avoid incrementing environment pointer if not actually
+ adding to the environment. That could result in garbage in the
+ environment table. Be more defensive when reallocing envblock.
- * security.cc (alloc_sd): Revert to setting inheritance attribute for
- permissions given to directories. Never set inheritance on NULL ACE.
+2002-06-29 Christopher Faylor <cgf@redhat.com>
-Tue Aug 7 18:11:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * uinfo.cc (cygheap_user::test_uid): Return NULL or further tests are
+ sorta useless.
+ (cygheap_user::env_domain): Recalculate if name is missing.
- * security.cc (alloc_sd): Don't set FILE_DELETE_CHILD for group
- if S_ISVTX attribute is given.
- * dir.cc (mkdir): Allow immediate setting of S_ISUID, S_ISGID and
- S_ISVTX attribute.
- * syscalls.cc (_open): Ditto.
+2002-06-29 Christopher Faylor <cgf@redhat.com>
-Tue Aug 7 16:24:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * environ.cc (spenv::from_cygheap): Still need to take setuid into
+ consideration.
- * dir.cc (mkdir): Set security attributes correctly for
- CreateDirectoryA () call if ntsec is on. Don't call
- set_file_attributes () then.
- * fhandler.cc (fhandler_base::open): Ditto for CreateFileA () call.
- * path.cc (symlink): Ditto.
- * security.cc (set_security_attribute): New function.
- * security.h: Add declaration for `allow_ntea' and
- `set_security_attribute'.
+2002-06-28 Christopher Faylor <cgf@redhat.com>
-Tue Aug 7 10:54:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * uinfo.cc (cygheap_user::env_logsrv): Return "almost_null" in case
+ where no domain or username is "SYSTEM".
- * grp.cc (class grp_check): New class. Make `group_state'
- a member of class grp_check.
- (read_etc_group): Free former allocated memory on reread.
- * passwd.cc (class pwd_check): New class Make `passwd_state'
- a member of class pwd_check.
- (read_etc_passwd): Free former allocated memory on reread.
+2002-06-28 Christopher Faylor <cgf@redhat.com>
-Tue Aug 7 01:13:58 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygheap.h (cygheap_user): Reorg to accommodate environment caching.
+ (cygheap_user::logsrv): New method.
+ (cygheap_user::winname): Ditto.
+ (cygheap_user::domain): Ditto.
+ (cygheap_user::test_uid): Ditto.
+ * cygheap.cc (cygheap_user::set_name): Reflect name "pwinname" name
+ change.
+ * environ.cc (getwinenveq): New function.
+ (penv::from_cygheap): penv::from_cygheap): Change arguments.
+ (spenv::retrieve): Ditto for call. Use getwinenveq to retrieve info
+ from environment. Always return value from cygwin environment, if it
+ exists.
+ * environ.h (getwinenveq): Declare.
+ * uinfo.cc (cygheap_user::ontherange): Use logsrv() rather than
+ env_logsrv().
+ (cygheap_user::test_uid): Define new method.
+ (cygheap_user::env_logsrv): Accept environment arguments. Use test_uid
+ to find info.
+ (cygheap_user::env_domain): Ditto.
+ (cygheap_user::env_userprofile): Ditto.
+ (cygheap_user::env_homepath): Ditto.
+ (cygheap_user::env_homedrive): Ditto.
+ (cygheap_user::env_name): Ditto.
+
+2002-06-27 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (cfree_and_set): New function.
+ (cygheap_user::set_name): Use cfree_and_set to reset members.
+ * cygheap.h (cygheap_user): Delete static members.
+ (cygheap_user::puserprof): New member.
+ (cfree_and_set): Declare.
+ * dcrt0.cc (almost_null): Define.
+ * environ.cc (env_dontadd): Redefine as "almost_null".
+ * winsup.h (almost_null): Declare.
+ * syscalls.cc (cfree_and_set): Remove unused variable.
+ * uinfo.cc (cygheap_user::homepath_env_buf): Eliminate.
+ (cygheap_user::homedrive_env_buf): Ditto.
+ (cygheap_user::userprofile_env_buf): Ditto.
+ (cygheap_user::ontherange): YA change to try to preserve existing
+ HOMEPATH and HOMEDRIVE. Return almost_null values when variables
+ should not actually exist.
+ (cygheap_user::env_logsrv): Ditto.
+ (cygheap_user::env_domain): Ditto.
+ (cygheap_user::env_userprofile): Ditto.
+
+2002-06-27 Corinna Vinschen <corinna@vinschen.de>
+
+ * dcrt0.cc (dll_crt0_1): Let __progname point to the applications
+ basename. Move eliminating ".exe" suffix from argv[0] so that it
+ always also affects __progname.
+
+2002-06-27 Thomas Pfaff <tpfaff@gmx.net>
+
+ * thread.cc (pthread::create): Add trace printf to get CreateThread
+ LastError.
+
+2002-06-27 Corinna Vinschen <corinna@vinschen.de>
+
+ * mmap.cc (list::match): Check using pagesize aligned size.
+
+2002-06-26 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_by_name): Force
+ FindFirstFile on first file of directory when asking for x:\ .
+
+2002-06-26 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (cygheap_user::set_name): Correct thinko in below change.
+
+2002-06-26 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (cygheap_user::set_name): Avoid clearing things when just
+ setting name to itself or during first time initialization.
+
+ * environ.cc (check_case_init): Make case insensitive.
+
+2002-06-26 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler.h (fhandler_socket::bind): Add method definition.
+ (fhandler_socket::connect): Ditto.
+ (fhandler_socket::listen): Ditto.
+ (fhandler_socket::accept): Ditto.
+ (fhandler_socket::getsockname): Ditto.
+ (fhandler_socket::getpeername): Ditto.
+ (fhandler_socket::recvfrom): Ditto.
+ (fhandler_socket::recvmsg): Ditto.
+ (fhandler_socket::sendto): Ditto.
+ (fhandler_socket::sendmsg): Ditto.
+ (fhandler_socket::shutdown): Ditto.
+ * fhandler_socket.cc (get_inet_addr): Move here from net.cc.
+ (fhandler_socket::bind): New method.
+ (fhandler_socket::connect): Ditto.
+ (fhandler_socket::listen): Ditto.
+ (fhandler_socket::accept): Ditto.
+ (fhandler_socket::getsockname): Ditto.
+ (fhandler_socket::getpeername): Ditto.
+ (fhandler_socket::recvfrom): Ditto.
+ (fhandler_socket::recvmsg): Ditto.
+ (fhandler_socket::sendto): Ditto.
+ (fhandler_socket::sendmsg): Ditto.
+ (fhandler_socket::shutdown): Ditto.
+ * net.cc: Various formatting cleanups throughout.
+ (get_inet_addr): Move to fhandler_socket.cc.
+ (cygwin_bind): Move base functionality to appropriate fhandler_socket
+ method.
+ (cygwin_connect): Ditto.
+ (cygwin_listen): Ditto.
+ (cygwin_accept): Ditto.
+ (cygwin_getsockname): Ditto.
+ (cygwin_getpeername): Ditto.
+ (cygwin_recvfrom): Ditto.
+ (cygwin_recvmsg): Ditto.
+ (cygwin_sendto): Ditto.
+ (cygwin_sendmsg): Ditto.
+ (cygwin_shutdown): Ditto.
+
+2002-06-26 Corinna Vinschen <corinna@vinschen.de>
+
+ * pwdgrp.h (pwdgrp_read::~pwdgrp_read): Avoid compiler warning.
+
+2002-06-26 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (_dcrt0): Be more defensive when reserved block is used and
+ it's not cygwin info.
+
+2002-06-26 Christopher Faylor <cgf@redhat.com>
+
+ * autoload (noload): Avoid clobbering bx register.
+
+ * environ.cc (codepage_init): Use case insensitive match.
+
+ * fhandler_console.cc (cp_get_internal): Delete.
+ (con_to_str): Use get_cp to derive code page.
+ (str_to_con): Ditto.
+ * miscfuncs.cc (get_cp): New function.
+ (sys_wcstombs): New function. Converted from macro.
+ (sys_mbstowcs): Ditto.
+ * winsup.h: Reflect above changes.
- * fhandler_console.cc (get_tty_stuff): Don't initialize shared memory
- console area if it is already initialized.
+2002-06-26 Christopher Faylor <cgf@redhat.com>
- * fhandler_termios.cc (fhandler_termios::tcsetpgrp): Augment debugging
- info.
+ * winsup.h: Minor cleanup.
+ * path.h (path_conv::[]): New operator.
+ * syscalls.cc (_link): Use path_conv operators rather than methods,
+ where appropriate. Minor white space cleanup.
-Mon Aug 6 19:58:43 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-26 Christopher Faylor <cgf@redhat.com>
- * cygheap.cc (cygheap_root::set): Avoid treating '/' specially.
+ * include/cygwin/version.h: Bump DLL minor number.
- * fhandler.cc (fhandler_base::fcntl): Only set specific O_NDELAY style
- flag passed in from application.
- * fhandler_socket.cc (fhandler_socket::fcntl): Ditto.
- * fhandler.h: Set constant for future use.
- * winsup.h: Define OLD_O_NDELAY only for old programs.
- * include/cygwin/version.h: Define
- CYGWIN_VERSION_CHECK_FOR_OLD_O_NONBLOCK.
+2002-06-25 Thomas Pfaff <tpfaff@gmx.net>
-Sat Aug 4 16:52:03 2001 Christopher Faylor <cgf@cygnus.com>
+ * include/pthread.h (PTHREAD_CANCELED): Define a reasonable value.
+ * pthread.cc (pthread_exit): Call method instead of function.
+ (pthread_setcancelstate): Ditto.
+ (pthread_setcanceltype): Ditto.
+ (pthread_testcancel): Ditto.
+ * thread.h (pthread::cancel_event): New member.
+ (__pthread_cancel_self): New prototype.
+ (pthread::exit): New Method.
+ (pthread::cancel): Ditto.
+ (pthread::testcancel): Ditto.
+ (pthread::cancel_self): Ditto.
+ (pthread::static_cancel_self): Ditto.
+ (pthread::setcancelstate): Ditto.
+ (pthread::setcanceltype): Ditto.
+ (__pthread_cancel): Give c++ linkage.
+ (__pthread_exit): Remove.
+ (__pthread_setcancelstate): Ditto.
+ (__pthread_setcanceltype): Ditto.
+ (__pthread_testcancel): Ditto.
+ * thread.cc (pthread::pthread): Inititialize cancel_event.
+ (pthread::~pthread): Close cancel_event if needed.
+ (pthread::create): Create cancel_event.
+ (pthread::exit): New method. Replacement for __pthread_exit.
+ (pthread::cancel): New method.
+ (pthread::testcancel): Ditto.
+ (pthread::static_cancel_self); New static method.
+ (pthread::setcancelstate): New method. Replacement for
+ __pthread_setcancelstate.
+ (pthread::setcanceltype): New method. Replacement for
+ __pthread_setcanceltype.
+ (pthread::pop_cleanup_handler): Add lock for async cancel safe
+ cancellation.
+ (pthread::thread_init_wrapper): Change __pthread_exit to
+ thread->exit().
+ (__pthread_cancel): Call method thread->cancel().
+ (__pthread_exit): Remove.
+ (__pthread_setcancelstate): Ditto.
+ (__pthread_setcanceltype): Ditto.
+ (__pthread_testcancel): Ditto.
- Throughout, change check for running under Windows NT to 'iswinnt'.
- * dcrt0.cc (set_os_type): Set 'iswinnt' appropriately.
- * cygheap.cc (init_cheap): Revert to using VirtualAlloc for allocating
- cygheap.
- (cygheap_setup_for_child_cleanup): New function. Standard function to
- call after calling CreateProcess to cleanup cygheap info passed to
- child.
- (cygheap_fixup_in_child): Copy cygheap from shared memory into
- allocated space under Windows 9x or if can't relocate shared space
- under NT.
- * cygheap.h: Declare new function.
- * spawn.cc (spawn_guts): Use cygheap_fixup_in_child.
- * fork.cc (fork_parent): Ditto.
- * winsup.h: Declare iswinnt.
+2002-06-25 Christopher Faylor <cgf@redhat.com>
-2001-08-04 Egor Duda <deo@logos-m.ru>
+ * dcrt0.cc (sm): Make NO_COPY.
- * dtable.cc (dtable::release): Avoid messing with console when
- closing socket.
+2002-06-25 Corinna Vinschen <corinna@vinschen.de>
-Fri Aug 3 14:02:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * syscalls.cc (chown): Convert uid to 32 bit.
+ (lchown): Ditto.
+ (fchown): Ditto.
- * net.cc (cygwin_accept): Allow NULL peer and len parameters.
- * include/cygwin/socket.h: Define socklen_t as int.
+2002-06-24 Christopher Faylor <cgf@redhat.com>
-Fri Aug 3 13:04:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * dtable.cc (dtable::find_unused_handle): Avoid coercion.
- * path.cc (fchdir): Set the fhandler's path to absolute value to ensure
- changing to the correct directory even if the fhandler originally
- points to a relative path.
+2002-06-24 Christopher Faylor <cgf@redhat.com>
-Thu Aug 2 17:59:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * dtable.cc (fhandler_base::dup2): Cleanup. Ensure that lock is turned
+ off in error condition.
- * security.cc (set_file_attribute): Clean up. Don't call
- `set_nt_attribute' when ntsec isn't set.
+2002-06-24 Corinna Vinschen <corinna@vinschen.de>
-Sat Jul 28 22:30:55 2001 Christopher Faylor <cgf@cygnus.com>
+ * uinfo.cc (internal_getlogin): Set myself->uid and myself->gid instead
+ of user.real_uid and user.real_gid.
+ (uinfo_init): Evaluate orig_uid and real_uid from myself->uid. Ditto
+ for gid.
- * dcrt0.cc (alloc_stack_hard_way): Make half-hearted attempt to deal
- with growing stack under Windows 95.
+2002-06-23 Pierre Humblet <pierre.humblet@ieee.org>
-Fri Jul 27 12:36:07 2001 Christopher Faylor <cgf@cygnus.com>
+ * security.cc (get_group_sidlist): Add pw argument and use pw->pw_name
+ in call to get_supplementary_group_sidlist.
+ (create_token): Add pw argument and use it in call to
+ get_group_sidlist.
+ * security.h: Add pw argument in declaration of create_token.
+ * syscalls.cc (seteuid32): Add pw argument in call to create_token.
- * Makefile.in: Add install-lib and install-headers.
+2002-06-23 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler.cc (fhandler_base::fstat): Set S_IFIFO for pipes.
+ * fhandler_socket.cc (fhandler_socket.cc::fstat): Set S_IFSOCK.
+
+2002-06-23 Christopher Faylor <cgf@redhat.com>
+
+ * lib/_cygwin_S_IEXEC.cc: Remove obsolete file.
+
+2002-06-23 Christopher Faylor <cgf@redhat.com>
+
+ Use cygwin_{shm,ipc}.h instead of /sys/{shm,ipc}.h throughout.
+ * sys/ipc.h: Remove.
+ * sys/shm.h: Remove.
+ * cygwin_ipc.h: New file.
+ * cygwin_shm.h: New file.
+
+2002-06-23 Christopher Faylor <cgf@redhat.com>
+
+ * cygwin.sc: Add recent changes from ld sources.
+
+2002-06-23 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * winsup.h: Move #ifdef EXPCGF code into "winbase.h".
+ * winbase.h: #ifdef EXPCGF code moved here from "winsup.h".
+
+2002-06-12 Thomas Pfaff <tpfaff@gmx.net>
+
+ * thread.h (pthread::cleanup_stack): Rename cleanup_handlers to
+ cleanup_stack.
+ * thread.cc (pthread::pthread): Ditto.
+ (pthread::create): Fix mutex verification.
+ (pthread::push_cleanup_handler): Renam cleanup_handlers to
+ cleanup_stack. Remvoe Mutex calls, use InterlockedExchangePointer
+ instead.
+ (pthread::pop_cleanup_handler): Rename cleanup_handlers to
+ cleanup_stack.
+ (pthread::pop_all_cleanup_handlers): Ditto.
+ (__pthread_once): Check state first and return if already done.
+ (__pthread_join): Revert DEADLOCK test to __pthread_equal call.
+ (__pthread_detach): Unlock mutex before deletion.
-Fri Jul 27 12:28:12 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-21 Christopher Faylor <cgf@redhat.com>
- * cygwin.din: Export sys_errlist, sys_nerr.
- * include/cygwin/version.h: Bump minor version number.
+ * Makefile.in (cygrun.exe): Move -lgcc where it will do some good.
-Fri 27 Jul 2001 10:29:00 Corinna Vinschen <corinna@vinschen.de>
+2002-06-21 Corinna Vinschen <corinna@vinschen.de>
- * security.cc (get_user_primary_group): Fix compiler warning.
- (alloc_sd): Add DELETE permission for user when S_IWUSR is given.
+ * syscalls.cc (stat64_to_stat32): Correctly evaluate st_rdev.
+ (fstat64): Set st_rdev to same value as st_dev.
+ (stat_worker): Ditto.
-Thu Jul 26 16:43:39 2001 Pieter de Visser <pieterdv@knoware.nl>
+2002-06-21 Corinna Vinschen <corinna@vinschen.de>
- * thread.cc (__pthread_equal): Invert return value so that true is
- returned when threads are equal.
+ * security.cc (alloc_sd): Carefully check owner_sid again after trying
+ SIDs from cygheap.
-Thu Jul 26 15:50:38 2001 Charles Wilson <cwilson@ece.gatech.edu>
- Christopher Faylor <cgf@cygnus.com>
+2002-06-21 Corinna Vinschen <corinna@vinschen.de>
- * cygwin.din: Export __signgam.
- * include/cygwin/version.h: Bump minor version number.
+ * security.cc (alloc_sd): Remove unnecessary retrieval of owner name.
+ Check uid for current user first and use SIDs from cygheap if so.
+ Set errno to EINVAL if user SID isn't retrievable. Just print user SID
+ as debug output.
+ Don't bail out if group SID isn't retrievable. Change debug output
+ appropriately.
-Thu Jul 26 15:19:50 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-21 Christopher Faylor <cgf@redhat.com>
- Throughout, reorganize header file inclusion to put security.h prior to
- fhandler.h.
- * fhandler.h (fhandler_base::get_inheritance): New method.
- * fhandler_socket.cc (fhandler_socket::create_secret_event): Use proper
- close-on-exec inheritance when creating.
- (fhandler_socket::check_peer_secret_event): Create handle as
- non-inheritable.
+ * errno.cc: Change text description for EBADF throughout.
-2001-07-25 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
+2002-06-20 Pierre Humblet <pierre.humblet@ieee.org>
- * syscalls.cc (setsid): Detach process from its console if the current
- controlling tty is the console and already closed.
- * dtable.h (class dtable): Add members to count descriptors referring
- to the console.
- * dtable.cc (dtable::dec_console_fds): New function to detach process
- from its console.
- (dtable::release): Decrement the counter of console descriptors.
- (dtable::build_fhandler): Increment it.
- * exception.cc (ctrl_c_handler): Send SIGTERM to myself when catch
- CTRL_SHUTDOWN_EVENT.
+ * uinfo.cc (cygheap_user::ontherange): Use env_name for NetUserGetInfo.
+ (cygheap_user::env_logsrv): Verify env_domain is valid.
+ * environ.cc: Include child_info.h and keep spenvs[] sorted.
+ (environ_init): Check child_proc_info instead of myself->ppid_handle.
-Tue 24 Jul 2001 02:28:00 PM Trevor Forbes <t4bs@hotmail.com>
+2002-06-19 Christopher Faylor <cgf@redhat.com>
- * thread.cc (verifyable_object_isvalid): Don't validate
- PTHREAD_MUTEX_INITIALIZER pointer as it will cause an exception
- in IsBadWritePtr() when running GDB.
-
-Wed 25 Jul 2001 23:46:00 Corinna Vinschen <corinna@vinschen.de>
+ * fhandler.cc (fhandler_base::set_flags): Change priority of "linked
+ in" default binmode setting so that it has priority over optional
+ setting.
- * localtime.c: Changed whole file to become C++ clean. Rename to
- localtime.cc.
- * localtime.cc (tzload): Preserve errno.
+2002-06-19 Christopher Faylor <cgf@redhat.com>
-Fri 20 Jul 2001 11:15:50 PM EDT Christopher Faylor <cgf@cygnus.com>
+ Use hMainProc where appropriate, throughout.
+ * environ.cc (spenv::retrieve): Add debugging statements.
- * cygheap.cc (cygheap_fixup_in_child): Attempt Win95 workaround.
- * dtable.cc (dtable::dup_worker): Add debugging output.
- (dtable::vfork_child_dup): Correctly set close_on_exec.
- * fhandler.cc (fhandler_base::fork_fixup): Don't mess with handle if
- there is no need to get it from the parent.
- * fhandler_tty.cc (fhandler_tty_common::close): Add debugging output.
+ * pinfo.cc (set_myself): Don't call strace.hello if already stracing.
+ * strace.cc (strace): Move NO_COPY keyword so that it will actually
+ take effect.
-Fri 20 Jul 2001 09:15:00 Mark Bradshaw <bradshaw@staff.crosswalk.com>
+2002-06-19 Corinna Vinschen <corinna@vinschen.de>
- * dir.cc (readdir): Protect FindNextFileA against INVALID_HANDLE_VALUE.
+ * uinfo.cc (cygheap_user::ontherange): Call NetUserGetInfo() only with
+ non-NULL logserver parameter.
-Wed 18 Jul 2001 01:00:47 PM EDT Christopher Faylor <cgf@cygnus.com>
+2002-06-16 Christopher Faylor <cgf@redhat.com>
- * cygheap.cc (_cmalloc): Use correct constants for size calculation.
- * dcrt0.cc (dll_crt0_1): Move uid initialization earlier.
- * fork.cc (fork_parent): Move cygheap_setup_in_child to just prior to
- CreateProcess so that all contents of cygheap are copied.
+ * cygheap.h (cygheap_user::issetuid): New method.
+ * dtable.cc (dtable::vfork_child_dup): Use new method to determine if
+ we are in "setuid mode."
+ * fork.cc (fork_parent): Ditto.
* spawn.cc (spawn_guts): Ditto.
+ * syscalls.cc (seteuid32): Ditto.
+ (setegid32): Ditto.
+ * environ.cc (spenv::retrieve): (Suggested by Pierre Humblet) Do
+ potential recalculation of cygheap_user stuff when in setuid mode.
+ Return special value when environment variable should be calculated but
+ not added.
+ (build_env): Don't add retrieved value to dstp if it is 'dont_add'.
+
+2002-06-16 Christopher Faylor <cgf@redhat.com>
+
+ Changes suggested by Pierre Humblet.
+ * environ.cc (NL): New macro.
+ (conv_envvars): Use NL macro to fill in name and namelen.
+ (spenv::namelen): New field.
+ (spenvs): Use NL to fill in name and namelen.
+ (spenv::retrieve): Eliminate length argument. Instead, use namelen
+ throughout.
+ (build_env): Don't calculate length of initial FOO= part of
+ environment. Accommodate spenv::retrive argument change.
-Wed 18 Jul 2001 12:54:17 Corinna Vinschen <corinna@vinschen.de>
-
- * security.cc (get_user_groups): Call Net function with NULL server
- name under specific error conditions.
- (is_group_member): Ditto.
- (get_user_local_groups): Ditto.
- (get_user_primary_group): Ditto.
-
-Wed 18 Jul 2001 11:56:00 Corinna Vinschen <corinna@vinschen.de>
-
- * syscalls.cc (_unlink): Explicitly check for non-existant file.
-
-Tue 17 Jul 2001 10:19:00 Corinna Vinschen <corinna@vinschen.de>
-
- * delqueue.h: Remove obsolete file.
-
-Mon 16 Jul 2001 10:47:17 PM EDT Christopher Faylor <cgf@cygnus.com>
-
- * child_info.h: Bump magic number.
- (class child_info): Add an element.
- * cygheap.cc (init_cheap): Allocate cygwin heap in shared memory area.
- (cygheap_fixup_in_child): Map cygwin heap, passed from parent via
- shared memory into correct address.
- (cygheap_setup_for_child): New function.
- * cygheap.h: Declare new functions.
- * dcrt0.cc (dll_crt0_1): Accomodate new cygheap_fixup_in_child
- arguments. Avoid protecting subproc_ready unless it is spawn/nowait.
- * fork.cc (fork_parent): Use new cygheap_setup_for_child function to
- setup cygwin heap info. Close passed cygheap shared memory handle.
- * spawn.cc (spawn_guts): Ditto. Also, reorganize to avoid
- synchronization between parent and child in non-P_OVERLAY case.
- * sigproc.cc (wait_sig): Only signal subproc_ready when execing.
-
-Mon 16 Jul 2001 15:21:00 Corinna Vinschen <corinna@vinschen.de>
-
- * grp.cc: Add missing Copyright date 2001.
-
-Mon 16 Jul 2001 00:11:00 Corinna Vinschen <corinna@vinschen.de>
-
- Change well_known_admin_sid to well_known_admins_sid throughout.
- * sec_acl.cc (setacl): Never set DELETE permission. Set
- FILE_DELETE_CHILD only on readable and executable directories.
- * sec_helper.cc: Add constructor for `well_known_null_sid'.
- * security.cc (get_nt_attribute): Set S_ISVTX for directories if
- FILE_WRITE_DATA and FILE_EXECUTE but not FILE_DELETE_CHILD is set.
- Add evaluation of S_ISVTX, S_ISGID and S_ISUID from NULL ACE.
- (alloc_sd): Never set DELETE permission. Set FILE_DELETE_CHILD
- only on readable and executable directories.
- Add creation of NULL ACE for S_ISVTX, S_ISGID and S_ISUID permissions.
- * security.h: Add extern declaration for `well_known_null_sid'.
-
-Fri 13 Jul 2001 08:08:49 PM EDT Christopher Faylor <cgf@cygnus.com>
-
- * syscalls.cc (stat_worker): Simplify previous change.
-
-Fri Jul 13 13:13:09 2001 Christopher Faylor <cgf@cygnus.com>
-
- * syscalls.cc (_unlink): Correct (?) logic which determines when
- to report an access violation and when to queue file for eventual
- deletion.
- (stat_worker): Check for invalid buf argument.
-
-Tue Jul 10 23:01:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * mmap.cc (fhandler_disk_file::mmap): Try to open file mappings
- by a unified name when running under 9x/ME. If that failes, create
- the file mapping using the unified name.
-
-Mon Jul 9 10:43:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (internal_getlogin): Add pointer check.
-
-Mon Jul 9 10:05:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * security.cc (alloc_sd): Don't set inheritance attribute for
- permissions given to directories.
-
-Thu Jun 28 22:19:08 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler_dsp.cc (fhandler_dev_dsp::ioctl): Return 0 for success.
-
-Wed Jun 27 22:19:07 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (path_conv::check): Add signal protection here since
- retrieving info about remote shares can take some time.
-
-Wed Jun 27 23:30:00 2001 Robert Collins <rbtcollins@hotmail.com>
- Christopher Faylor <cgf@cygnus.com>
-
- Change check_null_empty_path* to check_null_empty_str* throughout.
- * path.h (check_null_empty_str_errno): Convert to a function prototype.
- * path.cc (check_null_empty_str): Move to miscfuncs.cc.
- * miscfuncs.cc (check_null_empty_str_errno): New function.
- (__check_null_invalid_struct): Ditto.
- (__check_null_invalid_struct_errno): Ditto.
- (check_null_empty_str): Change from VirtualQuery to IsBadWritePtr.
- * thread.cc (check_valid_pointer): Ditto.
- * resource.cc (getrlimit): Use check_null_invalid_struct macro for
- checking validity of pointer.
- (setrlimit): Ditto.
-
-Tue Jun 26 16:59:16 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler.cc (fhandler_disk_file::fstat): Don't rely on exactly 3
- characters being read for executable test since we could be checking
- for less than that.
- * syscalls.cc (stat_worker): Try opening the file the "correct" way
- first so that #! processing can potentially happen. If that fails,
- then use "query open" method.
+2002-06-16 Christopher Faylor <cgf@redhat.com>
- * spawn.cc (spawn_guts): Delay processing of signal until after we've
- notified parent about reparenting.
+ * cygheap.h (cygheap_user::winname): New field.
+ * cygheap.cc (cygheap_user::set_name): Clear winname when name changes.
+ * uinfo.cc (cygheap_user::env_logsrv): Avoid calculating server when
+ Windows user == SYSTEM.
+ (cygheap_user::env_domain): Set winname here too.
+ (cygheap_user::env_userprofile): Eliminate superfluous tests.
+ (cygheap_user::env_name): Seed winname by calling env_domain().
-Tue Jun 26 10:47:24 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-12 Pierre Humblet <pierre.humblet@ieee.org>
- * mmap.cc: Clean up *ResourceLock calls throughout.
+ * spawn.cc (spawn_guts): Revert removal of ciresrv.moreinfo->uid =
+ ILLEGAL_UID.
-Tue Jun 26 22:10:00 2001 Robert Collins rbtcollins@hotmail.com
+2002-06-15 Christopher Faylor <cgf@redhat.com>
- * thread.cc (pthread_cond::TimedWait): Check for WAIT_TIMEOUT as well
- as WAIT_ABANDONED.
- (__pthread_cond_timedwait): Calculate a relative wait from the abstime
- parameter.
+ * child_info.h (child_proc_info): Declare as base class.
+ (spawn_info): Declare as alias of child_proc_info to aid debugging.
+ (fork_info): Ditto.
+ * cygheap.cc (cygheap_fixup_in_child): Use child_proc_info global
+ rather than parameter.
+ * cygheap.h (cygheap_fixup_in_child): Reflect above change in
+ declaration.
+ * dcrt0.cc (_dll_crt0): Move 'si' definition here. Assign
+ child_proc_info.
+ (dll_crt0_1): Accommodate cygheap_fixup_in_child and *_info changes.
+ * environ.cc (spenv::retrieve): Make regparm.
+ * environ.h (environ_init): Ditto.
+ (win_env::add_cache): Ditto.
+ (build_env): Ditto.
+ (getwinenv): Ditto.
+ * fork.cc (sync_with_parent): Use fork_info global.
+ (fork_child): Ditto.
+
+2002-06-14 Christopher Faylor <cgf@redhat.com>
+
+ * uinfo.cc (cygheap_user::ontherange): Don't set HOMEDRIVE or HOMEPATH
+ unless one or the other is specified.
+
+2002-06-14 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.h (cygheap_user::userprofile_env_buf): New static member.
+ * environ.cc (build_env): Add debugging statement.
+ (spenvs): Switch functions for USERDOMAIN and USERNAME.
+ * spawn.cc (spawn_guts): Move environment initialization prior to
+ cygheap_setup_for_child or environment info will never be copied to
+ child.
-Sun Jun 24 17:38:19 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-14 Christopher Faylor <cgf@redhat.com>
- * exceptions.cc (interrupt_setup): Move actions from setup_handler to
- here.
- (setup_handler): Move actions after a successful interrupt to
- interrupt_setup.
- * fork.cc (vfork): Augment debugging output.
- * sigproc.cc (proc_subproc): Ditto.
- * spawn.cc (spawn_guts): Ditto. Correctly fill out progname when spawn
- NO_WAIT. Call signal handler when a signal arrives.
- * sigproc.h: Declare a function.
+ * cygheap.h (cygheap_user): Add static members to hold home{drive,path}
+ info.
+ * uinfo.cc (cygheap_user::ontherange): Use static class members for
+ local HOME* storage.
+
+2002-06-14 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (cygheap_user::set_logsrv): Remove.
+ (cygheap_user::set_domain): Ditto.
+ * cygheap.h (cygheap_user::set_logsrv): Remove declaration.
+ (cygheap_user::set_domain): Ditto.
+ (cygheap_user::env_domain): Declare new method.
+ (cygheap_user::env_name): Ditto.
+ * environ.cc (spenvs): Add two environment variables.
+ * spawn.cc (spawn_guts): Call build_env after RevertToSelf. Always set
+ ciresrv.mount_h.
+ (cygheap_user::ontherange): Recalculate homedrive/homepath if they are
+ empty. Use env_logsrv to get logon server.
+ (cygheap_user::env_logsrv): Calculate server name here rather than
+ relying on it having been previously calculated.
+ (cygheap_user::env_domain): Ditto for domain name.
+ (cygheap-user::env_name): New method.
+
+2002-06-12 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * syscalls.cc (seteuid32): Do not get or set the environment. Do not
+ call LookupAccountSid nor internal_getlogin. Set cygheap->user name
+ and sid from the passwd entry.
+ * uinfo.cc (uinfo_init): Only call internal_getlogin when starting from
+ a non Cygwin process and use the values returned in user.
+ (internal_getlogin): Simplify to case where starting from a non Cygwin
+ process. Store return values in user and return void. Do not set the
+ Windows default environment.
+ * dcrt0.cc (dll_crt0_1): Call uinfo_init only when needed. Do not set
+ myself->uid nor reset user.sid.
+ * spawn.cc (spawn_guts): Get the sid from cygheap->user. Always
+ RevertToSelf(). Don't set uid in impersonated case.
+ * cygheap.cc (cygheap_user::set_sid): Do not set orig_sig.
+ (cygheap_user::set_orig_sid): New.
+ * cygheap.h: Declare cygheap_user::set_sid.
+ * winsup.h: Add argument to uinfo_init().
+
+2002-06-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * environ.cc (build_env): If realloc moves envblock, move s with it.
+
+2002-06-13 Nicholas S. Wourms <nwourms@netscape.net>
+
+ * winver.rc: Add more words to copyright.
+
+2002-06-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygheap.cc (cygheap_user::set_name): Revert previous change.
+ * environ.cc (spenv::retrieve): Check return value of call to
+ cygheap->user.*from_cygheap().
+
+2002-06-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygheap.cc (cygheap_user::set_name): Remove setting homedrive and
+ homepath to NULL.
+ (cygheap_user::set_logsrv): Fix free'ing of plogsrv.
+ * cygheap.h (cygheap_user::cygheap_user): Initialize homedrive and
+ homepath to NULL.
+
+2002-06-13 Christopher Faylor <cgf@redhat.com>
+
+ * security.cc (get_logon_server): Use strcasematch rather than
+ strcasecmp.
+
+2002-06-12 Christopher Faylor <cgf@redhat.com>
+
+ * path.cc (chdir): Minor cleanup.
+
+2002-06-12 Christopher Faylor <cgf@redhat.com>
+
+ * environ.cc (build_env): Correctly fill out windows environment block
+ with win32 paths rather than posix paths.
+
+2002-06-12 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (cygheap_user::set_name): Set homedrive and homepath to
+ NULL on user name change.
+ (cygheap_user::set_logsrv): Allocate enough space for leading \\ so
+ that we can put this in the environment, if needed.
+ * cygheap.h (homebodies): New enum.
+ (cygheap_user::homedrive): New field.
+ (cygheap_user::homepath): Ditto.
+ (cygheap_user::env_logsrv): New method.
+ (cygheap_user::env_homepath): New method.
+ (cygheap_user::env_homedrive): New method.
+ (cygheap_user::env_userprofile): New method.
+ (cygheap_user::ontherange): New method.
+ * environ.cc (envsize): Eliminate debugging argument.
+ (environ_init): Assume that envc counts number of elments not total
+ size.
+ (spenv): New class.
+ (spenvs): New array, rename from forced_winenv_vars, using spenv.
+ (spenv::retrieve): New method.
+ (build_env): Rename from 'winenv' -- one stop shopping for building new
+ environment blocks for both windows and "unix".
+ * environ.h (build_env: Declare.
+ (winenv): Delete declaration.
+ (envsize): Ditto.
+ * spawn.cc (spawn_guts): Use build_env to build windows and cygwin
+ environment blocks.
+ * uinfo.cc (internal_getlogin): Eliminate environment manipulation.
+ Default to info from GetUserName if it exists. Move HOMEPATH and
+ HOMEDRIVE stuff elsewhere. Move HOME setting elsewhere. Only set HOME
+ environment variable in processes that are not parented by a cygwin
+ process.
+ (cygheap_user::ontherange): Define new method.
+ (cygheap_user::env_logsrv): Ditto.
+ (cygheap_user::env_homepath): Ditto.
+ (cygheap_user::env_homedrive): Ditto.
+ (cygheap_user::env_userprofile): Ditto.
+
+2002-06-11 Christopher Faylor <cgf@redhat.com>
+
+ * spawn.cc (spawn_guts): More hToken removal cleanup.
+
+2002-06-09 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * spawn.cc (spawn_guts): Define sec_attribs and call sec_user_nih()
+ only once.
+
+2002-06-10 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Ensure that -MD gets added to CFLAGS regardless of
+ CFLAGS command-line setting.
+
+ * cygwin.din: Export sexec* functions as function which returns ENOSYS
+ (i.e., sexec* is deprecated).
+ * dtable.cc (dtable::vfork_child_dup): Ensure that impersonation is
+ restored even on failure.
+ * exec.cc: Throughout, remove references to sexec* and _spawnve.
+ * pinfo.h: Remove _spawnve declaration.
+ * spawn.cc: Rename _spawnve to spawnve and use throughout.
+ (spawn_guts): Eliminate hToken argument and processing of same. Just
+ perform special actions if impersonating.
+ (spawnve): Rename from _spawnve.
+
+2002-06-10 Christopher Faylor <cgf@redhat.com>
+
+ * include/sys/strace.h (strace): Avoid use of constructor.
+
+2002-06-10 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (dll_crt0_1): Initialize wincap and check for sanity before
+ running global ctors.
+ * wincap.h (wincap): Eliminate constructor. Default is to zero memory,
+ anyway.
+ * wincap.cc (wincap): Copy this on fork to avoid initialization in
+ forked processes.
+
+2002-06-10 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler.h (fhandler_socket::fixup_after_fork): Revert patch from
+ 2002-06-04.
+ * fhandler_socket.cc (fhandler_socket::fixup_after_fork): Ditto.
+ (fhandler_socket::dup): Ditto.
+ * net.cc (fdsock): Make sockets explicitely noninheritable on NT.
+
+2002-06-09 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_helper): Correctly
+ set number of links for directory, if appropriate.
+
+2002-06-10 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc: Variation of a patch from Thomas Pffaf.
+ (__pthread_detach): Cleanup thread object if the thread has terminated.
+ (__pthread_join): Change order of error checks, and lock against
+ join/detach/exit races.
+ (__pthread_exit): Lock object against join/detach/exit races.
+ (pthread::thread_init_wrapper): Ditto.
+ (thread_init_wrapper): Rename to pthread::thread_init_wrapper.
+ (pthread::create): Check that the mutex initialized correctly.
+ (pthread::push_cleanup_handler): Lock against potential cancellation
+ race. NB: this may not be required if pthread_cleanup_push is non-
+ cancelable.
+ * thread.h (pthread::mutex): New member.
+ (thread_init_wrapper): Rename to pthread::thread_init_wrapper.
+ (pthread::thread_init_wrapper_: New static member.
+
+2002-06-10 Robert Collins <rbtcollins@hotmail.com>
+
+ * cygwin.din: Add _pthread_cleanup_push and _pthread_cleanup_pop.
+ * pthread.cc: Change __pthread_self to pthread::self() thruoghout.
+ (_pthread_cleanup_push): New function.
+ (_pthread_cleanup_pop): Ditto.
+ * thread.cc: Thanks to Thomas Pfaff for the pthread cleanup_push,_pop
+ patch, this work is derived from that.
+ Change __pthread_self to pthread::self() thruoghout.
+ (__pthread_self): Rename to pthread::self.
+ (pthread::self): New method.
+ (pthread::pthread): Initialize new member.
+ (pthread::push_cleanup_handler): New method.
+ (pthread::pop_cleanup_handler): New method.
+ (pthread::pop_all_cleanup_handlers): New method.
+ (__pthread_exit): Pop all cleanup handlers.
+ * thread.h (pthread::push_cleanup_handler): Declare.
+ (pthread::pop_cleanup_handler): Ditto.
+ (pthread::pop_all_cleanup_handlers): Ditto.
+ (pthread::self): New static method.
+ (__pthread_exit): Give C++ linkage.
+ (__pthread_join): Ditto.
+ (__pthread_detach): Ditto.
+ (__pthread_self): Remove.
-Fri Jun 22 16:50:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-04-24 Thomas Pfaff <tpfaff@gmx.net>
- * fhandler.h class fhandler_socket): Declare new method
- `set_close_on_exec'.
- * fhandler_socket.cc (fhandler_socket::set_close_on_exec):
- New method.
+ * include/pthread.h (__pthread_cleanup_handler): New structure.
+ (pthread_cleanup_push): Rewritten.
+ (pthread_cleanup_pop): Ditto.
+ (_pthread_cleanup_push): New prototype.
+ (_pthread_cleanup_pop): Ditto.
-Fri Jun 22 16:12:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-04-24 Thomas Pfaff <tpfaff@gmx.net>
- * fhandler_tape.cc (fhandler_dev_tape::tape_erase): Set size
- parameter to value expected by GetTapeParameters().
+ * thread.cc (thread_init_wrapper): Check if thread is already joined.
+ (__pthread_join): Set joiner first.
+ (__pthread_detach): Ditto.
-Thu Jun 21 22:01:39 2001 Marius Gedminas <mgedmin@delfi.lt>
+2002-06-10 Robert Collins <rbtcollins@hotmail.com>
+
+ * cygserver_transport.cc (create_server_transport): Finish the split
+ out of sockets code from transport_layer_base. Thanks to Nicholas
+ Wourms and Conrad Scott for catching this.
+
+2002-06-08 Christopher Faylor <cgf@redhat.com>
+
+ * pinfo.cc (pinfo_dummy): Initialize to correct size.
- * fhandler_console.cc (fhandler_console::read): Detect AltGr more
- robustly on WinNT.
+2002-06-08 Christopher Faylor <cgf@redhat.com>
-2001-06-22 Robert Collins <rbbtcollins@hotmail.com>
+ * path.cc: Change MOUNT_AUTO to MOUNT_CYGDRIVE throughout.
+ * shared_info.h (CURR_MOUNT_MAGIC): Update.
- * thread.cc (__pthread_cond_timedwait): Lock the waiting mutex before
- the condition protect mutex to avoid deadlocking. (Found by Greg Smith).
- (__pthread_cond_wait): Ditto.
+2002-06-08 Christopher Faylor <cgf@redhat.com>
-2001-06-30 Egor Duda <deo@logos-m.ru>
+ * external.cc (cygwin_internal): Make v1 mount table access invalid.
+ * path.cc (mount_info::init): Remove had_to_create_mount_areas initialization.
+ (mount_info::from_registry): Remove v1 table import.
+ (mount_info::read_v1_mounts): Eliminate.
+ (mount_info::import_v1_mounts): Ditto.
+ * shared_info.h (mount_info): Ditto for both of above.
+ * sys/mount.h (MOUNT_DEVFS): New enum.
+ (MOUNT_PROC): Ditto.
- * fhandler.cc (fhandler_base::open): Work around windows bug when
- CreateFile() with dwDesiredAccess == 0 called on remote share returns
- valid handle even if file doesn't exist.
+2002-06-08 Christopher Faylor <cgf@redhat.com>
-2001-06-20 Egor Duda <deo@logos-m.ru>
+ * include/wchar.h: Define __need_size_t.
- * fhandler_socket.cc (fhandler_socket::signal_secret_event): New
- function.
- * fhandler.h: Declare it.
- * fhandler_socket.cc (fhandler_socket::create_secret_event): Don't
- signal secret event immediately.
- (fhandler_socket::check_peer_secret_event): Do it after peer event
- was opened.
- * net.cc (cygwin_connect): Or if socket is non-blocking.
- (cygwin_accept): Ditto.
+2002-06-07 Christopher Faylor <cgf@redhat.com>
-Mon Jun 18 17:09:25 2001 Christopher Faylor <cgf@cygnus.com>
+ * fhandler_socket.cc (fhandler_socket::fstat): Don't assume that socket
+ is unix-domain socket.
- * fhandler_tty.cc (fhandler_tty_slave::init): Revert 2001-06-16 change.
+2002-06-07 Christopher Faylor <cgf@redhat.com>
- * fork.cc (fork_copy): Print more debugging info.
- (fork_parent): Change order of arguments to accomdate buggy gcc.
- (fork): Ditto.
+ * times.cc (hires_ms::prime): Set init flag.
-Sun Jun 17 18:54:46 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-07 Conrad Scott <conrad.scott@dsl.pipex.com>
- * syscalls.cc (_unlink): Reorganize to try harder to delete file with
- DeleteFile and to recover more gracefully if FILE_FLAG_DELETE_ON_CLOSE
- doesn't work properly.
+ * times.cc (hires_ms::prime): Adjust epoch of initime_us from 1601 to
+ 1970.
-Sat Jun 16 13:06:49 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-06 Christopher Faylor <cgf@redhat.com>
- * exceptions.cc (sig_handle_tty_stop): Reset PID_STOPPED if not
- actually stopping.
- * fhandler_console.cc (fhandler_console::fixup_after_fork): Don't set
- controlling terminal if just inheriting a handle.
- (fhandler_console::fixup_after_exec): Ditto.
- * fhandler_tty.cc (fhandler_tty_slave::init): Ditto.
- * signal.cc (kill_worker): Set appropriate errno if proc_exists
- determines that process does not really exist.
+ * autoload.cc (timeGetDevCaps): Define new autoload function.
+ (timeGetTime): Ditto.
+ (timeBeginPeriod): Ditto.
+ (timeEndPeriod): Ditto.
+ * hires.h (hires_base): New class. Rename from hires.
+ (hires_us): New class.
+ (hires_ms): New class.
+ * strace.cc (strace::microseconds): Use hires_us class.
+ * times.cc (gettimeofday): Use hires-ms class.
+ (hires_us::prime): Rename from hires::prime.
+ (hires_us::usecs): Rename from hires:usecs.
+ (hires_ms::prime): New method.
+ (hires_ms::usecs): New method.
+ (hires_ms::~hires_ms): New destructor.
-Fri Jun 15 14:34:19 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-06 Christopher Faylor <cgf@redhat.com>
- * path.cc (path_conv::check): Deal more robustly with foo/ behavior.
+ * autoload.cc (noload): Correctly save argument count register.
-Fri Jun 15 11:15:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_tape.cc (fhandler_dev_tape::tape_status): Set size
- parameter to value expected by GetTapeParameters().
+2002-06-05 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * fhandler.cc (fhandler_base::fstat): Initialise tv_nsec member of
+ st_atim, st_mtim, and st_ctim fields.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_helper): Ditto.
+ * fhandler_process.cc (fhandler_process::fstat): Ditto.
+ * glob.c (stat32_to_STAT): Copy across the whole st_atim, st_mtime, and
+ st_ctim fields.
+ * syscalls.cc (stat64_to_stat32): Ditto.
+ * times.cc (to_timestruc_t): New function.
+ (time_as_timestruc_t): New function.
+ * winsup.h: Add to_timestruc_t and time_as_timestruc_t functions.
+ * include/cygwin/stat.h: Replace time_t with timestruc_t throughout for
+ all file times, removing the st_spare1, st_spare2, and st_spare3 fields
+ in the process. Add macros to access tv_sec fields by old names.
+ * include/cygwin/types.h: Typedef timespec_t and timestruc_t as struct
+ timespec.
+
+2002-06-03 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * sec_helper.cc (lookup_name): Suppress.
+ * security.cc (alloc_sd): Remove logsrv argument.
+ Remove two calls to lookup_name.
+ (set_security_attribute): Remove logsrv argument.
+ Remove logsrv argument in call to alloc_sd.
+ (set_nt_attribute): Remove logsrv argument.
+ Remove logsrv argument in call to set_security_attribute.
+ (set_file_attribute): Remove logsrv argument.
+ Remove logsrv argument in call to set_nt_attribute.
+ (set_file_attribute): Remove logsrv argument.
+ Remove logsrv argument in call to set_file_attribute.
+ * syscalls.cc (chown_worker): Remove logserver argument in
+ call to set_file_attribute.
+ (chmod): Ditto.
+ * shm.cc (shmget): Remove logsrv argument in call to alloc_sd.
+ * uinfo.cc (internal_getlogin): Replace calls to
+ lookup_name by call to LookupAccountName.
+ * security.h: Remove logsrv in declarations of set_file_attribute
+ and alloc_sd. Remove declaration of lookup_name.
+
+2002-06-05 Christopher Faylor <cgf@redhat.com>
+
+ * child_info.h (CHILD_INFO_MAGIC): Oops. Revert previous change. gcc
+ 3.1 bug?
+
+2002-06-05 Christopher Faylor <cgf@redhat.com>
+
+ * child_info.h (CHILD_INFO_MAGIC): Update.
+
+2002-06-05 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (strace::hello): Set inited, when appropriate.
+
+2002-06-05 Christopher Faylor <cgf@redhat.com>
+
+ * cygwin.din: Eliminate some newlib wrappers.
+ * path.cc (get_devn): Only consider first 99 potential com devices.
+ (get_device_number): Ditto.
+ * times.cc (_times): Eliminate.
+ (_times): Rename from times().
+
+2002-06-05 Christopher Faylor <cgf@redhat.com>
+
+ * dir.cc (rmdir): Streamline. Detect attempts to remove directories
+ from "read-only" virtual devices. (Suggested by Pavel Tsekov)
+ * syscalls.cc (unlink): Detect attempts to remove directories from
+ "read-only" virtual devices. (From Pavel Tsekov)
+
+2002-06-05 Christopher Faylor <cgf@redhat.com>
+
+ * dtable.cc (handle_to_fn): Check error return value from NtQueryObject
+ first before seeing if name buffer is NULL.
+
+ * grp.cc (read_etc_group): Fix gcc warning regarding snprintf format.
+ * passwd.cc (read_etc_passwd): Ditto.
+
+2002-04-18 Thomas Pfaff <tpfaff@gmx.net>
+
+ * thread.h (pthread::joiner): New member.
+ * thread.cc (pthread::pthread): Initialize joiner to NULL
+ (pthread::create): Increment of thread counter moved from
+ __pthread_create to this location.
+ (__pthread_create): Increment thread counter removed.
+ (thread_init_wrapper): Set joiner to self when thread was created
+ detached.
+ (__pthread_exit): delete thread when it is detached and not
+ joined.
+ (__pthread_join): Check for deadlock and delete thread when it has
+ terminated.
+ (__pthread_detach): Set joiner to self when thread state
+ changed to detached.
+
+2002-06-05 Corinna Vinschen <corinna@vinschen.de>
+
+ * grp.cc (read_etc_group): When emulating nonexisting group file on
+ NT systems, read primary group SID from process token. Use that info
+ to create correct group entry. On error or on 9x systems fallback
+ to emulating Administrators group as before.
+ * passwd.cc (read_etc_passwd): When emulating nonexisting passwd file
+ on NT systems, read user and primary group SID from process token.
+ Use that info to create correct passwd entry. On error or on 9x
+ systems fallback to emulating user with Administrator user id and
+ Administrators group as before.
+
+2002-06-05 Corinna Vinschen <corinna@vinschen.de>
+
+ * grp.cc (etc_group): Removed.
+ (parse_grp): Make line parameter nonconst. Don't copy data into new
+ allocated memory. Check for CR instead of LF to accomodate new
+ read method.
+ (add_grp_line): Make line parameter nonconst.
+ (read_etc_group): Rearrange using new pwdgrp_read class.
+ * passwd.cc (parse_pwd): Don't copy data into new allocated memory.
+ Check for CR instead of LF to accomodate new read method.
+ (read_etc_passwd): Rearrange using new pwdgrp_read class.
+ * pwdgrp.h (pwdgrp_check::set_last_modified): Use different
+ parameters.
+ (class pwdgrp_read): New class for opening and reading passwd and
+ group files.
+
+2002-06-04 Christopher Faylor <cgf@redhat.com>
+
+ * dtable.cc (handle_to_fn): Attempt to handle "raw" accesses to remote
+ shares.
+ * path.cc (mount_info::conv_to_win32_path): Set flags to binary when
+ mount entry is not found.
+ (mount_info::set_flags_from_win32_path): Ditto.
+
+2002-06-04 Christopher Faylor <cgf@redhat.com>
+
+ * dtable.cc (handle_to_fn): Correct placement and length of name
+ buffer. (Suggested by Pavel Tsekov)
+
+2002-06-04 Christopher Faylor <cgf@redhat.com>
+
+ Remove fcntl.h includes throughout.
+ * fhandler.h: Move fcntl.h include here.
+ (fhandler_base::set_flags): Accept supplied_bin argument. Make
+ non-inlined.
+ * dtable.cc (dtable::init_std_file_from_handle): Just use binmode from
+ pc.
+ (reset_to_open_binmode): Use set_flags.
+ * cygwin.din (open): Avoid newlib wrapper.
+ (read): Ditto.
+ (unlink): Ditto.
+ (write): Ditto.
+ * fhandler.cc (fhandler_base::set_flags): Accept supplied_bin argument.
+ Make binmode decisions here.
+ (fhandler_base::open): Avoid using pc if it is NULL. Eliminate binmode
+ logic. Just call set_flags with binmode argument.
+ (fhandler_base::init): Call set_flags with binmode argument.
+ * fhandler_clipboard.cc (fhandler_dev_clipboard::open): Ditto.
+ * fhandler_console.cc (fhandler_console::open): Ditto.
+ (fhandler_console::init): Force binary on open.
+ * fhandler_disk_file.cc (fhandler_disk_file::open): Don't set binmode
+ here. Let it happen in base class.
+ * fhandler_dsp.cc (fhandler_dev_dsp::open): Force binmode open. Set
+ return value appropriately if unable to open.
+ * fhandler_proc.cc (fhandler_proc::open): Make sure flags are set
+ before open_status.
+ * fhandler_process.cc (fhandler_process::open): Ditto.
+ * fhandler_registry.cc (fhandler_registry::open): Ditto.
+ * fhandler_random.cc (fhandler_dev_random::fhandler_dev_random): Ditto.
+ * fhandler_raw.cc (fhandler_dev_raw::open): Force O_BINARY by default.
+ * fhandler_serial.cc (fhandler_serial::init): Ditto.
+ * fhandler_tty.cc (fhandler_tty_slave::open): Ditto.
+ (fhandler_pty_master::open): Ditto.
+ * fhandler_virtual.cc (fhandler_virtual::open): Ditto.
+ * fhandler_windows.cc (fhandler_windows::open): Ditto.
+ * fhandler_zero.cc (fhandler_dev_zero::open): Ditto.
+ * net.cc (fdsock): Ditto.
+ * path.cc (path_conv::check): Avoid checking for executable extension
+ when directory. (Suggested by Pavel Tsekov)
+ (set_flags): Set PATH_TEXT explicitly, when appropriate.
+ (mount_info::conv_to_win32_path): Use set_flags() to set path flags.
+ * path.h (PATH_TEXT): New enum.
+ (path_conv::binmode): Return appropriate constant based on binmode.
+ * pipe.cc (make_pipe): Set binmode to O_TEXT xor O_BINARY.
+ * syscalls.cc (setmode_helper): Make debugging message a little
+ clearer.
+ (setmode): Set binmode via set_flags.
+
+2002-06-04 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler.h (class fhandler_socket): Add private method
+ fixup_after_fork (bool, HANDLE).
+ * fhandler_socket.cc (fhandler_socket::fixup_after_fork): Move
+ functionality to new private method. Add closing parent socket
+ if not called from dup(). Create method new calling private method
+ with appropriate parameter.
+ (fhandler_socket::fixup_after_exec): Call private method
+ fixup_after_fork with appropriate parameter.
+ (fhandler_socket::dup): Ditto.
+
+2002-06-04 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_dsp.cc (fhandler_dev_dsp::open): Set errno to EACCES if
+ requested mode isn't supported.
+
+2002-06-03 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler.cc (fhandler_base::open): Don't set binmode if already set.
+ Don't check for file. Files should already be set. Report on binary
+ mode for debugging.
+ (fhandler_base::fhandler_base): Don't set default binmode here. That's
+ for later.
+ * fhandler_console.cc (fhandler_console::output_tcsetattr): Don't set
+ binmode, ever, for console.
+ * fhandler_disk_file.cc (fhandler_disk_file::open): Always set the
+ binary mode to the value derived from mount table.
+ * path.cc (mount_info::conv_to_win32_path): Default to binmode if path
+ does not translate into anything in the mount table.
+
+2002-06-03 Corinna Vinschen <corinna@vinschen.de>
+
+ * external.cc (cygwin_internal): Add CW_EXTRACT_DOMAIN_AND_USER
+ handling to call extract_nt_dom_user() from applications.
+ * include/sys/cygwin.h (cygwin_getinfo_types): Add
+ CW_EXTRACT_DOMAIN_AND_USER.
+
+2002-06-03 Corinna Vinschen <corinna@vinschen.de>
+
+ * syscalls.cc (stat64_to_stat32): Transform st_dev correctly.
+ (fstat64): Add evaluating st_ino and st_dev.
+ (stat_worker): Evaluate st_dev as 32 bit value.
+ * include/cygwin/stat.h: Use new dev_t definition throughout.
+ * include/cygwin/types.h: Define __dev16_t and __dev32_t. Define
+ dev_t according to __CYGWIN_USE_BIG_TYPES__ setting.
+ * include/sys/sysmacros.h: Define major, minor and makedev
+ according to __CYGWIN_USE_BIG_TYPES__ setting.
+
+2002-06-03 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * syscalls.cc (setegid32): Verify the correctness of the gid
+ of the group returned by getgrgid32.
+
+2002-06-03 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * security.cc (lsa2wchar): Suppressed.
+ (get_lsa_srv_inf): Suppressed.
+ (get_logon_server_and_user_domain): Suppressed.
+ (get_logon_server): Essentially new.
+ (get_user_groups): Add "domain" argument. Only lookup the
+ designated server and use "domain" in LookupAccountName.
+ (is_group_member): Simplify the arguments.
+ (get_user_local_groups): Simplify the arguments. Do only a
+ local lookup. Use "BUILTIN" and local domain in LookupAccountName.
+ (get_user_primary_group). Only lookup the designated server.
+ (get_group_sidlist): Remove logonserver argument. Do not lookup
+ any server for the SYSTEM account.
+ (create_token): Delete logonserver and call to get_logon_server.
+ Adjust arguments of get_group_sidlist, see above.
+ * security.h: Delete declaration of get_logon_server_and_user_domain
+ and add declaration of get_logon_server.
+ * uinfo.cc (internal_get_login): Call get_logon_server instead of
+ get_logon_server_and_user_domain.
+
+2002-06-02 Christopher Faylor <cgf@redhat.com>
+
+ * dtable.cc (handle_to_fn): Use largest match for device. Correctly
+ (?) deal with remote drive weirdness.
+
+2002-06-02 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_by_name): Check
+ specifically for non-existent file, first.
+ (fhandler_disk_file::fstat): Perform fd open on files with funny
+ characters.
+
+2002-06-02 Christopher January <chris@atomice.net>
+
+ * fhandler_process.cc (fhandler_process::open): Set fileid.
+
+2002-06-02 Christopher Faylor <cgf@redhat.com>
+
+ Remove unneeded sigproc.h includes throughout.
+ * fhandler.h (fhandler_proc::fill_filebuf): Take a pinfo argument.
+ * fhandler_proc.cc (fhandler_proc::get_proc_fhandler): Simplify search
+ for given pid.
+ (fhandler_proc::readdir): Assume that pid exists if it shows up in the
+ winpid list.
+ * fhandler_process.cc (fhandler_process::open): Simplify search for
+ given pid. Call fill_filebuf with pinfo argument.
+ (fhandler_process::fill_filebuf): Pass pinfo here and assume that it
+ exists.
+ * pinfo.h (pinfo::remember): Define differently if sigproc.h is not
+ included.
-Thu Jun 14 20:19:46 2001 Christopher Faylor <cgf@cygnus.com>
+2002-06-02 Christopher Faylor <cgf@redhat.com>
- * fhandler.cc (fhandler_disk_file::fstat): Properly set executable bits
- for directory when !ntsec && !ntea. Also move common code prior to
- call to get_attributes.
+ * dll_init.cc (dll_list::detach): Don't run destructor on exit.
-Fri June 15 09:25:00 Robert Collins <rbtcollins@hotmail.com>
+2002-06-01 Christopher Faylor <cgf@redhat.com>
- * thread.cc (pthread_cond::Signal): Release the condition access
- variable correctly.
+ * fhandler.cc (fhandler_base::fstat): Move dev and ino calculation into
+ caller.
+ * syscalls.cc (stat_worker): Calculate dev and ino calculation here, if
+ zero.
+ * fhandler_proc.cc (fhandler_proc::fhandler_proc): Minor reorg for
+ debugging.
+ * fhandler_process.cc (fhandler_process::exists): Return 0 on
+ nonexistence.
+ (fhandler_process::fstat): Simplify pid logic.
+ * fhandler_tape.cc (fhandler_dev_tape::fstat): Minor reformatting.
-2001-06-14 Egor Duda <deo@logos-m.ru>
+2002-06-01 Christopher Faylor <cgf@redhat.com>
- * fhandler.cc (fhandler_base::open): Set win32 access flags to 0, when
- requested.
- * fhandler.h: New status flag FH_QUERYOPEN.
- (fhandler::get_query_open): New function.
- (fhandler::set_query_open): Ditto.
- * syscalls.cc (stat_worker): Request query-only open mode.
+ * path.cc (chdir): Don't allow cd'ing to a non-directory virtual path.
-2001-06-12 Egor Duda <deo@logos-m.ru>
+2002-05-31 Christopher Faylor <cgf@redhat.com>
- * environ.cc (set_file_api_mode): New function. Move setting
- of file APIs mode (OEM/ANSI) here.
- (codepage_init): From here.
- * winsup.h (set_file_api_mode): Declare it.
- * fork.cc (fork_child): Set file APIs mode in forkee.
+ * fhandler_disk_file.cc (readdir): Move inode calculation into caller.
+ (fhandler_cygdrive::readdir): Add "." and "..".
+ * dir.cc (readdir): Move inode calculation here so that fhandler
+ readdirs can benefit.
-Mon Jun 11 14:19:49 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-31 Christopher Faylor <cgf@redhat.com>
- * pinfo.cc: Use autoloaded ToolHelp functions throughout for Win9x.
- * autoload.cc: Autoload ToolHelp functions.
+ * fhandler_console.cc (fhandler_console::open): Reinstate setting of
+ flags.
- * sigproc.cc (proc_subproc): Incorporate SIGCHLD == SIG_IGN special
- handling of zombie processes. Ensure that zombie processes which are
- at the end of the zombie array are properly cleaned up.
+ * dtable.cc (dtable::init_std_file_from_handle): Default to using
+ binmode derived from path_conv, when required.
+ * fhandler.h (fhandler_base::get_w_binary): Default to binmode if
+ nothing else is specified.
+ * fhandler.h (fhandler_base::get_r_binary): Ditto.
-Mon Jun 11 11:18:56 2001 Christopher Faylor <cgf@cygnus.com>
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_by_handle): Work
+ around g++ warning.
- * path.cc (chdir): Fix call to path_conv constructor so that it REALLY
- doesn't check for the null/non-empty path.
+ * path.cc (path_conv::check): Remove a debugging statement.
-Sun Jun 10 23:34:09 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-31 Christopher Faylor <cgf@redhat.com>
- * path.cc (path_conv::update_fs_info): Don't consider remote drives to
- be NTFS. Set root_dir before invoking GetDriveType (from Kazuhiro
- Fujieda <fujieda@jaist.ac.jp>). Eliminate extra checks for rootdir.
+ * fhandler_console.cc (fhandler_console::open): Always default to
+ binmode.
+ (fhandler_console::write_normal): Don't honor binmode setting. There
+ is already a termios setting for this.
+ (fhandler_console::init): Correct argument order in init call.
-Sun Jun 10 20:19:47 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-31 Christopher Faylor <cgf@redhat.com>
- * path.cc (chdir): Pre-check path for validity before eating trailing
- space. Then, ensure that path_conv doesn't check the path for validity
- again.
+ * fhandler.cc (fhandler_base::open): Make default open mode == binmode.
+ (fhandler_base::init): Set open flags based on derived binmode argument.
-Sun Jun 10 12:56:00 2001 Christopher Faylor <cgf@redhat.com>
+2002-05-31 Christopher Faylor <cgf@redhat.com>
- * exceptions.cc (sigdelayed): Ensure that signal is cleared as
- the last operation or suffer races.
- * sigproc.cc (proc_subproc): Deal with zombie array overflow.
+ * dll_init.cc (dll_list::init): Eliminate unneeded debugging statement.
-Sun Jun 10 11:56:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-31 Christopher Faylor <cgf@redhat.com>
- * cygwin.din: Add fchdir symbols.
- * path.cc (chdir): Guard against invalid parameter.
- (fchdir): New function.
- * include/cygwin/version.h: Bump API minor version to 40.
- * uinfo.cc (internal_getlogin): Remove unused variable.
+ * fhandler_proc.cc (fhandler_proc::readdir): Set errno when no more
+ files.
+ * fhandler_process.cc (fhandler_process::readdir): Ditto.
+ * fhandler_registry.cc (fhandler_registry::readdir): Ditto.
-Sat Jun 9 23:20:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-30 Christopher Faylor <cgf@redhat.com>
- * syscalls.cc (seteuid): Set environment variables USERNAME and
- USERDOMAIN before impersonation to workaround a LookupAccountSid()
- misbehaviour.
- * uinfo.cc (internal_getlogin): Revert most of the previous change.
- Don't set environment variables USERNAME and USERDOMAIN. That's
- the job of seteuid() now. Try to get logon server from Lsa
- only if logon server isn't already known.
+ * path.cc (path_conv::check): Set fileattr to INVALID_FILE_ATTRIBUTES
+ for nonexistent virtual device path.
+ (chdir): Set correct errno when attempt is made to cd to nonexistent
+ virtual device path.
-Thu Jun 7 15:54:32 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-05-30 Christopher Faylor <cgf@redhat.com>
- * thread.cc (pthread_cond::Broadcast): Don't print error messages on
- invalid mutexs - user programs are allowed to call
- pthread_cond_broadcast like that.
- (__pthread_cond_timedwait): Initialise themutex properly.
- (__pthread_cond_wait): Initialise themutex properly.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat): Always call
+ fstat_by_name if fd is not opened to allow fstat_by_name to properly
+ set errno.
-Tue Jun 5 19:56:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-30 Corinna Vinschen <corinna@vinschen.de>
- * fhandler_console.cc (fhandler_console::dup): Allocate space for
- savebuf on Cygwin heap.
- (fhandler_console::char_command): Ditto. Use correct values for size.
+ * autoload.cc: Replace autoload statments for ZwXXX by NtXXX.
+ Drop ZwQuerySystemInformation since NtQuerySystemInformation was
+ already available.
+ * fhandler_proc.cc (format_proc_uptime): Replace call to
+ ZwQuerySystemInformation by call to NtQuerySystemInformation.
+ (format_proc_stat): Ditto.
+ * fhandler_process.cc (format_process_stat): Replace call to
+ ZwQueryInformationProcess by call to NtQueryInformationProcess.
+ (get_process_state): Ditto.
+ (get_mem_values): Ditto. Replace call to ZwQueryVirtualMemory by
+ call to NtQueryVirtualMemory.
+ * ntdll.h: Cleanup. Drop ZwQuerySystemInformation since
+ NtQuerySystemInformation was already available. Replace declarations
+ of ZwXXX functions by declarations of NtXXX.
+ * pinfo.cc (winpids::enumNT): Replace call to ZwQuerySystemInformation
+ by call to NtQuerySystemInformation.
-2001-06-05 Egor Duda <deo@logos-m.ru>
+2002-05-29 Christopher Faylor <cgf@redhat.com>
- * security.h (NTWriteEA): Change prototype.
- * ntea.cc (NTReadEA): Don't check for global ntea setting, now
- it's caller responsibility.
- (NTWriteEA): Ditto.
- * security.cc (get_file_attribute): Read attribute from EA only
- if 'ntea' is enabled.
- (set_file_attribute): Ditto.
- * path.h: (class path_conv): Add members to store file system
- information.
- (path_conv::get_drive_type): New function.
- * syscalls.cc (stat_worker): Use it.
- * path.cc (path_conv::update_fs_info): New functions.
- (path_conv::check): Get file system information from device where
- file resides. On NTFS, try to read symlink contents from EA.
- (get_symlink_ea): New function.
- (set_symlink_ea): Ditto.
- (symlink): Store symlink in extended attribute, if possible.
+ * fhandler.cc (binmode): Default to binmode when mode is not known.
-Tue Jun 5 11:18:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-29 Christopher Faylor <cgf@redhat.com>
- * fhandler.cc (fhandler_disk_file::fstat): Always reset file position
- to original value after checking for executable magic.
+ * include/sys/cygwin.h (EXTERNAL_PINFO_VERSION): Reinstate.
+ * external.cc (fillout_pinfo): Use it.
-Mon Jun 4 16:21:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-29 Corinna Vinschen <corinna@vinschen.de>
- * cygheap.h (cygheap_user::cygheap_user): Initialize token to
- INVALID_HANDLE_VALUE.
- * uinfo.cc (uinfo_init): Close token handle if needed.
+ * external.cc (fillout_pinfo): Use new version define.
+ * include/sys/cygwin.h (external_pinfo): Define
+ EXTERNAL_PINFO_VERSION_16_BIT and EXTERNAL_PINFO_VERSION_32_BIT
+ instead of just EXTERNAL_PINFO_VERSION.
-Sun Jun 3 20:52:13 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-29 Christopher Faylor <cgf@redhat.com>
- * path.cc (normalize_posix_path): Revert .. check removed by previous
- changes.
- * cygheap.h: Temporarily declare path_prefix_p here.
-
-Mon Jun 4 0:14:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (wsock_event): Add destructor.
-
-Sun Jun 3 09:49:55 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * dlfcn.cc (dlclose): Do not call FreeLibrary if the symbol to close
- was obtained by dlopen(NULL,...).
-
-Sat Jun 2 23:11:52 2001 Christopher Faylor <cgf@cygnus.com>
-
- * syscalls.cc (sleep): Try to be a little more accomodating of signal
- arrival. Ensure that the signal handler is called.
-
-Sat Jun 2 14:07:28 2001 Christopher Faylor <cgf@cygnus.com>
-
- * cygheap.cc (cygheap_root::cygheap_root): Remove constructor.
- (cygheap_root::~cygheap_root): Remove destructor.
- (cygheap_root::operator =): Remove.
- (cygheap_root::set): New method.
- * cygheap.h (cygheap_root): Reflect above changes. Store root info in
- mount-like structure.
- (cygheap_root:posix_ok): New method.
- (cygheap_root::ischroot_native): Ditto.
- (cygheap_root::unchroot): Ditto.
- (cygheap_root::exists): Ditto.
- (cygheap_root::posix_length): Ditto.
- (cygheap_root::posix_path): Ditto.
- (cygheap_root::native_length): Ditto.
- (cygheap_root::native_path): Ditto.
- * dir.cc (opendir): Remove special chroot test.
- * path.cc (path_prefix_p): Remove front end.
- (normalize_posix_path): Reorganize chroot tests to accomodate new
- convention of allowing paths using posix chroot prefix.
- (path_conv::check): Pass a "already ran normalize" option to
- conv_to_win32_path. Return if there is an error from this function.
- (mount_info::conv_to_win32_path): Add extra argument. Don't call
- normalize_posix_path if caller has already done so. Substitute chroot
- setting, if any, for root translation. Add chroot checking to final
- output step.
- * shared_info (mount_info): Accomodate additional argument to
- conv_to_win32_path.
- * syscalls.cc (chroot): Store both normalized posix path and native
- path in chroot.
-
-Fri Jun 1 10:57:19 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (chdir): Really make sure that isspace gets only an unsigned
- char.
-
-Fri Jun 1 13:45:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * syscalls.cc (_rename): Handle the case that `foo' is renamed to
- `bar' while `bar.lnk' is an existing shortcut-symlink.
-
-Thu May 31 15:57:57 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler.cc (fhandler_disk_file::fstat): Avoid clearing S_IFMT bits
- since we've already pre-cleared everything anyway.
-
-Wed May 30 23:51:32 2001 Earnie Boyd <earnie_boyd@yahoo.com>
-
- * path.cc (chdir): Always send unsigned chars to isspace since newlib's
- isspace doesn't deal well with "negative" chars.
-
-Wed May 30 23:51:32 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler.cc (fhandler_disk_file::open): Propagate remote status of
- file garnered from path_conv. Move #! checking to fstat.
- (fhandler_disk_file::fstat): Reorganize st_mode setting to eliminate
- duplication. Move check for #! here from fhandler::open.
-
- * fhandler.h (fhandler_base::isremote): New method.
- (fhandler_base::set_isremote): Ditto.
- (fhandler_base::set_execable_p): Also record "don't care if executable
- state".
- (fhandler_base::dont_care_if_execable): New method.
- * path.cc (path_conv::check): Clear new flags. Appropriately set
- vol_flags, drive_type, and is_remote_drive.
- * path.h: Add new flags and methods for manipulating them.
- * syscalls.cc (_unlink): Use isremote() to determine if a path is
- remote rather than calling GetDriveType.
- (stat_worker): Ditto.
- * security.cc (get_file_attribute): Or attribute with result of
- NTReadEA to be consistent with get_nt_attribute.
+ * external.cc (fillout_pinfo): Set new version field in external_pinfo
+ structure.
+ * include/sys/cygwin.h (external_pinfo): Replace strace_file with
+ version field.
-Tue May 29 19:02:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-29 Corinna Vinschen <corinna@vinschen.de>
- * sec_helper.cc (cygsid::getfrompw): Change parameter to `const'.
- (cygsid::getfromgr): Ditto.
- * security.cc: Use `sys_mbstowcs' and `sys_wcstombs' throughout.
- (extract_nt_dom_user): Try to get user and domain from SID in
- pw->pw_gecos first.
- * security.h (class cygsid): Change parameter of getfrompw() and
- getfromgr() to `const'.
- * uinfo.cc (internal_getlogin): Change order for evaluating user
- information in winNT case. Drop usage of NetWkstaUserGetInfo().
+ Change internal uid datatype from __uid16_t to __uid32_t
+ throughout.
+ * cygwin.din: Export new symbols getpwuid32, getpwuid_r32, getuid32,
+ geteuid32, setuid32, seteuid32.
+ * passwd.cc (getpwuid32): New function.
+ (getpwuid_r32): Ditto.
+ * syscalls.cc (seteuid32): Ditto.
+ (setuid32): Ditto.
+ * uinfo.cc (getuid32): Ditto.
+ (geteuid32): Ditto.
+ * winsup.h (uid16touid32): New macro, correct casting from __uid16_t
+ to __uid32_t.
+ (gid16togid32): Ditto fir gids.
+ (getuid32): Declare.
+ (geteuid32): Ditto.
+ (getpwuid32): Ditto.
+ * include/sys/cygwin.h (struct external_pinfo): Add members uid32 and
+ gid32.
+
+2002-05-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * include/cygwin/socket.h: Protect some symbols against multiple
+ definition.
+ * include/netinet/ip.h: Ditto.
+ * include/netinet/tcp.h: Ditto.
-Mon May 28 21:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-29 Wu Yongwei <adah@netstd.com>
- * shortcut.c (check_shortcut): Treat only Cygwin shortcuts as symlinks.
+ * include/netinet/ip.h: Replace by BSD derived version of the file.
+ * include/netinet/tcp.h: Ditto.
+ * include/netinet/udp.h: New file.
+ * include/cygwin/ip.h: Remove.
-Fri May 25 11:07:07 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-29 Christopher Faylor <cgf@redhat.com>
- * path.cc (symlink_info::check): Correctly set 'ext_tacked_on'. Use
- this to determine if user specified 'foo.lnk' explicitly. Reorganize
- slightly to get rid of one goto.
+ * dtable.cc (dtable::init_std_file_from_handle): Attempt stronger
+ detection of invalid handle.
+ (handle_to_fn): Detect pathological condition where NT resets the
+ buffer pointer to NULL on an invalid handle.
-Fri May 25 10:15:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-28 Christopher Faylor <cgf@redhat.com>
- * path.cc (symlink_info::check): Add a check to return correctly
- if incoming `*.lnk' file is not a symlink.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_helper): Properly
+ check for whether we should be opening the file to search for #!
+ characters. Set path_conv structure execability, too, when
+ appropriate.
-Thu May 24 15:46:50 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-28 Corinna Vinschen <corinna@vinschen.de>
- * path.cc (slash_drive_prefix_p): Remove.
- (mount_info::slash_drive_to_win32_path): Ditto.
- (mount_info::conv_to_win32_path): Remove slash drive prefix check.
- (mount_info::add_item): Ditto.
- (mount_info::del_item): Ditto.
- * shared_info.h (mount_info): Remove slash_drive_to_win32_path
- declaration.
+ * security.cc (set_security_attribute): Call getegid32() instead of
+ getegid().
+ * include/cygwin/grp.h: Declare getegid32().
-Thu May 24 01:17:33 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-28 Corinna Vinschen <corinna@vinschen.de>
- * exceptions.cc (handle_exceptions): Bump repeat count for debugging
- kick out.
+ Change internal gid datatype from __gid16_t to __gid32_t
+ throughout.
+ * cygwin.din: Export new symbols chown32, fchown32, getegid32,
+ getgid32, getgrgid32, getgrnam32, getgroups32, initgroups32, lchown32,
+ setgid32, setegid32, getgrent32.
+ * grp.cc (grp32togrp16): New static function.
+ (getgrgid32): New function.
+ (getgrnam32): Ditto.
+ (getgrent32): Ditto.
+ (getgroups32): Change name of internal function from getgroups.
+ (getgroups32): New function.
+ (initgroups32): Ditto.
+ * syscalls.cc (chown32): Ditto.
+ (lchown32): Ditto.
+ (fchown32): Ditto.
+ (setegid32): Ditto.
+ (setgid32): Ditto.
+ * uinfo.cc (getgid32): Ditto.
+ (getegid32): Ditto.
+ * include/cygwin/grp.h: Remove declaration of getgrgid() and getgrnam().
+ Declare getgrgid32() and getgrnam32() instead. Declare getgid32().
+
+2002-05-27 Christopher Faylor <cgf@redhat.com>
+
+ * autoload.cc (noload): Properly mask low order word for determining
+ number of bytes to pop.
+
+2002-05-27 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat): Minor logic
+ cleanup.
+
+2002-05-27 Christopher Faylor <cgf@redhat.com>
+
+ * autoload.cc (LoadFuncEx): Define via new LoadFuncEx2 macro.
+ (LoadFuncEx2): Adapt from LoadFuncEx. Provides control of return
+ value for nonexistent function.
+ (NtQueryObject): Declare.
+ (IsDebuggerPresent): Declare via LoadFuncEx2 and always return true if
+ not available.
+ * debug.h (being_debugged): Just rely on IsDebuggerPresent return
+ value.
+ * dtable.cc (handle_to_fn): New function.
+ (dtable::init_std_file_from_handle): Attempt to derive std handle's
+ name via handle_to_fn.
+ (dtable::build_fhandler_from_name): Fill in what we can in path_conv
+ structure when given a handle and path doesn't exist.
+ * fhandler.cc (fhandler_base::open): Don't set the file pointer here.
+ Use pc->exists () to determine if file exists rather than calling
+ GetFileAttributes again.
+ * fhandler.h (fhandler_base::exec_state_isknown): New method.
+ (fhandler_base::fstat_helper): Add extra arguments to declaration.
+ (fhandler_base::fstat_by_handle): Declare new method.
+ (fhandler_base::fstat_by_name): Declare new method.
+ * fhandler_disk_file (num_entries): Make __stdcall.
+ (fhandler_base::fstat_by_handle): Define new method.
+ (fhandler_base::fstat_by_name): Define new method.
+ (fhandler_base:fstat): Call fstat_by_{handle,name} as appropriate.
+ (fhandler_disk_file::fstat_helper): Accept extra arguments for filling
+ out stat structure. Move handle or name specific stuff to new methods
+ above.
+ (fhandler_disk_file::open): Use real_path->exists rather than calling
+ GetFileAttributes again.
+ * ntdll.h (FILE_NAME_INFORMATION): Define new structure.
+ (OBJECT_INFORMATION_CLASS): Partially define new enum.
+ (OBJECT_NAME_INFORMATION): Define new structure.
+ (NtQueryInformationFile): New declaration.
+ (NtQueryObject): New declaration.
+ * path.cc (path_conv::fillin): Define new method.
+ * path.h (path_conv::fillin): Declare new method.
+ (path_conv::drive_thpe): Rename from 'get_drive_type'.
+ (path_conv::volser): Declare new method.
+ (path_conv::volname): Declare new method.
+ (path_conv::root_dir): Declare new method.
+ * syscalls.cc (fstat64): Send real path_conv to fstat as second
+ argument.
+
+2002-05-24 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * security.cc (lsa2str): New function.
+ (get_priv_list): Call lsa2str instead of sys_wcstombs.
+
+2002-05-22 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * syscalls.cc (seteuid): Do not take allow_ntsec into account.
+ Attempt to use an existing or new token even when the uid
+ matches orig_uid, but the gid is not in the process token.
+ Major reorganization after several incremental changes.
+ (setegid): Do not take allow_ntsec into account. Minor
+ reorganization after several incremental changes.
+
+2002-05-26 Christopher Faylor <cgf@redhat.com>
+
+ * debug.h (being_debugged): New macro.
+ * dtable.cc (dtable::extend): Use new macro.
+ * exceptions.cc (try_to_debug): Ditto.
+ * strace.cc (strace::hello): Only output debugging info when we think
+ we're being debugged.
+
+2002-05-25 Robert Collins <rbtcollins@hotmail.com>
+
+ * winsup.h: Remove duplicate declarations of malloc_lock and
+ malloc_unlock.
+
+2002-05-24 Christopher Faylor <cgf@redhat.com>
+
+ Remove unneeded sync.h, where appropriate, throughout.
+ Remove unneeded heap.h, where appropriate, throughout.
+ Remove unneeded exceptions.h, where appropriate, throughout.
+ Remove unneeded perprocess.h, where appropriate, throughout.
+
+2002-05-22 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * security.cc (create_token): Call __sec_user() instead of
+ sec_user() to remove dependence on allow_ntsec. Verify that
+ the returned sd is non-null.
+
+2002-05-25 Robert Collins <rbtcollins@hotmail.com>
+
+ * gmon.c (fake_sbrk): Correctly return -1 on failed malloc's.
+
+2002-05-24 Christopher Faylor <cgf@redhat.com>
+
+ * dtable.cc (dtable::build_fhandler_from_name): Just pass posix path
+ along to set_name via return_and_clear_normalized_path.
+ (dtable::build_fhandler): New method with const char * argument.
+ (dtable::reset_unix_path_name): Eliminate.
+ (dtable::dup_worker): Use correct build_fhandler method.
+ * mmap.cc (mmap_record::alloc_fh): Ditto.
+ * dtable.h (dtable::build_fhandler): New method.
+ (dtable::reset_unix_path_name): Eliminate.
+ * fhandler.cc (fhandler_base::set_name): Assume that unix_name has
+ already been cmalloced.
+ (fhandler_base::reset_unix_path_name): Eliminate.
+ (fhandler_base::~fhandler_base): Coercion for cfree.
+ * fhandler.h (fhandler_base::unix_path_name): Make const char *.
+ (fhandler_base::win32_path_name): Ditto.
+ (fhandler_base::reset_unix_path_name): Eliminate.
+ * fhandler_disk_file.cc (fhandler_cygdrive::set_drives): Accommodate
+ const char *ness of win32_path_name.
+ * fhandler_socket.cc (fhandler_socket::fstat): Accommodate new set_name
+ requirements.
+ * path.cc (path_conv::return_and_clear_normalized_path): New method.
+ (path_conv::clear_normalized_path): Eliminate.
+ (path_conv::~path_conv): Ditto.
+ (path_conv::check): Accommodate new build_fhandler method.
+ * path.h (path_conv::~path_conv): Eliminate.
+ (path_conv::clear_normalized_path): Ditto.
+ (path_conv::return_and_clear_normalized_path): Declare new method.
+
+2002-05-23 Christopher Faylor <cgf@redhat.com>
+
+ * path.cc (path_conv::check): Make sure any trailing path component is
+ part of potential normalized posix path.
+
+2002-05-23 Christopher Faylor <cgf@redhat.com>
+
+ * smallprint.c (__small_vsprintf): Implement '%o' after all these
+ years.
+
+2002-05-22 Christopher Faylor <cgf@redhat.com>
- * fhandler.h (fhandler_dev_dsp): Add a fixup_after_exec.
- * fhandler_dsp.cc (class Audio): Add TOT_BLOCK_SIZE to enum.
- (operator new): New.
- (bigwavebuffer): Declare using TOT_BLOCK_SIZE to avoid buffer overruns.
- (Audio::Audio): Optimize slightly.
- (fhandler_dev_dsp::open): Allocate s_audio using static buffer.
- (fhandler_dev_dsp::fixup_after_exec): New function. Ditto.
+ * fhandler.h (fhandler_virtual::exists): Eliminate path argument.
+ (fhandler_proc::exists): Ditto.
+ (fhandler_registry::exists): Ditto.
+ (fhandler_process::exists): Ditto.
+ * fhandler_proc.cc (fhandler_proc::exists): Ditto. Use built-in name.
+ * fhandler_process.cc (fhandler_process::exists): Ditto.
+ (fstat): Ditto.
+ * fhandler_registry.cc (fhandler_registry::exists): Ditto.
+ (fhandler_registry::fstat): Ditto.
+ * fhandler_virtual.cc (fhandler_virtual::opendir): Ditto.
+ * path.cc (path_conv::check): Ditto. Add debugging.
-Wed May 23 17:45:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-22 Christopher Faylor <cgf@redhat.com>
- * syscalls.cc (seteuid): Restrict overriding external provided
- user tokens to ntsec. Don't test external tokens for primary
- group to evaluate if it should be overridden. Restrict creating
- internal tokens to ntsec.
+ * syscalls.cc (dup): Always call dup2 for error handling.
-Wed May 23 10:11:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-22 Corinna Vinschen <corinna@vinschen.de>
- * syscalls.cc (chown_worker): Don't check for ENOSYS.
+ * include/cygwin/types.h: Revert previous patch.
-Tue May 22 12:20:07 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-22 Corinna Vinschen <corinna@vinschen.de>
- * signal.cc (sleep): Protect with sigframe.
+ * include/cygwin/types.h: Define pthread stuff only if _POSIX_THREADS
+ is defined.
-Tue May 22 17:58:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-19 Pierre Humblet <pierre.humblet@ieee.org>
- * security.cc (get_file_attribute): Don't set errno.
+ * security.cc (open_local_policy): Initialize lsa to
+ INVALID_HANDLE_VALUE instead of NULL.
+ (get_logon_server_and_user_domain): Test for INVALID_HANDLE_VALUE
+ instead of NULL.
+ (create_token): Both of the above.
-Mon May 21 15:08:00 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-18 Christopher Faylor <cgf@redhat.com>
- * configure.in: Allow --enable-newvfork to turn NEWVFORK on and off.
- * configure: Regenerate.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat): Make handling of
+ nlink consistent for remote files.
-Mon May 21 11:46:01 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-18 Christopher Faylor <cgf@redhat.com>
- * include/cygwin/version.h: Bump minor version number.
+ * path.cc (path_conv::check): Always set executable bit for executable
+ extension.
-Sun May 20 13:26:25 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-17 Christopher Faylor <cgf@redhat.com>
- * fhandler_dsp.cc: Reformat to GNU standards.
- (s_audio): Change to a pointer throughout.
- (fhandler_dev_dsp::open): Initialize s_audio, if required.
+ * fhandler.cc (fhandler_base::lseek): Avoid calling SetFilePointer with
+ high order part of 64 bit address on OS's which do not support that
+ kind of operation. Otherwise Windows 95 will become confused.
-Sat May 19 23:40:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-16 Pierre Humblet <pierre.humblet@ieee.org>
- * autoload.cc: Add load statements for `LookupAccountNameW',
- `LsaClose', `LsaEnumerateAccountRights', `LsaFreeMemory',
- `LsaOpenPolicy', `LsaQueryInformationPolicy', `NetLocalGroupEnum',
- `NetLocalGroupGetMembers', `NetServerEnum', `NetUserGetGroups' and
- `NtCreateToken'.
- * ntdll.h: Add declaration for `NtCreateToken'.
- * sec_helper.cc: Add `well_known_local_sid', `well_known_dialup_sid',
- `well_known_network_sid', `well_known_batch_sid',
- `well_known_interactive_sid', `well_known_service_sid' and
- `well_known_authenticated_users_sid'.
- (cygsid::string): Define as const method.
- (cygsid::get_sid): Set psid to NO_SID on error.
- (cygsid::getfromstr): Ditto.
- (cygsid::getfrompw): Simplify.
- (cygsid::getfromgr): Check for gr == NULL.
- (legal_sid_type): Move to security.h.
- (set_process_privilege): Return -1 on error, otherwise 0 or 1 related
- to previous privilege setting.
- * security.cc (extract_nt_dom_user): Remove `static'.
- (lsa2wchar): New function.
- (open_local_policy): Ditto.
- (close_local_policy): Ditto.
+ * fhandler_raw.cc (fhandler_dev_raw::open): Replace set_errno()
+ by __seterrno_from_win_error().
+ * security.cc (open_local_policy): Ditto.
(get_lsa_srv_inf): Ditto.
- (get_logon_server): Ditto.
- (get_logon_server_and_user_domain): Ditto.
(get_user_groups): Ditto.
- (is_group_member): Ditto.
- (get_user_local_groups): Ditto.
- (sid_in_token_groups): Ditto.
(get_user_primary_group): Ditto.
- (get_group_sidlist): Ditto.
- (get_system_priv_list): Ditto.
- (get_priv_list): Ditto.
- (get_dacl): Ditto.
(create_token): Ditto.
- (subauth): Return immediately if SE_TCB_NAME can't be assigned.
- Change all return statements in case of error to jumps to `out'
- label. Add `out' label to support cleanup.
- * security.h: Add extern declarations for `well_known_local_sid',
- `well_known_dialup_sid', `well_known_network_sid',
- `well_known_batch_sid', `well_known_interactive_sid',
- `well_known_service_sid' and `well_known_authenticated_users_sid'.
- Add extern declarations for functions `create_token',
- `extract_nt_dom_user' and `get_logon_server_and_user_domain'.
- (class cygsid): Add method `assign'. Change operator= to call new
- `assign' method. Add `debug_print' method.
- (class cygsidlist): New class.
- (legal_sid_type): Moved from sec_helper.cc to here.
- * spawn.cc (spawn_guts) Revert reversion of previous patch.
- Call `RevertToSelf' and `ImpersonateLoggedOnUser' instead of `seteuid'
- again.
- * syscalls.cc (seteuid): Rearranged. Call `create_token' now when
- needed. Call `subauth' if `create_token' fails. Try setting token
- owner and primary group only if token was not explicitely created
- by `create_token'.
- * uinfo.cc (internal_getlogin): Try harder to generate correct user
- information. Especially don't trust return value of `GetUserName'.
-
-Sat May 19 21:16:07 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fork.cc (fork_parent): Move atforkprepare call here.
- (fork): From here.
-
-Sat May 19 18:35:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc: Add missing load statement for `CancelIo'.
-
-Sat May 19 01:22:43 2001 Christopher Faylor <cgf@cygnus.com>
-
- * grp.cc (read_etc_group): Don't copy mutex on fork.
- * pwd.cc (read_etc_passwd): Ditto.
- * autoload.cc (LoadDLLfuncEx): Use LoadDLLprime to initialize DLL
- specific area.
-
-Fri May 18 10:31:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (wsock_event::wait): Explicitely cancel IO when a signal
- arrived to avoid data loss. Fallback to blocking IO when canceling
- fails.
-
-Thu May 17 15:29:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * security.cc (cygwin_set_impersonation_token): Never destroy
- previous token object.
- (subauth): Create token source with well defined identifier.
-
-Wed May 16 23:27:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (uinfo_init): Just set user token to INVALID_HANDLE_VALUE.
- Token value is already invalid at that point.
-
-Wed May 16 21:34:00 2001 Fred Yankowski <fred@ontosys.com>
-
- * net.cc (errmap): Add missing mapping from WSAEINTR to EINTR.
-
-Wed May 16 09:20:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_helper.cc (legal_sid_type): Fix conditional. Change to
- inline function.
-
-Wed May 16 01:01:48 2001 Christopher Faylor <cgf@cygnus.com>
-
- * autoload.h: Eliminate.
- * autoload.cc: Pull in autoload.h. Eliminate many macros. Rewrite to
- avoid necessity of initialization routines. Just use a standard one.
- (wsock_init): New function. Moved from net.cc.
- * net.cc (wsock_init): Move to autoload.cc.
- (wsadata): Make global.
- * dtable.cc (dtable::build_fhandler): Use more reliable method for
- checking if net stuff has been loaded.
-
-Tue May 15 19:52:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fork.cc (fork): Eliminate superfluous call to getuid().
- * security.h: New define `NO_SID'. Remove declarations of functions
- moved to methods into class cygsid.
- (class cygsid): Declare new methods `getfromstr', `get_sid',
- `getfrompw', `getfromgr', `get_rid', `get_uid', `get_gid', `string'
- and new constructors and operators =, == and !=.
- Declare new global cygsids `well_known_XXX_sid' substituting the
- corresponding `get_XXX_sid' functions. Remove declarations of
- these functions.
- * sec_helper.cc (well_known_admin_sid): New global variable.
- (well_known_system_sid): Ditto
- (well_known_creator_owner_sid): Ditto
- (well_known_world_sid): Ditto
- (cygsid::string): New method, substituting `convert_sid_to_string_sid'.
- (cygsid::get_sid): New method, substituting `get_sid'.
- (cygsid::getfromstr): New method, substituting
- `convert_string_sid_to_sid'.
- (cygsid::getfrompw): New method, substituting `get_pw_sid'.
- (cygsid::getfromgr): New method, substituting `get_gr_sid'.
- (cygsid::get_id): New method, substituting `get_id_from_sid'.
- (get_admin_sid): Eliminated.
- (get_system_sid): Ditto.
- (get_creator_owner_sid): Ditto.
- (get_world_sid): Ditto.
- * grp.cc: Use new cygsid methods and well known sids throughout.
- * registry.cc: Ditto.
- * sec_acl.cc: Ditto.
- * security.cc: Ditto.
- * shared.cc: Ditto.
- * syscalls.cc (seteuid): Ditto. Eliminate redundant conditional.
- * uinfo.cc (internal_getlogin): Ditto.
- * spawn.cc (spawn_guts) Revert previous patch.
-
-Tue May 15 10:20:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::ioctl): Convert s_addr
- field to host byte order before comparing with INADDR_LOOPBACK.
-
-Tue May 15 9:03:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc: Add autoload statements for ws2_32 functions
- `WSACloseEvent', `WSACreateEvent', `WSAGetOverlappedResult',
- `WSARecv', `WSARecvFrom', `WSASend', `WSASendTo' and `WSASetEvent',
- `WSAWaitForMultipleEvents'.
- * net.cc: Define wsock_evt.
- (wsock_event): New class.
- (cygwin_sendto): Use overlapped socket io if available.
- (cygwin_recvfrom): Ditto.
- (cygwin_recv): Ditto.
- (cygwin_send): Ditto.
- * security.cc (subauth): Set Win32 error to 0 to safely ask for the
- error code of dynamically loaded function `LsaRegisterLogonProcess'.
-
-Mon May 14 15:37:29 2001 Christopher Faylor <cgf@cygnus.com>
-
- * errno.cc (_sys_errlist): Add missing commas.
-
-Mon May 14 16:13:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * security.cc (subauth): Check if Secur32.dll could be loaded.
-
-Sun May 13 22:49:04 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (path_conv::check): Revert allow_ntsec check so that volume
- info is always retrieved and isdisk setting is properly set.
-
-Sun May 13 14:02:36 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler_tty.cc (fhandler_tty_common::dup): Preserve O_NOCTTY when
- duping a filehandle.
-
-Sat May 12 18:19:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * dir.cc (rmdir): Rearrange slightly to allow removing directories
- even when R/O attribute is set.
-
-Fri May 11 16:53:38 2001 Christopher Faylor <cgf@cygnus.com>
-
- * external.cc (fillout_pinfo): Use correct pids.
- * path.cc (mount_info::conv_to_win32_path): Correct test for whether to
- include a slash.
-
-Fri May 11 01:04:17 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (handle_exceptions): Don't print message when executing
- from a cygwin program.
-
-2001-05-10 Egor Duda <deo@logos-m.ru>
- Christopher Faylor <cgf@redhat.com>
-
- * environ.cc (winenv): Always add SYSTEMDRIVE and SYSYEMROOT to
- win32-style environment if they don't already exist.
-
-2001-05-10 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * path.cc (mount_info::conv_to_win32_path): Treat UNC paths the same as
- paths including `:' or `\'.
-
-Wed May 9 14:46:32 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler.h (fhandler_termios::echo_erase): Declare new method.
- * fhandler_termios.cc (fhandler_termios::echo_erase): New method for
- echoing erase characters.
- (fhandler_termios::line_edit): Check the echo flag before echoing
- control characters (from Kazuhiro Fujieda <fujieda@jaist.ac.jp>).
-
-Wed May 9 10:43:30 2001 Christopher Faylor <cgf@cygnus.com>
-
- * include/pthread.h: Remove C++ comment.
-
-Tue May 8 11:09:59 2001 Christopher Faylor <cgf@cygnus.com>
-
- * cygheap.cc (_cfree): Add regparm attribute.
- (_crealloc): Ditto.
-
- * dcrt0.cc (dll_crt0_1): Default to always checking for executable for now.
-
- * dtable.cc (dtable::not_open): Move method.
- * dtable.h (dtable): Here.
-
- * exceptions.cc (ctrl_c_handler): Don't expect process group leader to
- handle a signal if it doesn't exist.
-
- * fhandler.h (fhandler_base): Make openflags protected.
-
- * localtime.c (tzsetwall): Check for __CYGWIN__ as well as __WIN32__.
-
- * path.cc (path_conv::check): Add some comments. Change strcat to assignment.
-
- * lib/_cygwin_S_IEXEC.cc (_cygwin_bob__): Eliminate.
-
- * fhandler_tty.cc (fhandler_console::dup): Set controlling terminal if necessary.
- * fhandler_tty.cc (fhandler_tty_slave::dup): Ditto.
-
-Mon May 7 21:33:17 2001 Christopher Faylor <cgf@cygnus.com>
-
- * include/sys/file.h: Revert special X_OK usage. Just make it a
- constant.
-
-Sun May 6 17:05:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.h (pthread_cond): New element cond_access to allow atomic
- broadcasts.
- * thread.cc (pthread_cond::pthread_cond): Initialise cond_access.
- (pthread_cond::~pthread_cond): Destroy cond_access.
- (pthread_cond::Broadcast): Use cond_access.
- (pthread_cond::Signal): Use cond_access.
- (pthread_cond_wait): Use cond_access.
- (pthread_cond_timedwait): Use cond_access.
-
-Sun May 6 11:55:40 2001 Christopher Faylor <cgf@cygnus.com>
-
- * string.h (cygwin_strchr): Make 'static inline' so that things will
- still work when optimized.
-
-Sat May 5 01:04:11 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (handle_exceptions): Vastly increase test for exception
- loop guard variable.
-
-Fri May 4 22:23:33 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (stack_info): Add some controls.
- (stack_info::init): Add extra arguments to control method of
- initialization.. If we have a known good frame, set things up so that
- this frame is not skipped the first time through. Record whether
- caller cares about arguments or not.
- (stack_info::walk): Don't store arguments if they're unwanted.
- (stackdump): Add isexception parameter for use when called by exception
- handler.
- (cygwin_stackdump): Accomodate extra argument to stackdump.
- (handle_exceptions): Ditto.
- (sig_handle): Ditto.
- (interrupt_on_return): Accomodate extra arguments to stack walk
- initialization.
-
-Fri May 4 21:05:20 2001 Christopher Faylor <cgf@cygnus.com>
-
- * localtime.c: Revert exclusion of windows.h.
-
-Fri May 4 17:03:16 2001 Christopher Faylor <cgf@cygnus.com>
-
- * string.h: Fix last-minute typo.
-
-Fri May 4 16:49:34 2001 Christopher Faylor <cgf@cygnus.com>
-
- * pinfo.h: Correctly set __SIGOFFSET.
-
- * path.cc (hash_path_name): Avoid calling library functions for simple
- copying of characters.
-
- * shortcut.c: Use WIN32_LEAN_AND_MEAN.
- * smallprint.c: Ditto.
-
- * environ.cc (getwinenv): Minor clarity fix.
-
- * localtime.c: No need to include windows.h
-
- * string.h: New file.
-
-Fri May 4 16:37:30 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (ctrl_c_handler): Always send signal to process if it
- has no tty.
-
-2001-05-04 Egor Duda <deo@logos-m.ru>
-
- * fhandler_socket.cc (set_connect_secret): Use /dev/urandom to
- generate secret cookie.
-
-Thu May 3 16:37:55 2001 Christopher Faylor <cgf@cygnus.com>
-
- * include/pthread.h (pthread_cleanup_push): Eliminate space preceding
- arguments.
- (pthread_cleanup_pop): Ditto.
-
-Thu May 3 18:16:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (wsock_init): Rename `was_in_progress' to `wsock_started'
- for clearness.
-
-Thu May 3 10:44:16 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (handle_exceptions): Break out of "loop" if the
- debugger doesn't seem to be attaching to our process.
-
-Wed May 2 20:18:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc: Use new definition of LoadDLLinitfunc throughout.
- Redefine wrapper for wsock32.dll and ws2_32.dll.
- (std_dll_init): New function.
- * autoload.h: Rename LoadDLLinitfunc to LoadDLLinitfuncdef.
- Add new defines LoadDLLinitfunc and LoadDLLstdfunc.
- * net.cc (wsock_init): Add guard variable handling. Take care
- to call WSAStartup only once. Load WSAStartup without using
- autoload wrapper to eliminate recursion. Eliminate FIONBIO
- and srandom stuff.
-
-Tue May 1 01:26:15 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (mount_info::conv_to_win32_path): More path tweaking.
-
-Tue May 1 00:34:46 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (mount_info::conv_to_win32_path): Fix debugging output to
- avoid a SIGSEGV. Avoid double backslashes in middle of filename.
-
-Mon Apr 30 21:51:14 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (mkrelpath): New function.
- (mount_info::conv_to_win32_path): Eliminate now-unneeded relative path
- name arg and processing.
- (path_conv::check): Accomodate relative path names again. Accomodate
- one extra argument in mount_info::conv_to_win32_path. Tack trailing
- slash on end of relative path as a side effect, like before.
- * shared_info.h (mount_info::conv_to_win32_path): Reflect new argument
- ordering.
-
-Mon Apr 30 22:09:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc: Add LoadDLLinitfunc for secur32.dll.
- Add LoadDLLfuncEx statements for AllocateLocallyUniqueId@4,
- DuplicateTokenEx@24, LsaNtStatusToWinError@4,
- LsaDeregisterLogonProcess@4, LsaFreeReturnBuffer@4,
- LsaLogonUser@56, LsaLookupAuthenticationPackage@12,
- LsaRegisterLogonProcess@12,
- * environ.cc: Add extern declaration for `subauth_id'.
- (subauth_id_init): New function for setting `subauth_id'.
- (struct parse_thing): Add entry for `subauth_id'.
- * fork.cc (fork_parent): Call `RevertToSelf' and
- `ImpersonateLoggedOnUser' instead of `seteuid'.
- * security.cc: Define global variable `subauth_id'.
- (extract_nt_dom_user): New function.
- (cygwin_logon_user): Call `extract_nt_dom_user' now.
- (str2lsa): New static function.
- (str2buf2lsa): Ditto.
- (str2buf2uni): Ditto.
(subauth): Ditto.
- * security.h: Add prototype for `subauth'.
- * spawn.cc (spawn_guts): Use cygheap->user.token only if impersonated.
- Use `cygsid' type. Remove impersonation before allowing access to
- workstation/desktop to everyone. Call `RevertToSelf' and
- `ImpersonateLoggedOnUser' instead of `seteuid'.
- * syscalls.cc (seteuid): Rearranged to allow using subauthentication
- to retrieve user tokens when needed.
-
-Mon Apr 30 20:26:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (internal_getlogin): Formatting change.
-
-Mon Apr 30 19:58:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * grp.cc: Eliminate MAX_DOMAIN_NAME define.
- (read_etc_group): Substitute MAX_DOMAIN_NAME by
- INTERNET_MAX_HOST_NAME_LENGTH.
- * passwd.cc (parse_pwd): Don't force pw_name to be lower case.
- * sec_helper.cc: Substitute MAX_USER_NAME by UNLEN,
- MAX_COMPUTERNAME_LENGTH by INTERNET_MAX_HOST_NAME_LENGTH throughout.
- (lookup_name): Slight cleanup.
- * security.cc (alloc_sd): Substitute MAX_USER_NAME by UNLEN.
- * security.h: Define DEFAULT_UID as DOMAIN_USER_RID_ADMIN and
- DEFAULT_GID as DOMAIN_ALIAS_RID_ADMINS.
- * shared.cc (memory_init): Substitute MAX_USER_NAME by UNLEN.
- * thread.h: Ditto.
- * uinfo.cc (internal_getlogin): Substitute MAX_USER_NAME by UNLEN.
- Substitute MAX_COMPUTERNAME_LENGTH and MAX_HOST_NAME by
- INTERNET_MAX_HOST_NAME_LENGTH.
- * winsup.h: Include lmcons.h. Eliminate MAX_USER_NAME and
- MAX_HOST_NAME. Move DEFAULT_UID and DEFAULT_GID to security.h.
-
-Mon Apr 30 12:35:40 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (path_conv::check): Don't use path_flags when converting to
- MS-DOS syntax unless parsing tail of path component. Stop parsing path
- when we reach the 'root' of the path. Correctly copy tail to path
- component.
-
-Sun Apr 29 22:28:06 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (INIT_EXCEPTION_HANDLER): Eliminate.
- (init_exceptions): Just use init_exception_handler.
- (open_stackdumpfile): New function.
- (stack_info::first_time): Eliminate.
- (stack_info::init): Set up fields to avoid "first_time" consideration.
- (stack_info::walk): Remove "first_time" consideration.
- (stackdump): Change arguments to accept initial frame pointer and open
- stack file flag.
- (stack): Eliminate.
- (cygwin_stackdump): Use stackdump() rather than stack().
- (try_to_debug): Remove all synchronization logic. Just keep looping in
- exception handler until debugger notices us. Return 1 if successfully
- started debugger.
- (handle_exceptions): Just return if we know that we're debugging.
- Reorganize to avoid creating a stackdump file if we are starting a
- debugger. Return from exception handler if debugger started
- successfully.
- (sig_handle): Create a stackdump only if debugger wasn't started.
- * winsup.h (try_to_debug): Add an argument.
-
-Sun Apr 29 21:41:25 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (symlink_info::check): Remove extra arguments, move
- functionality back to path_conv::check. Clear symlink bit from pflags
- argument before detecting if this is a symlink.
- (path_conv::check): Convert posix path here instead of
- symlink_info::check. Only grab volflags when using ntsec.
- (symlink_info::check_case): Just replace appropriate part of input
- path.
-
-Sat Apr 28 19:36:13 2001 Christopher Faylor <cgf@cygnus.com>
-
- Throughout, change 'tty_attached' to 'real_tty_attached', for clarity.
- Throughout, change 'OutputStopped' to 'output_stopped', for
- consistency.
- * dtable.cc (stdio_init): Set controlling tty if not set by stdio
- opens.
- * exceptions.cc (ctrl_c_handler): Avoid special pgid checking if no tty
- is associated with the process.
- (Suggested by Tim Baker <dbaker@direct.ca>)
- * external.cc (fillout_pinfo): Return actual tty number for ctty.
- * fhandler_console.cc (get_tty_stuff): Set ctty when shared memory is
- allocated. Accept flags input from open().
- (set_console_ctty): New function.
- (fhandler_console::open): Pass flags to get_tty_stuff and rely on this
- function to set the ctty, if appropriate.
- * fhandler_termios.cc (fhandler_termios::set_ctty): Move to tty_min
- class.
- * fhandler_tty.cc (fhandler_tty_slave::open): Use tc field to access
- set_ctty().
- * tty.h (TTY_CONSOLE): Move to include/sys/cygwin.h.
- (tty_min): Add set_ctty class here.
- * include/sys/cygwin.h (TTY_CONSOLE): New home here.
-
- * path.cc (symlink_info): Make contents an actual buffer. Pass more
- flags to case_check.
- (path_conv::check): Reorganize to do parsing based on posix path rather
- than native path.
- (symlink_info::check): Expect posix path as input. Translate to native
- path here. Accept path_conv flags. Stop parsing if not a symlink
- regardless of whether previous path was a symlink.
-
-2001-04-27 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * thread.cc (thread_init_wrapper): Use _REENT_INIT to initialize the
- reent structure of newlib.
-
-Fri Apr 27 14:02:24 2001 Christopher Faylor <cgf@cygnus.com>
-
- * sigproc.h (sig_send): Add exception parameter to sig_send.
- * sigproc.cc (sig_send): Ditto. Use it when setting frame info.
- * exceptions.cc (handle_exceptions): Use exception flag when calling
- sig_send.
-
-2001-04-27 Egor Duda <deo@logos-m.ru>
-
- * tty.cc (tty::make_pipes): Set to_slave pipe mode to nonblocking.
- * fhandler_tty.cc (fhandler_pty_master::accept_input): If pipe buffer
- is full, give slave a chance to read data.
-
-2001-04-26 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * security.cc (alloc_sd): Add unrelated ACCESS_ALLOWED_ACE behind
- the `everyone' ACE.
-
-Wed Apr 25 15:07:37 2001 Christopher Faylor <cgf@cygnus.com>
-
- * sigproc.h [sigthread]: Add exception field.
- [sigframe::~sigframe]: Clear exception field.
- [sigframe::set]: Set exception field from caller.
- * sigproc.cc (sig_send): Set exception field when frame pointer is
- passed in.
- * exceptions.cc (interrupt_on_return): Always treat exception as
- interruptible.
-
-2001-04-25 Egor Duda <deo@logos-m.ru>
-
- * cygwin.din: Export asctime_r, ctime_r, gmtime_r, localtime_r
- * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 39
-
-Wed Apr 25 10:57:36 2001 Christopher Faylor <cgf@cygnus.com>
-
- * include/cygwin/version.h: Bump minor version number.
- * childinfo.h: Bump child structure magic number.
-
-2001-04-25 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * uinfo.cc (internal_getlogin): Return pointer to struct passwd.
- (uinfo_init): Accommodate the above change.
- * syscalls.cc (seteuid): Ditto.
-
-Tue Apr 25 11:08:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc: Add LoadDLLfunc statements for SetTokenInformation@16.
- * cygheap.cc: Include security.h.
- * grp.cc (internal_getgrent): New function.
- (getgroups): Rearranged using `internal_getgrent' and the new
- `cygsid' class.
- * passwd.cc (internal_getpwent): New function.
- * sec_acl.cc: Use new `cygsid' class throughout.
- (acl_access): Use `internal_getgrent' instead of `getgrent'.
- * sec_helper.cc: Use new `cygsid' class throughout.
- (get_id_from_sid): Use `internal_getgrent' instead of `getgrent'.
- Use `internal_getpwent' instead of `getpwent'.
- * security.cc: Use new `cygsid' class throughout.
- * security.h: Move `MAX_SID_LEN' from winsup.h to here.
- Add extern declarations for `internal_getgrent' and `internal_getpwent'.
- (class cygsid): New class.
- * shared.cc (sec_user): Use new `cygsid' class.
- * syscalls.cc (seteuid): Try to set owner to user and primary group to
- current group in impersonation token before performing impersonation.
- (setegid): Try to set primary group in process token to the new group
- if ntsec is on.
- * uinfo.cc (internal_getlogin): Use new `cygsid' class.
- Try to set owner to user and primary group to current group in process
- token if the process has been started from a non cygwin process.
- (uinfo_init): Set primary group only if the process has been started
- from a non cygwin process.
- * winsup.h: Move define for `MAX_SID_LEN' to security.h.
-
-Mon Apr 16 23:20:00 2001 Andy Younger <andylyounger@hotmail.com>
-
- * fhandler_dsp.cc: Improved handling of 8 bit playback modes.
- Put in mock support for SNDCTL_DSP_SETFRAGMENT.
-
-Tue Apr 24 23:51:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (getpwnam_r): Add pw_passwd handling as well.
- (getpwuid_r): Ditto.
-
-Tue Apr 24 23:43:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (getpwnam_r): Use correct offsets into buffer.
- Copy pw_gecos field as well.
- (getpwuid_r): Ditto.
-
-2001-04-24 Egor Duda <deo@logos-m.ru>
-
- * dlmalloc.c: New file. Port of Doug Lea's malloc
- * dlmalloc.h: Ditto.
- * Makefile.in: Add support for MALLOC_DEBUG
- * config.h.in: Ditto.
- * winsup.h: Ditto.
- * configure.in: Add --enable-malloc-debugging option.
- * configure: Regenerate.
- * debug.h: Include declarations for debugging malloc.
- * tty.cc (grantpt): Fix definition.
- (unlockpt): Ditto.
-
-Mon Apr 23 22:00:29 2001 Christopher Faylor <cgf@cygnus.com>
-
- Remove trailing underscore from fhandler_base and friends, throughout.
- * fhandler.h (fhandler_base::set_open_status): New method. Stores
- original open status.
- (fhandler_base::get_open_status): New method. Retrieves original open
- status.
- (fhandler_base::reset_to_open_binmode): New method.
- * fhandler.cc (fhandler_base::open): Save open status.
- (fhandler_base::init): Ditto.
- * fhandler_clipboard.cc (fhandler_clipboard::open): Ditto.
- * fhandler_console.cc (fhandler_console::open): Ditto.
- * fhandler_dsp.cc (fhandler_dsp::open): Ditto.
- * fhandler_dev_mem.cc (fhandler_dev_mem::open): Ditto.
- * fhandler_dev_random.cc (fhandler_dev_random::open): Ditto.
- * fhandler_serial.cc (fhandler_serial::open): Ditto.
- * fhandler_tty_slave.cc (fhandler_tty_slave::open): Ditto.
- * fhandler_tty_master.cc (fhandler_tty_master::open): Ditto.
- * fhandler_dev_zero.cc (fhandler_dev_zero::open): Ditto.
- * syscalls.cc (setmode): Rework so that 0 mode value causes reversion
- to open state.
-
- * fhandler_tty_slave.cc (fhandler_tty_slave::read): Use correct
- multiplier when converting from deciseconds to milliseconds.
-
-Mon Apr 23 13:28:35 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler.h (fhandler_base::clear_r_binary): New method.
- (fhandler_base::clear_w_binary): New method.
- * syscalls.cc (setmode): Accept 0 as mode value. Resets text/binary
- behavior for fd to default.
-
-Mon Apr 23 12:46:07 2001 Christopher Faylor <cgf@cygnus.com>
-
- * net.cc [errmap]: Add '0' condition.
- (find_winsock_errno): Don't translate no error to EPERM.
-
-Sun Apr 22 20:48:24 2001 Christopher Faylor <cgf@cygnus.com>
- * include/cygwin/version.h: Bump Cygwin version and API version.
+2002-05-17 Corinna Vinschen <corinna@vinschen.de>
-Mon Apr 23 9:27:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.cc (MTinterface::Init): Always initialise per process variables.
-
-Sun Apr 22 19:18:18 2001 Christopher Faylor <cgf@cygnus.com>
-
- * features.h: Reinstate as wrapper for sys/features.h.
-
-Mon Apr 23 0:10:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * security.cc (alloc_sd): Reformat comment.
- * shared.cc: Drop function declarations already in security.h.
+ * times.cc (utimes): Use FILE_WRITE_ATTRIBUTES even on 9x/Me when
+ opening file for writing timestamp.
+ * wincap.cc: Remove flag has_specific_access_rights.
+ * wincap.h: Ditto.
-Sun Apr 22 12:17:57 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-13 Pierre Humblet <pierre.humblet@ieee.org>
- * shortcut.c (check_shortcut): Close input file handle before
- returning.
- * path.cc (check_sysfile): Ditto.
- (symlink_info::check): Rely on opened file handle being closed by
- symlink checking routines. Set ext_tacked_on when .lnk is detected.
+ * syscalls.cc (seteuid): Set default dacl in process token.
+ Replace in-line code by call to verify_token().
+ (setegid): Reverse change from 2002-01-21. Add call to
+ RevertToSelf and set primary group in impersonation token.
+ * security.cc (create_token): Store pgrpsid in token security
+ descriptor, except if it already appears in my_grps.
+ Use sec_acl() in place of get_dacl().
+ (verify_token): Create from code in seteuid(), with tighter checks.
+ (get_dacl): Deleted.
+ (get_group_sidlist): Add argument to indicate if pgrpsid is already
+ in the groups.
+ * security.h: Define verify_token().
+ * autoload.cc: Load GetKernelObjectSecurity().
-Sat Apr 21 19:26:05 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-13 Mark Bradshaw <bradshaw@staff.crosswalk.com>
- * thread.cc (MTinterface::Init): Remove accidentally checked in code.
+ * cygwin.din: Add strlcat and strlcpy.
+ * include/cygwin/version.h: Increment API minor version number.
-Sun Apr 22 00:22:00 2001 Robert Collins <rbtcollins@hotmail.com>
+2002-05-09 Pierre Humblet <pierre.humblet@ieee.org>
- * passwd.cc (getpwuid): Check for thread cancellation.
- (getpwuid_r): Ditto.
- (getpwname): Ditto.
- (getpwnam_r): Ditto.
- * thread.h (pthread_mutex): New constructors for pshared operation.
- (MTinterface): Associative array for pshared mutex's.
- * thread.cc (MTinterface::Init): Initailize pshared mutex array.
- (pthread_cond::BroadCast): Implementation notes.
- (pthread_cond::TimedWait): Remove use of SignalObjectAndWait on non-NT systems.
- (pthread_mutex::pthread_mutex(unsigned short)): New function.
- (pthread_mutex::pthread_mutex (pthread_mutex_t *, pthread_mutexattr *)):New function.
- (pthread_mutex::pthread_mutex(pthread_mutexattr *)): Fail on pshared mutex's.
- (__pthread_mutex_getpshared): New function.
- (__pthread_join): Check for thread cancellation.
- (__pthread_cond_timedwait): Support pshared mutex's.
- (__pthread_cond_wait): Ditto.
- (__pthread_condattr_setpshared): Error on PROCESS_SHARED requests.
- (__pthread_mutex_init): Support pshared mutex's.
- (__pthread_mutex_getprioceiling): Ditto.
- (__pthread_mutex_lock): Ditto.
- (__pthread_mutex_trylock): Ditto.
- (__pthread_mutex_unlock): Ditto.
- (__pthread_mutex_destroy): Ditto.
- (__pthread_mutex_setprioceiling): Ditto.
- (__pthread_mutexattr_setpshared): Support PTHREAD_PROCESS_PSHARED requests.
+ * shared.cc (__sec_user): Split into sec_acl() and call orig_sid().
+ (sec_acl): Create from part of __sec_user(), except creator/owner.
+ * security.h: Define sec_acl() and MAX_DACL_LEN.
-Fri Apr 20 19:38:29 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-12 Christopher Faylor <cgf@redhat.com>
- * cygwin.din: Add *scanf and *scan_r functions.
+ * fhandler_disk_file.cc (fhandler_disk_file::open): Avoid using
+ O_DIROPEN when OS doesn't support it. Return proper errno in that
+ case.
-Fri Apr 20 22:25:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-05-12 Christopher Faylor <cgf@redhat.com>
- * security.cc (set_process_privileges): Swap out.
- * sec_helper.cc (set_process_privilege): Rename from
- `set_process_privileges'. Takes the privilege to enable or disable
- as parameter now.
- * security.h: Add prototype for `set_process_privileges'.
+ * syscalls.cc (_read): Change error to EBADF if attempt to read from a
+ non-readable fd.
-2001-04-19 Egor Duda <deo@logos-m.ru>
+2002-05-11 Christopher Faylor <cgf@redhat.com>
- * path.cc (path_conv::check): Always initialize member variables.
+ * fhandler.h (executable_states): For now, make dont_care_if_executable
+ equivalent to not_executable.
+ * sys/mount.h: Define MOUNT_NOTEXEC.
+ * path.h (fs_info): New class.
+ (path_conv): Move fs-specific fields to new 'fs' structure.
+ (path_conv::update_fs_info): Move to fs_info and rename to just 'update'.
+ * path.cc (fs_info::update): Ditto. Return 'true' if successful.
+ (fillout_mntent): Add ',noexec' to list of reported options.
-Fri Apr 20 12:27:49 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-11 Christopher Faylor <cgf@redhat.com>
- * include/sys/file.h: More cleanup for X_OK.
+ * fhandler_virtual.cc (fhandler_virtual::close): Quiet a compiler
+ warning.
-Fri Apr 20 11:48:45 2001 Christopher Faylor <cgf@cygnus.com>
+2002-05-10 Christopher January <chris@atomice.net>
+
+ * autoload.cc: Add dynamic load statements for
+ 'ZwQueryInformationProcess' and 'ZwQueryVirtualMemory'.
+ * fhandler.h: Change type of bufalloc and filesize members of
+ fhandler_virtual from int to size_t. Change type of position member
+ from __off32_t to __off64_t. Add new fileid member to fhandler_virtual
+ class. Make seekdir take an __off64_t argument. Make lseek take an
+ __off64_t argument. Add fill_filebuf method to fhandler_virtual. Add
+ fill_filebuf method to fhandler_proc. Add fill_filebuf method to
+ fhandler_registry. Add fill_filebuf method to fhandler_process. Add
+ saved_pid and saved_p members to fhandler_process.
+ * fhandler_proc.cc (proc_listing_array): Add 'loadavg', 'meminfo', and 'stat'.
+ (proc_fhandlers array): Ditto.
+ (fhandler_proc::open): Use fill_filebuf to flesh out the file contents.
+ (fhandler_proc::fill_filebuf): New method.
+ (fhandler_proc::format_proc_meminfo): Ditto.
+ (fhandler_proc::format_proc_stat): Ditto.
+ (fhandler_proc::format_proc_uptime): Ditto.
+ * fhandler_process.cc (process_listing): Add 'stat' and 'statm'.
+ (fhandler_process::fstat): Find the _pinfo structure for the process
+ named in the filename. Return ENOENT if the process is no longer
+ around. Set the gid and uid fields of the stat structure.
+ (fhandler_process::open): Store pid and pointer to _pinfo structure in
+ saved_pid and saved_p respectively. Use fill_filebuf to flesh out file
+ contents.
+ (fhandler_proc::fill_filebuf): New method.
+ (format_process_stat): New function.
+ (format_process_status): Ditto.
+ (format_process_statm): Ditto.
+ (get_process_state): Ditto.
+ (get_mem_values): Ditto.
+ * fhandler_registry.cc (fhandler_registry::seekdir): Change argument
+ type from __off32_t to __off64_t.
+ (fhandler_registry::fill_filebuf): New method.
+ * fhandler_virtual.cc (fhandler_virtual::seekdir): Change argument type
+ from __off32_t to __off64_t.
+ (fhandler_virtual::lseek): Ditto.
+ (fhandler_virtual::fill_filebuf): New method.
+ (fhandler_virtual::fhandler_virtual): Initialise fileid to -1.
+ * wincap.cc: Set flag has_process_io_counters appropriately.
+ * wincap.h: Add flag has_process_io_counters.
+
+2002-05-09 Christopher Faylor <cgf@redhat.com>
+
+ * syscalls.cc (_write): Change error to EBADF if attempt to write to a
+ non-writeable fd.
+
+2002-05-08 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygheap.h (class cygheap_user): Add member `orig_psid'.
+ Add method `orig_sid()'.
+ * cygheap.cc (cygheap_user::set_sid): Maintain orig_psid.
+
+2002-04-28 Norbert Schulze <norbert.schulze@web.de>
+
+ * localtime.cc (tzsetwall): Use wildabbr if generated timezone name
+ length < 3.
+
+2002-05-05 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * spawn.cc (spawn_guts): Move call to set_process_privilege()
+ to load_registry_hive().
+ * registry.cc (load_registry_hive): ditto.
+ * fork.cc (fork_parent): Call sec_user_nih() only once.
+
+2002-05-04 Christopher January <chris@atomice.net>
+
+ * path.h (path_conv::path_conv): Initialise normalized_path to NULL.
+
+2002-05-03 Christopher Faylor <cgf@redhat.com>
+
+ * net.cc (getdomainname): Change second argument of getdomainname to
+ size_t.
+
+2002-05-03 Christopher January <chris@atomice.net>
+
+ * fhandler_proc.cc (proc_listing): Add '.' and '..' to directory
+ listing.
+ (fhandler_proc::open): Change use of mode to flags. If the file does
+ not exist already, fail with EROFS if O_CREAT flag is set. Change
+ EROFS error to EACCES error when writing to a file. Use cmalloc to
+ allocate memory for filebuf.
+ (fhandler_proc::close): Use cfree to free filebuf.
+ (fhandler_proc::get_proc_fhandler): Properly detect attempts to access
+ unknown subdir.
+ * fhandler_process.cc (process_listing): Add '.' and '..' to directory
+ listing.
+ (fhandler_process::open): Use cmalloc to allocate memory for filebuf.
+ (fhandler_process::close): Use cfree to free filebuf.
+ * fhandler_registry.cc (registry_listing): Add . and '..' to directory
+ listing.
+ (fhandler_registry::open): Move check for open for writing before
+ open_key. Use cmalloc to allocate memory for filebuf.
+ (fhandler_registry::close): Use cfree to free filebuf.
+ (fhandler_registry::telldir): Use lower 16 bits of __d_position as
+ position in directory.
+ (fhandler_registry::seekdir): Ditto.
+ * fhandler_virtual.cc (fhandler_virtual::write): Change EROFS error to
+ EACCES error.
+ (fhandler_virtual::open): Set the NOHANDLE flag.
+ (fhandler_virtual::dup): Add call to fhandler_base::dup. Allocate
+ child's filebuf using cmalloc. Copy filebuf from parent to child.
+ (fhandler_virtual::close): Use cfree to free filebuf.
+ (fhandler_virtual::~fhandler_virtual): Ditto.
+ (from Chris Faylor <cgf@redhat.com>).
+ (fhandler_registry::readdir): Add support for '.' and '..' files in
+ subdirectories of /proc/registry.
+ * path.cc (path_conv::check): Do not return ENOENT if a file is not
+ found in /proc.
+
+2002-05-02 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_proc.cc (fhandler_proc::fstat): Use fhandler name rather
+ than path_conv name.
+ (fhandler_proc::open): Ditto.
+ * fhandler_process.cc (fhandler_process::fstat): Use fhandler name
+ rather than path_conv name.
+ (fhandler_process::open): Ditto.
+ * fhandler_registry.cc (fhandler_registry::fstat): Use fhandler name
+ rather than path_conv name.
+ (fhandler_registry::open): Ditto.
+ * path.cc (path_conv::check): Don't copy posix path when virtual.
+ (mount_info::conv_to_win32_path): Don't zero string when isproc. Just
+ derive normal windows path.
+
+ * path.h (path_conv::clear_normalized_path): Declare new method.
+ * path.cc (path_conv::clear_normalized_path): Define new method.
+ * dtable.cc (build_fhandler_from_name): Clear normalized path when
+ finished to conserve space.
+
+2002-05-02 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_proc.cc (fhandler_proc::fstat): Prime with information from
+ fhandler_base::fstat. Use defines rather than constants for permission
+ settings.
+
+2002-04-30 Eric Blake <ebb9@email.byu.edu>
+
+ * path.cc (hash_path_name): Improve hash function strength.
+
+2002-05-02 Robert Collins <rbtcollins@hotmail.com>
+
+ * thread.cc (__pthread_cond_dowait): Fix a race on signalling from a
+ thread woken by the same condition variable it's signalling on. Thanks
+ to Michael Beach for the report and test case.
+
+2002-05-02 Christopher Faylor <cgf@redhat.com>
+
+ * path.h (pathconv_arg): Add PC_POSIX.
+ (path_conv): Add normalized_path field.
+ * path.cc (path_conv::~path_conv): New destructor.
+ (path_conv::check): Set normalized_path, where appropriate.
+ * dtable.cc (build_fhandler_from_name): Use normalized path from
+ path_conv.
+ * syscalls.cc (chroot): Ditto.
+
+ * cygheap.h: Remove path_prefix_p declaration.
+
+2002-02-26 Christopher January <chris@atomice.net>
+ Christopher Faylor <cgf@redhat.com> (minor fixups)
+
+ * Makefile.in: Add fhandler_proc.o, fhandler_registry.o,
+ fhandler_process.o and fhandler_virtual.o.
+ * dtable.cc (dtable::build_fhandler): Add entries for FH_PROC,
+ FH_REGISTRY and FH_PROCESS. Set unix_name to the normalized posix
+ path.
+ * fhandler.h: Add constants for FH_PROC, FH_REGISTRY and FH_PROCESS.
+ Add class declarations for fhandler_virtual, fhandler_proc,
+ fhandler_registry and fhandler_virtual. Update fhandler_union
+ accordingly.
+ * fhandler_proc.cc: New file. Add implementation for fhandler_proc.
+ * fhandler_virtual.cc: New file. Add implementation for
+ fhandler_virtual.
+ * fhandler_process.cc: New file. Add implementation for
+ fhandler_process.
+ * fhandler_registry.cc: New file. Add implementation for
+ fhandler_registry.
+ * path.cc (isproc): New macro.
+ (isvirtual_dev): Ditto.
+ * path.cc (path_conv::check): Add check for virtual devices.
+ * path.cc (mount_info::conv_to_win32_path): Convert paths in /proc to
+ empty Win32 paths.
+ * path.cc (chdir): Replace check for FH_CYGDRIVE with more generic
+ isvirtual_dev macro. Force setting of posix path for virtual
+ fhandlers.
+ * path.h (path_prefix_p): Declare.
+
+
+Wed May 1 16:06:02 2002 Jason Tishler <jason@tishler.net>
+
+ * include/cygwin/types.h: Include <sys/sysmacros.h>.
+
+Wed Apr 17 11:27:04 2002 Jason Tishler <jason@tishler.net>
+
+ * security.cc (get_lsa_srv_inf): Prevent extraneous backslashes for
+ the NT Domain case.
+
+2002-04-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * net.cc (cygwin_accept): Set socket type for accepted socket.
+ (socketpair): Set socket type for both sockets.
+
+2002-04-12 Egor Duda <deo@logos-m.ru>
+
+ * fhandler.h (class fhandler_socket): New member to store socket type.
+ (fhandler_socket::get_socket_type): Access it.
+ (fhandler_socket::set_socket_type): Ditto.
+ * net.cc (cygwin_socket): Store socket type.
+ (cygwin_connect): Disable security checks for connectionless sockets.
+ (cygwin_accept): Ditto.
- * include/sys/file.h: Move X_OK protection earlier.
+2002-04-09 Mark Bradshaw <bradshaw@staff.crosswalk.com>
- * dtable.cc (dtable::vfork_child_fixup): Avoid closing already closed
- handles.
+ * cygwin.din: Add strptime.
+ * include/cygwin/version.h: Increment API version number.
-Fri Apr 20 16:29:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-04-09 Corinna Vinschen <corinna@vinschen.de>
- * grp.cc (getgroups): Change so that SIDs get compared instead
- of strings to SIDs.
+ * fork.cc (fork_child): Call fixup_mmaps_after_fork() somewhat earlier.
-Fri Apr 20 14:50:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-04-09 Corinna Vinschen <corinna@vinschen.de>
- * Makefile.in: Add object files `sec_helper.cc' and `sec_acl.cc'.
- * security.cc: Swap out several functions.
- * sec_acl.cc: New file. Move Sun compatibel ACL functions from
- `security.cc' to here.
- * sec_helper.cc: New file. Move security helper functions from
- `security.cc' to here.
- * security.h: Changed to accomodate the above changes.
+ * fhandler.cc (fhandler_base::open): Set read-only bit in
+ file_attributes when adequate.
-Fri Apr 20 14:12:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-03-28 Christopher Faylor <cgf@redhat.com>
- * grp.cc: Replace `group_in_memory_p' by `group_state'.
- Eliminate group_sem throughout.
- (enum grp_state): New enumeration type.
- (read_etc_group): Make race safe.
- * security.cc: Eliminate group_sem throughout.
+ * times.cc (gettimeofday): Fix typo in previous patch.
-Thu Apr 19 9:40:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-03-27 Wu Yongwei <adah@netstd.com>
- * mmap.cc (mmap): Drop usage of the same memory area if the same
- region of the same file is mapped twice.
+ * times.cc (gettimeofday): Revert to setting timezone info if tz !=
+ NULL.
-Wed Apr 18 16:53:54 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-21 Christopher Faylor <cgf@redhat.com>
- Throughout, change fdtab references to cygheap->fdtab.
- * child_info.h (cygheap_exec_info): Eliminate special fdtab stuff.
- * spawn.cc (spawn_guts): Ditto.
- * cygheap.cc (cygheap_init): Initialize fdtab, if appropriate.
- * cygheap.h (CYGHEAPSIZE): Include size of init_cygheap.
- (_cmalloc_entry): Include fdtab here.
- * dtable.h (dtable): Declare/define new methods.
- * dtable.cc (dtable::vfork_child_fixup): New method.
- (dtable::fixup_after_exec): Remove unneeded extra arguments.
- * dcrt0.cc (dll_crt0_1): Ditto.
+ * fhandler_disk_file.cc (fhandler_disk_file::fstat_helper): Always set
+ st_[ug]id to value derived from get_file_attributes.
- * environ.cc (getwinenv): Use case sensitive comparison.
- (winenv): Make a copy of environment cache to avoid realloc problems
- when duplicate environment variables exist in the environment. (From
- Egor Duda)
+2002-03-21 Christopher Faylor <cgf@redhat.com>
- * net.cc (cygwin_socket): Revert Apr 14 change.
+ * spawn.cc (find_exec): Return input if file not found.
- * include/sys/file.h: Protect against previous X_OK definition.
+2002-03-19 Boris Schaeling <boriss@web.de>
-Tue Apr 17 12:18:28 2001 Christopher Faylor <cgf@cygnus.com>
+ * poll.cc (poll): Add support for invalid descriptors.
- * passwd.cc: Eliminate passwd_sem throughout.
- * security.cc: Ditto.
+2002-03-15 Robert Collins <rbtcollins@hotmail.com>
-Tue Apr 17 12:18:28 2001 Robert Collins <rbtcollins@hotmail.com>
+ * fhandler.h (fhandler_termios::lseek): Override lseek.
+ * fhandler_termios.cc (fhandler_termios::lseek): Implement this.
- * cygwin.din: Export New functions.
- * passwd.cc (read_etc_passwd): Make race safe.
- (getpwuid_r): New function.
- (getpwnam_r): New function.
+2002-03-15 Christopher Faylor <cgf@redhat.com>
-2001-04-18 Egor Duda <deo@logos-m.ru>
+ * cygserver.cc: Include stdlib.h for exit declaration.
+ * threaded_queue.cc: Ditto.
- * grp.cc (getgroups): Avoid crash if passwd field if /etc/group is
- empty.
+2002-03-15 Christopher Faylor <cgf@redhat.com>
-Tue Apr 17 19:05:44 2001 Christopher Faylor <cgf@cygnus.com>
+ * pinfo.cc (pinfo::init): Use PID_ALLPIDS flag to control when a
+ redirected block should be marked as nonexistent.
+ (winpids::add): Use PID_ALLPIDS when looking for all pids.
+ * cygwin.h (PID_ALLPIDS): New enum element.
- * path.h (path_conv::add_ext_from_sym): Declare.
- * path.cc (path_conv::add_ext_from_sym): Convert to pure inline method.
+2002-03-15 Corinna Vinschen <corinna@vinschen.de>
-Tue Apr 17 18:50:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * glob.c (stat32_to_STAT): New function.
+ (g_lstat): Call user space functions always with 32 bit struct stat
+ as a workaround.
+ (g_stat): Ditto.
+ * include/glob.h (struct glob): Don't prototype function pointers
+ when compiling Cygwin.
- * path.cc (windows_device_names): Add missing NULL element.
+2002-03-14 Christopher Faylor <cgf@redhat.com>
-Tue Apr 17 12:14:54 2001 Christopher Faylor <cgf@cygnus.com>
+ * pinfo.cc (pinfo::init): Properly handle execed process stub when
+ PID_NOREDIR is specified.
- * path.cc (windows_device_names): Move dsp to proper location.
+2002-03-13 Boris Schaeling <boriss@web.de>
-Tue Apr 17 13:44:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * poll.cc (poll): Remove variable open_fds. Rearrange and add code to
+ fix settings of revents.
- * path.cc (path_conv::check): Set case_clash even if pcheck_case
- is set to PCHECK_ADJUST when a case clash is given for the last
- component in path.
- (symlink_info::case_check): Ditto.
- * syscalls.cc (_rename): Avoid overwriting an already existing file
- if a case clash is given even if pcheck_case is set to PCHECK_ADJUST.
+2002-03-13 Corinna Vinschen <corinna@vinschen.de>
-Tue Apr 17 2:07:07 2001 Christopher Faylor <cgf@cygnus.com>
+ * mmap.cc (mmap_record::map_map): Return -1 if VirtualProtect fails.
+ (list::erase): New method with no argument. Erase latest record
+ added.
+ (mmap64): Fail if map_map() fails.
- * config.h.in: Turn off VFORK again.
+2002-03-12 Corinna Vinschen <corinna@vinschen.de>
-Mon Apr 16 23:45:24 2001 Christopher Faylor <cgf@cygnus.com>
+ * sysconf.cc (sysconf): Fix condition.
- * path.h (cwdstuff): Move class.
- * cygheap.h (cwdstuff): To here.
- (init_cygheap): Add cwd field.
- * child_info.h (cygheap_exec_info): Eliminate cwd stuff.
- (child_info_spawn): Ditto.
- * dcrt0.cc (dll_crt0_1): Remove cygcwd.fixup_after_exec call. Convert
- cygcwd reference to cygheap->cwd.
- * path.cc: Ditto, throughout.
- (cwdstuff::copy): Eliminate.
- (cwdstuff::fixup_after_exec): Ditto.
- * spawn.cc (spawn_guts): Eliminate call to cygcwd.copy.
+2002-03-11 Corinna Vinschen <corinna@vinschen.de>
- * fhandler.h (FH_OSS_DSP): Move into "fast" device category.
+ * mmap.cc (msync): Check area given by addr and len for being a
+ contigeous mmap'd region.
-Mon Apr 16 19:19:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-03-11 Corinna Vinschen <corinna@vinschen.de>
- * mmap.cc: Move fh_paging_file from some functions to be
- a global static variable.
- (class mmap_record): Add `devtype_' member to remember
- the device type of the file. Add declaration for methods
- `get_device', `alloc_fh' and `free_fh'.
- (mmap_record::mmap_record): Initialize `devtype_' correctly.
- (mmap_record::alloc_fh): New method.
- (mmap_record::free_fh): Ditto.
- (munmap): Use new mmap_record::alloc_fh and mmap_record::free_fh
- methods to create a correct fhandler.
- (msync): Ditto.
- (fixup_mmaps_after_fork): Ditto.
+ * fork.cc (fork_child): Call fixup_mmaps_after_fork() before
+ closing parent process handle. Call fixup_mmaps_after_fork()
+ with parent process handle as parameter.
+ * mmap.cc (mmap_record::access): New method.
+ (fixup_mmaps_after_fork): Take process handle as parameter.
+ In case of FILE_MAP_COPY access, copy valid memory regions to child.
+ * pinfo.h (fixup_mmaps_after_fork): Change prototype accordingly.
-Mon Apr 16 16:01:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-03-07 Corinna Vinschen <corinna@vinschen.de>
- * grp.cc (getgroups): If `allow_ntsec' is set, use the process token
- information to evaluate the groups list.
+ * autoload.cc (NetGetDCName): Add symbol.
+ (NetServerEnum): Remove symbol.
+ * security.cc (get_lsa_srv_inf): Call NetGetDCName() instead of
+ NetServerEnum() since it's faster. Don't call it at all if machine
+ is not a domain member.
-Mon Apr 16 00:08:02 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-06 Christopher Faylor <cgf@redhat.com>
- * features.h: Remove this file as it is now being supplied by newlib.
+ * path.cc (normalize_posix_path): Avoid runs of '.'s > 2.
-Sun Apr 15 23:23:29 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-05 Christopher Faylor <cgf@redhat.com>
- * autoload.cc: Add winmm functions needed by fhandler_dsp.cc.
-
-Sun Apr 15 22:53:52 2001 Andy Younger <andylyounger@hotmail.com>
-
- * fhandler_dsp.cc: New file. Implements OSS like /dev/dsp.
- * include/sys/soundcard.h: New file. User land includes for OSS
- /dev/dsp.
- * fhandler.h: Add new class fhandler_dev_dsp and a FH_OSS_DSP
- definition.
- * dtable.cc (dtable::build_fhandler): Allow creation of the /dev/dsp
- device.
- * path.cc (windows_device_names): Add /dev/dsp into list of device
- names.
- * Makefile.in (DLL_OFILES): Add fhandler_dsp.o.
-
-Sun Apr 15 16:36:27 2001 Christopher Faylor <cgf@cygnus.com>
-
- * uname.c (uname): Default n in in86 to 6 if Windows returns > 6.
-
-Sun Apr 15 15:56:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (add_ext_from_sym): Redefine to call `add_ext_from_sym_'.
- (add_ext_from_sym_): New inline function.
-
-Sat Apr 14 19:23:52 2001 Christopher Faylor <cgf@cygnus.com>
-
- * config.h.in: Turn on VFORK by default.
-
-Sat Apr 14 18:04:35 2001 Christopher Faylor <cgf@cygnus.com>
-
- * net.cc (cygwin_socket): Set SO_LINGER to small value so closed UNIX
- domain sockets will not stay around.
-
-Sat Apr 14 18:01:43 2001 Pierre A. Humblet <Pierre.Humblet@ieee.org>
-
- * select.cc (socket_cleanup): Set SO_LINGER to small value so closed
- dummy sockets do not stay around. Use correct value for second argument
- to shutdown.
-
-Sat Apr 14 17:04:00 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.h (MTinterface): Add threadcount.
- * thread.cc (MTinterface::Init): Set threadcount to 1.
- (__pthread_create): Increment threadcount.
- (__pthread_exit): Decrement threadcount and call exit() from the last thread.
-
-Fri Apr 13 11:34:24 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * fork.cc (fork_child): Call the __pthread_atforkchild function.
- (fork_parent): Call the __pthread_atforkparent function.
- * cygwin.din: Export pthread_atfork.
- * thread.h (callback): New class.
- (MTinterface): Use it.
- * thread.cc (__pthread_atforkprepare): New function.
- (__pthread_atforkparent): New function.
- (__pthread_atforkchild): New function.
- (__pthread_atfork): New function.
- * pthread.cc (pthread_atfork): New function.
-
-Fri Apr 13 9:52:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (add_ext_from_sym): New define evaluating `known'suffix'.
- (path_conv::check): Use add_ext_from_sym throughout.
-
-Thu Apr 12 23:19:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * dir.cc (mkdir): Check for case clash.
- * environ.cc: Add extern declaration for `pcheck_case'.
- (check_case_init): New function.
- (struct parse_thing): Add "check_case" option.
- * errno.cc (_sys_nerrlist): Add text for ECASECLASH.
- (strerror): Add case branch for ECASECLASH.
- * fhandler.cc (fhandler_disk_file::open): Check for case clash.
- * path.cc: Add global variable `pcheck_case'.
- (struct symlink_info): Add member `case_clash' and method `case_check'.
- (path_prefix_p_): Call `pathnmatch' instead of `strncasematch'.
- (pathnmatch): New funtion.
- (pathmatch): Ditto.
- (path_conv::check): Add handling for case checking.
- (symlink): Check for case clash.
- (symlink_info::check): Add parameter for case checking.
- Handle case checking.
- (symlink_info::case_check): New method.
- (chdir): Don't use unconverted path if pcheck_case==PCHECK_STRICT.
- * path.h: Add extern declarations for `pathmatch' and
- `pathnmatch'.
- (enum case_checking): New enumeration type describing
- the case checking behaviour of path conversion routines.
- (class path_conv): Add member `case_clash'.
- * syscalls.cc (_link): Check for case clash.
-
-Thu Apr 12 12:49:53 2001 Christopher Faylor <cgf@cygnus.com>
-
- * syscalls.cc (mkfifo): New function stub.
-
-2001-04-12 Robert Collins <rbtcollins@hotmail.com>
-
- * configure.in: Remove PTH_ALLOW.
- * cygwin.din: Remove @PTH_ALLOW@ prefixes to pthread functions. Add
- new pthread exports.
- * pthread.cc: New wrapper functions for the above new exports.
- * sched.cc (valid_sched_parameters): New function.
- (sched_setparam): Use it.
- (sched_set_thread_priority): New function. Used by pthread_sched*.
- * thread.cc (pthread_key_destructor::InsertAfter): New function.
- (pthread_key_destructor::UnlinkNext): New function.
- (pthread_key_destructor::Next): New function.
- (pthread_key_destructor_list::Insert): New function.
- (pthread_key_destructor_list::Remove): New function.
- (pthread_key_destructor_list::Pop): New function.
- (pthread_key_destructor::pthread_key_destructor): New function.
- (pthread_key_destructor_list::IterateNull): New function.
- (MTinterface::Init): Initialise new member.
- (pthread::pthread): Initialise new members.
- (pthread::create): Copy new attributes. Set the new thread priority.
- (pthread_attr::pthread_attr): Initialise new members.
- (pthread_key::pthread_key): Setup destructor function.
- (pthread_key::~pthread_key): Remove destructor function.
- (pthread_mutexattr::pthread_mutexattr): New function.
- (pthread_mutexattr::~pthread_mutexattr): New function.
- (__pthread_once): New function.
- (__pthread_cleanup): New function.
- (__pthread_cancel): New function.
- (__pthread_setcancelstate): New function.
- (__pthread_setcanceltype): New function.
- (__pthread_testcancel): New function.
- (__pthread_attr_getinheritsched): New function.
- (__pthread_attr_getschedparam): New function.
- (__pthread_attr_getschedpolicy): New function.
- (__pthread_attr_getscope): New function.
- (__pthread_attr_setinheritsched): New function.
- (__pthread_attr_setschedparam): New function.
- (__pthread_attr_setschedpolicy): New function.
- (__pthread_attr_setscope): New function.
- (__pthread_exit): Call any key destructors on thread exit.
- (__pthread_join): Use the embedded attr values.
- (__pthread_detach): Use the embedded attr values.
- (__pthread_getconcurrency): New function.
- (__pthread_getschedparam): New function.
- (__pthread_key_create): Pass the destructor on object creation.
- (__pthread_key_delete): Correct incorrect prototype.
- (__pthread_setconcurrency): New function.
- (__pthread_setschedparam): New function.
- (__pthread_cond_timedwait): Support static mutex initialisers.
- (__pthread_cond_wait): Ditto.
- (__pthread_mutex_getprioceiling): New function.
- (__pthread_mutex_lock): Support static mutex initialisers.
- (__pthread_mutex_trylock): Ditto.
- (__pthread_mutex_unlock): Ditto.
- (__pthread_mutex_destroy): Ditto.
- (__pthread_mutex_setprioceiling): New function.
- (__pthread_mutexattr_getprotocol): New function.
- (__pthread_mutexattr_getpshared): New function.
- (__pthread_mutexattr_gettype): New function.
- (__pthread_mutexattr_init): New function.
- (__pthread_mutexattr_destroy): New function.
- (__pthread_mutexattr_setprotocol): New function.
- (__pthread_mutexattr_setprioceiling): New function.
- (__pthread_mutexattr_getprioceiling): New function.
- (__pthread_mutexattr_setpshared): New function.
- (__pthread_mutexattr_settype): New function. Remove stubs for non
- MT_SAFE compilation.
- * thread.h: Remove duplicate #defines. Add prototypes for new
- functions in thread.cc.
- (pthread_key_destructor): New class.
- (pthread_key_destructor_list): New class.
- (pthread_attr): Add new members.
- (pthread): Remove members that are duplicated in the pthread_attr
- class.
- (pthread_mutex_attr): Add new members.
- (pthread_once): New class.
- * include/pthread.h: Add prototypes for new functions exported from
- cygwin1.dll. Remove typedefs.
- * include/sched.h: Add prototypes for new functions in sched.cc.
- * include/cygwin/types.h: Add typedefs from pthread.h
-
-Tue Apr 10 22:02:53 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (struct symlink_info): Add extn and ext_tacked_on fields.
- (path_conv::check): Only tack on extension if a known one didn't
- already exist.
- (suffix_scan::has): Return pointer to known extension.
- (symlink_info::check): Record location of extension, if any.
-
-2001-04-09 Egor Duda <deo@logos-m.ru>
-
- * fhandler.h (class fhandler_socket): Add members and methods to
- support secure connections on AF_UNIX sockets.
- * fhandler_socket.cc (fhandler_socket::set_connect_secret): New method.
- (fhandler_socket::get_connect_secret): Ditto.
- (fhandler_socket::create_secret_event): Ditto.
- (fhandler_socket::close_secret_event): Ditto.
- (fhandler_socket::check_peer_secret_event): Ditto.
- (fhandler_socket::fixup_after_fork): Duplicate secret event to child.
- (fhandler_socket::dup): Copy address family.
- (fhandler_socket::close): Close secret event.
- * net.cc (get_inet_addr): Read secret cookie.
- (cygwin_connect): Check if peer knows secret cookie value.
- (cygwin_accept): Ditto. Copy address family to newly created socket.
- (cygwin_bind): Generate and write secret cookie.
- (wsock_init): Initialize random number generator.
-
-Sun Apr 8 20:40:58 2001 Christopher Faylor <cgf@cygnus.com>
-
- * Makefile.in: Put -lgcc last in list of libraries, since stdc++
- library needs it.
- * cygwin.din: Remove obsolete "__empty" export.
- * exceptions.cc (call_signal_handler_now): Force inclusion of function
- even when -finline-functions is specified.
- * sigproc.h: Remove obsolete call_signal_handler declaration.
-
-Sun Apr 8 20:36:55 2001 Benjamin Riefenstahl <Benjamin.Riefenstahl@epost.de>
-
- * fhandler_console.cc (cp_get_internal): New function.
- (cp_convert): New function.
- (con_to_str): New function.
- (str_to_con): New function.
- (fhandler_console::read): Replace OemToCharBuff with con_to_str.
- (fhandler_console::write_normal): Replace CharToOemBuff with str_to_con.
-
-Thu Apr 5 22:41:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * syscalls.cc (stat_worker): Fix conditional which still allowed
- successful stat'ing of non-existant files.
-
-Wed Apr 4 10:37:44 2001 Christopher Faylor <cgf@cygnus.com>
-
- * child_info.h: Bump magic number for fork/exec/spawn.
-
-Tue Apr 3 20:06:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * errno.cc (errmap): Map ERROR_FILE_INVALID to ENXIO.
-
-Mon Apr 2 22:48:58 2001 Christopher Faylor <cgf@cygnus.com>
-
- * cygrun.c (main): Fix compiler warning.
- * gmon.c (_mcleanup): Ditto.
- * profil.c (profile_off): Ditto.
-
- * net.cc (find_winsock_errno): New function.
- (__set_winsock_errno): Use find_winsock_errno.
- (cygwin_setsockopt): Detect SO_ERROR for debugging.
- (cygwin_getsockopt): Ditto. Translate error when getsockopt returns
- SO_ERROR.
- * winsup.h: regparmize __set_winsock_errno.
- * include/sys/strace.h: Document that strace functions can't use
- regparm.
-
-2001-04-02 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * fhandler.cc (fhandler_disk_file::open): Avoid checking a magic
- number of a directory.
-
-Mon Apr 2 00:24:08 2001 Christopher Faylor <cgf@cygnus.com>
-
- * shared_info.h (mount_info): Remove mnt_ elements.
- * thread.h (struct _winsup_t): Add mnt_ elements.
- * path.cc (fillout_mntent): Use mnt_ elements from reent_winsup ().
-
-Sun Apr 1 20:10:34 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (sigframe::call_signal_handler): Return value of
- call_signal_handler_now.
- * sigproc.h (sigframe): Use constructor.
- * syscalls.cc (_read): Correct errno test prior to calling signal
- handler.
+ * errno.cc: Change EPERM associated text to "Operation not permitted"
+ throughout.
-Sun Apr 1 00:38:06 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-05 Christopher Faylor <cgf@redhat.com>
- * exceptions.cc (sigframe::call_signal_handler): Move outside of "C"
- block or some compilers will complain.
+ * fhandler_socket.cc (fhandler_socket::close): Respond to signals while
+ looping, waiting for socket to close. Superstitiously clear last error
+ when WSAEWOULDBLOCK.
-Sun Apr 1 00:24:14 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-05 Robert Collins <rbtcollins@hotmail.com>
- * exceptions.cc (call_signal_handler_now): Rename from
- call_signal_handler to avoid C++ confusion.
+ * cygserver_transport_pipes.cc (transport_layer_pipes::transport_layer_pipes):
+ Always init - until static members work correctly.
+ * shm.cc (shmget): Initialize the security descriptor - thanks Corinna!
+ * include/sys/ipc.h: Make the ipc control constants partitioned off from the sem
+ control constants.
-Sun Apr 1 00:08:15 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-04 Christian Lestrade <christian.lestrade@free.fr>
- * path.cc (fillout_mntent): Always remove drive root directories from
- future consideration by "/cygdrive" reporting.
- (cygdrive_getmnt): Avoid reporting removable drives or drives with no
- media mounted.
+ * include/sys/termios.h: Define _POSIX_VDISABLE. Define CCEQ macro.
+ * fhandler_termios.cc: Include <sys/termios.h>.
+ (line_edit): Recognize disabled c_cc[] chars. Ignore VDISCARD when
+ not in ICANON mode.
-Sat Mar 31 21:56:19 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-04 Dmitry Timoshkov <dmitry@baikal.ru>
- * thread.h (struct _winsup_t): Remove obsolete elements. Add
- available_drives element.
- * path.cc (mount_info::getmntent): Report "/cygdrive" drives when
- mounted drives are exhausted.
- (fillout_mntent): New function.
- (mount_item::getmntent): Use fillout_mntent.
- (cygdrives_mntent): New function. Returns next available "/cygdrive".
- (setmntent): Initialize available "/cygdrives".
- * syscalls.cc: Remove some if 0'ed code.
- * times.cc (timezone): Use more descriptive variable name.
+ * syscalls.cc (truncate64): Use ftruncate64 directly to not lose
+ upper 32 bits.
-Sat Mar 31 18:59:52 2001 Christopher Faylor <cgf@cygnus.com>
+2002-03-04 Robert Collins <rbtcollins@hotmail.com>
- * sigproc.h (class sigframe): Implement 'unregister()' method.
- (sigframe::~sigframe): Use unregister method.
- (sigframe::call_signal_handler): Declare new method.
- * exceptions.cc (sigframe::call_signal_handler): New method.
- Unregisters current sigframe before calling signal handler.
- (setup_handler): Clear waiting threads prior to arming signal_arrived.
- * syscalls.cc (_read): Change goto to loop. Recalculate sigframe
- inside of loop so that constructor is called when appropriate.
- * wait.cc (wait4): Ditto.
+ * cygserver_shm.cc (delete_shmnode): New function.
+ (client_request_shm::serve): Use it.
- * signal.cc: Change "sig" to "signal" in debugging messages throughout.
- * sigproc.cc: Ditto.
+2002-03-04 Robert Collins <rbtcollins@hotmail.com>
-Sat Mar 31 17:12:08 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygserver_shm.cc (client_request_shm::serve): Implement SHM_DETACH.
+ * shm.cc (shmdt): Implement.
- * fhandler_serial.cc (fhandler_serial::raw_write): Close protected
- handles with ForceCloseHandle or suffer spurious warnings.
+2002-03-04 Robert Collins <rbtcollins@hotmail.com>
-Sat Mar 31 16:23:32 2001 Christopher Faylor <cgf@cygnus.com>
+ * cygserver_shm.cc: Run indent.
+ (deleted_head): New global for storing shm id's pending deletion.
+ (client_request_shm::serve): Return ENOSYS for invalid request types.
+ Implement SHM_DEL - delete a shm id.
+ * cygserver_shm.h (SHM_DEL): New type value.
+ * shm.cc (delete_inprocess_shmds): New function, does what it's name implies.
+ (shmctl): Implement shm_rmid control type.
- * fhandler.cc (fhandler_base::read): Remove special handling of CTRL-Z.
+2002-03-04 Robert Collins <rbtcollins@hotmail.com>
-Sat Mar 31 11:09:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * Makefile.in (install): Remove install-bin to allow make install to work.
- * fhandler.h (class fhandler_console): Add members `insert_mode'.
- * fhandler_console.cc (fhandler_console::dup): Duplicate `insert_mode'.
- (fhandler_console::fhandler_console): Initialize `insert_mode'.
- (fhandler_console::char_command): Add terminal capabilities
- "enter insert mode" = \E[4h and "exit insert mode" = \E[4l.
- Care for insert mode on terminal capability "repeat char" = \E[x;yb.
- (fhandler_console::write_normal): Care for insert mode before writing
- to the console.
- (array keytable): Add keymapping for modified cursor and control
- block keys (xterm like).
+2002-03-03 Robert Collins <rbtcollins@hotmail.com>
-Fri Mar 30 13:02:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * shm.cc (shmat): Prevent a compile error.
+ (shmdt): Set errno as this function is incomplete.
- * fhandler.h (class fhandler_console): Add members `savebufsiz' and
- `savebuf' to allow save/restore of screen.
- * fhandler_console.cc (fhandler_console::dup): Duplicate `savebufsiz'
- and `savebuf'.
- (fhandler_console::fhandler_console): Initialize `savebufsiz' and
- `savebuf'.
- (fhandler_console::char_command): Add terminal capabilities
- "save screen content" = \E[?47h and "restore screen content" = \E[?47l.
+2002-02-28 Christopher Faylor <cgf@redhat.com>
-Wed Mar 28 19:28:50 2001 Christopher Faylor <cgf@cygnus.com>
+ * times.cc: Remove if 0'd code. Clean up slightly.
- * path.cc (chdir): Eat trailing whitespace on input path.
+2002-02-28 Robert Collins <rbtcollins@hotmail.com>
-Tue Mar 27 22:38:42 2001 Christopher Faylor <cgf@cygnus.com>
+ * Merge cygwin_daemon into head minus the new shm and ipc exports.
- * lib/_cygwin_S_IEXEC.c: Remove "const" from globals or they never seem
- to be defined. Wrap definitions in extern "C". Include winsup.h to
- assure proper definitions.
+2002-02-28 Robert Collins <rbtcollins@hotmail.com>
- * dcrt0.cc (dll_crt0_1): Call stdio_init after premain run so that
- binmode.o, etc., will control default stdio settings.
- * dtable.cc (dtable::init_std_file_from_handle): Allow __fmode to force
- binmode/textmode settings. Default pipes to binmode.
+ * fhandler_tty.cc (fhandler_tty_slave::open): More debugging.
+ (fhandler_tty_slave::read): Fix printf type for the handle.
+ * tty.cc (tty::common_init): Add a FIXME for security.
-Tue Mar 27 11:31:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-29 Robert Collins <rbtcollins@hotmail.com>
- * mmap.cc (mmap): Fix conditional for previous patch.
+ * Makefile.in (OBJS): Remove duplicate localtime.o.
-Mon Mar 26 18:48:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-17 Robert Collins <rbtcollins@hotmail.com>
- * mmap.cc (mmap): Outflank copy-on-write problem on 9x by
- setting access mode to FILE_MAP_READ when read access is requested.
+ * cygserver.cc (check_and_dup_handle): Consolidate the two variants for
+ simplicity.
+ Add Some basic debug output.
+ (client_request_attach_tty::serve): Use the new debug_printf for clarity.
+ Mark the duplicated handles as inheritable - fixup_after_fork() doesn't reopen
+ tty's.
-Sun Mar 25 20:12:21 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-16 Robert Collins <rbtcollins@hotmail.com>
- * dlfcn.cc (check_access): Eliminate.
- (check_path_access): Use passed in path_conv buf.
- (get_full_path_of_dll): Use passed in name buf to avoid a static. Rip
- out most of the path checking since LoadLibrary will do all of this
- automatically.
- (dlopen): Set errno when appropriate (may not be compliant?).
- * environ.cc (posify): Don't pass in "native" path if it seems to
- actually be posix.
-
-Thursday Mar 22 2001 Robert Collins <rbtcollins@hotmail.com>
+ * cygserver.cc (transport): Correct scope.
+ (client_request_attach_tty::serve): Add more debug information.
+ Fix erroneous use of transport instead of conn.
+ * cygserver_transport_pipes.cc (transport_layer_pipes::close): More debug.
+ (transport_layer_pipes::read): Ditto.
+ (transport_layer_pipes::write): Ditto.
+ (transport_layer_pipes::impersonate_client): Ditto.
- * fhandler.h (fhandler_dev_clipboard): Extend to support writing.
- * fhandler_clipboard.cc (fhandler_dev_clipboard::fhandler_dev_clipboard):
- Initialize new fields. Open clipboard here.
- (fhandler_dev_clipboard::dup): New method.
- (fhandler_dev_clipboard::open): Accomodate new fields. Register
- clipboard here, if appropriate.
- (set_clipboard): New function. Moves buffer to clipboard.
- (fhandler_dev_clipboard::write): Truly implement clipboard writing.
- (fhandler_dev_clipboard::read): Reimplement to allow successive reads.
- (fhandler_dev_clipboard::lseek): Truly implement seeks in clipboard.
- (fhandler_dev_clipboard::close): Clear out new fields. Support
- sequential reads and sequential writes. Support for binary data via a
- native clipboard format.
+Mon Oct 8 7:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
-2001-03-22 Egor Duda <deo@logos-m.ru>
+ * cygserver.cc (server_request::process): Rename client_request_shm_get to
+ client_request_shm.
+ * cygserver_process.cc (process_cache::add): Rename to add_task.
+ Use process_cleanup instead of process_request.
+ (process_cache::remove_process): New method.
+ (process::process): Initialize new members.
+ (process::~process): New member.
+ (process::cleanup): New method.
+ (process::add_cleanup_routine): New method.
+ (process_request::process): Rename to process_cleanup.
+ Call the process object's cleanup method and then delete it.
+ (process_process_param::request_loop): Remove the signalling process.
+ * cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm.
+ (client_request_shm_get::serve): Handle attach request counting.
+ * cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm.
+ (class shm_cleanup): New class.
+ * shm.cc: Globally rename client_request_shm_get to client_request_shm.
+ (client_request_shm::client_request_shm): New constructor for attach requests.
+ (shmat): Use it.
+ * include/cygwin/cygserver_process.h (class process_request): Rename to
+ process_cleanup.
+ (class cleanup_routine): New class.
+ (class process): New members and methods to allow calling back when the process
+ terminates.
- * fhandler_console.cc (fhandler_console::set_default_attr): Update
- console color attributes on tty reset.
+Thu Oct 4 14:12:00 2001 Robert Collins <rbtcollins@hotmail.com>
+ * cygserver.cc (request_loop): Make static.
+ (main): Use new cache constructor syntax.
+ Start cache worker threads.
+ Cleanup the cache at shutdown.
+ * cygserver_process.cc: Run indent.
+ (process_cache::process_cache): Add a trigger to use when adding a process.
+ (process_cache::process): Move process_entry to process.
+ Insert at the end of the list.
+ Trigger the request loop when new process's inserted.
+ (process_cache::process_requests): Do it.
+ (process_cache::add): New method.
+ (process_cache::handle_snapshot): New method.
+ (process::process): Merge in the process_entry fields.
+ (process::handle): Make a stub function.
+ (process::exit_code): New method.
+ (process_request::process): New method.
+ (process_process_param::request_loop): New method.
+ * cygserver_shm.cc: New header dependency - threaded_queue.h.
+ * threaded_queue.cc (threaded_queue::cleanup): Clearer messages.
+ (queue_process_param::stop): Short spinlock on interruptible threads.
+ * threaded_queue.h (class threaded_queue): New constructor.
+ * include/cygwin/cygserver_process.h (process_request): New class.
+ (process_entry): Remove.
+ (process): Merge in process_entry.
+ (process_cache): Inherit from threaded_queue.
-Wed Mar 21 22:12:36 2001 Christopher Faylor <cgf@cygnus.com>
+Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * autoload.cc (kernel32_init): New function for kernel32 autoload
- initialization.
- (SignalObjectAndWait): Add conditional load of this function when it is
- available.
+ * cygserver.cc (class server_process_param): Use new constructor syntax.
+ * cygserver_process.cc (process_cache::~process_cache): New function.
+ * threaded_queue.cc: Define condition debug_printf.
+ Run indent.
+ (threaded_queue::cleanup): Move queue_process_param guts to a method.
+ (threaded_queue::process_requests): Ditto.
+ (queue_process_param::queue_process_param): New method.
+ (queue_process_param::~queue_process_param): Ditto.
+ (queue_process_param::start): Ditto.
+ (queue_process_param::stop): Ditto.
+ * threaded_queue.h (class queue_process_param): Add support for
+ interruptible request loops.
+ * cygwin/include/cygwin/cygserver_process.h (class process_cache): Add
+ destructor.
-2001-03-21 Robert Collins <rbtcollins@hotmail.com>
+Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * sched.cc: New file. Implement sched*.
- * include/sched.h: New file. User land includes for sched*.
- * Makefile.in: Add sched.o
- * cygwin.din: Add exports for sched*.
+ * cygserver_client.cc: New flag allow_daemon to disable the daemon completely.
+ (cygserver_request): Check it.
+ (cygserver_init): Ditto.
+ * environ.cc (parse_thing): Add (no)daemon option.
-Tue Mar 20 14:48:46 2001 Christopher Faylor <cgf@cygnus.com>
+Tue Oct 2 23:00:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * dtable.cc: Guard against new winsock.h/winsock2.h warnings when
- mixing winsock*.h and sys/types.h.
- * fhandler_socket.cc: Ditto.
- * net.cc: Ditto.
- * select.cc: Ditto.
- * exceptions.cc: Remove unneeded define.
+ * shm.cc: Update to handle include changes from HEAD.
-Mon Mar 19 17:43:29 2001 Christopher Faylor <cgf@cygnus.com>
+Tue Oct 2 16:06:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * exceptions.cc (interruptible): Update debugging output.
- (setup_handler): Ensure that wait_sig loop wakes up when we punt on
- sending a signal.
- * poll.cc (poll): Add signal guard here.
+ * Makefile.in: Remove cygserver_shm.o from cygwin1.dll.
+ Rename cygserver_shm_outside.o to cygserver_shm.o.
+ * cygserver.cc (server_request::process): Use the new client_request
+ constructor.
+ * cygserver_client.cc: Remove the #ifdef's stubs for the server method
+ within cygwin.
+ (client_request_attach_tty::client_request_attach_tty): Use the new
+ client_request constructor.
+ (client_request_shutdown::client_request_shutdown): Ditto.
+ (client_request::client_request): Ditto.
+ * cygserver_shm.cc (client_request_shm_get::serve): Remove the
+ #ifdef'd stub for in-cygwin builds.
+ (client_request_shm_get::client_request_shm_get): Use the new
+ client_request constructor, and remove the in-cygwin variants.
+ * cygserver_shm.h (class client_request_shm_get): #ifndef test the
+ serve method - it's only used in cygserver.
+ * shm.cc (client_request_shm_get::client_request_shm_get): New function.
+ * include/cygwin/cygserver.h (request_header): New constructor.
+ (class client_request): Use it.
+ New constructor accepting the header size.
+ #ifndef test the server method - it's only used within cygserver.
+ (client_request_get_version): #ifdef test the server method.
+ (client_request_shutdown): Ditto.
+ (client_request_attach_tty): Ditto.
-2001-03-19 Egor Duda <deo@logos-m.ru>
+Tue Oct 2 9:57:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * tty.h (tty::create_inuse): Add new parameter to allow non-
- inheritable 'inuse' events.
- * tty.cc (tty::create_inuse): Use new parameter.
- * fhandler_tty.cc (fhandler_tty_master::init): Ditto.
- * fhandler_tty.cc (fhandler_pty_master::open): Ditto.
- * fhandler_tty.cc (fhandler_tty_master::init): Create master_alive
- event.
- * tty.cc (tty_list::terminate): Close master_alive event.
- * fhandler_tty.cc (fhandler_tty_common::close): Send EOF to slaves
- when master side is closed.
+ * Makefile.in: add threaded_queue.o to cygserver.exe.
+ * cygserver.cc: Include threaded_queue.h
+ (class server_request): Inherit from queue_request.
+ (class server_process_param): Inherit from queue_process_param.
+ (class server_request_queue): Inherit from threaded_queue.
+ (request_loop): Adjust for new types.
+ (server_request_queue::process_requests): Remove guts to
+ threaded_queue::process_requests.
+ (server_request::server_request): Adjust for new types.
+ (worker_function): Delete.
+ (server_request_queue::create_workers): Delete.
+ (server_request_queue::cleanup): Delete.
+ (server_request_queue::add): Move guts to threaded_queue::add.
+ * threaded_queue.cc: New file.
+ * threaded_queue.h: New file.
-Mon Mar 19 14:32:00 2001 Corinna Vinschen <corinna@vinschen.de>
+Mon Oct 1 12:38:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * mmap.cc (map::get_list_by_fd): Avoid calling `get_namehash' when
- file descriptor is -1.
+ * cygserver.cc (client_request::serve): New function.
+ * cygserver_process.cc: Inlude <pthread.h> for pthread_once.
+ (process_cache::process_cache): Initialise a crtiical section for write access.
+ (process_cache::process): Use the critical section. Also add missing entries to
+ the cache.
+ (do_process_init): New function to initalise class process static variables.
+ (process::process): Ensure that the process access critical section is
+ initialised.
+ (process::handle): Close the handle of old process's when they have terminated
+ and we are returning the handle for a process with the same pid.
+ * cygserver_shm.cc: Run indent.
+ Include cygserver_process.h to allow process cache functionality.
+ (client_request_shm_get::serve): New parameter for process cache support.
+ Use the process cache, not OpenProcess to get a handle to the originating process.
+ Fix a handle leak with token_handle.
+ * cygserver_shm.h (class client_request_shm_get): Update ::serve for process
+ cache support.
+ * cygserver_transport_pipes.cc: Redefine debug_printf to be conditional on DEBUG.
+ * include/cygwin/cygserver.h: Do not implement client_request::serve in the
+ header.
+ * include/cygwin/cygserver_process.h (class process_cache): Add a write access
+ critical section to prevent races when requests from a multithreaded
+ application arrive.
-Sat Mar 17 18:30:00 2001 Corinna Vinschen <corinna@vinschen.de>
+Sun Sep 30 23:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * syscalls.cc (check_posix_perm): New static function.
- (fpathconf): Add _PC_POSIX_PERMISSIONS and _PC_POSIX_SECURITY
+ * Makefile.in: Add cygserver_process.o to cygserver.exe.
+ * cygserver.cc: Include signal.h and cygwin_version.h.
+ Define debug_printf as a macro.
+ Define DEBUG to a value.
+ (client_request_attach_tty::serve): Add beginning of process cache support.
+ Change from #ifdef DEBUG to work with new DEBUG style.
+ (client_request_get_version::serve): Add beginning of process cache support.
+ (class server_request): New prototype for support of process cache.
+ (class queue_process_param): New class to allow request loop threading.
+ (class server_request_queue): Add beginning of process cache support.
+ Allow request loop threading.
+ (request_loop): Thread function for request loops.
+ (server_request_queue::process_requests): Initiator for threaded request loops.
+ (client_request_shutdown::serve): Add beginning of process cache support.
+ (server_request::server_request): Ditto.
+ (server_request::process): Use debug_printf. Add beginning of process cache
support.
- (pathconf): Ditto.
- * include/cygwin/version.h: Bump API minor number to 37.
-
-2001-03-18 Egor Duda <deo@logos-m.ru>
-
- * fhandler.h (fhandler_tty_slave): Declare new methods.
- * select.cc (fhandler_tty_slave::select_read): New method.
- * select.cc (fhandler_tty_slave::ready_for_read): Ditto.
- * select.cc (verify_tty_slave): New function.
- * fhandler_termios.cc (fhandler_termios::line_edit): Empty input
- buffer on signal.
- * fhandler_tty.cc (fhandler_tty_slave::read): Check for input data
- after reading from pipe. Reset event if input pipe is empty.
- * tty.h (class tty): Allow creating events with manual reset.
- * tty.cc (tty::get_event): Use manual_reset flag.
- * tty.cc (tty::common_init): Create input_available_event with
- manual reset.
-
-Sat Mar 17 21:48:03 2001 Christopher Faylor <cgf@cygnus.com>
-
- * external.cc (fillout_pinfo): Match windows pid, as well as cygwin pid
- when passed in pid. Don't prematurely break when searching for a pid.
-
- * thread.h (_winsup_t): Eliminate unneeded field.
-
-Sat Mar 17 20:46:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (get_95_ifconf): Use strcasematch instead of strcasecmp.
- * syscalls.cc (_unlink): Ditto.
- (_rename): Ditto.
-
-Sat Mar 17 12:43:15 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc (suffix_scan::next): Avoid searching for foo.lnk twice when
- input is "foo".
-
-Sat Mar 17 18:10:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * net.cc (cygwin_socket): Set protocol to 0 when address family is
- AF_UNIX to avoid WSAEPROTONOSUPPORT error.
-
-Sat Mar 17 09:51:32 2001 Mathew Brozowski <brozow@tavve.com>
-
- * net.cc (cygwin_socket): Pass protocol parameter to socket call.
-
-Sat Mar 17 02:05:38 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dir.cc (readdir): Use strcasematch for consistency.
- * path.cc (symlink_info): Eliminate known_suffix.
- (path_conv::check): Always copy ext_here to end of buffer, if found.
- (suffix_scan): Eliminate ext_here, add suffixes_start.
- (suffix_scan::has): Eliminate an argument. Reorganize. Always return
- pointer to end of input path.
- (suffix_scan::next): Take a second pass through the suffix list looking
- for .lnk.
- (symlink_info::check): Eliminate known_suffix usage.
-
-Sat Mar 17 00:10:52 2001 Christopher Faylor <cgf@cygnus.com>
-
- * syscalls.cc (stat_dev): Give devices full read/write by default.
-
-Saturday Mar 17 3:45 2001 Robert Collins <rbtcollins@hotmail.com>
-
- * thread.cc (MTinterface::CreateCond): Check for null attr pointer.
-
-Fri Mar 16 21:13:23 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fhandler_termios.cc (fhandler_termios::line_edit): Don't accept input
- when a signal is sent or we'll end up in an EOF/signal race.
-
-Fri Mar 16 20:25:40 2001 Christopher Faylor <cgf@cygnus.com>
-
- * path.cc: Translate scan states from defines to enums.
- (suffix_scan): Rename state to nextstate for clarity.
- (lnk_match): Change to allow multiple states to indicate that a .lnk
- has been matched.
- (suffix_scan::has): Eliminate a goto. Handle .lnk as a special case,
- since a .lnk may also need to be tacked on the end of a .lnk.
- (suffix_scan::next): Don't increment next state. Set it specifically.
- Recognize new .lnk states.
-
-Saturday Mar 17 01:19 2001 Robert Collins rbtcollins@hotmail.com
-
- * cygwin.din: Export the new functions.
- * pthread.cc (pthread_cond_*): Add wrapper functions that call
- __pthread_cond* functions.
- * thread.cc (__pthread_cond_*): Implement the pthread_cond* functions.
- * thread.h: Add new class entries and prototypes for __pthread_cond*
- functions.
- * include/pthread.h: user land header prototypes for pthread_cond*
- functions and related defines.
-
-Wed Mar 14 16:30:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * environ.cc (parse_options): Use strtok_r instead of strtok.
- * security.cc (convert_string_sid_to_sid): Ditto.
- (aclfromtext): Ditto. Fix buffer usage.
-
-Wed Mar 14 10:11:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (lnk_suffixes): Remove.
- (class suffix_scan): Add `lnk_state' flag.
- (suffix_scan::lnk_match): Return state of `lnk_state' now.
- (suffix_scan::has): Changed behaviour if file has `.lnk' suffix.
- (suffix_scan::next): Set `lnk_state' where appropriate.
- (symlink_info::check): Fix a wrong `break'.
- * syscalls.cc (chown_worker): Change debug statement to reflect
- lchown fix.
- (lchown): Call chown_worker with `PC_SYM_NOFOLLOW' instead of
- `PC_SYM_IGNORE'.
-
-Tue Mar 13 13:52:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler.cc (fhandler_disk_file::fstat): Add correct modes to
- symlinks when stat'ing on FAT or FAT32 file systems.
-
-2001-03-12 Egor Duda <deo@logos-m.ru>
-
- * fhandler.h (fhandler_termios::fixup_after_exec): New function.
- * fhandler_termios.cc (fhandler_termios::fixup_after_fork): New
- function. Fixup output handle.
- * fhandler_tty.cc (fhandler_tty_common::fixup_after_fork): Output
- handle is now fixed up in fhandler_termios::fixup_after_fork().
-
-2001-03-12 Egor Duda <deo@logos-m.ru>
-
- * fhandler.h (fhandler_termios::fhandler_termios): Enable fixup
- after fork.
- * fhandler_console.cc (fhandler_console::fhandler_console): Fixup
- after fork is now enabled in the base class constructor.
-
-Mon Mar 12 11:19:41 2001 Christopher Faylor <cgf@cygnus.com>
-
- * mkvers.sh: Include config.h so that DEBUGGING is correctly defined.
+ (server_request_queue::cleanup): Kill off any request loop threads.
+ (server_request_queue::add): Add beginning of process cache support.
+ (handle_signal): Trigger a shutdown.
+ (main): Print out some useful info at startup - version, date time.
+ Add process cache support.
+ Spawn a separate thread for the transport request loop, thus allowing concurrent
+ support for multiple transports.
+ * cygserver_client.cc (client_request_get_version::serve): Add process cache
+ support.
+ (client_request_attach_tty::serve): Add process cache support.
+ (client_request_shutdown::serve): Add process cache support.
+ * cygsserver_process.cc: New file with the process cache support.
+ * cygserver_shm.cc: Redefine debug_printf to allow conditional output.
+ * cygwin.din: Export shmdt().
+ * shm.cc: Run indent.
+ Update FIXME's.
+ (shmdt): New function.
+ * include/cygwin/cygserver.h (class client_request): Add process cache support.
+ (class client_request_get_version): Ditto.
+ (class client_request_shutdown): Ditto.
+ (class client_request_attach_tty): Ditto.
+ * include/cygwin/cygserver_process.h: New header for process cache support.
-Mon Mar 12 09:47:55 2001 Christopher Faylor <cgf@cygnus.com>
+Sun Sep 30 8:52:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * spawn.cc (spawn_guts): Don't set EXIT_REPARENTING if parent process
- is not a cygwin process (suggested by Jason Gouger
- <cygwin@jason-gouger.com>).
+ * include/cygwin/cygserver_transport.h: Add copyright header.
+ * include/cygwin/cygserver_transport_pipes.h: Ditto.
+ * include/cygwin/cygserver_transport_sockets.h: Ditto.
-Sun Mar 11 16:00:58 2001 Christopher Faylor <cgf@cygnus.com>
+Sat Sep 29 20:40:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * child_info.h: Bump magic number for fork/exec/spawn.
+ * Makefile.in: Add cygserver_transport_sockets.o to DLL_OFILES.
+ Add cygserver_transport_sockets_outside.o to cygserver.exe.
+ * cygserver.cc: Include new include files.
+ * cygserver_client.cc: Ditto.
+ * cygserver_shm.h: No need to include <sys/socket.h> now.
+ * cygerver_transport.cc: Include new include files.
+ (transport_layer_base::transport_layer_base): Strip back to a stub.
+ (transport_layer_base::listen): Ditto.
+ (transport_layer_base::accept): Ditto.
+ (transport_layer_base::close): Ditto.
+ (transport_layer_base::read): Ditto.
+ (transport_layer_base::write): Ditto.
+ (transport_layer_base::connect): Ditto.
+ * cygserver_transport_pipes.cc: Include new header
+ "cygwin/cygserver_transport_pipes.h".
+ * cygserver_transport_sockets.cc: New file.
+ * dcrt0.cc: No need to include <sys/socket.h> now.
+ * fhandler_tty.cc: Ditto.
+ * tty.cc: Ditto.
+ * include/cygwin/cygserver_transport.h: Strip the base class to a stub.
+ Remove the cygserver_transport_pipes class.
+ * include/cygwin/cygserver_transport_pipes.h: New file.
+ * include/cygwin/cygserver_transport_sockets.h: New file.
-Sat Mar 10 20:54:47 2001 Christopher Faylor <cgf@cygnus.com>
+Tue Sep 25 16:22:00 2001 Robert Collins <rbtcollins@hotmail.com>
- * autoload.cc (noload): Use proper method for multiline strings or
- newer gcc's complain.
- * exceptions.cc (unused_sig_wrapper): Ditto.
- * fhandler.h (fhandler_base): Make get_io_handle and friends return
- self.
- * fhandler_tty.cc (fhandler_pty_common::close_on_exec): Accomodate
- DEBUGGING flag to avoid spurious warnings when inheritance is set.
+ * autoload.cc: Add dynamic load statement for 'ImpersonateNamedPipeClient'.
+ * Makefile.in: Add new object files, and build instructions for cygserver.exe.
+ * cygwin.din: Export ftok, shmat, shmctl and shmget.
+ * dcrt0.cc: Additional includes for cygserver support.
+ (dll_crt0_1): Initialise the cygserver client.
+ * fhandler.h (fhandler_tty): New method cygserver_attach_tty.
+ * fhandler_tty.cc: Additional includes for cygserver support.
+ (fhandler_tty_slave::open): Attempt to use the cygserver when obtaining
+ handles from the parent process. On failure or 9x use the current method.
+ (fhandler_tty_slave::cygserver_attach_tty): New function.
+ * fork.cc (fork_child): Fixup shm memory mapped areas.
+ * pinfo.h: Declare fixup_shms_after_fork().
+ * security.h: Declare alloc_sd().
+ * tty.cc: Additonal includes to support cygserver.
+ (tty::common_init): Don't allow others to open us if the cygserver is running.
+ * winsup.h: Declare cygserver_running.
+ * cygserver.cc: New file.
+ * cygserver_client.cc: New file.
+ * cygserver_shm.cc: New file.
+ * cygserver_shm.h: New file.
+ * cygserver_transport.cc: New file.
+ * cygserver_transport_pipes.cc: New file.
+ * ipc.cc: New file.
+ * shm.cc: New file.
+ * include/cygwin/cygserver.h: New file.
+ * include/cygwin/cygserver_transport.h: New file.
+ * include/sys/ipc.h: New file.
+ * include/sys/shm.h: New file.
-Sat Mar 10 16:52:12 2001 Christopher Faylor <cgf@cygnus.com>
+2002-02-28 Robert Collins <rbtcollins@hotmail.com>
- * shortcut.c (PATH_ALL_EXEC): Add parentheses to avoid a compiler
- warning.
+ * thread.cc (semaphore::TryWait): Set errno as required by posix 1003.1.
+ (__sem_wait): Ditto.
+ (__sem_trywait): Ditto.
- * exceptions.cc (setup_handler): Clarify debugging message.
- * sigproc.cc (proc_subproc): Remove PROC_CHILDSTOPPED test. It is
- handled by normal PROC_CLEARWAIT case.
- (wait_sig): Eliminate "dispatched" tracking. Remove __SIGCHILDSTOPPED
- test. Decrement counter again before jumping out of
- InterlockedDecrement loop so that subsequent InterlockedIncrement will
- keep the counter at the correctly decremented value and also detect
- when there are pending signals.
- * sigproc.h: Remove __SIGCHILDSTOPPED element.
- (procstuff): Remove PROC_CHILDSTOPPED element.
+2002-02-27 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/version.h: Bump DLL minor number.
+
+2002-02-23 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygwin.din (fstat64): New symbol.
+ (ftruncate64): Ditto.
+ (lseek64): Ditto.
+ (lstat64): Ditto.
+ (mmap64): Ditto.
+ (seekdir64): Ditto.
+ (stat64): Ditto.
+ (telldir64): Ditto.
+ (truncate64): Ditto.
+ * dir.cc (telldir64): New function.
+ (telldir): Call telldir64().
+ (seekdir64): New function.
+ (seekdir): Call seekdir64().
+ * fhandler.h: Redefine all methods using __off32_t to use __off64_t.
+ * fhandler.cc: Use __off64_t and struct __stat64 throughout.
+ * fhandler_clipboard.cc: Ditto.
+ * fhandler_disk_file.cc: Ditto.
+ * fhandler_dsp.cc: Ditto.
+ * fhandler_floppy.cc: Ditto.
+ * fhandler_mem.cc: Ditto.
+ * fhandler_random.cc: Ditto.
+ * fhandler_socket.cc: Ditto.
+ * fhandler_tape.cc: Ditto.
+ * fhandler_zero.cc: Ditto.
+ * pipe.cc: Ditto.
+ * glob.c: Ditto, call lstat64 and stat64 in Cygwin.
+ * mmap.cc: Use __off64_t throughout.
+ (mmap64): New function.
+ * sec_acl.cc (acl_worker): Use struct __stat64, call stat64 and lstat64.
+ * syscalls.cc (lseek64): New function.
+ (stat64_to_stat32): Ditto.
+ (fstat64): Ditto.
+ (stat64): Ditto.
+ (lstat64): Ditto.
+ (ftruncate64): Ditto.
+ (truncate64): Ditto.
+ (_fstat): Call fstat64.
+ (_stat): Call stat64.
+ (cygwin_lstat): Rename to avoid declaration problem. Call lstat64.
+ (stat_worker): Use struct __stat64.
+ (access): Ditto.
+ (ftruncate): Call ftruncate64.
+ (truncate): Call truncate64.
+ * wincap.cc: Set flag has_64bit_file_access appropriately.
+ * wincap.h: Add flag has_64bit_file_access.
+ * winsup.h (ILLEGAL_SEEK): Define as __off64_t.
+ (stat_dev): Declare using struct __stat64.
+ (stat_worker): Ditto.
+ * include/cygwin/stat.h (struct __stat32): Define if compiling Cygwin.
+ (struct __stat64): Ditto.
+ (struct stat): Revert definition with explicitly sized datatypes.
+ Eliminate sized field names.
+ * include/cygwin/types.h (blksize_t): New type.
+ (__blkcnt32_t): Ditto.
+ (__blkcnt64_t): Ditto.
+ (blkcnt_t): Ditto.
+
+2002-02-22 Christopher Faylor <cgf@redhat.com>
+
+ * sync.h (new_muto): Just accept an argument which denotes the name of
+ the muto. Use this argument to construct static storage.
+ * cygheap.cc (cygheap_init): Reflect above change.
+ * exceptions.cc (events_init): Ditto.
+ * malloc.cc (malloc_init): Ditto.
+ * path.cc (cwdstuff::init): Ditto.
+ * cygheap.h (cwdstuff): Change name of lock element to make it less
+ generic.
+ * path.cc (cwdstuff::get_hash): Ditto.
+ (cwdstuff::get_initial): Ditto.
+ (cwdstuff::set): Ditto.
+ (cwdstuff::get): Ditto.
+ * sigproc.cc (proc_subproc): Ditto.
-Sat Mar 10 15:22:44 2001 Christopher Faylor <cgf@cygnus.com>
+ * debug.cc (lock_debug): Change to method. Use method rather than
+ macro throughout.
+
+ * tty.h (tty_min::kill_pgrp): Declare new method.
+ * fhandler_termios.cc (tty_min::kill_pgrp): New method.
+ (fhandler_termios::line_edit): Use new method for killing process.
+ * dcrt0.cc (do_exit): Ditto.
+
+ * dtable.cc (dtable::get_debugger_info): New method for inheriting
+ dtable info from a debugger.
+ * tty.cc (tty_init): Attempt to grab file handle info from parent
+ debugger, if appropriate.
+
+ # dtable.cc (dtable::stdio_init): Make this a method.
+ (dtable::init_std_file_from_handle): Don't set fd unless it's not open.
+ (dtable::build_fhandler_from_name): Move name setting to
+ dtable::build_fhandler.
+ (dtable::build_fhandler): Add win32 name parameter.
+ * dcrt0.cc (dll_crt0_1): Change to use dtable stdio_init.
+ * dtable.h (dtable): Reflect build_fhandler parameter change.
+ * mmap.cc (mmap_record::alloc_fh): Don't set name parameter in
+ build_fhandler.
+ * net.cc (fdsock): Remove set_name call since it is now handled by
+ build_fhandler.
- * syscalls.cc (_rename): Set errno to ENOENT when an old path doesn't
- exist (from Kazuhiro Fujieda <fujieda@jaist.ac.jp>). Also set EACCES
- when directory is not writable.
+ * sigproc.cc (proc_subproc): Release muto as early as possible.
-Wed Mar 7 15:49:47 2001 Christopher Faylor <cgf@cygnus.com>
+2001-02-22 Corinna Vinschen <corinna@vinschen.de>
- * syscalls.cc (_read): Change definition to return ssize_t to be
- consistent with read.
- (_write): Change definition to return ssize_t to be consistent with
- write.
+ * smallprint.c (rn): Allow long long values.
+ (__small_vsprintf): Add 'D', 'U' and 'X' formats for long long
+ parameters.
-Wed Mar 7 01:08:21 2001 Christopher Faylor <cgf@cygnus.com>
+2002-02-19 Christopher Faylor <cgf@redhat.com>
- * sigproc.h (sigthread): Declare new methods. Create new winapi_lock
- field.
- (sigframe:;set): Call get_winapi_lock after frame is set so that signal
- handler thread knows not to call SuspendThread.
- (sigframe::~sigframe): Release winapi_lock.
- * exceptions.cc (sigthread::get_winapi_lock): New method.
- (sigthread::release_winapi_lock): New method.
- (setup_handler): Use get_winapi_lock to ensure that signalled thread is
- not blocked in a Windows API.
-
- * path.h (path_types): Avoid broken GCC warning.
-
-Tue Mar 6 14:02:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (suffix_scan::has): Change order of conditionals
- to allow checking for .lnk suffixes even if in_suffixes is empty.
-
-Tue Mar 6 13:02:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.c (cygwin_premain0): Add missing parameter.
- * binmode.c (cygwin_premain0): Ditto.
- * textmode.c (cygwin_premain0): Ditto.
-
-Tue Mar 6 12:04:00 2001 Jason Tiller <jtiller@sjm.com>
-
- * auto_load.cc: Add "GetKeyboardLayout" entry in the list of
- Win32 User32.DLL exports to provide.
- * fhandler.h (class fhandler_console): Add meta_mask private
- member to remember which keystroke modifiers should generate
- META.
- * fhandler_console.cc (fhandler_console::read): Modify code that
- tests a keystroke for a META-escaped key to use the 'meta_mask'
- variable.
- (fhandler_console::fhandler_console): Add definition for
- variable "meta_mask" used to determine if a keystroke should be
- preceded by META in the client console stream. Set meta_mask
- based on whether or not user's keyboard language is English -
- non-English keyboards pass AltGr (right <ALT>) unmolested,
- whereas English keyboards now interpret left- and right-<ALT>
- as META.
-
-Mon Mar 5 20:15:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * include/a.out.h: Add copyright hint.
- * include/fcntl.h: Ditto.
- * include/lastlog.h: Ditto.
- * include/memory.h: Ditto.
- * include/mntent.h: Ditto.
- * include/paths.h: Ditto.
- * include/poll.h: Ditto.
- * include/syslog.h: Ditto.
- * include/termio.h: Ditto.
- * include/tzfile.h: Ditto.
- * include/arpa/inet.h: Ditto.
- * include/asm/byteorder.h: Ditto.
- * include/asm/socket.h: Ditto.
- * include/asm/types.h: Ditto.
- * include/cygwin/if.h: Ditto.
- * include/cygwin/mtio.h: Ditto.
- * include/cygwin/rdevio.h: Ditto.
- * include/cygwin/socket.h: Ditto.
- * include/net/if.h: Ditto.
- * include/netinet/in.h: Ditto.
- * include/netinet/in_systm.h: Ditto.
- * include/netinet/ip.h: Ditto.
- * include/netinet/ip_icmp.h: Ditto.
- * include/netinet/tcp.h: Ditto.
- * include/sys/cdefs.h: Ditto.
- * include/sys/cygwin.h: Ditto.
- * include/sys/ioctl.h: Ditto.
- * include/sys/mman.h: Ditto.
- * include/sys/mount.h: Ditto.
- * include/sys/mtio.h: Ditto.
- * include/sys/procfs.h: Ditto.
- * include/sys/resource.h: Ditto.
- * include/sys/smallprint.h: Ditto.
- * include/sys/socket.h: Ditto.
- * include/sys/strace.h: Ditto.
- * include/sys/syslog.h: Ditto.
- * include/sys/sysmacros.h: Ditto.
- * include/sys/termio.h: Ditto.
- * include/sys/termios.h: Ditto.
- * include/sys/uio.h: Ditto.
- * include/sys/un.h: Ditto.
- * include/sys/utsname.h: Ditto.
- * include/sys/vfs.h: Ditto.
- * include/sys/wait.h: Ditto.
- * regexp/regerror.c: Ditto.
- * regexp/regexp.h: Ditto.
- * regexp/regmagic.h: Ditto.
-
-Mon Mar 5 01:25:03 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dlopen.c (dlopen): Return NULL when name is NULL (suggested by
- chrisiasci@aol.com).
-
- * cygwin.din: Add a new, internally used export -
- _check_for_executable.
- * dcrt0.cc (dll_crt0_1): Set _check_for_executable for older binaries.
- Pass user_data to premain functions.
- * fhandler.cc (fhandler_disk_file::open): Only check for executable if
- the linked program is interested in the executable bit.
- (fhandler_disk_file::check_execable_p): Delete.
- * fhandler.h (executable_states): New enumeration of various states of
- executable bit caring.
- (fhandler_base::set_execable_p): New method.
-
- * fhandler_termios.cc (fhandler_termios::line_edit): Flag when a signal
- has been sent to the tty. Return -1 when this is so.
- * fhandler_console.cc (fhandler_console::read): Return -1 when signal
- sending character encountered.
-
- * path.cc (path_conv::check): Record when path refers to a disk device.
- Move executable extension check here.
- (check_sysfile): Accomodate new EXEC path states.
- (has_suffix): Remove.
- (next_suffix): Remove.
- (class suffix_scan): New clas.
- (suffix_scan::has): New method.
- (suffix_scan:next): New method.
- (symlink_info::check): Use suffix_scan method to control for scanning
- for suffixes.
- * path.h (path_conv::exec_state): New method.
- * perprocess.h: Make "C" friendly.
- * include/cygwin/version.h: Define CYGWIN_VERSION_CHECK_FOR_S_IEXEC.
- Bump CYGWIN_VERSION_API_MINOR.
- * include/sys/cygwin.h: Change premain declarations.
-
- * winsup.h: Move __cplusplus test to after builtin defines.
-
-2001-03-04 Egor Duda <deo@logos-m.ru>
-
- * fhandler.h (class fhandler_tty_common): New mutex and event to
- syncronize input on master tty with slave tty.
- * fhandler_tty.cc (fhandler_pty_master::accept_input): Use them to
- syncronize with slave.
- * fhandler_tty.cc (fhandler_tty_slave::read): Use input mutex and
- event to syncronize with master. Do not limit amount of data read
- from master to vmin value. Interrupt on signal and return already
- read data, if any.
- * fhandler_tty.cc (fhandler_tty_slave::open): Handle input mutex and
- event.
- * fhandler_tty.cc (fhandler_tty_common::close): Ditto.
- * fhandler_tty.cc (fhandler_tty_common::set_close_on_exec): Ditto.
- * fhandler_tty.cc (fhandler_tty_common::fixup_after_fork): Ditto.
- * fhandler_tty.cc (fhandler_tty_common::dup): Ditto.
- * tty.h (tty::open_input_mutex): New function.
- * tty.cc (tty::common_init): Create input mutex and event.
-
-Fri Mar 2 13:32:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * dir.cc (readdir): Fix creating path in symlink check.
-
-Fri Mar 2 12:33:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * dir.cc (readdir): Fix shortcut==symlink condition.
- * environ.cc: Add extern decl for `allow_winsymlinks'.
- (struct parse_thing): Add entry for `[no]winsymlinks'.
- * path.cc (symlink): Change to be able to create both,
- symlink==shortcut and symlink==systemfile, dependent of
- the setting of `allow_winsymlinks'.
- * security.cc (cygwin_logon_user): Add debug output.
- * shortcut.c: Add defines from path.h.
- (has_exec_chars): Copy from path.h.
- (check_shortcut): Check for executable file condition if not a
- shortcut.
-
-Thu Mar 1 21:06:07 2001 Christopher Faylor <cgf@cygnus.com>
-
- * exceptions.cc (sig_handle_tty_stop): Ignore attempts to suspend a
- process if started by non-cygwin parent.
-
-Thu Mar 1 20:48:11 2001 Christopher Faylor <cgf@cygnus.com>
-
- * select.cc (peek_console): Don't report read_ready on mouse events
- unless we are looking for mouse events.
- * fhandler.h (fhandler_console::mouse_aware): New method.
-
-Wed Feb 28 15:10:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc: Eliminate `#include <wchar.h>'.
-
-2001-02-28 Egor Duda <deo@logos-m.ru>
-
- * fhandler_floppy.cc (fhandler_dev_floppy::lseek): Determine
- drive geometry or partition size to allow seeking from the end of
- raw floppy device. Don't allow positioning past the end of media or
- to offsets bigger then max off_t.
-
-2001-02-27 Egor Duda <deo@logos-m.ru>
-
- * fhandler.h (class fhandler_console): Make all variables that
- describe "state" of console to be members of fhandler_console.
- default_color is now the color which is set when console recieves
- reset command.
- * fhandler_console.cc (fhandler_console::fhandler_console): Turn
- mouse handling and raw keyboard mode off by default. Initialize
- state information.
- * fhandler.cc (fhandler_console::set_raw_win32_keyboard_mode): New
- function.
- * fhandler_console.cc (fhandler_console::set_default_attr): New
- function. Reset console attributes to default values.
- * fhandler_console.cc (fhandler_console::open): Reset attributes.
- * fhandler_console.cc (fhandler_console::get_win32_attr): New function.
- Calculate win32-style console attribute based on terminal attributes.
- * fhandler_console.cc (fhandler_console::set_cursor_maybe): Use
- member variable.
- * fhandler_console.cc (fhandler_console::read): If in raw-win32
- keyboard mode, encode win32 keyboard events in \033{x;y;z;t;u;wK
- sequences.
- * fhandler_console.cc (fhandler_console::dup): Copy all state
- information to the dup()ed handle.
- * fhandler_console.cc (fhandler_console::scroll_screen): Use current
- fill-in attribute.
- * fhandler_console.cc (fhandler_console::clear_screen): Ditto.
- * fhandler_console.cc (fhandler_console::char_command): Check if we
- saw '?' symbol by member variable. Set terminal attributes on \033[Xm
- commands. \033[24m - turn off underline mode, \033[27m - turn off
- reverse mode, \033[39m - restore default foreground color.
- \033[49m - restore default background color. \033[2000h - turn on raw
- keyboard mode, \033[2000l - turn off raw keyboard mode.
- * fhandler_console.cc (fhandler_console::write): Set attribues to
- default values on reset command.
-
-2001-02-26 Mike Simons <msimons@moria.simons-clan.com>
-
- * times.cc (settimeofday): Replace function stub with working code.
-
-Mon Feb 26 10:42:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * strace.cc (strace::vprntf): Move prntf functionality to this function
- adding an va_list interface to strace.
- (strace::printf): Calls strace::vprntf now.
- (strace_printf): New function providing an extern "C" interface to
- trace output.
- * include/sys/strace.h: Make plain C clean.
- (class strace): Add `vprntf' method.
-
-Mon Feb 26 0:10:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * shortcut.c: Remove #include <sys/strace.h>.
-
-Sun Feb 25 10:32:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (symlink): Add a ".lnk" suffix regardless. Add a comment.
-
-Sun Feb 25 10:18:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * shortcut.c (check_shortcut): Change symlink condition.
-
-Fri Feb 23 10:42:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * mmap.cc (fhandler_disk_file::mmap): Use `addr' correctly.
- * fhandler_mem.cc (fhandler_dev_mem::mmap): Ditto.
-
-Thu Feb 22 17:09:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (symlink): Keep relative paths relative in the DOS
- path inside of a shortcut. If that's impossible or the target
- path is already absolute save an absolute path.
-
-Thu Feb 22 15:33:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * cygerrno.h: Revert previous patch.
- * errno.cc: Ditto.
- * dir.cc: Eliminate `dir_suffixes'.
- (opendir): Remove usage of `dir_suffixes'.
- (rmdir): Ditto.
- * fhandler.cc (fhandler_disk_file::open): Remove usage of
- `inner_suffixes'.
- * path.cc: Rename `inner_suffixes' to `lnk_suffixes'.
- (path_conv::check): Remove usage of `inner_suffixes'.
- (symlink): Ditto.
- (symlink_info::check): Handle checking for `.lnk' in path_conv
- exclusively here.
- (chdir): Remove usage of `dir_suffixes'.
- * shortcut.c: Eliminate debug_printf lines.
- (check_shortcut): Don't set error except on failing ReadFile.
- * spawn.cc: Remove ".lnk" from `std_suffixes'.
- * syscalls.cc (_unlink): Remove usage of `inner_suffixes'.
- Remove ".lnk" from `stat_suffixes'.
- (_rename): Add check for renaming a symlink to keep the ".lnk"
- suffix after renaming.
-
-Thu Feb 22 13:38:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * shortcut.c: New file. Provides a C interface to reading of
- Windows shortcuts to avoid compiler flag `-fvtable-thunks'.
- * shortcut.h: Ditto.
- * Makefile.in: Add shortcut.o to DLL_OFILES.
- * cygerrno.h: Provide a C interface to `geterrno_from_win_error' for
- using in shortcut.c.
- * errno.cc (geterrno_from_win_error): Define as extern "C".
- * path.cc (struct symlink_info): Remove methods `check_shortcut' and
- `check_sysfile'.
- (shortcut_header): Move to shortcut.c.
- (shortcut_initalized): Ditto.
- (create_shortcut_header): Ditto.
- (cmp_shortcut_header): Ditto.
- (symlink_info::check_shortcut): Ditto. Reorganize as a plain C function.
- (symlink_info::check_sysfile): Redefine as a global function using the
- same parameter list as `check_shortcut' for clearness.
- (symlink_info::check): Change parameter list for calls to
- `check_shortcut' and `check_sysfile'.
-
-Thu Feb 22 12:04:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler.cc (fhandler_disk_file::open): Use `inner_suffixes' when
- resolving real_path.
- * path.cc (symlink): Ditto for win32_topath.
-
-Wed Feb 21 22:41:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * Makefile.in: Add `-lshell32 -luuid' to link pass for new-cygwin1.dll.
- * autoload.cc: Add LoadDLLinitfunc for ole32.dll.
- Add LoadDLLfuncEx statements for CoInitialize@4, CoUninitialize@0
- and CoCreateInstance@20.
- * dir.cc (dir_suffixes): New datastructure.
- (readdir): Check for R/O *.lnk files to hide the suffix.
- (opendir): Use `dir_suffixes' in path conversion.
- (rmdir): Ditto.
- * fhandler.cc (fhandler_disk_file::fstat): Add S_IFLNK flag
- before calling `get_file_attribute'. Take FILE_ATTRIBUTE_READONLY
- into account only if the file is no symlink.
- * path.cc (inner_suffixes): New datastructure.
- (SYMLINKATTR): Eliminated.
- (path_conv::check): Use `inner_suffixes' on inner path components.
- (shortcut_header): New global static variable.
- (shortcut_initalized): Ditto.
- (create_shortcut_header): New function.
- (cmp_shortcut_header): Ditto.
- (symlink): Create symlinks by creating windows shortcuts. Preserve
- the old code.
- (symlink_info::check_shortcut): New method.
- (symlink_info::check_sysfile): Ditto.
- (symlink_info::check): Check for shortcuts. Move code reading
- old system attribute symlinks into symlink_info::check_sysfile().
- (chdir): Use `dir_suffixes' in path conversion.
- * security.cc (get_file_attribute): Check for S_IFLNK flag.
- Force 0777 permissions then.
- * spawn.cc (std_suffixes): Add ".lnk" suffix.
- * syscalls.cc (_unlink): Use `inner_suffixes' in path conversion.
- Check for shortcut symlinks to eliminate R/O attribute before
- calling DeleteFile().
- (stat_suffixes): Add ".lnk" suffix.
- (stat_worker): Force 0777 permissions if file is a symlink.
-
-2001-02-21 Egor Duda <deo@logos-m.ru>
-
- * sigproc.cc (getsem): Make semaphore always non-inheritable.
-
-Mon Feb 19 22:25:53 2001 Christopher Faylor <cgf@cygnus.com>
-
- * dcrt0.cc (locale_init): Remove.
-
-2001-02-15 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
-
- * cygwin.din: Export rand48 functions.
- * thread.cc (MTinterface::Init): Remove the initialization of
- `reent_data'.
- * dcrt0.cc: Add the initalizer to the declaration of `reent_data'.
- * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 35.
-
-2001-02-16 Egor Duda <deo@logos-m.ru>
-
- * signal.cc (signal): Prohibit setting handlers for SIGKILL and
- SIGSTOP
- * signal.cc (sigaction): Ditto
- * syscalls.cc (_lseek): Return EINVAL on invalid input
-
-Wed Feb 14 14:54:40 2001 Christophe Iasci <chrisiasci@aol.com>
-
- * dlfcn.cc (dlopen): Do not call LoadLibrary with a NULL pointer, when
- the library is not found
-
-2001-02-14 Egor Duda <deo@logos-m.ru>
-
- * fhandler_console.cc (fhandler_console::char_command): Ignore unknown
- rendition codes in \033[xx;yym control sequences
-
-Fri Feb 9 23:19:01 2001 Christopher Faylor <cgf@cygnus.com>
-
- * fork.cc (fork_parent): Return EAGAIN when can't record pid.
- * pinfo.h (pinfo::remember): Return value of call to proc_subproc.
- * sigproc.cc (proc_subproc): Return error if can't record pid.
-
-Fri Feb 9 12:17:27 2001 Christopher Faylor <cgf@cygnus.com>
+ * fhandler.cc (fhandler_base::puts_readahead): Remove default parameter
+ setting. Newer gcc's complain about this.
+ (fhandler_base::set_readahead_valid): Ditto.
+ * fhandler_dsp.cc (Audio::open): Ditto.
+ (fhandler_dev_dsp::open): Ditto.
- * syscalls.cc (mknod): Add valid parameters.
+2002-02-19 Christopher Faylor <cgf@redhat.com>
-Thu Feb 8 22:09:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * fork.cc (fork_parent): Use sec_user_nih to control process/thread
+ inheritance/permission.
+ * spawn.cc (spawn_guts): Ditto.
+ * security.cc (create_token): Initialize token so that it is not tested
+ for bogus value later. Use sec_user to control process/thread
+ creation.
+ * security.h (__sec_user): Rename declaration from sec_user.
+ (sec_user_nih): Declare here as inline function wrapper for __sec_user.
+ (sec_user): Ditto.
+ * sigproc.cc (czombies): Allocate a character array for zombies to
+ avoid constructor overhead
+ (extremely hackish, I know).
+ (cpchildren): Ditto.
+ (pchildren): New define.
+ (zombies): Ditto.
+ (getsem): Use sec_user_nih to control semaphore inheritance/permission.
+
+2002-02-16 Christopher Faylor <cgf@redhat.com>
+
+ * times.cc (hires::prime): Restore thread priority on failure
+ condition.
+
+ * uinfo.cc (uinfo_init): Use more robust method for determining if
+ process was invoked from a non-cygwin process.
+
+ * sync.h (muto::init): Eliminate "inheritance" parameter.
+ (new_muto): Reflect removal of parameter.
+ * sync.cc (muto::init): Ditto.
+ * cygheap.cc (cygheap_init): Ditto.
+ * debug.cc (threadname_init): Ditto.
+ * exceptions.cc (events_init): Ditto.
+ * malloc.cc (malloc_init): Ditto.
+ * path.cc (cwdstuff::init): Ditto.
+ * sigproc.cc (sigproc_init): Ditto.
+
+ * grp.cc (group_lock): Use different method for locking with static
+ member.
+ (read_etc_group): REALLY ensure that read lock mutex is released.
+ * passwd.cc (passwd_lock): Use different method for locking with static
+ member.
+ (read_etc_passwd): REALLY ensure that read lock mutex is released.
+
+ * shared.cc (sec_user): Correct reversed inheritance test.
+
+2002-02-15 Christopher Faylor <cgf@redhat.com>
+
+ * hires.h (hires::usecs): Rename from utime. Accept an argument.
+ * strace.cc (strace::microseconds): Use hires class for calculating
+ times.
+ * sync.h (new_muto): Use NO_COPY explicitly in declaration.
+ * times.cc (gettimeofday): Reflect change in usecs argument.
+ (hires::usecs): Ditto. Changed name from utime.
+ * winsup.h (NO_COPY): Add nocommon attribute to force setting aside
+ space for variable.
+ * regcomp.c (REQUIRE): Add a void cast to bypass a warning.
+
+2002-02-15 Christopher Faylor <cgf@redhat.com>
+
+ * hires.h: New file.
+ * times.cc (gettimeofday): Use hires class for calculating current time.
+ (hires::prime): New method.
+ (hires::utime): Ditto.
+
+2002-02-14 Christopher Faylor <cgf@redhat.com>
+
+ * include/sys/cygwin.h (cygwin_getinfo_types): New CW_STRACE_ACTIVE.
+ * external.cc (cygwin_internal): Handle CW_STRACE_ACTIVE.
+
+2002-02-14 Christopher Faylor <cgf@redhat.com>
+
+ * exceptions.cc (unused_sig_wrapper): Eliminate unused parameter to
+ asm.
+ * external.cc (cygwin_internal): Change CW_STRACE_ON to
+ CW_STRACE_TOGGLE.
+ * strace.cc (strace::hello): Toggle strace on and off.
+ * sync.cc (muto::init): Rename from constructor.
+ * sync.h (muto::new): Delete.
+ (muto::delete): Ditto.
+ (new_muto): Simplify. Use muto.init for nearly everything.
+ * uinfo.cc (uinfo_init): Avoid closing a NULL handle.
+ * include/sys/cygwin.h (cygwin_getinfo_types): Rename CW_STRACE_OFF to
+ CW_STRACE_TOGGLE. Delete CW_STRACE_OFF.
+ * include/sys/strace.h (strace): Add "inited" field.
+
+2001-02-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * include/cygwin/acl.h: Fix definition of aclent_t.
+
+2002-02-10 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (DLL_OFILES): Consolidate object files.
+
+2002-02-10 Corinna Vinschen <corinna@vinschen.de>
+
+ * child_info.h, cygheap.h, fhandler_clipboard.cc, fhandler_dsp.cc,
+ fhandler_floppy.cc, fhandler_mem.cc, fhandler_random.cc,
+ fhandler_tape.cc, fhandler_zero.cc, grp.cc, mmap.cc, passwd.cc,
+ pinfo.cc, pinfo.h, pipe.cc, sec_acl.cc, sec_helper.cc, security.cc,
+ security.h, thread.h, uinfo.cc, include/cygwin/acl.h: Fix copyright.
+
+2002-02-10 Corinna Vinschen <corinna@vinschen.de>
+
+ * child_info.h, cygheap.h, dcrt0.cc, dir.cc, fhandler.cc, fhandler.h,
+ fhandler_clipboard.cc, fhandler_disk_file.cc, fhandler_dsp.cc,
+ fhandler_floppy.cc, fhandler_mem.cc, fhandler_random.cc,
+ fhandler_tape.cc, fhandler_zero.cc, grp.cc, mmap.cc, passwd.cc,
+ pinfo.cc, pinfo.h, pipe.cc, sec_acl.cc, sec_helper.cc, security.cc,
+ security.h, spawn.cc, syscalls.cc, thread.h, uinfo.cc, winsup.h:
+ Change usage of uid_t to __uid16_t, gid_t to __gid16_t and
+ off_t to __off32_t throughout. Use INVALID_UID, INVALID_GID and
+ INVALID_SEEK instead casting -1 to the appropriate type.
+ * winsup.h: Define INVALID_UID, INVALID_GID and INVALID_SEEK.
+ * include/cygwin/acl.h: Define internal __aclent16_t and __aclent32_t
+ types. Don't declare acl functions when compiling Cygwin.
+ * include/cygwin/grp.h: Declare getgrgid() and getgrnam() with
+ correct types for internal usage.
+
+2002-02-10 Corinna Vinschen <corinna@vinschen.de>
+
+ Patch suggested by Pierre A. Humblet <Pierre.Humblet@ieee.org>:
+ * uinfo.cc (internal_getlogin): Try evaluating user by SID even if
+ ntsec is off.
+ (uinfo_init): Set primary group even if ntsec is off.
+
+2002-02-09 Corinna Vinschen <corinna@vinschen.de>
+
+ * include/cygwin/grp.h: New file.
+ * include/cygwin/stat.h: Ditto.
+ * include/cygwin/types.h: Add definitions for __off32_t,
+ __off64_t, off_t, __uid16_t, __uid32_t, uid_t, __gid16_t,
+ __gid32_t and gid_t.
+ * include/sys/cygwin.h: Use correct uid and gid types.
- * mmap.cc (mmap): Check for reusing a mapping only on MAP_SHARED
- and on MAP_PRIVATE|MAP_ANON in the special case of offset 0.
+2002-02-09 Corinna Vinschen <corinna@vinschen.de>
-Thu Feb 8 21:57:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * dtable.cc (dtable::dup2): Revert previous patch.
+ * fhandler.h: Ditto.
+ (fhandler_socket::recv): Define new method.
+ (fhandler_socket::send): Ditto.
+ * fhandler_socket.cc (fhandler_socket::recv): New method.
+ (fhandler_socket::send): Ditto.
+ (fhandler_socket::read): Call fhandler_socket::recv() now.
+ (fhandler_socket::write): Call fhandler_socket::send() now.
+ * net.cc (class wsock_event): Move definition to wsock_event.h.
+ (fdsock): Revert previous patch.
+ (cygwin_recv): Move implementation to fhandler_socket::recv().
+ (cygwin_send): Move implementation to fhandler_socket::send().
+ * wsock_event.h: New file.
- * mmap.cc (class list): Add member `hash'.
- (list::list): Initialize `hash'.
- (list::get_list_by_fd): Use filepath hash value to get the correct
- mapping list if it's not an anonymous mapping.
- (map::add_list): Initialize `hash' with filepath hash value.
- (mmap): Check for reusing a mapping only on MAP_SHARED.
+2002-02-06 Alexander Gottwald <Alexander.Gottwald@s1999.tuchemnitz.de>
-Wed Feb 7 18:47:36 2001 Christopher Faylor <cgf@cygnus.com>
+ * net.cc (get_2k_ifconf): Create interface entries for tokenring cards.
- * signal.cc (killpg): Correct first argument.
+2002-02-08 Corinna Vinschen <corinna@vinschen.de>
-Wed Feb 7 22:22:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * dtable.cc (dtable::dup2): Store fd for fhandler_socket.
+ * fhandler.h (fhandler_base::set_fd): New virtual method.
+ (fhandler_base::get_fd): Ditto.
+ (fhandler_socket::set_fd): Ditto.
+ (fhandler_socket::get_fd): Ditto.
+ * fhandler_socket.cc (fhandler_socket::read): Call cygwin_recv instead
+ of native Winsock recv.
+ (fhandler_socket::write): Call cygwin_send instead of native Winsock
+ send.
+ * net.cc (fdsock): Store fd in fhandler_socket.
- * autoload.cc: Add LoadDLLinitfunc for iphlpapi.dll.
- Add LoadDLLfuncEx statements for GetIfTable@12 and GetIpAddrTable@12.
- * fhandler_socket.cc (fhandler_socket::ioctl): Move variable
- definitions to the beginning of the function to allow better debugging.
- Add handling for SIOCGIFHWADDR, SIOCGIFMETRIC and SIOCGIFMTU.
- * net.cc: Include iphlpapi.h.
- (get_2k_ifconf): Rewritten. Uses IP Helper API now.
- (get_nt_ifconf): Add handling for SIOCGIFHWADDR, SIOCGIFMETRIC
- and SIOCGIFMTU.
- (get_95_ifconf): Ditto. Renamed from `get_9x_ifconf'.
- (get_ifconf): Name loopback `lo' instead of `lo0' as in Linux.
- Add handling for SIOCGIFHWADDR, SIOCGIFMETRIC and SIOCGIFMTU.
- Call `get_95_ifconf' only on Windows 95, `get_nt_ifconf' only
- on Windows NT < Service Pack 3, `get_2k_ifconf otherwise.
- * include/asm/socket.h: Add defines for SIOCGIFHWADDR, SIOCGIFMETRIC
- and SIOCGIFMTU.
- * include/cygwin/if.h: Add `ifr_hwaddr', `ifr_metric' and `ifr_mtu'.
- (struct ifreq): Add `ifru_hwaddr'.
+2002-02-07 Corinna Vinschen <corinna@vinschen.de>
-Tue Feb 6 15:04:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * net.cc (cygwin_getsockname): Fix handling of NULL sun_path.
- * syscalls.cc (stat_worker): Add a check for the special case when
- a process creates a file using mode 000 using ntsec.
+2002-01-29 Corinna Vinschen <corinna@vinschen.de>
-Mon Feb 5 17:00:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * net.cc (getdomainname): Fix registry key for 9x systems, too.
- * fhandler.cc (fhandler_base::open): Always add GENERIC_READ access
- when opening raw disk devices.
- * fhandler_floppy.cc (fhandler_dev_floppy::lseek): Implement bytewise
- access.
- * fhandler_raw.cc (fhandler_dev_raw::open): Always open raw disk device
- binary.
- (fhandler_dev_raw::raw_write): Don't drop read buffer content when
- writing after read.
+2002-01-29 Corinna Vinschen <corinna@vinschen.de>
-Mon Feb 5 13:30:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * net.cc (getdomainname): Fix registry key for NT systems.
- * mmap.cc (mmap_record::fixup_map): New method to duplicate
- the memory protection in a just forked child.
- (mmap): Realign gran_len to page boundary only on anonymous
- mapping before saving in the mmap_record.
- (munmap): Cleanup code.
- (msync): Ditto.
- (fixup_mmaps_after_fork): Ditto. Call mmap_record::fixup_map now.
+2002-01-28 Christopher Faylor <cgf@redhat.com>
-Thu Feb 1 23:08:29 2001 Christopher Faylor <cgf@cygnus.com>
+ * external.cc (cygwin_internal): Initialize various internal settings
+ if required to allow use of some things from user loaded DLL.
+ (CW_STRACE_ON): Add new feature.
+ (CW_CYGWIN_PID_TO_WINPID): Ditto.
+ * pinfo.cc (set_myself): Call "strace.hello" to initiate possible
+ strace session.
+ (pinfo::init): Guard against dereferencing uninitialized myself.
+ * sigproc.cc (wait_sig): Call strace.hello() when __SIGTRACE "signal"
+ received.
+ * strace.cc (strace::hello): New method.
+ * wincap.cc (wincapc::init): Avoid initializing if already initialized.
+ * wincap.h (wincapc::wincapc): New method.
+ * include/sys/cygwin.h: Add new CW_ enums. Kludge typedefs of
+ {g,u}id_t if required.
+ * strace.h (strace::hello): Declare new method.
- * cygheap.cc (creturn): Correctly calculate cygheap_max.
+2002-01-28 Earnie Boyd <earnie@users.sf.net>
-Wed Jan 31 10:04:58 2001 Christopher Faylor <cgf@cygnus.com>
+ * include/sys/strace.h (_STRACE_ON): Define.
+ (_STRACE_OFF): Ditto.
- * shared.cc (shared_info::initialize): Reduce size of heap.
+2002-01-24 Christopher Faylor <cgf@redhat.com>
-Wed Jan 31 13:22:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * speclib: Ensure that temporary def file is removed.
- * include/sys/resource.h: Fix typo.
+2002-01-23 Christopher Faylor <cgf@redhat.com>
-Wed Jan 31 13:20:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * speclib: Use rm -f to remove temp file just to quiet any potential
+ warnings.
- * include/sys/resource.h: Add RLIMIT_NLIMITS and RLIM_NLIMITS.
+2002-01-23 Corinna Vinschen <corinna@vinschen.de>
-Tue Jan 30 18:15:23 2001 Christopher Faylor <cgf@cygnus.com>
+ * security.cc (create_token): Use sec_user() to create
+ SECURITY_ATTRIBUTES structure for primary token. Use
+ MAXIMUM_ALLOWED access rights instead of TOKEN_ALL_ACCESS.
- * include/cygwin/version.h: Bump version to 1.3.0.
+2002-01-23 Corinna Vinschen <corinna@vinschen.de>
-Tue Jan 30 8:55:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * path.cc (symlink): Fix check for already existing file.
- * pinfo.cc (pinfo::init): Use INVALID_HANDLE_VALUE instead of
- explicit cast (HANDLE) 0xffffffff.
- * shared.cc (open_shared): Ditto.
+2002-01-21 Christopher Faylor <cgf@redhat.com>
-Mon Jan 29 17:15:22 2001 Bill Hegardt <bill@troyxcd.com>
-
- * fhandler_serial.cc (raw_write): Use local copy of OVERLAPPED
- structure instead of shared structure to fix a race condition between
- read/write.
+ * cygmagic: Suppress error output when figuring out if sum takes an
+ option.
-Mon Jan 29 14:30:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-21 Christopher Faylor <cgf@redhat.com>
- * mmap.cc (mmap): Remove obsolete check for MAP_SHARED|MAP_ANON as
- being invalid.
+ * cygmagic: Attempt to figure out if sum takes an option.
-Mon Jan 29 10:23:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-21 DJ Delorie <dj@redhat.com>
- * mmap.cc (mmap_record::find_empty): Fix loop condition.
+ * Makefile.in (libpthread.a): Pass the assembler also.
+ (libm.a): Ditto.
+ (libc.a): Ditto.
+ * speclib: Specify the assembler to dlltool.
-Sun Jan 28 19:40:40 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-21 Christopher Faylor <cgf@redhat.com>
- * syscalls.cc (_link): Make sure that newpath does not exist. Set
- errno if it does.
+ * include/cygwin/version.h: Bump DLL minor number.
-Sun Jan 28 19:29:08 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-21 Corinna Vinschen <corinna@vinschen.de>
- * cygheap.cc (init_cheap): Don't specify a load address for the heap.
- It doesn't work on #!*& Windows 9x.
- (cygheap_init): Move GetUserName to memory_init.
- * dcrt0.cc (dll_crt0_1): Call new memory_init functin, eliminate call
- to heap_init.
- * heap.cc (heap_init): Improve error output.
- * heap.h: Correct some declarations.
- * shared.cc (mount_table_init): Remove.
- (memory_init): Renamed from shared_init. Reorganize to accomodate
- strange Windows 9x problems with cygheap/heap interaction.
- * shared_info.h: Rename shared_init to memory_init.
+ * grp.cc (getgrgid): Don't return default gid entry when ntsec is on.
+ * syscalls.cc (setegid): Don't set primary group in process token.
-Sun Jan 28 01:25:33 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-21 Christopher Faylor <cgf@redhat.com>
- * include/cygwin/version.h: Bump API version.
+ * speclib: Don't use /dev/null as DLL name. Just default to what's
+ already in .def file.
-Sun Jan 28 01:18:22 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-21 Christopher Faylor <cgf@redhat.com>
- * cygheap.cc (init_cheap): Move username initialization.
- (cygheap_init): Here.
- * shared_info.h (mount_info): Add a sys_mount_table_counter field.
- (shared_info): Ditto.
- * path.cc (mount_info::conv_to_win32_path): Check that our mount table
- is in sync with the system mount table and reinitialize it if not.
- (mount_info::add_reg_mount): Bump sys_mount_table counters if the
- system mount table changes.
- (mount_info::del_reg_mount): Ditto.
- (mount_info::write_cygdrive_info_to_registry): Ditto.
- (mount_info::remove_cygdrive_info_from_registry): Ditto.
+ * exceptions.cc (sig_handle): Remove last vestiges of SA_NOCLDSTOP code
+ which caused SIGCHLD to be ignored.
-Sun Jan 28 00:28:30 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-20 Christopher Faylor <cgf@redhat.com>
- Throughout, change 'cygwin_shared.mount' to 'mount_table'.
- * child_info.h (child_info): Move shared_h, console_h to cygheap. Add
- mount_h.
- * cygheap.h (init_cygheap): Add shared_h, console_h.
- * cygheap.cc (init_cheap): Initialize heap at a fixed location after
- the shared memory regions. Initialize cygheap->user name here.
- * dcrt0.cc (dll_crt0_1): Call getpagesize () to initialize constants.
- Remove cygheap_init since it is done in shared_init now.
- (_dll_crt0): Initialize mount_h, remove shared_h and console_h
- initialization.
- * fhandler_console.cc (console_shared_h): Eliminate.
- (get_tty_stuff): Use cygheap->console_h rather than console_shared_h.
- * heap.cc (heap_init): Use page size constant calculated earlier in
- initialization.
- * shared.cc: Eliminate cygwin_shared_h. Add cygwin_mount_h.
- (mount_table_init): New function for initializing a user mount table.
- (open_shared_file_map): Use constant for shared memory region.
- Initialize cygheap and mount table here.
- (open_shared): Improve debugging output.
- (shared_info::initialize): Eliminate call to mount.init.
- (shared_terminate): Use cygheap->shared_h. Close cygwin_mount_h.
- (open_shared_file_map): Eliminate.
- * shared_info.h (mount_info): Add a version field.
- (shared_align_past): New macro for calculating location for shared
- memory regions.
- * sigproc.cc (init_child_info): Eliminate shared_h, console_h.
- * spawn.cc (spawn_guts): Pass on cygwin_mount_h iff not a different
- user.
- * syscalls.cc (system_info): New global holding system memory defaults.
- (getpagesize): Use system_info.
- * uinfo.cc (internal_getlogin): Only fill in user name if nonexistent.
- * winsup.h: Declare system_info.
+ * include/cygwin/version.h: Bump DLL minor number.
- * passwd.cc (read_etc_passwd): Use cygheap->user.name () rather than
- retrieving the name again.
+2002-01-20 Christopher Faylor <cgf@redhat.com>
-Sat Jan 27 10:18:02 2001 Christopher Faylor <cgf@cygnus.com>
+ * syscalls.cc (regfree): Make dll_export.
- * path.cc (path_conv::check): Detect when path has symlinks.
- (symlink_info::check): Remove debugging stuff.
- (chdir): Use posix'ized win32 path if cd'ed to a path using symlinks.
+2002-01-20 Christopher Faylor <cgf@redhat.com>
-Fri Jan 26 21:20:28 2001 Christopher Faylor <cgf@cygnus.com>
+ * exceptions.cc (ctrl_c_handler): Convert windows pid to cygwin pid
+ when detecting if we should actually handle CTRL-C.
- * exceptions.cc (sigreturn): Call any pending signals prior to
- resetting the signal mask so that stacked signals behave correctly.
- (sigdelayed): Avoid a race where a signal could end up calling an
- incorrect signal handler if two signals come in close together.
+2002-01-19 Christopher Faylor <cgf@redhat.com>
-Tue Jan 23 21:56:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * Makefile.in (new-cygwin1.dll): Revert previous change. libsupc++.a
+ is only available in libstdc++-v3.
- * mmap.cc (fhandler_disk_file::mmap): Call CreateFileMapping with
- len != 0 only when performing an anonymous mapping.
+2002-01-19 Christopher Faylor <cgf@redhat.com>
-Mon Jan 22 15:35:28 2001 Christopher Faylor <cgf@cygnus.com>
+ * exceptions.cc (sig_handle_tty_stop): Don't send SIGCHLD if parent
+ doesn't want it.
+ (sig_handle): Don't check for SA_NOCLDSTOP here. We don't have enough
+ information.
- * path.h: Add a new constant.
- * syscalls.cc (_read): Oscillate errno check.
+2002-01-19 Christopher Faylor <cgf@redhat.com>
-Mon Jan 22 15:27:12 2001 Christopher Faylor <cgf@cygnus.com>
+ * include/cygwin/version.h: Bump DLL minor number.
- * include/cygwin/version.h: Bump API to reflect setlogmask.
+2002-01-19 Christopher Faylor <cgf@redhat.com>
-Sun Jan 21 22:40:25 2001 Jason Tishler <jt@dothill.com>
+ * Makefile.in (new-cygwin1.dll): Just use -lsupc++ for link.
+ * sigproc.cc (proc_exists): Change existence criteria.
+ * sync.h (new_muto): Add volatile to definition to avoid gcc
+ optimization problems.
- * cygwin.din: Add export for setlogmask().
- * syslog.cc (setlogmask): New function.
-
-Thu Jan 18 10:27:00 2001 Corinna Vinschen <corinna@vinschen.de>
-
- * resource.cc (setrlimit): Support RLIMIT_NOFILE.
-
-Wed Jan 17 23:23:12 2001 Christopher Faylor <cgf@cygnus.com>
-
- * syscalls.cc (setdtablesize): Call with amount to increment not total
- amount. Return success or failure error code.
+2002-01-19 Corinna Vinschen <corinna@vinschen.de>
-Wed Jan 17 09:47:13 2001 Christopher Faylor <cgf@cygnus.com>
+ * include/cygwin/version.h: Bump API minor version to 51.
- * autoload.cc (LoadDLLinitfunc): Remove debugging statement.
-
- * exceptions.cc (sig_handle_tty_stop): Move setting of PID_STOPPED to
- earlier in interrupt.
- (interrupt_setup): i.e., here.
- (sig_handle): Don't queue multiple SIGSTOPS.
- * fhandler.h (bg_check_types): Enumerate return value of bg_check for
- clarity.
- * signal.cc (kill_pgrp): Minor cleanup.
- * fhandler_termios.cc (fhandler_termios::bg_check): Use enumerated type
- for function return. Don't raise signal if a signal is already queued.
- * fhandler_console.cc (fhandler_console::read): Use enumerated return
- type for bg_check.
- * select.cc: Ditto, throughout.
- * read.cc: Ditto, throughout.
- * termios.cc: Ditto, throughout.
- (_read): YA interrupt detect simplification.
- * wait.cc (wait4): Ditto.
+2002-01-19 Mark Bradshaw <bradshaw@staff.crosswalk.com>
-Wed Jan 17 10:56:00 2001 Corinna Vinschen <corinna@vinschen.de>
+ * cygwin.din: Add recvmsg and sendmsg.
+ * net.cc: Add cygwin_recvmsg and cygwin_sendmsg.
+ * /usr/include/sys/socket.h: Add recvmsg and sendmsg.
- * cygheap.cc (cygheap_user::~cygheap_user): Temporarily
- disable free'ing memory.
-
-Tue Jan 16 18:01:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-19 Corinna Vinschen <corinna@vinschen.de>
- * mmap.cc (mmap): Initialize fh to avoid compiler warnings.
+ * security.cc (create_token): Close processes token handle as soon
+ as it's not used anymore.
-Mon Jan 15 21:07:00 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-17 Corinna Vinschen <corinna@vinschen.de>
- * wait.cc (wait4): Rename variable for consistency. Allow restartable
- signal behavior.
+ * Makefile.in: Add fnmatch.o to DLL_OFILES.
+ * cygwin.din: Add fnmatch export symbol.
+ * fnmatch.c: New file.
+ * include/fnmatch.h: Ditto.
+ * include/cygwin/version.h: Bump API minor version to 50.
-Mon Jan 15 23:15:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-15 Corinna Vinschen <corinna@vinschen.de>
- * mmap.cc (mmap): Add more parameter checking. Change error output
- in case of EINVAL. Treat mmapping /dev/zero like MAP_ANONYMOUS.
+ * path.cc (fchdir): Call chdir with full windows path.
-Mon Jan 15 20:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-14 Corinna Vinschen <corinna@vinschen.de>
- * mmap.cc: include <unistd.h>. Define some bit operations for
- the new page map.
- (mmap_record): Change type of base_address_ to caddr_t.
- Add map_map_ member. Add several methods to manipulate map_map_.
- (mmap_record::alloc_map): New method.
- (mmap_record::free_map): Ditto.
- (mmap_record::find_empty): Ditto.
- (mmap_record::map_map): Ditto.
- (mmap_record::unmap_map): Ditto.
- (list::add_record): Change return type to `mmap_record *'.
- Allocate page map.
- (list::match): New method.
- (mmap): Partly rewritten to take care for the new page map. Add some
- parameter checking.
- (munmap): Ditto.
+ * dir.cc: Use INVALID_FILE_ATTRIBUTES instead of "(DWORD) -1"
+ for file attributes throughout.
+ * fhandler.cc: Ditto.
+ * fhandler_disk_file.cc: Ditto.
+ * path.cc: Ditto.
+ * path.h: Ditto.
+ * syscalls.cc: Ditto.
+ * times.cc (utimes): Use path_conv::isdir() instead of explicit
+ GetFileAttributes() call.
-Mon Jan 15 13:50:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-13 Christopher Faylor <cgf@redhat.com>
- * heap.cc (heap_init): Fix extern declaration of getpagesize.
- * syscalls.cc (getpagesize): Fix another typo.
+ * dcrt0.cc (multiple_cygwin_problem): Clarify logic and make
+ CYGWIN_MISMATCH_OK more powerful.
-Mon Jan 15 12:48:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-10 Christopher Faylor <cgf@redhat.com>
- * syscalls.cc (getpagesize): Save pagesize in global variable to
- avoid calling GetSystemInfo too often.
- * heap.cc (getpagesize): Eliminate.
- (heap_init): Use getpagesize function from syscalls.cc.
+ * exceptions.cc (sig_handle): Accept a second argument indicating
+ whether the signal came from this process or not.
+ * sigproc.h: Reflect sig_handle arg change.
+ * signal.cc (kill_pgrp): Add sigframe info.
+ (abort): New function. Eliminates newlib function of same name.
+ * sigproc.cc (wait_sig): Pass "signal from this process" value as arg
+ 2.
-Mon Jan 15 11:56:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-10 Corinna Vinschen <corinna@vinschen.de>
- * sysconf.cc (sysconf): return `getpagesize ()' on _SC_PAGESIZE
- request to avoid implementing the same twice.
+ * syscalls.cc (pathconf): Guard _PC_PATH_MAX branch against invalid
+ file parameter.
-Sun Jan 14 14:07:50 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-09 Christopher Faylor <cgf@redhat.com>
+ Robert Collins <rbtcollins@hotmail.com>
- * syscalls.cc (_read): Use more lightweight method for determining if
- read has been interrupted by a signal.
+ * exceptions.cc (early_stuff_init): Rename from misnamed
+ set_console_handler.
+ (ctrl_c_handler): Attempt to work around potential signal duplication
+ during process startup.
+ (sig_handle): Ignore SIGINT when we're just an "exec stub".
+ * spawn.cc (spawn_guts): Store pid of spawned process in global for use
+ by ctrl_c_handler.
+ * dcrt0.cc (dll_crt0_1): Call renamed initialization function.
+ * winsup.h: Reflect function name change.
-Fri Jan 12 00:35:15 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-08 Corinna Vinschen <corinna@vinschen.de>
- * debug.h: Add regparm attributes to some functions.
+ * net.cc (cygwin_accept): Set sun_path for newly connected socket.
- * signal.cc (sigaction): Don't treat SIGCONT specially.
+2002-01-07 Ralf Habacker <Ralf.Habacker@freenet.de>
- * exceptions.cc (interrupt_setup): Save sa_flags of interrupted signal
- for later use.
- (sig_handler): Default any stopping signal to SIGSTOP.
- (call_signal_handler): New function.
- (sigdelayed0): New function.
- * sigproc.cc (sigproc_init): Initialize SIGSTOP sigaction for special
- behavior.
- * sigproc.h: Define call_signal_handler.
- * syscalls.cc (_read): Allow restartable signal behavior.
+ * Makefile.in: Add uninstall target.
-Thu Jan 11 13:17:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-07 Christopher Faylor <cgf@redhat.com>
- * fhandler.h (fhandler_base): New method `fixup_mmap_after_fork'.
- (fhandler_disk_file: Ditto.
- (fhandler_dev_mem): Ditto.
- * fhandler_mem.cc (fhandler_dev_mem::open): Set OBJ_INHERIT attribute
- for device\physicalmemory handle.
- (fhandler_dev_mem::mmap): Ditto.
- * fhandler_mem.cc (fhandler_dev_mem::fixup_mmap_after_fork): New
- method.
- * mmap.cc (mmap_record): Add private `fdesc_' member. Change
- constructor accordingly.
- (get_fd): New method.
- (mmap): Use new mmap_record constructor.
- (fhandler_base::fixup_mmap_after_fork): New method.
- (fhandler_disk_file::fixup_mmap_after_fork): Ditto.
- (fixup_mmaps_after_fork): Call `fixup_mmap_after_fork' of appropriate
- fhandler class.
+ * sigproc.cc (getsem): Clean up debugging output.
-Wed Jan 10 22:08:30 2001 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
+2002-01-07 Christopher Faylor <cgf@redhat.com>
- * sigproc.cc (wait_sig): Allow SIGCONT when stopped.
+ * sigproc.cc (getsem): Set errno when unable to create own semaphore.
+ Reorganize to make clearer that error should only come from initial
+ creation of process semaphore.
-Tue Jan 9 16:55:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-06 Christopher Faylor <cgf@redhat.com>
- Patch suggested by René Møller Fonseca <fonseca@mip.sdu.dk>
- * include/sys/socket.h: Change prototype to have 2nd parameter `const'.
- * net.cc (cygwin_bind): Change 2nd parameter to `const'.
+ * dtable.cc (dtable::init_std_file_from_handle): Add some defensive
+ code to invalid handle case.
-Sun Jan 7 22:59:37 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-06 Corinna Vinschen <corinna@vinschen.de>
- * pinfo.cc (codepage_init): Move function.
- * environ.cc (codepage_init): To here.
- * exceptoins.cc (SIG_NONMASKABLE): Remove SIGCONT from consideration
- since it is supposed to be maskable.
- * signal.cc (sigaction): Ditto.
- * sigproc.cc (wait_sig): Ditto.
- * winsup.h: Eliminate global declaration of codepage_init.
+ * ioctl.cc (ioctl): Make third argument optional.
+ * include/sys/ioctl.h: Ditto in declaration.
+ * dtable.cc (dtable::init_std_file_from_handle): Revert previous
+ bogus patch.
+ * window.cc (WndProc): Raise SIGURG instead of SIGIO in case of FD_OOB
+ message.
-Thu Jan 5 9:33:00 2001 Corinna Vinschen <corinna@vinschen.de>
+2002-01-05 Christopher Faylor <cgf@redhat.com>
- * resource.cc (getrlimit): Set errno on EFAULT instead of returning
- it.
- (setrlimit): Ditto.
+ * dir.cc (opendir): Guarantee release of alloced fhandler structure on
+ error.
-Thu Jan 5 3:38:00 2001 David Sainty <David.Sainty@optimation.co.nz>
+2002-01-05 Corinna Vinschen <corinna@vinschen.de>
- * resource.cc (setrlimit): Prevent failing with an error when the
- operation would not have changed anything.
+ * exceptions.cc (sig_handle): Set default action for SIGURG to SIG_IGN.
-Thu Jan 4 10:29:54 2001 Earnie Boyd <earnie_boyd@yahoo.com>
+2002-01-05 Corinna Vinschen <corinna@vinschen.de>
- * thread.cc: Need LONG_MAX definition.
+ * dtable.cc (dtable::init_std_file_from_handle): Don't treat NULL
+ handle as errorneous.
-Wed Jan 3 13:47:23 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-04 Christopher Faylor <cgf@redhat.com>
- * thread.cc (MTinterface::CreateSemaphore): Correctly set semaphore
- max.
+ * cygmagic: Change logic for equality test.
-Wed Jan 3 09:44:51 2001 Christopher Faylor <cgf@cygnus.com>
+2002-01-04 Christopher Faylor <cgf@redhat.com>
- * fhandler_console.cc (fhandler_console::read): Restore missing test
- for code page before doing OemToCharBuff.
+ * dir.cc (opendir): Don't attempt to call sub-opendir if ENOENT.
-Wed Jan 3 09:20:20 2001 Jason Tishler <jt@dothill.com>
+2002-01-04 Corinna Vinschen <corinna@vinschen.de>
- * include/cygwin/version.h: Fix typo in CYGWIN_VERSION_DLL_COMBINED
- macro.
+ * net.cc: Replace usage of AF_UNIX by Posix compliant AF_LOCAL
+ throughout.
+ (socketpair): Explicitly allow SOCK_STREAM and SOCK_DGRAM socket types
+ in families AF_UNIX and AF_LOCAL. Explicitly allow PF_UNSPEC, PF_LOCAL
+ and PF_INET protocols. Return error otherwise. Implement datagram
+ socketpairs.
+
+2002-01-01 Christopher Faylor <cgf@redhat.com>
+
+ * speclib: Remove temp files automatically.
+
+2002-01-01 Corinna Vinschen <corinna@vinschen.de>
+ * fhandler.h (fhandler_socket::sun_path): New private member.
+ (fhandler_socket::set_sun_path): New method.
+ (fhandler_socket::get_sun_path): Ditto.
+ * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize
+ sun_path to NULL.
+ (fhandler_socket::~fhandler_socket): Free sun_path if needed.
+ (fhandler_socket::set_sun_path): New method.
+ * net.cc (cygwin_bind): Set sun_path to path of local socket file.
+ (cygwin_getsockname): Add code to return correct sockaddr for unix
+ domain sockets.
diff --git a/winsup/cygwin/ChangeLog-1998 b/winsup/cygwin/ChangeLog-1998
index e22a158ed..aa657e01e 100644
--- a/winsup/cygwin/ChangeLog-1998
+++ b/winsup/cygwin/ChangeLog-1998
@@ -24,7 +24,7 @@ Wed Dec 30 21:41:25 1998 Christopher Faylor <cgf@cygnus.com>
assignment here but only do it when it is necessary or
programs will die abnormally.
* fhandler.h: Add raw_write method to fhandler_serial.
- * fhandler_serial.cc (raw_write): New method. Accomodates
+ * fhandler_serial.cc (raw_write): New method. Accommodates
overlapped I/O that now must be used with serial.
* utils/kill.cc (main): Allow `0' signal. Just checks
for existence of process.
@@ -430,7 +430,7 @@ Tue Dec 1 14:43:35 1998 Christopher Faylor <cgf@cygnus.com>
Tue Dec 1 08:34:18 1998 Christopher Faylor <cgf@cygnus.com>
- * mkvers.sh: Accomodate lack of timezone in date output so that
+ * mkvers.sh: Accommodate lack of timezone in date output so that
year shows up correctly.
Mon Nov 30 14:30:51 1998 Jeff Johnston <jjohnstn@cygnus.com>
@@ -2113,7 +2113,7 @@ Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
overhead.
(symlink_check_one): Check extensions for existence for use
with spawn.
- (readlink): Accomodate changes to symlink_check_one.
+ (readlink): Accommodate changes to symlink_check_one.
* spawn.cc (perhaps_suffix): Use new extension checking
capabilities of path_conv.
(find_exec_1): Delete.
@@ -2369,7 +2369,7 @@ Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
(setenv): Convert special environment variables to native here,
when they are set.
(struct parse_thing): Simplify struct.
- (struct parse_things): Extend table to accomodate "envcache"
+ (struct parse_things): Extend table to accommodate "envcache"
setting.
(parse_options): Add "envcache" option to control whether special
environment variables are cached. Simplify handling of remembered
@@ -2722,7 +2722,7 @@ Thu Aug 27 14:20:38 1998 Christopher Faylor <cgf@cygnus.com>
Wed Aug 26 14:15:22 1998 Christopher Faylor <cgf@cygnus.com>
* fhandler.h (fhandler_base): Make set_name() public and implement
- clear_name() to accomodate dup2.
+ clear_name() to accommodate dup2.
* hinfo.cc (dup2): Previous change exposed problem with dup2.
Same unix_path_name_ ptr was being used in two separate fds.
Fix this.
@@ -3722,7 +3722,7 @@ Tue Mar 10 15:41:29 1998 Geoffrey Noer <noer@cygnus.com>
Reorganize lpReserved2 buffer to avoid conflicts with Microsoft
usage which resulted in incorrect stdin/stdout operation with
programs compiled using MSVC.
- * pinfo.cc (pinfo_init): Accomodate change to lpReserved2
+ * pinfo.cc (pinfo_init): Accommodate change to lpReserved2
organization.
Mon Mar 9 19:27:17 1998 Geoffrey Noer <noer@cygnus.com>
diff --git a/winsup/cygwin/ChangeLog-1999 b/winsup/cygwin/ChangeLog-1999
index 49d6fe468..f2da41f51 100644
--- a/winsup/cygwin/ChangeLog-1999
+++ b/winsup/cygwin/ChangeLog-1999
@@ -73,7 +73,7 @@ Fri Dec 10 20:22:41 1999 Christopher Faylor <cgf@cygnus.com>
signal handler.
(handle_sigsuspend): Use set_sig_errno to ensure that the correct errno
is set after a signal handler.
- (interrupt_now): Accomodate default errno field in stack.
+ (interrupt_now): Accommodate default errno field in stack.
(intterupt_on_return): Ditto.
(sigreturn): Pop, test, and possibly restore saved errno on return from
signal handler.
@@ -117,9 +117,9 @@ Wed Dec 8 23:06:07 1999 Christopher Faylor <cgf@cygnus.com>
* Makefile.in: Ensure that winver.o is a dependency for building the
dll.
- * mkvers.sh: Attempt to call windres in a fashion that accomodates
+ * mkvers.sh: Attempt to call windres in a fashion that accommodates
older and newer versions.
- * winver.c: Reorganize slightly to accomodate older versions of
+ * winver.c: Reorganize slightly to accommodate older versions of
windres.
* fhandler.cc (fhandler_disk_file::fstat): Avoid using Windows "inodes"
on disks which do not support them.
@@ -207,7 +207,7 @@ Fri Dec 3 22:52:05 1999 Christopher Faylor <cgf@cygnus.com>
(events_init): Allocate mask_sync muto.
(unused_sig_wrapper): New function. Encapsulates assembly language
signal handling support.
- * fhandler.h (class select_stuff): Accomodate new signal-handling
+ * fhandler.h (class select_stuff): Accommodate new signal-handling
scheme.
* fhandler_console.cc (fhandler_console): Simplify to use new
signal-handling scheme.
@@ -321,7 +321,7 @@ Tue Nov 16 23:29:17 1999 Christopher Faylor <cgf@cygnus.com>
Sat Oct 30 00:59:38 1999 Christopher Faylor <cgf@cygnus.com>
* Makefile.in: Some general cleanup.
- * smallprint.c (__small_vsprintf): Accomodate new format for
+ * smallprint.c (__small_vsprintf): Accommodate new format for
__PRETTY_FUNCTION__.
Wed Oct 27 16:13:36 1999 Christopher Faylor <cgf@cygnus.com>
@@ -384,7 +384,7 @@ Tue Oct 19 22:10:21 1999 Christopher Faylor <cgf@cygnus.com>
Tue Oct 19 21:09:42 1999 Christopher Faylor <cgf@cygnus.com>
- Make minor changes throughout to accomodate new gcc merge.
+ Make minor changes throughout to accommodate new gcc merge.
* Makefile.in: Remvoe -fpermissive option when compiling using g++.
* dcrt0.cc (noload): Mark as "unused" to avoid a compiler warning.
* exceptions.cc (sigreturn): Make this "extern" since it essentially
@@ -393,7 +393,7 @@ Tue Oct 19 21:09:42 1999 Christopher Faylor <cgf@cygnus.com>
considered void.
* heap.cc (sbrk): Remove debugging code.
* passwd.cc (getpass): Don't use fprintf to print the prompt.
- * path.cc (mount_info::conv_to_win32_path): Accomodate compiler
+ * path.cc (mount_info::conv_to_win32_path): Accommodate compiler
warning.
* select.cc (cygwin_select): Experimental version of select which
handles fd_sets with non-standard FD_SETSIZE.
@@ -851,7 +851,7 @@ Mon Sep 6 13:36:34 1999 Christopher Faylor <cgf@cygnus.com>
* fhandler_tty.cc (fhandler_tty_master::init_console): Remove retrieval
of stderr handle since it is not required for correct init operation.
- * hinfo.cc (hinfo_init): Reorganize to accomodate potential closing of
+ * hinfo.cc (hinfo_init): Reorganize to accommodate potential closing of
console handles by fhandler_console::init.
(init_std_file_from_handle): Set standard handle as appropriate.
(hinfo::de_linearize_fd_arry): Ditto.
@@ -1407,9 +1407,9 @@ Tue Jul 27 23:31:28 1999 Christopher Faylor <cgf@cygnus.com>
or suffer weird behavior. Suggested by Andrew Dalgleish
<andrewd@axonet.com.au>.
* shared.cc: Make SHAREDVER "unsigned" to avoid a compiler warning.
- * spawn.cc : Accomodate additional argument to _spawnve, throughout.
+ * spawn.cc : Accommodate additional argument to _spawnve, throughout.
(_spawnve): Make this a global function and take an hToken argument so
- that it can be used by sexecve. Accomodate experimental vfork
+ that it can be used by sexecve. Accommodate experimental vfork
functionality.
* winsup.h: Add initial support for per-thread vfork stuff.
* include/cygwin/version.h: Bump shared memory version number.
@@ -1440,7 +1440,7 @@ Sat Jul 17 00:45:34 1999 Christopher Faylor <cgf@cygnus.com>
Fri Jul 16 23:47:31 1999 Christopher Faylor <cgf@cygnus.com>
- * sigproc.cc (proc_can_be_signalled): Accomodate different flavors of
+ * sigproc.cc (proc_can_be_signalled): Accommodate different flavors of
myself.
* include/ddeml.h: Add missing struct.
* include/wingdi.h: Add missing defines.
@@ -1534,7 +1534,7 @@ Wed Jul 14 22:08:52 1999 Christopher Faylor <cgf@cygnus.com>
(sig_wait): Set active state after all handles have been set up and
before protecting the handles. Use ForceCloseHandle to close
subproc_ready as it is now protected. Close signal_mutex here.
- * sigproc.h: Accomodate alive_parent rename.
+ * sigproc.h: Accommodate alive_parent rename.
* spawn.cc Use init_child_info to initilize memory block passed to
subprocess.
* strace.cc (__system_printf): Write to screen before writing to strace
@@ -1614,7 +1614,7 @@ Wed Jul 7 23:59:50 1999 Christopher Faylor <cgf@cygnus.com>
* fhandler.h: Add an extra 'fd' argument to all ready_for_read methods.
* select.cc: Ditto, throughout.
* fhandler_console (get_tty_stuff): Protect the tty_stuff handle here.
- * fhandler_termios.cc (fhandler_termios::line_edit): Accomodate fd
+ * fhandler_termios.cc (fhandler_termios::line_edit): Accommodate fd
argument to ready_for_read.
* fhandler_tty.cc (fhandler_tty_master::init): Close an unneeded thread
handle.
@@ -1724,7 +1724,7 @@ Thu Jul 1 22:36:31 1999 Christopher Faylor <cgf@cygnus.com>
* net.cc: Redo winsock functions to use dynamic loading scheme.
* shared.cc (shared_info::initialize): Cosmetic change.
* shared.h: Change magic number for memory block sent to child
- processes. Accomodate new heap information in child_info.
+ processes. Accommodate new heap information in child_info.
* sigproc.cc (sig_dispatch_pending): Remove some memory debugging checks.
(__release_signal_mutex): Ditto.
* syscalls.cc (stat_worker): Don't attempt the .exe hack unless the
@@ -1732,7 +1732,7 @@ Thu Jul 1 22:36:31 1999 Christopher Faylor <cgf@cygnus.com>
and the file did not already contain an extension.
* times.cc: Initialize static NO_COPY variables throughout or they will
not actually be NO_COPY.
- * winsup.h: Rename heap fields in per_process to accomodate new sbrk.
+ * winsup.h: Rename heap fields in per_process to accommodate new sbrk.
Eliminate winsock stuff invalidated by dynamic loading change.
* include/winsock.h: Make this file C++ safe.
@@ -1876,7 +1876,7 @@ Mon Jun 14 12:43:32 1999 Christopher Faylor <cgf@cygnus.com>
(strace_dump): Delete.
(mark): Gut.
* winsup.h: Remove a declaration. Add a new one.
- * include/sys/strace.h: Modify to accomodate new strace scheme.
+ * include/sys/strace.h: Modify to accommodate new strace scheme.
* utils/Makefile.in: Build strace.exe
* utils/strace.cc: New file.
@@ -2036,7 +2036,7 @@ Mon May 31 22:10:57 1999 Christopher Faylor <cgf@cygnus.com>
* fhandler.cc: Use methods to access path_conv flags
throughout.
* path.cc: (symlink-check_one): Accept a bitmask flags
- variable to accomodate path_conv changes.
+ variable to accommodate path_conv changes.
(path_conv::path_conv): Propagate path_flags from mount
table to path_conv class. Avoid walking the mount table
twice to find "binary" info.
@@ -2593,7 +2593,7 @@ Wed Mar 24 20:04:21 1999 Christopher Faylor <cgf@cygnus.com>
there is no change or Windows 95 will eat input.
(fhandler_console::tcsetattr): Use ONLRET to control binary behavior
since it is more closely analgous.
- (fhandler_console::fhandler_console): Accomodate fhandler_termios
+ (fhandler_console::fhandler_console): Accommodate fhandler_termios
base class.
(fhandler_console::init): Ditto.
(fhandler_console::igncr_enabled): Ditto.
@@ -2601,20 +2601,20 @@ Wed Mar 24 20:04:21 1999 Christopher Faylor <cgf@cygnus.com>
(fhandler_console::de_linearize): New function.
* fhandler_serial.cc: Need additional include.
* fhandler_tty.cc (fhandler_tty_master::fhandler_tty_master):
- Accomodate fhandler_termios base class.
+ Accommodate fhandler_termios base class.
(fhandler_tty_master::init): Ditto.
(fhandler_tty_master::accept_input): New function. Sends
(possibly line-edited) input to slave.
(process_input): Use line editing capabilities of fhandler_termios
base class when processing input.
- (fhandler_tty_slave::open): Accomodate fhandler_termios base class.
+ (fhandler_tty_slave::open): Accommodate fhandler_termios base class.
(fhandler_tty_slave::tcgetattr): Ditto.
(fhandler_tty_slave::ioctl): Ditto.
(fhandler_pty_master::fhandler_pty_master): Ditto.
(fhandler_pty_master::read): Ditto.
(fhandler_tty_slave::dup): Be more paranoid about setting output
handle in case of error.
- * fhandler_tty.h: Accomodate new tty_min base class in tty class.
+ * fhandler_tty.h: Accommodate new tty_min base class in tty class.
* hinfo.cc (hinfo::build_fhandler): Send tty 'unit' to constructor.
* select.cc (peek_console): Send resize event to window regardless
of tty setting. Eliminate ReadFile kludge.
diff --git a/winsup/cygwin/ChangeLog-2000 b/winsup/cygwin/ChangeLog-2000
index 10e7e30af..54494e610 100644
--- a/winsup/cygwin/ChangeLog-2000
+++ b/winsup/cygwin/ChangeLog-2000
@@ -120,7 +120,7 @@ Sat Dec 9 16:29:45 2000 Christopher Faylor <cgf@cygnus.com>
Fri Dec 8 22:21:01 2000 Christopher Faylor <cgf@cygnus.com>
- * path.cc (normalize_win32_path): Reorganize logic to accomodate
+ * path.cc (normalize_win32_path): Reorganize logic to accommodate
chroot. Always check for MAX_PATH overrun. Avoid adding one too many
backslashes when src path begins with a slash. From Corinna Vinschen.
* winsup.h: Force demangling for dll_crt0 for newer compilers.
@@ -567,7 +567,7 @@ Thu Nov 2 00:10:23 2000 Christopher Faylor <cgf@cygnus.com>
psapi.h.
(EnumProcesses9x): Rename from EnumProcessesW95. Change arguments to
be more useful for cygwin.
- (winpids::init): Accomodate argument changes.
+ (winpids::init): Accommodate argument changes.
(enum_init): Ditto.
* pinfo.h (winpids): Make pidlist dynamically extendable by storing it
as a pointer and remembering the size.
@@ -958,7 +958,7 @@ Mon Oct 16 18:37:22 2000 Christopher Faylor <cgf@cygnus.com>
(normalize_win32_path): Ditto.
(cwdstuff::get_initial): Always set lock.
* sigproc.h: Remove hExeced.
- * strace.cc (strace::vsprntf): Modify to accomodate for lack of hExeced.
+ * strace.cc (strace::vsprntf): Modify to accommodate for lack of hExeced.
* thread.cc (MTinterface::Init): Merge Init1 and ClearReent into this method.
(MTinterface::Init1): Eliminate.
(MTinterface::ClearReent): Eliminate.
@@ -1301,7 +1301,7 @@ Sun Oct 1 16:36:00 2000 Corinna Vinschen <corinna@vinschen.de>
Sun Oct 1 22:20:39 2000 Christopher Faylor <cgf@cygnus.com>
* cygheap.cc (cygheap_init): Born again function.
- (_cmalloc): Reorganize to accomodate muto locking.
+ (_cmalloc): Reorganize to accommodate muto locking.
(_cfree): Use muto lock to avoid multi-thread problems.
* cygheap.h (incygheap): Just use cygheap_max to find upper cygwin heap
bounds.
@@ -1334,8 +1334,8 @@ Sat Sep 30 00:43:42 2000 Christopher Faylor <cgf@cygnus.com>
execed or not. In execed case, walk the heap, cleaning up any orphaned
blocks.
* cygheap.h: Add a "MAX" value to cygheap_types. Remove cygheap_init
- declaration. Accomodate new argument to cygheap_fixup_in child.
- * fork.cc (fork): Accomodate extra argument to cygheap_fixup_in_child.
+ declaration. Accommodate new argument to cygheap_fixup_in child.
+ * fork.cc (fork): Accommodate extra argument to cygheap_fixup_in_child.
* dcrt0.cc (dll_crt0_1): Ditto. Remove call to cygheap_init.
Fri Sep 29 21:49:27 2000 Christopher Faylor <cgf@cygnus.com>
@@ -1360,7 +1360,7 @@ Thu Sep 28 01:46:00 2000 Corinna Vinschen <corinna@vinschen.de>
Wed Sep 27 01:10:07 2000 Christopher Faylor <cgf@cygnus.com>
- * spawn.cc (spawn_guts): Attempt to accomodate archaic windows quoting
+ * spawn.cc (spawn_guts): Attempt to accommodate archaic windows quoting
mechanism when dealing with '\' and '"'.
Mon Sep 25 20:47:04 2000 Christopher Faylor <cgf@cygnus.com>
@@ -1606,7 +1606,7 @@ Mon Sep 4 22:53:58 2000 Christopher Faylor <cgf@cygnus.com>
(normalize_win32_path): Ditto.
(mount_info::conv_to_win32_path): Eliminate cwd retrieval here.
(mount_info::conv_to_posix_path): Ditto.
- (hash_path_name): Accomodate additional methods in cwdstuff.
+ (hash_path_name): Accommodate additional methods in cwdstuff.
(get_cwd_win32): Eliminate.
(getcwd): Use cwdstuff methods. Properly handle case where buf == NULL
and len < 0.
@@ -1641,7 +1641,7 @@ Sun Sep 3 00:07:32 2000 Christopher Faylor <cgf@cygnus.com>
* dcrt0.cc (quoted): Simplify due to new method for passing arguments
between cygwin programs.
(alloc_stack_hard_way): Attempt to handle overlapped stack.
- (dll_crt0_1): Move child_info processing here. Accomodate new method
+ (dll_crt0_1): Move child_info processing here. Accommodate new method
for passing arguments between cygwin programs. Initialize cygwin heap.
Establish __argc and __argv variables.
(_dll_crt0): Move most of child_info processing to dll_crt0_1.
@@ -1668,7 +1668,7 @@ Sun Sep 3 00:07:32 2000 Christopher Faylor <cgf@cygnus.com>
(fhandler_base::de_linearize): Delete.
(fhandler_base::operator delete): Free from cygwin heap.
(fhandler_base::~fhandler_base): Ditto.
- * fhandler.h: Accomodate elimination of *linearize and other changes
+ * fhandler.h: Accommodate elimination of *linearize and other changes
above.
* fhandler_console.cc (fhandler_console::fixup_after_exec): Rename from
de_linearize.
@@ -1687,10 +1687,10 @@ Sun Sep 3 00:07:32 2000 Christopher Faylor <cgf@cygnus.com>
(cwd_posix): New function.
(cwd_hash): New function.
(cwd_fixup_after_exec): New function.
- * path.h: Accomodate path.cc changes.
+ * path.h: Accommodate path.cc changes.
* pinfo.cc (pinfo_init): Accept a pointer to an environment table.
Pass this to environ_init. Eliminate old 'title' tests.
- * pinfo.h: Accomodate above change in argument.
+ * pinfo.h: Accommodate above change in argument.
* spawn.cc (struct av): New method for building argv list.
(av::unshift): New method.
(spawn_guts): Allocate everything that the child process needs in the
@@ -2069,8 +2069,8 @@ Sat Jul 29 12:01:32 2000 Christopher Faylor <cgf@cygnus.com>
Redefine process structure to avoid a fixed size table. Redefine
pinfo/_pinfo classes. Use these throughout.
- * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change.
- (__api_fatal): Accomodate _pinfo::record_death argument change.
+ * dcrt0.cc (dll_crt0_1): Accommodate set_myself argument change.
+ (__api_fatal): Accommodate _pinfo::record_death argument change.
* exceptions.cc (really_exit): Ditto.
(sig_handle_tty_stop): Use pinfo constructor to access process info.
(events_init): Don't create pinfo_mutex since it is no longer required.
@@ -2089,7 +2089,7 @@ Sat Jul 29 12:01:32 2000 Christopher Faylor <cgf@cygnus.com>
(set_myself): Accept a pid argument now. Call pinfo initializer to
initialize myself. Detect when this is an "execed" process and create
an "indirect" pid block.
- (pinfo_init): Accomodate set_myself arg change.
+ (pinfo_init): Accommodate set_myself arg change.
(procinfo): Remove.
(pinfo::lock_pinfo): Remove.
(pinfo::unlock_pinfo): Remove.
@@ -2126,7 +2126,7 @@ Sat Jul 29 12:01:32 2000 Christopher Faylor <cgf@cygnus.com>
(internal_getlogin): Use _pinfo.
* winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration
since it is static now. Reflect set_myself argument change.
- * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo
+ * include/sys/cygwin.h: Add some PID_* enums to accommodate new pinfo
stuff.
Sat Jul 29 12:13:27 2000 Christopher Faylor <cgf@cygnus.com>
@@ -2312,7 +2312,7 @@ Fri Jul 21 12:03:00 2000 Corinna Vinschen <corinna@vinschen.de>
Wed Jul 19 22:24:00 2000 Corinna Vinschen <corinna@vinschen.de>
* spawn.cc (spawn_guts): Don't restore impersonation in case
- of _P_OVERLAY. Clean up slightly. Accomodate comments.
+ of _P_OVERLAY. Clean up slightly. Accommodate comments.
Wed Jul 19 22:11:00 2000 Corinna Vinschen <corinna@vinschen.de>
@@ -2488,7 +2488,7 @@ Sat Jul 8 00:15:01 2000 Christopher Faylor <cgf@cygnus.com>
__cygwin_user_data pointer from cygwin_internal. If it doesn't exist,
return failure. Use either this pointer or passed in pointer
throughout. Clear forkee.
- * lib/crt0.h: Accomodate argument changes to _cygwin_crt0_common.
+ * lib/crt0.h: Accommodate argument changes to _cygwin_crt0_common.
* lib/cygwin_attach_dll.c (cygwin_attach_dll): Reorganize to allow use
of newer binaries with older DLLs. Detect older DLLs when
_cygwin_crt0_common returns 0 and allocate space for a per_process
@@ -2518,7 +2518,7 @@ Wed Jul 5 18:56:58 2000 Christopher Faylor <cgf@cygnus.com>
(DllListIterator::operator *): Ditto.
(dll_dllcrt0): Default to __cygwin_user_data if arg is NULL.
* include/sys/cygwin.h: Reorganize per_process to eliminate obsolete
- fields and accomodate new way of initializing.
+ fields and accommodate new way of initializing.
* lib/_cygwin_crt0_common: Initialize _impure_ptr from
__cygwin_user_data.impure_ptr.
@@ -2624,7 +2624,7 @@ Sat Jul 1 11:43:32 2000 Christopher Faylor <cgf@cygnus.com>
Sat Jul 1 00:24:04 2000 Christopher Faylor <cgf@cygnus.com>
* dcrt0.cc (_dll_crt0): Renamed from dll_crt0 ().
- * winsup.h: Accomodate above change.
+ * winsup.h: Accommodate above change.
* cygwin.din: Ditto.
* lib/cygwin_crt0.c: Ditto.
@@ -2813,7 +2813,7 @@ Sat Jun 17 13:51:48 2000 Christopher Faylor <cgf@cygnus.com>
* configure.in: Detect "cross-hosting" situation and set appropriate
variables in Makefile to avoid building excess stuff.
* configure: Regenerate.
- * Makefile.in: Accomodate above change.
+ * Makefile.in: Accommodate above change.
Sat Jun 17 19:52:00 2000 Corinna Vinschen <corinna@vinschen.de>
@@ -3189,7 +3189,7 @@ Mon May 15 00:35:35 2000 Christopher Faylor <cgf@cygnus.com>
Sun May 14 23:41:24 2000 Christopher Faylor <cgf@cygnus.com>
* shared.h: Bump PROC_MAGIC.
- * include/cygwin/version.h: Bump API minor to accomodate two recent
+ * include/cygwin/version.h: Bump API minor to accommodate two recent
exports.
2000-05-13 Mumit Khan <khan@xraylith.wisc.edu>
@@ -3438,7 +3438,7 @@ Fri Apr 21 10:37:08 2000 Christopher Faylor <cgf@cygnus.com>
Thu Apr 20 17:32:42 2000 Christopher Faylor <cgf@cygnus.com>
* exceptions.cc (handle_exceptions): Search further for stack info to
- accomodate Windows 95.
+ accommodate Windows 95.
Thu Apr 20 16:39:18 2000 Christopher Faylor <cgf@cygnus.com>
@@ -3956,7 +3956,7 @@ Sat Feb 5 00:26:01 2000 Christopher Faylor <cgf@cygnus.com>
* exceptions.cc (sigWaitForSingleObject): Eliminate obsolete function
definition.
* fhandler.h: Reflect change to select_stuff wait method.
- * fhandler_tape.cc (get_ll): Accomodate new w32api LARGE_INTEGER
+ * fhandler_tape.cc (get_ll): Accommodate new w32api LARGE_INTEGER
definition.
* ntea.c (NTReadEARaw): Ditto.
(NTWriteEA): Ditto.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 6aaca814f..7bdb6aad7 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -14,7 +14,7 @@ srcdir:=@srcdir@
objdir:=.
CONFIG_DIR:=$(srcdir)/config/@CONFIG_DIR@
-VPATH:=$(srcdir):$(CONFIG_DIR):$(srcdir)/regexp:$(srcdir)/lib
+VPATH:=$(srcdir):$(CONFIG_DIR):$(srcdir)/regex:$(srcdir)/regexp:$(srcdir)/lib
target_alias:=@target_alias@
build_alias:=@build_alias@
@@ -44,14 +44,14 @@ INSTALL_PROGRAM:=@INSTALL_PROGRAM@
#
# --enable options from configure
#
-MT_SAFE = @MT_SAFE@
-DEFS = @DEFS@
+MT_SAFE:=@MT_SAFE@
+DEFS:=@DEFS@
CC:=@CC@
# FIXME: Which is it, CC or CC_FOR_TARGET?
CC_FOR_TARGET:=$(CC)
CFLAGS:=@CFLAGS@
-CFLAGS+=-MD -fbuiltin
+override CFLAGS+=-MMD -fbuiltin
CXX:=@CXX@
CXXFLAGS:=@CXXFLAGS@
@@ -65,7 +65,8 @@ LD:=@LD@
DLLTOOL:=@DLLTOOL@
WINDRES:=@WINDRES@
AS:=@AS@
-LDSCRIPT=cygwin.sc
+NM:=@NM@
+LDSCRIPT:=cygwin.sc
#
# Include common definitions for winsup directory
@@ -78,8 +79,8 @@ INSTALL_DATA:=$(SHELL) $(updir1)/install-sh -c
# Setup the testing framework, if you have one
EXPECT = `if [ -f $${rootme}/../../expect/expect$(EXEEXT) ] ; then \
- echo $${rootme}/../../expect/expect$(EXEEXT) ; \
- else echo expect ; fi`
+ echo $${rootme}/../../expect/expect$(EXEEXT) ; \
+ else echo expect ; fi`
RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \
echo $${srcdir}/../dejagnu/runtest ; \
@@ -114,31 +115,50 @@ EXTRA_OFILES=$(bupdir1)/libiberty/random.o $(bupdir1)/libiberty/strsignal.o
MALLOC_OFILES=@MALLOC_OFILES@
-DLL_IMPORTS:=$(w32api_lib)/libkernel32.a
-
-DLL_OFILES:=assert.o autoload.o cygheap.o cygserver_client.o \
- cygserver_transport.o cygserver_transport_pipes.o cygserver_transport_sockets.o \
- dcrt0.o debug.o \
- delqueue.o dir.o \
- dlfcn.o dll_init.o dtable.o environ.o errno.o exceptions.o exec.o \
- external.o fcntl.o fhandler.o fhandler_clipboard.o fhandler_console.o \
- fhandler_dsp.o fhandler_floppy.o fhandler_mem.o fhandler_random.o \
- fhandler_raw.o fhandler_serial.o fhandler_socket.o fhandler_tape.o \
- fhandler_termios.o fhandler_tty.o fhandler_windows.o fhandler_zero.o \
- fork.o glob.o grp.o heap.o init.o ioctl.o ipc.o localtime.o malloc.o \
- miscfuncs.o mmap.o net.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o \
- pthread.o regexp.o regerror.o regsub.o registry.o resource.o scandir.o \
- sched.o sec_acl.o sec_helper.o security.o select.o shared.o shm.o \
- shortcut.o signal.o sigproc.o \
- smallprint.o spawn.o strace.o strsep.o sync.o syscalls.o sysconf.o \
- syslog.o termios.o thread.o times.o tty.o uinfo.o uname.o wait.o \
- wincap.o window.o \
- $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS)
-
-GMON_OFILES:= gmon.o mcount.o profil.o
-
+DLL_IMPORTS:=$(w32api_lib)/libuuid.a $(w32api_lib)/libshell32.a $(w32api_lib)/libkernel32.a
+
+# Please maintain this list in sorted order, with maximum files per 80 col line
+DLL_OFILES:= \
+ assert.o autoload.o cygheap.o cygserver_client.o \
+ cygserver_transport.o cygserver_transport_pipes.o \
+ cygserver_transport_sockets.o cygthread.o dcrt0.o debug.o \
+ delqueue.o dir.o dlfcn.o dll_init.o dtable.o environ.o errno.o \
+ exceptions.o exec.o external.o fcntl.o fhandler.o \
+ fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \
+ fhandler_dsp.o fhandler_floppy.o fhandler_mem.o \
+ fhandler_proc.o fhandler_process.o fhandler_random.o \
+ fhandler_raw.o fhandler_registry.o fhandler_serial.o \
+ fhandler_socket.o fhandler_tape.o fhandler_termios.o \
+ fhandler_tty.o fhandler_virtual.o fhandler_windows.o \
+ fhandler_zero.o fnmatch.o fork.o glob.o grp.o heap.o init.o \
+ ioctl.o ipc.o localtime.o malloc.o malloc_wrapper.o \
+ miscfuncs.o mmap.o msg.o net.o ntea.o passwd.o path.o pinfo.o \
+ pipe.o poll.o pthread.o regcomp.o regerror.o regexec.o \
+ regfree.o registry.o resource.o scandir.o sched.o sec_acl.o \
+ sec_helper.o security.o select.o sem.o shared.o shm.o signal.o \
+ sigproc.o smallprint.o spawn.o strace.o strsep.o sync.o \
+ syscalls.o sysconf.o syslog.o termios.o thread.o times.o tty.o \
+ uinfo.o uname.o v8_regexp.o v8_regerror.o v8_regsub.o wait.o \
+ wincap.o window.o \
+ $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS)
+
+GMON_OFILES:=gmon.o mcount.o profil.o
+
+OBSOLETE_FUNCTIONS:=regcomp regerror regexec regfree regsub
+NEW_FUNCTIONS:=regcomp posix_regcomp \
+ regerror posix_regerror \
+ regexec posix_regexec \
+ regfree posix_regfree
+
+API_VER:=$(srcdir)/include/cygwin/version.h
+
+PWD:=${shell pwd}
+SUBLIBS:=libpthread.a $(PWD)/libm.a libc.a
+EXTRALIBS:=libautomode.a libbinmode.a libtextmode.a
+INSTOBJS:=automode.o binmode.o textmode.o
+TARGET_LIBS:=$(LIB_NAME) $(SUBLIBS) $(GMON_START) $(LIBGMON_A) $(SUBLIBS) $(INSTOBJS) $(EXTRALIBS)
.PHONY: all force dll_ofiles install all_target install_target all_host install_host \
- install install_target install-libs install-headers
+ install install-libs install-headers -lgcc
.SUFFIXES:
.SUFFIXES: .c .cc .def .a .o .d
@@ -148,21 +168,21 @@ install_host=@install_host@
all: all_target $(all_host)
-all_target: $(LIB_NAME) automode.o binmode.o textmode.o $(LIBGMON_A) cygserver.exe
+all_target: $(TARGET_LIBS) cygserver.exe
all_host: new-$(LIB_NAME) cygrun.exe
force:
-install: install-bin install-libs install-headers $(install_host) $(install_target)
+install: install-libs install-headers install-man install_target \
+ $(install_host) $(install_target)
-install-bin: cygserver.exe
- $(INSTALL_PROGRAM) cygserver.exe $(bindir)/cygserver.exe
+uninstall: uninstall-libs uninstall-headers uninstall-man
-install-libs: $(LIB_NAME)
+install-libs: $(TARGET_LIBS)
$(INSTALL_DATA) new-$(DLL_NAME) $(bindir)/$(DLL_NAME); \
- for i in $(LIB_NAME) $(GMON_START) $(LIBGMON_A) automode.o binmode.o textmode.o ; do \
- $(INSTALL_DATA) $$i $(tooldir)/lib/$$i ; \
+ for i in $^; do \
+ $(INSTALL_DATA) $$i $(tooldir)/lib/`basename $$i` ; \
done
install-headers:
@@ -172,61 +192,139 @@ install-headers:
$(INSTALL_DATA) $$i $(tooldir)/$$sub/`basename $$i` ; \
done ; \
done ; \
- $(INSTALL_DATA) regexp/regexp.h $(tooldir)/include/regexp.h
+ $(INSTALL_DATA) regex/regex.h $(tooldir)/include/regex.h
+
+install-man:
+ cd $(srcdir); \
+ for i in `find . -type f -name '*.2'`; do \
+ $(INSTALL_DATA) $$i $(tooldir)/man/man2/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.3'`; do \
+ $(INSTALL_DATA) $$i $(tooldir)/man/man3/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.5'`; do \
+ $(INSTALL_DATA) $$i $(tooldir)/man/man5/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.7'`; do \
+ $(INSTALL_DATA) $$i $(tooldir)/man/man7/`basename $$i` ; \
+ done
+
+install_target: cygserver.exe
+ $(INSTALL_PROGRAM) cygserver.exe $(bindir)/cygserver.exe
install_host:
+
+uninstall-libs: $(TARGET_LIBS)
+ rm -f $(bindir)/$(DLL_NAME); \
+ for i in $^; do \
+ rm -f $(tooldir)/lib/$$i ; \
+ done
+
+uninstall-headers:
+ cd $(srcdir); \
+ for sub in `find include -name '[a-z]*' -type d -print | sort`; do \
+ for i in $$sub/*.h ; do \
+ rm -f $(tooldir)/$$sub/`basename $$i` ; \
+ done ; \
+ done ; \
+ rm -f $(tooldir)/include/regex.h
+
+uninstall-man:
+ cd $(srcdir); \
+ for i in `find . -type f -name '*.2'`; do \
+ rm -f $(tooldir)/man/man2/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.3'`; do \
+ rm -f $(tooldir)/man/man3/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.5'`; do \
+ rm -f $(tooldir)/man/man5/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.7'`; do \
+ rm -f $(tooldir)/man/man7/`basename $$i` ; \
+ done
+
clean:
- -rm -f *.o *.dll *.a *.exp junk *.base version.cc regexp/*.o winver_stamp *.exe *.d
+ -rm -f *.o *.dll *.a *.exp junk *.base version.cc regexp/*.o winver_stamp *.exe *.d *stamp* *_magic.h
maintainer-clean realclean: clean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
-rm -fr configure
+
+# Rule to build cygwin.dll
+new-$(DLL_NAME): $(LDSCRIPT) $(DLL_OFILES) $(DEF_FILE) $(DLL_IMPORTS) $(LIBC) $(LIBM) $(API_VER) Makefile winver_stamp
+ $(CXX) $(CXXFLAGS) -nostdlib -Wl,-T$(firstword $^) -Wl,--out-implib,cygdll.a -shared -o $@ \
+ -e $(DLL_ENTRY) $(DEF_FILE) $(DLL_OFILES) version.o winver.o \
+ $(MALLOC_OBJ) $(LIBM) $(LIBC) \
+ -lstdc++ -lgcc $(DLL_IMPORTS)
+
# Rule to build libcygwin.a
+$(LIB_NAME): rmsym newsym new-$(DLL_NAME) $(LIBCOS)
+ /bin/sh ${word 1,$^} ./cygdll.a "$(NM)" "$(AR)" "$(RANLIB)" $(OBSOLETE_FUNCTIONS) || exit 0
+ /bin/sh ${word 2,$^} ./cygdll.a "$(AS)" "$(AR)" "$(RANLIB)" $(NEW_FUNCTIONS) || exit 0
+ (echo create $(LIB_NAME); echo addmod $(LIBCOS); echo addlib cygdll.a; echo save) | $(AR) -M
# Rule to make stub library used by testsuite
-
-# dependency set to $(LIB_NAME) to accomodate make -j2.
+# dependency set to $(LIB_NAME) to accommodate make -j2.
# Otherwise dlltool gets confused. cgf (11-16-2000)
new-$(LIB_NAME): $(LIB_NAME)
$(DLLTOOL) --as=$(AS) --dllname new-$(DLL_NAME) --def $(DEF_FILE) --output-lib new-templib.a
$(AR) rcv new-templib.a $(LIBCOS)
mv new-templib.a new-$(LIB_NAME)
-
-# Rule to build cygwin.dll
-
-new-$(DLL_NAME): $(LDSCRIPT) $(DLL_OFILES) $(DEF_FILE) $(DLL_IMPORTS) $(LIBC) $(LIBM) Makefile winver_stamp
- $(CXX) $(CXXFLAGS) -nostdlib -Wl,-T$(firstword $^) -Wl,--out-implib,$(LIB_NAME) -shared -o $@ \
- -e $(DLL_ENTRY) $(DEF_FILE) $(DLL_OFILES) version.o winver.o \
- $(DLL_IMPORTS) $(MALLOC_OBJ) $(LIBM) $(LIBC) \
- -lstdc++ -lgcc -lshell32 -luuid
- @rm -f stamp-cygwin-lib
-
-$(LIB_NAME): new-$(DLL_NAME) $(LIBCOS) stamp-cygwin-lib
- $(AR) rcv $(LIB_NAME) $(LIBCOS)
-
-stamp-cygwin-lib:
- @touch stamp-cygwin-lib
+ $(RANLIB) $@
dll_ofiles: $(DLL_OFILES)
$(LIBGMON_A): $(GMON_OFILES) $(GMON_START)
$(AR) rcv $(LIBGMON_A) $(GMON_OFILES)
+$(API_VER): $(srcdir)/cygwin.din
+ @echo Error: Version info is older than DLL API!
+ @false
+
version.cc winver.o: winver_stamp
@ :
+shared_info_magic.h: cygmagic shared_info.h
+ /bin/sh ${word 1,$^} $@ "$(CC) -x c" ${word 2,$^} MOUNT_MAGIC 'class mount_info' SHARED_MAGIC 'class shared_info'
+
+child_info_magic.h: cygmagic child_info.h
+ /bin/sh ${word 1,$^} $@ "$(CC) -x c" ${word 2,$^} CHILD_INFO_MAGIC 'class child_info'
+
+dcrt0.o sigproc.o: child_info_magic.h
+
+shared.o: shared_info_magic.h
+
+libpthread.a: speclib cygwin.def pthread.o thread.o
+ /bin/sh ${word 1, $^} $@ "${NM}" "${DLLTOOL}" "${AS}" ${wordlist 2, 99, $^}
+
+$(PWD)/libm.a: speclib cygwin.def $(LIBM)
+ /bin/sh ${word 1, $^} $@ "${NM}" "${DLLTOOL}" "${AS}" ${wordlist 2, 99, $^}
+
+$(PWD)/libc.a: speclib cygwin.def $(PWD)/libm.a libpthread.a
+ /bin/sh ${word 1, $^} -v $@ "${NM}" "${DLLTOOL}" "${AS}" ${wordlist 2, 99, $^}
+
+lib%.a: %.o
+ $(AR) cru $@ $?
+
winver_stamp: mkvers.sh include/cygwin/version.h winver.rc $(DLL_OFILES)
@echo "Making version.o and winver.o";\
$(SHELL) ${word 1,$^} ${word 2,$^} ${word 3,$^} $(WINDRES) && \
$(COMPILE_CXX) -o version.o version.cc && \
touch $@
-cygrun.exe : cygrun.o $(LIB_NAME) $(w32api_lib)/libuser32.a \
+malloc.o: malloc.cc
+ $(COMPILE_CXX) -fomit-frame-pointer -o $@ $<
+
+cygrun.o: cygrun.c
+ $(CC) $(MINGW_CFLAGS) -o $@ -c $<
+
+cygrun.exe : cygrun.o -lgcc $(w32api_lib)/libuser32.a \
$(w32api_lib)/libshell32.a $(w32api_lib)/libkernel32.a
- $(CC) -nodefaultlibs -o $@ $^
+ $(CC) -mno-cygwin -o $@ $^
cygserver_transport_outside.o: cygserver_transport.cc
$(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $<
@@ -240,11 +338,8 @@ cygserver_transport_sockets_outside.o: cygserver_transport_sockets.cc
cygserver_client_outside.o: cygserver_client.cc
$(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $<
-cygserver_shm.o: cygserver_shm.cc
- $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $<
-
-cygserver.exe: cygserver.o cygserver_shm.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o
- $(CXX) -o $@ $^
+cygserver.exe: cygserver.o cygserver_shm.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o
+ $(CXX) -o $@ $^ -lstdc++
#ifdef VERBOSE
# $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS)
#else
@@ -252,6 +347,9 @@ cygserver.exe: cygserver.o cygserver_shm.o cygserver_transport_outside.o cygserv
# $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS)
#endif
+-lgcc:
+ :
+
#
Makefile: cygwin.din
diff --git a/winsup/cygwin/assert.cc b/winsup/cygwin/assert.cc
index 4c5a3b08f..063c7b852 100644
--- a/winsup/cygwin/assert.cc
+++ b/winsup/cygwin/assert.cc
@@ -28,9 +28,9 @@ __assert (const char *file, int line, const char *failedexpr)
/* If we don't have a console in a Windows program, then bring up a
message box for the assertion failure. */
- h = CreateFileA ("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, &sec_none_nih,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (h == INVALID_HANDLE_VALUE || h == 0)
+ h = CreateFile ("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, &sec_none_nih,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
{
char *buf;
@@ -46,6 +46,9 @@ __assert (const char *file, int line, const char *failedexpr)
failedexpr, file, line);
}
+#ifdef DEBUGGING
+ try_to_debug ();
+#endif
abort (); // FIXME: Someday this should work.
/* NOTREACHED */
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index ffd9f0078..7c3f47fc6 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -1,6 +1,6 @@
/* autoload.cc: all dynamic load stuff.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -72,9 +72,10 @@ details. */
/* Standard DLL load macro. Invokes a fatal warning if the function isn't
found. */
#define LoadDLLfunc(name, n, dllname) LoadDLLfuncEx (name, n, dllname, 0)
+#define LoadDLLfuncEx(name, n, dllname, notimp) LoadDLLfuncEx2(name, n, dllname, notimp, 0)
/* Main DLL setup stuff. */
-#define LoadDLLfuncEx(name, n, dllname, notimp) \
+#define LoadDLLfuncEx2(name, n, dllname, notimp, err) \
LoadDLLprime (dllname, dll_func_load) \
__asm__ (" \n\
.section ." #dllname "_text,\"wx\" \n\
@@ -83,10 +84,12 @@ details. */
.align 8 \n\
_" mangle (name, n) ": \n\
_win32_" mangle (name, n) ": \n\
- movl (1f),%eax \n\
+ .byte 0xe9 \n\
+ .long -4 + 1f - . \n\
+1:movl (2f),%eax \n\
call *(%eax) \n\
-1:.long ." #dllname "_info \n\
- .long " #n "+" #notimp " \n\
+2:.long ." #dllname "_info \n\
+ .long (" #n "+" #notimp ") | " #err "<<16 \n\
.asciz \"" #name "\" \n\
.text \n\
");
@@ -122,10 +125,14 @@ noload: \n\
decl %eax # Yes. This is the # of bytes + 1 \n\
popl %edx # Caller's caller \n\
addl %eax,%esp # Pop off bytes \n\
+ andl $0xffff0000,%eax# upper word \n\
+ subl %eax,%esp # adjust for possible return value \n\
+ pushl %eax # Save for later \n\
movl $127,%eax # ERROR_PROC_NOT_FOUND \n\
pushl %eax # First argument \n\
call _SetLastError@4 # Set it \n\
- xor %eax,%eax # Zero functional return \n\
+ popl %eax # Get back argument \n\
+ shrl $16,%eax # return value in high order word \n\
jmp *%edx # Return \n\
1: \n\
movl (%edx),%eax # Handle value \n\
@@ -148,12 +155,11 @@ dll_func_load: \n\
jne gotit # Yes \n\
jmp noload # Issue an error or return \n\
gotit: \n\
- popl %ecx # Pointer to 'return address' \n\
- movb $0xe9,-7(%ecx) # Turn preceding call to a jmp *%eax \n\
- movl %eax,%edx # Save \n\
- subl %ecx,%eax # Make it relative \n\
- addl $2,%eax # Tweak \n\
- movl %eax,-6(%ecx) # Move relative address after jump \n\
+ popl %edx # Pointer to 'return address' \n\
+ subl %edx,%eax # Make it relative \n\
+ addl $7,%eax # Tweak \n\
+ subl $12,%edx # Point to jmp \n\
+ movl %eax,1(%edx) # Move relative address after jump \n\
jmp *%edx # Jump to actual function \n\
\n\
.global dll_chain \n\
@@ -241,10 +247,8 @@ static long long
wsock_init ()
{
static LONG NO_COPY here = -1L;
- extern WSADATA wsadata;
struct func_info *func = (struct func_info *) __builtin_return_address (0);
struct dll_info *dll = func->dll;
- retchain ret;
__asm__ (" \n\
.section .ws2_32_info \n\
@@ -262,7 +266,7 @@ wsock_init ()
Sleep (0);
}
- if (!wsock_started && (wsock32_handle || ws2_32_handle))
+ if (!wsock_started && (winsock_active || winsock2_active))
{
/* Don't use autoload to load WSAStartup to eliminate recursion. */
int (*wsastartup) (int, WSADATA *);
@@ -293,6 +297,7 @@ wsock_init ()
movl $dll_chain1,4(%ebp) \n\
");
+ volatile retchain ret;
/* Set "arguments for dll_chain1. */
ret.low = (long) dll_func_load;
ret.high = (long) func;
@@ -317,10 +322,12 @@ LoadDLLfuncEx (DuplicateTokenEx, 24, advapi32, 1)
LoadDLLfunc (EqualSid, 8, advapi32)
LoadDLLfunc (GetAce, 12, advapi32)
LoadDLLfunc (GetFileSecurityA, 20, advapi32)
+LoadDLLfunc (GetKernelObjectSecurity, 20, advapi32)
LoadDLLfunc (GetLengthSid, 4, advapi32)
LoadDLLfunc (GetSecurityDescriptorDacl, 16, advapi32)
LoadDLLfunc (GetSecurityDescriptorGroup, 12, advapi32)
LoadDLLfunc (GetSecurityDescriptorOwner, 12, advapi32)
+LoadDLLfunc (GetSecurityInfo, 32, advapi32)
LoadDLLfunc (GetSidIdentifierAuthority, 4, advapi32)
LoadDLLfunc (GetSidSubAuthority, 8, advapi32)
LoadDLLfunc (GetSidSubAuthorityCount, 4, advapi32)
@@ -353,6 +360,7 @@ LoadDLLfunc (RegLoadKeyA, 12, advapi32)
LoadDLLfunc (RegEnumKeyExA, 32, advapi32)
LoadDLLfunc (RegEnumValueA, 32, advapi32)
LoadDLLfunc (RegOpenKeyExA, 20, advapi32)
+LoadDLLfunc (RegQueryInfoKeyA, 48, advapi32)
LoadDLLfunc (RegQueryValueExA, 24, advapi32)
LoadDLLfunc (RegSetValueExA, 24, advapi32)
LoadDLLfunc (RegisterEventSourceA, 8, advapi32)
@@ -366,21 +374,27 @@ LoadDLLfunc (SetSecurityDescriptorOwner, 12, advapi32)
LoadDLLfunc (SetTokenInformation, 16, advapi32)
LoadDLLfunc (NetApiBufferFree, 4, netapi32)
+LoadDLLfuncEx (NetGetDCName, 12, netapi32, 1)
LoadDLLfunc (NetLocalGroupEnum, 28, netapi32)
LoadDLLfunc (NetLocalGroupGetMembers, 32, netapi32)
-LoadDLLfunc (NetServerEnum, 36, netapi32)
LoadDLLfunc (NetUserGetGroups, 28, netapi32)
LoadDLLfunc (NetUserGetInfo, 16, netapi32)
LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32)
LoadDLLfuncEx (NtCreateToken, 52, ntdll, 1)
LoadDLLfuncEx (NtMapViewOfSection, 40, ntdll, 1)
+LoadDLLfuncEx (NtOpenFile, 24, ntdll, 1)
LoadDLLfuncEx (NtOpenSection, 12, ntdll, 1)
+LoadDLLfuncEx (NtQueryInformationFile, 20, ntdll, 1)
+LoadDLLfuncEx (NtQueryInformationProcess, 20, ntdll, 1)
+LoadDLLfuncEx2 (NtQueryObject, 20, ntdll, 1, 1)
LoadDLLfuncEx (NtQuerySystemInformation, 16, ntdll, 1)
+LoadDLLfuncEx (NtQueryVirtualMemory, 24, ntdll, 1)
LoadDLLfuncEx (NtUnmapViewOfSection, 8, ntdll, 1)
LoadDLLfuncEx (RtlInitUnicodeString, 8, ntdll, 1)
LoadDLLfuncEx (RtlNtStatusToDosError, 4, ntdll, 1)
-LoadDLLfuncEx (ZwQuerySystemInformation, 16, ntdll, 1)
+
+LoadDLLfuncEx (GetProcessMemoryInfo, 12, psapi, 1)
LoadDLLfuncEx (LsaDeregisterLogonProcess, 4, secur32, 1)
LoadDLLfuncEx (LsaFreeReturnBuffer, 4, secur32, 1)
@@ -418,11 +432,12 @@ LoadDLLfunc (SetClipboardData, 8, user32)
LoadDLLfunc (SetTimer, 16, user32)
LoadDLLfunc (SetUserObjectSecurity, 12, user32)
+LoadDLLfuncEx (load_wsock32, 0, wsock32, 1) // non-existent function forces wsock32 load
LoadDLLfunc (WSAAsyncSelect, 16, wsock32)
LoadDLLfunc (WSACleanup, 0, wsock32)
LoadDLLfunc (WSAGetLastError, 0, wsock32)
LoadDLLfunc (WSASetLastError, 4, wsock32)
-LoadDLLfunc (WSAStartup, 8, wsock32)
+// LoadDLLfunc (WSAStartup, 8, wsock32)
LoadDLLfunc (__WSAFDIsSet, 8, wsock32)
LoadDLLfunc (accept, 12, wsock32)
LoadDLLfunc (bind, 12, wsock32)
@@ -466,6 +481,8 @@ LoadDLLfuncEx (WSASendTo, 36, ws2_32, 1)
LoadDLLfuncEx (WSASetEvent, 4, ws2_32, 1)
LoadDLLfuncEx (WSASocketA, 24, ws2_32, 1)
LoadDLLfuncEx (WSAWaitForMultipleEvents, 20, ws2_32, 1)
+LoadDLLfuncEx (WSAEventSelect, 12, ws2_32, 1)
+LoadDLLfuncEx (WSAEnumNetworkEvents, 12, ws2_32, 1)
LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1)
LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1)
@@ -474,12 +491,14 @@ LoadDLLfunc (CoInitialize, 4, ole32)
LoadDLLfunc (CoUninitialize, 0, ole32)
LoadDLLfunc (CoCreateInstance, 20, ole32)
-LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1)
LoadDLLfuncEx (CancelIo, 4, kernel32, 1)
+LoadDLLfuncEx (CreateHardLinkA, 12, kernel32, 1)
+LoadDLLfuncEx (CreateToolhelp32Snapshot, 8, kernel32, 1)
+LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1)
+LoadDLLfuncEx2 (IsDebuggerPresent, 0, kernel32, 1, 1)
LoadDLLfuncEx (Process32First, 8, kernel32, 1)
LoadDLLfuncEx (Process32Next, 8, kernel32, 1)
-LoadDLLfuncEx (CreateToolhelp32Snapshot, 8, kernel32, 1)
-LoadDLLfuncEx (CreateHardLinkA, 12, kernel32, 1)
+LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1)
LoadDLLfunc (TryEnterCriticalSection, 4, kernel32)
LoadDLLfuncEx (waveOutGetNumDevs, 0, winmm, 1)
@@ -491,4 +510,8 @@ LoadDLLfuncEx (waveOutSetVolume, 8, winmm, 1)
LoadDLLfuncEx (waveOutUnprepareHeader, 12, winmm, 1)
LoadDLLfuncEx (waveOutPrepareHeader, 12, winmm, 1)
LoadDLLfuncEx (waveOutWrite, 12, winmm, 1)
+LoadDLLfuncEx (timeGetDevCaps, 8, winmm, 1)
+LoadDLLfuncEx (timeGetTime, 0, winmm, 1)
+LoadDLLfuncEx (timeBeginPeriod, 4, winmm, 1)
+LoadDLLfuncEx (timeEndPeriod, 4, winmm, 1)
}
diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h
index 983675877..1aca7247b 100644
--- a/winsup/cygwin/child_info.h
+++ b/winsup/cygwin/child_info.h
@@ -1,6 +1,6 @@
-/* childinfo.h: shared child info for cygwin
+/* child_info.h: shared child info for cygwin
- Copyright 2000 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -12,26 +12,36 @@ details. */
enum
{
- PROC_MAGIC = 0xaf12f000,
- PROC_FORK = PROC_MAGIC + 1,
- PROC_EXEC = PROC_MAGIC + 2,
- PROC_SPAWN = PROC_MAGIC + 3,
- PROC_FORK1 = PROC_MAGIC + 4, // Newer versions provide stack
- // location information
- PROC_SPAWN1 = PROC_MAGIC + 5
+ _PROC_EXEC,
+ _PROC_SPAWN,
+ _PROC_FORK,
+ _PROC_WHOOPS
};
-#define PROC_MAGIC_MASK 0xff00f000
-#define PROC_MAGIC_GENERIC 0xaf00f000
-#define PROC_MAGIC_VER_MASK 0x0ff0000
+#define OPROC_MAGIC_MASK 0xff00ff00
+#define OPROC_MAGIC_GENERIC 0xaf00f000
+
+#define PROC_MAGIC_GENERIC 0xaf00fa00
+
+#define PROC_EXEC (_PROC_EXEC)
+#define PROC_SPAWN (_PROC_SPAWN)
+#define PROC_FORK (_PROC_FORK)
#define EXEC_MAGIC_SIZE sizeof(child_info)
+
+#define CURR_CHILD_INFO_MAGIC 0xb3836013U
+
+/* NOTE: Do not make gratuitous changes to the names or organization of the
+ below class. The layout is checksummed to determine compatibility between
+ different cygwin versions. */
class child_info
{
public:
DWORD zero[4]; // must be zeroed
DWORD cb; // size of this record
- DWORD type; // type of record
+ DWORD intro; // improbable string
+ unsigned long magic; // magic number unique to child_info
+ unsigned short type; // type of record, exec, spawn, fork
int cygpid; // cygwin pid of child process
HANDLE subproc_ready; // used for synchronization with parent
HANDLE mount_h;
@@ -40,6 +50,7 @@ public:
init_cygheap *cygheap;
void *cygheap_max;
HANDLE cygheap_h;
+ unsigned fhandler_union_cb;
};
class child_info_fork: public child_info
@@ -60,7 +71,7 @@ class fhandler_base;
class cygheap_exec_info
{
public:
- uid_t uid;
+ __uid32_t uid;
char *old_title;
int argc;
char **argv;
@@ -98,4 +109,6 @@ public:
void __stdcall init_child_info (DWORD, child_info *, int, HANDLE);
-extern child_info_fork *child_proc_info;
+extern child_info *child_proc_info;
+extern child_info_spawn *spawn_info __attribute__ ((alias ("child_proc_info")));
+extern child_info_fork *fork_info __attribute__ ((alias ("child_proc_info")));
diff --git a/winsup/cygwin/configure b/winsup/cygwin/configure
index 11311edda..3f41211fb 100755
--- a/winsup/cygwin/configure
+++ b/winsup/cygwin/configure
@@ -1274,10 +1274,77 @@ else
fi
fi
+# Extract the first word of "${ac_tool_prefix}nm", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nm; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1281: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$NM"; then
+ ac_cv_prog_NM="$NM" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_NM="${ac_tool_prefix}nm"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+NM="$ac_cv_prog_NM"
+if test -n "$NM"; then
+ echo "$ac_t""$NM" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+if test -z "$ac_cv_prog_NM"; then
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "nm", so it can be a program name with args.
+set dummy nm; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1313: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$NM"; then
+ ac_cv_prog_NM="$NM" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_NM="nm"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_NM" && ac_cv_prog_NM="nm"
+fi
+fi
+NM="$ac_cv_prog_NM"
+if test -n "$NM"; then
+ echo "$ac_t""$NM" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+ NM="nm"
+fi
+fi
+
# Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
set dummy ${ac_tool_prefix}dlltool; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1281: checking for $ac_word" >&5
+echo "configure:1348: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1309,7 +1376,7 @@ if test -n "$ac_tool_prefix"; then
# Extract the first word of "dlltool", so it can be a program name with args.
set dummy dlltool; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1313: checking for $ac_word" >&5
+echo "configure:1380: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1344,7 +1411,7 @@ fi
# Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args.
set dummy ${ac_tool_prefix}windres; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1348: checking for $ac_word" >&5
+echo "configure:1415: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1376,7 +1443,7 @@ if test -n "$ac_tool_prefix"; then
# Extract the first word of "windres", so it can be a program name with args.
set dummy windres; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1380: checking for $ac_word" >&5
+echo "configure:1447: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1410,7 +1477,7 @@ fi
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1414: checking how to run the C preprocessor" >&5
+echo "configure:1481: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
@@ -1425,13 +1492,13 @@ else
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <<EOF
-#line 1429 "configure"
+#line 1496 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1435: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1502: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -1442,13 +1509,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF
-#line 1446 "configure"
+#line 1513 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1452: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1519: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -1459,13 +1526,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -nologo -E"
cat > conftest.$ac_ext <<EOF
-#line 1463 "configure"
+#line 1530 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1469: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1536: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -1492,19 +1559,19 @@ echo "$ac_t""$CPP" 1>&6
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless!
echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:1496: checking for working alloca.h" >&5
+echo "configure:1563: checking for working alloca.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1501 "configure"
+#line 1568 "configure"
#include "confdefs.h"
#include <alloca.h>
int main() {
char *p = alloca(2 * sizeof(int));
; return 0; }
EOF
-if { (eval echo configure:1508: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1575: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_header_alloca_h=yes
else
@@ -1525,12 +1592,12 @@ EOF
fi
echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:1529: checking for alloca" >&5
+echo "configure:1596: checking for alloca" >&5
if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1534 "configure"
+#line 1601 "configure"
#include "confdefs.h"
#ifdef __GNUC__
@@ -1558,7 +1625,7 @@ int main() {
char *p = (char *) alloca(1);
; return 0; }
EOF
-if { (eval echo configure:1562: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1629: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_func_alloca_works=yes
else
@@ -1590,12 +1657,12 @@ EOF
echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:1594: checking whether alloca needs Cray hooks" >&5
+echo "configure:1661: checking whether alloca needs Cray hooks" >&5
if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1599 "configure"
+#line 1666 "configure"
#include "confdefs.h"
#if defined(CRAY) && ! defined(CRAY2)
webecray
@@ -1620,12 +1687,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6
if test $ac_cv_os_cray = yes; then
for ac_func in _getb67 GETB67 getb67; do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1624: checking for $ac_func" >&5
+echo "configure:1691: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1629 "configure"
+#line 1696 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -1648,7 +1715,7 @@ $ac_func();
; return 0; }
EOF
-if { (eval echo configure:1652: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1719: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -1675,7 +1742,7 @@ done
fi
echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:1679: checking stack direction for C alloca" >&5
+echo "configure:1746: checking stack direction for C alloca" >&5
if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1683,7 +1750,7 @@ else
ac_cv_c_stack_direction=0
else
cat > conftest.$ac_ext <<EOF
-#line 1687 "configure"
+#line 1754 "configure"
#include "confdefs.h"
find_stack_direction ()
{
@@ -1702,7 +1769,7 @@ main ()
exit (find_stack_direction() < 0);
}
EOF
-if { (eval echo configure:1706: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1773: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
ac_cv_c_stack_direction=1
else
@@ -1724,7 +1791,7 @@ EOF
fi
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:1728: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:1795: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1761,7 +1828,7 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes
cross_compiling=$ac_cv_prog_cxx_cross
cat > conftest.$ac_ext <<EOF
-#line 1765 "configure"
+#line 1832 "configure"
#include "confdefs.h"
#include <string.h>
@@ -1774,7 +1841,7 @@ int main() {
; return 0; }
EOF
-if { (eval echo configure:1778: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1845: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
use_builtin_memset=yes
else
@@ -1899,7 +1966,7 @@ esac
echo $ac_n "checking if newlib is part of the build tree""... $ac_c" 1>&6
-echo "configure:1903: checking if newlib is part of the build tree" >&5
+echo "configure:1970: checking if newlib is part of the build tree" >&5
EXE_LDFLAGS=
if test -d ../newlib
@@ -1914,9 +1981,9 @@ fi
if test x"$EXE_LDFLAGS" = x
then
echo $ac_n "checking if installed newlib needed""... $ac_c" 1>&6
-echo "configure:1918: checking if installed newlib needed" >&5
+echo "configure:1985: checking if installed newlib needed" >&5
cat > conftest.$ac_ext <<EOF
-#line 1920 "configure"
+#line 1987 "configure"
#include "confdefs.h"
int main() {
@@ -1924,7 +1991,7 @@ int main() {
; return 0; }
EOF
-if { (eval echo configure:1928: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1995: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
echo "$ac_t""no" 1>&6
@@ -2115,6 +2182,7 @@ s%@AR@%$AR%g
s%@AS@%$AS%g
s%@RANLIB@%$RANLIB%g
s%@LD@%$LD%g
+s%@NM@%$NM%g
s%@DLLTOOL@%$DLLTOOL%g
s%@WINDRES@%$WINDRES%g
s%@CPP@%$CPP%g
diff --git a/winsup/cygwin/configure.in b/winsup/cygwin/configure.in
index 8a20f084b..3934992a7 100644
--- a/winsup/cygwin/configure.in
+++ b/winsup/cygwin/configure.in
@@ -91,6 +91,8 @@ AC_CHECK_TOOL(RANLIB, ranlib, ranlib)
dnl C_SUBST(RANLIB)
AC_CHECK_TOOL(LD, ld, ld)
dnl C_SUBST(LD)
+AC_CHECK_TOOL(NM, nm, nm)
+dnl C_SUBST(NM)
AC_CHECK_TOOL(DLLTOOL, dlltool, dlltool)
dnl C_SUBST(DLLTOOL)
AC_CHECK_TOOL(WINDRES, windres, windres)
diff --git a/winsup/cygwin/cygerrno.h b/winsup/cygwin/cygerrno.h
index dd40819b9..0c1513f25 100644
--- a/winsup/cygwin/cygerrno.h
+++ b/winsup/cygwin/cygerrno.h
@@ -15,7 +15,12 @@ int __stdcall geterrno_from_win_error (DWORD code, int deferrno) __attribute__ (
#define __seterrno() seterrno (__FILE__, __LINE__)
#define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val)
+#ifndef DEBUGGING
#define set_errno(val) (_impure_ptr->_errno = (val))
+#else
+int __stdcall __set_errno (const char *ln, int ln, int val) __attribute ((regparm(3)));
+#define set_errno(val) __set_errno (__PRETTY_FUNCTION__, __LINE__, (val))
+#endif
#define get_errno() (_impure_ptr->_errno)
extern "C" void __stdcall set_sig_errno (int e);
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index a0e00d3c7..937c3392c 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -1,6 +1,6 @@
/* cygheap.cc: Cygwin heap manager.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -17,10 +17,10 @@
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
+#include "cygerrno.h"
#include "cygheap.h"
#include "child_info.h"
#include "heap.h"
-#include "cygerrno.h"
#include "sync.h"
#include "shared_info.h"
@@ -45,7 +45,6 @@ struct cygheap_entry
extern "C" {
static void __stdcall _cfree (void *ptr) __attribute__((regparm(1)));
-extern void *_cygheap_start;
}
inline static void
@@ -57,11 +56,11 @@ init_cheap ()
MEMORY_BASIC_INFORMATION m;
if (!VirtualQuery ((LPCVOID) &_cygheap_start, &m, sizeof m))
system_printf ("couldn't get memory info, %E");
- small_printf ("AllocationBase %p, BaseAddress %p, RegionSize %p, State %p\n",
- m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
- api_fatal ("Couldn't reserve space for cygwin's heap, %E");
+ system_printf ("Couldn't reserve space for cygwin's heap, %E");
+ api_fatal ("AllocationBase %p, BaseAddress %p, RegionSize %p, State %p\n",
+ m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
}
- cygheap_max = cygheap + 1;
+ cygheap_max = cygheap;
}
static void dup_now (void *, child_info *, unsigned) __attribute__ ((regparm(3)));
@@ -82,7 +81,7 @@ cygheap_setup_for_child (child_info *ci, bool dup_later)
ci->cygheap_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none,
CFMAP_OPTIONS, 0, CYGHEAPSIZE, NULL);
newcygheap = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL);
- ProtectHandle1 (ci->cygheap_h, passed_cygheap_h);
+ ProtectHandle1INH (ci->cygheap_h, passed_cygheap_h);
if (!dup_later)
dup_now (newcygheap, ci, n);
cygheap_protect->release ();
@@ -93,12 +92,12 @@ cygheap_setup_for_child (child_info *ci, bool dup_later)
void __stdcall
cygheap_setup_for_child_cleanup (void *newcygheap, child_info *ci,
- bool dup_it_now)
+ bool dup_it_now)
{
if (dup_it_now)
{
/* NOTE: There is an assumption here that cygheap_max has not changed
- between the time that cygheap_setup_for_child was called and now.
+ between the time that cygheap_setup_for_child was called and now.
Make sure that this is a correct assumption. */
cygheap_protect->acquire ();
dup_now (newcygheap, ci, (char *) cygheap_max - (char *) cygheap);
@@ -110,31 +109,31 @@ cygheap_setup_for_child_cleanup (void *newcygheap, child_info *ci,
/* Called by fork or spawn to reallocate cygwin heap */
void __stdcall
-cygheap_fixup_in_child (child_info *ci, bool execed)
+cygheap_fixup_in_child (bool execed)
{
- cygheap = ci->cygheap;
- cygheap_max = ci->cygheap_max;
+ cygheap = child_proc_info->cygheap;
+ cygheap_max = child_proc_info->cygheap_max;
void *addr = !wincap.map_view_of_file_ex_sucks () ? cygheap : NULL;
void *newaddr;
- newaddr = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, addr);
+ newaddr = MapViewOfFileEx (child_proc_info->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, addr);
if (newaddr != cygheap)
{
if (!newaddr)
- newaddr = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL);
+ newaddr = MapViewOfFileEx (child_proc_info->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL);
DWORD n = (DWORD) cygheap_max - (DWORD) cygheap;
/* Reserve cygwin heap in same spot as parent */
if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS))
- {
- MEMORY_BASIC_INFORMATION m;
- memset (&m, 0, sizeof m);
- if (!VirtualQuery ((LPCVOID) cygheap, &m, sizeof m))
- system_printf ("couldn't get memory info, %E");
-
- small_printf ("m.AllocationBase %p, m.BaseAddress %p, m.RegionSize %p, m.State %p\n",
- m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
- api_fatal ("Couldn't reserve space for cygwin's heap (%p <%p>) in child, %E", cygheap, newaddr);
- }
+ {
+ MEMORY_BASIC_INFORMATION m;
+ memset (&m, 0, sizeof m);
+ if (!VirtualQuery ((LPCVOID) cygheap, &m, sizeof m))
+ system_printf ("couldn't get memory info, %E");
+
+ system_printf ("Couldn't reserve space for cygwin's heap (%p <%p>) in child, %E", cygheap, newaddr);
+ api_fatal ("m.AllocationBase %p, m.BaseAddress %p, m.RegionSize %p, m.State %p\n",
+ m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
+ }
/* Allocate same amount of memory as parent */
if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE))
@@ -144,9 +143,10 @@ cygheap_fixup_in_child (child_info *ci, bool execed)
UnmapViewOfFile (newaddr);
}
- ForceCloseHandle1 (ci->cygheap_h, passed_cygheap_h);
+ ForceCloseHandle1 (child_proc_info->cygheap_h, passed_cygheap_h);
cygheap_init ();
+ debug_fixup_after_fork_exec ();
if (execed)
{
@@ -171,34 +171,26 @@ cygheap_fixup_in_child (child_info *ci, bool execed)
static void *__stdcall
_csbrk (int sbs)
{
- void *lastheap;
- bool needalloc;
-
- if (cygheap)
- needalloc = 0;
- else
- {
- init_cheap ();
- needalloc = 1;
- }
-
- lastheap = cygheap_max;
+ void *prebrk = cygheap_max;
+ void *prebrka = pagetrunc (prebrk);
(char *) cygheap_max += sbs;
- void *heapalign = (void *) pagetrunc (lastheap);
-
- if (!needalloc)
- needalloc = sbs && ((heapalign == lastheap) || heapalign != pagetrunc (cygheap_max));
- if (needalloc && !VirtualAlloc (lastheap, (DWORD) sbs ?: 1, MEM_COMMIT, PAGE_READWRITE))
+ if (!sbs || (prebrk != prebrka && prebrka == pagetrunc (cygheap_max)))
+ /* nothing to do */;
+ else if (!VirtualAlloc (prebrk, (DWORD) sbs, MEM_COMMIT, PAGE_READWRITE))
api_fatal ("couldn't commit memory for cygwin heap, %E");
- return lastheap;
+ return prebrk;
}
extern "C" void __stdcall
cygheap_init ()
{
- cygheap_protect = new_muto (FALSE, "cygheap_protect");
- _csbrk (0);
+ new_muto (cygheap_protect);
+ if (!cygheap)
+ {
+ init_cheap ();
+ (void) _csbrk (sizeof (*cygheap));
+ }
if (!cygheap->fdtab)
cygheap->fdtab.init ();
}
@@ -322,12 +314,19 @@ crealloc (void *s, DWORD n)
extern "C" void __stdcall
cfree (void *s)
{
- MALLOC_CHECK;
assert (!inheap (s));
(void) _cfree (tocygheap (s));
MALLOC_CHECK;
}
+extern "C" void __stdcall
+cfree_and_set (char *&s, char *what)
+{
+ if (s && s != almost_null)
+ cfree (s);
+ s = what;
+}
+
extern "C" void *__stdcall
ccalloc (cygheap_types x, DWORD n, DWORD size)
{
@@ -378,13 +377,13 @@ init_cygheap::etc_changed ()
FILE_NOTIFY_CHANGE_LAST_WRITE);
if (etc_changed_h == INVALID_HANDLE_VALUE)
system_printf ("Can't open /etc for checking, %E", (char *) pwd,
- etc_changed_h);
+ etc_changed_h);
else if (!DuplicateHandle (hMainProc, etc_changed_h, hMainProc,
- &etc_changed_h, 0, TRUE,
+ &etc_changed_h, 0, TRUE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
{
system_printf ("Can't inherit /etc handle, %E", (char *) pwd,
- etc_changed_h);
+ etc_changed_h);
etc_changed_h = INVALID_HANDLE_VALUE;
}
}
@@ -430,7 +429,7 @@ cygheap_user::~cygheap_user ()
if (pname)
cfree (pname);
if (plogsrv)
- cfree (plogsrv);
+ cfree (plogsrv - 2);
if (pdomain)
cfree (pdomain);
if (psid)
@@ -441,41 +440,47 @@ cygheap_user::~cygheap_user ()
void
cygheap_user::set_name (const char *new_name)
{
- if (pname)
- cfree (pname);
- pname = cstrdup (new_name ? new_name : "");
-}
+ bool allocated = !!pname;
-void
-cygheap_user::set_logsrv (const char *new_logsrv)
-{
- if (plogsrv)
- cfree (plogsrv);
- plogsrv = (new_logsrv && *new_logsrv) ? cstrdup (new_logsrv) : NULL;
-}
+ if (allocated)
+ {
+ if (strcasematch (new_name, pname))
+ return;
+ cfree (pname);
+ }
-void
-cygheap_user::set_domain (const char *new_domain)
-{
- if (pdomain)
- cfree (pdomain);
- pdomain = (new_domain && *new_domain) ? cstrdup (new_domain) : NULL;
+ pname = cstrdup (new_name ? new_name : "");
+ if (!allocated)
+ return; /* Initializing. Don't bother with other stuff. */
+
+ cfree_and_set (homedrive);
+ cfree_and_set (homepath);
+ cfree_and_set (plogsrv);
+ cfree_and_set (pdomain);
+ cfree_and_set (pwinname);
}
BOOL
cygheap_user::set_sid (PSID new_sid)
{
- if (!new_sid)
+ if (new_sid)
{
+ if (!psid)
+ psid = cmalloc (HEAP_STR, MAX_SID_LEN);
if (psid)
- cfree (psid);
- psid = NULL;
- return TRUE;
+ return CopySid (MAX_SID_LEN, psid, new_sid);
}
- else
+ return FALSE;
+}
+
+BOOL
+cygheap_user::set_orig_sid ()
+{
+ if (psid)
{
- if (!psid)
- psid = cmalloc (HEAP_STR, MAX_SID_LEN);
- return CopySid (MAX_SID_LEN, psid, new_sid);
+ if (!orig_psid) orig_psid = cmalloc (HEAP_STR, MAX_SID_LEN);
+ if (orig_psid)
+ return CopySid (MAX_SID_LEN, orig_psid, psid);
}
+ return FALSE;
}
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 1972411c7..6f81eaa41 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -1,6 +1,6 @@
/* cygheap.h: Cygwin heap manager.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -48,7 +48,6 @@ struct cygheap_root_mount_info
/* CGF: FIXME This doesn't belong here */
-int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__ ((regparm (3)));
class cygheap_root
{
/* Root directory information.
@@ -86,6 +85,15 @@ public:
const char *native_path () const { return m->native_path; }
};
+enum homebodies
+{
+ CH_HOMEDRIVE,
+ CH_HOMEPATH,
+ CH_HOME
+};
+
+struct passwd;
+
class cygheap_user
{
/* Extendend user information.
@@ -94,41 +102,73 @@ class cygheap_user
char *pname; /* user's name */
char *plogsrv; /* Logon server, may be FQDN */
char *pdomain; /* Logon domain of the user */
+ char *homedrive; /* User's home drive */
+ char *homepath; /* User's home path */
+ char *pwinname; /* User's name as far as Windows knows it */
+ char *puserprof; /* User profile */
PSID psid; /* buffer for user's SID */
+ PSID orig_psid; /* Remains intact even after impersonation */
public:
- uid_t orig_uid; /* Remains intact even after impersonation */
- uid_t orig_gid; /* Ditto */
- uid_t real_uid; /* Remains intact on seteuid, replaced by setuid */
- gid_t real_gid; /* Ditto */
+ __uid32_t orig_uid; /* Remains intact even after impersonation */
+ __gid32_t orig_gid; /* Ditto */
+ __uid32_t real_uid; /* Remains intact on seteuid, replaced by setuid */
+ __gid32_t real_gid; /* Ditto */
+ user_groups groups; /* Primary and supp SIDs */
/* token is needed if set(e)uid should be called. It can be set by a call
to `set_impersonation_token()'. */
HANDLE token;
BOOL impersonated;
+ /* CGF 2002-06-27. I removed the initializaton from this constructor
+ since this class is always allocated statically. That means that everything
+ is zero anyway so there is no need to initialize it to zero. Since the
+ token initialization is always handled during process startup as well,
+ I've removed the constructor entirely. Please reinstate this f this
+ situation ever changes.
cygheap_user () : pname (NULL), plogsrv (NULL), pdomain (NULL),
- psid (NULL), token (INVALID_HANDLE_VALUE) {}
+ homedrive (NULL), homepath (NULL), psid (NULL),
+ token (INVALID_HANDLE_VALUE) {}
+ */
+
~cygheap_user ();
void set_name (const char *new_name);
const char *name () const { return pname; }
- void set_logsrv (const char *new_logsrv);
- const char *logsrv () const { return plogsrv; }
-
- void set_domain (const char *new_domain);
- const char *domain () const { return pdomain; }
+ const char *env_logsrv (const char *, size_t);
+ const char *env_homepath (const char *, size_t);
+ const char *env_homedrive (const char *, size_t);
+ const char *env_userprofile (const char *, size_t);
+ const char *env_domain (const char *, size_t);
+ const char *env_name (const char *, size_t);
+ const char *logsrv ()
+ {
+ const char *p = env_logsrv ("LOGONSERVER=", sizeof ("LOGONSERVER=") - 1);
+ return (p == almost_null) ? NULL : p;
+ }
+ const char *winname ()
+ {
+ const char *p = env_name ("USERNAME=", sizeof ("USERNAME=") - 1);
+ return (p == almost_null) ? NULL : p;
+ }
+ const char *domain ()
+ {
+ const char *p = env_domain ("USERDOMAIN=", sizeof ("USERDOMAIN=") - 1);
+ return (p == almost_null) ? NULL : p;
+ }
BOOL set_sid (PSID new_sid);
+ BOOL set_orig_sid ();
PSID sid () const { return psid; }
-
- void operator =(cygheap_user &user)
+ PSID orig_sid () const { return orig_psid; }
+ const char *ontherange (homebodies what, struct passwd * = NULL);
+ bool issetuid () const
{
- set_name (user.name ());
- set_logsrv (user.logsrv ());
- set_domain (user.domain ());
- set_sid (user.sid ());
+ return impersonated && token != INVALID_HANDLE_VALUE;
}
+ const char *cygheap_user::test_uid (char *&, const char *, size_t)
+ __attribute__ ((regparm (3)));
};
/* cwd cache stuff. */
@@ -140,7 +180,7 @@ struct cwdstuff
char *posix;
char *win32;
DWORD hash;
- muto *lock;
+ muto *cwd_lock;
char *get (char *buf, int need_posix = 1, int with_chroot = 0, unsigned ulen = MAX_PATH);
DWORD get_hash ();
void init ();
@@ -149,6 +189,15 @@ struct cwdstuff
void set (const char *win32_cwd, const char *posix_cwd = NULL);
};
+#ifdef DEBUGGING
+struct cygheap_debug
+{
+ handle_list starth;
+ handle_list *endh;
+ handle_list freeh[500];
+};
+#endif
+
struct init_cygheap
{
_cmalloc_entry *chain;
@@ -165,8 +214,12 @@ struct init_cygheap
HANDLE shared_h;
HANDLE console_h;
HANDLE etc_changed_h;
+ char *cygwin_regname;
cwdstuff cwd;
dtable fdtab;
+#ifdef DEBUGGING
+ cygheap_debug debug;
+#endif
bool etc_changed ();
};
@@ -176,10 +229,92 @@ struct init_cygheap
extern init_cygheap *cygheap;
extern void *cygheap_max;
+class cygheap_fdmanip
+{
+ protected:
+ int fd;
+ fhandler_base **fh;
+ bool locked;
+ public:
+ cygheap_fdmanip (): fh (NULL) {}
+ virtual ~cygheap_fdmanip ()
+ {
+ if (locked)
+ ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "cygheap_fdmanip");
+ }
+ void release ()
+ {
+ cygheap->fdtab.release (fd);
+ }
+ operator int &() {return fd;}
+ operator fhandler_base* &() {return *fh;}
+ void operator = (fhandler_base *fh) {*this->fh = fh;}
+ fhandler_base *operator -> () const {return *fh;}
+ bool isopen () const
+ {
+ if (*fh)
+ return true;
+ set_errno (EBADF);
+ return false;
+ }
+};
+
+class cygheap_fdnew : public cygheap_fdmanip
+{
+ public:
+ cygheap_fdnew (int seed_fd = -1, bool lockit = true)
+ {
+ if (lockit)
+ SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "cygheap_fdnew");
+ if (seed_fd < 0)
+ fd = cygheap->fdtab.find_unused_handle ();
+ else
+ fd = cygheap->fdtab.find_unused_handle (seed_fd + 1);
+ if (fd >= 0)
+ {
+ locked = lockit;
+ fh = cygheap->fdtab + fd;
+ }
+ else
+ {
+ set_errno (EMFILE);
+ if (lockit)
+ ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "cygheap_fdnew");
+ locked = false;
+ }
+ }
+ void operator = (fhandler_base *fh) {*this->fh = fh;}
+};
+
+class cygheap_fdget : public cygheap_fdmanip
+{
+ public:
+ cygheap_fdget (int fd, bool lockit = false, bool do_set_errno = true)
+ {
+ if (lockit)
+ SetResourceLock (LOCK_FD_LIST, READ_LOCK, "cygheap_fdget");
+ if (fd >= 0 && fd < (int) cygheap->fdtab.size
+ && *(fh = cygheap->fdtab + fd) != NULL)
+ {
+ this->fd = fd;
+ locked = lockit;
+ }
+ else
+ {
+ this->fd = -1;
+ if (do_set_errno)
+ set_errno (EBADF);
+ if (lockit)
+ ReleaseResourceLock (LOCK_FD_LIST, READ_LOCK, "cygheap_fdget");
+ locked = false;
+ }
+ }
+};
+
class child_info;
void *__stdcall cygheap_setup_for_child (child_info *ci, bool dup_later) __attribute__ ((regparm(2)));
void __stdcall cygheap_setup_for_child_cleanup (void *, child_info *, bool) __attribute__ ((regparm(3)));
-void __stdcall cygheap_fixup_in_child (child_info *, bool);
+void __stdcall cygheap_fixup_in_child (bool);
extern "C" {
void __stdcall cfree (void *) __attribute__ ((regparm(1)));
void *__stdcall cmalloc (cygheap_types, DWORD) __attribute__ ((regparm(2)));
@@ -187,5 +322,7 @@ void *__stdcall crealloc (void *, DWORD) __attribute__ ((regparm(2)));
void *__stdcall ccalloc (cygheap_types, DWORD, DWORD) __attribute__ ((regparm(3)));
char *__stdcall cstrdup (const char *) __attribute__ ((regparm(1)));
char *__stdcall cstrdup1 (const char *) __attribute__ ((regparm(1)));
+void __stdcall cfree_and_set (char *&, char * = NULL) __attribute__ ((regparm(2)));
void __stdcall cygheap_init ();
+extern DWORD _cygheap_start;
}
diff --git a/winsup/cygwin/cygmagic b/winsup/cygwin/cygmagic
index 5589b26f6..a8ccc8c76 100755
--- a/winsup/cygwin/cygmagic
+++ b/winsup/cygwin/cygmagic
@@ -1,4 +1,14 @@
#!/bin/sh
+# cygmagic - Generate "magic numbers" from a structure.
+#
+# Copyright 2001, 2002 Red Hat, Inc.
+#
+# This file is part of Cygwin.
+#
+# This software is a copyrighted work licensed under the terms of the
+# Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+# details.
+
file_magic=$1; shift
gcc=$1; shift
file=$1; shift
@@ -7,13 +17,17 @@ cat <<EOF > $file_magic
/* autogenerated - do not edit */
#include "$file"
EOF
+sumit() {
+ cksum $*
+}
+
while [ -n "$1" ]; do
define=$1; shift
struct=$1; shift
- sum=`$gcc -E $file | sed -n "/^$struct/,/^};/p" | sed -e 's/[ ]//g' -e '/^$/d' | sum | awk '{printf "0x%x", $1}'`
+ sum=`$gcc -E $file | sed -n "/^$struct/,/^};/p" | sed -e 's/[ ]//g' -e '/^$/d' | sumit | awk '{printf "0x%xU", $1}'`
echo "#define $define $sum"
curr=`sed -n "s/^#[ ]*define CURR_$define[ ][ ]*\([^ ][^ ]*\)/\1/p" $file`
- [ "$curr" == "$sum" ] || echo "*** WARNING WARNING WARNING WARNING WARNING ***
+ [ "$curr" != "$sum" ] && echo "*** WARNING WARNING WARNING WARNING WARNING ***
*** $file: magic number for $define changed old $curr != new $sum
*** WARNING WARNING WARNING WARNING WARNING ***" 1>&2
done >> $file_magic
diff --git a/winsup/cygwin/cygmalloc.h b/winsup/cygwin/cygmalloc.h
new file mode 100644
index 000000000..2c1bbde42
--- /dev/null
+++ b/winsup/cygwin/cygmalloc.h
@@ -0,0 +1,29 @@
+/* cygmalloc.h: cygwin DLL malloc stuff
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+extern "C" void dlfree (void *p) __attribute__ ((regparm (1)));
+extern "C" void *dlmalloc (unsigned size) __attribute__ ((regparm (1)));
+extern "C" void *dlrealloc (void *p, unsigned size) __attribute__ ((regparm (2)));
+extern "C" void *dlcalloc (size_t nmemb, size_t size) __attribute__ ((regparm (2)));
+extern "C" void *dlmemalign (size_t alignment, size_t bytes) __attribute__ ((regparm (2)));
+extern "C" void *dlvalloc (size_t bytes) __attribute__ ((regparm (1)));
+extern "C" size_t dlmalloc_usable_size (void *p) __attribute__ ((regparm (1)));
+extern "C" int dlmalloc_trim (size_t) __attribute__ ((regparm (1)));
+extern "C" int dlmallopt (int p, int v) __attribute__ ((regparm (2)));
+extern "C" void dlmalloc_stats ();
+
+#ifndef __INSIDE_CYGWIN__
+# define USE_DL_PREFIX 1
+# define MORECORE_CANNOT_TRIM 1
+#else
+# define __malloc_lock() mallock->acquire ()
+# define __malloc_unlock() mallock->release ()
+extern muto *mallock;
+#endif
diff --git a/winsup/cygwin/cygrun.c b/winsup/cygwin/cygrun.c
index 6380bf818..94b0c399f 100644
--- a/winsup/cygwin/cygrun.c
+++ b/winsup/cygwin/cygrun.c
@@ -1,6 +1,6 @@
/* cygrun.c: testsuite support program
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -18,34 +18,47 @@ details. */
#include <stdlib.h>
int
-main(int argc, char **argv)
+main (int argc, char **argv)
{
STARTUPINFO sa;
PROCESS_INFORMATION pi;
DWORD ec = 1;
+ char *p;
if (argc < 2)
{
- fprintf(stderr, "Usage: cygrun [program]\n");
+ fprintf (stderr, "Usage: cygrun [program]\n");
exit (0);
}
- putenv("CYGWIN_TESTING=1");
- SetEnvironmentVariable("CYGWIN_TESTING", "1");
+ SetEnvironmentVariable ("CYGWIN_TESTING", "1");
+ if ((p = getenv ("CYGWIN")) == NULL || (strstr (p, "ntsec") == NULL))
+ {
+ char buf[4096];
+ if (!p)
+ p[0] = '\0';
+ else
+ {
+ strcat (buf, p);
+ strcat (buf, " ");
+ }
+ strcat(buf, "ntsec");
+ SetEnvironmentVariable ("CYGWIN", buf);
+ }
- memset(&sa, 0, sizeof(sa));
- memset(&pi, 0, sizeof(pi));
- if (!CreateProcess(0, argv[1], 0, 0, 1, 0, 0, 0, &sa, &pi))
+ memset (&sa, 0, sizeof (sa));
+ memset (&pi, 0, sizeof (pi));
+ if (!CreateProcess (0, argv[1], 0, 0, 1, 0, 0, 0, &sa, &pi))
{
- fprintf(stderr, "CreateProcess %s failed\n", argv[1]);
- exit(1);
+ fprintf (stderr, "CreateProcess %s failed\n", argv[1]);
+ exit (1);
}
- WaitForSingleObject(pi.hProcess, INFINITE);
+ WaitForSingleObject (pi.hProcess, INFINITE);
- GetExitCodeProcess(pi.hProcess, &ec);
+ GetExitCodeProcess (pi.hProcess, &ec);
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
+ CloseHandle (pi.hProcess);
+ CloseHandle (pi.hThread);
return ec;
}
diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc
index 24a90dc20..0c0740379 100755
--- a/winsup/cygwin/cygserver.cc
+++ b/winsup/cygwin/cygserver.cc
@@ -1,72 +1,154 @@
/* cygserver.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Egor Duda <deo@logos-m.ru>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+#include "woutsup.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <signal.h>
-#include "wincap.h"
-#include "cygwin_version.h"
-#include "getopt.h"
+#include "cygerrno.h"
+#include "cygwin_version.h"
-#include "cygwin/cygserver_transport.h"
-#include "cygwin/cygserver_transport_pipes.h"
-#include "cygwin/cygserver_transport_sockets.h"
-#include "threaded_queue.h"
-#include "cygwin/cygserver_process.h"
#include "cygwin/cygserver.h"
-#include "cygserver_shm.h"
+#include "cygwin/cygserver_process.h"
+#include "cygwin/cygserver_transport.h"
-/* for quieter operation, set to 0 */
-#define DEBUG 0
-#define debug_printf if (DEBUG) printf
+// Version string.
+static const char version[] = "$Revision$";
-GENERIC_MAPPING access_mapping;
-class transport_layer_base *transport;
+/*
+ * Support function for the XXX_printf () macros in "woutsup.h".
+ * Copied verbatim from "strace.cc".
+ */
+static int
+getfunc (char *in_dst, const char *func)
+{
+ const char *p;
+ const char *pe;
+ char *dst = in_dst;
+ for (p = func; (pe = strchr (p, '(')); p = pe + 1)
+ if (isalnum ((int)pe[-1]) || pe[-1] == '_')
+ break;
+ else if (isspace ((int)pe[-1]))
+ {
+ pe--;
+ break;
+ }
+ if (!pe)
+ pe = strchr (func, '\0');
+ for (p = pe; p > func; p--)
+ if (p != pe && *p == ' ')
+ {
+ p++;
+ break;
+ }
+ if (*p == '*')
+ p++;
+ while (p < pe)
+ *dst++ = *p++;
+
+ *dst++ = ':';
+ *dst++ = ' ';
+ *dst = '\0';
+
+ return dst - in_dst;
+}
+
+/*
+ * Support function for the XXX_printf () macros in "woutsup.h".
+ */
+extern "C" void
+__cygserver__printf (const char *const function, const char *const fmt, ...)
+{
+ const DWORD lasterror = GetLastError ();
+ const int lasterrno = errno;
+
+ va_list ap;
+
+ char *const buf = (char *) alloca (BUFSIZ);
+
+ assert (buf);
+
+ int len = 0;
+
+ if (function)
+ len += getfunc (buf, function);
+
+ va_start (ap, fmt);
+ len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap);
+ va_end (ap);
-DWORD request_count = 0;
+ len += snprintf (buf + len, BUFSIZ - len, "\n");
-BOOL
+ const int actual = (len > BUFSIZ ? BUFSIZ : len);
+
+ write (2, buf, actual);
+
+ errno = lasterrno;
+ SetLastError (lasterror);
+
+ return;
+}
+
+#ifdef DEBUGGING
+
+int __stdcall
+__set_errno (const char *func, int ln, int val)
+{
+ debug_printf ("%s:%d val %d", func, ln, val);
+ return _impure_ptr->_errno = val;
+}
+
+#endif /* DEBUGGING */
+
+GENERIC_MAPPING access_mapping;
+
+static BOOL
setup_privileges ()
{
BOOL rc, ret_val;
HANDLE hToken = NULL;
TOKEN_PRIVILEGES sPrivileges;
- rc = OpenProcessToken ( GetCurrentProcess() , TOKEN_ALL_ACCESS , &hToken ) ;
- if ( !rc )
+ rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ;
+ if (!rc)
{
- printf ( "error opening process token (%lu)\n", GetLastError () );
+ system_printf ("error opening process token (%lu)", GetLastError ());
ret_val = FALSE;
goto out;
}
- rc = LookupPrivilegeValue ( NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid );
- if ( !rc )
+ rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid);
+ if (!rc)
{
- printf ( "error getting prigilege luid (%lu)\n", GetLastError () );
+ system_printf ("error getting privilege luid (%lu)", GetLastError ());
ret_val = FALSE;
goto out;
}
sPrivileges.PrivilegeCount = 1 ;
sPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ;
- rc = AdjustTokenPrivileges ( hToken, FALSE, &sPrivileges, 0, NULL, NULL ) ;
- if ( !rc )
+ rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ;
+ if (!rc)
{
- printf ( "error adjusting prigilege level. (%lu)\n", GetLastError () );
+ system_printf ("error adjusting privilege level. (%lu)",
+ GetLastError ());
ret_val = FALSE;
goto out;
}
@@ -79,194 +161,232 @@ setup_privileges ()
ret_val = TRUE;
out:
- CloseHandle ( hToken );
+ CloseHandle (hToken);
return ret_val;
}
int
check_and_dup_handle (HANDLE from_process, HANDLE to_process,
HANDLE from_process_token,
- DWORD access,
- HANDLE from_handle,
- HANDLE* to_handle_ptr, BOOL bInheritHandle)
+ DWORD access,
+ HANDLE from_handle,
+ HANDLE *to_handle_ptr, BOOL bInheritHandle = FALSE)
{
HANDLE local_handle = NULL;
int ret_val = EACCES;
- char sd_buf [1024];
- PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) &sd_buf;
- DWORD bytes_needed;
- PRIVILEGE_SET ps;
- DWORD ps_len = sizeof (ps);
- BOOL status;
if (from_process != GetCurrentProcess ())
-{
-
- if (!DuplicateHandle (from_process, from_handle,
- GetCurrentProcess (), &local_handle,
- 0, bInheritHandle,
- DUPLICATE_SAME_ACCESS))
{
- printf ( "error getting handle(%u) to server (%lu)\n", (unsigned int)from_handle, GetLastError ());
- goto out;
- }
-} else
- local_handle = from_handle;
+ if (!DuplicateHandle (from_process, from_handle,
+ GetCurrentProcess (), &local_handle,
+ 0, bInheritHandle,
+ DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("error getting handle(%u) to server (%lu)",
+ (unsigned int)from_handle, GetLastError ());
+ goto out;
+ }
+ } else
+ local_handle = from_handle;
- if (!GetKernelObjectSecurity (local_handle,
- OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
- sd, sizeof (sd_buf), &bytes_needed))
+ if (!wincap.has_security ())
+ assert (!from_process_token);
+ else
{
- printf ( "error getting handle SD (%lu)\n", GetLastError ());
- goto out;
- }
+ char sd_buf [1024];
+ PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) &sd_buf;
+ DWORD bytes_needed;
+ PRIVILEGE_SET ps;
+ DWORD ps_len = sizeof (ps);
+ BOOL status;
+
+ if (!GetKernelObjectSecurity (local_handle,
+ (OWNER_SECURITY_INFORMATION
+ | GROUP_SECURITY_INFORMATION
+ | DACL_SECURITY_INFORMATION),
+ sd, sizeof (sd_buf), &bytes_needed))
+ {
+ system_printf ("error getting handle SD (%lu)", GetLastError ());
+ goto out;
+ }
- MapGenericMask (&access, &access_mapping);
+ MapGenericMask (&access, &access_mapping);
- if (!AccessCheck (sd, from_process_token, access, &access_mapping,
- &ps, &ps_len, &access, &status))
- {
- printf ( "error checking access rights (%lu)\n", GetLastError ());
- goto out;
- }
+ if (!AccessCheck (sd, from_process_token, access, &access_mapping,
+ &ps, &ps_len, &access, &status))
+ {
+ system_printf ("error checking access rights (%lu)",
+ GetLastError ());
+ goto out;
+ }
- if (!status)
- {
- printf ( "access to object denied\n");
- goto out;
+ if (!status)
+ {
+ system_printf ("access to object denied");
+ goto out;
+ }
}
if (!DuplicateHandle (from_process, from_handle,
- to_process, to_handle_ptr,
- access, bInheritHandle, 0))
+ to_process, to_handle_ptr,
+ access, bInheritHandle, 0))
{
- printf ( "error getting handle to client (%lu)\n", GetLastError ());
+ system_printf ("error getting handle to client (%lu)", GetLastError ());
goto out;
}
+ // verbose: debug_printf ("Duplicated %p to %p", from_handle, *to_handle_ptr);
+
ret_val = 0;
-
-out:
+
+ out:
if (local_handle && from_process != GetCurrentProcess ())
CloseHandle (local_handle);
return (ret_val);
}
-int
-check_and_dup_handle (HANDLE from_process, HANDLE to_process,
- HANDLE from_process_token,
- DWORD access,
- HANDLE from_handle,
- HANDLE* to_handle_ptr)
-{
- return check_and_dup_handle(from_process,to_process,from_process_token,access,from_handle,to_handle_ptr,FALSE);
-}
+/*
+ * client_request_attach_tty::serve ()
+ */
void
-client_request::serve (transport_layer_base *conn, class process_cache *cache)
+client_request_attach_tty::serve (transport_layer_base *const conn,
+ process_cache *)
{
- printf ("*****************************************\n"
- "A call to the base client_request class has occured\n"
- "This indicates a mismatch in a virtual function definition somewhere\n");
- exit (1);
-}
+ assert (conn);
-void
-client_request_attach_tty::serve(transport_layer_base *conn, class process_cache *cache)
-{
- HANDLE from_process_handle = NULL;
- HANDLE to_process_handle = NULL;
- HANDLE token_handle = NULL;
- DWORD rc;
+ assert (!error_code ());
- if (header.cb != sizeof (req))
+ if (!wincap.has_security ())
{
- header.error_code = EINVAL;
+ syscall_printf ("operation only supported on systems with security");
+ error_code (EINVAL);
+ msglen (0);
return;
}
-#if DEBUG
- printf ("%ld:(%p,%p) -> %ld\n", req.master_pid,
- req.from_master, req.to_master,
- req.pid);
-#endif
-
- from_process_handle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
- to_process_handle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
- if (!from_process_handle || !to_process_handle)
+ if (msglen () != sizeof (req))
{
- printf ("error opening process (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- goto out;
+ syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
+ sizeof (req), msglen ());
+ error_code (EINVAL);
+ msglen (0);
+ return;
}
- transport->impersonate_client ();
-
- rc = OpenThreadToken (GetCurrentThread (),
- TOKEN_QUERY,
- TRUE,
- &token_handle);
+ msglen (0); // Until we fill in some fields.
- transport->revert_to_self ();
+ // verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld",
+ // req.master_pid, req.from_master, req.to_master,
+ // req.pid);
- if (!rc)
+ // verbose: debug_printf ("opening process %ld", req.master_pid);
+
+ const HANDLE from_process_handle =
+ OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
+
+ if (!from_process_handle)
{
- printf ("error opening thread token (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- goto out;
+ system_printf ("error opening `from' process, error = %lu",
+ GetLastError ());
+ error_code (EACCES);
+ return;
}
- if (check_and_dup_handle (from_process_handle, to_process_handle,
- token_handle,
- GENERIC_READ,
- req.from_master,
- &req.from_master) != 0)
+ // verbose: debug_printf ("opening process %ld", req.pid);
+
+ const HANDLE to_process_handle =
+ OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
+
+ if (!to_process_handle)
{
- printf ("error duplicating from_master handle (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- goto out;
+ system_printf ("error opening `to' process, error = %lu",
+ GetLastError ());
+ CloseHandle (from_process_handle);
+ error_code (EACCES);
+ return;
}
- if (req.to_master)
+ // verbose: debug_printf ("Impersonating client");
+ conn->impersonate_client ();
+
+ HANDLE token_handle = NULL;
+
+ // verbose: debug_printf ("about to open thread token");
+ const DWORD rc = OpenThreadToken (GetCurrentThread (),
+ TOKEN_QUERY,
+ TRUE,
+ &token_handle);
+
+ // verbose: debug_printf ("opened thread token, rc=%lu", rc);
+ conn->revert_to_self ();
+
+ if (!rc)
{
- if (check_and_dup_handle (from_process_handle, to_process_handle,
- token_handle,
- GENERIC_WRITE,
- req.to_master,
- &req.to_master) != 0)
- {
- printf ("error duplicating to_master handle (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- goto out;
- }
+ system_printf ("error opening thread token, error = %lu",
+ GetLastError ());
+ CloseHandle (from_process_handle);
+ CloseHandle (to_process_handle);
+ error_code (EACCES);
+ return;
}
-#if DEBUG
- printf ("%ld -> %ld(%p,%p)\n", req.master_pid, req.pid,
- req.from_master, req.to_master);
-#endif
+ // From this point on, a reply body is returned to the client.
- header.error_code = 0;
+ const HANDLE from_master = req.from_master;
+ const HANDLE to_master = req.to_master;
-out:
- if (from_process_handle)
- CloseHandle (from_process_handle);
- if (to_process_handle)
- CloseHandle (to_process_handle);
- if (token_handle)
- CloseHandle (token_handle);
+ req.from_master = NULL;
+ req.to_master = NULL;
+
+ msglen (sizeof (req));
+
+ if (from_master)
+ if (check_and_dup_handle (from_process_handle, to_process_handle,
+ token_handle,
+ GENERIC_READ,
+ from_master,
+ &req.from_master, TRUE) != 0)
+ {
+ system_printf ("error duplicating from_master handle, error = %lu",
+ GetLastError ());
+ error_code (EACCES);
+ }
+
+ if (to_master)
+ if (check_and_dup_handle (from_process_handle, to_process_handle,
+ token_handle,
+ GENERIC_WRITE,
+ to_master,
+ &req.to_master, TRUE) != 0)
+ {
+ system_printf ("error duplicating to_master handle, error = %lu",
+ GetLastError ());
+ error_code (EACCES);
+ }
+
+ CloseHandle (from_process_handle);
+ CloseHandle (to_process_handle);
+ CloseHandle (token_handle);
+
+ debug_printf ("%lu(%lu, %lu) -> %lu(%lu,%lu)",
+ req.master_pid, from_master, to_master,
+ req.pid, req.from_master, req.to_master);
+
+ return;
}
void
-client_request_get_version::serve(transport_layer_base *conn, class process_cache *cache)
+client_request_get_version::serve (transport_layer_base *, process_cache *)
{
- if (header.cb != sizeof (version))
- {
- header.error_code = EINVAL;
- return;
- }
- header.error_code = 0;
+ assert (!error_code ());
+
+ if (msglen ())
+ syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
+
+ msglen (sizeof (version));
+
version.major = CYGWIN_SERVER_VERSION_MAJOR;
version.api = CYGWIN_SERVER_VERSION_API;
version.minor = CYGWIN_SERVER_VERSION_MINOR;
@@ -275,280 +395,380 @@ client_request_get_version::serve(transport_layer_base *conn, class process_cach
class server_request : public queue_request
{
- public:
- server_request (transport_layer_base *newconn, class process_cache *newcache);
- virtual void process ();
- private:
- char request_buffer [MAX_REQUEST_SIZE];
- transport_layer_base *conn;
- class process_cache *cache;
-};
+public:
+ server_request (transport_layer_base *const conn, process_cache *const cache)
+ : _conn (conn), _cache (cache)
+ {}
-class server_process_param : public queue_process_param
-{
- public:
- transport_layer_base *transport;
- server_process_param () : queue_process_param (false) {};
-};
+ virtual ~server_request ()
+ {
+ safe_delete (_conn);
+ }
-class server_request_queue : public threaded_queue
-{
- public:
- class process_cache *cache;
- void process_requests (transport_layer_base *transport);
- virtual void add (transport_layer_base *conn);
+ virtual void process ()
+ {
+ client_request::handle_request (_conn, _cache);
+ }
+
+private:
+ transport_layer_base *const _conn;
+ process_cache *const _cache;
};
-class server_request_queue request_queue;
-static DWORD WINAPI
-request_loop (LPVOID LpParam)
+class server_submission_loop : public queue_submission_loop
{
- class server_process_param *params = (server_process_param *) LpParam;
- class server_request_queue *queue = (server_request_queue *) params->queue;
- class transport_layer_base * transport = params->transport;
- while (queue->active)
+public:
+ server_submission_loop (threaded_queue *const queue,
+ transport_layer_base *const transport,
+ process_cache *const cache)
+ : queue_submission_loop (queue, false),
+ _transport (transport),
+ _cache (cache)
{
- transport_layer_base * new_conn = transport->accept ();
- /* FIXME: this is a little ugly. What we really want is to wait on two objects:
- * one for the pipe/socket, and one for being told to shutdown. Otherwise
- * this will stay a problem (we won't actually shutdown until the request
- * _AFTER_ the shutdown request. And sending ourselves a request is ugly
- */
- if (new_conn && queue->active)
- queue->add (new_conn);
+ assert (_transport);
+ assert (_cache);
}
- return 0;
-}
-/* TODO: check we are not being asked to service a already serviced transport */
+private:
+ transport_layer_base *const _transport;
+ process_cache *const _cache;
+
+ virtual void request_loop ();
+};
+
+/* FIXME: this is a little ugly. What we really want is to wait on
+ * two objects: one for the pipe/socket, and one for being told to
+ * shutdown. Otherwise this will stay a problem (we won't actually
+ * shutdown until the request _AFTER_ the shutdown request. And
+ * sending ourselves a request is ugly
+ */
void
-server_request_queue::process_requests (transport_layer_base *transport)
+server_submission_loop::request_loop ()
+{
+ /* I'd like the accepting thread's priority to be above any "normal"
+ * thread in the system to avoid overflowing the listen queue (for
+ * sockets; similar issues exist for named pipes); but, for example,
+ * a normal priority thread in a foregrounded process is boosted to
+ * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current
+ * thread's priority to a level one above that. This fails on
+ * win9x/ME so assume any failure in that call is due to that and
+ * simply call again at one priority level lower.
+ */
+ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1))
+ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST))
+ debug_printf ("failed to raise accept thread priority, error = %lu",
+ GetLastError ());
+
+ while (_running)
+ {
+ bool recoverable = false;
+ transport_layer_base *const conn = _transport->accept (&recoverable);
+ if (!conn && !recoverable)
+ {
+ system_printf ("fatal error on IPC transport: closing down");
+ return;
+ }
+ // EINTR probably implies a shutdown request; so back off for a
+ // moment to let the main thread take control, otherwise the
+ // server spins here receiving EINTR repeatedly since the signal
+ // handler in the main thread doesn't get a chance to be called.
+ if (!conn && errno == EINTR)
+ {
+ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
+ debug_printf ("failed to reset thread priority, error = %lu",
+ GetLastError ());
+
+ Sleep (0);
+ if (!SetThreadPriority (GetCurrentThread (),
+ THREAD_PRIORITY_HIGHEST + 1))
+ if (!SetThreadPriority (GetCurrentThread (),
+ THREAD_PRIORITY_HIGHEST))
+ debug_printf ("failed to raise thread priority, error = %lu",
+ GetLastError ());
+ }
+ if (conn)
+ _queue->add (safe_new (server_request, conn, _cache));
+ }
+}
+
+client_request_shutdown::client_request_shutdown ()
+ : client_request (CYGSERVER_REQUEST_SHUTDOWN)
{
- class server_process_param *params = new server_process_param;
- params->transport = transport;
- threaded_queue::process_requests (params, request_loop);
+ // verbose: syscall_printf ("created");
}
void
-client_request_shutdown::serve (transport_layer_base *conn, class process_cache *cache)
+client_request_shutdown::serve (transport_layer_base *, process_cache *)
{
+ assert (!error_code ());
+
+ if (msglen ())
+ syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
+
/* FIXME: link upwards, and then this becomes a trivial method call to
* only shutdown _this queue_
*/
- /* tell the main thread to shutdown */
- request_queue.active=false;
+
+ kill (getpid (), SIGINT);
+
+ msglen (0);
}
-server_request::server_request (transport_layer_base *newconn, class process_cache *newcache)
+static sig_atomic_t shutdown_server = false;
+
+static void
+handle_signal (const int signum)
{
- conn = newconn;
- cache = newcache;
+ /* any signal makes us die :} */
+
+ shutdown_server = true;
}
-void
-server_request::process ()
+/*
+ * print_usage ()
+ */
+
+static void
+print_usage (const char *const pgm)
{
- ssize_t bytes_read, bytes_written;
- struct request_header* req_ptr = (struct request_header*) &request_buffer;
- client_request *req = NULL;
- debug_printf ("about to read\n");
+ printf ("Usage: %s [OPTIONS]\n", pgm);
+ printf (" -c, --cleanup-threads number of cleanup threads to use\n");
+ printf (" -h, --help output usage information and exit\n");
+ printf (" -r, --request-threads number of request threads to use\n");
+ printf (" -s, --shutdown shutdown the daemon\n");
+ printf (" -v, --version output version information and exit\n");
+}
- bytes_read = conn->read (request_buffer, sizeof (struct request_header));
- if (bytes_read != sizeof (struct request_header))
- {
- printf ("error reading from connection (%lu)\n", GetLastError ());
- goto out;
- }
- debug_printf ("got header (%ld)\n", bytes_read);
+/*
+ * print_version ()
+ */
- switch (req_ptr->req_id)
- {
- case CYGSERVER_REQUEST_GET_VERSION:
- req = new client_request_get_version (); break;
- case CYGSERVER_REQUEST_ATTACH_TTY:
- req = new client_request_attach_tty (); break;
- case CYGSERVER_REQUEST_SHUTDOWN:
- req = new client_request_shutdown (); break;
- case CYGSERVER_REQUEST_SHM_GET:
- req = new client_request_shm (); break;
- default:
- req = new client_request (CYGSERVER_REQUEST_INVALID, 0);
- req->header.error_code = ENOSYS;
- debug_printf ("Bad client request - returning ENOSYS\n");
- }
+static void
+print_version (const char *const pgm)
+{
+ char *vn = NULL;
- if (req->header.cb != req_ptr->cb)
- {
- debug_printf ("Mismatch in request buffer sizes\n");
- goto out;
- }
+ const char *const colon = strchr (version, ':');
- if (req->header.cb)
+ if (!colon)
{
-
- bytes_read = conn->read (req->buffer, req->header.cb);
- if (bytes_read != req->header.cb)
- {
- debug_printf ("error reading from connection (%lu)\n", GetLastError ());
- goto out;
- }
- debug_printf ("got body (%ld)\n",bytes_read);
+ vn = strdup ("?");
}
+ else
+ {
+ vn = strdup (colon + 2); // Skip ": "
- /* this is not allowed to fail. We must return ENOSYS at a minimum to the client */
- req->serve (conn, cache);
+ char *const spc = strchr (vn, ' ');
- if ((bytes_written = conn->write ((char *)&req->header, sizeof (req->header)))
- != sizeof(req->header) || (req->header.cb &&
- (bytes_written = conn->write (req->buffer, req->header.cb)) != req->header.cb))
- {
- req->header.error_code = -1;
- printf ("error writing to connection (%lu)\n", GetLastError ());
- goto out;
+ if (spc)
+ *spc = '\0';
}
- debug_printf("Sent reply, size (%ld)\n",bytes_written);
- printf (".");
-
-out:
- conn->close ();
- delete conn;
- if (req)
- delete (req);
+ char buf[200];
+ snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s",
+ cygwin_version.dll_major / 1000,
+ cygwin_version.dll_major % 1000,
+ cygwin_version.dll_minor,
+ cygwin_version.api_major,
+ cygwin_version.api_minor,
+ cygwin_version.shared_data,
+ CYGWIN_SERVER_VERSION_MAJOR,
+ CYGWIN_SERVER_VERSION_API,
+ CYGWIN_SERVER_VERSION_MINOR,
+ CYGWIN_SERVER_VERSION_PATCH,
+ cygwin_version.mount_registry,
+ cygwin_version.dll_build_date);
+
+ printf ("%s (cygwin) %s\n", pgm, vn);
+ printf ("API version %s\n", buf);
+ printf ("Copyright 2001, 2002 Red Hat, Inc.\n");
+ printf ("Compiled on %s\n", __DATE__);
+
+ free (vn);
}
-void
-server_request_queue::add (transport_layer_base *conn)
-{
- /* safe to not "Try" because workers don't hog this, they wait on the event
- */
- /* every derived ::add must enter the section! */
- EnterCriticalSection (&queuelock);
- if (!running)
- {
- conn->close ();
- delete conn;
- LeaveCriticalSection (&queuelock);
- return;
- }
- queue_request * listrequest = new server_request (conn, cache);
- threaded_queue::add (listrequest);
- LeaveCriticalSection (&queuelock);
-}
+/*
+ * main ()
+ */
-void
-handle_signal (int signal)
+int
+main (const int argc, char *argv[])
{
- /* any signal makes us die :} */
- /* FIXME: link upwards, and then this becomes a trivial method call to
- * only shutdown _this queue_
- */
- /* tell the main thread to shutdown */
- request_queue.active=false;
-}
+ const struct option longopts[] = {
+ {"cleanup-threads", required_argument, NULL, 'c'},
+ {"help", no_argument, NULL, 'h'},
+ {"request-threads", required_argument, NULL, 'r'},
+ {"shutdown", no_argument, NULL, 's'},
+ {"version", no_argument, NULL, 'v'},
+ {0, no_argument, NULL, 0}
+ };
-struct option longopts[] = {
- {"shutdown", no_argument, NULL, 's'},
- {0, no_argument, NULL, 0}
-};
+ const char opts[] = "c:hr:sv";
-char opts[] = "s";
+ int cleanup_threads = 2;
+ int request_threads = 10;
+ bool shutdown = false;
-int
-main (int argc, char **argv)
-{
- int shutdown=0;
- char i;
+ const char *pgm = NULL;
+
+ if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/')))
+ pgm = *argv;
+ else
+ pgm++;
+
+ wincap.init ();
+ if (wincap.has_security ())
+ setup_privileges ();
+
+ int opt;
- while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
- switch (i)
+ while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
+ switch (opt)
{
+ case 'c':
+ cleanup_threads = atoi (optarg);
+ if (cleanup_threads <= 0)
+ {
+ fprintf (stderr,
+ "%s: number of cleanup threads must be positive\n",
+ pgm);
+ exit (1);
+ }
+ break;
+
+ case 'h':
+ print_usage (pgm);
+ return 0;
+
+ case 'r':
+ request_threads = atoi (optarg);
+ if (request_threads <= 0)
+ {
+ fprintf (stderr,
+ "%s: number of request threads must be positive\n",
+ pgm);
+ exit (1);
+ }
+ break;
+
case 's':
- shutdown = 1;
- break;
- default:
- break;
- /*NOTREACHED*/
+ shutdown = true;
+ break;
+
+ case 'v':
+ print_version (pgm);
+ return 0;
+
+ case '?':
+ fprintf (stderr, "Try `%s --help' for more information.\n", pgm);
+ exit (1);
}
- wincap.init();
- if (wincap.has_security ())
- setup_privileges ();
- transport = create_server_transport ();
+ if (optind != argc)
+ {
+ fprintf (stderr, "%s: too many arguments\n", pgm);
+ exit (1);
+ }
if (shutdown)
{
- if (!transport->connect())
+ /* Setting `cygserver_running' stops the request code making a
+ * version request, which is not much to the point.
+ */
+ cygserver_running = CYGSERVER_OK;
+
+ client_request_shutdown req;
+
+ if (req.make_request () == -1 || req.error_code ())
{
- printf ("couldn't establish connection with server\n");
+ fprintf (stderr, "%s: shutdown request failed: %s\n",
+ pgm, strerror (req.error_code ()));
exit (1);
}
- client_request_shutdown *request =
- new client_request_shutdown ();
- request->send (transport);
- transport->close();
- delete transport;
- delete request;
- exit(0);
+
+ // FIXME: It would be nice to wait here for the daemon to exit.
+
+ return 0;
}
- char version[200];
- /* Cygwin dll release */
- snprintf (version, 200, "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s",
- cygwin_version.dll_major / 1000,
- cygwin_version.dll_major % 1000,
- cygwin_version.dll_minor,
- cygwin_version.api_major,
- cygwin_version.api_minor,
- cygwin_version.shared_data,
- CYGWIN_SERVER_VERSION_MAJOR,
- CYGWIN_SERVER_VERSION_API,
- CYGWIN_SERVER_VERSION_MINOR,
- CYGWIN_SERVER_VERSION_PATCH,
- cygwin_version.mount_registry,
- cygwin_version.dll_build_date);
+#define SIGHANDLE(SIG) \
+ do \
+ { \
+ struct sigaction act; \
+ \
+ act.sa_handler = &handle_signal; \
+ act.sa_mask = 0; \
+ act.sa_flags = 0; \
+ \
+ if (sigaction (SIG, &act, NULL) == -1) \
+ { \
+ system_printf ("failed to install handler for " #SIG ": %s", \
+ strerror (errno)); \
+ exit (1); \
+ } \
+ } while (false)
+
+ SIGHANDLE (SIGHUP);
+ SIGHANDLE (SIGINT);
+ SIGHANDLE (SIGTERM);
+
+ print_version (pgm);
setbuf (stdout, NULL);
- printf ("daemon version %s starting up", version);
- if (signal (SIGQUIT, handle_signal) == SIG_ERR)
+ printf ("daemon starting up");
+
+ threaded_queue request_queue (request_threads);
+ printf (".");
+
+ transport_layer_base *const transport = create_server_transport ();
+ assert (transport);
+ printf (".");
+
+ process_cache cache (cleanup_threads);
+ printf (".");
+
+ server_submission_loop submission_loop (&request_queue, transport, &cache);
+ printf (".");
+
+ request_queue.add_submission_loop (&submission_loop);
+ printf (".");
+
+ if (transport->listen () == -1)
{
- printf ("\ncould not install signal handler (%d)- aborting startup\n", errno);
exit (1);
}
printf (".");
- transport->listen ();
- printf (".");
- class process_cache cache (2);
- request_queue.initial_workers = 10;
- request_queue.cache = &cache;
- request_queue.create_workers ();
- printf (".");
- request_queue.process_requests (transport);
+
+ cache.start ();
printf (".");
- cache.create_workers ();
+
+ request_queue.start ();
printf (".");
- cache.process_requests ();
- printf (".complete\n");
- /* TODO: wait on multiple objects - the thread handle for each request loop +
- * all the process handles. This should be done by querying the request_queue and
- * the process cache for all their handles, and then waiting for (say) 30 seconds.
- * after that we recreate the list of handles to wait on, and wait again.
- * the point of all this abstraction is that we can trivially server both sockets
- * and pipes simply by making a new transport, and then calling
- * request_queue.process_requests (transport2);
+
+ printf ("complete\n");
+
+ /* TODO: wait on multiple objects - the thread handle for each
+ * request loop + all the process handles. This should be done by
+ * querying the request_queue and the process cache for all their
+ * handles, and then waiting for (say) 30 seconds. after that we
+ * recreate the list of handles to wait on, and wait again. the
+ * point of all this abstraction is that we can trivially server
+ * both sockets and pipes simply by making a new transport, and then
+ * calling request_queue.process_requests (transport2);
*/
/* WaitForMultipleObjects abort && request_queue && process_queue && signal
-- if signal event then retrigger it
- */
- while (1 && request_queue.active)
- {
- sleep (1);
- }
- printf ("\nShutdown request recieved - new requests will be denied\n");
- request_queue.cleanup ();
+ */
+ while (!shutdown_server && request_queue.running () && cache.running ())
+ pause ();
+
+ printf ("\nShutdown request received - new requests will be denied\n");
+ request_queue.stop ();
printf ("All pending requests processed\n");
- transport->close ();
+ safe_delete (transport);
printf ("No longer accepting requests - cygwin will operate in daemonless mode\n");
- cache.cleanup ();
+ cache.stop ();
printf ("All outstanding process-cache activities completed\n");
printf ("daemon shutdown\n");
+
+ return 0;
}
diff --git a/winsup/cygwin/cygserver_client.cc b/winsup/cygwin/cygserver_client.cc
index 8a1eeafef..138c9ddc0 100755
--- a/winsup/cygwin/cygserver_client.cc
+++ b/winsup/cygwin/cygserver_client.cc
@@ -1,207 +1,529 @@
/* cygserver_client.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Egor Duda <deo@logos-m.ru>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+/* to allow this to link into cygwin and the .dll, a little magic is needed. */
#ifdef __OUTSIDE_CYGWIN__
-#undef __INSIDE_CYGWIN__
+#include "woutsup.h"
#else
#include "winsup.h"
#endif
-#ifndef __INSIDE_CYGWIN__
-#define debug_printf printf
-#define api_fatal printf
-#include <stdio.h>
-#include <windows.h>
-#endif
-#include <sys/socket.h>
+#include <assert.h>
#include <errno.h>
+#include <stdio.h>
#include <unistd.h>
-//#include "security.h"
-#include "cygwin/cygserver_transport.h"
-#include "cygwin/cygserver_transport_pipes.h"
-#include "cygwin/cygserver_transport_sockets.h"
+
+#include "cygerrno.h"
+#include "cygserver_shm.h"
+#include "safe_memory.h"
+
#include "cygwin/cygserver.h"
+#include "cygwin/cygserver_transport.h"
+
+int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
-/* 0 = untested, 1 = running, 2 = dead */
-int cygserver_running=CYGSERVER_UNKNOWN;
-/* on by default during development. For release, we probably want off by default */
-int allow_daemon = TRUE;
+/* On by default during development. For release, we probably want off
+ * by default.
+ */
+bool allow_daemon = true; // Nb: inherited by children.
-client_request_get_version::client_request_get_version () : client_request (CYGSERVER_REQUEST_GET_VERSION, sizeof (version))
+client_request_get_version::client_request_get_version ()
+ : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version))
{
- buffer = (char *)&version;
+ msglen (0); // No parameters for request.
+
+ // verbose: syscall_printf ("created");
}
-client_request_attach_tty::client_request_attach_tty () : client_request (CYGSERVER_REQUEST_ATTACH_TTY, sizeof (req))
+/*
+ * client_request_get_version::check_version ()
+ *
+ * The major version and API version numbers must match exactly. An
+ * older than expected minor version number is accepted (as long as
+ * the first numbers match, that is).
+ */
+
+bool
+client_request_get_version::check_version () const
{
- buffer = (char *)&req;
- req.pid = 0;
- req.master_pid = 0;
- req.from_master = NULL;
- req.to_master = NULL;
+ const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR
+ && version.api == CYGWIN_SERVER_VERSION_API
+ && version.minor <= CYGWIN_SERVER_VERSION_MINOR);
+
+ if (!ok)
+ syscall_printf (("incompatible version of cygwin server: "
+ "client version %d.%d.%d.%d, "
+ "server version %ld.%ld.%ld.%ld"),
+ CYGWIN_SERVER_VERSION_MAJOR,
+ CYGWIN_SERVER_VERSION_API,
+ CYGWIN_SERVER_VERSION_MINOR,
+ CYGWIN_SERVER_VERSION_PATCH,
+ version.major,
+ version.api,
+ version.minor,
+ version.patch);
+
+ return ok;
}
-client_request_attach_tty::client_request_attach_tty (DWORD npid, DWORD nmaster_pid, HANDLE nfrom_master, HANDLE nto_master) : client_request (CYGSERVER_REQUEST_ATTACH_TTY, sizeof (req))
+#ifdef __INSIDE_CYGWIN__
+
+client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
+ HANDLE nfrom_master,
+ HANDLE nto_master)
+ : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
{
- buffer = (char *)&req;
- req.pid = npid;
+ req.pid = GetCurrentProcessId ();
req.master_pid = nmaster_pid;
req.from_master = nfrom_master;
req.to_master = nto_master;
-}
-client_request_shutdown::client_request_shutdown () : client_request (CYGSERVER_REQUEST_SHUTDOWN, 0)
-{
- buffer = NULL;
+ syscall_printf (("created: pid = %lu, master_pid = %lu, "
+ "from_master = %lu, to_master = %lu"),
+ req.pid, req.master_pid, req.from_master, req.to_master);
}
-client_request::client_request (cygserver_request_code id, ssize_t buffer_size) : header (id, buffer_size)
+#else /* !__INSIDE_CYGWIN__ */
+
+client_request_attach_tty::client_request_attach_tty ()
+ : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
{
+ // verbose: syscall_printf ("created");
}
-client_request::~client_request ()
+#endif /* __INSIDE_CYGWIN__ */
+
+/*
+ * client_request_attach_tty::send ()
+ *
+ * Wraps the base method to provide error handling support. If the
+ * reply contains a body but is flagged as an error, close any handles
+ * that have been returned by cygserver and then discard the message
+ * body, i.e. the client either sees a successful result with handles
+ * or an unsuccessful result with no handles.
+ */
+
+void
+client_request_attach_tty::send (transport_layer_base * const conn)
{
+ client_request::send (conn);
+
+ if (msglen () && error_code ())
+ {
+ if (from_master ())
+ CloseHandle (from_master ());
+ if (to_master ())
+ CloseHandle (to_master ());
+ msglen (0);
+ }
}
-client_request::operator class request_header ()
+client_request::header_t::header_t (const request_code_t request_code,
+ const size_t msglen)
+ : msglen (msglen),
+ request_code (request_code)
{
- return header;
+ assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST);
}
+// FIXME: also check write and read result for -1.
+
void
-client_request::send (transport_layer_base *conn)
+client_request::send (transport_layer_base * const conn)
{
- if (!conn)
- return;
- debug_printf("this=%p, conn=%p\n",this, conn);
- ssize_t bytes_written, bytes_read;
- debug_printf("header.cb = %ld\n",header.cb);
- if ((bytes_written = conn->write ((char *)&header, sizeof (header)))
- != sizeof(header) || (header.cb &&
- (bytes_written = conn->write (buffer, header.cb)) != header.cb))
+ assert (conn);
+ assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf
+ assert (msglen () <= _buflen);
+
+ {
+ const ssize_t count = conn->write (&_header, sizeof (_header));
+
+ if (count != sizeof (_header))
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("request header write failure: "
+ "only %ld bytes sent of %ld, "
+ "error = %d(%lu)"),
+ count, sizeof (_header),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ if (msglen ())
{
- header.error_code = -1;
- debug_printf ("bytes written != request size\n");
+ const ssize_t count = conn->write (_buf, msglen ());
+
+ if (count == -1 || (size_t) count != msglen ())
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("request body write failure: "
+ "only %ld bytes sent of %ld, "
+ "error = %d(%lu)"),
+ count, msglen (),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ // verbose: syscall_printf ("request sent (%ld + %ld bytes)",
+ // sizeof (_header), msglen ());
+
+ {
+ const ssize_t count = conn->read (&_header, sizeof (_header));
+
+ if (count != sizeof (_header))
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("reply header read failure: "
+ "only %ld bytes received of %ld, "
+ "error = %d(%lu)"),
+ count, sizeof (_header),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ if (msglen () && !_buf)
+ {
+ system_printf ("no client buffer for reply body: %ld bytes needed",
+ msglen ());
+ error_code (EINVAL);
+ return;
+ }
+
+ if (msglen () > _buflen)
+ {
+ system_printf (("client buffer too small for reply body: "
+ "have %ld bytes and need %ld"),
+ _buflen, msglen ());
+ error_code (EINVAL);
return;
}
- debug_printf("Sent request, size (%ld)\n",bytes_written);
+ if (msglen ())
+ {
+ const ssize_t count = conn->read (_buf, msglen ());
+
+ if (count == -1 || (size_t) count != msglen ())
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("reply body read failure: "
+ "only %ld bytes received of %ld, "
+ "error = %d(%lu)"),
+ count, msglen (),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ // verbose: syscall_printf ("reply received (%ld + %ld bytes)",
+ // sizeof (_header), msglen ());
+}
+
+#ifndef __INSIDE_CYGWIN__
+
+/*
+ * client_request::handle_request ()
+ *
+ * A server-side method.
+ *
+ * This is a factory method for the client_request subclasses. It
+ * reads the incoming request header and, based on its request code,
+ * creates an instance of the appropriate class.
+ *
+ * FIXME: If the incoming packet is malformed, the server drops it on
+ * the floor. Should it try and generate some sort of reply for the
+ * client? As it is, the client will simply get a broken connection.
+ *
+ * FIXME: also check write and read result for -1.
+ */
+
+/* static */ void
+client_request::handle_request (transport_layer_base *const conn,
+ process_cache *const cache)
+{
+ // verbose: debug_printf ("about to read");
+
+ header_t header;
+
+ {
+ const ssize_t count = conn->read (&header, sizeof (header));
+
+ if (count != sizeof (header))
+ {
+ syscall_printf (("request header read failure: "
+ "only %ld bytes received of %ld, "
+ "error = %d(%lu)"),
+ count, sizeof (header),
+ errno, GetLastError ());
+ return;
+ }
+
+ // verbose: debug_printf ("got header (%ld)", count);
+ }
- if ((bytes_read = conn->read ((char *)&header, sizeof (header)))
- != sizeof (header) || (header.cb &&
- (bytes_read = conn->read (buffer, header.cb) ) != header.cb))
+ client_request *req = NULL;
+
+ switch (header.request_code)
{
- header.error_code = -1;
- debug_printf("failed reading response \n");
+ case CYGSERVER_REQUEST_GET_VERSION:
+ req = safe_new0 (client_request_get_version);
+ break;
+ case CYGSERVER_REQUEST_SHUTDOWN:
+ req = safe_new0 (client_request_shutdown);
+ break;
+ case CYGSERVER_REQUEST_ATTACH_TTY:
+ req = safe_new0 (client_request_attach_tty);
+ break;
+ case CYGSERVER_REQUEST_SHM:
+ req = safe_new0 (client_request_shm);
+ break;
+ default:
+ syscall_printf ("unknown request code %d received: request ignored",
+ header.request_code);
return;
}
- debug_printf ("completed ok\n");
+
+ assert (req);
+
+ req->msglen (header.msglen);
+ req->handle (conn, cache);
+
+ safe_delete (req);
+
+#ifndef DEBUGGING
+ printf ("."); // A little noise when we're being quiet.
+#endif
}
-/* Oh, BTW: Fix the procedural basis and make this more intuitive. */
+#endif /* !__INSIDE_CYGWIN__ */
-int
-cygserver_request (client_request * req)
+client_request::client_request (request_code_t const id,
+ void * const buf,
+ size_t const buflen)
+ : _header (id, buflen),
+ _buf (buf),
+ _buflen (buflen)
{
- class transport_layer_base *transport;
+ assert ((!_buf && !_buflen) || (_buf && _buflen));
+}
- if (!req || allow_daemon != TRUE)
- return -1;
+client_request::~client_request ()
+{}
- /* dont' retry every request if the server's not there */
- if (cygserver_running==CYGSERVER_DEAD && req->header.req_id != CYGSERVER_REQUEST_GET_VERSION)
- return -1;
+int
+client_request::make_request ()
+{
+ assert (cygserver_running == CYGSERVER_UNKNOWN \
+ || cygserver_running == CYGSERVER_OK \
+ || cygserver_running == CYGSERVER_UNAVAIL);
- transport = create_server_transport ();
+ if (cygserver_running == CYGSERVER_UNKNOWN)
+ cygserver_init ();
- /* FIXME: have at most one connection per thread. use TLS to store the details */
- /* logic is:
- * if not tlskey->conn, new conn,
- * then; transport=conn;
- */
- if (!transport->connect ())
+ assert (cygserver_running == CYGSERVER_OK \
+ || cygserver_running == CYGSERVER_UNAVAIL);
+
+ /* Don't retry every request if the server's not there */
+ if (cygserver_running == CYGSERVER_UNAVAIL)
{
- delete transport;
+ syscall_printf ("cygserver un-available");
+ error_code (ENOSYS);
return -1;
}
- debug_printf ("connected to server %p\n", transport);
+ transport_layer_base *const transport = create_server_transport ();
+
+ assert (transport);
+
+ if (transport->connect () == -1)
+ {
+ if (errno)
+ error_code (errno);
+ else
+ error_code (ENOSYS);
+ safe_delete (transport);
+ return -1;
+ }
- req->send(transport);
+ // verbose: debug_printf ("connected to server %p", transport);
- transport->close ();
+ send (transport);
- delete transport;
+ safe_delete (transport);
return 0;
}
-#if 0
-BOOL
+#ifndef __INSIDE_CYGWIN__
+
+/*
+ * client_request::handle ()
+ *
+ * A server-side method.
+ *
+ * At this point, the header of an incoming request has been read and
+ * an appropriate client_request object constructed. This method has
+ * to read the request body into its buffer, if there is such a body,
+ * then perform the request and send back the results to the client.
+ *
+ * FIXME: If the incoming packet is malformed, the server drops it on
+ * the floor. Should it try and generate some sort of reply for the
+ * client? As it is, the client will simply get a broken connection.
+ *
+ * FIXME: also check write and read result for -1.
+ */
+
+void
+client_request::handle (transport_layer_base *const conn,
+ process_cache *const cache)
+{
+ if (msglen () && !_buf)
+ {
+ system_printf ("no buffer for request body: %ld bytes needed",
+ msglen ());
+ error_code (EINVAL);
+ return;
+ }
+
+ if (msglen () > _buflen)
+ {
+ system_printf (("buffer too small for request body: "
+ "have %ld bytes and need %ld"),
+ _buflen, msglen ());
+ error_code (EINVAL);
+ return;
+ }
+
+ if (msglen ())
+ {
+ const ssize_t count = conn->read (_buf, msglen ());
+
+ if (count == -1 || (size_t) count != msglen ())
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("request body read failure: "
+ "only %ld bytes received of %ld, "
+ "error = %d(%lu)"),
+ count, msglen (),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ // verbose: syscall_printf ("request received (%ld + %ld bytes)",
+ // sizeof (_header), msglen ());
+
+ error_code (0); // Overwrites the _header.request_code field.
+
+ /*
+ * This is not allowed to fail. We must return ENOSYS at a minimum
+ * to the client.
+ */
+ serve (conn, cache);
+
+ {
+ const ssize_t count = conn->write (&_header, sizeof (_header));
+
+ if (count != sizeof (_header))
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("reply header write failure: "
+ "only %ld bytes sent of %ld, "
+ "error = %d(%lu)"),
+ count, sizeof (_header),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ if (msglen ())
+ {
+ const ssize_t count = conn->write (_buf, msglen ());
+
+ if (count == -1 || (size_t) count != msglen ())
+ {
+ assert (errno);
+ error_code (errno);
+ syscall_printf (("reply body write failure: "
+ "only %ld bytes sent of %ld, "
+ "error = %d(%lu)"),
+ count, msglen (),
+ errno, GetLastError ());
+ return;
+ }
+ }
+
+ // verbose: syscall_printf ("reply sent (%ld + %ld bytes)",
+ // sizeof (_header), msglen ());
+}
+
+#endif /* !__INSIDE_CYGWIN__ */
+
+bool
check_cygserver_available ()
{
- BOOL ret_val = FALSE;
- HANDLE pipe = CreateFile (pipe_name,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_all_nih,
- OPEN_EXISTING,
- 0,
- NULL);
- if (pipe != INVALID_HANDLE_VALUE || GetLastError () != ERROR_PIPE_BUSY)
- ret_val = TRUE;
-
- if (pipe && pipe != INVALID_HANDLE_VALUE)
- CloseHandle (pipe);
-
- return (ret_val);
+ assert (cygserver_running == CYGSERVER_UNKNOWN \
+ || cygserver_running == CYGSERVER_UNAVAIL);
+
+ cygserver_running = CYGSERVER_OK; // For make_request ().
+
+ client_request_get_version req;
+
+ /* This indicates that we failed to connect to cygserver at all but
+ * that's fine as cygwin doesn't need it to be running.
+ */
+ if (req.make_request () == -1)
+ return false;
+
+ /* We connected to the server but something went wrong after that
+ * (in sending the message, in cygserver itself, or in receiving the
+ * reply).
+ */
+ if (req.error_code ())
+ {
+ syscall_printf ("failure in cygserver version request: %d",
+ req.error_code ());
+ syscall_printf ("process will continue without cygserver support");
+ return false;
+ }
+
+ return req.check_version ();
}
-#endif
void
cygserver_init ()
{
- int rc;
- if (allow_daemon != TRUE)
+ if (!allow_daemon)
{
- cygserver_running = CYGSERVER_DEAD;
+ syscall_printf ("cygserver use disabled in client");
+ cygserver_running = CYGSERVER_UNAVAIL;
return;
}
- if (cygserver_running==CYGSERVER_OK)
+ assert (cygserver_running == CYGSERVER_UNKNOWN \
+ || cygserver_running == CYGSERVER_OK \
+ || cygserver_running == CYGSERVER_UNAVAIL);
+
+ if (cygserver_running == CYGSERVER_OK)
return;
- client_request_get_version *req =
- new client_request_get_version ();
-
- rc = cygserver_request (req);
- delete req;
- if (rc < 0)
- cygserver_running = CYGSERVER_DEAD;
- else if (rc > 0)
- api_fatal ( "error connecting to cygwin server. error: %d", rc );
- else if (req->version.major != CYGWIN_SERVER_VERSION_MAJOR ||
- req->version.api != CYGWIN_SERVER_VERSION_API ||
- req->version.minor > CYGWIN_SERVER_VERSION_MINOR)
- api_fatal ( "incompatible version of cygwin server.\n\
- client version %d.%d.%d.%d, server version%ld.%ld.%ld.%ld",
- CYGWIN_SERVER_VERSION_MAJOR,
- CYGWIN_SERVER_VERSION_API,
- CYGWIN_SERVER_VERSION_MINOR,
- CYGWIN_SERVER_VERSION_PATCH,
- req->version.major,
- req->version.api,
- req->version.minor,
- req->version.patch );
- else
- cygserver_running = CYGSERVER_OK;
+ if (!check_cygserver_available ())
+ cygserver_running = CYGSERVER_UNAVAIL;
}
diff --git a/winsup/cygwin/cygserver_ipc.h b/winsup/cygwin/cygserver_ipc.h
new file mode 100644
index 000000000..0d0ebbc76
--- /dev/null
+++ b/winsup/cygwin/cygserver_ipc.h
@@ -0,0 +1,84 @@
+/* cygserver_ipc.h
+
+ Copyright 2002 Red Hat, Inc.
+
+ Originally written by Conrad Scott <conrad.scott@dsl.pipex.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef __CYGSERVER_IPC_H__
+#define __CYGSERVER_IPC_H__
+
+#include <assert.h>
+#include <limits.h> /* For OPEN_MAX. */
+
+/*
+ * The sysv ipc id's (msgid, semid, shmid) are integers arranged such
+ * that they no subsystem will generate the same id as some other
+ * subsystem; nor do these ids overlap file descriptors (the other
+ * common integer ids). Since Cygwin can allocate more than OPEN_MAX
+ * file descriptors, it can't be guaranteed not to overlap, but it
+ * should help catch some errors.
+ *
+ * msgid's: OPEN_MAX, OPEN_MAX + 3, OPEN_MAX + 6, . . .
+ * semid's: OPEN_MAX + 1, OPEN_MAX + 4, OPEN_MAX + 7, . . .
+ * shmid's: OPEN_MAX + 2, OPEN_MAX + 5, OPEN_MAX + 8, . . .
+ *
+ * To further ensure that ids are unique, if ipc objects are created
+ * and destroyed and then re-created, they are given new ids by
+ * munging the basic id (as above) with a sequence number.
+ *
+ * Internal ipc id's, which are 0, 1, ... within each subsystem (and
+ * not munged with a sequence number), are used solely by the ipcs(8)
+ * interface.
+ */
+
+enum ipc_subsys_t
+ {
+ IPC_MSGOP = 0,
+ IPC_SEMOP = 1,
+ IPC_SHMOP = 2,
+ IPC_SUBSYS_COUNT
+ };
+
+/*
+ * IPCMNI - The absolute maximum number of simultaneous ipc ids for
+ * any one subsystem.
+ */
+
+enum
+ {
+ IPCMNI = 0x10000 // Must be a power of two.
+ };
+
+inline int
+ipc_int2ext (const int intid, const ipc_subsys_t subsys, long & sequence)
+{
+ assert (0 <= intid && intid < IPCMNI);
+
+ const long tmp = InterlockedIncrement (&sequence);
+
+ return (((tmp & 0x7fff) << 16)
+ | (OPEN_MAX + (intid * IPC_SUBSYS_COUNT) + subsys));
+}
+
+inline int
+ipc_ext2int_subsys (const int extid)
+{
+ return ((extid & (IPCMNI - 1)) - OPEN_MAX) % IPC_SUBSYS_COUNT;
+}
+
+inline int
+ipc_ext2int (const int extid, const ipc_subsys_t subsys)
+{
+ if (ipc_ext2int_subsys (extid) != subsys)
+ return -1;
+ else
+ return ((extid & (IPCMNI - 1)) - OPEN_MAX) / IPC_SUBSYS_COUNT;
+}
+
+#endif /* __CYGSERVER_IPC_H__ */
diff --git a/winsup/cygwin/cygserver_process.cc b/winsup/cygwin/cygserver_process.cc
index a5173afd3..7118bbcd9 100755
--- a/winsup/cygwin/cygserver_process.cc
+++ b/winsup/cygwin/cygserver_process.cc
@@ -1,389 +1,432 @@
/* cygserver_process.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+#include "woutsup.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include "wincap.h"
-#include <pthread.h>
-#include <threaded_queue.h>
-#include <cygwin/cygserver_process.h>
-
-#define debug_printf if (DEBUG) printf
-#define DEBUG 1
-
-/* the cache structures and classes are designed for one cache per server process.
- * To make multiple process caches, a redesign will be needed
- */
-/* process cache */
-process_cache::process_cache (unsigned int num_initial_workers):
-head (NULL)
+#include "cygerrno.h"
+
+#include "cygwin/cygserver_process.h"
+
+/*****************************************************************************/
+
+#define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY))
+
+/*****************************************************************************/
+
+process_cleanup::~process_cleanup ()
{
- /* there can only be one */
- InitializeCriticalSection (&cache_write_access);
- if ((cache_add_trigger = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL)
- {
- printf ("Failed to create cache add trigger (%lu), terminating\n",
- GetLastError ());
- exit (1);
- }
- initial_workers = num_initial_workers;
+ safe_delete (_process);
}
-process_cache::~process_cache ()
+void
+process_cleanup::process ()
{
+ _process->cleanup ();
}
-class process *
-process_cache::process (long pid)
+/*****************************************************************************/
+
+/* cleanup_routine */
+cleanup_routine::~cleanup_routine ()
{
- class process *entry = head;
- /* TODO: make this more granular, so a search doesn't involve the write lock */
- EnterCriticalSection (&cache_write_access);
- if (!entry)
+}
+
+/*****************************************************************************/
+
+process::process (const pid_t cygpid, const DWORD winpid)
+ : _cygpid (cygpid),
+ _winpid (winpid),
+ _hProcess (NULL),
+ _cleaning_up (false),
+ _exit_status (STILL_ACTIVE),
+ _routines_head (NULL),
+ _next (NULL)
+{
+ _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid);
+ if (!_hProcess)
{
- entry = new class process (pid);
- entry->next =
- (class process *) InterlockedExchangePointer (&head, entry);
- PulseEvent (cache_add_trigger);
+ system_printf ("unable to obtain handle for new cache process %d(%lu)",
+ _cygpid, _winpid);
+ _hProcess = INVALID_HANDLE_VALUE;
+ _exit_status = 0;
}
else
- {
- while (entry->winpid != pid && entry->next)
- entry = entry->next;
- if (entry->winpid != pid)
- {
- class process *new_entry = new class process (pid);
- new_entry->next =
- (class process *) InterlockedExchangePointer (&entry->next,
- new_entry);
- entry = new_entry;
- PulseEvent (cache_add_trigger);
- }
- }
- LeaveCriticalSection (&cache_write_access);
- return entry;
+ debug_printf ("got handle %p for new cache process %d(%lu)",
+ _hProcess, _cygpid, _winpid);
+ InitializeCriticalSection (&_access);
}
-static DWORD WINAPI
-request_loop (LPVOID LpParam)
+process::~process ()
{
- class process_process_param *params = (process_process_param *) LpParam;
- return params->request_loop ();
+ DeleteCriticalSection (&_access);
+ (void) CloseHandle (_hProcess);
}
-void
-process_cache::process_requests ()
+/* No need to be thread-safe as this is only ever called by
+ * process_cache::remove_process (). If it has to be made thread-safe
+ * later on, it should not use the `access' critical section as that
+ * is held by the client request handlers for an arbitrary length of
+ * time, i.e. while they do whatever processing is required for a
+ * client request.
+ */
+DWORD
+process::check_exit_code ()
{
- class process_process_param *params = new process_process_param;
- threaded_queue::process_requests (params, request_loop);
+ if (_hProcess && _hProcess != INVALID_HANDLE_VALUE
+ && _exit_status == STILL_ACTIVE
+ && !GetExitCodeProcess (_hProcess, &_exit_status))
+ {
+ system_printf ("failed to retrieve exit code for %d(%lu), error = %lu",
+ _cygpid, _winpid, GetLastError ());
+ _hProcess = INVALID_HANDLE_VALUE;
+ }
+ return _exit_status;
}
-void
-process_cache::add_task (class process * theprocess)
+bool
+process::add (cleanup_routine *const entry)
{
- /* safe to not "Try" because workers don't hog this, they wait on the event
- */
- /* every derived ::add must enter the section! */
- EnterCriticalSection (&queuelock);
- queue_request *listrequest = new process_cleanup (theprocess);
- threaded_queue::add (listrequest);
- LeaveCriticalSection (&queuelock);
-}
+ assert (entry);
-/* NOT fully MT SAFE: must be called by only one thread in a program */
-void
-process_cache::remove_process (class process *theprocess)
-{
- class process *entry = head;
- /* unlink */
- EnterCriticalSection (&cache_write_access);
- if (entry == theprocess)
+ bool res = false;
+ EnterCriticalSection (&_access);
+
+ if (!_cleaning_up)
{
- entry = (class process *) InterlockedExchangePointer (&head, theprocess->next);
- if (entry != theprocess)
- {
- printf ("Bug encountered, process cache corrupted\n");
- exit (1);
- }
+ entry->_next = _routines_head;
+ _routines_head = entry;
+ res = true;
}
- else
+
+ LeaveCriticalSection (&_access);
+ return res;
+}
+
+bool
+process::remove (const cleanup_routine *const entry)
+{
+ assert (entry);
+
+ bool res = false;
+ EnterCriticalSection (&_access);
+
+ if (!_cleaning_up)
{
- while (entry->next && entry->next != theprocess)
- entry = entry->next;
- class process *temp = (class process *) InterlockedExchangePointer (&entry->next, theprocess->next);
- if (temp != theprocess)
+ cleanup_routine *previous = NULL;
+
+ for (cleanup_routine *ptr = _routines_head;
+ ptr;
+ previous = ptr, ptr = ptr->_next)
{
- printf ("Bug encountered, process cache corrupted\n");
- exit (1);
+ if (*ptr == *entry)
+ {
+ if (previous)
+ previous->_next = ptr->_next;
+ else
+ _routines_head = ptr->_next;
+
+ safe_delete (ptr);
+ res = true;
+ break;
+ }
}
}
- LeaveCriticalSection (&cache_write_access);
- /* Process any cleanup tasks */
- add_task (theprocess);
+
+ LeaveCriticalSection (&_access);
+ return res;
}
-
-
-/* copy <= max_copy HANDLEs to dest[], starting at an offset into _our list_ of
- * begin_at. (Ie begin_at = 5, the first copied handle is still written to dest[0]
- * NOTE: Thread safe, but not thread guaranteed - a newly added process may be missed.
- * Who cares - It'll get caught the next time.
+
+/* This is single threaded. It's called after the process is removed
+ * from the cache, but inserts may be attemped by worker threads that
+ * have a pointer to it.
*/
-int
-process_cache::handle_snapshot (HANDLE * hdest, class process ** edest,
- ssize_t max_copy, int begin_at)
+void
+process::cleanup ()
{
- /* TODO:? grab a delete-lock, to prevent deletes during this process ? */
- class process *entry = head;
- int count = begin_at;
- /* skip begin_at entries */
- while (entry && count)
- {
- if (entry->exit_code () == STILL_ACTIVE)
- count--;
- entry = entry->next;
- }
- /* hit the end of the list within begin_at entries */
- if (count)
- return 0;
- HANDLE *hto = hdest;
- class process **eto = edest;
- while (entry && count < max_copy)
+ EnterCriticalSection (&_access);
+ assert (!is_active ());
+ assert (!_cleaning_up);
+ InterlockedExchange (&_cleaning_up, true);
+ cleanup_routine *entry = _routines_head;
+ _routines_head = NULL;
+ LeaveCriticalSection (&_access);
+
+ while (entry)
{
- /* hack */
- if (entry->exit_code () == STILL_ACTIVE)
- {
- *hto = entry->handle ();
- *eto = entry;
- count++;
- hto++;
- eto++;
- }
- entry = entry->next;
+ cleanup_routine *const ptr = entry;
+ entry = entry->_next;
+ ptr->cleanup (this);
+ safe_delete (ptr);
}
- return count;
}
-/* process's */
-/* global process crit section */
-static CRITICAL_SECTION process_access;
-static pthread_once_t process_init;
+/*****************************************************************************/
void
-do_process_init (void)
+process_cache::submission_loop::request_loop ()
{
- InitializeCriticalSection (&process_access);
- /* we don't have a cache shutdown capability today */
+ assert (this);
+ assert (_cache);
+ assert (_interrupt_event);
+
+ while (_running)
+ _cache->wait_for_processes (_interrupt_event);
}
-process::process (long pid):
-winpid (pid), next (NULL), cleaning_up (0), head (NULL), _exit_status (STILL_ACTIVE)
+/*****************************************************************************/
+
+process_cache::process_cache (const unsigned int initial_workers)
+ : _queue (initial_workers),
+ _submitter (this, &_queue), // true == interruptible
+ _processes_count (0),
+ _processes_head (NULL),
+ _cache_add_trigger (NULL)
{
- pthread_once (&process_init, do_process_init);
- EnterCriticalSection (&process_access);
- thehandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
- if (!thehandle)
+ /* there can only be one */
+ InitializeCriticalSection (&_cache_write_access);
+
+ _cache_add_trigger = CreateEvent (NULL, // SECURITY_ATTRIBUTES
+ FALSE, // Auto-reset
+ FALSE, // Initially non-signalled
+ NULL); // Anonymous
+
+ if (!_cache_add_trigger)
{
- printf ("unable to obtain handle for new cache process %ld\n", pid);
- thehandle = INVALID_HANDLE_VALUE;
+ system_printf ("failed to create cache add trigger, error = %lu",
+ GetLastError ());
+ abort ();
}
- debug_printf ("Got handle %p for new cache process %ld\n", thehandle, pid);
- InitializeCriticalSection (&access);
- LeaveCriticalSection (&process_access);
-}
-process::~process ()
-{
- DeleteCriticalSection (&access);
+ _queue.add_submission_loop (&_submitter);
}
-HANDLE
-process::handle ()
+process_cache::~process_cache ()
{
-// DWORD exitstate = exit_code ();
-// if (exitstate == STILL_ACTIVE)
- return thehandle;
-
- /* FIXME: call the cleanup list ? */
-
-// CloseHandle (thehandle);
-// debug_printf ("Process id %ld has terminated, attempting to open a new handle\n",
-// winpid);
-// thehandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid);
-// debug_printf ("Got handle %p when refreshing cache process %ld\n", thehandle, winpid);
-// /* FIXME: what if OpenProcess fails ? */
-// if (thehandle)
-// {
-// _exit_status = STILL_ACTIVE;
-// exit_code ();
-// }
-// else
-// thehandle = INVALID_HANDLE_VALUE;
-// return thehandle;
+ (void) CloseHandle (_cache_add_trigger);
+ DeleteCriticalSection (&_cache_write_access);
}
-DWORD process::exit_code ()
+/* This returns the process object to the caller already locked, that
+ * is, with the object's `access' critical region entered. Thus the
+ * caller must unlock the object when it's finished with it (via
+ * process::release ()). It must then not try to access the object
+ * afterwards, except by going through this routine again, as it may
+ * have been deleted once it has been unlocked.
+ */
+class process *
+process_cache::process (const pid_t cygpid, const DWORD winpid)
{
- if (_exit_status != STILL_ACTIVE)
- return _exit_status;
- bool
- err = GetExitCodeProcess (thehandle, &_exit_status);
- if (!err)
+ /* TODO: make this more granular, so a search doesn't involve the
+ * write lock.
+ */
+ EnterCriticalSection (&_cache_write_access);
+ class process *previous = NULL;
+ class process *entry = find (winpid, &previous);
+
+ if (!entry)
{
- debug_printf ("Failed to retrieve exit code (%ld)\n", GetLastError ());
- thehandle = INVALID_HANDLE_VALUE;
- return _exit_status;
+ if (_processes_count + SPECIALS_COUNT >= MAXIMUM_WAIT_OBJECTS)
+ {
+ LeaveCriticalSection (&_cache_write_access);
+ system_printf (("process limit (%d processes) reached; "
+ "new connection refused for %d(%lu)"),
+ MAXIMUM_WAIT_OBJECTS - SPECIALS_COUNT,
+ cygpid, winpid);
+ set_errno (EAGAIN);
+ return NULL;
+ }
+
+ entry = safe_new (class process, cygpid, winpid);
+ if (!entry->is_active ())
+ {
+ LeaveCriticalSection (&_cache_write_access);
+ safe_delete (entry);
+ set_errno (ESRCH);
+ return NULL;
+ }
+
+ if (previous)
+ {
+ entry->_next = previous->_next;
+ previous->_next = entry;
+ }
+ else
+ {
+ entry->_next = _processes_head;
+ _processes_head = entry;
+ }
+
+ _processes_count += 1;
+ SetEvent (_cache_add_trigger);
}
- else if (_exit_status == STILL_ACTIVE)
- return _exit_status;
- /* add new cleanup task etc etc ? */
- return _exit_status;
+
+ EnterCriticalSection (&entry->_access); // To be released by the caller.
+ LeaveCriticalSection (&_cache_write_access);
+ assert (entry);
+ assert (entry->_winpid == winpid);
+ return entry;
}
-/* this is single threaded. It's called after the process is removed from the cache,
- * but inserts may be attemped by worker threads that have a pointer to it */
void
-process::cleanup ()
+process_cache::wait_for_processes (const HANDLE interrupt_event)
{
- /* Serialize this */
- EnterCriticalSection (&access);
- InterlockedIncrement (&(long)cleaning_up);
- class cleanup_routine *entry = head;
- while (entry)
+ // Update `_wait_array' with handles of all current processes.
+ const size_t count = sync_wait_array (interrupt_event);
+
+ debug_printf ("waiting on %u objects in total (%u processes)",
+ count, _processes_count);
+
+ const DWORD rc = WaitForMultipleObjects (count, _wait_array,
+ FALSE, INFINITE);
+
+ if (rc == WAIT_FAILED)
+ {
+ system_printf ("could not wait on the process handles, error = %lu",
+ GetLastError ());
+ abort ();
+ }
+
+ const size_t start = rc - WAIT_OBJECT_0;
+
+ if (rc < WAIT_OBJECT_0 || start > count)
{
- class cleanup_routine *temp;
- entry->cleanup (winpid);
- temp = entry->next;
- delete entry;
- entry = temp;
+ system_printf (("unexpected return code %rc "
+ "from WaitForMultipleObjects: "
+ "expected [%u .. %u)"),
+ rc, WAIT_OBJECT_0, WAIT_OBJECT_0 + count);
+ abort ();
}
- LeaveCriticalSection (&access);
+
+ // Tell all the processes, from the signalled point up, the bad news.
+ for (size_t index = start; index != count; index++)
+ if (_process_array[index])
+ check_and_remove_process (index);
}
-bool
-process::add_cleanup_routine (class cleanup_routine *new_cleanup)
+/*
+ * process_cache::sync_wait_array ()
+ *
+ * Fill-in the wait array with the handles that the cache needs to wait on.
+ * These handles are:
+ * - the process_process_param's interrupt event
+ * - the process_cache's cache_add_trigger event
+ * - the handle for each live process in the cache.
+ *
+ * Return value: the number of live handles in the array.
+ */
+
+size_t
+process_cache::sync_wait_array (const HANDLE interrupt_event)
{
- if (cleaning_up)
- return false;
- EnterCriticalSection (&access);
- /* check that we didn't block with ::cleanup ()
- * This rigmarole is to get around win9x's glaring missing TryEnterCriticalSection call
- * which would be a whole lot easier
- */
- if (cleaning_up)
+ assert (this);
+ assert (_cache_add_trigger && _cache_add_trigger != INVALID_HANDLE_VALUE);
+ assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE);
+
+ EnterCriticalSection (&_cache_write_access);
+
+ assert (_processes_count + SPECIALS_COUNT <= elements (_wait_array));
+
+ size_t index = 0;
+
+ for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
{
- LeaveCriticalSection (&access);
- return false;
+ assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE);
+ assert (ptr->is_active ());
+
+ _wait_array[index] = ptr->handle ();
+ _process_array[index++] = ptr;
+
+ assert (index <= elements (_wait_array));
}
- new_cleanup->next = head;
- head = new_cleanup;
- LeaveCriticalSection (&access);
- return true;
+
+ /* Sorry for shouting, but THESE MUST BE ADDED AT THE END! */
+ /* Well, not strictly `must', but it's more efficient if they are :-) */
+
+ _wait_array[index] = interrupt_event;
+ _process_array[index++] = NULL;
+
+ _wait_array[index] = _cache_add_trigger;
+ _process_array[index++] = NULL;
+
+ /* Phew, back to normal volume now. */
+
+ assert (index <= elements (_wait_array));
+
+ LeaveCriticalSection (&_cache_write_access);
+
+ return index;
}
-/* process_cleanup */
void
-process_cleanup::process ()
+process_cache::check_and_remove_process (const size_t index)
{
- theprocess->cleanup ();
- delete theprocess;
+ assert (this);
+ assert (index < elements (_wait_array) - SPECIALS_COUNT);
+
+ class process *const process = _process_array[index];
+
+ assert (process);
+ assert (process->handle () == _wait_array[index]);
+
+ if (process->check_exit_code () == STILL_ACTIVE)
+ return;
+
+ debug_printf ("process %d(%lu) has left the building ($? = %lu)",
+ process->_cygpid, process->_winpid, process->_exit_status);
+
+ /* Unlink the process object from the process list. */
+
+ EnterCriticalSection (&_cache_write_access);
+
+ class process *previous = NULL;
+
+ const class process *const tmp = find (process->_winpid, &previous);
+
+ assert (tmp == process);
+ assert (previous ? previous->_next == process : _processes_head == process);
+
+ if (previous)
+ previous->_next = process->_next;
+ else
+ _processes_head = process->_next;
+
+ _processes_count -= 1;
+ LeaveCriticalSection (&_cache_write_access);
+
+ /* Schedule any cleanup tasks for this process. */
+ _queue.add (safe_new (process_cleanup, process));
}
-/* process_process_param */
-DWORD
-process_process_param::request_loop ()
+class process *
+process_cache::find (const DWORD winpid, class process **previous)
{
- process_cache *cache = (process_cache *) queue;
- /* always malloc one, so there is no special case in the loop */
- ssize_t HandlesSize = 2;
- HANDLE *Handles = (HANDLE *) malloc (sizeof (HANDLE) * HandlesSize);
- process **Entries = (process **) malloc (sizeof (LPVOID) * HandlesSize);
- /* TODO: put [1] at the end as it will also get done if a process dies? */
- Handles[0] = interrupt;
- Handles[1] = cache->cache_add_trigger;
- while (cache->active && !shutdown)
- {
- int copied;
- copied = -1;
- int offset;
- offset = 1;
- int count;
- count = 2;
- while ((copied == HandlesSize - 2 - offset) || copied < 0)
- {
- /* we need more storage to cope with all the HANDLES */
- if (copied == HandlesSize - 2 - offset)
- {
- HANDLE *temp = (HANDLE *) realloc (Handles,
- sizeof (HANDLE) *
- HandlesSize + 10);
- if (!temp)
- {
- printf
- ("cannot allocate more storage for the handle array!\n");
- exit (1);
- }
- Handles = temp;
- process **ptemp = (process **) realloc (Entries,
- sizeof (LPVOID) *
- HandlesSize + 10);
- if (!ptemp)
- {
- printf
- ("cannot allocate more storage for the handle array!\n");
- exit (1);
- }
- Entries = ptemp;
- HandlesSize += 10;
- }
- offset += copied;
- copied =
- cache->handle_snapshot (&Handles[2], &Entries[2],
- HandlesSize - 2 - offset, offset);
- count += copied;
- }
- debug_printf ("waiting on %u objects\n", count);
- DWORD rc = WaitForMultipleObjects (count, Handles, FALSE, INFINITE);
- if (rc == WAIT_FAILED)
- {
- printf ("Could not wait on the process handles (%ld)!\n",
- GetLastError ());
- exit (1);
- }
- int objindex = rc - WAIT_OBJECT_0;
- if (objindex > 1 && objindex < count)
- {
- debug_printf ("Process %ld has left the building\n",
- Entries[objindex]->winpid);
- /* fire off the termination routines */
- cache->remove_process (Entries[objindex]);
- }
- else if (objindex >= 0 && objindex < 2)
- {
- /* 0 is shutdown - do nothing */
- /* 1 is a cache add event - just rebuild the object list */
- }
- else
- {
- printf
- ("unexpected return code from WaitForMultiple objects in process_process_param::request_loop\n");
- }
- }
- running = false;
- return 0;
+ if (previous)
+ *previous = NULL;
+
+ for (class process *ptr = _processes_head; ptr; ptr = ptr->_next)
+ if (ptr->_winpid == winpid)
+ return ptr;
+ else if (ptr->_winpid > winpid) // The list is sorted by winpid.
+ return NULL;
+ else if (previous)
+ *previous = ptr;
+
+ return NULL;
}
+
+/*****************************************************************************/
diff --git a/winsup/cygwin/cygserver_shm.cc b/winsup/cygwin/cygserver_shm.cc
index c29938bb9..18b1c3d83 100755
--- a/winsup/cygwin/cygserver_shm.cc
+++ b/winsup/cygwin/cygserver_shm.cc
@@ -1,552 +1,896 @@
-/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin
+/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin.
- Copyright 2001 Red Hat, Inc.
+ Copyright 2002 Red Hat, Inc.
- Originally written by Robert Collins <robert.collins@hotmail.com>
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+ Based on code by Robert Collins <robert.collins@hotmail.com>.
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+#include "woutsup.h"
-#ifdef __OUTSIDE_CYGWIN__
-#undef __INSIDE_CYGWIN__
-#else
-#include "winsup.h"
-#endif
-
-#ifndef __INSIDE_CYGWIN__
-#define DEBUG 0
-#define system_printf printf
-#define debug_printf if (DEBUG) printf
-#define api_fatal printf
-#include <stdio.h>
-#include <windows.h>
-#endif
-
-#include <sys/stat.h>
#include <errno.h>
-#include "cygerrno.h"
-#include <unistd.h>
-#include "security.h"
-//#include "fhandler.h"
-//#include "dtable.h"
-//#include "cygheap.h"
+#include <pthread.h>
#include <stdio.h>
-//#include "thread.h"
-#ifndef __INSIDE_CYGWIN__
-#define __INSIDE_CYGWIN__
-#include <sys/shm.h>
-#undef __INSIDE_CYGWIN__
-#else
-#include <sys/shm.h>
-#endif
-//#include "perprocess.h"
-#include <threaded_queue.h>
-#include <cygwin/cygserver_process.h>
+#include <string.h>
+#include <time.h>
+
+#include "cygserver_ipc.h"
#include "cygserver_shm.h"
+#include "security.h"
+
+#include "cygwin/cygserver.h"
+#include "cygwin/cygserver_process.h"
+#include "cygwin/cygserver_transport.h"
+
+/*---------------------------------------------------------------------------*
+ * class server_shmmgr
+ *
+ * A singleton class.
+ *---------------------------------------------------------------------------*/
-// FIXME IS THIS CORRECT
-/* Implementation notes: We use two shared memory regions per key:
- * One for the control structure, and one for the shared memory.
- * While this has a higher overhead tham a single shared area,
- * It allows more flexability. As the entire code is transparent to the user
- * We can merge these in the future should it be needed.
- * Also, IPC_PRIVATE keys create unique mappings each time. The shm_ids just
- * keep monotonically incrementing - system wide.
- */
-size_t
-getsystemallocgranularity ()
+#define shmmgr (server_shmmgr::instance ())
+
+class server_shmmgr
{
- SYSTEM_INFO sysinfo;
- static size_t buffer_offset = 0;
- if (buffer_offset)
- return buffer_offset;
- GetSystemInfo (&sysinfo);
- buffer_offset = sysinfo.dwAllocationGranularity;
- return buffer_offset;
-}
+private:
+ class attach_t
+ {
+ public:
+ class process *const _client;
+ unsigned int _refcnt;
+
+ attach_t *_next;
+
+ attach_t (class process *const client)
+ : _client (client),
+ _refcnt (0),
+ _next (NULL)
+ {}
+ };
+
+ class segment_t
+ {
+ private:
+ // Bits for the _flg field.
+ enum { IS_DELETED = 0x01 };
+
+ public:
+ const int _intid;
+ const int _shmid;
+ struct shmid_ds _ds;
+
+ segment_t *_next;
+
+ segment_t (const key_t key, const int intid, const HANDLE hFileMap);
+ ~segment_t ();
+
+ bool is_deleted () const
+ {
+ return _flg & IS_DELETED;
+ }
+ bool is_pending_delete () const
+ {
+ return !_ds.shm_nattch && is_deleted ();
+ }
-client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters))
+ void mark_deleted ()
+ {
+ assert (!is_deleted ());
+
+ _flg |= IS_DELETED;
+ }
+
+ int attach (class process *, HANDLE & hFileMap);
+ int detach (class process *);
+
+ private:
+ static long _sequence;
+
+ int _flg;
+ const HANDLE _hFileMap;
+ attach_t *_attach_head; // A list sorted by winpid;
+
+ attach_t *find (const class process *, attach_t **previous = NULL);
+ };
+
+ class cleanup_t : public cleanup_routine
+ {
+ public:
+ cleanup_t (const segment_t *const segptr)
+ : cleanup_routine (reinterpret_cast<void *> (segptr->_shmid))
+ {
+ assert (key ());
+ }
+
+ int shmid () const { return reinterpret_cast<int> (key ()); }
+
+ virtual void cleanup (class process *const client)
+ {
+ const int res = shmmgr.shmdt (shmid (), client);
+
+ if (res != 0)
+ debug_printf ("process cleanup failed [shmid = %d]: %s",
+ shmid (), strerror (-res));
+ }
+ };
+
+public:
+ static server_shmmgr & instance ();
+
+ int shmat (HANDLE & hFileMap,
+ int shmid, int shmflg, class process *);
+ int shmctl (int & out_shmid, struct shmid_ds & out_ds,
+ struct shminfo & out_shminfo, struct shm_info & out_shm_info,
+ const int shmid, int cmd, const struct shmid_ds &,
+ class process *);
+ int shmdt (int shmid, class process *);
+ int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t,
+ class process *);
+
+private:
+ static server_shmmgr *_instance;
+ static pthread_once_t _instance_once;
+
+ static void initialise_instance ();
+
+ CRITICAL_SECTION _segments_lock;
+ segment_t *_segments_head; // A list sorted by int_id.
+
+ int _shm_ids; // Number of shm segments (for ipcs(8)).
+ int _shm_tot; // Total bytes of shm segments (for ipcs(8)).
+ int _shm_atts; // Number of attached segments (for ipcs(8)).
+ int _intid_max; // Highest intid yet allocated (for ipcs(8)).
+
+ server_shmmgr ();
+ ~server_shmmgr ();
+
+ // Undefined (as this class is a singleton):
+ server_shmmgr (const server_shmmgr &);
+ server_shmmgr & operator= (const server_shmmgr &);
+
+ segment_t *find_by_key (key_t);
+ segment_t *find (int intid, segment_t **previous = NULL);
+
+ int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t);
+
+ segment_t *new_segment (key_t, size_t, HANDLE);
+ void delete_segment (segment_t *);
+};
+
+/* static */ long server_shmmgr::segment_t::_sequence = 0;
+
+/* static */ server_shmmgr *server_shmmgr::_instance = NULL;
+/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT;
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::segment_t::segment_t ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::segment_t::segment_t (const key_t key,
+ const int intid,
+ const HANDLE hFileMap)
+ : _intid (intid),
+ _shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)),
+ _next (NULL),
+ _flg (0),
+ _hFileMap (hFileMap),
+ _attach_head (NULL)
{
- buffer = (char *) &parameters;
+ assert (0 <= _intid && _intid < SHMMNI);
+
+ memset (&_ds, '\0', sizeof (_ds));
+ _ds.shm_perm.key = key;
}
-/* FIXME: If building on a 64-bit compiler, the address->int typecast will fail.
- * Solution: manually calculate the next id value
- */
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::segment_t::~segment_t ()
+ *---------------------------------------------------------------------------*/
-#if 0
-extern "C" void *
-shmat (int shmid, const void *shmaddr, int parameters.in.shmflg)
+server_shmmgr::segment_t::~segment_t ()
{
- class shmid_ds *shm = (class shmid_ds *) shmid; //FIXME: verifyable object test
+ assert (!_attach_head);
+
+ if (!CloseHandle (_hFileMap))
+ syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap);
+}
- if (shmaddr)
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::segment_t::attach ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::segment_t::attach (class process *const client,
+ HANDLE & hFileMap)
+{
+ assert (client);
+
+ if (!DuplicateHandle (GetCurrentProcess (),
+ _hFileMap,
+ client->handle (),
+ &hFileMap,
+ 0,
+ FALSE, // bInheritHandle
+ DUPLICATE_SAME_ACCESS))
{
- //FIXME: requested base address ?!
- set_errno (EINVAL);
- return (void *) -1;
- }
+ syscall_printf (("failed to duplicate handle for client "
+ "[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"),
+ _ds.shm_perm.key, _shmid, _hFileMap);
- void *rv = MapViewOfFile (shm->attachmap,
+ return -EACCES; // FIXME: Case analysis?
+ }
+ _ds.shm_lpid = client->cygpid ();
+ _ds.shm_nattch += 1;
+ _ds.shm_atime = time (NULL); // FIXME: sub-second times.
- (parameters.in.shmflg & SHM_RDONLY) ?
- FILE_MAP_READ : FILE_MAP_WRITE, 0,
- 0, 0);
+ attach_t *previous = NULL;
+ attach_t *attptr = find (client, &previous);
- if (!rv)
+ if (!attptr)
{
- //FIXME: translate GetLastError()
- set_errno (EACCES);
- return (void *) -1;
+ attptr = safe_new (attach_t, client);
+
+ if (previous)
+ {
+ attptr->_next = previous->_next;
+ previous->_next = attptr;
+ }
+ else
+ {
+ attptr->_next = _attach_head;
+ _attach_head = attptr;
+ }
}
-/* FIXME: this needs to be globally protected to prevent a mismatch betwen
- * attach count and attachees list
- */
+ attptr->_refcnt += 1;
+
+ cleanup_t *const cleanup = safe_new (cleanup_t, this);
- InterlockedIncrement (&shm->shm_nattch);
- _shmattach *attachnode = new _shmattach;
+ // FIXME: ::add should only fail if the process object is already
+ // cleaning up; but it can't be doing that since this thread has it
+ // locked.
- attachnode->data = rv;
- attachnode->next =
- (_shmattach *) InterlockedExchangePointer ((LONG *) & shm->attachhead,
- (long int) attachnode);
- return rv;
+ const bool result = client->add (cleanup);
+
+ assert (result);
+
+ return 0;
}
-#endif
-
-/* FIXME: evaluate getuid() and getgid() against the requested mode. Then
- * choose PAGE_READWRITE | PAGE_READONLY and FILE_MAP_WRITE | FILE_MAP_READ
- * appropriately
- */
-
-/* Test result from openbsd: shm ids are persistent cross process if a handle is left
- * open. This could lead to resource starvation: we're not copying that behaviour
- * unless we have to. (It will involve acygwin1.dll gloal shared list :[ ).
- */
-/* FIXME: shmid should be a verifyable object
- */
-
-/* FIXME: on NT we should check everything against the SD. On 95 we just emulate.
- */
-
-extern GENERIC_MAPPING access_mapping;
-
-extern int
-check_and_dup_handle (HANDLE from_process, HANDLE to_process,
- HANDLE from_process_token,
- DWORD access,
- HANDLE from_handle,
- HANDLE * to_handle_ptr, BOOL bInheritHandle);
-
-//FIXME: where should this live
-static shmnode *shm_head = NULL;
-/* must be long for InterlockedIncrement */
-static long new_id = 0;
-static long new_private_key = 0;
-void
-client_request_shm::serve (transport_layer_base * conn,
- process_cache * cache)
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::segment_t::detach ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::segment_t::detach (class process *const client)
{
-// DWORD sd_size = 4096;
-// char sd_buf[4096];
- PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) parameters.in.sd_buf;
-// /* create a sd for our open requests based on shmflag & 0x01ff */
-// psd = alloc_sd (getuid (), getgid (), cygheap->user.logsrv (),
-// parameters.in.shmflg & 0x01ff, psd, &sd_size);
-
- HANDLE from_process_handle = NULL;
- HANDLE token_handle = NULL;
- DWORD rc;
-
- from_process_handle = cache->process (parameters.in.pid)->handle ();
- /* possible TODO: reduce the access on the handle before we use it */
- /* Note that unless we do this, we don't need to call CloseHandle - it's kept open
- * by the process cache until the process terminates.
- * We may need a refcount on the cache however...
- */
- if (!from_process_handle)
+ attach_t *previous = NULL;
+ attach_t *const attptr = find (client, &previous);
+
+ if (!attptr)
+ return -EINVAL;
+
+ if (client->is_active ())
{
- debug_printf ("error opening process (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- return;
+ const cleanup_t key (this);
+
+ if (!client->remove (&key))
+ syscall_printf (("failed to remove cleanup routine for %d(%lu) "
+ "[shmid = %d]"),
+ client->cygpid (), client->winpid (),
+ _shmid);
}
- conn->impersonate_client ();
+ attptr->_refcnt -= 1;
- rc = OpenThreadToken (GetCurrentThread (),
- TOKEN_QUERY, TRUE, &token_handle);
+ if (!attptr->_refcnt)
+ {
+ assert (previous ? previous->_next == attptr : _attach_head == attptr);
- conn->revert_to_self ();
+ if (previous)
+ previous->_next = attptr->_next;
+ else
+ _attach_head = attptr->_next;
- if (!rc)
- {
- debug_printf ("error opening thread token (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- CloseHandle (from_process_handle);
- return;
+ safe_delete (attptr);
}
+ assert (_ds.shm_nattch > 0);
- /* we trust the clients request - we will be doing it as them, and
- * the worst they can do is open their own permissions
- */
+ _ds.shm_lpid = client->cygpid ();
+ _ds.shm_nattch -= 1;
+ _ds.shm_dtime = time (NULL); // FIXME: sub-second times.
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::segment_t::find ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::attach_t *
+server_shmmgr::segment_t::find (const class process *const client,
+ attach_t **previous)
+{
+ if (previous)
+ *previous = NULL;
+
+ // Nb. The _attach_head list is sorted by winpid.
+
+ for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next)
+ if (attptr->_client == client)
+ return attptr;
+ else if (attptr->_client->winpid () > client->winpid ())
+ return NULL;
+ else if (previous)
+ *previous = attptr;
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::instance ()
+ *---------------------------------------------------------------------------*/
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof (sa);
- sa.lpSecurityDescriptor = psd;
- sa.bInheritHandle = TRUE; /* the memory structures inherit ok */
+/* static */ server_shmmgr &
+server_shmmgr::instance ()
+{
+ pthread_once (&_instance_once, &initialise_instance);
- char *shmname = NULL, *shmaname = NULL;
- char stringbuf[29], stringbuf1[29];
+ assert (_instance);
- /* TODO: make this code block a function! */
- if (parameters.in.type == SHM_REATTACH)
+ return *_instance;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmat ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::shmat (HANDLE & hFileMap,
+ const int shmid, const int shmflg,
+ class process *const client)
+{
+ syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",
+ shmid, shmflg, client->cygpid (), client->winpid ());
+
+ int result = 0;
+ EnterCriticalSection (&_segments_lock);
+
+ segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
+
+ if (!segptr)
+ result = -EINVAL;
+ else
+ result = segptr->attach (client, hFileMap);
+
+ if (!result)
+ _shm_atts += 1;
+
+ LeaveCriticalSection (&_segments_lock);
+
+ if (result < 0)
+ syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) "
+ "for %d(%lu)"),
+ -result, shmid, shmflg,
+ client->cygpid (), client->winpid ());
+ else
+ syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) "
+ "for %d(%lu)"),
+ hFileMap, shmid, shmflg,
+ client->cygpid (), client->winpid ());
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmctl ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::shmctl (int & out_shmid,
+ struct shmid_ds & out_ds,
+ struct shminfo & out_shminfo,
+ struct shm_info & out_shm_info,
+ const int shmid, const int cmd,
+ const struct shmid_ds & ds,
+ class process *const client)
+{
+ syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)",
+ shmid, cmd, client->cygpid (), client->winpid ());
+
+ int result = 0;
+ EnterCriticalSection (&_segments_lock);
+
+ switch (cmd)
{
- /* just find and fill out the existing shm_id */
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->shm_id == parameters.in.shm_id)
+ case IPC_STAT:
+ case SHM_STAT: // Uses intids rather than shmids.
+ case IPC_SET:
+ case IPC_RMID:
+ {
+ int intid;
+
+ if (cmd == SHM_STAT)
+ intid = shmid;
+ else
+ intid = ipc_ext2int (shmid, IPC_SHMOP);
+
+ segment_t *const segptr = find (intid);
+
+ if (!segptr)
+ result = -EINVAL;
+ else
+ switch (cmd)
{
- parameters.out.shm_id = tempnode->shm_id;
- parameters.out.key = tempnode->key;
- if (check_and_dup_handle
- (GetCurrentProcess (), from_process_handle, token_handle,
- DUPLICATE_SAME_ACCESS, tempnode->filemap,
- &parameters.out.filemap, TRUE) != 0)
- {
- debug_printf ("error duplicating filemap handle (%lu)\n",
- GetLastError ());
- header.error_code = EACCES;
- }
- if (check_and_dup_handle
- (GetCurrentProcess (), from_process_handle, token_handle,
- DUPLICATE_SAME_ACCESS, tempnode->attachmap,
- &parameters.out.attachmap, TRUE) != 0)
+ case IPC_STAT:
+ out_ds = segptr->_ds;
+ break;
+
+ case IPC_SET:
+ segptr->_ds.shm_perm.uid = ds.shm_perm.uid;
+ segptr->_ds.shm_perm.gid = ds.shm_perm.gid;
+ segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777;
+ segptr->_ds.shm_lpid = client->cygpid ();
+ segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
+ break;
+
+ case IPC_RMID:
+ if (segptr->is_deleted ())
+ result = -EIDRM;
+ else
{
- debug_printf ("error duplicating attachmap handle (%lu)\n",
- GetLastError ());
- header.error_code = EACCES;
+ segptr->mark_deleted ();
+ if (segptr->is_pending_delete ())
+ delete_segment (segptr);
}
- CloseHandle (token_handle);
- return;
+ break;
+
+ case SHM_STAT: // ipcs(8) i'face.
+ out_ds = segptr->_ds;
+ out_shmid = segptr->_shmid;
+ break;
}
- tempnode = tempnode->next;
- }
- header.error_code = EINVAL;
- CloseHandle (token_handle);
- return;
+ }
+ break;
+
+ case IPC_INFO:
+ out_shminfo.shmmax = SHMMAX;
+ out_shminfo.shmmin = SHMMIN;
+ out_shminfo.shmmni = SHMMNI;
+ out_shminfo.shmseg = SHMSEG;
+ out_shminfo.shmall = SHMALL;
+ break;
+
+ case SHM_INFO: // ipcs(8) i'face.
+ out_shmid = _intid_max;
+ out_shm_info.shm_ids = _shm_ids;
+ out_shm_info.shm_tot = _shm_tot;
+ out_shm_info.shm_atts = _shm_atts;
+ break;
+
+ default:
+ result = -EINVAL;
+ break;
}
- /* someone attached */
- /* someone can send shm_id's they don't have and currently we will increment those
- * attach counts. If someone wants to fix that, please go ahead.
- * The problem is that shm_get has nothing to do with the ability to attach. Attach
- * requires a permission check, which we get the OS to do in MapViewOfFile.
- */
- if (parameters.in.type == SHM_ATTACH)
- {
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->shm_id == parameters.in.shm_id)
- {
- InterlockedIncrement (&tempnode->shmds->shm_nattch);
- header.error_code = 0;
- CloseHandle (token_handle);
- return;
- }
- tempnode = tempnode->next;
- }
- header.error_code = EINVAL;
- CloseHandle (token_handle);
- return;
- }
+ LeaveCriticalSection (&_segments_lock);
- /* it's a original request from the users */
+ if (result < 0)
+ syscall_printf (("-1 [%d] = "
+ "shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
+ -result,
+ shmid, cmd, client->cygpid (), client->winpid ());
+ else
+ syscall_printf (("%d = "
+ "shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
+ ((cmd == SHM_STAT || cmd == SHM_INFO)
+ ? out_shmid
+ : result),
+ shmid, cmd, client->cygpid (), client->winpid ());
+
+ return result;
+}
- /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
- * to prevent races on shmget.
- */
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmdt ()
+ *---------------------------------------------------------------------------*/
- if (parameters.in.key == IPC_PRIVATE)
+int
+server_shmmgr::shmdt (const int shmid, class process *const client)
+{
+ syscall_printf ("shmdt (shmid = %d) for %d(%lu)",
+ shmid, client->cygpid (), client->winpid ());
+
+ int result = 0;
+ EnterCriticalSection (&_segments_lock);
+
+ segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
+
+ if (!segptr)
+ result = -EINVAL;
+ else
+ result = segptr->detach (client);
+
+ if (!result)
+ _shm_atts -= 1;
+
+ if (!result && segptr->is_pending_delete ())
+ delete_segment (segptr);
+
+ LeaveCriticalSection (&_segments_lock);
+
+ if (result < 0)
+ syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d(%lu)",
+ -result, shmid, client->cygpid (), client->winpid ());
+ else
+ syscall_printf ("%d = shmdt (shmid = %d) for %d(%lu)",
+ result, shmid, client->cygpid (), client->winpid ());
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::shmget ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::shmget (int & out_shmid,
+ const key_t key, const size_t size, const int shmflg,
+ const uid_t uid, const gid_t gid,
+ class process *const client)
+{
+ syscall_printf (("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
+ "for %d(%lu)"),
+ key, size, shmflg,
+ client->cygpid (), client->winpid ());
+
+ int result = 0;
+ EnterCriticalSection (&_segments_lock);
+
+ if (key == IPC_PRIVATE)
+ result = new_segment (key, size, shmflg,
+ client->cygpid (), uid, gid);
+ else
{
- /* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */
- /* The K refers to Key, the actual mapped area has D */
- long private_key = (int) InterlockedIncrement (&new_private_key);
- snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key);
- shmname = stringbuf;
- snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key);
- shmaname = stringbuf1;
+ segment_t *const segptr = find_by_key (key);
+
+ if (!segptr)
+ if (shmflg & IPC_CREAT)
+ result = new_segment (key, size, shmflg,
+ client->cygpid (), uid, gid);
+ else
+ result = -ENOENT;
+ else if (segptr->is_deleted ())
+ result = -EIDRM;
+ else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
+ result = -EEXIST;
+ else if ((shmflg & ~(segptr->_ds.shm_perm.mode)) & 0777)
+ result = -EACCES;
+ else if (size && segptr->_ds.shm_segsz < size)
+ result = -EINVAL;
+ else
+ result = segptr->_shmid;
}
- else
+
+ LeaveCriticalSection (&_segments_lock);
+
+ if (result >= 0)
{
- /* create the mapping name (CYGWINSHMK0x0123456789abcdef */
- /* The K refers to Key, the actual mapped area has D */
-
- snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key);
- shmname = stringbuf;
- snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key);
- shmaname = stringbuf1;
- debug_printf ("system id strings are \n%s\n%s\n", shmname, shmaname);
- debug_printf ("key input value is 0x%0qx\n", parameters.in.key);
+ out_shmid = result;
+ result = 0;
}
- /* attempt to open the key */
+ if (result < 0)
+ syscall_printf (("-1 [%d] = "
+ "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
+ "for %d(%lu)"),
+ -result,
+ key, size, shmflg,
+ client->cygpid (), client->winpid ());
+ else
+ syscall_printf (("%d = "
+ "shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
+ "for %d(%lu)"),
+ out_shmid,
+ key, size, shmflg,
+ client->cygpid (), client->winpid ());
+
+ return result;
+}
- /* get an existing key */
- /* On unix the same shmid identifier is returned on multiple calls to shm_get
- * with the same key and size. Different modes is a ?.
- */
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::initialise_instance ()
+ *---------------------------------------------------------------------------*/
+/* static */ void
+server_shmmgr::initialise_instance ()
+{
+ assert (!_instance);
+ _instance = safe_new0 (server_shmmgr);
- /* walk the list of known keys and return the id if found. remember, we are
- * authoritative...
- */
+ assert (_instance);
+}
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- if (tempnode->key == parameters.in.key
- && parameters.in.key != IPC_PRIVATE)
- {
- // FIXME: free the mutex
- if (parameters.in.size
- && tempnode->shmds->shm_segsz < parameters.in.size)
- {
- header.error_code = EINVAL;
- CloseHandle (token_handle);
- return;
- }
- /* FIXME: can the same process call this twice without error ? test
- * on unix
- */
- if ((parameters.in.shmflg & IPC_CREAT)
- && (parameters.in.shmflg & IPC_EXCL))
- {
- header.error_code = EEXIST;
- debug_printf
- ("attempt to exclusively create already created shm_area with key 0x%0qx\n",
- parameters.in.key);
- // FIXME: free the mutex
- CloseHandle (token_handle);
- return;
- }
- // FIXME: do we need to other tests of the requested mode with the
- // tempnode->shm_id mode ? testcase on unix needed.
- // FIXME how do we do the security test? or
- // do we wait for shmat to bother with that?
- /* One possibly solution: impersonate the client, and then test we can
- * reopen the area. In fact we'll probably have to do that to get
- * handles back to them, alternatively just tell them the id, and then
- * let them attempt the open.
- */
- parameters.out.shm_id = tempnode->shm_id;
- if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
- token_handle,
- DUPLICATE_SAME_ACCESS,
- tempnode->filemap,
- &parameters.out.filemap, TRUE) != 0)
- {
- printf ("error duplicating filemap handle (%lu)\n",
- GetLastError ());
- header.error_code = EACCES;
-/*mutex*/
- CloseHandle (token_handle);
- return;
- }
- if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
- token_handle,
- DUPLICATE_SAME_ACCESS,
- tempnode->attachmap,
- &parameters.out.attachmap, TRUE) != 0)
- {
- printf ("error duplicating attachmap handle (%lu)\n",
- GetLastError ());
- header.error_code = EACCES;
-/*mutex*/
- CloseHandle (token_handle);
- return;
- }
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::server_shmmgr ()
+ *---------------------------------------------------------------------------*/
- CloseHandle (token_handle);
- return;
- }
- tempnode = tempnode->next;
- }
- /* couldn't find a currently open shm area. */
+server_shmmgr::server_shmmgr ()
+ : _segments_head (NULL),
+ _shm_ids (0),
+ _shm_tot (0),
+ _shm_atts (0),
+ _intid_max (0)
+{
+ InitializeCriticalSection (&_segments_lock);
+}
- /* create one */
- /* do this as the client */
- conn->impersonate_client ();
- /* This may need sh_none... it's only a control structure */
- HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile.
- &sa,
- PAGE_READWRITE, // protection
- 0x00000000,
- getsystemallocgranularity (),
- shmname // object name
- );
- int lasterr = GetLastError ();
- conn->revert_to_self ();
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::~server_shmmgr ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::~server_shmmgr ()
+{
+ DeleteCriticalSection (&_segments_lock);
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::find_by_key ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::segment_t *
+server_shmmgr::find_by_key (const key_t key)
+{
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
+ if (segptr->_ds.shm_perm.key == key)
+ return segptr;
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::find ()
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::segment_t *
+server_shmmgr::find (const int intid, segment_t **previous)
+{
+ if (previous)
+ *previous = NULL;
+
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
+ if (segptr->_intid == intid)
+ return segptr;
+ else if (segptr->_intid > intid) // The list is sorted by intid.
+ return NULL;
+ else if (previous)
+ *previous = segptr;
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::new_segment ()
+ *---------------------------------------------------------------------------*/
+
+int
+server_shmmgr::new_segment (const key_t key,
+ const size_t size,
+ const int shmflg,
+ const pid_t cygpid,
+ const uid_t uid,
+ const gid_t gid)
+{
+ if (size < SHMMIN || size > SHMMAX)
+ return -EINVAL;
+
+ const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE,
+ NULL, PAGE_READWRITE,
+ 0, size,
+ NULL);
- if (filemap == NULL)
+ if (!hFileMap)
{
- /* We failed to open the filemapping ? */
- system_printf ("failed to open file mapping: %lu\n", GetLastError ());
- // free the mutex
- // we can assume that it exists, and that it was an access problem.
- header.error_code = EACCES;
- CloseHandle (token_handle);
- return;
+ syscall_printf ("failed to create file mapping [size = %lu]: %E", size);
+ return -ENOMEM; // FIXME
}
- /* successfully opened the control region mapping */
- /* did we create it ? */
- int oldmapping = lasterr == ERROR_ALREADY_EXISTS;
- if (oldmapping)
+ segment_t *const segptr = new_segment (key, size, hFileMap);
+
+ if (!segptr)
{
- /* should never happen - we are the global daemon! */
-#if 0
- if ((parameters.in.shmflg & IPC_CREAT)
- && (parameters.in.shmflg & IPC_EXCL))
-#endif
- {
- /* FIXME free mutex */
- CloseHandle (filemap);
- header.error_code = EEXIST;
- CloseHandle (token_handle);
- return;
- }
+ (void) CloseHandle (hFileMap);
+ return -ENOSPC;
}
- /* we created a new mapping */
- if (parameters.in.key != IPC_PRIVATE &&
- (parameters.in.shmflg & IPC_CREAT) == 0)
+ segptr->_ds.shm_perm.cuid = segptr->_ds.shm_perm.uid = uid;
+ segptr->_ds.shm_perm.cgid = segptr->_ds.shm_perm.gid = gid;
+ segptr->_ds.shm_perm.mode = shmflg & 0777;
+ segptr->_ds.shm_segsz = size;
+ segptr->_ds.shm_cpid = cygpid;
+ segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
+
+ return segptr->_shmid;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::new_segment ()
+ *
+ * Allocate a new segment for the given key and file map with the
+ * lowest available intid and insert into the segment map.
+ *---------------------------------------------------------------------------*/
+
+server_shmmgr::segment_t *
+server_shmmgr::new_segment (const key_t key, const size_t size,
+ const HANDLE hFileMap)
+{
+ // FIXME: Overflow risk.
+ if (_shm_tot + size > SHMALL)
+ return NULL;
+
+ int intid = 0; // Next expected intid value.
+ segment_t *previous = NULL; // Insert pointer.
+
+ // Find first unallocated intid.
+ for (segment_t *segptr = _segments_head;
+ segptr && segptr->_intid == intid;
+ segptr = segptr->_next, intid++)
{
- CloseHandle (filemap);
- /* FIXME free mutex */
- header.error_code = ENOENT;
- CloseHandle (token_handle);
- return;
+ previous = segptr;
}
- conn->impersonate_client ();
- void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0);
- conn->revert_to_self ();
+ /* By the time this condition is reached (given the default value of
+ * SHMMNI), the linear searches should all replaced by something
+ * just a *little* cleverer . . .
+ */
+ if (intid >= SHMMNI)
+ return NULL;
+
+ segment_t *const segptr = safe_new (segment_t, key, intid, hFileMap);
- if (!mapptr)
+ assert (segptr);
+
+ if (previous)
{
- CloseHandle (filemap);
- //FIXME: close filemap and free the mutex
- /* we couldn't access the mapped area with the requested permissions */
- header.error_code = EACCES;
- CloseHandle (token_handle);
- return;
+ segptr->_next = previous->_next;
+ previous->_next = segptr;
+ }
+ else
+ {
+ segptr->_next = _segments_head;
+ _segments_head = segptr;
}
- conn->impersonate_client ();
- /* Now get the user data */
- HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile
- &sa,
- PAGE_READWRITE, // protection (FIXME)
- 0x00000000,
- parameters.in.size +
- parameters.in.size %
- getsystemallocgranularity (),
- shmaname // object name
- );
- conn->revert_to_self ();
+ _shm_ids += 1;
+ _shm_tot += size;
+ if (intid > _intid_max)
+ _intid_max = intid;
+
+ return segptr;
+}
+
+/*---------------------------------------------------------------------------*
+ * server_shmmgr::delete_segment ()
+ *---------------------------------------------------------------------------*/
+
+void
+server_shmmgr::delete_segment (segment_t *const segptr)
+{
+ assert (segptr);
+ assert (segptr->is_pending_delete ());
+
+ segment_t *previous = NULL;
+
+ const segment_t *const tmp = find (segptr->_intid, &previous);
+
+ assert (tmp == segptr);
+ assert (previous ? previous->_next == segptr : _segments_head == segptr);
+
+ if (previous)
+ previous->_next = segptr->_next;
+ else
+ _segments_head = segptr->_next;
+
+ assert (_shm_ids > 0);
+ _shm_ids -= 1;
+ _shm_tot -= segptr->_ds.shm_segsz;
+
+ safe_delete (segptr);
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm ()
+ : client_request (CYGSERVER_REQUEST_SHM,
+ &_parameters, sizeof (_parameters))
+{
+ // verbose: syscall_printf ("created");
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::serve ()
+ *---------------------------------------------------------------------------*/
- if (attachmap == NULL)
+void
+client_request_shm::serve (transport_layer_base *const conn,
+ process_cache *const cache)
+{
+ assert (conn);
+
+ assert (!error_code ());
+
+ if (msglen () != sizeof (_parameters.in))
{
- system_printf ("failed to get shm attachmap\n");
- header.error_code = ENOMEM;
- UnmapViewOfFile (mapptr);
- CloseHandle (filemap);
- /* FIXME exit the mutex */
- CloseHandle (token_handle);
+ syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
+ sizeof (_parameters), msglen ());
+ error_code (EINVAL);
+ msglen (0);
return;
}
- shmid_ds *shmtemp = new shmid_ds;
- if (!shmtemp)
+ // FIXME: Get a return code out of this and don't continue on error.
+ conn->impersonate_client ();
+
+ class process *const client = cache->process (_parameters.in.cygpid,
+ _parameters.in.winpid);
+
+ if (!client)
{
- system_printf ("failed to malloc shm node\n");
- header.error_code = ENOMEM;
- UnmapViewOfFile (mapptr);
- CloseHandle (filemap);
- CloseHandle (attachmap);
- /* FIXME exit mutex */
- CloseHandle (token_handle);
+ error_code (EAGAIN);
+ msglen (0);
return;
}
- /* fill out the node data */
- shmtemp->shm_perm.cuid = getuid ();
- shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid;
- shmtemp->shm_perm.cgid = getgid ();
- shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid;
- shmtemp->shm_perm.mode = parameters.in.shmflg & 0x01ff;
- shmtemp->shm_lpid = 0;
- shmtemp->shm_nattch = 0;
- shmtemp->shm_atime = 0;
- shmtemp->shm_dtime = 0;
- shmtemp->shm_ctime = time (NULL);
- shmtemp->shm_segsz = parameters.in.size;
- *(shmid_ds *) mapptr = *shmtemp;
- shmtemp->mapptr = mapptr;
-
- /* no need for InterlockedExchange here, we're serialised by the global mutex */
- tempnode = new shmnode;
- tempnode->shmds = shmtemp;
- tempnode->shm_id = (int) InterlockedIncrement (&new_id);
- tempnode->key = parameters.in.key;
- tempnode->filemap = filemap;
- tempnode->attachmap = attachmap;
- tempnode->next = shm_head;
- shm_head = tempnode;
-
- /* we now have the area in the daemon list, opened.
-
- FIXME: leave the system wide shm mutex */
-
- parameters.out.shm_id = tempnode->shm_id;
- if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
- token_handle,
- DUPLICATE_SAME_ACCESS,
- tempnode->filemap, &parameters.out.filemap,
- TRUE) != 0)
+ int result = -EINVAL;
+
+ switch (_parameters.in.shmop)
{
- printf ("error duplicating filemap handle (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- CloseHandle (token_handle);
-/* mutex et al */
- return;
+ case SHMOP_shmget:
+ result = shmmgr.shmget (_parameters.out.shmid,
+ _parameters.in.key, _parameters.in.size,
+ _parameters.in.shmflg,
+ _parameters.in.uid, _parameters.in.gid,
+ client);
+ break;
+
+ case SHMOP_shmat:
+ result = shmmgr.shmat (_parameters.out.hFileMap,
+ _parameters.in.shmid, _parameters.in.shmflg,
+ client);
+ break;
+
+ case SHMOP_shmdt:
+ result = shmmgr.shmdt (_parameters.in.shmid, client);
+ break;
+
+ case SHMOP_shmctl:
+ result = shmmgr.shmctl (_parameters.out.shmid,
+ _parameters.out.ds, _parameters.out.shminfo,
+ _parameters.out.shm_info,
+ _parameters.in.shmid, _parameters.in.cmd,
+ _parameters.in.ds,
+ client);
+ break;
}
- if (check_and_dup_handle (GetCurrentProcess (), from_process_handle,
- token_handle,
- DUPLICATE_SAME_ACCESS,
- tempnode->attachmap, &parameters.out.attachmap,
- TRUE) != 0)
+
+ client->release ();
+ conn->revert_to_self ();
+
+ if (result < 0)
{
- printf ("error duplicating attachmap handle (%lu)\n", GetLastError ());
- header.error_code = EACCES;
- CloseHandle (from_process_handle);
- CloseHandle (token_handle);
-/* more cleanup... yay! */
- return;
+ error_code (-result);
+ msglen (0);
}
- CloseHandle (token_handle);
- return;
+ else
+ msglen (sizeof (_parameters.out));
}
diff --git a/winsup/cygwin/cygserver_shm.h b/winsup/cygwin/cygserver_shm.h
index 32947f8ec..b1ff353da 100644
--- a/winsup/cygwin/cygserver_shm.h
+++ b/winsup/cygwin/cygserver_shm.h
@@ -1,7 +1,9 @@
-/* cygserver_shm.h
+/* cygserver_shm.h: Single unix specification IPC interface for Cygwin.
- Copyright 2001 Red Hat Inc.
- Written by Robert Collins <rbtcollins@hotmail.com>
+ Copyright 2002 Red Hat, Inc.
+
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+ Based on code by Robert Collins <robert.collins@hotmail.com>.
This file is part of Cygwin.
@@ -9,83 +11,137 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#ifndef __CYGSERVER_SHM_H__
+#define __CYGSERVER_SHM_H__
+
#include <sys/types.h>
-#include "cygwin/cygserver_transport.h"
+#include <cygwin/shm.h>
+
+#include <assert.h>
+#include <limits.h>
+
+#include "cygserver_ipc.h"
+
#include "cygwin/cygserver.h"
-#define SHM_CREATE 0
-#define SHM_REATTACH 1
-#define SHM_ATTACH 2
-#define SHM_DETACH 3
+/*---------------------------------------------------------------------------*
+ * Values for the shminfo entries.
+ *
+ * Nb. The values are segregated between two enums so that the `small'
+ * values aren't promoted to `unsigned long' equivalents.
+ *---------------------------------------------------------------------------*/
+enum
+ {
+ SHMMAX = ULONG_MAX,
+ SHMSEG = ULONG_MAX,
+ SHMALL = ULONG_MAX
+ };
+
+enum
+ {
+ SHMMIN = 1,
+ SHMMNI = IPCMNI // Must be <= IPCMNI.
+ };
+
+/*---------------------------------------------------------------------------*
+ * class client_request_shm
+ *---------------------------------------------------------------------------*/
-class client_request_shm : public client_request
-{
- public:
#ifndef __INSIDE_CYGWIN__
- virtual void serve (transport_layer_base *conn, process_cache *cache);
+class transport_layer_base;
+class process_cache;
#endif
- client_request_shm (key_t, size_t, int, char psdbuf[4096], pid_t);
- client_request_shm ();
- client_request_shm (int, int, pid_t);
- client_request_shm (int, int);
- union {
- struct {int type; pid_t pid; int shm_id; key_t key; size_t size; int shmflg; char sd_buf[4096];} in;
- struct {int shm_id; HANDLE filemap; HANDLE attachmap; key_t key;} out;
- } parameters;
-};
-#ifndef __INSIDE_CYGWIN__
-class shm_cleanup : cleanup_routine
+class client_request_shm : public client_request
{
+ friend class client_request;
+
public:
- virtual void cleanup (long winpid);
-};
+ enum shmop_t
+ {
+ SHMOP_shmat,
+ SHMOP_shmctl,
+ SHMOP_shmdt,
+ SHMOP_shmget
+ };
+
+#ifdef __INSIDE_CYGWIN__
+ client_request_shm (int shmid, int shmflg); // shmat
+ client_request_shm (int shmid, int cmd, const struct shmid_ds *); // shmctl
+ client_request_shm (int shmid); // shmdt
+ client_request_shm (key_t, size_t, int shmflg); // shmget
#endif
-#if 0
-class _shmattach {
-public:
- void *data;
- class _shmattach *next;
-};
-class shmid_ds {
-public:
- struct ipc_perm shm_perm;
- size_t shm_segsz;
- pid_t shm_lpid;
- pid_t shm_cpid;
- shmatt_t shm_nattch;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
- HANDLE filemap;
- HANDLE attachmap;
- void *mapptr;
- class _shmattach *attachhead;
-};
+ // Accessors for out parameters.
-class shmnode {
-public:
- class shmid_ds * shmid;
- class shmnode *next;
- key_t key;
-};
-//....
-struct shmid_ds {
- struct ipc_perm shm_perm;
- size_t shm_segsz;
- pid_t shm_lpid;
- pid_t shm_cpid;
- shmatt_t shm_nattch;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
-};
+ int shmid () const
+ {
+ assert (!error_code ());
+ return _parameters.out.shmid;
+ }
+
+ HANDLE hFileMap () const
+ {
+ assert (!error_code ());
+ return _parameters.out.hFileMap;
+ }
+
+ const struct shmid_ds & ds () const
+ {
+ assert (!error_code ());
+ return _parameters.out.ds;
+ }
+
+ const struct shminfo & shminfo () const
+ {
+ assert (!error_code ());
+ return _parameters.out.shminfo;
+ }
+
+ const struct shm_info & shm_info () const
+ {
+ assert (!error_code ());
+ return _parameters.out.shm_info;
+ }
-void *shmat(int, const void *, int);
-int shmctl(int, int, struct shmid_ds *);
-int shmdt(const void *);
-int shmget(key_t, size_t, int);
+private:
+ union
+ {
+ struct
+ {
+ shmop_t shmop;
+ key_t key;
+ size_t size;
+ int shmflg;
+ int shmid;
+ int cmd;
+ pid_t cygpid;
+ DWORD winpid;
+ uid_t uid;
+ gid_t gid;
+ struct shmid_ds ds;
+ } in;
+ struct {
+ int shmid;
+ union
+ {
+ HANDLE hFileMap;
+ struct shmid_ds ds;
+ struct shminfo shminfo;
+ struct shm_info shm_info;
+ };
+ } out;
+ } _parameters;
+
+#ifndef __INSIDE_CYGWIN__
+ client_request_shm ();
+#endif
+
+#ifndef __INSIDE_CYGWIN__
+ virtual void serve (transport_layer_base *, process_cache *);
#endif
+};
+
+#endif /* __CYGSERVER_SHM_H__ */
diff --git a/winsup/cygwin/cygserver_transport.cc b/winsup/cygwin/cygserver_transport.cc
index 7c6e5fe00..8684a6148 100755
--- a/winsup/cygwin/cygserver_transport.cc
+++ b/winsup/cygwin/cygserver_transport.cc
@@ -1,92 +1,51 @@
/* cygserver_transport.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* to allow this to link into cygwin and the .dll, a little magic is needed. */
+#ifdef __OUTSIDE_CYGWIN__
+#include "woutsup.h"
+#else
+#include "winsup.h"
+#endif
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <windows.h>
-#include <sys/types.h>
#include <sys/socket.h>
-#include <netdb.h>
-#include "wincap.h"
+
+#include "safe_memory.h"
+
#include "cygwin/cygserver_transport.h"
#include "cygwin/cygserver_transport_pipes.h"
#include "cygwin/cygserver_transport_sockets.h"
-/* to allow this to link into cygwin and the .dll, a little magic is needed. */
-#ifndef __OUTSIDE_CYGWIN__
-#include "winsup.h"
-#else
-#define debug_printf printf
-#endif
-
/* The factory */
-class transport_layer_base *create_server_transport()
+transport_layer_base *
+create_server_transport ()
{
- transport_layer_base *temp;
- /* currently there is only the base class! */
if (wincap.is_winnt ())
- temp = new transport_layer_pipes ();
+ return safe_new0 (transport_layer_pipes);
else
- temp = new transport_layer_base ();
- return temp;
+ return safe_new0 (transport_layer_sockets);
}
-
-transport_layer_base::transport_layer_base ()
-{
- /* should we throw an error of some sort ? */
-}
-
-void
-transport_layer_base::listen ()
-{
-}
-
-class transport_layer_base *
-transport_layer_base::accept ()
-{
- return NULL;
-}
-
-void
-transport_layer_base::close()
-{
-}
-
-ssize_t
-transport_layer_base::read (char *buf, size_t len)
-{
- return 0;
-}
-
-ssize_t
-transport_layer_base::write (char *buf, size_t len)
-{
- return 0;
-}
-
-bool
-transport_layer_base::connect ()
-{
- return false;
-}
+#ifndef __INSIDE_CYGWIN__
void
transport_layer_base::impersonate_client ()
-{
-}
+{}
void
transport_layer_base::revert_to_self ()
-{
-}
+{}
+
+#endif /* !__INSIDE_CYGWIN__ */
+
+transport_layer_base::~transport_layer_base ()
+{}
diff --git a/winsup/cygwin/cygserver_transport_pipes.cc b/winsup/cygwin/cygserver_transport_pipes.cc
index d9accce1e..f318a7592 100755
--- a/winsup/cygwin/cygserver_transport_pipes.cc
+++ b/winsup/cygwin/cygserver_transport_pipes.cc
@@ -1,197 +1,363 @@
/* cygserver_transport_pipes.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* to allow this to link into cygwin and the .dll, a little magic is needed. */
+#ifdef __OUTSIDE_CYGWIN__
+#include "woutsup.h"
+#else
+#include "winsup.h"
+#endif
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <windows.h>
#include <sys/types.h>
-#include <sys/socket.h>
+
+#include <assert.h>
+#include <errno.h>
#include <netdb.h>
-#include "wincap.h"
+#include <pthread.h>
+#include <unistd.h>
+
+#include "cygerrno.h"
#include "cygwin/cygserver_transport.h"
#include "cygwin/cygserver_transport_pipes.h"
-/* to allow this to link into cygwin and the .dll, a little magic is needed. */
-#ifndef __OUTSIDE_CYGWIN__
-#include "winsup.h"
-#else
-#define DEBUG 0
-#define debug_printf if (DEBUG) printf
+#ifndef __INSIDE_CYGWIN__
+#include "cygwin/cygserver.h"
#endif
-transport_layer_pipes::transport_layer_pipes (HANDLE new_pipe)
+enum
+ {
+ MAX_WAIT_NAMED_PIPE_RETRY = 64,
+ WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds
+ };
+
+#ifndef __INSIDE_CYGWIN__
+
+static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT;
+static CRITICAL_SECTION pipe_instance_lock;
+static long pipe_instance = 0;
+
+static void
+initialise_pipe_instance_lock ()
{
- pipe = new_pipe;
- if (inited != true)
- init_security();
-};
+ assert (pipe_instance == 0);
+ InitializeCriticalSection (&pipe_instance_lock);
+}
+
+#endif /* !__INSIDE_CYGWIN__ */
+
+#ifndef __INSIDE_CYGWIN__
-transport_layer_pipes::transport_layer_pipes ()
+transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
+ : _pipe_name (""),
+ _hPipe (hPipe),
+ _is_accepted_endpoint (true),
+ _is_listening_endpoint (false)
{
- pipe = NULL;
- strcpy(pipe_name, "\\\\.\\pipe\\cygwin_lpc");
- if (inited != true)
- init_security();
+ assert (_hPipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
+
+ init_security ();
}
+#endif /* !__INSIDE_CYGWIN__ */
+
+transport_layer_pipes::transport_layer_pipes ()
+ : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"),
+ _hPipe (NULL),
+ _is_accepted_endpoint (false),
+ _is_listening_endpoint (false)
+{
+ init_security ();
+}
void
-transport_layer_pipes::init_security()
+transport_layer_pipes::init_security ()
{
+ assert (wincap.has_security ());
+
/* FIXME: pthread_once or equivalent needed */
- InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
- SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
-
- sec_none_nih.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
- sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE;
- sec_none_nih.lpSecurityDescriptor = NULL;
- sec_all_nih.lpSecurityDescriptor = &sd;
- inited = true;
+
+ InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE);
+
+ _sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
+ _sec_all_nih.lpSecurityDescriptor = &_sd;
+ _sec_all_nih.bInheritHandle = FALSE;
}
-void
+transport_layer_pipes::~transport_layer_pipes ()
+{
+ close ();
+}
+
+#ifndef __INSIDE_CYGWIN__
+
+int
transport_layer_pipes::listen ()
{
+ assert (!_hPipe);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
+
+ _is_listening_endpoint = true;
+
/* no-op */
+ return 0;
}
class transport_layer_pipes *
-transport_layer_pipes::accept ()
+transport_layer_pipes::accept (bool *const recoverable)
{
- if (pipe)
+ assert (!_hPipe);
+ assert (!_is_accepted_endpoint);
+ assert (_is_listening_endpoint);
+
+ pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock);
+
+ EnterCriticalSection (&pipe_instance_lock);
+
+ // Read: http://www.securityinternals.com/research/papers/namedpipe.php
+ // See also the Microsoft security bulletins MS00-053 and MS01-031.
+
+ // FIXME: Remove FILE_CREATE_PIPE_INSTANCE.
+
+ const bool first_instance = (pipe_instance == 0);
+
+ const HANDLE accept_pipe =
+ CreateNamedPipe (_pipe_name,
+ (PIPE_ACCESS_DUPLEX
+ | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)),
+ (PIPE_TYPE_BYTE | PIPE_WAIT),
+ PIPE_UNLIMITED_INSTANCES,
+ 0, 0, 1000,
+ &_sec_all_nih);
+
+ const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
+ && pipe_instance == 0
+ && GetLastError () == ERROR_ACCESS_DENIED);
+
+ if (accept_pipe != INVALID_HANDLE_VALUE)
+ InterlockedIncrement (&pipe_instance);
+
+ LeaveCriticalSection (&pipe_instance_lock);
+
+ if (duplicate)
{
- debug_printf ("Already have a pipe in this %p\n",this);
+ *recoverable = false;
+ system_printf ("failed to create named pipe: "
+ "is the daemon already running?");
return NULL;
}
- pipe = CreateNamedPipe (pipe_name,
- PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- 0, 0, 1000,
- &sec_all_nih );
- if (pipe == INVALID_HANDLE_VALUE)
+ if (accept_pipe == INVALID_HANDLE_VALUE)
{
- debug_printf ("error creating pipe (%lu)\n.", GetLastError ());
+ debug_printf ("error creating pipe (%lu).", GetLastError ());
+ *recoverable = true; // FIXME: case analysis?
return NULL;
}
- if ( !ConnectNamedPipe ( pipe, NULL ) &&
- GetLastError () != ERROR_PIPE_CONNECTED)
+ assert (accept_pipe);
+
+ if (!ConnectNamedPipe (accept_pipe, NULL)
+ && GetLastError () != ERROR_PIPE_CONNECTED)
{
- printf ("error connecting to pipe (%lu)\n.", GetLastError ());
- CloseHandle (pipe);
- pipe = NULL;
+ debug_printf ("error connecting to pipe (%lu)\n.", GetLastError ());
+ (void) CloseHandle (accept_pipe);
+ *recoverable = true; // FIXME: case analysis?
return NULL;
}
-
- transport_layer_pipes *new_conn = new transport_layer_pipes (pipe);
- pipe = NULL;
- return new_conn;
+ return safe_new (transport_layer_pipes, accept_pipe);
}
+#endif /* !__INSIDE_CYGWIN__ */
+
void
-transport_layer_pipes::close()
+transport_layer_pipes::close ()
{
- if (pipe && pipe != INVALID_HANDLE_VALUE)
+ // verbose: debug_printf ("closing pipe %p", _hPipe);
+
+ if (_hPipe)
{
- FlushFileBuffers (pipe);
- DisconnectNamedPipe (pipe);
- CloseHandle (pipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
+
+#ifndef __INSIDE_CYGWIN__
+
+ if (_is_accepted_endpoint)
+ {
+ (void) FlushFileBuffers (_hPipe); // Blocks until client reads.
+ (void) DisconnectNamedPipe (_hPipe);
+ EnterCriticalSection (&pipe_instance_lock);
+ (void) CloseHandle (_hPipe);
+ assert (pipe_instance > 0);
+ InterlockedDecrement (&pipe_instance);
+ LeaveCriticalSection (&pipe_instance_lock);
+ }
+ else
+ (void) CloseHandle (_hPipe);
+
+#else /* __INSIDE_CYGWIN__ */
+
+ assert (!_is_accepted_endpoint);
+ (void) ForceCloseHandle (_hPipe);
+
+#endif /* __INSIDE_CYGWIN__ */
+
+ _hPipe = NULL;
}
}
ssize_t
-transport_layer_pipes::read (char *buf, size_t len)
+transport_layer_pipes::read (void *const buf, const size_t len)
{
- DWORD bytes_read, rc;
- if (!pipe || pipe == INVALID_HANDLE_VALUE)
- return -1;
+ // verbose: debug_printf ("reading from pipe %p", _hPipe);
+
+ assert (_hPipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
+ assert (!_is_listening_endpoint);
- rc = ReadFile (pipe, buf, len, &bytes_read, NULL);
- if (!rc)
+ DWORD count;
+ if (!ReadFile (_hPipe, buf, len, &count, NULL))
{
- debug_printf ("error reading from pipe (%lu)\n", GetLastError ());
+ debug_printf ("error reading from pipe (%lu)", GetLastError ());
+ set_errno (EINVAL); // FIXME?
return -1;
}
- return bytes_read;
+
+ return count;
}
ssize_t
-transport_layer_pipes::write (char *buf, size_t len)
+transport_layer_pipes::write (void *const buf, const size_t len)
{
- DWORD bytes_written, rc;
- if (!pipe || pipe == INVALID_HANDLE_VALUE)
- return -1;
+ // verbose: debug_printf ("writing to pipe %p", _hPipe);
+
+ assert (_hPipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
+ assert (!_is_listening_endpoint);
- rc = WriteFile (pipe, buf, len, &bytes_written, NULL);
- if (!rc)
+ DWORD count;
+ if (!WriteFile (_hPipe, buf, len, &count, NULL))
{
- debug_printf ("error writing to pipe (%lu)\n", GetLastError ());
+ debug_printf ("error writing to pipe, error = %lu", GetLastError ());
+ set_errno (EINVAL); // FIXME?
return -1;
}
- return bytes_written;
+
+ return count;
}
-bool
+/*
+ * This routine holds a static variable, assume_cygserver, that is set
+ * if the transport has good reason to think that cygserver is
+ * running, i.e. if if successfully connected to it with the previous
+ * attempt. If this is set, the code tries a lot harder to get a
+ * connection, making the assumption that any failures are just
+ * congestion and overloading problems.
+ */
+
+int
transport_layer_pipes::connect ()
{
- if (pipe && pipe != INVALID_HANDLE_VALUE)
- {
- debug_printf ("Already have a pipe in this %p\n",this);
- return false;
- }
+ assert (!_hPipe);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
+
+ static bool assume_cygserver = false;
+
+ BOOL rc = TRUE;
+ int retries = 0;
- while (1)
+ while (rc)
{
- pipe = CreateFile (pipe_name,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_all_nih,
- OPEN_EXISTING,
- 0, NULL);
-
- if (pipe != INVALID_HANDLE_VALUE)
- /* got the pipe */
- return true;
-
- if (GetLastError () != ERROR_PIPE_BUSY)
- {
- debug_printf ("Error opening the pipe (%lu)\n", GetLastError ());
- pipe = NULL;
- return false;
- }
- if (!WaitNamedPipe (pipe_name, 20000))
- debug_printf ( "error connecting to server pipe after 20 seconds (%lu)\n", GetLastError () );
- /* We loop here, because the pipe exists but is busy. If it doesn't exist
- * the != ERROR_PIPE_BUSY will catch it.
- */
+ _hPipe = CreateFile (_pipe_name,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &_sec_all_nih,
+ OPEN_EXISTING,
+ SECURITY_IMPERSONATION,
+ NULL);
+
+ if (_hPipe != INVALID_HANDLE_VALUE)
+ {
+ assert (_hPipe);
+#ifdef __INSIDE_CYGWIN__
+ ProtectHandle (_hPipe);
+#endif
+ assume_cygserver = true;
+ return 0;
+ }
+
+ _hPipe = NULL;
+
+ if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY)
+ {
+ debug_printf ("Error opening the pipe (%lu)", GetLastError ());
+ return -1;
+ }
+
+ /* Note: `If no instances of the specified named pipe exist, the
+ * WaitNamedPipe function returns immediately, regardless of the
+ * time-out value.' Thus the explicit Sleep if the call fails
+ * with ERROR_FILE_NOT_FOUND.
+ */
+ while (retries != MAX_WAIT_NAMED_PIPE_RETRY
+ && !(rc = WaitNamedPipe (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT)))
+ {
+ if (GetLastError () == ERROR_FILE_NOT_FOUND)
+ Sleep (0); // Give the server a chance.
+
+ retries += 1;
+ }
}
+
+ assert (retries == MAX_WAIT_NAMED_PIPE_RETRY);
+
+ system_printf ("lost connection to cygserver, error = %lu",
+ GetLastError ());
+
+ assume_cygserver = false;
+
+ return -1;
}
+#ifndef __INSIDE_CYGWIN__
+
void
transport_layer_pipes::impersonate_client ()
{
- if (pipe && pipe != INVALID_HANDLE_VALUE)
- ImpersonateNamedPipeClient (pipe);
- debug_printf("I am who you are\n");
+ assert (_hPipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
+ assert (_is_accepted_endpoint);
+
+ // verbose: debug_printf ("impersonating pipe %p", _hPipe);
+ if (_hPipe)
+ {
+ assert (_hPipe != INVALID_HANDLE_VALUE);
+
+ if (!ImpersonateNamedPipeClient (_hPipe))
+ debug_printf ("Failed to Impersonate the client, (%lu)",
+ GetLastError ());
+ }
+ // verbose: debug_printf ("I am who you are");
}
void
transport_layer_pipes::revert_to_self ()
{
- RevertToSelf ();
- debug_printf("I am who I yam\n");
+ assert (_is_accepted_endpoint);
+
+ RevertToSelf ();
+ // verbose: debug_printf ("I am who I yam");
}
+#endif /* !__INSIDE_CYGWIN__ */
diff --git a/winsup/cygwin/cygserver_transport_sockets.cc b/winsup/cygwin/cygserver_transport_sockets.cc
index 6b75365b4..6ade14bff 100755
--- a/winsup/cygwin/cygserver_transport_sockets.cc
+++ b/winsup/cygwin/cygserver_transport_sockets.cc
@@ -1,131 +1,387 @@
/* cygserver_transport_sockets.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+/* to allow this to link into cygwin and the .dll, a little magic is needed. */
+#ifdef __OUTSIDE_CYGWIN__
+#include "woutsup.h"
+#else
+#include "winsup.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include "wincap.h"
+
#include "cygwin/cygserver_transport.h"
#include "cygwin/cygserver_transport_sockets.h"
/* to allow this to link into cygwin and the .dll, a little magic is needed. */
#ifndef __OUTSIDE_CYGWIN__
-#include "winsup.h"
-extern "C" int
-cygwin_socket (int af, int type, int protocol);
-extern "C" int
-cygwin_connect (int fd,
- const struct sockaddr *name,
- int namelen);
-extern "C" int
-cygwin_accept (int fd, struct sockaddr *peer, int *len);
-extern "C" int
-cygwin_listen (int fd, int backlog);
-extern "C" int
-cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen);
-#else
-#define cygwin_accept(A,B,C) ::accept(A,B,C)
-#define cygwin_socket(A,B,C) ::socket(A,B,C)
-#define cygwin_listen(A,B) ::listen(A,B)
-#define cygwin_bind(A,B,C) ::bind(A,B,C)
-#define cygwin_connect(A,B,C) ::connect(A,B,C)
-#define debug_printf printf
-#endif
+extern "C" int cygwin_accept (int fd, struct sockaddr *, int *len);
+extern "C" int cygwin_bind (int fd, const struct sockaddr *, int len);
+extern "C" int cygwin_connect (int fd, const struct sockaddr *, int len);
+extern "C" int cygwin_listen (int fd, int backlog);
+extern "C" int cygwin_shutdown (int fd, int how);
+extern "C" int cygwin_socket (int af, int type, int protocol);
+
+#else /* __OUTSIDE_CYGWIN__ */
+
+#define cygwin_accept(A,B,C) ::accept (A,B,C)
+#define cygwin_bind(A,B,C) ::bind (A,B,C)
+#define cygwin_connect(A,B,C) ::connect (A,B,C)
+#define cygwin_listen(A,B) ::listen (A,B)
+#define cygwin_shutdown(A,B) ::shutdown (A,B)
+#define cygwin_socket(A,B,C) ::socket (A,B,C)
+
+#endif /* __OUTSIDE_CYGWIN__ */
-transport_layer_sockets::transport_layer_sockets (int newfd): fd(newfd)
+enum
+ {
+ MAX_CONNECT_RETRY = 64
+ };
+
+transport_layer_sockets::transport_layer_sockets (const int fd)
+ : _fd (fd),
+ _addr_len (0),
+ _is_accepted_endpoint (true),
+ _is_listening_endpoint (false)
{
- /* This may not be needed in this constructor - it's only used
- * when creating a connection via bind or connect
- */
- sockdetails.sa_family = AF_UNIX;
- strcpy (sockdetails.sa_data, "/tmp/cygdaemo");
- sdlen = strlen(sockdetails.sa_data) + sizeof(sockdetails.sa_family);
-};
-
-transport_layer_sockets::transport_layer_sockets (): fd (-1)
+ assert (_fd != -1);
+
+ memset (&_addr, '\0', sizeof (_addr));
+}
+
+transport_layer_sockets::transport_layer_sockets ()
+ : _fd (-1),
+ _addr_len (0),
+ _is_accepted_endpoint (false),
+ _is_listening_endpoint (false)
{
- sockdetails.sa_family = AF_UNIX;
- strcpy (sockdetails.sa_data, "/tmp/cygdaemo");
- sdlen = strlen(sockdetails.sa_data) + sizeof(sockdetails.sa_family);
+ memset (&_addr, '\0', sizeof (_addr));
+
+ _addr.sun_family = AF_UNIX;
+ strcpy (_addr.sun_path, "/tmp/cygdaemo"); // FIXME: $TMP?
+ _addr_len = SUN_LEN (&_addr);
}
-void
+transport_layer_sockets::~transport_layer_sockets ()
+{
+ close ();
+}
+
+#ifndef __INSIDE_CYGWIN__
+
+int
transport_layer_sockets::listen ()
{
- /* we want a thread pool based approach. */
- if ((fd = cygwin_socket (AF_UNIX, SOCK_STREAM,0)) < 0)
- printf ("Socket not created error %d\n", errno);
- if (cygwin_bind(fd, &sockdetails, sdlen))
- printf ("Bind doesn't like you. Tsk Tsk. Bind said %d\n", errno);
- if (cygwin_listen(fd, 5) < 0)
- printf ("And the OS just isn't listening, all it says is %d\n", errno);
+ assert (_fd == -1);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
+
+ debug_printf ("listen () [this = %p]", this);
+
+ struct stat sbuf;
+
+ if (stat (_addr.sun_path, &sbuf) == -1)
+ {
+ if (errno != ENOENT)
+ {
+ system_printf ("cannot access socket file `%s': %s",
+ _addr.sun_path, strerror (errno));
+ return -1;
+ }
+ }
+ else if (S_ISSOCK (sbuf.st_mode))
+ {
+ // The socket already exists: is a duplicate cygserver running?
+
+ const int newfd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (newfd == -1)
+ {
+ system_printf ("failed to create UNIX domain socket: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ if (cygwin_connect (newfd, (struct sockaddr *) &_addr, _addr_len) == 0)
+ {
+ system_printf ("the daemon is already running");
+ (void) cygwin_shutdown (newfd, SHUT_WR);
+ char buf[BUFSIZ];
+ while (::read (newfd, buf, sizeof (buf)) > 0)
+ {}
+ (void) ::close (newfd);
+ return -1;
+ }
+
+ if (unlink (_addr.sun_path) == -1)
+ {
+ system_printf ("failed to remove `%s': %s",
+ _addr.sun_path, strerror (errno));
+ (void) ::close (newfd);
+ return -1;
+ }
+ }
+ else
+ {
+ system_printf ("cannot create socket `%s': File already exists",
+ _addr.sun_path);
+ return -1;
+ }
+
+ _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (_fd == -1)
+ {
+ system_printf ("failed to create UNIX domain socket: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ if (cygwin_bind (_fd, (struct sockaddr *) &_addr, _addr_len) == -1)
+ {
+ const int saved_errno = errno;
+ close ();
+ errno = saved_errno;
+ system_printf ("failed to bind UNIX domain socket `%s': %s",
+ _addr.sun_path, strerror (errno));
+ return -1;
+ }
+
+ _is_listening_endpoint = true; // i.e. this really means "have bound".
+
+ if (cygwin_listen (_fd, SOMAXCONN) == -1)
+ {
+ const int saved_errno = errno;
+ close ();
+ errno = saved_errno;
+ system_printf ("failed to listen on UNIX domain socket `%s': %s",
+ _addr.sun_path, strerror (errno));
+ return -1;
+ }
+
+ debug_printf ("0 = listen () [this = %p, fd = %d]", this, _fd);
+
+ return 0;
}
class transport_layer_sockets *
-transport_layer_sockets::accept ()
+transport_layer_sockets::accept (bool *const recoverable)
{
- /* FIXME: check we have listened */
- int new_fd;
+ assert (_fd != -1);
+ assert (!_is_accepted_endpoint);
+ assert (_is_listening_endpoint);
+
+ debug_printf ("accept () [this = %p, fd = %d]", this, _fd);
+
+ struct sockaddr_un client_addr;
+ socklen_t client_addr_len = sizeof (client_addr);
- if ((new_fd = cygwin_accept(fd, &sockdetails, &sdlen)) < 0)
+ const int accept_fd =
+ cygwin_accept (_fd, (struct sockaddr *) &client_addr, &client_addr_len);
+
+ if (accept_fd == -1)
{
- printf ("Nup, could' accept. %d\n",errno);
+ system_printf ("failed to accept connection: %s", strerror (errno));
+ switch (errno)
+ {
+ case ECONNABORTED:
+ case EINTR:
+ case EMFILE:
+ case ENFILE:
+ case ENOBUFS:
+ case ENOMEM:
+ *recoverable = true;
+ break;
+
+ default:
+ *recoverable = false;
+ break;
+ }
return NULL;
}
-
- transport_layer_sockets *new_conn = new transport_layer_sockets (new_fd);
- return new_conn;
+ debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd);
+ return safe_new (transport_layer_sockets, accept_fd);
}
+#endif /* !__INSIDE_CYGWIN__ */
+
void
-transport_layer_sockets::close()
+transport_layer_sockets::close ()
{
- /* FIXME - are we open? */
- ::close (fd);
+ debug_printf ("close () [this = %p, fd = %d]", this, _fd);
+
+ if (_is_listening_endpoint)
+ (void) unlink (_addr.sun_path);
+
+ if (_fd != -1)
+ {
+ (void) cygwin_shutdown (_fd, SHUT_WR);
+ if (!_is_listening_endpoint)
+ {
+ char buf[BUFSIZ];
+ while (::read (_fd, buf, sizeof (buf)) > 0)
+ {}
+ }
+ (void) ::close (_fd);
+ _fd = -1;
+ }
+
+ _is_listening_endpoint = false;
}
ssize_t
-transport_layer_sockets::read (char *buf, size_t len)
+transport_layer_sockets::read (void *const buf, const size_t buf_len)
{
- /* FIXME: are we open? */
- return ::read (fd, buf, len);
+ assert (_fd != -1);
+ assert (!_is_listening_endpoint);
+
+ assert (buf);
+ assert (buf_len > 0);
+
+ // verbose: debug_printf ("read (buf = %p, len = %u) [this = %p, fd = %d]",
+ // buf, buf_len, this, _fd);
+
+ char *read_buf = static_cast<char *> (buf);
+ size_t read_buf_len = buf_len;
+ ssize_t res = 0;
+
+ while (read_buf_len != 0
+ && (res = ::read (_fd, read_buf, read_buf_len)) > 0)
+ {
+ read_buf += res;
+ read_buf_len -= res;
+
+ assert (read_buf_len >= 0);
+ }
+
+ if (res != -1)
+ {
+ if (res == 0)
+ errno = EIO; // FIXME?
+
+ res = buf_len - read_buf_len;
+ }
+
+ if (res != static_cast<ssize_t> (buf_len))
+ debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]: %s",
+ res, buf, buf_len, this, _fd,
+ (res == -1 ? strerror (errno) : "EOF"));
+ else
+ {
+ // verbose: debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]",
+ // res, buf, buf_len, this, _fd);
+ }
+
+ return res;
}
ssize_t
-transport_layer_sockets::write (char *buf, size_t len)
+transport_layer_sockets::write (void *const buf, const size_t buf_len)
{
- /* FIXME: are we open? */
- return ::write (fd, buf, len);
+ assert (_fd != -1);
+ assert (!_is_listening_endpoint);
+
+ assert (buf);
+ assert (buf_len > 0);
+
+ // verbose: debug_printf ("write (buf = %p, len = %u) [this = %p, fd = %d]",
+ // buf, buf_len, this, _fd);
+
+ char *write_buf = static_cast<char *> (buf);
+ size_t write_buf_len = buf_len;
+ ssize_t res = 0;
+
+ while (write_buf_len != 0
+ && (res = ::write (_fd, write_buf, write_buf_len)) > 0)
+ {
+ write_buf += res;
+ write_buf_len -= res;
+
+ assert (write_buf_len >= 0);
+ }
+
+ if (res != -1)
+ {
+ if (res == 0)
+ errno = EIO; // FIXME?
+
+ res = buf_len - write_buf_len;
+ }
+
+ if (res != static_cast<ssize_t> (buf_len))
+ debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]: %s",
+ res, buf, buf_len, this, _fd,
+ (res == -1 ? strerror (errno) : "EOF"));
+ else
+ {
+ // verbose: debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]",
+ // res, buf, buf_len, this, _fd);
+ }
+
+ return res;
}
-bool
+int
transport_layer_sockets::connect ()
{
- /* are we already connected? */
- if (fd != -1)
- return false;
- fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
- if (cygwin_connect (fd, &sockdetails, sdlen) < 0)
+ assert (_fd == -1);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
+
+ static bool assume_cygserver = false;
+
+ debug_printf ("connect () [this = %p]", this);
+
+ for (int retries = 0; retries != MAX_CONNECT_RETRY; retries++)
{
- debug_printf("client connect failure %d\n", errno);
- ::close (fd);
- return false;
+ _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (_fd == -1)
+ {
+ system_printf ("failed to create UNIX domain socket: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ if (cygwin_connect (_fd, (struct sockaddr *) &_addr, _addr_len) == 0)
+ {
+ assume_cygserver = true;
+ debug_printf ("0 = connect () [this = %p, fd = %d]", this, _fd);
+ return 0;
+ }
+
+ if (!assume_cygserver || errno != ECONNREFUSED)
+ {
+ debug_printf ("failed to connect to server: %s", strerror (errno));
+ (void) ::close (_fd);
+ _fd = -1;
+ return -1;
+ }
+
+ (void) ::close (_fd);
+ _fd = -1;
+ Sleep (0); // Give the server a chance.
}
- return true;
+
+ debug_printf ("failed to connect to server: %s", strerror (errno));
+ return -1;
}
diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc
new file mode 100644
index 000000000..b81c4c16f
--- /dev/null
+++ b/winsup/cygwin/cygthread.cc
@@ -0,0 +1,261 @@
+/* cygthread.cc
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <windows.h>
+#include <stdlib.h>
+#include "exceptions.h"
+#include "security.h"
+#include "cygthread.h"
+
+#undef CloseHandle
+
+static cygthread NO_COPY threads[6];
+#define NTHREADS (sizeof (threads) / sizeof (threads[0]))
+
+DWORD NO_COPY cygthread::main_thread_id;
+bool NO_COPY cygthread::initialized;
+
+/* Initial stub called by cygthread constructor. Performs initial
+ per-thread initialization and loops waiting for new thread functions
+ to execute. */
+DWORD WINAPI
+cygthread::simplestub (VOID *arg)
+{
+ DECLARE_TLS_STORAGE;
+ exception_list except_entry;
+
+ /* Initialize this thread's ability to respond to things like
+ SIGSEGV or SIGFPE. */
+ init_exceptions (&except_entry);
+
+ cygthread *info = (cygthread *) arg;
+ info->func (info->arg == cygself ? info : info->arg);
+ ExitThread (0);
+}
+
+/* Initial stub called by cygthread constructor. Performs initial
+ per-thread initialization and loops waiting for new thread functions
+ to execute. */
+DWORD WINAPI
+cygthread::stub (VOID *arg)
+{
+ DECLARE_TLS_STORAGE;
+ exception_list except_entry;
+
+ /* Initialize this thread's ability to respond to things like
+ SIGSEGV or SIGFPE. */
+ init_exceptions (&except_entry);
+
+ cygthread *info = (cygthread *) arg;
+ info->ev = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+ while (1)
+ {
+ if (!info->func)
+ ExitThread (0);
+
+ /* Cygwin threads should not call ExitThread directly */
+ info->func (info->arg == cygself ? info : info->arg);
+ /* ...so the above should always return */
+
+#ifdef DEBUGGING
+ info->func = NULL; // catch erroneous activation
+#endif
+ SetEvent (info->ev);
+ info->__name = NULL;
+ SuspendThread (info->h);
+ }
+}
+
+/* This function runs in a secondary thread and starts up a bunch of
+ other suspended threads for use in the cygthread pool. */
+DWORD WINAPI
+cygthread::runner (VOID *arg)
+{
+ for (unsigned i = 0; i < NTHREADS; i++)
+ threads[i].h = CreateThread (&sec_none_nih, 0, cygthread::stub, &threads[i],
+ CREATE_SUSPENDED, &threads[i].avail);
+ cygthread::initialized = true;
+ return 0;
+}
+
+/* Start things going. Called from dll_crt0_1. */
+void
+cygthread::init ()
+{
+ DWORD tid;
+ HANDLE h = CreateThread (&sec_none_nih, 0, cygthread::runner, NULL, 0, &tid);
+ if (!h)
+ api_fatal ("can't start thread_runner, %E");
+ CloseHandle (h);
+ main_thread_id = GetCurrentThreadId ();
+}
+
+bool
+cygthread::is ()
+{
+ DWORD tid = GetCurrentThreadId ();
+
+ for (DWORD i = 0; i < NTHREADS; i++)
+ if (threads[i].id == tid)
+ return 1;
+
+ return 0;
+}
+
+void *
+cygthread::freerange ()
+{
+ cygthread *self = (cygthread *) calloc (1, sizeof (*self));
+ self->is_freerange = true;
+ self->h = CreateThread (&sec_none_nih, 0, cygthread::simplestub, self,
+ CREATE_SUSPENDED, &self->id);
+ self->ev = self->h;
+ return self;
+}
+
+void * cygthread::operator
+new (size_t)
+{
+ DWORD id;
+ cygthread *info;
+
+ for (;;)
+ {
+ bool was_initialized = initialized;
+ /* Search the threads array for an empty slot to use */
+ for (info = threads + NTHREADS - 1; info >= threads; info--)
+ if ((id = (DWORD) InterlockedExchange ((LPLONG) &info->avail, 0)))
+ {
+ info->id = id;
+#ifdef DEBUGGING
+ if (info->__name)
+ api_fatal ("name not NULL? id %p, i %d", id, info - threads);
+#endif
+ return info;
+ }
+
+ if (!was_initialized)
+ Sleep (0); /* thread_runner is not finished yet. */
+ else
+ {
+#ifdef DEBUGGING
+ char buf[1024];
+ if (GetEnvironmentVariable ("CYGWIN_NOFREERANGE", buf, sizeof (buf)))
+ api_fatal ("Overflowed cygwin thread pool");
+#endif
+ return freerange ();
+ }
+ }
+}
+
+cygthread::cygthread (LPTHREAD_START_ROUTINE start, LPVOID param,
+ const char *name): func (start), arg (param)
+{
+#ifdef DEBUGGGING
+ if (!__name)
+ api_fatal ("name should never be NULL");
+#endif
+ thread_printf ("name %s, id %p", name, id);
+ while (!h || ResumeThread (h) != 1)
+#ifndef DEBUGGING
+ Sleep (0);
+#else
+ {
+ thread_printf ("waiting for %s<%p> to become active", __name, h);
+ Sleep (0);
+ }
+#endif
+ __name = name; /* Need to set after thread has woken up to
+ ensure that it won't be cleared by exiting
+ thread. */
+}
+
+/* Return the symbolic name of the current thread for debugging.
+ */
+const char *
+cygthread::name (DWORD tid)
+{
+ const char *res = NULL;
+ if (!tid)
+ tid = GetCurrentThreadId ();
+
+ if (tid == main_thread_id)
+ return "main";
+
+ for (DWORD i = 0; i < NTHREADS; i++)
+ if (threads[i].id == tid)
+ {
+ res = threads[i].__name ?: "exiting thread";
+ break;
+ }
+
+ if (!res)
+ {
+ static char buf[30] NO_COPY = {0};
+ __small_sprintf (buf, "unknown (%p)", tid);
+ res = buf;
+ }
+
+ return res;
+}
+
+cygthread::operator
+HANDLE ()
+{
+ while (!ev)
+ Sleep (0);
+ return ev;
+}
+
+/* Should only be called when the process is exiting since it
+ leaves an open thread slot. */
+void
+cygthread::exit_thread ()
+{
+ if (!is_freerange)
+ SetEvent (*this);
+ ExitThread (0);
+}
+
+/* Detach the cygthread from the current thread. Note that the
+ theory is that cygthread's are only associated with one thread.
+ So, there should be no problems with multiple threads doing waits
+ on the one cygthread. */
+void
+cygthread::detach ()
+{
+ if (avail)
+ system_printf ("called detach on available thread %d?", avail);
+ else
+ {
+ DWORD avail = id;
+ /* Checking for __name here is just a minor optimization to avoid
+ an OS call. */
+ if (!__name)
+ thread_printf ("thread id %p returned. No need to wait.", id);
+ else
+ {
+ DWORD res = WaitForSingleObject (*this, INFINITE);
+ thread_printf ("WFSO returns %d, id %p", res, id);
+ }
+ if (is_freerange)
+ {
+ CloseHandle (h);
+ free (this);
+ }
+ else
+ {
+ ResetEvent (*this);
+ id = 0;
+ __name = NULL;
+ /* Mark the thread as available by setting avail to non-zero */
+ (void) InterlockedExchange ((LPLONG) &this->avail, avail);
+ }
+ }
+}
diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h
new file mode 100644
index 000000000..37f7c6537
--- /dev/null
+++ b/winsup/cygwin/cygthread.h
@@ -0,0 +1,38 @@
+/* cygthread.h
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+class cygthread
+{
+ DWORD avail;
+ DWORD id;
+ HANDLE h;
+ HANDLE ev;
+ const char *__name;
+ LPTHREAD_START_ROUTINE func;
+ VOID *arg;
+ bool is_freerange;
+ static DWORD main_thread_id;
+ static bool initialized;
+ static DWORD WINAPI runner (VOID *);
+ static DWORD WINAPI free_runner (VOID *);
+ static DWORD WINAPI stub (VOID *);
+ static DWORD WINAPI simplestub (VOID *);
+ public:
+ static const char * name (DWORD = 0);
+ cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *);
+ cygthread () {};
+ static void init ();
+ void detach ();
+ operator HANDLE ();
+ static bool is ();
+ void * operator new (size_t);
+ static void * freerange ();
+ void exit_thread ();
+};
+
+#define cygself NULL
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 690f4aec3..2c5e9f38c 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -4,8 +4,12 @@ EXPORTS
__assert
__eprintf
__errno
+__fpclassifyd
+__fpclassifyf
__infinity
__main
+__signbitd
+__signbitf
__signgam
__srget
__swbuf
@@ -80,8 +84,8 @@ cabs
_cabs = cabs
cabsf
_cabsf = cabsf
-calloc = export_calloc
-_calloc = export_calloc
+calloc
+_calloc = calloc
cbrt
_cbrt = cbrt
cbrtf
@@ -100,13 +104,14 @@ chmod
_chmod = chmod
chown
_chown = chown
+chown32
cleanup_glue
clearerr
_clearerr = clearerr
clock
_clock = clock
-close
-_close = close
+_close
+close = _close
closedir
_closedir = closedir
copysign
@@ -159,6 +164,8 @@ ecvtf
_ecvtf = ecvtf
endgrent
_endgrent = endgrent
+endutent
+_endutent = endutent
erf
_erf = erf
erfc
@@ -203,10 +210,15 @@ fchmod
_fchmod = fchmod
fchown
_fchown = fchown
+fchown32
fclose
_fclose = fclose
-fcntl
-_fcntl = fcntl
+fcloseall
+_fcloseall = fcloseall
+_fcloseall_r
+fcloseall_r = _fcloseall_r
+_fcntl
+fcntl = _fcntl
fcvt
_fcvt = fcvt
fcvtbuf
@@ -261,6 +273,8 @@ floor
_floor = floor
floorf
_floorf = floorf
+fnmatch
+_fnmatch = fnmatch
fmod
_fmod = fmod
fmodf
@@ -282,8 +296,8 @@ fputs
_fputs = fputs
fread
_fread = fread
-free = export_free
-_free = export_free
+free
+_free = free
freopen
_freopen = freopen
frexp
@@ -298,8 +312,9 @@ fseek
_fseek = fseek
fsetpos
_fsetpos = fsetpos
-fstat
-_fstat = fstat
+_fstat
+fstat = _fstat
+fstat64
fstatfs
_fstatfs = fstatfs
fsync
@@ -314,6 +329,7 @@ ftime
_ftime = ftime
ftruncate
_ftruncate = ftruncate
+ftruncate64
fwrite
_fwrite = fwrite
gamma
@@ -330,24 +346,34 @@ gcvtf
_gcvtf = gcvtf
getc
_getc = getc
+getc_unlocked
+_getc_unlocked = getc_unlocked
getchar
_getchar = getchar
+getchar_unlocked
+_getchar_unlocked = getchar_unlocked
getcwd
_getcwd = getcwd
getdtablesize
_getdtablesize = getdtablesize
getegid
_getegid = getegid
+getegid32
geteuid
_geteuid = geteuid
+geteuid32
getgid
_getgid = getgid
+getgid32
getgrgid
_getgrgid = getgrgid
+getgrgid32
getgrnam
_getgrnam = getgrnam
+getgrnam32
getgroups
_getgroups = getgroups
+getgroups32
gethostname = cygwin_gethostname
_gethostname = cygwin_gethostname
getlogin
@@ -372,10 +398,18 @@ getrusage
_getrusage = getrusage
gets
_gets = gets
+getsid
gettimeofday
_gettimeofday = gettimeofday
getuid
_getuid = getuid
+getuid32
+getutent
+_getutent = getutent
+getutid
+_getutid = getutid
+getutline
+_getutline = getutline
glob
_glob = glob
globfree
@@ -400,6 +434,7 @@ _infinity = infinity
infinityf
_infinityf = infinityf
initgroups
+initgroups32
ioctl
_ioctl = ioctl
iprintf
@@ -450,12 +485,13 @@ jn
_jn = jn
jnf
_jnf = jnf
-kill
-_kill = kill
+_kill
+kill = _kill
labs
_labs = labs
lchown
_lchown = lchown
+lchown32
ldexp
_ldexp = ldexp
ldexpf
@@ -498,12 +534,18 @@ login
logout
longjmp
_longjmp = longjmp
-lseek
-_lseek = lseek
-lstat
-_lstat = lstat
-malloc = export_malloc
-_malloc = export_malloc
+_lseek
+lseek = _lseek
+lseek64
+lstat = cygwin_lstat
+_lstat = cygwin_lstat
+lstat64
+malloc
+_malloc = malloc
+malloc_stats
+malloc_trim
+malloc_usable_size
+mallopt
matherr
_matherr = matherr
mblen
@@ -512,6 +554,7 @@ mbstowcs
_mbstowcs = mbstowcs
mbtowc
_mbtowc = mbtowc
+memalign
memchr
_memchr = memchr
memcmp
@@ -534,6 +577,7 @@ _mktemp = mktemp
mktime
_mktime = mktime
mmap
+mmap64
mprotect
msync
munmap
@@ -549,8 +593,8 @@ nextafter
_nextafter = nextafter
nextafterf
_nextafterf = nextafterf
-open
-_open = open
+_open
+open = _open
opendir
_opendir = opendir
pathconf
@@ -569,8 +613,12 @@ printf
_printf = printf
putc
_putc = putc
+putc_unlocked
+_putc_unlocked = putc_unlocked
putchar
_putchar = putchar
+putchar_unlocked
+_putchar_unlocked = putchar_unlocked
puts
_puts = puts
putw
@@ -584,34 +632,28 @@ _rand = rand
random
initstate
setstate
-read
-_read = read
+_read
+read = _read
readdir
_readdir = readdir
readlink
_readlink = readlink
readv
_readv = readv
-realloc = export_realloc
-_realloc = export_realloc
-regcomp
-_regcomp = regcomp
-regexec
-_regexec = regexec
-regerror
-_regerror = regerror
-regfree
-_regfree = regfree
-regsub
-_regsub = regsub
+realloc
+_realloc = realloc
+posix_regcomp
+posix_regerror
+posix_regexec
+posix_regfree
remainder
_remainder = remainder
remainderf
_remainderf = remainderf
remove
_remove = remove
-rename
-_rename = rename
+_rename
+rename = _rename
rewind
_rewind = rewind
rewinddir
@@ -642,12 +684,17 @@ _scanf_r
scanf_r = _scanf_r
seekdir
_seekdir = seekdir
+seekdir64
setbuf
_setbuf = setbuf
setdtablesize
_setdtablesize = setdtablesize
setgid
_setgid = setgid
+setgid32
+setgroups
+_setgroups = setgroups
+setgroups32
setjmp
_setjmp = setjmp
setlocale
@@ -662,10 +709,15 @@ settimeofday
_settimeofday = settimeofday
seteuid
_seteuid = seteuid
+seteuid32
setegid
_setegid = setegid
+setegid32
setuid
_setuid = setuid
+setuid32
+setutent
+_setutent = setutent
chroot
_chroot = chroot
setvbuf
@@ -737,8 +789,9 @@ sscanf
_sscanf = sscanf
_sscanf_r
sscanf_r = _sscanf_r
-stat
-_stat = stat
+_stat
+stat = _stat
+stat64
statfs
_statfs = statfs
strcasecmp
@@ -835,12 +888,13 @@ tcsetpgrp
_tcsetpgrp = tcsetpgrp
telldir
_telldir = telldir
+telldir64
tempnam
_tempnam = tempnam
time
_time = time
-times
-_times = times
+_times
+times = _times
timezone
tmpfile
_tmpfile = tmpfile
@@ -854,22 +908,30 @@ toupper
_toupper = toupper
truncate
_truncate = truncate
+truncate64
ttyname
_ttyname = ttyname
tzset
_tzset = tzset
+ualarm
+_ualarm = ualarm
umask
_umask = umask
uname
_uname = uname
ungetc
_ungetc = ungetc
-unlink
-_unlink = unlink
+_unlink
+unlink = _unlink
+usleep
+_usleep = usleep
utime
_utime = utime
utimes
_utimes = utimes
+utmpname
+_utmpname = utmpname
+valloc
vfiprintf
_vfiprintf = vfiprintf
vfork
@@ -894,8 +956,8 @@ vsscanf
_vsscanf = vsscanf
_vsscanf_r
vsscanf_r = _vsscanf_r
-wait
-_wait = wait
+_wait
+wait = _wait
waitpid
_waitpid = waitpid
wait3
@@ -904,8 +966,8 @@ wcstombs
_wcstombs = wcstombs
wctomb
_wctomb = wctomb
-write
-_write = write
+_write
+write = _write
writev
_writev = writev
y0
@@ -945,6 +1007,12 @@ pclose
_pclose = pclose
strftime
_strftime = strftime
+strlcat
+_strlcat = strlcat
+strlcpy
+_strlcpy = strlcpy
+strptime
+_strptime = strptime
setgrent
_setgrent = setgrent
cuserid
@@ -963,8 +1031,6 @@ wcscmp
_wcscmp = wcscmp
wcslen
_wcslen = wcslen
-usleep
-_usleep = usleep
wprintf
_wprintf = wprintf
memccpy
@@ -982,11 +1048,14 @@ _getpwnam = getpwnam
getpwnam_r
getpwuid
_getpwuid = getpwuid
+getpwuid32
getpwuid_r
+getpwuid_r32
getpgrp
_getpgrp = getpgrp
getgrent
_getgrent = getgrent
+getgrent32
ntohl
_ntohl = ntohl
htonl
@@ -1025,6 +1094,8 @@ setsockopt = cygwin_setsockopt
inet_aton = cygwin_inet_aton
inet_ntoa = cygwin_inet_ntoa
recvfrom = cygwin_recvfrom
+recvmsg = cygwin_recvmsg
+sendmsg = cygwin_sendmsg
sendto = cygwin_sendto
shutdown = cygwin_shutdown
sethostent
@@ -1098,14 +1169,14 @@ _tzname DATA
ptsname
grantpt
unlockpt
-sexecve
-sexecl
-sexecle
-sexeclp
-sexeclpe
-sexecv
-sexecp
-sexecvpe
+sexecve = sexecve_is_bad
+sexecl = sexecve_is_bad
+sexecle = sexecve_is_bad
+sexeclp = sexecve_is_bad
+sexeclpe = sexecve_is_bad
+sexecv = sexecve_is_bad
+sexecp = sexecve_is_bad
+sexecvpe = sexecve_is_bad
ttyslot
rcmd = cygwin_rcmd
rresvport = cygwin_rresvport
@@ -1140,6 +1211,8 @@ pthread_attr_setschedpolicy
pthread_attr_setscope
pthread_attr_setstacksize
pthread_cancel
+_pthread_cleanup_push
+_pthread_cleanup_pop
pthread_cond_broadcast
pthread_cond_destroy
pthread_cond_init
@@ -1224,8 +1297,3 @@ acltotext
_acltotext = acltotext
aclfromtext
_aclfromtext = aclfromtext
-ftok
-shmat
-shmctl
-shmdt
-shmget
diff --git a/winsup/cygwin/cygwin.sc b/winsup/cygwin/cygwin.sc
index 43d880c06..fe00e2bd4 100644
--- a/winsup/cygwin/cygwin.sc
+++ b/winsup/cygwin/cygwin.sc
@@ -11,9 +11,9 @@ SECTIONS
*(.glue_7t)
*(.glue_7)
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
- LONG (-1); *(.ctors); *(.ctor); LONG (0);
+ LONG (-1); *(SORT(.ctors.*)); *(.ctors); *(.ctor); LONG (0);
___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
- LONG (-1); *(.dtors); *(.dtor); LONG (0);
+ LONG (-1); *(SORT(.dtors.*)); *(.dtors); *(.dtor); LONG (0);
*(.fini)
/* ??? Why is .gcc_exc here? */
*(.gcc_exc)
@@ -107,5 +107,5 @@ SECTIONS
{
__system_dlls__ = ABSOLUTE(.) ;
__cygheap_start = ABSOLUTE(.) ;
- }
+ }
}
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 9fb6ca906..701fb140c 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -1,6 +1,6 @@
/* dcrt0.cc -- essentially the main() for the Cygwin dll
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -17,10 +17,9 @@ details. */
#include <limits.h>
#include <wingdi.h>
#include <winuser.h>
-#include "sync.h"
+#include <errno.h>
#include "sigproc.h"
#include "pinfo.h"
-#include "heap.h"
#include "cygerrno.h"
#define NEED_VFORK
#include "perprocess.h"
@@ -29,20 +28,19 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "child_info.h"
+#include "child_info_magic.h"
#include "perthread.h"
#include "shared_info.h"
#include "cygwin_version.h"
#include "dll_init.h"
-#include "cygwin/cygserver_transport.h"
-#include "cygwin/cygserver.h"
+#include "cygthread.h"
#define MAX_AT_FILE_LEVEL 10
#define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))
-HANDLE NO_COPY hMainProc = NULL;
-HANDLE NO_COPY hMainThread = NULL;
+HANDLE NO_COPY hMainProc;
+HANDLE NO_COPY hMainThread;
sigthread NO_COPY mainthread; // ID of the main thread
@@ -74,14 +72,12 @@ ResourceLocks _reslock NO_COPY;
MTinterface _mtinterf;
bool NO_COPY _cygwin_testing;
+unsigned NO_COPY _cygwin_testing_magic;
+
+char NO_COPY almost_null[1];
extern "C"
{
- void *export_malloc (unsigned int);
- void export_free (void *);
- void *export_realloc (void *, unsigned int);
- void *export_calloc (unsigned int, unsigned int);
-
/* This is an exported copy of environ which can be used by DLLs
which use cygwin.dll. */
char **__cygwin_environ;
@@ -94,12 +90,12 @@ extern "C"
/* dll_major */ CYGWIN_VERSION_DLL_MAJOR,
/* dll_major */ CYGWIN_VERSION_DLL_MINOR,
/* impure_ptr_ptr */ NULL, /* envptr */ NULL,
- /* malloc */ export_malloc, /* free */ export_free,
- /* realloc */ export_realloc,
+ /* malloc */ malloc, /* free */ free,
+ /* realloc */ realloc,
/* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL,
/* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL,
/* bss_start */ NULL, /* bss_end */ NULL,
- /* calloc */ export_calloc,
+ /* calloc */ calloc,
/* premain */ {NULL, NULL, NULL, NULL},
/* run_ctors_p */ 0,
/* unused */ {0, 0, 0, 0, 0, 0, 0},
@@ -157,10 +153,10 @@ do_global_ctors (void (**in_pfunc)(), int force)
}
/*
- * Replaces -@file in the command line with the contents of the file.
- * There may be multiple -@file's in a single command line
- * A \-@file is replaced with -@file so that echo \-@foo would print
- * -@foo and not the contents of foo.
+ * Replaces @file in the command line with the contents of the file.
+ * There may be multiple @file's in a single command line
+ * A \@file is replaced with @file so that echo \@foo would print
+ * @foo and not the contents of foo.
*/
static int __stdcall
insert_file (char *name, char *&cmd)
@@ -451,13 +447,11 @@ check_sanity_and_sync (per_process *p)
signal_shift_subtract = 0;
}
-static NO_COPY STARTUPINFO si;
-# define fork_info ((struct child_info_fork *)(si.lpReserved2))
-# define spawn_info ((struct child_info_spawn *)(si.lpReserved2))
-child_info_fork NO_COPY *child_proc_info = NULL;
-static MEMORY_BASIC_INFORMATION sm;
+child_info NO_COPY *child_proc_info = NULL;
+static MEMORY_BASIC_INFORMATION NO_COPY sm;
-#define CYGWIN_GUARD ((wincap.has_page_guard ()) ? PAGE_GUARD : PAGE_NOACCESS)
+#define CYGWIN_GUARD ((wincap.has_page_guard ()) ? \
+ PAGE_EXECUTE_READWRITE|PAGE_GUARD : PAGE_NOACCESS)
// __inline__ void
extern void
@@ -498,7 +492,7 @@ alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
{
m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1);
if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
- PAGE_EXECUTE_READWRITE|CYGWIN_GUARD))
+ CYGWIN_GUARD))
api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
m.BaseAddress);
}
@@ -517,18 +511,13 @@ alloc_stack (child_info_fork *ci)
fork on Win95, but I don't know exactly why yet. DJ */
volatile char b[ci->stacksize + 16384];
- if (ci->type == PROC_FORK)
- ci->stacksize = 0; // flag to fork not to do any funny business
- else
- {
- if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm))
- api_fatal ("fork: couldn't get stack info, %E");
+ if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm))
+ api_fatal ("fork: couldn't get stack info, %E");
- if (sm.AllocationBase != ci->stacktop)
- alloc_stack_hard_way (ci, b + sizeof (b) - 1);
- else
- ci->stacksize = 0;
- }
+ if (sm.AllocationBase != ci->stacktop)
+ alloc_stack_hard_way (ci, b + sizeof (b) - 1);
+ else
+ ci->stacksize = 0;
return;
}
@@ -560,12 +549,12 @@ dll_crt0_1 ()
/* Initialize SIGSEGV handling, etc. */
init_exceptions (&cygwin_except_entry);
- do_global_ctors (&__CTOR_LIST__, 1);
-
/* Set the os_being_run global. */
wincap.init ();
check_sanity_and_sync (user_data);
+ do_global_ctors (&__CTOR_LIST__, 1);
+
/* Nasty static stuff needed by newlib -- point to a local copy of
the reent stuff.
Note: this MUST be done here (before the forkee code) as the
@@ -577,11 +566,6 @@ dll_crt0_1 ()
user_data->resourcelocks->Init ();
user_data->threadinterface->Init (user_data->forkee);
- threadname_init ();
- debug_init ();
- (void) getpagesize (); /* initialize page size constant */
-
- regthread ("main", GetCurrentThreadId ());
mainthread.init ("mainthread"); // For use in determining if signals
// should be blocked.
@@ -590,30 +574,32 @@ dll_crt0_1 ()
if (child_proc_info)
{
+ bool close_ppid_handle = false;
+ bool close_hexec_proc = false;
switch (child_proc_info->type)
{
- case PROC_FORK:
- case PROC_FORK1:
- cygheap_fixup_in_child (child_proc_info, 0);
+ case _PROC_FORK:
+ cygheap_fixup_in_child (0);
alloc_stack (fork_info);
set_myself (mypid);
- ProtectHandle (child_proc_info->forker_finished);
+ close_ppid_handle = !!child_proc_info->pppid_handle;
break;
- case PROC_SPAWN:
- CloseHandle (spawn_info->hexec_proc);
+ case _PROC_SPAWN:
+ /* Have to delay closes until after cygheap is setup */
+ close_hexec_proc = !!spawn_info->hexec_proc;
+ close_ppid_handle = !!child_proc_info->pppid_handle;
goto around;
- case PROC_EXEC:
+ case _PROC_EXEC:
hexec_proc = spawn_info->hexec_proc;
around:
HANDLE h;
- cygheap_fixup_in_child (spawn_info, 1);
+ cygheap_fixup_in_child (1);
if (!spawn_info->moreinfo->myself_pinfo ||
!DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
hMainProc, &h, 0, 0,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
h = NULL;
set_myself (mypid, h);
- myself->uid = spawn_info->moreinfo->uid;
__argc = spawn_info->moreinfo->argc;
__argv = spawn_info->moreinfo->argv;
envp = spawn_info->moreinfo->envp;
@@ -626,19 +612,26 @@ dll_crt0_1 ()
old_title = strcpy (title_buf, spawn_info->moreinfo->old_title);
cfree (spawn_info->moreinfo->old_title);
}
- if (child_proc_info->subproc_ready)
- ProtectHandle (child_proc_info->subproc_ready);
- if (myself->uid == USHRT_MAX)
- cygheap->user.set_sid (NULL);
break;
}
+ if (close_hexec_proc)
+ CloseHandle (spawn_info->hexec_proc);
+ if (close_ppid_handle)
+ CloseHandle (child_proc_info->pppid_handle);
}
- ProtectHandle (hMainProc);
- ProtectHandle (hMainThread);
/* Initialize the cygwin subsystem if this is the first process,
or attach to shared data structures if it's already running. */
memory_init ();
+ cygthread::init ();
+
+ ProtectHandle (hMainProc);
+ ProtectHandle (hMainThread);
+
+ /* Initialize debug muto, if DLL is built with --enable-debugging.
+ Need to do this before any helper threads start. */
+ debug_init ();
+
cygheap->fdtab.vfork_child_fixup ();
(void) SetErrorMode (SEM_FAILCRITICALERRORS);
@@ -684,14 +677,13 @@ dll_crt0_1 ()
/* Allocate cygheap->fdtab */
dtable_init ();
-/* Initialize uid, gid. */
- uinfo_init ();
+ /* Initialize uid, gid if necessary. */
+ if (child_proc_info == NULL || spawn_info->moreinfo->uid == ILLEGAL_UID)
+ uinfo_init ();
/* Initialize signal/subprocess handling. */
sigproc_init ();
- cygserver_init ();
-
/* Connect to tty. */
tty_init ();
@@ -714,9 +706,6 @@ dll_crt0_1 ()
{
char *new_argv0 = (char *) alloca (MAX_PATH);
cygwin_conv_to_posix_path (__argv[0], new_argv0);
- char *p = strchr (new_argv0, '\0') - 4;
- if (p > new_argv0 && strcasematch (p, ".exe"))
- *p = '\0';
__argv[0] = new_argv0;
}
}
@@ -726,10 +715,19 @@ dll_crt0_1 ()
user_data->premain[i] (__argc, __argv, user_data);
/* Set up standard fds in file descriptor table. */
- stdio_init ();
+ cygheap->fdtab.stdio_init ();
/* Set up __progname for getopt error call. */
- __progname = __argv[0];
+ if (__argv[0] && (__progname = strrchr (__argv[0], '/')))
+ ++__progname;
+ else
+ __progname = __argv[0];
+ if (__progname)
+ {
+ char *cp = strchr (__progname, '\0') - 4;
+ if (cp > __progname && strcasematch (cp, ".exe"))
+ *cp = '\0';
+ }
/* Set new console title if appropriate. */
@@ -766,7 +764,7 @@ dll_crt0_1 ()
/* Flush signals and ensure that signal thread is up and running. Can't
do this for noncygwin case since the signal thread is blocked due to
LoadLibrary serialization. */
- sig_send (NULL, __SIGFLUSH);
+ wait_for_sigthread ();
set_errno (0);
@@ -776,6 +774,59 @@ dll_crt0_1 ()
exit (user_data->main (__argc, __argv, *user_data->envptr));
}
+#ifdef DEBUGGING
+void
+break_here ()
+{
+ debug_printf ("break here");
+}
+#endif
+
+void
+initial_env ()
+{
+ DWORD len;
+ char buf[MAX_PATH + 1];
+#ifdef DEBUGGING
+ if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
+ {
+ DWORD ms = atoi (buf);
+ buf[0] = '\0';
+ len = GetModuleFileName (NULL, buf, MAX_PATH);
+ console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf);
+ Sleep (ms);
+ }
+ if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
+ {
+ char buf1[MAX_PATH + 1];
+ len = GetModuleFileName (NULL, buf1, MAX_PATH);
+ strlwr (buf1);
+ strlwr (buf);
+ char *p = strchr (buf, '=');
+ if (!p)
+ p = (char *) "gdb.exe -nw";
+ else
+ *p++ = '\0';
+ if (strstr (buf1, buf))
+ {
+ error_start_init (p);
+ try_to_debug ();
+ break_here ();
+ }
+ }
+#endif
+
+ if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
+ {
+ _cygwin_testing = 1;
+ if ((len = GetModuleFileName (cygwin_hmodule, buf, MAX_PATH))
+ && len > sizeof ("new-cygwin1.dll")
+ && strcasematch (buf + len - sizeof ("new-cygwin1.dll"),
+ "\\new-cygwin1.dll"))
+ _cygwin_testing_magic = 0x10;
+ }
+}
+
/* Wrap the real one, otherwise gdb gets confused about
two symbols with the same name, but different addresses.
@@ -785,19 +836,10 @@ dll_crt0_1 ()
extern "C" void __stdcall
_dll_crt0 ()
{
- char envbuf[8];
-#ifdef DEBUGGING
- if (GetEnvironmentVariable ("CYGWIN_SLEEP", envbuf, sizeof (envbuf) - 1))
- {
- console_printf ("Sleeping %d, pid %u\n", atoi (envbuf), GetCurrentProcessId ());
- Sleep (atoi (envbuf));
- }
-#endif
-
- if (GetEnvironmentVariable ("CYGWIN_TESTING", envbuf, sizeof (envbuf) - 1))
- _cygwin_testing = 1;
-
+ DECLARE_TLS_STORAGE;
+ initial_env ();
char zeros[sizeof (fork_info->zero)] = {0};
+ static NO_COPY STARTUPINFO si;
#ifdef DEBUGGING
strace.microseconds ();
#endif
@@ -805,7 +847,7 @@ _dll_crt0 ()
main_environ = user_data->envptr;
*main_environ = NULL;
- set_console_handler ();
+ early_stuff_init ();
if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
GetCurrentProcess (), &hMainProc, 0, FALSE,
DUPLICATE_SAME_ACCESS))
@@ -815,34 +857,47 @@ _dll_crt0 ()
&hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
GetStartupInfo (&si);
- if (si.cbReserved2 >= EXEC_MAGIC_SIZE &&
- memcmp (fork_info->zero, zeros, sizeof (zeros)) == 0)
+ child_proc_info = (child_info *) si.lpReserved2;
+ if (si.cbReserved2 < EXEC_MAGIC_SIZE || !child_proc_info
+ || memcmp (child_proc_info->zero, zeros, sizeof (zeros)) != 0)
+ child_proc_info = NULL;
+ else
{
- switch (fork_info->type)
+ if ((child_proc_info->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC)
+ multiple_cygwin_problem ("proc", child_proc_info->intro, 0);
+ else if (child_proc_info->intro == PROC_MAGIC_GENERIC
+ && child_proc_info->magic != CHILD_INFO_MAGIC)
+ multiple_cygwin_problem ("proc", child_proc_info->magic,
+ CHILD_INFO_MAGIC);
+ else if (child_proc_info->cygheap != (void *) &_cygheap_start)
+ multiple_cygwin_problem ("cygheap", (DWORD) child_proc_info->cygheap,
+ (DWORD) &_cygheap_start);
+ unsigned should_be_cb = 0;
+ switch (child_proc_info->type)
{
- case PROC_FORK:
- case PROC_FORK1:
- user_data->forkee = fork_info->cygpid;
- case PROC_SPAWN:
- if (fork_info->pppid_handle)
- CloseHandle (fork_info->pppid_handle);
- case PROC_EXEC:
- {
- child_proc_info = fork_info;
- cygwin_mount_h = child_proc_info->mount_h;
- mypid = child_proc_info->cygpid;
- break;
- }
+ case _PROC_FORK:
+ user_data->forkee = child_proc_info->cygpid;
+ should_be_cb = sizeof (child_info_fork);
+ /* fall through */;
+ case _PROC_SPAWN:
+ case _PROC_EXEC:
+ if (!should_be_cb)
+ should_be_cb = sizeof (child_info);
+ if (should_be_cb != child_proc_info->cb)
+ multiple_cygwin_problem ("proc size", child_proc_info->cb, should_be_cb);
+ else if (sizeof (fhandler_union) != child_proc_info->fhandler_union_cb)
+ multiple_cygwin_problem ("fhandler size", child_proc_info->fhandler_union_cb, sizeof (fhandler_union));
+ else
+ {
+ cygwin_mount_h = child_proc_info->mount_h;
+ mypid = child_proc_info->cygpid;
+ break;
+ }
default:
- if (_cygwin_testing)
- fork_info = NULL;
- else if ((fork_info->type & PROC_MAGIC_MASK) == PROC_MAGIC_GENERIC)
- api_fatal ("\
-You have multiple copies of cygwin1.dll on your system.\n\
-Search for cygwin1.dll using the Windows Start->Find/Search facility\n\
-and delete all but the most recent version. This will probably be\n\
-the one that resides in x:\\cygwin\\bin, where 'x' is the drive on which\n\
-you have installed the cygwin distribution.\n");
+ system_printf ("unknown exec type %d", child_proc_info->type);
+ /* intentionally fall through */
+ case _PROC_WHOOPS:
+ child_proc_info = NULL;
break;
}
}
@@ -852,6 +907,7 @@ you have installed the cygwin distribution.\n");
void
dll_crt0 (per_process *uptr)
{
+ DECLARE_TLS_STORAGE;
/* Set the local copy of the pointer into the user space. */
if (uptr && uptr != user_data)
{
@@ -906,10 +962,7 @@ do_exit (int status)
vfork_save *vf = vfork_storage.val ();
if (vf != NULL && vf->pid < 0)
- {
- vf->pid = status < 0 ? status : -status;
- longjmp (vf->j, 1);
- }
+ vf->restore_exit (status);
if (exit_state < ES_SIGNAL)
{
@@ -962,7 +1015,7 @@ do_exit (int status)
/* CGF FIXME: This can't be right. */
if (tp->getsid () == myself->sid)
- kill_pgrp (tp->getpgid (), SIGHUP);
+ tp->kill_pgrp (SIGHUP);
}
tty_terminate ();
@@ -1000,10 +1053,10 @@ __api_fatal (const char *fmt, ...)
a serious error. */
if (GetFileType (GetStdHandle (STD_ERROR_HANDLE)) != FILE_TYPE_CHAR)
{
- HANDLE h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_WRITE | FILE_SHARE_WRITE, &sec_none,
- OPEN_EXISTING, 0, 0);
- if (h)
+ HANDLE h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_WRITE,
+ &sec_none, OPEN_EXISTING, 0, 0);
+ if (h != INVALID_HANDLE_VALUE)
(void) WriteFile (h, buf, len, &done, 0);
}
@@ -1016,6 +1069,30 @@ __api_fatal (const char *fmt, ...)
myself->exit (1);
}
+void
+multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version)
+{
+ if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap")))
+ {
+ child_proc_info->type = _PROC_WHOOPS;
+ return;
+ }
+
+ char buf[1024];
+ if (GetEnvironmentVariable ("CYGWIN_MISMATCH_OK", buf, sizeof (buf)))
+ return;
+
+ if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version)
+ system_printf ("%s magic number mismatch detected - %p/%p", what, magic_version, version);
+ else
+ api_fatal ("%s version mismatch detected - %p/%p.\n\
+You have multiple copies of cygwin1.dll on your system.\n\
+Search for cygwin1.dll using the Windows Start->Find/Search facility\n\
+and delete all but the most recent version. The most recent version *should*\n\
+reside in x:\\cygwin\\bin, where 'x' is the drive on which you have\n\
+installed the cygwin distribution.", what, magic_version, version);
+}
+
#ifdef DEBUGGING
void __stdcall
cygbench (const char *s)
diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc
index e8293b91f..418f35510 100644
--- a/winsup/cygwin/debug.cc
+++ b/winsup/cygwin/debug.cc
@@ -1,200 +1,66 @@
/* debug.cc
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include "exceptions.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "perthread.h"
#include "perprocess.h"
#include "security.h"
+#include "cygerrno.h"
+#ifdef DEBUGGING
+#include <errno.h>
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "cygheap.h"
+#endif
#undef CloseHandle
-static muto NO_COPY *threadname_lock = NULL;
-#define lock_threadname() \
- do {if (threadname_lock) threadname_lock->acquire (INFINITE); } while (0)
-
-#define unlock_threadname() \
- do {if (threadname_lock) threadname_lock->release (); } while (0)
-
-typedef struct
- {
- DWORD id;
- const char *name;
- } thread_info;
-
-static NO_COPY thread_info threads[32] = {{0, NULL}}; // increase as necessary
-#define NTHREADS (sizeof (threads) / sizeof (threads[0]))
-
-void
-threadname_init ()
-{
- threadname_lock = new_muto (FALSE, "threadname_lock");
-}
-
-void __stdcall
-regthread (const char *name, DWORD tid)
-{
- lock_threadname ();
- for (DWORD i = 0; i < NTHREADS; i++)
- if (threads[i].name == NULL || strcmp (threads[i].name, name) == 0 ||
- threads[i].id == tid)
- {
- threads[i].name = name;
- threads[i].id = tid;
- break;
- }
- unlock_threadname ();
-}
-
-int __stdcall
-iscygthread ()
-{
- DWORD tid = GetCurrentThreadId ();
- if (tid != mainthread.id)
- for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++)
- if (threads[i].id == tid)
- return 1;
- return 0;
-}
-
-struct thread_start
- {
- LONG notavail;
- LPTHREAD_START_ROUTINE func;
- VOID *arg;
- };
-
-/* A place to store arguments to thread_stub since they can't be
- stored on the stack. An available element is !notavail. */
-thread_start NO_COPY start_buf[NTHREADS] = {{0, NULL,NULL}};
-
-/* Initial stub called by makethread. Performs initial per-thread
- initialization. */
-static DWORD WINAPI
-thread_stub (VOID *arg)
-{
- LPTHREAD_START_ROUTINE threadfunc = ((thread_start *) arg)->func;
- VOID *threadarg = ((thread_start *) arg)->arg;
-
- exception_list except_entry;
-
- /* Give up our slot in the start_buf array */
- (void) InterlockedExchange (&((thread_start *) arg)->notavail, 0);
-
- /* Initialize this thread's ability to respond to things like
- SIGSEGV or SIGFPE. */
- init_exceptions (&except_entry);
-
- set_reent (user_data->impure_ptr);
- ExitThread (threadfunc (threadarg));
-}
-
-/* Wrapper for CreateThread. Registers the thread name/id and ensures that
- cygwin threads are properly initialized. */
-HANDLE __stdcall
-makethread (LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags,
- const char *name)
-{
- DWORD tid;
- HANDLE h;
- thread_start *info; /* Various information needed by the newly created thread */
-
- for (;;)
- {
- /* Search the start_buf array for an empty slot to use */
- for (info = start_buf; info < start_buf + NTHREADS; info++)
- if (!InterlockedExchange (&info->notavail, 1))
- goto out;
-
- /* Should never hit here, but be defensive anyway. */
- Sleep (0);
- }
-
-out:
- info->func = start; /* Real function to start */
- info->arg = param; /* The single parameter to the thread */
-
- if ((h = CreateThread (&sec_none_nih, 0, thread_stub, (VOID *) info, flags,
- &tid)))
- regthread (name, tid); /* Register for debugging output. */
-
- return h;
-}
-
-/* Return the symbolic name of the current thread for debugging.
- */
-const char * __stdcall
-threadname (DWORD tid, int lockit)
-{
- const char *res = NULL;
- if (!tid)
- tid = GetCurrentThreadId ();
-
- if (lockit)
- lock_threadname ();
- for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++)
- if (threads[i].id == tid)
- {
- res = threads[i].name;
- break;
- }
- if (lockit)
- unlock_threadname ();
-
- if (!res)
- {
- static char buf[30] NO_COPY = {0};
- __small_sprintf (buf, "unknown (%p)", tid);
- res = buf;
- }
-
- return res;
-}
-
#ifdef DEBUGGING
/* Here lies extra debugging routines which help track down internal
Cygwin problems when compiled with -DDEBUGGING . */
#include <stdlib.h>
+#define NFREEH (sizeof (cygheap->debug.freeh) / sizeof (cygheap->debug.freeh[0]))
-typedef struct _h
+class lock_debug
+{
+ static muto *locker;
+ bool acquired;
+ public:
+ lock_debug () : acquired (0)
{
- BOOL allocated;
- HANDLE h;
- const char *name;
- const char *func;
- int ln;
- DWORD clexec_pid;
- struct _h *next;
- } handle_list;
-
-static NO_COPY handle_list starth = {0, NULL, NULL, NULL, 0, 0, NULL};
-static NO_COPY handle_list *endh = NULL;
-
-static handle_list NO_COPY freeh[1000] = {{0, NULL, NULL, NULL, 0, 0, NULL}};
-#define NFREEH (sizeof (freeh) / sizeof (freeh[0]))
-
-static muto NO_COPY *debug_lock = NULL;
-
-#define lock_debug() \
- do {if (debug_lock) debug_lock->acquire (INFINITE); } while (0)
+ if (locker)
+ acquired = !!locker->acquire (INFINITE);
+ }
+ void unlock ()
+ {
+ if (locker && acquired)
+ {
+ locker->release ();
+ acquired = false;
+ }
+ }
+ ~lock_debug () {unlock ();}
+ friend void debug_init ();
+};
-#define unlock_debug() \
- do {if (debug_lock) debug_lock->release (); } while (0)
+muto NO_COPY *lock_debug::locker = NULL;
static bool __stdcall mark_closed (const char *, int, HANDLE, const char *, BOOL);
void
debug_init ()
{
- debug_lock = new_muto (FALSE, "debug_lock");
+ muto *debug_lock_muto;
+ lock_debug::locker = new_muto (debug_lock_muto);
}
/* Find a registered handle in the linked list of handles. */
@@ -202,68 +68,68 @@ static handle_list * __stdcall
find_handle (HANDLE h)
{
handle_list *hl;
- for (hl = &starth; hl->next != NULL; hl = hl->next)
+ for (hl = &cygheap->debug.starth; hl->next != NULL; hl = hl->next)
if (hl->next->h == h)
goto out;
- endh = hl;
+ cygheap->debug.endh = hl;
hl = NULL;
out:
return hl;
}
+#ifdef DEBUGGING_AND_FDS_PROTECTED
void
-setclexec_pid (HANDLE h, bool setit)
+setclexec (HANDLE oh, HANDLE nh, bool not_inheriting)
{
- handle_list *hl = find_handle (h);
+ handle_list *hl = find_handle (oh);
if (hl)
- hl->clexec_pid = setit ? GetCurrentProcessId () : 0;
+ {
+ hl = hl->next;
+ hl->inherited = !not_inheriting;
+ hl->h = nh;
+ }
}
+#endif
/* Create a new handle record */
static handle_list * __stdcall
newh ()
{
handle_list *hl;
- lock_debug ();
- for (hl = freeh; hl < freeh + NFREEH; hl++)
- if (hl->name == NULL)
- goto out;
+ lock_debug here;
- /* All used up??? */
- if ((hl = (handle_list *) malloc (sizeof *hl)) != NULL)
- {
- memset (hl, 0, sizeof (*hl));
- hl->allocated = TRUE;
- }
+ for (hl = cygheap->debug.freeh; hl < cygheap->debug.freeh + NFREEH; hl++)
+ if (hl->name == NULL)
+ return hl;
-out:
- unlock_debug ();
- return hl;
+ return NULL;
}
/* Add a handle to the linked list of known handles. */
void __stdcall
-add_handle (const char *func, int ln, HANDLE h, const char *name)
+add_handle (const char *func, int ln, HANDLE h, const char *name, bool inh)
{
handle_list *hl;
- lock_debug ();
+ lock_debug here;
if ((hl = find_handle (h)))
{
hl = hl->next;
+ if (hl->name == name && hl->func == func && hl->ln == ln)
+ return;
system_printf ("%s:%d - multiple attempts to add handle %s<%p>", func,
ln, name, h);
- system_printf (" previously allocated by %s:%d(%s<%p>)",
- hl->func, hl->ln, hl->name, hl->h);
- goto out; /* Already did this once */
+ system_printf (" previously allocated by %s:%d(%s<%p>) winpid %d",
+ hl->func, hl->ln, hl->name, hl->h, hl->pid);
+ return;
}
if ((hl = newh ()) == NULL)
{
- unlock_debug ();
- system_printf ("couldn't allocate memory for %s(%d): %s(%p)",
- func, ln, name, h);
+ here.unlock ();
+ debug_printf ("couldn't allocate memory for %s(%d): %s(%p)",
+ func, ln, name, h);
return;
}
hl->h = h;
@@ -271,44 +137,48 @@ add_handle (const char *func, int ln, HANDLE h, const char *name)
hl->func = func;
hl->ln = ln;
hl->next = NULL;
- endh->next = hl;
- endh = hl;
+ hl->inherited = inh;
+ hl->pid = GetCurrentProcessId ();
+ cygheap->debug.endh->next = hl;
+ cygheap->debug.endh = hl;
+ debug_printf ("protecting handle '%s', inherited flag %d", hl->name, hl->inherited);
-out:
- unlock_debug ();
+ return;
}
static void __stdcall
delete_handle (handle_list *hl)
{
handle_list *hnuke = hl->next;
+ debug_printf ("nuking handle '%s'", hnuke->name);
hl->next = hl->next->next;
- if (hnuke->allocated)
- free (hnuke);
- else
- memset (hnuke, 0, sizeof (*hnuke));
+ memset (hnuke, 0, sizeof (*hnuke));
}
void
-debug_fixup_after_fork ()
+debug_fixup_after_fork_exec ()
{
+ /* No lock needed at this point */
handle_list *hl;
- for (hl = &starth; hl->next != NULL; hl = hl->next)
- if (hl->next->clexec_pid)
- delete_handle (hl);
+ for (hl = &cygheap->debug.starth; hl->next != NULL; /* nothing */)
+ if (hl->next->inherited)
+ hl = hl->next;
+ else
+ delete_handle (hl); // removes hl->next
}
static bool __stdcall
mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force)
{
handle_list *hl;
- lock_debug ();
+ lock_debug here;
+
if ((hl = find_handle (h)) && !force)
{
hl = hl->next;
- unlock_debug (); // race here
- system_printf ("attempt to close protected handle %s:%d(%s<%p>)",
- hl->func, hl->ln, hl->name, hl->h);
+ here.unlock (); // race here
+ system_printf ("attempt to close protected handle %s:%d(%s<%p>) winpid %d",
+ hl->func, hl->ln, hl->name, hl->h, hl->pid);
system_printf (" by %s:%d(%s<%p>)", func, ln, name, h);
return FALSE;
}
@@ -324,7 +194,6 @@ mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force)
if (hl)
delete_handle (hl);
- unlock_debug ();
return TRUE;
}
@@ -334,18 +203,24 @@ BOOL __stdcall
close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
{
BOOL ret;
- lock_debug ();
+ lock_debug here;
if (!mark_closed (func, ln, h, name, force))
return FALSE;
ret = CloseHandle (h);
- unlock_debug ();
#if 0 /* Uncomment to see CloseHandle failures */
if (!ret)
small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
#endif
return ret;
}
+
+int __stdcall
+__set_errno (const char *func, int ln, int val)
+{
+ debug_printf ("%s:%d val %d", func, ln, val);
+ return _impure_ptr->_errno = val;
+}
#endif /*DEBUGGING*/
diff --git a/winsup/cygwin/debug.h b/winsup/cygwin/debug.h
index 8323e617a..09a74e917 100644
--- a/winsup/cygwin/debug.h
+++ b/winsup/cygwin/debug.h
@@ -1,6 +1,6 @@
/* debug.h
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@@ -23,16 +23,13 @@ DWORD __stdcall WFMO (DWORD, CONST HANDLE *, BOOL, DWORD) __attribute__ ((regpar
}
#define WaitForSingleObject WFSO
-#define WaitForMultipleObject WFMO
+#define WaitForMultipleObjects WFMO
#if !defined(_DEBUG_H_)
#define _DEBUG_H_
-void threadname_init ();
-HANDLE __stdcall makethread (LPTHREAD_START_ROUTINE, LPVOID, DWORD, const char *) __attribute__ ((regparm(3)));
-const char * __stdcall threadname (DWORD, int lockit = TRUE) __attribute__ ((regparm(2)));
-void __stdcall regthread (const char *, DWORD) __attribute__ ((regparm(1)));
-int __stdcall iscygthread ();
+#define being_debugged() \
+ (IsDebuggerPresent () /* || GetLastError () == ERROR_PROC_NOT_FOUND*/)
#ifndef DEBUGGING
# define cygbench(s)
@@ -42,9 +39,12 @@ int __stdcall iscygthread ();
# define ProtectHandle(h) do {} while (0)
# define ProtectHandle1(h,n) do {} while (0)
# define ProtectHandle2(h,n) do {} while (0)
+# define ProtectHandleINH(h) do {} while (0)
+# define ProtectHandle1INH(h,n) do {} while (0)
+# define ProtectHandle2INH(h,n) do {} while (0)
# define debug_init() do {} while (0)
-# define setclexec_pid(h, b) do {} while (0)
-# define debug_fixup_after_fork() do {} while (0)
+# define setclexec(h, nh, b) do {} while (0)
+# define debug_fixup_after_fork_exec() do {} while (0)
#else
@@ -64,17 +64,31 @@ int __stdcall iscygthread ();
# define ProtectHandle(h) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), #h)
# define ProtectHandle1(h, n) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), #n)
# define ProtectHandle2(h, n) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), n)
+# define ProtectHandleINH(h) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), #h, 1)
+# define ProtectHandle1INH(h, n) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), #n, 1)
+# define ProtectHandle2INH(h, n) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), n, 1)
void debug_init ();
-void __stdcall add_handle (const char *, int, HANDLE, const char *)
+void __stdcall add_handle (const char *, int, HANDLE, const char *, bool = false)
__attribute__ ((regparm (3)));
BOOL __stdcall close_handle (const char *, int, HANDLE, const char *, BOOL)
__attribute__ ((regparm (3)));
void __stdcall cygbench (const char *s) __attribute__ ((regparm (1)));
extern "C" void console_printf (const char *fmt,...);
-void setclexec_pid (HANDLE, bool);
-void debug_fixup_after_fork ();
+void setclexec (HANDLE, HANDLE, bool);
+void debug_fixup_after_fork_exec ();
extern int pinger;
+struct handle_list
+ {
+ HANDLE h;
+ const char *name;
+ const char *func;
+ int ln;
+ bool inherited;
+ DWORD pid;
+ struct handle_list *next;
+ };
+
#endif /*DEBUGGING*/
#endif /*_DEBUG_H_*/
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index 079c5c4fe..45ba57ff6 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -1,6 +1,6 @@
/* dir.cc: Posix directory-related routines
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <sys/fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
@@ -18,13 +17,10 @@ details. */
#define _COMPILING_NEWLIB
#include <dirent.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
-#include "perprocess.h"
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
@@ -65,6 +61,8 @@ writable_directory (const char *file)
extern "C" int
dirfd (DIR *dir)
{
+ if (check_null_invalid_struct_errno (dir))
+ return -1;
if (dir->__d_cookie != __DIRENT_COOKIE)
{
set_errno (EBADF);
@@ -76,220 +74,136 @@ dirfd (DIR *dir)
/* opendir: POSIX 5.1.2.1 */
extern "C" DIR *
-opendir (const char *dirname)
+opendir (const char *name)
{
- int len;
- DIR *dir;
- DIR *res = 0;
- struct stat statbuf;
-
- path_conv real_dirname (dirname, PC_SYM_FOLLOW | PC_FULL);
-
- if (real_dirname.error)
- {
- set_errno (real_dirname.error);
- goto failed;
- }
-
- if (stat (real_dirname, &statbuf) == -1)
- goto failed;
-
- if (!(statbuf.st_mode & S_IFDIR))
- {
- set_errno (ENOTDIR);
- goto failed;
- }
-
- len = strlen (real_dirname);
- if (len > MAX_PATH - 3)
- {
- set_errno (ENAMETOOLONG);
- goto failed;
- }
-
- if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
- {
- set_errno (ENOMEM);
- goto failed;
- }
- if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
- {
- free (dir);
- set_errno (ENOMEM);
- goto failed;
- }
- if ((dir->__d_dirent =
- (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
+ fhandler_base *fh;
+ path_conv pc;
+ DIR *res;
+
+ fh = cygheap->fdtab.build_fhandler_from_name (-1, name, NULL, pc,
+ PC_SYM_FOLLOW | PC_FULL, NULL);
+ if (!fh)
+ res = NULL;
+ else if (pc.exists ())
+ res = fh->opendir (pc);
+ else
{
- free (dir->__d_dirname);
- free (dir);
- set_errno (ENOMEM);
- goto failed;
+ set_errno (ENOENT);
+ res = NULL;
}
- strcpy (dir->__d_dirname, real_dirname.get_win32 ());
- dir->__d_dirent->d_version = __DIRENT_VERSION;
- dir->__d_dirent->d_fd = open (dir->__d_dirname, O_RDONLY | O_DIROPEN);
- /* FindFirstFile doesn't seem to like duplicate /'s. */
- len = strlen (dir->__d_dirname);
- if (len == 0 || SLASH_P (dir->__d_dirname[len - 1]))
- strcat (dir->__d_dirname, "*");
- else
- strcat (dir->__d_dirname, "\\*"); /**/
- dir->__d_cookie = __DIRENT_COOKIE;
- dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
- dir->__d_position = 0;
- dir->__d_dirhash = statbuf.st_ino;
- res = dir;
-
-failed:
- syscall_printf ("%p = opendir (%s)", res, dirname);
+ if (!res && fh)
+ delete fh;
return res;
}
/* readdir: POSIX 5.1.2.1 */
extern "C" struct dirent *
-readdir (DIR * dir)
+readdir (DIR *dir)
{
- WIN32_FIND_DATA buf;
- HANDLE handle;
- struct dirent *res = NULL;
+ if (check_null_invalid_struct_errno (dir))
+ return NULL;
if (dir->__d_cookie != __DIRENT_COOKIE)
{
set_errno (EBADF);
- syscall_printf ("%p = readdir (%p)", res, dir);
- return res;
- }
-
- if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE
- && dir->__d_position == 0)
- {
- handle = FindFirstFileA (dir->__d_dirname, &buf);
- DWORD lasterr = GetLastError ();
- dir->__d_u.__d_data.__handle = handle;
- if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES))
- {
- seterrno_from_win_error (__FILE__, __LINE__, lasterr);
- return res;
- }
- }
- else if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE)
- {
- return res;
- }
- else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf))
- {
- DWORD lasterr = GetLastError ();
- (void) FindClose (dir->__d_u.__d_data.__handle);
- dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
- /* POSIX says you shouldn't set errno when readdir can't
- find any more files; so, if another error we leave it set. */
- if (lasterr != ERROR_NO_MORE_FILES)
- seterrno_from_win_error (__FILE__, __LINE__, lasterr);
- syscall_printf ("%p = readdir (%p)", res, dir);
- return res;
+ syscall_printf ("%p = readdir (%p)", NULL, dir);
+ return NULL;
}
- /* We get here if `buf' contains valid data. */
- strcpy (dir->__d_dirent->d_name, buf.cFileName);
+ dirent *res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->readdir (dir);
- /* Check for Windows shortcut. If it's a Cygwin or U/WIN
- symlink, drop the .lnk suffix. */
- if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ if (res)
{
- char *c = dir->__d_dirent->d_name;
- int len = strlen (c);
- if (strcasematch (c + len - 4, ".lnk"))
+ /* Compute d_ino by combining filename hash with the directory hash
+ (which was stored in dir->__d_dirhash when opendir was called). */
+ if (res->d_name[0] == '.')
{
- char fbuf[MAX_PATH + 1];
- strcpy (fbuf, dir->__d_dirname);
- strcpy (fbuf + strlen (fbuf) - 1, dir->__d_dirent->d_name);
- path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
- if (fpath.issymlink ())
- c[len - 4] = '\0';
- }
- }
-
- /* Compute d_ino by combining filename hash with the directory hash
- (which was stored in dir->__d_dirhash when opendir was called). */
- if (buf.cFileName[0] == '.')
- {
- if (buf.cFileName[1] == '\0')
- dir->__d_dirent->d_ino = dir->__d_dirhash;
- else if (buf.cFileName[1] != '.' || buf.cFileName[2] != '\0')
- goto hashit;
- else
- {
- char *p, up[strlen (dir->__d_dirname) + 1];
- strcpy (up, dir->__d_dirname);
- if (!(p = strrchr (up, '\\')))
+ if (res->d_name[1] == '\0')
+ dir->__d_dirent->d_ino = dir->__d_dirhash;
+ else if (res->d_name[1] != '.' || res->d_name[2] != '\0')
goto hashit;
- *p = '\0';
- if (!(p = strrchr (up, '\\')))
- dir->__d_dirent->d_ino = hash_path_name (0, ".");
else
{
+ char *p, up[strlen (dir->__d_dirname) + 1];
+ strcpy (up, dir->__d_dirname);
+ if (!(p = strrchr (up, '\\')))
+ goto hashit;
*p = '\0';
- dir->__d_dirent->d_ino = hash_path_name (0, up);
+ if (!(p = strrchr (up, '\\')))
+ dir->__d_dirent->d_ino = hash_path_name (0, ".");
+ else
+ {
+ *p = '\0';
+ dir->__d_dirent->d_ino = hash_path_name (0, up);
+ }
}
}
+ else
+ {
+ hashit:
+ ino_t dino = hash_path_name (dir->__d_dirhash, "\\");
+ dir->__d_dirent->d_ino = hash_path_name (dino, res->d_name);
+ }
}
- else
- {
- hashit:
- ino_t dino = hash_path_name (dir->__d_dirhash, "\\");
- dir->__d_dirent->d_ino = hash_path_name (dino, buf.cFileName);
- }
-
- ++dir->__d_position;
- res = dir->__d_dirent;
- syscall_printf ("%p = readdir (%p) (%s)",
- &dir->__d_dirent, dir, buf.cFileName);
return res;
}
-/* telldir */
-extern "C" off_t
-telldir (DIR * dir)
+extern "C" __off64_t
+telldir64 (DIR *dir)
{
+ if (check_null_invalid_struct_errno (dir))
+ return -1;
+
if (dir->__d_cookie != __DIRENT_COOKIE)
return 0;
- return dir->__d_position;
+ return ((fhandler_base *) dir->__d_u.__d_data.__fh)->telldir (dir);
+}
+
+/* telldir */
+extern "C" __off32_t
+telldir (DIR *dir)
+{
+ return telldir64 (dir);
}
-/* seekdir */
extern "C" void
-seekdir (DIR * dir, off_t loc)
+seekdir64 (DIR *dir, __off64_t loc)
{
+ if (check_null_invalid_struct_errno (dir))
+ return;
+
if (dir->__d_cookie != __DIRENT_COOKIE)
return;
- rewinddir (dir);
- while (loc > dir->__d_position)
- if (! readdir (dir))
- break;
+ return ((fhandler_base *) dir->__d_u.__d_data.__fh)->seekdir (dir, loc);
+}
+
+/* seekdir */
+extern "C" void
+seekdir (DIR *dir, __off32_t loc)
+{
+ seekdir64 (dir, (__off64_t)loc);
}
/* rewinddir: POSIX 5.1.2.1 */
extern "C" void
-rewinddir (DIR * dir)
+rewinddir (DIR *dir)
{
- syscall_printf ("rewinddir (%p)", dir);
+ if (check_null_invalid_struct_errno (dir))
+ return;
if (dir->__d_cookie != __DIRENT_COOKIE)
return;
- if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE)
- {
- (void) FindClose (dir->__d_u.__d_data.__handle);
- dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
- }
- dir->__d_position = 0;
+ return ((fhandler_base *) dir->__d_u.__d_data.__fh)->rewinddir (dir);
}
/* closedir: POSIX 5.1.2.1 */
extern "C" int
-closedir (DIR * dir)
+closedir (DIR *dir)
{
+ if (check_null_invalid_struct_errno (dir))
+ return -1;
+
if (dir->__d_cookie != __DIRENT_COOKIE)
{
set_errno (EBADF);
@@ -297,25 +211,18 @@ closedir (DIR * dir)
return -1;
}
- if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE &&
- FindClose (dir->__d_u.__d_data.__handle) == 0)
- {
- __seterrno ();
- syscall_printf ("-1 = closedir (%p)", dir);
- return -1;
- }
-
- if (dir->__d_dirent->d_fd >= 0)
- close (dir->__d_dirent->d_fd);
-
/* Reset the marker in case the caller tries to use `dir' again. */
dir->__d_cookie = 0;
+ int res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->closedir (dir);
+
+ cygheap->fdtab.release (dir->__d_dirent->d_fd);
+
free (dir->__d_dirname);
free (dir->__d_dirent);
free (dir);
- syscall_printf ("0 = closedir (%p)", dir);
- return 0;
+ syscall_printf ("%d = closedir (%p)", res);
+ return res;
}
/* mkdir: POSIX 5.4.1.1 */
@@ -346,6 +253,11 @@ mkdir (const char *dir, mode_t mode)
if (!allow_ntsec && allow_ntea)
set_file_attribute (real_dir.has_acls (), real_dir.get_win32 (),
S_IFDIR | ((mode & 07777) & ~cygheap->umask));
+#ifdef HIDDEN_DOT_FILES
+ char *c = strrchr (real_dir.get_win32 (), '\\');
+ if ((c && c[1] == '.') || *real_dir.get_win32 () == '.')
+ SetFileAttributes (real_dir.get_win32 (), FILE_ATTRIBUTE_HIDDEN);
+#endif
res = 0;
}
else
@@ -361,37 +273,32 @@ extern "C" int
rmdir (const char *dir)
{
int res = -1;
+ DWORD devn;
path_conv real_dir (dir, PC_SYM_NOFOLLOW);
if (real_dir.error)
- {
- set_errno (real_dir.error);
- res = -1;
- }
+ set_errno (real_dir.error);
+ else if ((devn = real_dir.get_devn ()) == FH_PROC || devn == FH_REGISTRY
+ || devn == FH_PROCESS)
+ set_errno (EROFS);
else if (!real_dir.exists ())
- {
- set_errno (ENOENT);
- res = -1;
- }
+ set_errno (ENOENT);
else if (!real_dir.isdir ())
- {
- set_errno (ENOTDIR);
- res = -1;
- }
+ set_errno (ENOTDIR);
else
{
/* Even own directories can't be removed if R/O attribute is set. */
if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
SetFileAttributes (real_dir,
- (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY);
+ (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY);
if (RemoveDirectory (real_dir))
{
/* RemoveDirectory on a samba drive doesn't return an error if the
directory can't be removed because it's not empty. Checking for
existence afterwards keeps us informed about success. */
- if (GetFileAttributes (real_dir) != (DWORD) -1)
+ if (GetFileAttributes (real_dir) != INVALID_FILE_ATTRIBUTES)
set_errno (ENOTEMPTY);
else
res = 0;
@@ -418,22 +325,20 @@ rmdir (const char *dir)
else if ((res = rmdir (dir)))
SetCurrentDirectory (cygheap->cwd.win32);
}
- if (GetLastError () == ERROR_ACCESS_DENIED)
+ if (res)
{
-
- /* On 9X ERROR_ACCESS_DENIED is returned if you try to remove
- a non-empty directory. */
- if (wincap.access_denied_on_delete ())
- set_errno (ENOTEMPTY);
- else
+ if (GetLastError () != ERROR_ACCESS_DENIED
+ || !wincap.access_denied_on_delete ())
__seterrno ();
- }
- else
- __seterrno ();
+ else
+ set_errno (ENOTEMPTY); /* On 9X ERROR_ACCESS_DENIED is
+ returned if you try to remove a
+ non-empty directory. */
- /* If directory still exists, restore R/O attribute. */
- if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
- SetFileAttributes (real_dir, real_dir);
+ /* If directory still exists, restore R/O attribute. */
+ if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_dir, real_dir);
+ }
}
}
diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc
index 69716cc8a..b6babe66b 100644
--- a/winsup/cygwin/dlfcn.cc
+++ b/winsup/cygwin/dlfcn.cc
@@ -22,8 +22,8 @@ details. */
#include "dll_init.h"
#include "cygerrno.h"
-#define _dl_error _reent_winsup()->_dl_error
-#define _dl_buffer _reent_winsup()->_dl_buffer
+#define _dl_error _reent_winsup ()->_dl_error
+#define _dl_buffer _reent_winsup ()->_dl_buffer
static void __stdcall
set_dl_error (const char *str)
@@ -38,7 +38,7 @@ set_dl_error (const char *str)
inline const char * __stdcall
check_path_access (const char *mywinenv, const char *name, path_conv& buf)
{
- return find_exec (name, buf, mywinenv, TRUE);
+ return find_exec (name, buf, mywinenv, FE_NNF | FE_NATIVE | FE_CWD);
}
/* Search LD_LIBRARY_PATH for dll, if it exists.
@@ -85,7 +85,7 @@ get_full_path_of_dll (const char* str, char *name)
void *
dlopen (const char *name, int)
{
- SetResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlopen");
+ SetResourceLock (LOCK_DLL_LIST, READ_LOCK | WRITE_LOCK, "dlopen");
void *ret;
@@ -110,7 +110,7 @@ dlopen (const char *name, int)
set_dl_error ("dlopen");
debug_printf ("ret %p", ret);
- ReleaseResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlopen");
+ ReleaseResourceLock (LOCK_DLL_LIST, READ_LOCK | WRITE_LOCK, "dlopen");
return ret;
}
@@ -127,7 +127,7 @@ dlsym (void *handle, const char *name)
int
dlclose (void *handle)
{
- SetResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlclose");
+ SetResourceLock (LOCK_DLL_LIST, READ_LOCK | WRITE_LOCK, "dlclose");
int ret = -1;
void *temphandle = (void *) GetModuleHandle (NULL);
@@ -137,7 +137,7 @@ dlclose (void *handle)
set_dl_error ("dlclose");
CloseHandle ((HMODULE) temphandle);
- ReleaseResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlclose");
+ ReleaseResourceLock (LOCK_DLL_LIST, READ_LOCK | WRITE_LOCK, "dlclose");
return ret;
}
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index d4dcca0e9..5a5b165dc 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -1,6 +1,6 @@
/* dll_init.cc
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@@ -8,7 +8,7 @@ details. */
#include "winsup.h"
#include <stdlib.h>
-#include "exceptions.h"
+#include <errno.h>
#include "cygerrno.h"
#include "perprocess.h"
#include "dll_init.h"
@@ -18,6 +18,7 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
+#include "pinfo.h"
extern void __stdcall check_sanity_and_sync (per_process *);
@@ -97,7 +98,7 @@ dll_list::operator[] (const char *name)
return NULL;
}
-#define RETRIES 100
+#define RETRIES 1000
/* Allocate space for a dll struct contiguous with the just-loaded dll. */
dll *
@@ -183,6 +184,9 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
void
dll_list::detach (dll *d)
{
+ if (!myself || myself->process_state == PID_EXITED)
+ return;
+
if (d->count <= 0)
system_printf ("WARNING: try to detach an already detached dll ...\n");
else if (--d->count == 0)
@@ -203,7 +207,6 @@ dll_list::detach (dll *d)
void
dll_list::init ()
{
- debug_printf ("here");
/* Make sure that destructors are called on exit. */
if (!dll_global_dtors_recorded)
{
diff --git a/winsup/cygwin/dll_init.h b/winsup/cygwin/dll_init.h
index a5b33d572..bc9687bf7 100644
--- a/winsup/cygwin/dll_init.h
+++ b/winsup/cygwin/dll_init.h
@@ -73,12 +73,6 @@ public:
void detach (dll *);
void init ();
void load_after_fork (HANDLE, dll *);
- dll *istart (dll_type t)
- {
- hold_type = t;
- hold = &start;
- return inext ();
- }
dll *inext ()
{
while ((hold = hold->next))
@@ -86,6 +80,12 @@ public:
break;
return hold;
}
+ dll *istart (dll_type t)
+ {
+ hold_type = t;
+ hold = &start;
+ return inext ();
+ }
};
extern dll_list dlls;
diff --git a/winsup/cygwin/dlmalloc.c b/winsup/cygwin/dlmalloc.c
index 3435950b4..de14fcb6a 100644
--- a/winsup/cygwin/dlmalloc.c
+++ b/winsup/cygwin/dlmalloc.c
@@ -28,6 +28,29 @@
* malloc_usable_size(P) is equivalent to realloc(P, malloc_usable_size(P))
*
* $Log$
+ * Revision 1.5 2001/10/03 03:49:25 cgf
+ * * cygheap.cc (cfree): Remove malloc debugging probe.
+ * * dlmalloc.c (errprint): Remove abort() call which causes interesting error
+ * message printing to abort prematurely.
+ * * environ.cc: Sprinkle MALLOC_CHECKs liberally throughout.
+ * (_addenv): Allocate two empty elements at end of environ to
+ * (apparently) work around problems with some buggy applications.
+ * (winenv): Avoid calling alloca if no forced environment variable is present.
+ *
+ * * exceptions.cc (open_stackdumpfile): Don't print "Dumping stack trace to..."
+ * when running in a cygwin environment (i.e., the parent is a cygwin process).
+ *
+ * * dtable.cc (dtable::init_std_file_from_handle): Move device type detection
+ * code from build_fhandler here since it is only used by this function.
+ * (dtable::build_fhandler_from_name): New method. Renamed from
+ * dtable::build_fhandler.
+ * (dtable::build_fhandler): Use build_fhandler_from_name.
+ * (cygwin_attach_handle_to_fd): Ditto.
+ * * syscalls.cc (_open): Ditto.
+ * (stat_worker): Ditto.
+ * * dtable.h (dtable::build_fhandler_from_name): Rename declaration from
+ * dtable::build_fhandler.
+ *
* Revision 1.4 2001/09/07 21:32:04 cgf
* * cygheap.h (init_cygheap): Move heap pointers here.
* * include/sys/cygwin.h (perprocess): Remove heap pointers.
@@ -1843,7 +1866,6 @@ static void errprint(const char *file, int line, const char *err)
write(2, err, strlen(err));
write(2, "\n", 1);
recurs--;
- abort ();
}
static void malloc_err(const char *err, mchunkptr p)
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 96ee5a503..9fc6f4e21 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -1,6 +1,6 @@
/* dtable.cc: file descriptor support.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -16,13 +16,13 @@ details. */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <fcntl.h>
#include <sys/cygwin.h>
+#include <assert.h>
+#include <ntdef.h>
+#include <winnls.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "cygerrno.h"
#include "perprocess.h"
@@ -31,9 +31,12 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
+#include "ntdll.h"
static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
- STD_ERROR_HANDLE};
+ STD_ERROR_HANDLE};
+
+static char *handle_to_fn (HANDLE, char *);
/* Set aside space for the table of fds */
void
@@ -55,7 +58,8 @@ set_std_handle (int fd)
void
dtable::dec_console_fds ()
{
- if (console_fds > 0 && !--console_fds && myself->ctty != TTY_CONSOLE)
+ if (console_fds > 0 && !--console_fds &&
+ myself->ctty != TTY_CONSOLE && !check_pty_fds())
FreeConsole ();
}
@@ -88,59 +92,84 @@ dtable::extend (int howmuch)
return 1;
}
+void
+dtable::get_debugger_info ()
+{
+ if (being_debugged ())
+ {
+ char std[3][sizeof ("/dev/ttyNNNN")];
+ std[0][0] = std[1][0] = std [2][0] = '\0';
+ char buf[sizeof ("cYgstd %x") + 32];
+ sprintf (buf, "cYgstd %x %x %x", (unsigned) &std, sizeof (std[0]), 3);
+ OutputDebugString (buf);
+ for (int i = 0; i < 3; i++)
+ if (std[i][0])
+ {
+ path_conv pc;
+ HANDLE h = GetStdHandle (std_consts[i]);
+ fhandler_base *fh = build_fhandler_from_name (i, std[i], NULL, pc);
+ if (!fh)
+ continue;
+ if (!fh->open (&pc, (i ? O_WRONLY : O_RDONLY) | O_BINARY, 0777))
+ release (i);
+ else
+ CloseHandle (h);
+ }
+ }
+}
+
/* Initialize the file descriptor/handle mapping table.
- We only initialize the parent table here. The child table is
- initialized at each fork () call. */
+ This function should only be called when a cygwin function is invoked
+ by a non-cygwin function, i.e., it should only happen very rarely. */
void
-stdio_init (void)
+dtable::stdio_init ()
{
extern void set_console_ctty ();
/* Set these before trying to output anything from strace.
Also, always set them even if we're to pick up our parent's fds
in case they're missed. */
- if (!myself->ppid_handle && NOTSTATE (myself, PID_CYGPARENT))
- {
- HANDLE in = GetStdHandle (STD_INPUT_HANDLE);
- HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
- HANDLE err = GetStdHandle (STD_ERROR_HANDLE);
+ if (myself->ppid_handle || ISSTATE (myself, PID_CYGPARENT))
+ return;
- cygheap->fdtab.init_std_file_from_handle (0, in, GENERIC_READ);
+ HANDLE in = GetStdHandle (STD_INPUT_HANDLE);
+ HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
+ HANDLE err = GetStdHandle (STD_ERROR_HANDLE);
- /* STD_ERROR_HANDLE has been observed to be the same as
- STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes
- to pass data from child to parent). */
- if (out == err)
+ init_std_file_from_handle (0, in, GENERIC_READ);
+
+ /* STD_ERROR_HANDLE has been observed to be the same as
+ STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes
+ to pass data from child to parent). */
+ if (out == err)
+ {
+ /* Since this code is not invoked for forked tasks, we don't have
+ to worry about the close-on-exec flag here. */
+ if (!DuplicateHandle (hMainProc, out, hMainProc, &err, 0,
+ 1, DUPLICATE_SAME_ACCESS))
{
- /* Since this code is not invoked for forked tasks, we don't have
- to worry about the close-on-exec flag here. */
- if (!DuplicateHandle (hMainProc, out, hMainProc, &err, 0,
- 1, DUPLICATE_SAME_ACCESS))
- {
- /* If that fails, do this as a fall back. */
- err = out;
- system_printf ("couldn't make stderr distinct from stdout");
- }
+ /* If that fails, do this as a fall back. */
+ err = out;
+ system_printf ("couldn't make stderr distinct from stdout");
}
-
- cygheap->fdtab.init_std_file_from_handle (1, out, GENERIC_WRITE);
- cygheap->fdtab.init_std_file_from_handle (2, err, GENERIC_WRITE);
- /* Assign the console as the controlling tty for this process if we actually
- have a console and no other controlling tty has been assigned. */
- if (myself->ctty < 0 && GetConsoleCP () > 0)
- set_console_ctty ();
}
+
+ init_std_file_from_handle (1, out, GENERIC_WRITE);
+ init_std_file_from_handle (2, err, GENERIC_WRITE);
+ /* Assign the console as the controlling tty for this process if we actually
+ have a console and no other controlling tty has been assigned. */
+ if (myself->ctty < 0 && GetConsoleCP () > 0)
+ set_console_ctty ();
}
int
dtable::find_unused_handle (int start)
{
AssertResourceOwner (LOCK_FD_LIST, READ_LOCK);
-
do
{
- for (int i = start; i < (int) size; i++)
+ for (size_t i = start; i < size; i++)
/* See if open -- no need for overhead of not_open */
if (fds[i] == NULL)
return i;
@@ -168,189 +197,217 @@ dtable::release (int fd)
}
}
-void
-dtable::init_std_file_from_handle (int fd, HANDLE handle,
- DWORD myaccess)
-{
- int bin;
- const char *name = NULL;
-
- if (__fmode)
- bin = __fmode;
- else
- bin = binmode ?: 0;
-
- first_fd_for_open = 0;
- /* See if we can consoleify it - if it is a console,
- don't open it in binary. That will screw up our crlfs*/
- CONSOLE_SCREEN_BUFFER_INFO buf;
- if (GetConsoleScreenBufferInfo (handle, &buf))
- {
- if (ISSTATE (myself, PID_USETTY))
- name = "/dev/tty";
- else
- name = "/dev/conout";
- bin = 0;
- }
- else if (FlushConsoleInputBuffer (handle))
- {
- if (ISSTATE (myself, PID_USETTY))
- name = "/dev/tty";
- else
- name = "/dev/conin";
- bin = 0;
- }
- else if (GetFileType (handle) == FILE_TYPE_PIPE)
- {
- if (fd == 0)
- name = "/dev/piper";
- else if (fd == 1 || fd == 2)
- name = "/dev/pipew";
- if (bin == 0)
- bin = O_BINARY;
- }
-
- path_conv pc;
- build_fhandler (fd, name, handle, pc)->init (handle, myaccess, bin);
- set_std_handle (fd);
- paranoid_printf ("fd %d, handle %p", fd, handle);
-}
-
-extern "C"
-int
+extern "C" int
cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin,
DWORD myaccess)
{
if (fd == -1)
fd = cygheap->fdtab.find_unused_handle ();
path_conv pc;
- fhandler_base *res = cygheap->fdtab.build_fhandler (fd, name, handle, pc);
- res->init (handle, myaccess, bin);
+ fhandler_base *res = cygheap->fdtab.build_fhandler_from_name (fd, name, handle,
+ pc);
+ res->init (handle, myaccess, bin ?: pc.binmode ());
return fd;
}
-fhandler_base *
-dtable::build_fhandler (int fd, const char *name, HANDLE handle, path_conv& pc,
- unsigned opt, suffix_info *si)
+void
+dtable::init_std_file_from_handle (int fd, HANDLE handle, DWORD myaccess)
{
- if (!name && handle)
+ const char *name;
+ CONSOLE_SCREEN_BUFFER_INFO buf;
+ struct sockaddr sa;
+ int sal = sizeof (sa);
+ DCB dcb;
+
+ first_fd_for_open = 0;
+
+ if (!not_open (fd))
+ return;
+
+ SetLastError (0);
+ DWORD ft = GetFileType (handle);
+ if (ft == FILE_TYPE_UNKNOWN && GetLastError () == ERROR_INVALID_HANDLE)
+ name = NULL;
+ else
{
- struct sockaddr sa;
- int sal = sizeof (sa);
- CONSOLE_SCREEN_BUFFER_INFO cinfo;
- DCB dcb;
-
- if (GetNumberOfConsoleInputEvents (handle, (DWORD *) &cinfo))
- name = "/dev/conin";
- else if (GetConsoleScreenBufferInfo (handle, &cinfo))
- name = "/dev/conout";
+ /* See if we can consoleify it */
+ if (GetConsoleScreenBufferInfo (handle, &buf))
+ {
+ if (ISSTATE (myself, PID_USETTY))
+ name = "/dev/tty";
+ else
+ name = "/dev/conout";
+ }
+ else if (GetNumberOfConsoleInputEvents (handle, (DWORD *) &buf))
+ {
+ if (ISSTATE (myself, PID_USETTY))
+ name = "/dev/tty";
+ else
+ name = "/dev/conin";
+ }
+ else if (ft == FILE_TYPE_PIPE)
+ {
+ if (fd == 0)
+ name = "/dev/piper";
+ else
+ name = "/dev/pipew";
+ }
else if (wsock_started && getpeername ((SOCKET) handle, &sa, &sal) == 0)
name = "/dev/socket";
- else if (GetFileType (handle) == FILE_TYPE_PIPE)
- name = "/dev/pipe";
else if (GetCommState (handle, &dcb))
name = "/dev/ttyS0"; // FIXME - determine correct device
else
- name = "some disk file";
+ name = handle_to_fn (handle, (char *) alloca (MAX_PATH + 100));
+ }
+
+ if (!name)
+ fds[fd] = NULL;
+ else
+ {
+ path_conv pc;
+ build_fhandler_from_name (fd, name, handle, pc)->init (handle, myaccess,
+ pc.binmode ());
+ set_std_handle (fd);
+ paranoid_printf ("fd %d, handle %p", fd, handle);
}
+}
- pc.check (name, opt | PC_NULLEMPTY, si);
+fhandler_base *
+dtable::build_fhandler_from_name (int fd, const char *name, HANDLE handle,
+ path_conv& pc, unsigned opt, suffix_info *si)
+{
+ pc.check (name, opt | PC_NULLEMPTY | PC_FULL | PC_POSIX, si);
if (pc.error)
{
set_errno (pc.error);
return NULL;
}
- fhandler_base *fh = build_fhandler (fd, pc.get_devn (), name, pc.get_unitn ());
- fh->set_name (name, pc, pc.get_unitn ());
+ if (!pc.exists () && handle)
+ pc.fillin (handle);
+
+ fhandler_base *fh = build_fhandler (fd, pc.get_devn (),
+ pc.return_and_clear_normalized_path (),
+ pc, pc.get_unitn ());
return fh;
}
fhandler_base *
-dtable::build_fhandler (int fd, DWORD dev, const char *name, int unit)
+dtable::build_fhandler (int fd, DWORD dev, const char *unix_name,
+ const char *win32_name, int unit)
+{
+ return build_fhandler (fd, dev, cstrdup (unix_name), win32_name, unit);
+}
+
+#define cnew(name) new ((void *) ccalloc (HEAP_FHANDLER, 1, sizeof (name))) name
+fhandler_base *
+dtable::build_fhandler (int fd, DWORD dev, char *unix_name,
+ const char *win32_name, int unit)
{
fhandler_base *fh;
- void *buf = ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_union) + 100);
dev &= FH_DEVMASK;
switch (dev)
{
case FH_TTYM:
- fh = new (buf) fhandler_tty_master (name, unit);
+ fh = cnew (fhandler_tty_master) (unit);
break;
case FH_CONSOLE:
case FH_CONIN:
case FH_CONOUT:
- fh = new (buf) fhandler_console (name);
- inc_console_fds ();
+ if ((fh = cnew (fhandler_console) ()))
+ inc_console_fds ();
break;
case FH_PTYM:
- fh = new (buf) fhandler_pty_master (name);
+ fh = cnew (fhandler_pty_master) ();
break;
case FH_TTYS:
if (unit < 0)
- fh = new (buf) fhandler_tty_slave (name);
+ fh = cnew (fhandler_tty_slave) ();
else
- fh = new (buf) fhandler_tty_slave (unit, name);
+ fh = cnew (fhandler_tty_slave) (unit);
break;
case FH_WINDOWS:
- fh = new (buf) fhandler_windows (name);
+ fh = cnew (fhandler_windows) ();
break;
case FH_SERIAL:
- fh = new (buf) fhandler_serial (name, dev, unit);
+ fh = cnew (fhandler_serial) (unit);
break;
case FH_PIPE:
case FH_PIPER:
case FH_PIPEW:
- fh = new (buf) fhandler_pipe (name, dev);
+ fh = cnew (fhandler_pipe) (dev);
break;
case FH_SOCKET:
- fh = new (buf) fhandler_socket (name);
+ if ((fh = cnew (fhandler_socket) ()))
+ inc_need_fixup_before ();
break;
case FH_DISK:
- fh = new (buf) fhandler_disk_file (NULL);
+ fh = cnew (fhandler_disk_file) ();
+ break;
+ case FH_CYGDRIVE:
+ fh = cnew (fhandler_cygdrive) (unit);
break;
case FH_FLOPPY:
- fh = new (buf) fhandler_dev_floppy (name, unit);
+ fh = cnew (fhandler_dev_floppy) (unit);
break;
case FH_TAPE:
- fh = new (buf) fhandler_dev_tape (name, unit);
+ fh = cnew (fhandler_dev_tape) (unit);
break;
case FH_NULL:
- fh = new (buf) fhandler_dev_null (name);
+ fh = cnew (fhandler_dev_null) ();
break;
case FH_ZERO:
- fh = new (buf) fhandler_dev_zero (name);
+ fh = cnew (fhandler_dev_zero) ();
break;
case FH_RANDOM:
- fh = new (buf) fhandler_dev_random (name, unit);
+ fh = cnew (fhandler_dev_random) (unit);
break;
case FH_MEM:
- fh = new (buf) fhandler_dev_mem (name, unit);
+ fh = cnew (fhandler_dev_mem) (unit);
break;
case FH_CLIPBOARD:
- fh = new (buf) fhandler_dev_clipboard (name);
+ fh = cnew (fhandler_dev_clipboard) ();
break;
case FH_OSS_DSP:
- fh = new (buf) fhandler_dev_dsp (name);
+ fh = cnew (fhandler_dev_dsp) ();
+ break;
+ case FH_PROC:
+ fh = cnew (fhandler_proc) ();
+ break;
+ case FH_REGISTRY:
+ fh = cnew (fhandler_registry) ();
+ break;
+ case FH_PROCESS:
+ fh = cnew (fhandler_process) ();
break;
default:
+ system_printf ("internal error -- unknown device - %p", dev);
+ fh = NULL;
+ }
+
+ if (unix_name)
+ {
+ char new_win32_name[strlen (unix_name) + 1];
+ if (!win32_name)
{
- /* FIXME - this could recurse forever */
- path_conv pc;
- return build_fhandler (fd, name, NULL, pc);
+ char *p;
+ /* FIXME: ? Should we call win32_device_name here?
+ It seems like overkill, but... */
+ win32_name = strcpy (new_win32_name, unix_name);
+ for (p = (char *) win32_name; (p = strchr (p, '/')); p++)
+ *p = '\\';
}
+ fh->set_name (unix_name, win32_name, fh->get_unit ());
}
-
- debug_printf ("%s - cb %d, fd %d, fh %p", fh->get_name () ?: "", fh->cb,
- fd, fh);
+ debug_printf ("fd %d, fh %p", fd, fh);
return fd >= 0 ? (fds[fd] = fh) : fh;
}
fhandler_base *
dtable::dup_worker (fhandler_base *oldfh)
{
- fhandler_base *newfh = build_fhandler (-1, oldfh->get_device (), NULL);
+ fhandler_base *newfh = build_fhandler (-1, oldfh->get_device ());
*newfh = *oldfh;
newfh->set_io_handle (NULL);
if (oldfh->dup (newfh))
@@ -374,6 +431,7 @@ dtable::dup2 (int oldfd, int newfd)
MALLOC_CHECK;
debug_printf ("dup2 (%d, %d)", oldfd, newfd);
+ SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
if (not_open (oldfd))
{
@@ -382,6 +440,13 @@ dtable::dup2 (int oldfd, int newfd)
goto done;
}
+ if (newfd < 0)
+ {
+ syscall_printf ("new fd out of bounds: %d", newfd);
+ set_errno (EBADF);
+ goto done;
+ }
+
if (newfd == oldfd)
{
res = 0;
@@ -394,51 +459,33 @@ dtable::dup2 (int oldfd, int newfd)
goto done;
}
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
+ debug_printf ("newfh->io_handle %p, oldfh->io_handle %p",
+ newfh->get_io_handle (), fds[oldfd]->get_io_handle ());
- if (newfd < 0)
+ if (!not_open (newfd))
+ _close (newfd);
+ else if ((size_t) newfd < size)
+ /* nothing to do */;
+ else if (find_unused_handle (newfd) < 0)
{
- syscall_printf ("new fd out of bounds: %d", newfd);
- set_errno (EBADF);
+ newfh->close ();
+ res = -1;
goto done;
}
- if ((size_t) newfd >= cygheap->fdtab.size)
- {
- int inc_size = NOFILE_INCR * ((newfd + NOFILE_INCR - 1) / NOFILE_INCR) -
- cygheap->fdtab.size;
- cygheap->fdtab.extend (inc_size);
- }
-
- if (!not_open (newfd))
- _close (newfd);
fds[newfd] = newfh;
- /* Count sockets. */
- if ((fds[newfd]->get_device () & FH_DEVMASK) == FH_SOCKET)
- inc_need_fixup_before ();
-
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
- MALLOC_CHECK;
-
if ((res = newfd) <= 2)
set_std_handle (res);
- MALLOC_CHECK;
done:
+ MALLOC_CHECK;
+ ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
syscall_printf ("%d = dup2 (%d, %d)", res, oldfd, newfd);
return res;
}
-void
-dtable::reset_unix_path_name (int fd, const char *name)
-{
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "reset_unix_name");
- fds[fd]->reset_unix_path_name (name);
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "reset_unix_name");
-}
-
select_record *
dtable::select_read (int fd, select_record *s)
{
@@ -569,6 +616,10 @@ dtable::vfork_child_dup ()
newtable = (fhandler_base **) ccalloc (HEAP_ARGV, size, sizeof (fds[0]));
int res = 1;
+ /* Remove impersonation */
+ if (cygheap->user.issetuid ())
+ RevertToSelf ();
+
for (size_t i = 0; i < size; i++)
if (not_open (i))
continue;
@@ -585,6 +636,10 @@ dtable::vfork_child_dup ()
fds = newtable;
out:
+ /* Restore impersonation */
+ if (cygheap->user.issetuid ())
+ ImpersonateLoggedOnUser (cygheap->user.token);
+
ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
return 1;
}
@@ -596,6 +651,7 @@ dtable::vfork_parent_restore ()
close_all_files ();
fhandler_base **deleteme = fds;
+ assert (fds_on_hold != NULL);
fds = fds_on_hold;
fds_on_hold = NULL;
cfree (deleteme);
@@ -633,3 +689,102 @@ dtable::vfork_child_fixup ()
return;
}
+
+#define DEVICE_PREFIX "\\device\\"
+#define DEVICE_PREFIX_LEN sizeof(DEVICE_PREFIX) - 1
+#define REMOTE "\\Device\\LanmanRedirector\\"
+#define REMOTE_LEN sizeof (REMOTE) - 1
+
+static char *
+handle_to_fn (HANDLE h, char *posix_fn)
+{
+ OBJECT_NAME_INFORMATION *ntfn;
+ char fnbuf[32768];
+
+ memset (fnbuf, 0, sizeof (fnbuf));
+ ntfn = (OBJECT_NAME_INFORMATION *) fnbuf;
+ ntfn->Name.MaximumLength = sizeof (fnbuf) - sizeof (*ntfn);
+ ntfn->Name.Buffer = (WCHAR *) (ntfn + 1);
+
+ DWORD res = NtQueryObject (h, ObjectNameInformation, ntfn, sizeof (fnbuf), NULL);
+
+ if (res)
+ {
+ strcpy (posix_fn, "some disk file");
+ debug_printf ("NtQueryObject failed");
+ return posix_fn;
+ }
+
+ // NT seems to do this on an unopened file
+ if (!ntfn->Name.Buffer)
+ {
+ debug_printf ("nt->Name.Buffer == NULL");
+ return NULL;
+ }
+
+ ntfn->Name.Buffer[ntfn->Name.Length / sizeof (WCHAR)] = 0;
+
+ char win32_fn[MAX_PATH + 100];
+ sys_wcstombs (win32_fn, ntfn->Name.Buffer, ntfn->Name.Length);
+ debug_printf ("nt name '%s'", win32_fn);
+ if (!strncasematch (win32_fn, DEVICE_PREFIX, DEVICE_PREFIX_LEN)
+ || !QueryDosDevice (NULL, fnbuf, sizeof (fnbuf)))
+ return strcpy (posix_fn, win32_fn);
+
+ char *p = strchr (win32_fn + DEVICE_PREFIX_LEN, '\\');
+ if (!p)
+ p = strchr (win32_fn + DEVICE_PREFIX_LEN, '\0');
+
+ int n = p - win32_fn;
+ int maxmatchlen = 0;
+ char *maxmatchdos = NULL;
+ for (char *s = fnbuf; *s; s = strchr (s, '\0') + 1)
+ {
+ char device[MAX_PATH + 10];
+ device[MAX_PATH + 9] = '\0';
+ if (strchr (s, ':') == NULL)
+ continue;
+ if (!QueryDosDevice (s, device, sizeof (device) - 1))
+ continue;
+ char *q = strrchr (device, ';');
+ if (q)
+ {
+ char *r = strchr (q, '\\');
+ if (r)
+ strcpy (q, r + 1);
+ }
+ int devlen = strlen (device);
+ if (device[devlen - 1] == '\\')
+ device[--devlen] = '\0';
+ if (devlen < maxmatchlen)
+ continue;
+ if (!strncasematch (device, win32_fn, devlen) ||
+ (win32_fn[devlen] != '\0' && win32_fn[devlen] != '\\'))
+ continue;
+ maxmatchlen = devlen;
+ maxmatchdos = s;
+ debug_printf ("current match '%s'", device);
+ }
+
+ char *w32 = win32_fn;
+ if (maxmatchlen)
+ {
+ n = strlen (maxmatchdos);
+ if (maxmatchdos[n - 1] == '\\')
+ n--;
+ w32 += maxmatchlen - n;
+ memcpy (w32, maxmatchdos, n);
+ w32[n] = '\\';
+ }
+ else if (strncasematch (w32, REMOTE, REMOTE_LEN))
+ {
+ w32 += REMOTE_LEN - 2;
+ *w32 = '\\';
+ debug_printf ("remote drive");
+ }
+
+
+ debug_printf ("derived path '%s'", w32);
+ cygwin_conv_to_full_posix_path (w32, posix_fn);
+ return posix_fn;
+}
diff --git a/winsup/cygwin/dtable.h b/winsup/cygwin/dtable.h
index 0a00d91f5..5a8f5697a 100644
--- a/winsup/cygwin/dtable.h
+++ b/winsup/cygwin/dtable.h
@@ -48,11 +48,14 @@ public:
void fixup_before_exec (DWORD win_proc_id);
void fixup_before_fork (DWORD win_proc_id);
void fixup_after_fork (HANDLE);
- fhandler_base *build_fhandler (int fd, DWORD dev, const char *name,
- int unit = -1);
- fhandler_base *build_fhandler (int fd, const char *name, HANDLE h,
- path_conv& pc, unsigned opts = PC_SYM_FOLLOW,
- suffix_info *si = NULL);
+ fhandler_base *build_fhandler (int fd, DWORD dev, const char *unix_name,
+ const char *win32_name = NULL, int unit = -1);
+ fhandler_base *build_fhandler (int fd, DWORD dev, char *unix_name = NULL,
+ const char *win32_name = NULL, int unit = -1);
+ fhandler_base *build_fhandler_from_name (int fd, const char *name, HANDLE h,
+ path_conv& pc,
+ unsigned opts = PC_SYM_FOLLOW,
+ suffix_info *si = NULL);
inline int not_open (int fd)
{
SetResourceLock (LOCK_FD_LIST, READ_LOCK, "not_open");
@@ -62,7 +65,6 @@ public:
ReleaseResourceLock (LOCK_FD_LIST, READ_LOCK, "not open");
return res;
}
- void reset_unix_path_name (int fd, const char *name);
int find_unused_handle (int start);
int find_unused_handle () { return find_unused_handle (first_fd_for_open);}
void release (int fd);
@@ -74,6 +76,8 @@ public:
select_record *select_write (int fd, select_record *s);
select_record *select_except (int fd, select_record *s);
operator fhandler_base **() {return fds;}
+ void stdio_init ();
+ void get_debugger_info ();
};
void dtable_init (void);
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index d88ab35e5..ce6c8ba5d 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -1,7 +1,7 @@
/* environ.cc: Cygwin-adopted functions from newlib to manipulate
process's environment.
- Copyright 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@@ -12,11 +12,9 @@ details. */
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
-#include <fcntl.h>
+#include <assert.h>
#include <sys/cygwin.h>
#include <cygwin/version.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "perprocess.h"
#include "security.h"
@@ -27,6 +25,7 @@ details. */
#include "cygheap.h"
#include "registry.h"
#include "environ.h"
+#include "child_info.h"
extern BOOL allow_daemon;
extern BOOL allow_glob;
@@ -37,7 +36,7 @@ extern BOOL allow_winsymlinks;
extern BOOL strip_title_path;
extern int pcheck_case;
extern int subauth_id;
-BOOL reset_com = TRUE;
+BOOL reset_com = FALSE;
static BOOL envcache = TRUE;
static char **lastenviron;
@@ -46,6 +45,7 @@ static char **lastenviron;
(CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
<= CYGWIN_VERSION_DLL_MALLOC_ENV)
+#define NL(x) x, (sizeof (x) - 1)
/* List of names which are converted from dos to unix
on the way in and back again on the way out.
@@ -55,20 +55,20 @@ static char **lastenviron;
static int return_MAX_PATH (const char *) {return MAX_PATH;}
static NO_COPY win_env conv_envvars[] =
{
- {"PATH=", 5, NULL, NULL, cygwin_win32_to_posix_path_list,
+ {NL ("PATH="), NULL, NULL, cygwin_win32_to_posix_path_list,
cygwin_posix_to_win32_path_list,
cygwin_win32_to_posix_path_list_buf_size,
cygwin_posix_to_win32_path_list_buf_size},
- {"HOME=", 5, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
- return_MAX_PATH, return_MAX_PATH},
- {"LD_LIBRARY_PATH=", 16, NULL, NULL, cygwin_conv_to_full_posix_path,
+ {NL ("HOME="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("LD_LIBRARY_PATH="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("TMPDIR="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("TMP="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("TEMP="), NULL, NULL, cygwin_conv_to_full_posix_path,
cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
- {"TMPDIR=", 7, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
- return_MAX_PATH, return_MAX_PATH},
- {"TMP=", 4, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
- return_MAX_PATH, return_MAX_PATH},
- {"TEMP=", 5, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
- return_MAX_PATH, return_MAX_PATH},
{NULL, 0, NULL, NULL, NULL, NULL, 0, 0}
};
@@ -77,6 +77,7 @@ static unsigned char conv_start_chars[256] = {0};
void
win_env::add_cache (const char *in_posix, const char *in_native)
{
+ MALLOC_CHECK;
posix = (char *) realloc (posix, strlen (in_posix) + 1);
strcpy (posix, in_posix);
if (in_native)
@@ -91,16 +92,16 @@ win_env::add_cache (const char *in_posix, const char *in_native)
(void) strcpy (native, name);
towin32 (in_posix, native + namelen);
}
+ MALLOC_CHECK;
debug_printf ("posix %s", posix);
debug_printf ("native %s", native);
}
/* Check for a "special" environment variable name. *env is the pointer
- * to the beginning of the environment variable name. n is the length
- * of the name including a mandatory '='. Returns a pointer to the
- * appropriate conversion structure.
- */
+ to the beginning of the environment variable name. *in_posix is any
+ known posix value for the environment variable. Returns a pointer to
+ the appropriate conversion structure. */
win_env * __stdcall
getwinenv (const char *env, const char *in_posix)
{
@@ -112,7 +113,7 @@ getwinenv (const char *env, const char *in_posix)
{
win_env * const we = conv_envvars + i;
const char *val;
- if (!cur_environ () || !(val = in_posix ?: getenv(we->name)))
+ if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
debug_printf ("can't set native for %s since no environ yet",
we->name);
else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
@@ -146,6 +147,7 @@ posify (char **here, const char *value)
debug_printf ("env var converted to %s", outenv);
*here = outenv;
free (src);
+ MALLOC_CHECK;
}
/*
@@ -178,6 +180,7 @@ my_findenv (const char *name, int *offset)
*offset = p - cur_environ ();
return (char *) (++c);
}
+ MALLOC_CHECK;
return NULL;
}
@@ -194,13 +197,12 @@ getenv (const char *name)
return my_findenv (name, &offset);
}
-extern int __stdcall
-envsize (const char * const *in_envp, int debug_print)
+static int __stdcall
+envsize (const char * const *in_envp)
{
const char * const *envp;
for (envp = in_envp; *envp; envp++)
- if (debug_print)
- debug_printf ("%s", *envp);
+ continue;
return (1 + envp - in_envp) * sizeof (const char *);
}
@@ -232,12 +234,12 @@ _addenv (const char *name, const char *value, int overwrite)
else
{ /* Create new slot. */
int sz = envsize (cur_environ ());
- int allocsz = sz + sizeof (char *);
+ int allocsz = sz + (2 * sizeof (char *));
offset = (sz - 1) / sizeof (char *);
/* Allocate space for additional element plus terminating NULL. */
- if (__cygwin_environ == lastenviron)
+ if (cur_environ () == lastenviron)
lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
allocsz);
else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
@@ -249,7 +251,7 @@ _addenv (const char *name, const char *value, int overwrite)
#ifdef DEBUGGING
try_to_debug ();
#endif
- return -1; /* Oops. No more memory. */
+ return -1; /* Oops. No more memory. */
}
__cygwin_environ[offset + 1] = NULL; /* NULL terminate. */
@@ -283,6 +285,7 @@ _addenv (const char *name, const char *value, int overwrite)
if ((spenv = getwinenv (envhere)))
spenv->add_cache (value);
+ MALLOC_CHECK;
return 0;
}
@@ -363,7 +366,7 @@ ucenv (char *p, char *eq)
/* Parse CYGWIN options */
-static NO_COPY BOOL export_settings = FALSE;
+static NO_COPY BOOL export_settings = false;
enum settings
{
@@ -408,12 +411,12 @@ check_case_init (const char *buf)
pcheck_case = PCHECK_RELAXED;
debug_printf ("File case checking set to RELAXED");
}
- else if (strcmp (buf, "adjust")== 0)
+ else if (strcasematch (buf, "adjust"))
{
pcheck_case = PCHECK_ADJUST;
debug_printf ("File case checking set to ADJUST");
}
- else if (strcmp (buf, "strict")== 0)
+ else if (strcasematch (buf, "strict"))
{
pcheck_case = PCHECK_STRICT;
debug_printf ("File case checking set to STRICT");
@@ -445,20 +448,18 @@ codepage_init (const char *buf)
if (!buf || !*buf)
return;
- if (strcmp (buf, "oem")== 0)
+ if (strcasematch (buf, "oem"))
{
current_codepage = oem_cp;
set_file_api_mode (current_codepage);
}
- else if (strcmp (buf, "ansi")== 0)
+ else if (strcasematch (buf, "ansi"))
{
current_codepage = ansi_cp;
set_file_api_mode (current_codepage);
}
else
- {
- debug_printf ("Wrong codepage name: %s", buf);
- }
+ debug_printf ("Wrong codepage name: %s", buf);
}
static void
@@ -535,7 +536,8 @@ parse_options (char *buf)
if (buf == NULL)
{
- char newbuf[MAX_PATH + 7] = "CYGWIN";
+ char newbuf[MAX_PATH + 7];
+ newbuf[0] = '\0';
for (k = known; k->name != NULL; k++)
if (k->remember)
{
@@ -543,11 +545,12 @@ parse_options (char *buf)
free (k->remember);
k->remember = NULL;
}
- if (!export_settings)
- return;
- newbuf[sizeof ("CYGWIN") - 1] = '=';
- debug_printf ("%s", newbuf);
- putenv (newbuf);
+
+ if (export_settings)
+ {
+ debug_printf ("%s", newbuf + 1);
+ setenv ("CYGWIN", newbuf + 1, 1);
+ }
return;
}
@@ -556,6 +559,7 @@ parse_options (char *buf)
p != NULL;
p = strtok_r (NULL, " \t", &lasts))
{
+ char *keyword_here = p;
if (!(istrue = !strncasematch (p, "no", 2)))
p += 2;
else if (!(istrue = *p != '-'))
@@ -599,7 +603,7 @@ parse_options (char *buf)
*--eq = ch;
int n = eq - p;
- p = strdup (p);
+ p = strdup (keyword_here);
if (n > 0)
p[n] = ':';
k->remember = p;
@@ -611,18 +615,21 @@ parse_options (char *buf)
}
/* Set options from the registry. */
-static void __stdcall
+static bool __stdcall
regopt (const char *name)
{
- MALLOC_CHECK;
+ bool parsed_something = false;
/* FIXME: should not be under mount */
reg_key r (KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
char buf[MAX_PATH];
char lname[strlen(name) + 1];
strlwr (strcpy (lname, name));
- MALLOC_CHECK;
+
if (r.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
- parse_options (buf);
+ {
+ parse_options (buf);
+ parsed_something = true;
+ }
else
{
reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
@@ -630,9 +637,13 @@ regopt (const char *name)
CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
if (r1.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
- parse_options (buf);
+ {
+ parse_options (buf);
+ parsed_something = true;
+ }
}
MALLOC_CHECK;
+ return parsed_something;
}
/* Initialize the environ array. Look for the CYGWIN environment
@@ -646,6 +657,7 @@ environ_init (char **envp, int envc)
char *newp;
int sawTERM = 0;
bool envp_passed_in;
+ bool got_something_from_registry;
static char NO_COPY cygterm[] = "TERM=cygwin";
static int initted;
@@ -659,9 +671,9 @@ environ_init (char **envp, int envc)
initted = 1;
}
- regopt ("default");
+ got_something_from_registry = regopt ("default");
if (myself->progname[0])
- regopt (myself->progname);
+ got_something_from_registry = regopt (myself->progname) || got_something_from_registry;
#ifdef NTSEC_ON_BY_DEFAULT
/* Set ntsec explicit as default, if NT is running */
@@ -673,6 +685,8 @@ environ_init (char **envp, int envc)
envp_passed_in = 0;
else
{
+ envc++;
+ envc *= sizeof (char *);
char **newenv = (char **) malloc (envc);
memcpy (newenv, envp, envc);
cfree (envp);
@@ -710,7 +724,7 @@ environ_init (char **envp, int envc)
char *eq;
if ((eq = strchr (newp, '=')) == NULL)
eq = strchr (newp, '\0');
- if (!myself->ppid_handle)
+ if (!child_proc_info)
ucenv (newp, eq);
if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
sawTERM = 1;
@@ -735,7 +749,10 @@ out:
if (p)
parse_options (p);
}
- parse_options (NULL);
+
+ if (got_something_from_registry)
+ parse_options (NULL); /* possibly export registry settings to
+ environment */
MALLOC_CHECK;
}
@@ -749,104 +766,227 @@ env_sort (const void *a, const void *b)
return strcmp (*p, *q);
}
+char * __stdcall
+getwinenveq (const char *name, size_t namelen, int x)
+{
+ char dum[1];
+ char name0[namelen - 1];
+ memcpy (name0, name, namelen - 1);
+ name0[namelen - 1] = '\0';
+ int totlen = GetEnvironmentVariable (name0, dum, 0);
+ if (totlen > 0)
+ {
+ totlen++;
+ if (x == HEAP_1_STR)
+ totlen += namelen;
+ else
+ namelen = 0;
+ char *p = (char *) cmalloc ((cygheap_types) x, totlen);
+ if (namelen)
+ strcpy (p, name);
+ if (GetEnvironmentVariable (name0, p + namelen, totlen))
+ {
+ debug_printf ("using value from GetEnvironmentVariable for '%s'",
+ name0);
+ return p;
+ }
+ else
+ cfree (p);
+ }
+
+ debug_printf ("warning: %s not present in environment", name);
+ return NULL;
+}
+
+struct spenv
+{
+ const char *name;
+ size_t namelen;
+ const char * (cygheap_user::*from_cygheap) (const char *, size_t);
+ char *retrieve (bool, const char * const = NULL)
+ __attribute__ ((regparm (3)));
+};
+
+#define env_dontadd almost_null
+
/* Keep this list in upper case and sorted */
-static const NO_COPY char* forced_winenv_vars [] =
- {
- "SYSTEMDRIVE",
- "SYSTEMROOT",
- NULL
- };
+static NO_COPY spenv spenvs[] =
+{
+ {NL ("HOMEDRIVE="), &cygheap_user::env_homedrive},
+ {NL ("HOMEPATH="), &cygheap_user::env_homepath},
+ {NL ("LOGONSERVER="), &cygheap_user::env_logsrv},
+ {NL ("SYSTEMDRIVE="), NULL},
+ {NL ("SYSTEMROOT="), NULL},
+ {NL ("USERDOMAIN="), &cygheap_user::env_domain},
+ {NL ("USERNAME="), &cygheap_user::env_name},
+ {NL ("USERPROFILE="), &cygheap_user::env_userprofile},
+};
+
+char *
+spenv::retrieve (bool no_envblock, const char *const envname)
+{
+ if (envname && !strncasematch (envname, name, namelen))
+ return NULL;
+
+ debug_printf ("no_envblock %d", no_envblock);
+
+ if (from_cygheap)
+ {
+ const char *p;
+ if (envname && !cygheap->user.issetuid ())
+ {
+ debug_printf ("duping existing value for '%s'", name);
+ return cstrdup1 (envname); /* Don't really care what it's set to
+ if we're calling a cygwin program */
+ }
+
+ /* Calculate (potentially) value for given environment variable. */
+ p = (cygheap->user.*from_cygheap) (name, namelen);
+ if (!p || (no_envblock && !envname) || (p == env_dontadd))
+ return env_dontadd;
+ char *s = (char *) cmalloc (HEAP_1_STR, namelen + strlen (p) + 1);
+ strcpy (s, name);
+ (void) strcpy (s + namelen, p);
+ debug_printf ("using computed value for '%s'", name);
+ return s;
+ }
-#define FORCED_WINENV_SIZE (sizeof (forced_winenv_vars) / sizeof (forced_winenv_vars[0]))
+ if (envname)
+ return cstrdup1 (envname);
+
+ return getwinenveq (name, namelen, HEAP_1_STR);
+}
+
+#define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
/* Create a Windows-style environment block, i.e. a typical character buffer
filled with null terminated strings, terminated by double null characters.
Converts environment variables noted in conv_envvars into win32 form
prior to placing them in the string. */
-char * __stdcall
-winenv (const char * const *envp, int keep_posix)
+char ** __stdcall
+build_env (const char * const *envp, char *&envblock, int &envc,
+ bool no_envblock)
{
- int len, n, tl;
+ int len, n;
const char * const *srcp;
- const char **dstp;
- bool saw_forced_winenv[FORCED_WINENV_SIZE] = {0};
- char *p;
+ char **dstp;
+ bool saw_spenv[SPENVS_SIZE] = {0};
- debug_printf ("envp %p, keep_posix %d", envp, keep_posix);
-
- tl = 0;
+ debug_printf ("envp %p", envp);
+ /* How many elements? */
for (n = 0; envp[n]; n++)
continue;
- const char *newenvp[n + 1 + FORCED_WINENV_SIZE];
+ /* Allocate a new "argv-style" environ list with room for extra stuff. */
+ char **newenv = (char **) cmalloc (HEAP_1_ARGV, sizeof (char *) *
+ (n + SPENVS_SIZE + 1));
- for (srcp = envp, dstp = newenvp; *srcp; srcp++, dstp++)
+ int tl = 0;
+ /* Iterate over input list, generating a new environment list and refreshing
+ "special" entries, if necessary. */
+ for (srcp = envp, dstp = newenv; *srcp; srcp++)
{
- len = strcspn (*srcp, "=");
- win_env *conv;
+ /* Look for entries that require special attention */
+ for (unsigned i = 0; i < SPENVS_SIZE; i++)
+ if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
+ {
+ saw_spenv[i] = 1;
+ if (*dstp == env_dontadd)
+ goto next1;
+ goto next0;
+ }
- if (keep_posix || !(conv = getwinenv (*srcp, *srcp + len + 1)))
- *dstp = *srcp;
- else
- {
- p = (char *) alloca (strlen (conv->native) + 1);
- strcpy (p, conv->native);
- *dstp = p;
- }
- tl += strlen (*dstp) + 1;
- if ((*dstp)[0] == '!' && isdrive ((*dstp) + 1) && (*dstp)[3] == '=')
- {
- p = (char *) alloca (strlen (*dstp) + 1);
- strcpy (p, *dstp);
- *p = '=';
- *dstp = p;
- }
+ /* Add entry to new environment */
+ *dstp = cstrdup1 (*srcp);
- for (int i = 0; forced_winenv_vars[i]; i++)
- if (!saw_forced_winenv[i])
- saw_forced_winenv[i] = strncasematch (forced_winenv_vars[i], *srcp, len);
+ next0:
+ /* If necessary, calculate rough running total for envblock size */
+ if (!no_envblock)
+ tl += strlen (*dstp) + 1;
+ dstp++;
+ next1:
+ continue;
}
- char dum[1];
- for (int i = 0; forced_winenv_vars[i]; i++)
- if (!saw_forced_winenv[i])
+ assert ((srcp - envp) == n);
+ /* Fill in any required-but-missing environment variables. */
+ for (unsigned i = 0; i < SPENVS_SIZE; i++)
+ if (!saw_spenv[i])
{
- int namelen = strlen (forced_winenv_vars[i]) + 1;
- int vallen = GetEnvironmentVariable (forced_winenv_vars[i], dum, 0) + 1;
- p = (char *) alloca (namelen + vallen);
- strcpy (p, forced_winenv_vars[i]);
- strcat (p, "=");
- if (!GetEnvironmentVariable (forced_winenv_vars[i], p + namelen,
- vallen + 1))
- debug_printf ("warning: %s not present in environment", *srcp);
- else
+ *dstp = spenvs[i].retrieve (no_envblock);
+ if (*dstp && !no_envblock && *dstp != env_dontadd)
{
- *dstp++ = p;
- tl += strlen (p) + 1;
+ tl += strlen (*dstp) + 1;
+ dstp++;
}
}
- *dstp = NULL; /* Terminate */
+ envc = dstp - newenv; /* Number of entries in newenv */
+ assert ((size_t) envc <= (n + SPENVS_SIZE));
+ *dstp = NULL; /* Terminate */
- int envlen = dstp - newenvp;
- debug_printf ("env count %d, bytes %d", envlen, tl);
+ if (no_envblock)
+ envblock = NULL;
+ else
+ {
+ debug_printf ("env count %d, bytes %d", envc, tl);
- /* Windows programs expect the environment block to be sorted. */
- qsort (newenvp, envlen, sizeof (char *), env_sort);
+ /* Windows programs expect the environment block to be sorted. */
+ qsort (newenv, envc, sizeof (char *), env_sort);
- /* Create an environment block suitable for passing to CreateProcess. */
- char *ptr, *envblock;
- envblock = (char *) malloc (tl + 2);
- for (srcp = newenvp, ptr = envblock; *srcp; srcp++)
- {
- len = strlen (*srcp);
- memcpy (ptr, *srcp, len + 1);
- ptr += len + 1;
+ /* Create an environment block suitable for passing to CreateProcess. */
+ char *s;
+ envblock = (char *) malloc (2 + tl);
+ int new_tl = 0;
+ for (srcp = newenv, s = envblock; *srcp; srcp++)
+ {
+ const char *p;
+ win_env *conv;
+ len = strcspn (*srcp, "=") + 1;
+
+ /* See if this entry requires posix->win32 conversion. */
+ conv = getwinenv (*srcp, *srcp + len);
+ if (conv)
+ p = conv->native; /* Use win32 path */
+ else
+ p = *srcp; /* Don't worry about it */
+
+ len = strlen (p);
+ new_tl += len + 1; /* Keep running total of block length so far */
+
+ /* See if we need to increase the size of the block. */
+ if (new_tl > tl)
+ {
+ tl = new_tl + 100;
+ char *new_envblock =
+ (char *) realloc (envblock, 2 + tl);
+ /* If realloc moves the block, move `s' with it. */
+ if (new_envblock != envblock)
+ {
+ s += new_envblock - envblock;
+ envblock = new_envblock;
+ }
+ }
+
+ memcpy (s, p, len + 1);
+
+ /* See if environment variable is "special" in a Windows sense.
+ Under NT, the current directories for visited drives are stored
+ as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
+ reasons. We need to convert it back when building the envblock */
+ if (s[0] == '!' && (isdrive (s + 1) || (s[1] == ':' && s[2] == ':'))
+ && s[3] == '=')
+ *s = '=';
+ s += len + 1;
+ }
+ *s = '\0'; /* Two null bytes at the end */
+ assert ((s - envblock) <= tl); /* Detect if we somehow ran over end
+ of buffer */
}
- *ptr = '\0'; /* Two null bytes at the end */
- return envblock;
+ debug_printf ("envp %p, envc %d", newenv, envc);
+ return newenv;
}
/* This idiocy is necessary because the early implementers of cygwin
diff --git a/winsup/cygwin/environ.h b/winsup/cygwin/environ.h
index 888b473dd..1a616b214 100644
--- a/winsup/cygwin/environ.h
+++ b/winsup/cygwin/environ.h
@@ -1,6 +1,6 @@
/* environ.h: Declarations for environ manipulation
- Copyright 2000 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,14 +9,14 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
/* Initialize the environment */
-void environ_init (char **, int);
+void environ_init (char **, int)
+ __attribute__ ((regparm (2)));
/* The structure below is used to control conversion to/from posix-style
- * file specs. Currently, only PATH and HOME are converted, but PATH
- * needs to use a "convert path list" function while HOME needs a simple
- * "convert to posix/win32". For the simple case, where a calculated length
- * is required, just return MAX_PATH. *FIXME*
- */
+ file specs. Currently, only PATH and HOME are converted, but PATH
+ needs to use a "convert path list" function while HOME needs a simple
+ "convert to posix/win32". For the simple case, where a calculated length
+ is required, just return MAX_PATH. *FIXME* */
struct win_env
{
const char *name;
@@ -27,14 +27,20 @@ struct win_env
int (*towin32) (const char *, char *);
int (*posix_len) (const char *);
int (*win32_len) (const char *);
- void add_cache (const char *in_posix, const char *in_native = NULL);
- const char * get_native () {return native ? native + namelen : NULL;}
+ void add_cache (const char *in_posix, const char *in_native = NULL)
+ __attribute__ ((regparm (3)));
+ const char * get_native () const {return native ? native + namelen : NULL;}
+ const char * get_posix () const {return posix ? posix : NULL;}
};
-win_env * __stdcall getwinenv (const char *name, const char *posix = NULL);
+win_env * __stdcall getwinenv (const char *name, const char *posix = NULL)
+ __attribute__ ((regparm (3)));
+char * __stdcall getwinenveq (const char *name, size_t len, int)
+ __attribute__ ((regparm (3)));
void __stdcall update_envptrs ();
-char * __stdcall winenv (const char * const *, int);
extern char **__cygwin_environ, ***main_environ;
extern "C" char __stdcall **cur_environ ();
-int __stdcall envsize (const char * const *, int debug_print = 0);
+char ** __stdcall build_env (const char * const *envp, char *&envblock,
+ int &envc, bool need_envblock)
+ __attribute__ ((regparm (3)));
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index 540951c56..7cc3684e0 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -1,6 +1,6 @@
/* errno.cc: errno-related functions
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -8,12 +8,16 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#define _sys_nerr FOO_sys_nerr
+#define sys_nerr FOOsys_nerr
#include "winsup.h"
#define _REENT_ONLY
#include <stdio.h>
#include <errno.h>
#include "cygerrno.h"
#include "thread.h"
+#undef _sys_nerr
+#undef sys_nerr
/* Table to map Windows error codes to Errno values. */
/* FIXME: Doing things this way is a little slow. It's trivial to change
@@ -131,7 +135,7 @@ geterrno_from_win_error (DWORD code, int deferrno)
void __stdcall
seterrno_from_win_error (const char *file, int line, DWORD code)
{
- syscall_printf ("%s:%d errno %d", file, line, code);
+ syscall_printf ("%s:%d windows error %d", file, line, code);
set_errno (geterrno_from_win_error (code, EACCES));
return;
}
@@ -145,10 +149,11 @@ seterrno (const char *file, int line)
extern char *_user_strerror _PARAMS ((int));
-extern const NO_COPY char __declspec(dllexport) * const _sys_errlist[]=
+extern "C" {
+const NO_COPY char __declspec(dllexport) * const _sys_errlist[]=
{
/* NOERROR 0 */ "No error",
-/* EPERM 1 */ "Not super-user",
+/* EPERM 1 */ "Operation not permitted",
/* ENOENT 2 */ "No such file or directory",
/* ESRCH 3 */ "No such process",
/* EINTR 4 */ "Interrupted system call",
@@ -156,7 +161,7 @@ extern const NO_COPY char __declspec(dllexport) * const _sys_errlist[]=
/* ENXIO 6 */ "No such device or address",
/* E2BIG 7 */ "Arg list too long",
/* ENOEXEC 8 */ "Exec format error",
-/* EBADF 9 */ "Bad file number",
+/* EBADF 9 */ "Bad file descriptor",
/* ECHILD 10 */ "No children",
/* EAGAIN 11 */ "Resource temporarily unavailable",
/* ENOMEM 12 */ "Not enough core",
@@ -287,8 +292,8 @@ extern const NO_COPY char __declspec(dllexport) * const _sys_errlist[]=
/* ECASECLASH 137 */ "Filename exists with different case"
};
-int NO_COPY __declspec(dllexport) _sys_nerr =
- sizeof (_sys_errlist) / sizeof (_sys_errlist[0]);
+extern int const NO_COPY __declspec(dllexport) _sys_nerr = sizeof (_sys_errlist) / sizeof (_sys_errlist[0]);
+};
/* FIXME: Why is strerror() a long switch and not just:
return sys_errlist[errnum];
@@ -303,10 +308,13 @@ extern "C" char *
strerror (int errnum)
{
const char *error;
+ if (errnum < _sys_nerr)
+ error = _sys_errlist [errnum];
+ else
switch (errnum)
{
case EPERM:
- error = "Not owner";
+ error = "Operation not permitted";
break;
case ENOENT:
error = "No such file or directory";
@@ -330,7 +338,7 @@ strerror (int errnum)
error = "Exec format error";
break;
case EBADF:
- error = "Bad file number";
+ error = "Bad file descriptor";
break;
case ECHILD:
error = "No children";
@@ -665,7 +673,7 @@ strerror (int errnum)
break;
default:
#ifdef _MT_SAFE
- char *buf= _reent_winsup()->_strerror_buf;
+ char *buf= _reent_winsup ()->_strerror_buf;
#else
static NO_COPY char buf[20];
#endif
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 0102371a7..a1d7019fe 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1,6 +1,6 @@
/* exceptions.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,6 +11,7 @@ details. */
#include "winsup.h"
#include <imagehlp.h>
#include <errno.h>
+#include <stdlib.h>
#include "exceptions.h"
#include "sync.h"
@@ -37,6 +38,9 @@ extern DWORD __no_sig_start, __no_sig_end;
extern DWORD sigtid;
+extern HANDLE hExeced;
+extern DWORD dwExeced;
+
static BOOL WINAPI ctrl_c_handler (DWORD);
static void signal_exit (int) __attribute__ ((noreturn));
static char windows_system_directory[1024];
@@ -49,11 +53,11 @@ static NO_COPY muto *mask_sync = NULL;
HMODULE NO_COPY cygwin_hmodule;
-static const struct
+NO_COPY static struct
{
unsigned int code;
const char *name;
-} status_info[] NO_COPY =
+} status_info[] =
{
#define X(s) s, #s
{ X (STATUS_ABANDONED_WAIT_0) },
@@ -112,8 +116,12 @@ init_exception_handler (exception_list *el)
#endif
void
-set_console_handler ()
+early_stuff_init ()
{
+ (void) SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
+ if (!SetConsoleCtrlHandler (ctrl_c_handler, TRUE))
+ system_printf ("SetConsoleCtrlHandler failed, %E");
+
/* Initialize global security attribute stuff */
sec_none.nLength = sec_none_nih.nLength =
@@ -123,10 +131,6 @@ set_console_handler ()
sec_none.lpSecurityDescriptor = sec_none_nih.lpSecurityDescriptor = NULL;
sec_all.lpSecurityDescriptor = sec_all_nih.lpSecurityDescriptor =
get_null_sd ();
-
- (void) SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
- if (!SetConsoleCtrlHandler (ctrl_c_handler, TRUE))
- system_printf ("SetConsoleCtrlHandler failed, %E");
}
extern "C" void
@@ -144,11 +148,13 @@ error_start_init (const char *buf)
return;
}
- char myself_posix_name[MAX_PATH];
+ char pgm[MAX_PATH + 1];
+ if (!GetModuleFileName (NULL, pgm, MAX_PATH))
+ strcpy (pgm, "cygwin1.dll");
+ for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
+ *p = '/';
- /* FIXME: gdb cannot use win32 paths, but what if debugger isn't gdb? */
- cygwin_conv_to_posix_path (myself->progname, myself_posix_name);
- __small_sprintf (debugger_command, "%s %s", buf, myself_posix_name);
+ __small_sprintf (debugger_command, "%s %s", buf, pgm);
}
static void
@@ -170,7 +176,10 @@ open_stackdumpfile ()
CREATE_ALWAYS, 0, 0);
if (h != INVALID_HANDLE_VALUE)
{
- system_printf ("Dumping stack trace to %s", corefile);
+ if (!myself->ppid_handle)
+ system_printf ("Dumping stack trace to %s", corefile);
+ else
+ debug_printf ("Dumping stack trace to %s", corefile);
SetStdHandle (STD_ERROR_HANDLE, h);
}
}
@@ -334,8 +343,6 @@ try_to_debug (bool waitloop)
__small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
- BOOL dbg;
-
SetThreadPriority (hMainThread, THREAD_PRIORITY_HIGHEST);
PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
@@ -368,6 +375,7 @@ try_to_debug (bool waitloop)
}
}
+ BOOL dbg;
dbg = CreateProcess (NULL,
debugger_command,
NULL,
@@ -379,19 +387,19 @@ try_to_debug (bool waitloop)
&si,
&pi);
- static int NO_COPY keep_looping = 0;
-
- if (dbg)
+ if (!dbg)
+ system_printf ("Failed to start debugger: %E");
+ else
{
+ SetThreadPriority (hMainThread, THREAD_PRIORITY_IDLE);
if (!waitloop)
return 1;
- SetThreadPriority (hMainThread, THREAD_PRIORITY_IDLE);
- while (keep_looping)
+ while (!being_debugged ())
/* spin */;
+ Sleep (4000);
+ small_printf ("*** continuing from debugger call\n");
}
-
- system_printf ("Failed to start debugger: %E");
/* FIXME: need to know handles of all running threads to
resume_all_threads_except (current_thread_id);
*/
@@ -593,6 +601,7 @@ sig_handle_tty_stop (int sig)
myself->process_state &= ~PID_STOPPED;
return;
}
+
myself->stopsig = sig;
/* See if we have a living parent. If so, send it a special signal.
* It will figure out exactly which pid has stopped by scanning
@@ -601,11 +610,14 @@ sig_handle_tty_stop (int sig)
if (my_parent_is_alive ())
{
pinfo parent (myself->ppid);
- sig_send (parent, SIGCHLD);
+ if (!(parent->getsig (SIGCHLD).sa_flags & SA_NOCLDSTOP))
+ sig_send (parent, SIGCHLD);
}
sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p",
myself->pid, sig, myself->ppid_handle);
- SuspendThread (hMainThread);
+ if (WaitForSingleObject (sigCONT, INFINITE) != WAIT_OBJECT_0)
+ api_fatal ("WaitSingleObject failed, %E");
+ (void) ResetEvent (sigCONT);
return;
}
}
@@ -676,7 +688,8 @@ interrupt_setup (int sig, void *handler, DWORD retaddr, DWORD *retaddr_on_stack,
sigsave.retaddr = retaddr;
sigsave.retaddr_on_stack = retaddr_on_stack;
/* FIXME: Not multi-thread aware */
- sigsave.newmask = myself->getsigmask () | siga.sa_mask | SIGTOMASK (sig);
+ sigsave.oldmask = myself->getsigmask ();
+ sigsave.newmask = sigsave.oldmask | siga.sa_mask | SIGTOMASK (sig);
sigsave.sa_flags = siga.sa_flags;
sigsave.func = (void (*)(int)) handler;
sigsave.sig = sig;
@@ -705,15 +718,16 @@ interrupt_now (CONTEXT *ctx, int sig, void *handler, struct sigaction& siga)
void __stdcall
signal_fixup_after_fork ()
{
- if (!sigsave.sig)
- return;
-
- sigsave.sig = 0;
- if (sigsave.retaddr_on_stack)
+ if (sigsave.sig)
{
- *sigsave.retaddr_on_stack = sigsave.retaddr;
- set_process_mask (sigsave.oldmask);
+ sigsave.sig = 0;
+ if (sigsave.retaddr_on_stack)
+ {
+ *sigsave.retaddr_on_stack = sigsave.retaddr;
+ set_process_mask (sigsave.oldmask);
+ }
}
+ sigproc_init ();
}
void __stdcall
@@ -722,9 +736,9 @@ signal_fixup_after_exec (bool isspawn)
/* Set up child's signal handlers */
for (int i = 0; i < NSIG; i++)
{
- myself->getsig(i).sa_mask = 0;
- if (myself->getsig(i).sa_handler != SIG_IGN || isspawn)
- myself->getsig(i).sa_handler = SIG_DFL;
+ myself->getsig (i).sa_mask = 0;
+ if (myself->getsig (i).sa_handler != SIG_IGN || isspawn)
+ myself->getsig (i).sa_handler = SIG_DFL;
}
}
@@ -886,7 +900,7 @@ setup_handler (int sig, void *handler, struct sigaction& siga)
#error "Need to supply machine dependent setup_handler"
#endif
-/* CGF Keyboard interrupt handler. */
+/* Keyboard interrupt handler. */
static BOOL WINAPI
ctrl_c_handler (DWORD type)
{
@@ -907,8 +921,18 @@ ctrl_c_handler (DWORD type)
return FALSE;
}
+ /* If we are a stub and the new process has a pinfo structure, let it
+ handle this signal. */
+ if (dwExeced && pinfo (dwExeced))
+ return TRUE;
+
+ /* We're only the process group leader when we have a valid pinfo structure.
+ If we don't have one, then the parent "stub" will handle the signal. */
+ if (!pinfo (cygwin_pid (GetCurrentProcessId ())))
+ return TRUE;
+
tty_min *t = cygwin_shared->tty.get_tty (myself->ctty);
- /* Ignore this if we're not the process group lead since it should be handled
+ /* Ignore this if we're not the process group leader since it should be handled
*by* the process group leader. */
if (myself->ctty != -1 && t->getpgid () == myself->pid &&
(GetTickCount () - t->last_ctrl_c) >= MIN_CTRL_C_SLOP)
@@ -921,6 +945,7 @@ ctrl_c_handler (DWORD type)
t->last_ctrl_c = GetTickCount ();
return TRUE;
}
+
return TRUE;
}
@@ -945,7 +970,7 @@ set_process_mask (sigset_t newmask)
}
int __stdcall
-sig_handle (int sig)
+sig_handle (int sig, bool thisproc)
{
int rc = 0;
@@ -969,6 +994,7 @@ sig_handle (int sig)
/* FIXME: Should we still do this if SIGCONT has a handler? */
if (sig == SIGCONT)
{
+ DWORD stopped = myself->process_state & PID_STOPPED;
myself->stopsig = 0;
myself->process_state &= ~PID_STOPPED;
/* Clear pending stop signals */
@@ -976,10 +1002,8 @@ sig_handle (int sig)
sig_clear (SIGTSTP);
sig_clear (SIGTTIN);
sig_clear (SIGTTOU);
- /* Windows 95 hangs on resuming non-suspended thread */
- SuspendThread (hMainThread);
- while (ResumeThread (hMainThread) > 1)
- ;
+ if (stopped)
+ SetEvent (sigCONT);
/* process pending signals */
sig_dispatch_pending (1);
}
@@ -992,7 +1016,8 @@ sig_handle (int sig)
if (handler == (void *) SIG_DFL)
{
- if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH)
+ if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH
+ || sig == SIGURG || (thisproc && hExeced && sig == SIGINT))
{
sigproc_printf ("default signal %d ignored", sig);
goto done;
@@ -1013,9 +1038,6 @@ sig_handle (int sig)
if (handler == (void *) SIG_ERR)
goto exit_sig;
- if ((sig == SIGCHLD) && (thissig.sa_flags & SA_NOCLDSTOP))
- goto done;
-
goto dosig;
stop:
@@ -1055,8 +1077,6 @@ sig_handle (int sig)
static void
signal_exit (int rc)
{
- extern HANDLE hExeced;
-
rc = EXIT_SIGNAL | (rc << 8);
if (exit_already++)
myself->exit (rc);
@@ -1065,6 +1085,7 @@ signal_exit (int rc)
causes random, inexplicable hangs. So, instead, we set up the priority
of this thread really high so that it should do its thing and then exit. */
(void) SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+ (void) SetThreadPriority (hMainThread, THREAD_PRIORITY_IDLE);
/* Unlock any main thread mutos since we're executing with prejudice. */
muto *m;
@@ -1095,7 +1116,7 @@ events_init (void)
api_fatal ("can't create title mutex, %E");
ProtectHandle (title_mutex);
- mask_sync = new_muto (FALSE, "mask_sync");
+ new_muto (mask_sync);
windows_system_directory[0] = '\0';
(void) GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2);
char *end = strchr (windows_system_directory, '\0');
@@ -1203,14 +1224,14 @@ _sigdelayed0: \n\
pushl %%ecx \n\
pushl %%ebx \n\
pushl %%eax \n\
- pushl %7 # saved errno \n\
+ pushl %6 # saved errno \n\
pushl %3 # oldmask \n\
pushl %4 # signal argument \n\
pushl $_sigreturn \n\
\n\
call _reset_signal_arrived@0 \n\
pushl %5 # signal number \n\
- pushl %8 # newmask \n\
+ pushl %7 # newmask \n\
movl $0,%0 # zero the signal number as a \n\
# flag to the signal handler thread\n\
# that it is ok to set up sigsave\n\
@@ -1221,7 +1242,7 @@ _sigdelayed0: \n\
__no_sig_end: \n\
" : "=m" (sigsave.sig) : "m" (&_impure_ptr->_errno),
"g" (sigsave.retaddr), "g" (sigsave.oldmask), "g" (sigsave.sig),
- "g" (sigsave.func), "o" (pid_offset), "g" (sigsave.saved_errno), "g" (sigsave.newmask)
+ "g" (sigsave.func), "g" (sigsave.saved_errno), "g" (sigsave.newmask)
);
}
}
diff --git a/winsup/cygwin/exec.cc b/winsup/cygwin/exec.cc
index 228aa69b0..942b79d83 100644
--- a/winsup/cygwin/exec.cc
+++ b/winsup/cygwin/exec.cc
@@ -1,6 +1,6 @@
/* exec.cc: exec system call support.
- Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -17,27 +17,24 @@ details. */
#include "security.h"
#include "fhandler.h"
#include "path.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "environ.h"
+#include "cygerrno.h"
/* This is called _execve and not execve because the real execve is defined
in libc/posix/execve.c. It calls us. */
-extern "C"
-int
+extern "C" int
_execve (const char *path, char *const argv[], char *const envp[])
{
static char *const empty_env[] = { 0 };
MALLOC_CHECK;
if (!envp)
envp = empty_env;
- return _spawnve (NULL, _P_OVERLAY, path, argv, envp);
+ return spawnve (_P_OVERLAY, path, argv, envp);
}
-extern "C"
-int
+extern "C" int
execl (const char *path, const char *arg0, ...)
{
int i;
@@ -55,131 +52,18 @@ execl (const char *path, const char *arg0, ...)
return _execve (path, (char * const *) argv, cur_environ ());
}
-extern "C"
-int
+extern "C" int
execv (const char *path, char * const *argv)
{
MALLOC_CHECK;
return _execve (path, (char * const *) argv, cur_environ ());
}
-/* the same as a standard exec() calls family, but with NT security support */
-
-extern "C"
-pid_t
-sexecve (HANDLE hToken, const char *path, const char *const argv[],
- const char *const envp[])
-{
- _spawnve (hToken, _P_OVERLAY, path, argv, envp);
- return -1;
-}
-
-extern "C"
-int
-sexecl (HANDLE hToken, const char *path, const char *arg0, ...)
-{
- int i;
- va_list args;
- const char *argv[1024];
-
- va_start (args, arg0);
- argv[0] = arg0;
- i = 1;
-
- do
- argv[i] = va_arg (args, const char *);
- while (argv[i++] != NULL);
-
- va_end (args);
-
- MALLOC_CHECK;
- return sexecve (hToken, path, (char * const *) argv, cur_environ ());
-}
-
-extern "C"
-int
-sexecle (HANDLE hToken, const char *path, const char *arg0, ...)
-{
- int i;
- va_list args;
- const char * const *envp;
- const char *argv[1024];
-
- va_start (args, arg0);
- argv[0] = arg0;
- i = 1;
-
- do
- argv[i] = va_arg (args, const char *);
- while (argv[i++] != NULL);
-
- envp = va_arg (args, const char * const *);
- va_end (args);
-
- MALLOC_CHECK;
- return sexecve(hToken, path, (char * const *) argv, (char * const *) envp);
-}
-
-extern "C"
-int
-sexeclp (HANDLE hToken, const char *path, const char *arg0, ...)
-{
- int i;
- va_list args;
- const char *argv[1024];
-
- va_start (args, arg0);
- argv[0] = arg0;
- i = 1;
-
- do
- argv[i] = va_arg (args, const char *);
- while (argv[i++] != NULL);
-
- va_end (args);
-
- MALLOC_CHECK;
- return sexecvpe (hToken, path, (const char * const *) argv, cur_environ ());
-}
-
-extern "C"
-int
-sexeclpe (HANDLE hToken, const char *path, const char *arg0, ...)
-{
- int i;
- va_list args;
- const char * const *envp;
- const char *argv[1024];
-
- va_start (args, arg0);
- argv[0] = arg0;
- i = 1;
-
- do
- argv[i] = va_arg (args, const char *);
- while (argv[i++] != NULL);
-
- envp = va_arg (args, const char * const *);
- va_end (args);
-
- MALLOC_CHECK;
- return sexecvpe (hToken, path, argv, envp);
-}
-
-extern "C"
-int
-sexecv (HANDLE hToken, const char *path, const char * const *argv)
+extern "C" pid_t
+sexecve_is_bad ()
{
- MALLOC_CHECK;
- return sexecve (hToken, path, argv, cur_environ ());
-}
-
-extern "C"
-int
-sexecp (HANDLE hToken, const char *path, const char * const *argv)
-{
- MALLOC_CHECK;
- return sexecvpe (hToken, path, argv, cur_environ ());
+ set_errno (ENOSYS);
+ return 0;
}
/*
@@ -199,12 +83,16 @@ strccpy (char *s1, const char **s2, char c)
return s1;
}
-extern "C"
-int
-sexecvpe (HANDLE hToken, const char *file, const char * const *argv,
- const char *const *envp)
+extern "C" int
+execvp (const char *path, char * const *argv)
{
path_conv buf;
- MALLOC_CHECK;
- return sexecve (hToken, find_exec (file, buf), argv, envp);
+ return execv (find_exec (path, buf), argv);
+}
+
+extern "C" int
+execvpe (const char *path, char * const *argv, char *const *envp)
+{
+ path_conv buf;
+ return execve (find_exec (path, buf), argv, envp);
}
diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
index 099993e5c..571ea6742 100644
--- a/winsup/cygwin/external.cc
+++ b/winsup/cygwin/external.cc
@@ -1,6 +1,6 @@
/* external.cc: Interface to Cygwin internals from external programs.
- Copyright 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Christopher Faylor <cgf@cygnus.com>
@@ -11,15 +11,23 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
+#include <errno.h>
#include "security.h"
#include "fhandler.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include <exceptions.h>
#include "shared_info.h"
#include "cygwin_version.h"
#include "perprocess.h"
+#include "cygerrno.h"
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "wincap.h"
+#include "heap.h"
+#include "cygthread.h"
static external_pinfo *
fillout_pinfo (pid_t pid, int winpid)
@@ -32,10 +40,13 @@ fillout_pinfo (pid_t pid, int winpid)
static winpids pids (0);
+ static unsigned int i;
if (!pids.npids || !nextpid)
- pids.init (winpid);
+ {
+ pids.init (winpid);
+ i = 0;
+ }
- static unsigned int i;
if (!pid)
i = 0;
@@ -73,9 +84,12 @@ fillout_pinfo (pid_t pid, int winpid)
ep.rusage_children = p->rusage_children;
strcpy (ep.progname, p->progname);
ep.strace_mask = 0;
- ep.strace_file = 0;
+ ep.version = EXTERNAL_PINFO_VERSION;
ep.process_state = p->process_state;
+
+ ep.uid32 = p->uid;
+ ep.gid32 = p->gid;
break;
}
}
@@ -112,6 +126,16 @@ cygwin_internal (cygwin_getinfo_types t, ...)
{
va_list arg;
va_start (arg, t);
+ if (t != CW_USER_DATA)
+ {
+ wincap.init ();
+ if (!myself)
+ {
+ memory_init ();
+ malloc_init ();
+ set_myself (1);
+ }
+ }
switch (t)
{
@@ -122,13 +146,12 @@ cygwin_internal (cygwin_getinfo_types t, ...)
return 1;
case CW_GETTHREADNAME:
- return (DWORD) threadname (va_arg (arg, DWORD));
+ return (DWORD) cygthread::name (va_arg (arg, DWORD));
case CW_SETTHREADNAME:
{
- char *name = va_arg (arg, char *);
- regthread (name, va_arg (arg, DWORD));
- return 1;
+ set_errno (ENOSYS);
+ return 0;
}
case CW_GETPINFO:
@@ -138,9 +161,8 @@ cygwin_internal (cygwin_getinfo_types t, ...)
return (DWORD) cygwin_version_strings;
case CW_READ_V1_MOUNT_TABLES:
- /* Upgrade old v1 registry mounts to new location. */
- mount_table->import_v1_mounts ();
- return 0;
+ set_errno (ENOSYS);
+ return 1;
case CW_USER_DATA:
return (DWORD) &__cygwin_user_data;
@@ -172,6 +194,53 @@ cygwin_internal (cygwin_getinfo_types t, ...)
return get_cygdrive_info (user, system, user_flags, system_flags);
}
+ case CW_SET_CYGWIN_REGISTRY_NAME:
+ {
+# define cr ((char *) arg)
+ if (check_null_empty_str_errno (cr))
+ return (DWORD) NULL;
+ cygheap->cygwin_regname = (char *) crealloc (cygheap->cygwin_regname,
+ strlen (cr) + 1);
+ strcpy (cygheap->cygwin_regname, cr);
+ case CW_GET_CYGWIN_REGISTRY_NAME:
+ return (DWORD) cygheap->cygwin_regname;
+# undef cr
+ }
+
+ case CW_STRACE_TOGGLE:
+ {
+ pid_t pid = va_arg (arg, pid_t);
+ pinfo p (pid);
+ if (p)
+ {
+ sig_send (p, __SIGSTRACE);
+ return 0;
+ }
+ else
+ {
+ set_errno (ESRCH);
+ return (DWORD) -1;
+ }
+ }
+
+ case CW_STRACE_ACTIVE:
+ {
+ return strace.active;
+ }
+
+ case CW_CYGWIN_PID_TO_WINPID:
+ {
+ pinfo p (va_arg (arg, pid_t));
+ return p ? p->dwProcessId : 0;
+ }
+ case CW_EXTRACT_DOMAIN_AND_USER:
+ {
+ struct passwd *pw = va_arg (arg, struct passwd *);
+ char *domain = va_arg (arg, char *);
+ char *user = va_arg (arg, char *);
+ extract_nt_dom_user (pw, domain, user);
+ return 0;
+ }
default:
return (DWORD) -1;
}
diff --git a/winsup/cygwin/fcntl.cc b/winsup/cygwin/fcntl.cc
index b531218f6..0ba704991 100644
--- a/winsup/cygwin/fcntl.cc
+++ b/winsup/cygwin/fcntl.cc
@@ -1,6 +1,6 @@
/* fcntl.cc: fcntl syscall
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
@@ -17,8 +16,8 @@ details. */
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "cygheap.h"
#include "cygerrno.h"
+#include "cygheap.h"
#include "thread.h"
extern "C"
@@ -29,22 +28,20 @@ _fcntl (int fd, int cmd,...)
va_list args;
int res;
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd, true);
+ if (cfd < 0)
{
- set_errno (EBADF);
res = -1;
goto done;
}
- SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK, "_fcntl");
va_start (args, cmd);
arg = va_arg (args, void *);
- if (cmd == F_DUPFD)
- res = dup2 (fd, cygheap->fdtab.find_unused_handle ((int) arg));
+ if (cmd != F_DUPFD)
+ res = cfd->fcntl(cmd, arg);
else
- res = cygheap->fdtab[fd]->fcntl(cmd, arg);
+ res = dup2 (fd, cygheap_fdnew (((int) arg) - 1));
va_end (args);
- ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"_fcntl");
done:
syscall_printf ("%d = fcntl (%d, %d, %p)", res, fd, cmd, arg);
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 54adc8dc2..e1271bc79 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1,6 +1,6 @@
/* fhandler.cc. See console.cc for fhandler_console functions.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,11 +9,11 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <sys/fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/cygwin.h>
+#include <sys/uio.h>
#include <signal.h>
#include "cygerrno.h"
#include "perprocess.h"
@@ -24,7 +24,9 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "shared_info.h"
+#include "pinfo.h"
#include <assert.h>
+#include <limits.h>
static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
@@ -47,7 +49,7 @@ fhandler_base::operator =(fhandler_base &x)
}
int
-fhandler_base::puts_readahead (const char *s, size_t len = (size_t) -1)
+fhandler_base::puts_readahead (const char *s, size_t len)
{
int success = 1;
while ((*s || (len != (size_t) -1 && len--))
@@ -96,12 +98,12 @@ fhandler_base::peek_readahead (int queryput)
}
void
-fhandler_base::set_readahead_valid (int val, int ch = -1)
+fhandler_base::set_readahead_valid (int val, int ch)
{
if (!val)
ralen = raixget = raixput = 0;
if (ch != -1)
- put_readahead(ch);
+ put_readahead (ch);
}
int
@@ -145,7 +147,8 @@ fhandler_base::get_readahead_into_buffer (char *buf, size_t buflen)
/* Record the file name.
Filenames are used mostly for debugging messages, and it's hoped that
in cases where the name is really required, the filename wouldn't ever
- be too long (e.g. devices or some such). */
+ be too long (e.g. devices or some such).
+ The unix_path_name is also used by virtual fhandlers. */
void
fhandler_base::set_name (const char *unix_path, const char *win32_path, int unit)
{
@@ -157,8 +160,9 @@ fhandler_base::set_name (const char *unix_path, const char *win32_path, int unit
else
{
const char *fmt = get_native_name ();
- win32_path_name = (char *) cmalloc (HEAP_STR, strlen(fmt) + 16);
- __small_sprintf (win32_path_name, fmt, unit);
+ char *w = (char *) cmalloc (HEAP_STR, strlen (fmt) + 16);
+ __small_sprintf (w, fmt, unit);
+ win32_path_name = w;
}
if (win32_path_name == NULL)
@@ -174,12 +178,15 @@ fhandler_base::set_name (const char *unix_path, const char *win32_path, int unit
path_conv. Ideally, we should pass in a format string and build the
unix_path, too. */
if (!is_device () || *win32_path_name != '\\')
- unix_path_name = cstrdup (unix_path);
+ unix_path_name = unix_path;
else
{
- unix_path_name = cstrdup (win32_path_name);
- for (char *p = unix_path_name; (p = strchr (p, '\\')); p++)
- *p = '/';
+ char *p = cstrdup (win32_path_name);
+ unix_path_name = p;
+ while ((p = strchr (p, '\\')) != NULL)
+ *p++ = '/';
+ if (unix_path)
+ cfree ((void *) unix_path);
}
if (unix_path_name == NULL)
@@ -187,13 +194,7 @@ fhandler_base::set_name (const char *unix_path, const char *win32_path, int unit
system_printf ("fatal error. strdup failed");
exit (ENOMEM);
}
-}
-
-void
-fhandler_base::reset_unix_path_name (const char *unix_path)
-{
- cfree (unix_path_name);
- unix_path_name = cstrdup (unix_path);
+ namehash = hash_path_name (0, win32_path_name);
}
/* Detect if we are sitting at EOF for conditions where Windows
@@ -216,6 +217,34 @@ is_at_eof (HANDLE h, DWORD err)
return 0;
}
+void
+fhandler_base::set_flags (int flags, int supplied_bin)
+{
+ int bin;
+ int fmode;
+ debug_printf ("flags %p, supplied_bin %p", flags, supplied_bin);
+ if ((bin = flags & (O_BINARY | O_TEXT)))
+ debug_printf ("O_TEXT/O_BINARY set in flags %p", bin);
+ else if (get_r_binset () && get_w_binset ())
+ bin = get_r_binary () ? O_BINARY : O_TEXT; // FIXME: Not quite right
+ else if ((fmode = get_default_fmode (flags)) & O_BINARY)
+ bin = O_BINARY;
+ else if (fmode & O_TEXT)
+ bin = O_TEXT;
+ else if (supplied_bin)
+ bin = supplied_bin;
+ else
+ bin = get_w_binary () || get_r_binary () || (binmode != O_TEXT)
+ ? O_BINARY : O_TEXT;
+
+ openflags = flags | bin;
+
+ bin &= O_BINARY;
+ set_r_binary (bin);
+ set_w_binary (bin);
+ syscall_printf ("filemode set to %s", bin ? "binary" : "text");
+}
+
/* Normal file i/o handlers. */
/* Cover function to ReadFile to achieve (as much as possible) Posix style
@@ -225,7 +254,7 @@ fhandler_base::raw_read (void *ptr, size_t ulen)
{
DWORD bytes_read;
- if (!ReadFile (get_handle(), ptr, ulen, &bytes_read, 0))
+ if (!ReadFile (get_handle (), ptr, ulen, &bytes_read, 0))
{
int errcode;
@@ -246,6 +275,7 @@ fhandler_base::raw_read (void *ptr, size_t ulen)
return 0;
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_PARAMETER:
+ case ERROR_INVALID_HANDLE:
if (openflags & O_DIROPEN)
{
set_errno (EISDIR);
@@ -269,7 +299,7 @@ fhandler_base::raw_write (const void *ptr, size_t len)
{
DWORD bytes_written;
- if (!WriteFile (get_handle(), ptr, len, &bytes_written, 0))
+ if (!WriteFile (get_handle (), ptr, len, &bytes_written, 0))
{
if (GetLastError () == ERROR_DISK_FULL && bytes_written > 0)
return bytes_written;
@@ -285,13 +315,17 @@ fhandler_base::raw_write (const void *ptr, size_t len)
int
fhandler_base::get_default_fmode (int flags)
{
+ int fmode = __fmode;
if (perfile_table)
{
size_t nlen = strlen (get_name ());
unsigned accflags = ACCFLAGS (flags);
for (__cygwin_perfile *pf = perfile_table; pf->name; pf++)
if (!*pf->name && ACCFLAGS (pf->flags) == accflags)
- return pf->flags & ~(O_RDONLY | O_WRONLY | O_RDWR);
+ {
+ fmode = pf->flags & ~(O_RDONLY | O_WRONLY | O_RDWR);
+ break;
+ }
else
{
size_t pflen = strlen (pf->name);
@@ -299,22 +333,18 @@ fhandler_base::get_default_fmode (int flags)
if (pflen > nlen || (stem != get_name () && !isdirsep (stem[-1])))
continue;
else if (ACCFLAGS (pf->flags) == accflags && strcasematch (stem, pf->name))
- return pf->flags & ~(O_RDONLY | O_WRONLY | O_RDWR);
+ {
+ fmode = pf->flags & ~(O_RDONLY | O_WRONLY | O_RDWR);
+ break;
+ }
}
}
- return __fmode;
-}
-
-int
-fhandler_base::open (path_conv& real_path, int flags, mode_t mode)
-{
- return open ((char *) real_path, flags, mode);
+ return fmode;
}
-/* Open system call handler function.
- Path is now already checked for symlinks */
+/* Open system call handler function. */
int
-fhandler_base::open (int flags, mode_t mode)
+fhandler_base::open (path_conv *pc, int flags, mode_t mode)
{
int res = 0;
HANDLE x;
@@ -323,7 +353,7 @@ fhandler_base::open (int flags, mode_t mode)
int creation_distribution;
SECURITY_ATTRIBUTES sa = sec_none;
- syscall_printf ("(%s, %p)", get_win32_name (), flags);
+ syscall_printf ("(%s, %p) query_open %d", get_win32_name (), flags, get_query_open ());
if (get_win32_name () == NULL)
{
@@ -364,7 +394,7 @@ fhandler_base::open (int flags, mode_t mode)
creation_distribution = CREATE_NEW;
if (flags & O_APPEND)
- set_append_p();
+ set_append_p ();
/* These flags are host dependent. */
shared = wincap.shared ();
@@ -375,40 +405,58 @@ fhandler_base::open (int flags, mode_t mode)
if (get_device () == FH_SERIAL)
file_attributes |= FILE_FLAG_OVERLAPPED;
+#ifdef HIDDEN_DOT_FILES
+ if (flags & O_CREAT && get_device () == FH_DISK)
+ {
+ char *c = strrchr (get_win32_name (), '\\');
+ if ((c && c[1] == '.') || *get_win32_name () == '.')
+ file_attributes |= FILE_ATTRIBUTE_HIDDEN;
+ }
+#endif
+
/* CreateFile() with dwDesiredAccess == 0 when called on remote
share returns some handle, even if file doesn't exist. This code
works around this bug. */
- if (get_query_open () &&
- isremote () &&
- creation_distribution == OPEN_EXISTING &&
- GetFileAttributes (get_win32_name ()) == (DWORD) -1)
+ if (get_query_open () && isremote () &&
+ creation_distribution == OPEN_EXISTING && pc && !pc->exists ())
{
set_errno (ENOENT);
goto done;
}
+ /* If mode has no write bits set, we set the R/O attribute. */
+ if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+ file_attributes |= FILE_ATTRIBUTE_READONLY;
+
/* If the file should actually be created and ntsec is on,
set files attributes. */
if (flags & O_CREAT && get_device () == FH_DISK && allow_ntsec && has_acls ())
set_security_attribute (mode, &sa, alloca (4096), 4096);
- x = CreateFileA (get_win32_name (), access, shared,
- &sa, creation_distribution,
- file_attributes,
- 0);
+ x = CreateFile (get_win32_name (), access, shared, &sa, creation_distribution,
+ file_attributes, 0);
- syscall_printf ("%p = CreateFileA (%s, %p, %p, %p, %p, %p, 0)",
- x, get_win32_name (), access, shared,
- &sa, creation_distribution,
- file_attributes);
+ syscall_printf ("%p = CreateFile (%s, %p, %p, %p, %p, %p, 0)",
+ x, get_win32_name (), access, shared, &sa,
+ creation_distribution, file_attributes);
if (x == INVALID_HANDLE_VALUE)
{
- if (GetLastError () == ERROR_INVALID_HANDLE)
+ if (pc->isdir () && !wincap.can_open_directories ())
+ {
+ if (mode & (O_CREAT | O_EXCL) == (O_CREAT | O_EXCL))
+ set_errno (EEXIST);
+ else if (mode & (O_WRONLY | O_RDWR))
+ set_errno (EISDIR);
+ else
+ set_nohandle (true);
+ }
+ else if (GetLastError () == ERROR_INVALID_HANDLE)
set_errno (ENOENT);
else
__seterrno ();
- goto done;
+ if (!get_nohandle ())
+ goto done;
}
/* Attributes may be set only if a file is _really_ created.
@@ -419,39 +467,8 @@ fhandler_base::open (int flags, mode_t mode)
&& !allow_ntsec && allow_ntea)
set_file_attribute (has_acls (), get_win32_name (), mode);
- namehash = hash_path_name (0, get_win32_name ());
set_io_handle (x);
- int bin;
- int fmode;
- if ((bin = flags & (O_BINARY | O_TEXT)))
- /* nothing to do */;
- else if ((fmode = get_default_fmode (flags)) & O_BINARY)
- bin = O_BINARY;
- else if (fmode & O_TEXT)
- bin = O_TEXT;
- else if (get_device () == FH_DISK)
- bin = get_w_binary () || get_r_binary ();
- else
- bin = (binmode == O_BINARY) || get_w_binary () || get_r_binary ();
-
- if (bin & O_TEXT)
- bin = 0;
-
- set_flags (flags | (bin ? O_BINARY : O_TEXT));
-
- set_r_binary (bin);
- set_w_binary (bin);
- syscall_printf ("filemode set to %s", bin ? "binary" : "text");
-
- if (get_device () != FH_TAPE
- && get_device () != FH_FLOPPY
- && get_device () != FH_SERIAL)
- {
- if (flags & O_APPEND)
- SetFilePointer (get_handle(), 0, 0, FILE_END);
- else
- SetFilePointer (get_handle(), 0, 0, FILE_BEGIN);
- }
+ set_flags (flags, pc ? pc->binmode () : 0);
res = 1;
set_open_status ();
@@ -487,6 +504,9 @@ fhandler_base::read (void *in_ptr, size_t in_len)
len--;
}
+ if (copied_chars && is_slow ())
+ return copied_chars;
+
if (len)
{
int readlen = raw_read (ptr + copied_chars, len);
@@ -581,7 +601,7 @@ fhandler_base::write (const void *ptr, size_t len)
int res;
if (get_append_p ())
- SetFilePointer (get_handle(), 0, 0, FILE_END);
+ SetFilePointer (get_handle (), 0, 0, FILE_END);
else if (wincap.has_lseek_bug () && get_check_win95_lseek_bug ())
{
/* Note: this bug doesn't happen on NT4, even though the documentation
@@ -689,85 +709,154 @@ fhandler_base::write (const void *ptr, size_t len)
return res;
}
-off_t
-fhandler_base::lseek (off_t offset, int whence)
+ssize_t
+fhandler_base::readv (const struct iovec *const iov, const int iovcnt,
+ ssize_t tot)
{
- off_t res;
+ assert (iov);
+ assert (iovcnt >= 1);
- /* Seeks on text files is tough, we rewind and read till we get to the
- right place. */
+ if (iovcnt == 1)
+ return read (iov->iov_base, iov->iov_len);
- if (whence != SEEK_CUR || offset != 0)
+ if (tot == -1) // i.e. if not pre-calculated by the caller.
{
- if (whence == SEEK_CUR)
- offset -= ralen - raixget;
- set_readahead_valid (0);
+ tot = 0;
+ const struct iovec *iovptr = iov + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ tot += iovptr->iov_len;
+ }
+ while (iovptr != iov);
}
- debug_printf ("lseek (%s, %d, %d)", unix_path_name, offset, whence);
+ assert (tot >= 0);
-#if 0 /* lseek has no business messing about with text-mode stuff */
+ if (tot == 0)
+ return 0;
- if (!get_r_binary ())
+ char *buf = (char *) alloca (tot);
+
+ if (!buf)
{
- int newplace;
+ set_errno (ENOMEM);
+ return -1;
+ }
- if (whence == 0)
- {
- newplace = offset;
- }
- else if (whence ==1)
- {
- newplace = rpos + offset;
- }
- else
- {
- /* Seek from the end of a file.. */
- if (rsize == -1)
- {
- /* Find the size of the file by reading till the end */
+ const ssize_t res = read (buf, tot);
- char b[CHUNK_SIZE];
- while (read (b, sizeof (b)) > 0)
- ;
- rsize = rpos;
- }
- newplace = rsize + offset;
- }
+ const struct iovec *iovptr = iov;
+ int nbytes = res;
- if (rpos > newplace)
- {
- SetFilePointer (handle, 0, 0, 0);
- rpos = 0;
- }
+ while (nbytes > 0)
+ {
+ const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
+ memcpy (iovptr->iov_base, buf, frag);
+ buf += frag;
+ iovptr += 1;
+ nbytes -= frag;
+ }
+
+ return res;
+}
- /* You can never shrink something more than 50% by turning CRLF into LF,
- so we binary chop looking for the right place */
+ssize_t
+fhandler_base::writev (const struct iovec *const iov, const int iovcnt,
+ ssize_t tot)
+{
+ assert (iov);
+ assert (iovcnt >= 1);
+
+ if (iovcnt == 1)
+ return write (iov->iov_base, iov->iov_len);
- while (rpos < newplace)
+ if (tot == -1) // i.e. if not pre-calculated by the caller.
+ {
+ tot = 0;
+ const struct iovec *iovptr = iov + iovcnt;
+ do
{
- char b[CHUNK_SIZE];
- size_t span = (newplace - rpos) / 2;
- if (span == 0)
- span = 1;
- if (span > sizeof (b))
- span = sizeof (b);
-
- debug_printf ("lseek (%s, %d, %d) span %d, rpos %d newplace %d",
- name, offset, whence,span,rpos, newplace);
- read (b, span);
+ iovptr -= 1;
+ tot += iovptr->iov_len;
}
+ while (iovptr != iov);
+ }
+
+ assert (tot >= 0);
- debug_printf ("Returning %d", newplace);
- return newplace;
+ if (tot == 0)
+ return 0;
+
+ char *const buf = (char *) alloca (tot);
+
+ if (!buf)
+ {
+ set_errno (ENOMEM);
+ return -1;
}
-#endif /* end of deleted code dealing with text mode */
+
+ char *bufptr = buf;
+ const struct iovec *iovptr = iov;
+ int nbytes = tot;
+
+ while (nbytes != 0)
+ {
+ const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
+ memcpy (bufptr, iovptr->iov_base, frag);
+ bufptr += frag;
+ iovptr += 1;
+ nbytes -= frag;
+ }
+
+ return write (buf, tot);
+}
+
+__off64_t
+fhandler_base::lseek (__off64_t offset, int whence)
+{
+ __off64_t res;
+
+ /* 9x/Me doesn't support 64bit offsets. We trap that here and return
+ EINVAL. It doesn't make sense to simulate bigger offsets by a
+ SetFilePointer sequence since FAT and FAT32 don't support file
+ size >= 4GB anyway. */
+ if (!wincap.has_64bit_file_access ()
+ && (offset < LONG_MIN || offset > LONG_MAX))
+ {
+ debug_printf ("Win9x, offset not 32 bit.");
+ set_errno (EINVAL);
+ return (__off64_t)-1;
+ }
+
+ /* Seeks on text files is tough, we rewind and read till we get to the
+ right place. */
+
+ if (whence != SEEK_CUR || offset != 0)
+ {
+ if (whence == SEEK_CUR)
+ offset -= ralen - raixget;
+ set_readahead_valid (0);
+ }
+
+ debug_printf ("lseek (%s, %D, %d)", unix_path_name, offset, whence);
DWORD win32_whence = whence == SEEK_SET ? FILE_BEGIN
: (whence == SEEK_CUR ? FILE_CURRENT : FILE_END);
- res = SetFilePointer (get_handle(), offset, 0, win32_whence);
- if (res == -1)
+ LONG off_low = offset & 0xffffffff;
+ LONG *poff_high, off_high;
+ if (!wincap.has_64bit_file_access ())
+ poff_high = NULL;
+ else
+ {
+ off_high = offset >> 32;
+ poff_high = &off_high;
+ }
+
+ debug_printf ("setting file pointer to %u (high), %u (low)", off_high, off_low);
+ res = SetFilePointer (get_handle (), off_low, poff_high, win32_whence);
+ if (res == INVALID_SET_FILE_POINTER && GetLastError ())
{
__seterrno ();
}
@@ -792,12 +881,12 @@ fhandler_base::close ()
{
int res = -1;
- syscall_printf ("handle %p", get_handle());
- if (CloseHandle (get_handle()))
+ syscall_printf ("closing '%s' handle %p", get_name (), get_handle ());
+ if (get_nohandle () || CloseHandle (get_handle ()))
res = 0;
else
{
- paranoid_printf ("CloseHandle (%d <%s>) failed", get_handle(),
+ paranoid_printf ("CloseHandle (%d <%s>) failed", get_handle (),
get_name ());
__seterrno ();
@@ -820,12 +909,12 @@ fhandler_base::ioctl (unsigned int cmd, void *buf)
int
fhandler_base::lock (int, struct flock *)
{
- set_errno (ENOSYS);
+ set_errno (EINVAL);
return -1;
}
extern "C" char * __stdcall
-rootdir(char *full_path)
+rootdir (char *full_path)
{
/* Possible choices:
* d:... -> d:/
@@ -857,172 +946,33 @@ rootdir(char *full_path)
return root;
}
-int
-fhandler_disk_file::fstat (struct stat *buf)
+int __stdcall
+fhandler_base::fstat (struct __stat64 *buf, path_conv *)
{
- int res = 0; // avoid a compiler warning
- BY_HANDLE_FILE_INFORMATION local;
- save_errno saved_errno;
-
- memset (buf, 0, sizeof (*buf));
-
- /* NT 3.51 seems to have a bug when attempting to get vol serial
- numbers. This loop gets around this. */
- for (int i = 0; i < 2; i++)
- {
- if (!(res = GetFileInformationByHandle (get_handle (), &local)))
- break;
- if (local.dwVolumeSerialNumber && (long) local.dwVolumeSerialNumber != -1)
- break;
- }
- debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
- res, get_win32_name (), get_handle ());
- if (res == 0)
- {
- /* GetFileInformationByHandle will fail if it's given stdin/out/err
- or a pipe*/
- DWORD lsize, hsize;
-
- if (GetFileType (get_handle ()) != FILE_TYPE_DISK)
- buf->st_mode = S_IFCHR;
-
- lsize = GetFileSize (get_handle (), &hsize);
- if (lsize == 0xffffffff && GetLastError () != NO_ERROR)
- buf->st_mode = S_IFCHR;
- else
- buf->st_size = lsize;
- /* We expect these to fail! */
- buf->st_mode |= STD_RBITS | STD_WBITS;
- buf->st_blksize = S_BLKSIZE;
- buf->st_ino = get_namehash ();
- syscall_printf ("0 = fstat (, %p)", buf);
- return 0;
- }
-
- if (!get_win32_name ())
- {
- saved_errno.set (ENOENT);
- return -1;
- }
-
- buf->st_atime = to_time_t (&local.ftLastAccessTime);
- buf->st_mtime = to_time_t (&local.ftLastWriteTime);
- buf->st_ctime = to_time_t (&local.ftCreationTime);
- buf->st_nlink = local.nNumberOfLinks;
- buf->st_dev = local.dwVolumeSerialNumber;
- buf->st_size = local.nFileSizeLow;
-
- /* This is for FAT filesystems, which don't support atime/ctime */
- if (buf->st_atime == 0)
- buf->st_atime = buf->st_mtime;
- if (buf->st_ctime == 0)
- buf->st_ctime = buf->st_mtime;
-
- /* Allocate some place to determine the root directory. Need to allocate
- enough so that rootdir can add a trailing slash if path starts with \\. */
- char root[strlen (get_win32_name ()) + 3];
- strcpy (root, get_win32_name ());
-
- /* Assume that if a drive has ACL support it MAY have valid "inodes".
- It definitely does not have valid inodes if it does not have ACL
- support. */
- switch (has_acls () ? GetDriveType (rootdir (root)) : DRIVE_UNKNOWN)
+ debug_printf ("here");
+ switch (get_device ())
{
- case DRIVE_FIXED:
- case DRIVE_REMOVABLE:
- case DRIVE_CDROM:
- case DRIVE_RAMDISK:
- /* Although the documentation indicates otherwise, it seems like
- "inodes" on these devices are persistent, at least across reboots. */
- buf->st_ino = local.nFileIndexHigh | local.nFileIndexLow;
+ case FH_PIPE:
+ buf->st_mode = S_IFIFO | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH;
+ break;
+ case FH_PIPEW:
+ buf->st_mode = S_IFIFO | STD_WBITS | S_IWGRP | S_IWOTH;
+ break;
+ case FH_PIPER:
+ buf->st_mode = S_IFIFO | STD_RBITS;
+ break;
+ case FH_FLOPPY:
+ buf->st_mode = S_IFBLK | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH;
break;
default:
- /* Either the nFileIndex* fields are unreliable or unavailable. Use the
- next best alternative. */
- buf->st_ino = get_namehash ();
+ buf->st_mode = S_IFCHR | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH;
break;
}
+ buf->st_nlink = 1;
buf->st_blksize = S_BLKSIZE;
- buf->st_blocks = ((unsigned long) buf->st_size + S_BLKSIZE-1) / S_BLKSIZE;
-
- buf->st_mode = 0;
- /* Using a side effect: get_file_attibutes checks for
- directory. This is used, to set S_ISVTX, if needed. */
- if (local.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- buf->st_mode = S_IFDIR;
- else if (get_symlink_p ())
- buf->st_mode = S_IFLNK;
- else if (get_socket_p ())
- buf->st_mode = S_IFSOCK;
- if (get_file_attribute (has_acls (), get_win32_name (), &buf->st_mode,
- &buf->st_uid, &buf->st_gid) == 0)
- {
- /* If read-only attribute is set, modify ntsec return value */
- if ((local.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
- && !get_symlink_p ())
- buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
-
- if (!(buf->st_mode & S_IFMT))
- buf->st_mode |= S_IFREG;
- }
- else
- {
- buf->st_mode |= STD_RBITS;
-
- if (!(local.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
- buf->st_mode |= STD_WBITS;
- /* | S_IWGRP | S_IWOTH; we don't give write to group etc */
-
- if (buf->st_mode & S_IFDIR)
- buf->st_mode |= S_IFDIR | STD_XBITS;
- else if (buf->st_mode & S_IFMT)
- /* nothing */;
- else if (get_socket_p ())
- buf->st_mode |= S_IFSOCK;
- else
- switch (GetFileType (get_handle ()))
- {
- case FILE_TYPE_CHAR:
- case FILE_TYPE_UNKNOWN:
- buf->st_mode |= S_IFCHR;
- break;
- case FILE_TYPE_DISK:
- buf->st_mode |= S_IFREG;
- if (!dont_care_if_execable () && !get_execable_p ())
- {
- DWORD cur, done;
- char magic[3];
-
- /* First retrieve current position, set to beginning
- of file if not already there. */
- cur = SetFilePointer (get_handle(), 0, NULL, FILE_CURRENT);
- if (cur != INVALID_SET_FILE_POINTER &&
- (!cur ||
- SetFilePointer (get_handle(), 0, NULL, FILE_BEGIN)
- != INVALID_SET_FILE_POINTER))
- {
- /* FIXME should we use /etc/magic ? */
- magic[0] = magic[1] = magic[2] = '\0';
- if (ReadFile (get_handle (), magic, 3, &done, NULL) &&
- has_exec_chars (magic, done))
- set_execable_p ();
- SetFilePointer (get_handle(), cur, NULL, FILE_BEGIN);
- }
- }
- if (get_execable_p ())
- buf->st_mode |= STD_XBITS;
- break;
- case FILE_TYPE_PIPE:
- buf->st_mode |= S_IFSOCK;
- break;
- }
- }
-
- syscall_printf ("0 = fstat (, %p) st_atime=%x st_size=%d, st_mode=%p, st_ino=%d, sizeof=%d",
- buf, buf->st_atime, buf->st_size, buf->st_mode,
- (int) buf->st_ino, sizeof (*buf));
-
+ time_as_timestruc_t (&buf->st_ctim);
+ buf->st_atim = buf->st_mtim = buf->st_ctim;
return 0;
}
@@ -1030,18 +980,18 @@ void
fhandler_base::init (HANDLE f, DWORD a, mode_t bin)
{
set_io_handle (f);
- set_r_binary (bin);
- set_w_binary (bin);
access = a;
a &= GENERIC_READ | GENERIC_WRITE;
+ int flags = 0;
if (a == GENERIC_READ)
- set_flags (O_RDONLY);
- if (a == GENERIC_WRITE)
- set_flags (O_WRONLY);
- if (a == (GENERIC_READ | GENERIC_WRITE))
- set_flags (O_RDWR);
+ flags = O_RDONLY;
+ else if (a == GENERIC_WRITE)
+ flags = O_WRONLY;
+ else if (a == (GENERIC_READ | GENERIC_WRITE))
+ flags = O_RDWR;
+ set_flags (flags | bin);
set_open_status ();
- debug_printf ("created new fhandler_base for handle %p", f);
+ debug_printf ("created new fhandler_base for handle %p, bin %d", f, get_r_binary ());
}
void
@@ -1056,16 +1006,19 @@ fhandler_base::dup (fhandler_base *child)
debug_printf ("in fhandler_base dup");
HANDLE nh;
- if (!DuplicateHandle (hMainProc, get_handle(), hMainProc, &nh, 0, TRUE,
- DUPLICATE_SAME_ACCESS))
+ if (!get_nohandle ())
{
- system_printf ("dup(%s) failed, handle %x, %E",
- get_name (), get_handle());
- __seterrno ();
- return -1;
- }
+ if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, &nh, 0, TRUE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("dup(%s) failed, handle %x, %E",
+ get_name (), get_handle ());
+ __seterrno ();
+ return -1;
+ }
- child->set_io_handle (nh);
+ child->set_io_handle (nh);
+ }
return 0;
}
@@ -1184,7 +1137,8 @@ fhandler_base::operator delete (void *p)
}
/* Normal I/O constructor */
-fhandler_base::fhandler_base (DWORD devtype, const char *name, int unit):
+fhandler_base::fhandler_base (DWORD devtype, int unit):
+ status (devtype),
access (0),
io_handle (NULL),
namehash (0),
@@ -1198,281 +1152,26 @@ fhandler_base::fhandler_base (DWORD devtype, const char *name, int unit):
win32_path_name (NULL),
open_status (0)
{
- status = devtype;
- int bin = __fmode & O_TEXT ? 0 : 1;
- if (status != FH_DISK && status != FH_CONSOLE)
- {
- if (!get_r_binset ())
- set_r_binary (bin);
- if (!get_w_binset ())
- set_w_binary (bin);
- }
}
/* Normal I/O destructor */
fhandler_base::~fhandler_base (void)
{
if (unix_path_name != NULL)
- cfree (unix_path_name);
+ cfree ((void *) unix_path_name);
if (win32_path_name != NULL)
- cfree (win32_path_name);
+ cfree ((void *) win32_path_name);
if (rabuf)
free (rabuf);
unix_path_name = win32_path_name = NULL;
}
/**********************************************************************/
-/* fhandler_disk_file */
-
-fhandler_disk_file::fhandler_disk_file (const char *name) :
- fhandler_base (FH_DISK, name)
-{
- set_cb (sizeof *this);
-}
-
-int
-fhandler_disk_file::open (const char *path, int flags, mode_t mode)
-{
- syscall_printf ("(%s, %p)", path, flags);
-
- /* O_NOSYMLINK is an internal flag for implementing lstat, nothing more. */
- path_conv real_path (path, (flags & O_NOSYMLINK) ?
- PC_SYM_NOFOLLOW : PC_SYM_FOLLOW);
-
- if (real_path.error &&
- (flags & O_NOSYMLINK || real_path.error != ENOENT
- || !(flags & O_CREAT) || real_path.case_clash))
- {
- set_errno (flags & O_CREAT && real_path.case_clash ? ECASECLASH
- : real_path.error);
- syscall_printf ("0 = fhandler_disk_file::open (%s, %p)", path, flags);
- return 0;
- }
-
- set_name (path, real_path.get_win32 ());
- return open (real_path, flags, mode);
-}
-
-int
-fhandler_disk_file::open (path_conv& real_path, int flags, mode_t mode)
-{
- if (real_path.isbinary ())
- {
- set_r_binary (1);
- set_w_binary (1);
- }
-
- set_has_acls (real_path.has_acls ());
- set_isremote (real_path.isremote ());
-
- if (real_path.isdir ())
- flags |= O_DIROPEN;
-
- int res = this->fhandler_base::open (flags, mode);
-
- if (!res)
- goto out;
-
- /* This is for file systems known for having a buggy CreateFile call
- which might return a valid HANDLE without having actually opened
- the file.
- The only known file system to date is the SUN NFS Solstice Client 3.1
- which returns a valid handle when trying to open a file in a nonexistent
- directory. */
- if (real_path.has_buggy_open ()
- && GetFileAttributes (win32_path_name) == (DWORD) -1)
- {
- debug_printf ("Buggy open detected.");
- close ();
- set_errno (ENOENT);
- return 0;
- }
-
- if (flags & O_APPEND)
- SetFilePointer (get_handle(), 0, 0, FILE_END);
-
- set_symlink_p (real_path.issymlink ());
- set_execable_p (real_path.exec_state ());
- set_socket_p (real_path.issocket ());
-
-out:
- syscall_printf ("%d = fhandler_disk_file::open (%s, %p)", res,
- get_win32_name (), flags);
- return res;
-}
-
-int
-fhandler_disk_file::close ()
-{
- int res = this->fhandler_base::close ();
- if (!res)
- cygwin_shared->delqueue.process_queue ();
- return res;
-}
-
-/*
- * FIXME !!!
- * The correct way to do this to get POSIX locking
- * semantics is to keep a linked list of posix lock
- * requests and map them into Win32 locks. The problem
- * is that Win32 does not deal correctly with overlapping
- * lock requests. Also another pain is that Win95 doesn't do
- * non-blocking or non exclusive locks at all. For '95 just
- * convert all lock requests into blocking,exclusive locks.
- * This shouldn't break many apps but denying all locking
- * would.
- * For now just convert to Win32 locks and hope for the best.
- */
-
-int
-fhandler_disk_file::lock (int cmd, struct flock *fl)
-{
- int win32_start;
- int win32_len;
- DWORD win32_upper;
- DWORD startpos;
-
- /*
- * We don't do getlck calls yet.
- */
-
- if (cmd == F_GETLK)
- {
- set_errno (ENOSYS);
- return -1;
- }
-
- /*
- * Calculate where in the file to start from,
- * then adjust this by fl->l_start.
- */
-
- switch (fl->l_whence)
- {
- case SEEK_SET:
- startpos = 0;
- break;
- case SEEK_CUR:
- if ((off_t) (startpos = lseek (0, SEEK_CUR)) == (off_t)-1)
- return -1;
- break;
- case SEEK_END:
- {
- BY_HANDLE_FILE_INFORMATION finfo;
- if (GetFileInformationByHandle (get_handle(), &finfo) == 0)
- {
- __seterrno ();
- return -1;
- }
- startpos = finfo.nFileSizeLow; /* Nowhere to keep high word */
- break;
- }
- default:
- set_errno (EINVAL);
- return -1;
- }
-
- /*
- * Now the fun starts. Adjust the start and length
- * fields until they make sense.
- */
-
- win32_start = startpos + fl->l_start;
- if (fl->l_len < 0)
- {
- win32_start -= fl->l_len;
- win32_len = -fl->l_len;
- }
- else
- win32_len = fl->l_len;
-
- if (win32_start < 0)
- {
- /* watch the signs! */
- win32_len -= -win32_start;
- if (win32_len <= 0)
- {
- /* Failure ! */
- set_errno (EINVAL);
- return -1;
- }
- win32_start = 0;
- }
-
- /*
- * Special case if len == 0 for POSIX means lock
- * to the end of the entire file (and all future extensions).
- */
- if (win32_len == 0)
- {
- win32_len = 0xffffffff;
- win32_upper = wincap.lock_file_highword ();
- }
- else
- win32_upper = 0;
-
- BOOL res;
-
- if (wincap.has_lock_file_ex ())
- {
- DWORD lock_flags = (cmd == F_SETLK) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
- lock_flags |= (fl->l_type == F_WRLCK) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
-
- OVERLAPPED ov;
-
- ov.Internal = 0;
- ov.InternalHigh = 0;
- ov.Offset = (DWORD)win32_start;
- ov.OffsetHigh = 0;
- ov.hEvent = (HANDLE) 0;
-
- if (fl->l_type == F_UNLCK)
- {
- res = UnlockFileEx (get_handle (), 0, (DWORD)win32_len, win32_upper, &ov);
- }
- else
- {
- res = LockFileEx (get_handle (), lock_flags, 0, (DWORD)win32_len,
- win32_upper, &ov);
- /* Deal with the fail immediately case. */
- /*
- * FIXME !! I think this is the right error to check for
- * but I must admit I haven't checked....
- */
- if ((res == 0) && (lock_flags & LOCKFILE_FAIL_IMMEDIATELY) &&
- (GetLastError () == ERROR_LOCK_FAILED))
- {
- set_errno (EAGAIN);
- return -1;
- }
- }
- }
- else
- {
- /* Windows 95 -- use primitive lock call */
- if (fl->l_type == F_UNLCK)
- res = UnlockFile (get_handle (), (DWORD)win32_start, 0, (DWORD)win32_len,
- win32_upper);
- else
- res = LockFile (get_handle (), (DWORD)win32_start, 0, (DWORD)win32_len, win32_upper);
- }
-
- if (res == 0)
- {
- __seterrno ();
- return -1;
- }
-
- return 0;
-}
-
-/**********************************************************************/
/* /dev/null */
-fhandler_dev_null::fhandler_dev_null (const char *name) :
- fhandler_base (FH_NULL, name)
+fhandler_dev_null::fhandler_dev_null () :
+ fhandler_base (FH_NULL)
{
- set_cb (sizeof *this);
}
void
@@ -1484,6 +1183,9 @@ fhandler_dev_null::dump (void)
void
fhandler_base::set_inheritance (HANDLE &h, int not_inheriting)
{
+#ifdef DEBUGGING_AND_FDS_PROTECTED
+ HANDLE oh = h;
+#endif
/* Note that we could use SetHandleInformation here but it is not available
on all platforms. Test cases seem to indicate that using DuplicateHandle
in this fashion does not actually close the original handle, which is
@@ -1492,25 +1194,33 @@ fhandler_base::set_inheritance (HANDLE &h, int not_inheriting)
if (!DuplicateHandle (hMainProc, h, hMainProc, &h, 0, !not_inheriting,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
debug_printf ("DuplicateHandle failed, %E");
-#ifdef DEBUGGING
- setclexec_pid (h, not_inheriting);
+#ifdef DEBUGGING_AND_FDS_PROTECTED
+ if (h)
+ setclexec (oh, h, not_inheriting);
#endif
}
void
fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name)
{
- if (!get_close_on_exec ())
+ if (/* !is_socket () && */ !get_close_on_exec ())
debug_printf ("handle %p already opened", h);
else if (!DuplicateHandle (parent, h, hMainProc, &h, 0, !get_close_on_exec (),
- DUPLICATE_SAME_ACCESS))
+ DUPLICATE_SAME_ACCESS))
system_printf ("%s - %E, handle %s<%p>", get_name (), name, h);
+#ifdef DEBUGGING_AND_FDS_PROTECTED
+ else if (get_close_on_exec ())
+ ProtectHandle (h); /* would have to be fancier than this */
+ else
+ /* ProtectHandleINH (h) */; /* Should already be protected */
+#endif
}
void
fhandler_base::set_close_on_exec (int val)
{
- set_inheritance (io_handle, val);
+ if (!get_nohandle ())
+ set_inheritance (io_handle, val);
set_close_on_exec_flag (val);
debug_printf ("set close_on_exec for %s to %d", get_name (), val);
}
@@ -1519,10 +1229,11 @@ void
fhandler_base::fixup_after_fork (HANDLE parent)
{
debug_printf ("inheriting '%s' from parent", get_name ());
- fork_fixup (parent, io_handle, "io_handle");
+ if (!get_nohandle ())
+ fork_fixup (parent, io_handle, "io_handle");
}
-int
+bool
fhandler_base::is_nonblocking ()
{
return (openflags & O_NONBLOCK_MASK) != 0;
@@ -1535,3 +1246,45 @@ fhandler_base::set_nonblocking (int yes)
int new_flags = yes ? (!current ? O_NONBLOCK : current) : 0;
openflags = (openflags & ~O_NONBLOCK_MASK) | new_flags;
}
+
+DIR *
+fhandler_base::opendir (path_conv&)
+{
+ set_errno (ENOTDIR);
+ return NULL;
+}
+
+struct dirent *
+fhandler_base::readdir (DIR *)
+{
+ set_errno (ENOTDIR);
+ return NULL;
+}
+
+__off64_t
+fhandler_base::telldir (DIR *)
+{
+ set_errno (ENOTDIR);
+ return -1;
+}
+
+void
+fhandler_base::seekdir (DIR *, __off64_t)
+{
+ set_errno (ENOTDIR);
+ return;
+}
+
+void
+fhandler_base::rewinddir (DIR *)
+{
+ set_errno (ENOTDIR);
+ return;
+}
+
+int
+fhandler_base::closedir (DIR *)
+{
+ set_errno (ENOTDIR);
+ return -1;
+}
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 753508266..6b80ff22d 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1,6 +1,6 @@
/* fhandler.h
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -12,41 +12,7 @@ details. */
#define _FHANDLER_H_
#include <sys/ioctl.h>
-
-/* Classes
-
- Code is located in fhandler.cc unless another file name is given.
-
- fhandler_base normal I/O
-
- fhandler_disk_file
- fhandler_serial Adds vmin and vtime.
- fhandler_dev_null Not really I/O
- fhandler_dev_zero Faked
-
- fhandler_dev_raw (fhandler_raw.cc)
- fhandler_dev_floppy (fhandler_floppy.cc)
- fhandler_dev_tape (fhandler_tape.cc)
-
- fhandler_pipe
- fhandler_socket (fhandler_socket.cc)
-
- fhandler_tty_slave (tty.cc)
- fhandler_pty_master (tty.cc)
- fhandler_tty_master (tty.cc)
-
- fhandler_console Out with ansi control. (console.cc)
-
- fhandler_windows Windows messages I/O (fhandler_windows.cc)
-
- fhandler_dev_random /dev/[u]random implementation (fhandler_random.cc)
-
- fhandler_dev_mem /dev/mem implementation (fhandler_mem.cc)
-
- fhandler_dev_clipboard /dev/clipboard implementation (fhandler_clipboard.cc)
-
- fhandler_proc Interesting possibility, not implemented yet
-*/
+#include <fcntl.h>
enum
{
@@ -65,7 +31,7 @@ enum
FH_W95LSBUG = 0x00400000, /* set when lseek is called as a flag that
* _write should check if we've moved beyond
* EOF, zero filling if so. */
- FH_UNUSED = 0x00800000, /* currently unused. */
+ FH_NOHANDLE = 0x00800000, /* No handle associated with fhandler. */
FH_NOEINTR = 0x01000000, /* Set if I/O should be uninterruptible. */
FH_FFIXUP = 0x02000000, /* Set if need to fixup after fork. */
FH_LOCAL = 0x04000000, /* File is unix domain socket */
@@ -102,10 +68,14 @@ enum
FH_ZERO = 0x00000014, /* is the zero device */
FH_RANDOM = 0x00000015, /* is a random device */
FH_MEM = 0x00000016, /* is a mem device */
- FH_CLIPBOARD = 0x00000017, /* is a clipbaord device */
+ FH_CLIPBOARD = 0x00000017, /* is a clipboard device */
FH_OSS_DSP = 0x00000018, /* is a dsp audio device */
+ FH_CYGDRIVE= 0x00000019, /* /cygdrive/x */
+ FH_PROC = 0x0000001a, /* /proc */
+ FH_REGISTRY =0x0000001b, /* /proc/registry */
+ FH_PROCESS = 0x0000001c, /* /proc/<n> */
- FH_NDEV = 0x00000019, /* Maximum number of devices */
+ FH_NDEV = 0x0000001d, /* Maximum number of devices */
FH_DEVMASK = 0x00000fff, /* devices live here */
FH_BAD = 0xffffffff
};
@@ -124,20 +94,29 @@ enum
/* newlib used to define O_NDELAY differently from O_NONBLOCK. Now it
properly defines both to be the same. Unfortunately, we have to
- behave properly the old version, too, to accomodate older executables. */
+ behave properly the old version, too, to accommodate older executables. */
#define OLD_O_NDELAY (CYGWIN_VERSION_CHECK_FOR_OLD_O_NONBLOCK ? 4 : 0)
/* Care for the old O_NDELAY flag. If one of the flags is set,
both flags are set. */
#define O_NONBLOCK_MASK (O_NONBLOCK | OLD_O_NDELAY)
+#define UNCONNECTED 0
+#define CONNECT_PENDING 1
+#define CONNECTED 2
+
extern const char *windows_device_names[];
extern struct __cygwin_perfile *perfile_table;
#define __fmode (*(user_data->fmode_ptr))
+extern const char proc[];
+extern const int proc_len;
class select_record;
class path_conv;
class fhandler_disk_file;
+typedef struct __DIR DIR;
+struct dirent;
+struct iovec;
enum bg_check_types
{
@@ -150,24 +129,22 @@ enum bg_check_types
enum executable_states
{
is_executable,
- not_executable,
dont_care_if_executable,
+ not_executable = dont_care_if_executable,
dont_know_if_executable
};
class fhandler_base
{
-protected:
+ protected:
DWORD status;
-public:
- int cb;
-private:
+ private:
int access;
HANDLE io_handle;
unsigned long namehash; /* hashed filename, used as inode num */
-protected:
+ protected:
/* Full unix path name of this file */
/* File open flags from open () and fcntl () calls */
int openflags;
@@ -178,23 +155,20 @@ protected:
size_t raixput;
size_t rabuflen;
- char *unix_path_name;
- char *win32_path_name;
+ const char *unix_path_name;
+ const char *win32_path_name;
DWORD open_status;
-public:
- void set_name (const char * unix_path, const char * win32_path = NULL,
- int unit = 0);
+ public:
+ void set_name (const char * unix_path, const char *win32_path = NULL, int unit = 0);
- void reset_unix_path_name (const char *);
virtual fhandler_base& operator =(fhandler_base &x);
- fhandler_base (DWORD dev, const char *name = 0, int unit = 0);
+ fhandler_base (DWORD dev, int unit = 0);
virtual ~fhandler_base ();
/* Non-virtual simple accessor functions. */
void set_io_handle (HANDLE x) { io_handle = x; }
- void set_cb (size_t size) { cb = size; }
DWORD get_device () { return status & FH_DEVMASK; }
virtual int get_unit () { return 0; }
virtual BOOL is_slow () { return get_device () < FH_SLOW; }
@@ -202,40 +176,44 @@ public:
int get_access () { return access; }
void set_access (int x) { access = x; }
- int get_async () { return FHISSETF (ASYNC); }
+ bool get_async () { return FHISSETF (ASYNC); }
void set_async (int x) { FHCONDSETF (x, ASYNC); }
int get_flags () { return openflags; }
- void set_flags (int x) { openflags = x; }
+ void set_flags (int x, int supplied_bin = 0);
- int is_nonblocking ();
+ bool is_nonblocking ();
void set_nonblocking (int yes);
- int get_w_binary () { return FHISSETF (WBINARY); }
- int get_r_binary () { return FHISSETF (RBINARY); }
+ bool get_w_binary () { return FHISSETF (WBINSET) ? FHISSETF (WBINARY) : 1; }
+ bool get_r_binary () { return FHISSETF (RBINSET) ? FHISSETF (RBINARY) : 1; }
- int get_w_binset () { return FHISSETF (WBINSET); }
- int get_r_binset () { return FHISSETF (RBINSET); }
+ bool get_w_binset () { return FHISSETF (WBINSET); }
+ bool get_r_binset () { return FHISSETF (RBINSET); }
void set_w_binary (int b) { FHCONDSETF (b, WBINARY); FHSETF (WBINSET); }
void set_r_binary (int b) { FHCONDSETF (b, RBINARY); FHSETF (RBINSET); }
void clear_w_binary () {FHCLEARF (WBINARY); FHCLEARF (WBINSET); }
void clear_r_binary () {FHCLEARF (RBINARY); FHCLEARF (RBINSET); }
+
+ bool get_nohandle () { return FHISSETF (NOHANDLE); }
+ void set_nohandle (int x) { FHCONDSETF (x, NOHANDLE); }
+
void set_open_status () {open_status = status;}
DWORD get_open_status () {return open_status;}
void reset_to_open_binmode ()
{
- status = status & ~(FH_WBINARY | FH_WBINSET | FH_RBINARY | FH_RBINSET);
- status = status | ((FH_WBINARY | FH_WBINSET | FH_RBINARY | FH_RBINSET)
- & open_status);
+ set_flags ((get_flags () & ~(O_TEXT | O_BINARY))
+ | ((open_status & (FH_WBINARY | FH_RBINARY)
+ ? O_BINARY : O_TEXT)));
}
int get_default_fmode (int flags);
- int get_r_no_interrupt () { return FHISSETF (NOEINTR); }
+ bool get_r_no_interrupt () { return FHISSETF (NOEINTR); }
void set_r_no_interrupt (int b) { FHCONDSETF (b, NOEINTR); }
- int get_close_on_exec () { return FHISSETF (CLOEXEC); }
+ bool get_close_on_exec () { return FHISSETF (CLOEXEC); }
int set_close_on_exec_flag (int b) { return FHCONDSETF (b, CLOEXEC); }
LPSECURITY_ATTRIBUTES get_inheritance (bool all = 0)
@@ -247,9 +225,9 @@ public:
}
void set_check_win95_lseek_bug (int b = 1) { FHCONDSETF (b, W95LSBUG); }
- int get_check_win95_lseek_bug () { return FHISSETF (W95LSBUG); }
+ bool get_check_win95_lseek_bug () { return FHISSETF (W95LSBUG); }
- int get_need_fork_fixup () { return FHISSETF (FFIXUP); }
+ bool get_need_fork_fixup () { return FHISSETF (FFIXUP); }
void set_need_fork_fixup () { FHSETF (FFIXUP); }
virtual void set_close_on_exec (int val);
@@ -258,31 +236,32 @@ public:
virtual void fixup_after_fork (HANDLE);
virtual void fixup_after_exec (HANDLE) {}
- int get_symlink_p () { return FHISSETF (SYMLINK); }
+ bool get_symlink_p () { return FHISSETF (SYMLINK); }
void set_symlink_p (int val) { FHCONDSETF (val, SYMLINK); }
void set_symlink_p () { FHSETF (SYMLINK); }
- int get_socket_p () { return FHISSETF (LOCAL); }
+ bool get_socket_p () { return FHISSETF (LOCAL); }
void set_socket_p (int val) { FHCONDSETF (val, LOCAL); }
void set_socket_p () { FHSETF (LOCAL); }
- int get_execable_p () { return FHISSETF (EXECABL); }
+ bool get_execable_p () { return FHISSETF (EXECABL); }
void set_execable_p (executable_states val)
{
FHCONDSETF (val == is_executable, EXECABL);
FHCONDSETF (val == dont_care_if_executable, DCEXEC);
}
void set_execable_p () { FHSETF (EXECABL); }
- int dont_care_if_execable () { return FHISSETF (DCEXEC); }
+ bool dont_care_if_execable () { return FHISSETF (DCEXEC); }
+ bool exec_state_isknown () { return FHISSETF (DCEXEC) || FHISSETF (EXECABL); }
- int get_append_p () { return FHISSETF (APPEND); }
+ bool get_append_p () { return FHISSETF (APPEND); }
void set_append_p (int val) { FHCONDSETF (val, APPEND); }
void set_append_p () { FHSETF (APPEND); }
- int get_query_open () { return FHISSETF (QUERYOPEN); }
- void set_query_open (int val) { FHCONDSETF (val, QUERYOPEN); }
+ bool get_query_open () { return FHISSETF (QUERYOPEN); }
+ void set_query_open (bool val) { FHCONDSETF (val, QUERYOPEN); }
- int get_readahead_valid () { return raixget < ralen; }
+ bool get_readahead_valid () { return raixget < ralen; }
int puts_readahead (const char *s, size_t len = (size_t) -1);
int put_readahead (char value);
@@ -295,10 +274,10 @@ public:
int get_readahead_into_buffer (char *buf, size_t buflen);
- int has_acls () { return FHISSETF (HASACLS); }
+ bool has_acls () { return FHISSETF (HASACLS); }
void set_has_acls (int val) { FHCONDSETF (val, HASACLS); }
- int isremote () { return FHISSETF (ISREMOTE); }
+ bool isremote () { return FHISSETF (ISREMOTE); }
void set_isremote (int val) { FHCONDSETF (val, ISREMOTE); }
const char *get_name () { return unix_path_name; }
@@ -311,27 +290,23 @@ public:
/* fixup fd possibly non-inherited handles after fork */
void fork_fixup (HANDLE parent, HANDLE &h, const char *name);
- /* Potentially overridden virtual functions. */
- virtual int open (const char *, int flags, mode_t mode = 0)
- {
- return open (flags, mode);
- }
- virtual int open (path_conv& real_path, int flags, mode_t mode);
- virtual int open (int flags, mode_t mode = 0);
+ virtual int open (path_conv *real_path, int flags, mode_t mode = 0);
virtual int close ();
- virtual int fstat (struct stat *buf) { return stat_dev (get_device (), get_unit (), get_namehash (), buf); }
+ virtual int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
virtual int ioctl (unsigned int cmd, void *);
virtual int fcntl (int cmd, void *);
virtual char const * ttyname () { return get_name(); }
- virtual int read (void *ptr, size_t len);
+ virtual int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
virtual int write (const void *ptr, size_t len);
- virtual off_t lseek (off_t offset, int whence);
+ virtual ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ virtual __off64_t lseek (__off64_t offset, int whence);
virtual int lock (int, struct flock *);
virtual void dump ();
virtual int dup (fhandler_base *child);
virtual HANDLE mmap (caddr_t *addr, size_t len, DWORD access,
- int flags, off_t off);
+ int flags, __off64_t off);
virtual int munmap (HANDLE h, caddr_t addr, size_t len);
virtual int msync (HANDLE h, caddr_t addr, size_t len, int flags);
virtual BOOL fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
@@ -368,7 +343,7 @@ public:
virtual select_record *select_read (select_record *s);
virtual select_record *select_write (select_record *s);
virtual select_record *select_except (select_record *s);
- virtual int ready_for_read (int fd, DWORD howlong, int ignra);
+ virtual int ready_for_read (int fd, DWORD howlong);
virtual const char * get_native_name ()
{
return windows_device_names[FHDEVN (status)];
@@ -380,18 +355,29 @@ public:
rabuf = NULL;
}
void operator delete (void *);
+ virtual HANDLE get_guard () const {return NULL;}
+ virtual void set_eof () {}
+ virtual DIR *opendir (path_conv& pc);
+ virtual dirent *readdir (DIR *);
+ virtual __off64_t telldir (DIR *);
+ virtual void seekdir (DIR *, __off64_t);
+ virtual void rewinddir (DIR *);
+ virtual int closedir (DIR *);
};
class fhandler_socket: public fhandler_base
{
-private:
+ private:
int addr_family;
+ int type;
int connect_secret [4];
HANDLE secret_event;
struct _WSAPROTOCOL_INFOA *prot_info_ptr;
+ char *sun_path;
+ int had_connect_or_listen;
-public:
- fhandler_socket (const char *name = 0);
+ public:
+ fhandler_socket ();
~fhandler_socket ();
int get_socket () { return (int) get_handle(); }
fhandler_socket * is_socket () { return this; }
@@ -402,11 +388,32 @@ public:
void set_shutdown_read () {FHSETF (SHUTRD);}
void set_shutdown_write () {FHSETF (SHUTWR);}
- int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
+ bool is_unconnected () const {return had_connect_or_listen == UNCONNECTED;}
+ bool is_connect_pending () const {return had_connect_or_listen == CONNECT_PENDING;}
+ bool is_connected () const {return had_connect_or_listen == CONNECTED;}
+ void set_connect_state (int newstate) { had_connect_or_listen = newstate; }
+
+ int bind (const struct sockaddr *name, int namelen);
+ int connect (const struct sockaddr *name, int namelen);
+ int listen (int backlog);
+ int accept (struct sockaddr *peer, int *len);
+ int getsockname (struct sockaddr *name, int *namelen);
+ int getpeername (struct sockaddr *name, int *namelen);
+
+ ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ int recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen);
+ int recvmsg (struct msghdr *msg, int flags, ssize_t tot = -1);
+
+ ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ int sendto (const void *ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen);
+ int sendmsg (const struct msghdr *msg, int flags, ssize_t tot = -1);
+
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, void *);
- off_t lseek (off_t, int) { return 0; }
+ __off64_t lseek (__off64_t, int) { return 0; }
+ int shutdown (int how);
int close ();
void hclose (HANDLE) {close ();}
int dup (fhandler_base *child);
@@ -419,43 +426,49 @@ public:
select_record *select_read (select_record *s);
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
- int get_addr_family () {return addr_family;}
void set_addr_family (int af) {addr_family = af;}
+ int get_addr_family () {return addr_family;}
+ void set_socket_type (int st) { type = st;}
+ int get_socket_type () {return type;}
+ void set_sun_path (const char *path);
+ char *get_sun_path () {return sun_path;}
void set_connect_secret ();
void get_connect_secret (char*);
HANDLE create_secret_event (int *secret = NULL);
int check_peer_secret_event (struct sockaddr_in *peer, int *secret = NULL);
void signal_secret_event ();
void close_secret_event ();
+ int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
};
class fhandler_pipe: public fhandler_base
{
HANDLE guard;
+ bool broken_pipe;
HANDLE writepipe_exists;
DWORD orig_pid;
unsigned id;
-public:
- fhandler_pipe (const char *name = 0, DWORD devtype = FH_PIPE);
- off_t lseek (off_t offset, int whence);
+ public:
+ fhandler_pipe (DWORD devtype);
+ __off64_t lseek (__off64_t offset, int whence);
select_record *select_read (select_record *s);
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
void set_close_on_exec (int val);
- int read (void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
int close ();
void create_guard (SECURITY_ATTRIBUTES *sa) {guard = CreateMutex (sa, FALSE, NULL);}
int dup (fhandler_base *child);
void fixup_after_fork (HANDLE);
bool hit_eof ();
+ void set_eof () {broken_pipe = true;}
friend int make_pipe (int fildes[2], unsigned int psize, int mode);
+ HANDLE get_guard () const {return guard;}
};
class fhandler_dev_raw: public fhandler_base
{
-protected:
+ protected:
char *devbuf;
size_t devbufsiz;
size_t devbufstart;
@@ -476,19 +489,19 @@ protected:
/* returns not null, if `win_error' determines an end of file condition */
virtual int is_eof(int win_error) = 0;
- fhandler_dev_raw (DWORD dev, const char *name, int unit);
+ fhandler_dev_raw (DWORD dev, int unit);
-public:
+ public:
~fhandler_dev_raw (void);
- int open (const char *path, int flags, mode_t mode = 0);
+ int get_unit () { return unit; }
+
+ int open (path_conv *, int flags, mode_t mode = 0);
int close (void);
int raw_read (void *ptr, size_t ulen);
int raw_write (const void *ptr, size_t ulen);
- int fstat (struct stat *buf);
-
int dup (fhandler_base *child);
int ioctl (unsigned int cmd, void *buf);
@@ -499,47 +512,48 @@ public:
class fhandler_dev_floppy: public fhandler_dev_raw
{
-protected:
+ protected:
virtual int is_eom (int win_error);
virtual int is_eof (int win_error);
-public:
- fhandler_dev_floppy (const char *name, int unit);
+ public:
+ fhandler_dev_floppy (int unit);
- virtual int open (const char *path, int flags, mode_t mode = 0);
+ virtual int open (path_conv *, int flags, mode_t mode = 0);
virtual int close (void);
- virtual off_t lseek (off_t offset, int whence);
+ virtual __off64_t lseek (__off64_t offset, int whence);
virtual int ioctl (unsigned int cmd, void *buf);
};
class fhandler_dev_tape: public fhandler_dev_raw
{
- int norewind;
int lasterr;
-protected:
+ bool is_rewind_device () { return get_unit () < 128; }
+
+ protected:
virtual void clear (void);
virtual int is_eom (int win_error);
virtual int is_eof (int win_error);
-public:
- fhandler_dev_tape (const char *name, int unit);
+ public:
+ fhandler_dev_tape (int unit);
- virtual int open (const char *path, int flags, mode_t mode = 0);
+ virtual int open (path_conv *, int flags, mode_t mode = 0);
virtual int close (void);
- virtual off_t lseek (off_t offset, int whence);
+ virtual __off64_t lseek (__off64_t offset, int whence);
- virtual int fstat (struct stat *buf);
+ virtual int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
virtual int dup (fhandler_base *child);
virtual int ioctl (unsigned int cmd, void *buf);
-private:
+ private:
int tape_write_marks (int marktype, DWORD len);
int tape_get_pos (unsigned long *ret);
int tape_set_pos (int mode, long count, BOOLEAN sfm_func = FALSE);
@@ -556,38 +570,77 @@ private:
class fhandler_disk_file: public fhandler_base
{
-public:
- fhandler_disk_file (const char *name);
+ public:
+ fhandler_disk_file ();
+ fhandler_disk_file (DWORD devtype);
- int open (const char *path, int flags, mode_t mode = 0);
- int open (path_conv& real_path, int flags, mode_t mode);
+ int open (path_conv * real_path, int flags, mode_t mode);
int close ();
int lock (int, struct flock *);
BOOL is_device () { return FALSE; }
- int fstat (struct stat *buf);
-
- HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, off_t off);
+ int __stdcall fstat (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ int __stdcall fstat_helper (struct __stat64 *buf, path_conv *pc,
+ FILETIME ftCreateionTime,
+ FILETIME ftLastAccessTime,
+ FILETIME ftLastWriteTime,
+ DWORD nFileSizeHigh,
+ DWORD nFileSizeLow,
+ DWORD nFileIndexHigh = 0,
+ DWORD nFileIndexLow = 0,
+ DWORD nNumberOfLinks = 1)
+ __attribute__ ((regparm (3)));
+ int __stdcall fstat_by_handle (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ int __stdcall fstat_by_name (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
+
+ HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, __off64_t off);
int munmap (HANDLE h, caddr_t addr, size_t len);
int msync (HANDLE h, caddr_t addr, size_t len, int flags);
BOOL fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
DWORD size, void *address);
+ DIR *opendir (path_conv& pc);
+ struct dirent *readdir (DIR *);
+ __off64_t telldir (DIR *);
+ void seekdir (DIR *, __off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+};
+
+class fhandler_cygdrive: public fhandler_disk_file
+{
+ int unit;
+ int ndrives;
+ const char *pdrive;
+ void set_drives ();
+ public:
+ bool iscygdrive_root () const { return !unit; }
+ fhandler_cygdrive (int unit);
+ DIR *opendir (path_conv& pc);
+ struct dirent *readdir (DIR *);
+ __off64_t telldir (DIR *);
+ void seekdir (DIR *, __off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+ int __stdcall fstat (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
};
class fhandler_serial: public fhandler_base
{
-private:
+ private:
unsigned int vmin_; /* from termios */
unsigned int vtime_; /* from termios */
pid_t pgrp_;
+ int rts; /* for Windows 9x purposes only */
+ int dtr; /* for Windows 9x purposes only */
-public:
+ public:
int overlapped_armed;
OVERLAPPED io_status;
+ DWORD ev;
/* Constructor */
- fhandler_serial (const char *name, DWORD devtype = FH_SERIAL, int unit = 0);
+ fhandler_serial (int unit);
- int open (const char *path, int flags, mode_t mode);
+ int open (path_conv *, int flags, mode_t mode);
int close ();
void init (HANDLE h, DWORD a, mode_t flags);
void overlapped_setup ();
@@ -597,9 +650,10 @@ public:
int tcsendbreak (int);
int tcdrain ();
int tcflow (int);
+ int ioctl (unsigned int cmd, void *);
int tcsetattr (int a, const struct termios *t);
int tcgetattr (struct termios *t);
- off_t lseek (off_t, int) { return 0; }
+ __off64_t lseek (__off64_t, int) { return 0; }
int tcflush (int);
void dump ();
int is_tty () { return 1; }
@@ -614,7 +668,6 @@ public:
select_record *select_read (select_record *s);
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
};
#define acquire_output_mutex(ms) \
@@ -627,14 +680,14 @@ class tty;
class tty_min;
class fhandler_termios: public fhandler_base
{
-protected:
+ protected:
HANDLE output_handle;
virtual void doecho (const void *, DWORD) {};
virtual int accept_input () {return 1;};
-public:
+ public:
tty_min *tc;
- fhandler_termios (DWORD dev, const char *name = 0, int unit = 0) :
- fhandler_base (dev, name, unit)
+ fhandler_termios (DWORD dev, int unit = 0) :
+ fhandler_base (dev, unit)
{
set_need_fork_fixup ();
}
@@ -651,6 +704,7 @@ public:
void fixup_after_fork (HANDLE);
void fixup_after_exec (HANDLE parent) { fixup_after_fork (parent); }
void echo_erase (int force = 0);
+ virtual __off64_t lseek (__off64_t, int);
};
enum ansi_intensity
@@ -674,7 +728,7 @@ enum ansi_intensity
/* This is a input and output console handle */
class fhandler_console: public fhandler_termios
{
-private:
+ private:
WORD default_color, underline_color, dim_color;
@@ -686,13 +740,13 @@ private:
int args_[MAXARGS];
int nargs_;
unsigned rarg;
- BOOL saw_question_mark;
+ bool saw_question_mark;
char my_title_buf [TITLESIZE + 1];
WORD current_win32_attr;
ansi_intensity intensity;
- BOOL underline, blink, reverse;
+ bool underline, blink, reverse;
WORD fg, bg;
/* saved cursor coordinates */
@@ -720,9 +774,9 @@ private:
DWORD dwLastButtonState;
int nModifiers;
- BOOL insert_mode;
- BOOL use_mouse;
- BOOL raw_win32_keyboard_mode;
+ bool insert_mode;
+ bool use_mouse;
+ bool raw_win32_keyboard_mode;
/* Output calls */
void set_default_attr ();
@@ -744,17 +798,17 @@ private:
int input_tcsetattr (int a, const struct termios *t);
void set_cursor_maybe ();
-public:
+ public:
- fhandler_console (const char *name);
+ fhandler_console ();
fhandler_console* is_console () { return this; }
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void doecho (const void *str, DWORD len) { (void) write (str, len); }
- int read (void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
int close ();
int tcflush (int);
@@ -771,19 +825,20 @@ public:
select_record *select_read (select_record *s);
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
void fixup_after_exec (HANDLE);
void set_close_on_exec (int val);
void fixup_after_fork (HANDLE parent);
void set_input_state ();
+ void send_winch_maybe ();
};
class fhandler_tty_common: public fhandler_termios
{
-public:
- fhandler_tty_common (DWORD dev, const char *name = 0, int unit = 0) :
- fhandler_termios (dev, name, unit),
- ttynum (unit)
+ public:
+ fhandler_tty_common (DWORD dev, int unit = 0)
+ : fhandler_termios (dev, unit), output_done_event (NULL),
+ ioctl_request_event (NULL), ioctl_done_event (NULL), output_mutex (NULL),
+ input_mutex (NULL), input_available_event (NULL), inuse (NULL), ttynum (unit)
{
// nothing to do
}
@@ -796,12 +851,11 @@ public:
HANDLE output_mutex, input_mutex;
HANDLE input_available_event;
HANDLE inuse; // used to indicate that a tty is in use
-
+ int ttynum; // Master tty num.
DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms);
void __release_output_mutex (const char *fn, int ln);
- int ttynum; // Master tty num.
virtual int dup (fhandler_base *child);
tty *get_ttyp () { return (tty *)tc; }
@@ -813,19 +867,18 @@ public:
select_record *select_read (select_record *s);
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
};
class fhandler_tty_slave: public fhandler_tty_common
{
-public:
+ public:
/* Constructor */
- fhandler_tty_slave (const char *name);
- fhandler_tty_slave (int, const char *name);
+ fhandler_tty_slave ();
+ fhandler_tty_slave (int);
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
void init (HANDLE, DWORD, mode_t);
int tcsetattr (int a, const struct termios *t);
@@ -833,28 +886,26 @@ public:
int tcflush (int);
int ioctl (unsigned int cmd, void *);
- off_t lseek (off_t, int) { return 0; }
+ __off64_t lseek (__off64_t, int) { return 0; }
select_record *select_read (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
-
int cygserver_attach_tty (HANDLE*, HANDLE*);
};
class fhandler_pty_master: public fhandler_tty_common
{
int pktmode; // non-zero if pty in a packet mode.
-public:
+ public:
int need_nl; // Next read should start with \n
/* Constructor */
- fhandler_pty_master (const char *name, DWORD devtype = FH_PTYM, int unit = -1);
+ fhandler_pty_master (DWORD devtype = FH_PTYM, int unit = -1);
int process_slave_output (char *buf, size_t len, int pktmode_on);
void doecho (const void *str, DWORD len);
int accept_input ();
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
int close ();
int tcsetattr (int a, const struct termios *t);
@@ -862,21 +913,22 @@ public:
int tcflush (int);
int ioctl (unsigned int cmd, void *);
- off_t lseek (off_t, int) { return 0; }
+ __off64_t lseek (__off64_t, int) { return 0; }
char *ptsname ();
void set_close_on_exec (int val);
bool hit_eof ();
};
+class cygthread;
class fhandler_tty_master: public fhandler_pty_master
{
-public:
+ public:
/* Constructor */
- fhandler_tty_master (const char *name, int unit);
fhandler_console *console; // device handler to perform real i/o.
- HANDLE hThread; // process_output thread handle.
+ cygthread *output_thread; // process_output thread
+ fhandler_tty_master (int unit);
int init (int);
int init_console ();
void fixup_after_fork (HANDLE parent);
@@ -885,8 +937,8 @@ public:
class fhandler_dev_null: public fhandler_base
{
-public:
- fhandler_dev_null (const char *name);
+ public:
+ fhandler_dev_null ();
void dump ();
select_record *select_read (select_record *s);
@@ -896,20 +948,19 @@ public:
class fhandler_dev_zero: public fhandler_base
{
-public:
- fhandler_dev_zero (const char *name);
- int open (const char *path, int flags, mode_t mode = 0);
+ public:
+ fhandler_dev_zero ();
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
- off_t lseek (off_t offset, int whence);
- int close (void);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
+ __off64_t lseek (__off64_t offset, int whence);
void dump ();
};
class fhandler_dev_random: public fhandler_base
{
-protected:
+ protected:
int unit;
HCRYPTPROV crypt_prov;
long pseudo;
@@ -918,13 +969,13 @@ protected:
int pseudo_write (const void *ptr, size_t len);
int pseudo_read (void *ptr, size_t len);
-public:
- fhandler_dev_random (const char *name, int unit);
+ public:
+ fhandler_dev_random (int unit);
int get_unit () { return unit; }
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
- off_t lseek (off_t offset, int whence);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
+ __off64_t lseek (__off64_t offset, int whence);
int close (void);
int dup (fhandler_base *child);
@@ -933,24 +984,24 @@ public:
class fhandler_dev_mem: public fhandler_base
{
-protected:
+ protected:
int unit;
DWORD mem_size;
- DWORD pos;
+ __off64_t pos;
-public:
- fhandler_dev_mem (const char *name, int unit);
+ public:
+ fhandler_dev_mem (int unit);
~fhandler_dev_mem (void);
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t ulen);
- int read (void *ptr, size_t ulen);
- off_t lseek (off_t offset, int whence);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
+ __off64_t lseek (__off64_t offset, int whence);
int close (void);
- int fstat (struct stat *buf);
+ int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
int dup (fhandler_base *child);
- HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, off_t off);
+ HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, __off64_t off);
int munmap (HANDLE h, caddr_t addr, size_t len);
int msync (HANDLE h, caddr_t addr, size_t len, int flags);
BOOL fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
@@ -961,39 +1012,39 @@ public:
class fhandler_dev_clipboard: public fhandler_base
{
-public:
- fhandler_dev_clipboard (const char *name);
+ public:
+ fhandler_dev_clipboard ();
int is_windows (void) { return 1; }
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
- off_t lseek (off_t offset, int whence);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
+ __off64_t lseek (__off64_t offset, int whence);
int close (void);
int dup (fhandler_base *child);
void dump ();
-private:
- off_t pos;
+ private:
+ __off64_t pos;
void *membuffer;
size_t msize;
- BOOL eof;
+ bool eof;
};
class fhandler_windows: public fhandler_base
{
-private:
+ private:
HWND hWnd_; // the window whose messages are to be retrieved by read() call
int method_; // write method (Post or Send)
-public:
- fhandler_windows (const char *name = 0);
+ public:
+ fhandler_windows ();
int is_windows (void) { return 1; }
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
int ioctl (unsigned int cmd, void *);
- off_t lseek (off_t, int) { return 0; }
+ __off64_t lseek (__off64_t, int) { return 0; }
int close (void) { return 0; }
void set_close_on_exec (int val);
@@ -1001,78 +1052,168 @@ public:
select_record *select_read (select_record *s);
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
- int ready_for_read (int fd, DWORD howlong, int ignra);
};
class fhandler_dev_dsp : public fhandler_base
{
-private:
+ private:
int audioformat_;
int audiofreq_;
int audiobits_;
int audiochannels_;
bool setupwav(const char *pData, int nBytes);
-public:
- fhandler_dev_dsp (const char *name = 0);
+ public:
+ fhandler_dev_dsp ();
~fhandler_dev_dsp();
- int open (const char *path, int flags, mode_t mode = 0);
+ int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
- int read (void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
int ioctl (unsigned int cmd, void *);
- off_t lseek (off_t, int);
+ __off64_t lseek (__off64_t, int);
int close (void);
int dup (fhandler_base * child);
void dump (void);
void fixup_after_exec (HANDLE);
};
-#if 0
-/* You can't do this */
+class fhandler_virtual : public fhandler_base
+{
+ protected:
+ char *filebuf;
+ size_t bufalloc, filesize;
+ __off64_t position;
+ int fileid; // unique within each class
+ public:
+
+ fhandler_virtual (DWORD devtype);
+ virtual ~fhandler_virtual();
+
+ virtual int exists();
+ DIR *opendir (path_conv& pc);
+ __off64_t telldir (DIR *);
+ void seekdir (DIR *, __off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+ int write (const void *ptr, size_t len);
+ int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
+ __off64_t lseek (__off64_t, int);
+ int dup (fhandler_base * child);
+ int open (path_conv *, int flags, mode_t mode = 0);
+ int close (void);
+ int __stdcall fstat (struct stat *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ virtual bool fill_filebuf ();
+};
+
+class fhandler_proc: public fhandler_virtual
+{
+ public:
+ fhandler_proc ();
+ fhandler_proc (DWORD devtype);
+ int exists();
+ struct dirent *readdir (DIR *);
+ static DWORD get_proc_fhandler(const char *path);
+
+ int open (path_conv *real_path, int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ bool fill_filebuf ();
+};
+
+class fhandler_registry: public fhandler_proc
+{
+ private:
+ char *value_name;
+ public:
+ fhandler_registry ();
+ int exists();
+ struct dirent *readdir (DIR *);
+ __off64_t telldir (DIR *);
+ void seekdir (DIR *, __off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+
+ int open (path_conv *real_path, int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ bool fill_filebuf ();
+ int close (void);
+};
+
+class pinfo;
+class fhandler_process: public fhandler_proc
+{
+ pid_t pid;
+ public:
+ fhandler_process ();
+ int exists();
+ struct dirent *readdir (DIR *);
+ int open (path_conv *real_path, int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ bool fill_filebuf ();
+};
+
typedef union
{
- fhandler_normal normal;
- fhandler_dev_null dev_null;
- fhandler bare;
- fhandler_serial tty;
+ char base[sizeof(fhandler_base)];
+ char console[sizeof(fhandler_console)];
+ char dev_clipboard[sizeof(fhandler_dev_clipboard)];
+ char dev_dsp[sizeof(fhandler_dev_dsp)];
+ char dev_floppy[sizeof(fhandler_dev_floppy)];
+ char dev_mem[sizeof(fhandler_dev_mem)];
+ char dev_null[sizeof(fhandler_dev_null)];
+ char dev_random[sizeof(fhandler_dev_random)];
+ char dev_raw[sizeof(fhandler_dev_raw)];
+ char dev_tape[sizeof(fhandler_dev_tape)];
+ char dev_zero[sizeof(fhandler_dev_zero)];
+ char disk_file[sizeof(fhandler_disk_file)];
+ char pipe[sizeof(fhandler_pipe)];
+ char proc[sizeof(fhandler_proc)];
+ char process[sizeof(fhandler_process)];
+ char pty_master[sizeof(fhandler_pty_master)];
+ char registry[sizeof(fhandler_registry)];
+ char serial[sizeof(fhandler_serial)];
+ char socket[sizeof(fhandler_socket)];
+ char termios[sizeof(fhandler_termios)];
+ char tty_common[sizeof(fhandler_tty_common)];
+ char tty_master[sizeof(fhandler_tty_master)];
+ char tty_slave[sizeof(fhandler_tty_slave)];
+ char windows[sizeof(fhandler_windows)];
} fhandler_union;
-#else
-#define fhandler_union fhandler_console
-#endif
+
struct select_record
{
int fd;
HANDLE h;
fhandler_base *fh;
- BOOL saw_error;
- BOOL windows_handle;
- BOOL read_ready, write_ready, except_ready;
- BOOL read_selected, write_selected, except_selected;
+ bool saw_error;
+ bool windows_handle;
+ bool read_ready, write_ready, except_ready;
+ bool read_selected, write_selected, except_selected;
+ bool except_on_write;
int (*startup) (select_record *me, class select_stuff *stuff);
- int (*poll) (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds);
+ int (*peek) (select_record *, bool);
int (*verify) (select_record *me, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds);
void (*cleanup) (select_record *me, class select_stuff *stuff);
struct select_record *next;
select_record (fhandler_base *in_fh = NULL) : fd (0), h (NULL),
- fh (in_fh), saw_error (0), windows_handle (0),
- read_ready (0), write_ready (0), except_ready (0),
- read_selected (0), write_selected (0), except_selected (0),
- startup (NULL), poll (NULL), verify (NULL), cleanup (NULL),
+ fh (in_fh), saw_error (false), windows_handle (false),
+ read_ready (false), write_ready (false), except_ready (false),
+ read_selected (false), write_selected (false),
+ except_selected (false), except_on_write (false),
+ startup (NULL), peek (NULL), verify (NULL), cleanup (NULL),
next (NULL) {}
};
class select_stuff
{
-public:
+ public:
~select_stuff ();
select_stuff (): always_ready (0), windows_used (0), start (0)
{
memset (device_specific, 0, sizeof (device_specific));
}
- BOOL always_ready, windows_used;
+ bool always_ready, windows_used;
select_record start;
void *device_specific[FH_NDEV];
diff --git a/winsup/cygwin/fhandler_clipboard.cc b/winsup/cygwin/fhandler_clipboard.cc
index 6a22855aa..ce14def20 100644
--- a/winsup/cygwin/fhandler_clipboard.cc
+++ b/winsup/cygwin/fhandler_clipboard.cc
@@ -1,6 +1,6 @@
/* fhandler_dev_clipboard: code to access /dev/clipboard
- Copyright 2000, 2001 Red Hat, Inc
+ Copyright 2000, 2001, 2002 Red Hat, Inc
Written by Charles Wilson (cwilson@ece.gatech.edu)
@@ -32,14 +32,10 @@ static const NO_COPY char *CYGWIN_NATIVE = "CYGWIN_NATIVE_CLIPBOARD";
/* this is MT safe because windows format id's are atomic */
static UINT cygnativeformat;
-fhandler_dev_clipboard::fhandler_dev_clipboard (const char *name):
-fhandler_base (FH_CLIPBOARD, name)
+fhandler_dev_clipboard::fhandler_dev_clipboard ()
+ : fhandler_base (FH_CLIPBOARD), pos (0), membuffer (NULL), msize (0),
+ eof (true)
{
- set_cb (sizeof *this);
- eof = true;
- pos = 0;
- membuffer = NULL;
- msize = 0;
/* FIXME: check for errors and loop until we can open the clipboard */
OpenClipboard (NULL);
cygnativeformat = RegisterClipboardFormat (CYGWIN_NATIVE);
@@ -56,7 +52,7 @@ fhandler_dev_clipboard::dup (fhandler_base * child)
{
fhandler_dev_clipboard *fhc = (fhandler_dev_clipboard *) child;
- if (!fhc->open (get_name (), get_flags (), 0))
+ if (!fhc->open (NULL, get_flags (), 0))
system_printf ("error opening clipboard, %E");
fhc->membuffer = membuffer;
@@ -67,9 +63,9 @@ fhandler_dev_clipboard::dup (fhandler_base * child)
}
int
-fhandler_dev_clipboard::open (const char *, int flags, mode_t)
+fhandler_dev_clipboard::open (path_conv *, int flags, mode_t)
{
- set_flags (flags);
+ set_flags (flags | O_TEXT);
eof = false;
pos = 0;
if (membuffer)
@@ -77,6 +73,7 @@ fhandler_dev_clipboard::open (const char *, int flags, mode_t)
membuffer = NULL;
if (!cygnativeformat)
cygnativeformat = RegisterClipboardFormat (CYGWIN_NATIVE);
+ set_nohandle (true);
set_open_status ();
return 1;
}
@@ -188,7 +185,7 @@ fhandler_dev_clipboard::write (const void *buf, size_t len)
}
}
-int
+int __stdcall
fhandler_dev_clipboard::read (void *ptr, size_t len)
{
HGLOBAL hglb;
@@ -250,8 +247,8 @@ fhandler_dev_clipboard::read (void *ptr, size_t len)
}
}
-off_t
-fhandler_dev_clipboard::lseek (off_t offset, int whence)
+__off64_t
+fhandler_dev_clipboard::lseek (__off64_t offset, int whence)
{
/* On reads we check this at read time, not seek time.
* On writes we use this to decide how to write - empty and write, or open, copy, empty
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 9dd98e7f8..2c48325fc 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -1,6 +1,6 @@
/* fhandler_console.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -12,13 +12,12 @@ details. */
#include <sys/termios.h>
#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <wingdi.h>
#include <winuser.h>
#include <wincon.h>
-#include <winnls.h> // MultiByteToWideChar () and friends
+#include <winnls.h>
#include <ctype.h>
#include <sys/cygwin.h>
#include "cygerrno.h"
@@ -27,23 +26,15 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "shared_info.h"
+#include "cygthread.h"
#define CONVERT_LIMIT 4096
-/* The codepages are resolved here instead of using CP_ACP and
- CP_OEMCP, so that they can later be compared for equality. */
-inline UINT
-cp_get_internal ()
-{
- return current_codepage == ansi_cp ? GetACP() : GetOEMCP();
-}
-
static BOOL
-cp_convert (UINT destcp, char * dest, UINT srccp, const char * src, DWORD size)
+cp_convert (UINT destcp, char *dest, UINT srccp, const char *src, DWORD size)
{
if (!size)
/* no action */;
@@ -70,13 +61,13 @@ cp_convert (UINT destcp, char * dest, UINT srccp, const char * src, DWORD size)
inline BOOL
con_to_str (char *d, const char *s, DWORD sz)
{
- return cp_convert (cp_get_internal (), d, GetConsoleCP (), s, sz);
+ return cp_convert (get_cp (), d, GetConsoleCP (), s, sz);
}
inline BOOL
str_to_con (char *d, const char *s, DWORD sz)
{
- return cp_convert (GetConsoleOutputCP (), d, cp_get_internal (), s, sz);
+ return cp_convert (GetConsoleOutputCP (), d, get_cp (), s, sz);
}
/*
@@ -104,10 +95,10 @@ get_tty_stuff (int flags = 0)
if (shared_console_info)
return shared_console_info;
- shared_console_info = (tty_min *) open_shared (NULL, cygheap->console_h,
+ shared_console_info = (tty_min *) open_shared (NULL, 0, cygheap->console_h,
sizeof (*shared_console_info),
NULL);
- ProtectHandle (cygheap->console_h);
+ ProtectHandleINH (cygheap->console_h);
if (!shared_console_info->ntty)
{
shared_console_info->setntty (TTY_CONSOLE);
@@ -144,11 +135,11 @@ tty_list::get_tty (int n)
int __stdcall
set_console_state_for_spawn ()
{
- HANDLE h = CreateFileA ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE,
- &sec_none_nih, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE h = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE,
+ &sec_none_nih, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ NULL);
- if (h == INVALID_HANDLE_VALUE || h == NULL)
+ if (h == INVALID_HANDLE_VALUE)
return 0;
if (shared_console_info != NULL)
@@ -156,13 +147,6 @@ set_console_state_for_spawn ()
# define tc shared_console_info /* ACK. Temporarily define for use in TTYSETF macro */
SetConsoleMode (h, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
TTYSETF (RSTCONS);
-#if 0
- char ch;
- DWORD n;
- /* NOTE -- This ReadFile is apparently necessary for correct functioning on
- Windows NT 4.0. Without this, the next ReadFile returns garbage. */
- (void) ReadFile (h, &ch, 0, &n, NULL);
-#endif
# undef tc
}
@@ -195,12 +179,20 @@ fhandler_console::set_cursor_maybe ()
}
}
-int
-fhandler_console::read (void *pv, size_t buflen)
+void
+fhandler_console::send_winch_maybe ()
{
- if (!buflen)
- return 0;
+ SHORT y = info.dwWinSize.Y;
+ SHORT x = info.dwWinSize.X;
+ fillin_info ();
+
+ if (y != info.dwWinSize.Y || x != info.dwWinSize.X)
+ tc->kill_pgrp (SIGWINCH);
+}
+int __stdcall
+fhandler_console::read (void *pv, size_t buflen)
+{
HANDLE h = get_io_handle ();
#define buf ((char *) pv)
@@ -218,7 +210,7 @@ fhandler_console::read (void *pv, size_t buflen)
char tmp[60];
w4[0] = h;
- if (iscygthread ())
+ if (cygthread::is ())
nwait = 1;
else
{
@@ -310,7 +302,7 @@ fhandler_console::read (void *pv, size_t buflen)
tmp[1] = ich;
/* Need this check since US code page seems to have a bug when
converting a CTRL-U. */
- if ((unsigned char)ich > 0x7f)
+ if ((unsigned char) ich > 0x7f)
con_to_str (tmp + 1, tmp + 1, 1);
/* Determine if the keystroke is modified by META. The tricky
part is to distinguish whether the right Alt key should be
@@ -344,9 +336,10 @@ fhandler_console::read (void *pv, size_t buflen)
break;
case MOUSE_EVENT:
+ send_winch_maybe ();
if (use_mouse)
{
- MOUSE_EVENT_RECORD & mouse_event = input_rec.Event.MouseEvent;
+ MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent;
/* Treat the double-click event like a regular button press */
if (mouse_event.dwEventFlags == DOUBLE_CLICK)
@@ -428,10 +421,10 @@ fhandler_console::read (void *pv, size_t buflen)
}
break;
+ case FOCUS_EVENT:
case WINDOW_BUFFER_SIZE_EVENT:
- kill_pgrp (tc->getpgid (), SIGWINCH);
- continue;
-
+ send_winch_maybe ();
+ /* fall through */
default:
continue;
}
@@ -505,7 +498,7 @@ fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
CHAR_INFO fill;
COORD dest;
- (void)fillin_info ();
+ (void) fillin_info ();
sr1.Left = x1 >= 0 ? x1 : info.dwWinSize.X - 1;
if (y1 == 0)
sr1.Top = info.winTop;
@@ -542,21 +535,21 @@ fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
}
int
-fhandler_console::open (const char *, int flags, mode_t)
+fhandler_console::open (path_conv *, int flags, mode_t)
{
HANDLE h;
tcinit (get_tty_stuff (flags));
- set_io_handle (INVALID_HANDLE_VALUE);
- set_output_handle (INVALID_HANDLE_VALUE);
+ set_io_handle (NULL);
+ set_output_handle (NULL);
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
/* Open the input handle as handle_ */
- h = CreateFileA ("CONIN$", GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
- OPEN_EXISTING, 0, 0);
+ h = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
+ OPEN_EXISTING, 0, 0);
if (h == INVALID_HANDLE_VALUE)
{
@@ -566,9 +559,9 @@ fhandler_console::open (const char *, int flags, mode_t)
set_io_handle (h);
set_r_no_interrupt (1); // Handled explicitly in read code
- h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
- OPEN_EXISTING, 0, 0);
+ h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
+ OPEN_EXISTING, 0, 0);
if (h == INVALID_HANDLE_VALUE)
{
@@ -602,8 +595,8 @@ fhandler_console::close (void)
{
CloseHandle (get_io_handle ());
CloseHandle (get_output_handle ());
- set_io_handle (INVALID_HANDLE_VALUE);
- set_output_handle (INVALID_HANDLE_VALUE);
+ set_io_handle (NULL);
+ set_output_handle (NULL);
return 0;
}
@@ -617,7 +610,7 @@ fhandler_console::dup (fhandler_base *child)
{
fhandler_console *fhc = (fhandler_console *) child;
- if (!fhc->open (get_name (), get_flags () & ~O_NOCTTY, 0))
+ if (!fhc->open (NULL, get_flags () & ~O_NOCTTY, 0))
system_printf ("error opening console, %E");
fhc->default_color = default_color;
@@ -718,12 +711,6 @@ fhandler_console::tcflush (int queue)
int
fhandler_console::output_tcsetattr (int, struct termios const *t)
{
- /* Ignore the optional_actions stuff, since all output is emitted
- instantly */
-
- /* Enable/disable LF -> CRLF conversions */
- set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);
-
/* All the output bits we can ignore */
DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
@@ -746,8 +733,10 @@ fhandler_console::input_tcsetattr (int, struct termios const *t)
oflags = 0;
DWORD flags = 0;
+#if 0
/* Enable/disable LF -> CRLF conversions */
set_r_binary ((t->c_iflag & INLCR) ? 0 : 1);
+#endif
/* There's some disparity between what we need and what's
available. We've got ECHO and ICANON, they've
@@ -777,8 +766,6 @@ fhandler_console::input_tcsetattr (int, struct termios const *t)
{
flags |= ENABLE_PROCESSED_INPUT;
}
- /* What about ENABLE_WINDOW_INPUT
- and ENABLE_MOUSE_INPUT ? */
if (use_tty)
{
@@ -822,13 +809,6 @@ fhandler_console::tcgetattr (struct termios *t)
t->c_cflag |= CS8;
-#if 0
- if (!get_r_binary ())
- t->c_iflag |= IGNCR;
- if (!get_w_binary ())
- t->c_oflag |= ONLCR;
-#endif
-
DWORD flags;
if (!GetConsoleMode (get_io_handle (), &flags))
@@ -858,29 +838,21 @@ fhandler_console::tcgetattr (struct termios *t)
return res;
}
-/*
- * Constructor.
- */
-
-fhandler_console::fhandler_console (const char *name) :
- fhandler_termios (FH_CONSOLE, name, -1)
+fhandler_console::fhandler_console () :
+ fhandler_termios (FH_CONSOLE, -1),
+ default_color (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE),
+ underline_color (FOREGROUND_GREEN | FOREGROUND_BLUE),
+ dim_color (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE),
+ meta_mask (LEFT_ALT_PRESSED), state_ (normal), nargs_ (0), savex (0),
+ savey (0), savebuf (NULL), dwLastButtonState (0), nModifiers (0),
+ insert_mode (false), use_mouse (false), raw_win32_keyboard_mode (false)
{
- set_cb (sizeof *this);
- default_color = dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
- underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE;
- state_ = normal;
- nargs_ = 0;
for (int i = 0; i < MAXARGS; i++) args_ [i] = 0;
- savex = savey = 0;
savebufsiz.X = savebufsiz.Y = 0;
- savebuf = NULL;
scroll_region.Top = 0;
scroll_region.Bottom = -1;
dwLastCursorPosition.X = -1;
dwLastCursorPosition.Y = -1;
- dwLastButtonState = 0;
- nModifiers = 0;
- insert_mode = use_mouse = raw_win32_keyboard_mode = FALSE;
/* Set the mask that determines if an input keystroke is modified by
META. We set this based on the keyboard layout language loaded
for the current thread. The left <ALT> key always generates
@@ -890,7 +862,6 @@ fhandler_console::fhandler_console (const char *name) :
language-specific characters (umlaut, accent grave, etc.). On
these keyboards right <ALT> (called AltGr) is used to produce the
shell symbols and should not be interpreted as META. */
- meta_mask = LEFT_ALT_PRESSED;
if (PRIMARYLANGID (LOWORD (GetKeyboardLayout (0))) == LANG_ENGLISH)
meta_mask |= RIGHT_ALT_PRESSED;
@@ -988,7 +959,7 @@ fhandler_console::cursor_set (BOOL rel_to_top, int x, int y)
{
COORD pos;
- (void)fillin_info ();
+ (void) fillin_info ();
if (y > info.winBottom)
y = info.winBottom;
else if (y < 0)
@@ -1207,7 +1178,7 @@ fhandler_console::char_command (char c)
ReadConsoleOutputA (get_output_handle (), savebuf,
savebufsiz, cob, &now.srWindow);
}
- else /* restore */
+ else /* restore */
{
CONSOLE_SCREEN_BUFFER_INFO now;
COORD cob = { 0, 0 };
@@ -1456,21 +1427,19 @@ fhandler_console::write_normal (const unsigned char *src,
case ESC:
state_ = gotesc;
break;
- case DWN: /* WriteFile ("\n") always adds CR... */
+ case DWN:
cursor_get (&x, &y);
if (y >= srBottom)
{
- if (y < info.winBottom || scroll_region.Top)
+ if (y >= info.winBottom && !scroll_region.Top)
+ WriteFile (get_output_handle (), "\n", 1, &done, 0);
+ else
{
scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop);
y--;
}
- else
- WriteFile (get_output_handle (), "\n", 1, &done, 0);
}
- if (!get_w_binary ())
- x = 0;
- cursor_set (FALSE, x, y + 1);
+ cursor_set (FALSE, ((tc->ti.c_oflag & ONLCR) ? 0 : x), y + 1);
break;
case BAK:
cursor_rel (-1, 0);
@@ -1647,7 +1616,7 @@ fhandler_console::write (const void *vsrc, size_t len)
static struct {
int vk;
const char *val[4];
-} const keytable[] NO_COPY = {
+} keytable[] NO_COPY = {
/* NORMAL */ /* SHIFT */ /* CTRL */ /* ALT */
{VK_LEFT, {"\033[D", "\033[D", "\033[D", "\033\033[D"}},
{VK_RIGHT, {"\033[C", "\033[C", "\033[C", "\033\033[C"}},
@@ -1711,23 +1680,22 @@ get_nonascii_key (INPUT_RECORD& input_rec, char *tmp)
void
fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
{
- this->fhandler_termios::init (f, bin, a);
-
+ // this->fhandler_termios::init (f, mode, bin);
/* Ensure both input and output console handles are open */
- int mode = 0;
+ int flags = 0;
a &= GENERIC_READ | GENERIC_WRITE;
if (a == GENERIC_READ)
- mode = O_RDONLY;
+ flags = O_RDONLY;
if (a == GENERIC_WRITE)
- mode = O_WRONLY;
+ flags = O_WRONLY;
if (a == (GENERIC_READ | GENERIC_WRITE))
- mode = O_RDWR;
- open (0, mode);
+ flags = O_RDWR;
+ open ((path_conv *) NULL, flags | O_BINARY);
if (f != INVALID_HANDLE_VALUE)
CloseHandle (f); /* Reopened by open */
- output_tcsetattr (0, &tc->ti);
+ this->tcsetattr (0, &tc->ti);
}
int
@@ -1752,7 +1720,7 @@ fhandler_console::fixup_after_fork (HANDLE)
/* Windows does not allow duplication of console handles between processes
so open the console explicitly. */
- if (!open (get_name (), O_NOCTTY | get_flags (), 0))
+ if (!open (NULL, O_NOCTTY | get_flags (), 0))
system_printf ("error opening console after fork, %E");
if (!get_close_on_exec ())
@@ -1782,7 +1750,7 @@ fhandler_console::fixup_after_exec (HANDLE)
HANDLE h = get_handle ();
HANDLE oh = get_output_handle ();
- if (!open (get_name (), O_NOCTTY | get_flags (), 0))
+ if (!open (NULL, O_NOCTTY | get_flags (), 0))
{
int sawerr = 0;
if (!get_io_handle ())
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 1ce4893d2..f8a7afca1 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -1,6 +1,6 @@
/* fhandler_disk_file.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <sys/fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
@@ -24,14 +23,14 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "shared_info.h"
-#include "sigproc.h"
#include "pinfo.h"
#include <assert.h>
+#include <ctype.h>
#define _COMPILING_NEWLIB
#include <dirent.h>
-static int
+static int __stdcall
num_entries (const char *win32_name)
{
WIN32_FIND_DATA buf;
@@ -60,27 +59,126 @@ num_entries (const char *win32_name)
return count;
}
-int
-fhandler_disk_file::fstat (struct stat *buf, path_conv *pc)
+int __stdcall
+fhandler_disk_file::fstat_by_handle (struct __stat64 *buf, path_conv *pc)
+{
+ int res = 0;
+ BY_HANDLE_FILE_INFORMATION local;
+
+ /* NT 3.51 seems to have a bug when attempting to get vol serial
+ numbers. This loop gets around this. */
+ for (int i = 0; i < 2; i++)
+ {
+ if (!(res = GetFileInformationByHandle (get_handle (), &local)))
+ break;
+ if (local.dwVolumeSerialNumber && (long) local.dwVolumeSerialNumber != -1)
+ break;
+ }
+ debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
+ res, get_win32_name (), get_handle ());
+ if (res == 0)
+ /* GetFileInformationByHandle will fail if it's given stdin/out/err
+ or a pipe*/
+ {
+ memset (&local, 0, sizeof (local));
+ local.nFileSizeLow = GetFileSize (get_handle (), &local.nFileSizeHigh);
+ }
+
+ return fstat_helper (buf, pc,
+ local.ftCreationTime,
+ local.ftLastAccessTime,
+ local.ftLastWriteTime,
+ local.nFileSizeHigh,
+ local.nFileSizeLow,
+ local.nFileIndexHigh,
+ local.nFileIndexLow,
+ local.nNumberOfLinks);
+}
+
+int __stdcall
+fhandler_disk_file::fstat_by_name (struct __stat64 *buf, path_conv *pc)
+{
+ int res;
+ HANDLE handle;
+ WIN32_FIND_DATA local;
+
+ if (!pc->exists ())
+ {
+ debug_printf ("already determined that pc does not exist");
+ set_errno (ENOENT);
+ res = -1;
+ }
+ else
+ {
+ char drivebuf[5];
+ char *name;
+ if ((*pc)[3] != '\0' || !isalpha ((*pc)[0]) || (*pc)[1] != ':' || (*pc)[2] != '\\')
+ name = *pc;
+ else
+ {
+ /* FIXME: Does this work on empty disks? */
+ drivebuf[0] = (*pc)[0];
+ drivebuf[1] = (*pc)[1];
+ drivebuf[2] = (*pc)[2];
+ drivebuf[3] = '*';
+ drivebuf[4] = '\0';
+ name = drivebuf;
+ }
+
+ if ((handle = FindFirstFile (name, &local)) == INVALID_HANDLE_VALUE)
+ {
+ debug_printf ("FindFirstFile failed for '%s', %E", name);
+ __seterrno ();
+ res = -1;
+ }
+ else
+ {
+ FindClose (handle);
+ res = fstat_helper (buf, pc,
+ local.ftCreationTime,
+ local.ftLastAccessTime,
+ local.ftLastWriteTime,
+ local.nFileSizeHigh,
+ local.nFileSizeLow);
+ }
+ }
+ return res;
+}
+
+int __stdcall
+fhandler_disk_file::fstat (struct __stat64 *buf, path_conv *pc)
{
int res = -1;
int oret;
- uid_t uid;
- gid_t gid;
+ __uid32_t uid;
+ __gid32_t gid;
int open_flags = O_RDONLY | O_BINARY | O_DIROPEN;
+ bool query_open_already;
- if (!pc)
- return fstat_helper (buf);
-
- if ((oret = open (pc, open_flags, 0)))
- /* ok */;
+ if (get_io_handle ())
+ {
+ if (get_nohandle ())
+ return fstat_by_name (buf, pc);
+ else
+ return fstat_by_handle (buf, pc);
+ }
+ /* If we don't care if the file is executable or we already know if it is,
+ then just do a "query open" as it is apparently much faster. */
+ if (pc->exec_state () != dont_know_if_executable)
+ set_query_open (query_open_already = true);
else
+ query_open_already = false;
+
+ if (query_open_already && strncasematch (pc->volname (), "FAT", 3)
+ && !strpbrk (get_win32_name (), "?*|<>"))
+ oret = 0;
+ else if (!(oret = open (pc, open_flags, 0)))
{
int ntsec_atts = 0;
/* If we couldn't open the file, try a "query open" with no permissions.
This will allow us to determine *some* things about the file, at least. */
- set_query_open (TRUE);
- if ((oret = open (pc, open_flags, 0)))
+ set_query_open (true);
+ if (!query_open_already && (oret = open (pc, open_flags, 0)))
/* ok */;
else if (allow_ntsec && pc->has_acls () && get_errno () == EACCES
&& !get_file_attribute (TRUE, get_win32_name (), &ntsec_atts, &uid, &gid)
@@ -96,149 +194,54 @@ fhandler_disk_file::fstat (struct stat *buf, path_conv *pc)
set_file_attribute (TRUE, get_win32_name (), ntsec_atts);
}
}
- if (oret)
- {
- res = fstat_helper (buf);
- /* The number of links to a directory includes the
- number of subdirectories in the directory, since all
- those subdirectories point to it.
- This is too slow on remote drives, so we do without it and
- set the number of links to 2. */
- /* Unfortunately the count of 2 confuses `find (1)' command. So
- let's try it with `1' as link count. */
- if (pc->isdir ())
- buf->st_nlink = (pc->isremote ()
- ? 1 : num_entries (pc->get_win32 ()));
+
+ if (!oret || get_nohandle ())
+ res = fstat_by_name (buf, pc);
+ else
+ {
+ res = fstat_by_handle (buf, pc);
close ();
}
- else if (pc->exists ())
- {
- /* Unfortunately, the above open may fail if the file exists, though.
- So we have to care for this case here, too. */
- WIN32_FIND_DATA wfd;
- HANDLE handle;
- buf->st_nlink = 1;
- if (pc->isdir () && pc->isremote ())
- buf->st_nlink = num_entries (pc->get_win32 ());
- buf->st_dev = FHDEVN (FH_DISK) << 8;
- buf->st_ino = hash_path_name (0, pc->get_win32 ());
- if (pc->isdir ())
- buf->st_mode = S_IFDIR;
- else if (pc->issymlink ())
- buf->st_mode = S_IFLNK;
- else if (pc->issocket ())
- buf->st_mode = S_IFSOCK;
- else
- buf->st_mode = S_IFREG;
- if (!pc->has_acls ()
- || get_file_attribute (TRUE, pc->get_win32 (),
- &buf->st_mode,
- &buf->st_uid, &buf->st_gid))
- {
- buf->st_mode |= STD_RBITS | STD_XBITS;
- if (!(pc->has_attribute (FILE_ATTRIBUTE_READONLY)))
- buf->st_mode |= STD_WBITS;
- if (pc->issymlink ())
- buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO;
- get_file_attribute (FALSE, pc->get_win32 (),
- NULL, &buf->st_uid, &buf->st_gid);
- }
- if ((handle = FindFirstFile (pc->get_win32 (), &wfd))
- != INVALID_HANDLE_VALUE)
- {
- /* This is for FAT filesystems, which don't support atime/ctime */
- if (wfd.ftLastAccessTime.dwLowDateTime == 0
- && wfd.ftLastAccessTime.dwHighDateTime == 0)
- wfd.ftLastAccessTime = wfd.ftLastWriteTime;
- if (wfd.ftCreationTime.dwLowDateTime == 0
- && wfd.ftCreationTime.dwHighDateTime == 0)
- wfd.ftCreationTime = wfd.ftLastWriteTime;
-
- buf->st_atime = to_time_t (&wfd.ftLastAccessTime);
- buf->st_mtime = to_time_t (&wfd.ftLastWriteTime);
- buf->st_ctime = to_time_t (&wfd.ftCreationTime);
- buf->st_size = wfd.nFileSizeLow;
- buf->st_blksize = S_BLKSIZE;
- buf->st_blocks = ((unsigned long) buf->st_size +
- S_BLKSIZE-1) / S_BLKSIZE;
- FindClose (handle);
- }
- res = 0;
- }
return res;
}
-int
-fhandler_disk_file::fstat_helper (struct stat *buf)
+int __stdcall
+fhandler_disk_file::fstat_helper (struct __stat64 *buf, path_conv *pc,
+ FILETIME ftCreationTime,
+ FILETIME ftLastAccessTime,
+ FILETIME ftLastWriteTime,
+ DWORD nFileSizeHigh,
+ DWORD nFileSizeLow,
+ DWORD nFileIndexHigh,
+ DWORD nFileIndexLow,
+ DWORD nNumberOfLinks)
{
- int res = 0; // avoid a compiler warning
- BY_HANDLE_FILE_INFORMATION local;
- save_errno saved_errno;
-
- /* NT 3.51 seems to have a bug when attempting to get vol serial
- numbers. This loop gets around this. */
- for (int i = 0; i < 2; i++)
- {
- if (!(res = GetFileInformationByHandle (get_handle (), &local)))
- break;
- if (local.dwVolumeSerialNumber && (long) local.dwVolumeSerialNumber != -1)
- break;
- }
- debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
- res, get_win32_name (), get_handle ());
- if (res == 0)
- {
- /* GetFileInformationByHandle will fail if it's given stdin/out/err
- or a pipe*/
- DWORD lsize, hsize;
-
- if (GetFileType (get_handle ()) != FILE_TYPE_DISK)
- buf->st_mode = S_IFCHR;
-
- lsize = GetFileSize (get_handle (), &hsize);
- if (lsize == 0xffffffff && GetLastError () != NO_ERROR)
- buf->st_mode = S_IFCHR;
- else
- buf->st_size = lsize;
- /* We expect these to fail! */
- buf->st_mode |= STD_RBITS | STD_WBITS;
- buf->st_blksize = S_BLKSIZE;
- buf->st_ino = get_namehash ();
- syscall_printf ("0 = fstat (, %p)", buf);
- return 0;
- }
-
- if (!get_win32_name ())
- {
- saved_errno.set (ENOENT);
- return -1;
- }
-
/* This is for FAT filesystems, which don't support atime/ctime */
- if (local.ftLastAccessTime.dwLowDateTime == 0
- && local.ftLastAccessTime.dwHighDateTime == 0)
- local.ftLastAccessTime = local.ftLastWriteTime;
- if (local.ftCreationTime.dwLowDateTime == 0
- && local.ftCreationTime.dwHighDateTime == 0)
- local.ftCreationTime = local.ftLastWriteTime;
-
- buf->st_atime = to_time_t (&local.ftLastAccessTime);
- buf->st_mtime = to_time_t (&local.ftLastWriteTime);
- buf->st_ctime = to_time_t (&local.ftCreationTime);
- buf->st_nlink = local.nNumberOfLinks;
- buf->st_dev = local.dwVolumeSerialNumber;
- buf->st_size = local.nFileSizeLow;
-
- /* Allocate some place to determine the root directory. Need to allocate
- enough so that rootdir can add a trailing slash if path starts with \\. */
- char root[strlen (get_win32_name ()) + 3];
- strcpy (root, get_win32_name ());
+ if (ftLastAccessTime.dwLowDateTime == 0
+ && ftLastAccessTime.dwHighDateTime == 0)
+ ftLastAccessTime = ftLastWriteTime;
+ if (ftCreationTime.dwLowDateTime == 0
+ && ftCreationTime.dwHighDateTime == 0)
+ ftCreationTime = ftLastWriteTime;
+
+ to_timestruc_t (&ftLastAccessTime, &buf->st_atim);
+ to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
+ to_timestruc_t (&ftCreationTime, &buf->st_ctim);
+ buf->st_dev = pc->volser ();
+ buf->st_size = ((__off64_t)nFileSizeHigh << 32) + nFileSizeLow;
+ /* Unfortunately the count of 2 confuses `find (1)' command. So
+ let's try it with `1' as link count. */
+ if (pc->isdir () && !pc->isremote () && nNumberOfLinks == 1)
+ buf->st_nlink = num_entries (pc->get_win32 ());
+ else
+ buf->st_nlink = nNumberOfLinks;
/* Assume that if a drive has ACL support it MAY have valid "inodes".
It definitely does not have valid inodes if it does not have ACL
support. */
- switch (has_acls () ? GetDriveType (rootdir (root)) : DRIVE_UNKNOWN)
+ switch (pc->has_acls () && (nFileIndexHigh || nFileIndexLow)
+ ? pc->drive_type () : DRIVE_UNKNOWN)
{
case DRIVE_FIXED:
case DRIVE_REMOVABLE:
@@ -246,7 +249,7 @@ fhandler_disk_file::fstat_helper (struct stat *buf)
case DRIVE_RAMDISK:
/* Although the documentation indicates otherwise, it seems like
"inodes" on these devices are persistent, at least across reboots. */
- buf->st_ino = local.nFileIndexHigh | local.nFileIndexLow;
+ buf->st_ino = nFileIndexHigh | nFileIndexLow;
break;
default:
/* Either the nFileIndex* fields are unreliable or unavailable. Use the
@@ -256,23 +259,25 @@ fhandler_disk_file::fstat_helper (struct stat *buf)
}
buf->st_blksize = S_BLKSIZE;
- buf->st_blocks = ((unsigned long) buf->st_size + S_BLKSIZE-1) / S_BLKSIZE;
+ buf->st_blocks = (buf->st_size + S_BLKSIZE - 1) / S_BLKSIZE;
buf->st_mode = 0;
/* Using a side effect: get_file_attibutes checks for
directory. This is used, to set S_ISVTX, if needed. */
- if (local.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ if (pc->isdir ())
buf->st_mode = S_IFDIR;
- else if (get_symlink_p ())
+ else if (pc->issymlink ())
buf->st_mode = S_IFLNK;
- else if (get_socket_p ())
+ else if (pc->issocket ())
buf->st_mode = S_IFSOCK;
- if (get_file_attribute (has_acls (), get_win32_name (), &buf->st_mode,
- &buf->st_uid, &buf->st_gid) == 0)
+
+ __uid32_t uid;
+ __gid32_t gid;
+ if (get_file_attribute (pc->has_acls (), get_win32_name (), &buf->st_mode,
+ &uid, &gid) == 0)
{
/* If read-only attribute is set, modify ntsec return value */
- if ((local.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
- && !get_symlink_p ())
+ if (pc->has_attribute (FILE_ATTRIBUTE_READONLY) && !get_symlink_p ())
buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
if (!(buf->st_mode & S_IFMT))
@@ -282,7 +287,7 @@ fhandler_disk_file::fstat_helper (struct stat *buf)
{
buf->st_mode |= STD_RBITS;
- if (!(local.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+ if (!pc->has_attribute (FILE_ATTRIBUTE_READONLY))
buf->st_mode |= STD_WBITS;
/* | S_IWGRP | S_IWOTH; we don't give write to group etc */
@@ -290,51 +295,52 @@ fhandler_disk_file::fstat_helper (struct stat *buf)
buf->st_mode |= S_IFDIR | STD_XBITS;
else if (buf->st_mode & S_IFMT)
/* nothing */;
- else if (get_socket_p ())
+ else if (pc->issocket ())
buf->st_mode |= S_IFSOCK;
else
- switch (GetFileType (get_handle ()))
- {
- case FILE_TYPE_CHAR:
- case FILE_TYPE_UNKNOWN:
- buf->st_mode |= S_IFCHR;
- break;
- case FILE_TYPE_DISK:
- buf->st_mode |= S_IFREG;
- if (!dont_care_if_execable () && !get_execable_p ())
- {
- DWORD cur, done;
- char magic[3];
-
- /* First retrieve current position, set to beginning
- of file if not already there. */
- cur = SetFilePointer (get_handle(), 0, NULL, FILE_CURRENT);
- if (cur != INVALID_SET_FILE_POINTER &&
- (!cur ||
- SetFilePointer (get_handle(), 0, NULL, FILE_BEGIN)
- != INVALID_SET_FILE_POINTER))
- {
- /* FIXME should we use /etc/magic ? */
- magic[0] = magic[1] = magic[2] = '\0';
- if (ReadFile (get_handle (), magic, 3, &done, NULL) &&
- has_exec_chars (magic, done))
- set_execable_p ();
- SetFilePointer (get_handle(), cur, NULL, FILE_BEGIN);
- }
- }
- if (get_execable_p ())
- buf->st_mode |= STD_XBITS;
- break;
- case FILE_TYPE_PIPE:
- buf->st_mode |= S_IFSOCK;
- break;
- }
- }
-
- syscall_printf ("0 = fstat (, %p) st_atime=%x st_size=%d, st_mode=%p, st_ino=%d, sizeof=%d",
- buf, buf->st_atime, buf->st_size, buf->st_mode,
- (int) buf->st_ino, sizeof (*buf));
+ {
+ buf->st_mode |= S_IFREG;
+ if (pc->exec_state () == dont_know_if_executable)
+ {
+ DWORD cur, done;
+ char magic[3];
+
+ /* First retrieve current position, set to beginning
+ of file if not already there. */
+ cur = SetFilePointer (get_handle (), 0, NULL, FILE_CURRENT);
+ if (cur != INVALID_SET_FILE_POINTER &&
+ (!cur ||
+ SetFilePointer (get_handle (), 0, NULL, FILE_BEGIN)
+ != INVALID_SET_FILE_POINTER))
+ {
+ /* FIXME should we use /etc/magic ? */
+ magic[0] = magic[1] = magic[2] = '\0';
+ if (ReadFile (get_handle (), magic, 3, &done, NULL) &&
+ has_exec_chars (magic, done))
+ {
+ set_execable_p ();
+ pc->set_exec ();
+ }
+ SetFilePointer (get_handle (), cur, NULL, FILE_BEGIN);
+ }
+ }
+ if (pc->exec_state () == is_executable)
+ buf->st_mode |= STD_XBITS;
+ }
+ }
+
+ buf->st_uid = uid;
+ buf->st_gid = gid;
+ /* The number of links to a directory includes the
+ number of subdirectories in the directory, since all
+ those subdirectories point to it.
+ This is too slow on remote drives, so we do without it and
+ set the number of links to 2. */
+
+ syscall_printf ("0 = fstat (, %p) st_atime=%x st_size=%D, st_mode=%p, st_ino=%d, sizeof=%d",
+ buf, buf->st_atime, buf->st_size, buf->st_mode,
+ (int) buf->st_ino, sizeof (*buf));
return 0;
}
@@ -358,20 +364,10 @@ fhandler_disk_file::open (path_conv *real_path, int flags, mode_t mode)
return 0;
}
- if (real_path->isbinary ())
- {
- set_r_binary (1);
- set_w_binary (1);
- }
-
set_has_acls (real_path->has_acls ());
set_isremote (real_path->isremote ());
- if (real_path->isdir ())
- flags |= O_DIROPEN;
-
- int res = this->fhandler_base::open (real_path, flags, mode);
-
+ int res = this->fhandler_base::open (real_path, flags | O_DIROPEN, mode);
if (!res)
goto out;
@@ -381,8 +377,7 @@ fhandler_disk_file::open (path_conv *real_path, int flags, mode_t mode)
The only known file system to date is the SUN NFS Solstice Client 3.1
which returns a valid handle when trying to open a file in a nonexistent
directory. */
- if (real_path->has_buggy_open ()
- && GetFileAttributes (win32_path_name) == (DWORD) -1)
+ if (real_path->has_buggy_open () && !real_path->exists ())
{
debug_printf ("Buggy open detected.");
close ();
@@ -390,9 +385,6 @@ fhandler_disk_file::open (path_conv *real_path, int flags, mode_t mode)
return 0;
}
- if (flags & O_APPEND)
- SetFilePointer (get_handle(), 0, 0, FILE_END);
-
set_symlink_p (real_path->issymlink ());
set_execable_p (real_path->exec_state ());
set_socket_p (real_path->issocket ());
@@ -429,10 +421,10 @@ fhandler_disk_file::close ()
int
fhandler_disk_file::lock (int cmd, struct flock *fl)
{
- int win32_start;
+ __off64_t win32_start;
int win32_len;
DWORD win32_upper;
- DWORD startpos;
+ __off64_t startpos;
/*
* We don't do getlck calls yet.
@@ -455,18 +447,19 @@ fhandler_disk_file::lock (int cmd, struct flock *fl)
startpos = 0;
break;
case SEEK_CUR:
- if ((off_t) (startpos = lseek (0, SEEK_CUR)) == (off_t)-1)
+ if ((startpos = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK)
return -1;
break;
case SEEK_END:
{
BY_HANDLE_FILE_INFORMATION finfo;
- if (GetFileInformationByHandle (get_handle(), &finfo) == 0)
+ if (GetFileInformationByHandle (get_handle (), &finfo) == 0)
{
__seterrno ();
return -1;
}
- startpos = finfo.nFileSizeLow; /* Nowhere to keep high word */
+ startpos = ((__off64_t)finfo.nFileSizeHigh << 32)
+ + finfo.nFileSizeLow;
break;
}
default:
@@ -676,37 +669,6 @@ fhandler_disk_file::readdir (DIR *dir)
}
}
- /* Compute d_ino by combining filename hash with the directory hash
- (which was stored in dir->__d_dirhash when opendir was called). */
- if (buf.cFileName[0] == '.')
- {
- if (buf.cFileName[1] == '\0')
- dir->__d_dirent->d_ino = dir->__d_dirhash;
- else if (buf.cFileName[1] != '.' || buf.cFileName[2] != '\0')
- goto hashit;
- else
- {
- char *p, up[strlen (dir->__d_dirname) + 1];
- strcpy (up, dir->__d_dirname);
- if (!(p = strrchr (up, '\\')))
- goto hashit;
- *p = '\0';
- if (!(p = strrchr (up, '\\')))
- dir->__d_dirent->d_ino = hash_path_name (0, ".");
- else
- {
- *p = '\0';
- dir->__d_dirent->d_ino = hash_path_name (0, up);
- }
- }
- }
- else
- {
- hashit:
- ino_t dino = hash_path_name (dir->__d_dirhash, "\\");
- dir->__d_dirent->d_ino = hash_path_name (dino, buf.cFileName);
- }
-
dir->__d_position++;
res = dir->__d_dirent;
syscall_printf ("%p = readdir (%p) (%s)",
@@ -714,14 +676,14 @@ fhandler_disk_file::readdir (DIR *dir)
return res;
}
-off_t
+__off64_t
fhandler_disk_file::telldir (DIR *dir)
{
return dir->__d_position;
}
void
-fhandler_disk_file::seekdir (DIR *dir, off_t loc)
+fhandler_disk_file::seekdir (DIR *dir, __off64_t loc)
{
rewinddir (dir);
while (loc > dir->__d_position)
@@ -764,14 +726,18 @@ void
fhandler_cygdrive::set_drives ()
{
const int len = 1 + 26 * DRVSZ;
- win32_path_name = (char *) crealloc (win32_path_name, len);
-
- ndrives = GetLogicalDriveStrings (len, win32_path_name) / DRVSZ;
- pdrive = win32_path_name;
+ char *p = (char *) crealloc ((void *) win32_path_name,
+ sizeof (".") + sizeof ("..") + len);
+
+ win32_path_name = pdrive = p;
+ strcpy (p, ".");
+ strcpy (p + sizeof ("."), "..");
+ p += sizeof (".") + sizeof ("..");
+ ndrives = GetLogicalDriveStrings (len, p) / DRVSZ;
}
int
-fhandler_cygdrive::fstat (struct stat *buf, path_conv *pc)
+fhandler_cygdrive::fstat (struct __stat64 *buf, path_conv *pc)
{
if (!iscygdrive_root ())
return fhandler_disk_file::fstat (buf, pc);
@@ -804,33 +770,40 @@ fhandler_cygdrive::readdir (DIR *dir)
set_errno (ENMFILE);
return NULL;
}
- if (GetFileAttributes (pdrive) == (DWORD) -1)
+ else if (dir->__d_position > 1
+ && GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES)
{
- pdrive += DRVSZ;
+ pdrive = strchr (pdrive, '\0') + 1;
return readdir (dir);
}
- *dir->__d_dirent->d_name = cyg_tolower (*pdrive);
- dir->__d_dirent->d_name[1] = '\0';
+ else if (*pdrive == '.')
+ strcpy (dir->__d_dirent->d_name, pdrive);
+ else
+ {
+ *dir->__d_dirent->d_name = cyg_tolower (*pdrive);
+ dir->__d_dirent->d_name[1] = '\0';
+ }
dir->__d_position++;
- pdrive += DRVSZ;
+ pdrive = strchr (pdrive, '\0') + 1;
syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir,
- dir->__d_dirent->d_name);
+ dir->__d_dirent->d_name);
return dir->__d_dirent;
}
-off_t
+__off64_t
fhandler_cygdrive::telldir (DIR *dir)
{
return fhandler_disk_file::telldir (dir);
}
void
-fhandler_cygdrive::seekdir (DIR *dir, off_t loc)
+fhandler_cygdrive::seekdir (DIR *dir, __off64_t loc)
{
if (!iscygdrive_root ())
return fhandler_disk_file::seekdir (dir, loc);
- for (pdrive = win32_path_name, dir->__d_position = -1; *pdrive; pdrive += DRVSZ)
+ for (pdrive = win32_path_name, dir->__d_position = -1; *pdrive;
+ pdrive = strchr (pdrive, '\0') + 1)
if (++dir->__d_position >= loc)
break;
diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc
index 914caeec8..fad431900 100644
--- a/winsup/cygwin/fhandler_dsp.cc
+++ b/winsup/cygwin/fhandler_dsp.cc
@@ -1,6 +1,6 @@
/* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
- Copyright 2001 Red Hat, Inc
+ Copyright 2001, 2002 Red Hat, Inc
Written by Andy Younger (andy@snoogie.demon.co.uk)
@@ -15,7 +15,6 @@ details. */
#include <errno.h>
#include <windows.h>
#include <sys/soundcard.h>
-#include <sys/fcntl.h>
#include <mmsystem.h>
#include "cygerrno.h"
#include "security.h"
@@ -86,7 +85,7 @@ Audio::~Audio ()
}
bool
-Audio::open (int rate, int bits, int channels, bool bCallback = false)
+Audio::open (int rate, int bits, int channels, bool bCallback)
{
WAVEFORMATEX format;
int nDevices = waveOutGetNumDevs ();
@@ -420,10 +419,9 @@ fhandler_dev_dsp::setupwav (const char *pData, int nBytes)
}
//------------------------------------------------------------------------
-fhandler_dev_dsp::fhandler_dev_dsp (const char *name):
- fhandler_base (FH_OSS_DSP, name)
+fhandler_dev_dsp::fhandler_dev_dsp ():
+ fhandler_base (FH_OSS_DSP)
{
- set_cb (sizeof *this);
}
fhandler_dev_dsp::~fhandler_dev_dsp ()
@@ -431,35 +429,38 @@ fhandler_dev_dsp::~fhandler_dev_dsp ()
}
int
-fhandler_dev_dsp::open (const char *path, int flags, mode_t mode = 0)
+fhandler_dev_dsp::open (path_conv *, int flags, mode_t mode)
{
// currently we only support writing
if ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_WRONLY)
- return 0;
+ {
+ set_errno (EACCES);
+ return 0;
+ }
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
if (!s_audio)
s_audio = new (audio_buf) Audio;
// Work out initial sample format & frequency
- if (strcmp (path, "/dev/dsp") == 0L)
- {
// dev/dsp defaults
- audioformat_ = AFMT_S8;
- audiofreq_ = 8000;
- audiobits_ = 8;
- audiochannels_ = 1;
- }
+ audioformat_ = AFMT_S8;
+ audiofreq_ = 8000;
+ audiobits_ = 8;
+ audiochannels_ = 1;
+ int res;
if (!s_audio->open (audiofreq_, audiobits_, audiochannels_))
- debug_printf ("/dev/dsp: failed to open\n");
+ res = 0;
else
{
set_open_status ();
- debug_printf ("/dev/dsp: successfully opened\n");
+ res = 1;
}
- return 1;
+
+ debug_printf ("returns %d", res);
+ return res;
}
int
@@ -480,14 +481,14 @@ fhandler_dev_dsp::write (const void *ptr, size_t len)
return len;
}
-int
+int __stdcall
fhandler_dev_dsp::read (void *ptr, size_t len)
{
return len;
}
-off_t
-fhandler_dev_dsp::lseek (off_t offset, int whence)
+__off64_t
+fhandler_dev_dsp::lseek (__off64_t offset, int whence)
{
return 0;
}
@@ -529,7 +530,7 @@ fhandler_dev_dsp::ioctl (unsigned int cmd, void *ptr)
CASE (SNDCTL_DSP_GETBLKSIZE)
*intptr = Audio::BLOCK_SIZE;
- break;
+ return 0;
CASE (SNDCTL_DSP_SETFMT)
{
diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc
index 994bba9f1..f0380dc88 100644
--- a/winsup/cygwin/fhandler_floppy.cc
+++ b/winsup/cygwin/fhandler_floppy.cc
@@ -1,7 +1,7 @@
/* fhandler_floppy.cc. See fhandler.h for a description of the
fhandler classes.
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,7 +11,6 @@ details. */
#include "winsup.h"
#include <sys/termios.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <winioctl.h>
@@ -40,13 +39,12 @@ fhandler_dev_floppy::is_eof (int)
return ret;
}
-fhandler_dev_floppy::fhandler_dev_floppy (const char *name, int unit) : fhandler_dev_raw (FH_FLOPPY, name, unit)
+fhandler_dev_floppy::fhandler_dev_floppy (int unit) : fhandler_dev_raw (FH_FLOPPY, unit)
{
- set_cb (sizeof *this);
}
int
-fhandler_dev_floppy::open (const char *path, int flags, mode_t)
+fhandler_dev_floppy::open (path_conv *real_path, int flags, mode_t)
{
/* The correct size of the buffer would be 512 bytes,
* which is the atomic size, supported by WinNT.
@@ -61,7 +59,7 @@ fhandler_dev_floppy::open (const char *path, int flags, mode_t)
* and cpio buffer sizes by default!
*/
devbufsiz = 61440L; /* 512L; */
- return fhandler_dev_raw::open (path, flags);
+ return fhandler_dev_raw::open (real_path, flags);
}
int
@@ -78,16 +76,16 @@ fhandler_dev_floppy::close (void)
return fhandler_dev_raw::close ();
}
-off_t
-fhandler_dev_floppy::lseek (off_t offset, int whence)
+__off64_t
+fhandler_dev_floppy::lseek (__off64_t offset, int whence)
{
int ret;
char buf[512];
- long long drive_size = 0;
- long long lloffset = offset;
- long long current_position;
- off_t sector_aligned_offset;
- off_t bytes_left;
+ __off64_t drive_size = 0;
+ __off64_t lloffset = offset;
+ __off64_t current_position;
+ __off64_t sector_aligned_offset;
+ __off64_t bytes_left;
DWORD low;
LONG high = 0;
@@ -95,7 +93,7 @@ fhandler_dev_floppy::lseek (off_t offset, int whence)
PARTITION_INFORMATION pi;
DWORD bytes_read;
- if (!DeviceIoControl (get_handle(),
+ if (!DeviceIoControl (get_handle (),
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL, 0,
&di, sizeof (di),
@@ -118,11 +116,11 @@ fhandler_dev_floppy::lseek (off_t offset, int whence)
debug_printf ("partition info: %ld (%ld)",
pi.StartingOffset.LowPart,
pi.PartitionLength.LowPart);
- drive_size = (long long) pi.PartitionLength.QuadPart;
+ drive_size = pi.PartitionLength.QuadPart;
}
else
{
- drive_size = (long long) di.Cylinders.QuadPart * di.TracksPerCylinder *
+ drive_size = di.Cylinders.QuadPart * di.TracksPerCylinder *
di.SectorsPerTrack * di.BytesPerSector;
}
debug_printf ("drive size: %ld", drive_size);
@@ -141,7 +139,7 @@ fhandler_dev_floppy::lseek (off_t offset, int whence)
__seterrno ();
return -1;
}
- current_position = (long long) low + ((long long) high << 32);
+ current_position = low + ((__off64_t) high << 32);
if (is_writing)
current_position += devbufend - devbufstart;
else
@@ -157,18 +155,10 @@ fhandler_dev_floppy::lseek (off_t offset, int whence)
set_errno (EINVAL);
return -1;
}
- high = lloffset >> 32;
- low = lloffset & 0xffffffff;
- if (high || (off_t) low < 0)
- {
- set_errno (EFBIG);
- return -1;
- }
- offset = (off_t) low;
/* FIXME: sector can possibly be not 512 bytes long */
- sector_aligned_offset = (offset / 512) * 512;
- bytes_left = offset - sector_aligned_offset;
+ sector_aligned_offset = (lloffset / 512) * 512;
+ bytes_left = lloffset - sector_aligned_offset;
if (whence == SEEK_SET)
{
@@ -178,8 +168,10 @@ fhandler_dev_floppy::lseek (off_t offset, int whence)
return ret;
devbufstart = devbufend = 0;
- if (SetFilePointer (get_handle (), sector_aligned_offset, NULL, FILE_BEGIN)
- == INVALID_SET_FILE_POINTER)
+ low = sector_aligned_offset & 0xffffffff;
+ high = sector_aligned_offset >> 32;
+ if (SetFilePointer (get_handle (), low, &high, FILE_BEGIN)
+ == INVALID_SET_FILE_POINTER && GetLastError ())
{
__seterrno ();
return -1;
diff --git a/winsup/cygwin/fhandler_mem.cc b/winsup/cygwin/fhandler_mem.cc
index b6b461a62..7613b11ec 100644
--- a/winsup/cygwin/fhandler_mem.cc
+++ b/winsup/cygwin/fhandler_mem.cc
@@ -1,6 +1,6 @@
/* fhandler_mem.cc. See fhandler.h for a description of the fhandler classes.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,7 +9,6 @@
details. */
#include "winsup.h"
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
@@ -23,9 +22,8 @@
/**********************************************************************/
/* fhandler_dev_mem */
-fhandler_dev_mem::fhandler_dev_mem (const char *name, int nunit)
-: fhandler_base (FH_MEM, name),
- unit (nunit)
+fhandler_dev_mem::fhandler_dev_mem (int nunit)
+ : fhandler_base (FH_MEM), unit (nunit)
{
/* Reading physical memory only supported on NT/W2K. */
if (!wincap.has_physical_mem_access ())
@@ -72,7 +70,7 @@ fhandler_dev_mem::~fhandler_dev_mem (void)
}
int
-fhandler_dev_mem::open (const char *, int flags, mode_t)
+fhandler_dev_mem::open (path_conv *, int flags, mode_t)
{
if (!wincap.has_physical_mem_access ())
{
@@ -95,9 +93,9 @@ fhandler_dev_mem::open (const char *, int flags, mode_t)
RtlInitUnicodeString (&memstr, L"\\device\\physicalmemory");
OBJECT_ATTRIBUTES attr;
- InitializeObjectAttributes(&attr, &memstr,
- OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
- NULL, NULL);
+ InitializeObjectAttributes (&attr, &memstr,
+ OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
+ NULL, NULL);
ACCESS_MASK section_access;
if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY)
@@ -178,7 +176,7 @@ fhandler_dev_mem::write (const void *ptr, size_t ulen)
return ulen;
}
-int
+int __stdcall
fhandler_dev_mem::read (void *ptr, size_t ulen)
{
if (!ulen || pos >= mem_size)
@@ -232,8 +230,8 @@ fhandler_dev_mem::close (void)
return fhandler_base::close ();
}
-off_t
-fhandler_dev_mem::lseek (off_t offset, int whence)
+__off64_t
+fhandler_dev_mem::lseek (__off64_t offset, int whence)
{
switch (whence)
{
@@ -252,13 +250,13 @@ fhandler_dev_mem::lseek (off_t offset, int whence)
default:
set_errno (EINVAL);
- return (off_t) -1;
+ return ILLEGAL_SEEK;
}
if (pos > mem_size)
{
set_errno (EINVAL);
- return (off_t) -1;
+ return ILLEGAL_SEEK;
}
return pos;
@@ -266,11 +264,11 @@ fhandler_dev_mem::lseek (off_t offset, int whence)
HANDLE
fhandler_dev_mem::mmap (caddr_t *addr, size_t len, DWORD access,
- int flags, off_t off)
+ int flags, __off64_t off)
{
- if ((DWORD) off >= mem_size
+ if (off >= mem_size
|| (DWORD) len >= mem_size
- || (DWORD) off + len >= mem_size)
+ || off + len >= mem_size)
{
set_errno (EINVAL);
syscall_printf ("-1 = mmap(): illegal parameter, set EINVAL");
@@ -281,9 +279,9 @@ fhandler_dev_mem::mmap (caddr_t *addr, size_t len, DWORD access,
RtlInitUnicodeString (&memstr, L"\\device\\physicalmemory");
OBJECT_ATTRIBUTES attr;
- InitializeObjectAttributes(&attr, &memstr,
- OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
- NULL, NULL);
+ InitializeObjectAttributes (&attr, &memstr,
+ OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
+ NULL, NULL);
ACCESS_MASK section_access;
ULONG protect;
@@ -403,23 +401,15 @@ fhandler_dev_mem::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
}
int
-fhandler_dev_mem::fstat (struct stat *buf)
+fhandler_dev_mem::fstat (struct __stat64 *buf, path_conv *pc)
{
- if (!buf)
- {
- set_errno (EINVAL);
- return -1;
- }
-
- memset (buf, 0, sizeof *buf);
+ this->fhandler_base::fstat (buf, pc);
buf->st_mode = S_IFCHR;
- if (!wincap.has_physical_mem_access ())
+ if (wincap.has_physical_mem_access ())
buf->st_mode |= S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH;
- buf->st_nlink = 1;
buf->st_blksize = getpagesize ();
- buf->st_dev = buf->st_rdev = get_device () << 8 | (unit & 0xff);
return 0;
}
@@ -442,5 +432,5 @@ fhandler_dev_mem::dup (fhandler_base *child)
void
fhandler_dev_mem::dump ()
{
- paranoid_printf("here, fhandler_dev_mem");
+ paranoid_printf ("here, fhandler_dev_mem");
}
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
new file mode 100644
index 000000000..0338acd85
--- /dev/null
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -0,0 +1,509 @@
+/* fhandler_proc.cc: fhandler for /proc virtual filesystem
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <ntdef.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "pinfo.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <assert.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+#include "ntdll.h"
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+/* offsets in proc_listing */
+static const int PROC_LOADAVG = 2; // /proc/loadavg
+static const int PROC_MEMINFO = 3; // /proc/meminfo
+static const int PROC_REGISTRY = 4; // /proc/registry
+static const int PROC_STAT = 5; // /proc/stat
+static const int PROC_VERSION = 6; // /proc/version
+static const int PROC_UPTIME = 7; // /proc/uptime
+
+/* names of objects in /proc */
+static const char *proc_listing[] = {
+ ".",
+ "..",
+ "loadavg",
+ "meminfo",
+ "registry",
+ "stat",
+ "version",
+ "uptime",
+ NULL
+};
+
+static const int PROC_LINK_COUNT = (sizeof (proc_listing) / sizeof (const char *)) - 1;
+
+/* FH_PROC in the table below means the file/directory is handles by
+ * fhandler_proc.
+ */
+static const DWORD proc_fhandlers[PROC_LINK_COUNT] = {
+ FH_PROC,
+ FH_PROC,
+ FH_PROC,
+ FH_PROC,
+ FH_REGISTRY,
+ FH_PROC,
+ FH_PROC,
+ FH_PROC
+};
+
+/* name of the /proc filesystem */
+const char proc[] = "/proc";
+const int proc_len = sizeof (proc) - 1;
+
+static off_t format_proc_meminfo (char *destbuf, size_t maxsize);
+static off_t format_proc_stat (char *destbuf, size_t maxsize);
+static off_t format_proc_uptime (char *destbuf, size_t maxsize);
+
+/* auxillary function that returns the fhandler associated with the given path
+ * this is where it would be nice to have pattern matching in C - polymorphism
+ * just doesn't cut it
+ */
+DWORD
+fhandler_proc::get_proc_fhandler (const char *path)
+{
+ debug_printf ("get_proc_fhandler(%s)", path);
+ path += proc_len;
+ /* Since this method is called from path_conv::check we can't rely on
+ * it being normalised and therefore the path may have runs of slashes
+ * in it.
+ */
+ while (SLASH_P (*path))
+ path++;
+
+ /* Check if this is the root of the virtual filesystem (i.e. /proc). */
+ if (*path == 0)
+ return FH_PROC;
+
+ for (int i = 0; proc_listing[i]; i++)
+ {
+ if (path_prefix_p (proc_listing[i], path, strlen (proc_listing[i])))
+ return proc_fhandlers[i];
+ }
+
+ if (pinfo (atoi (path)))
+ return FH_PROCESS;
+
+ bool has_subdir = false;
+ while (*path)
+ if (SLASH_P (*path++))
+ {
+ has_subdir = true;
+ break;
+ }
+
+ if (has_subdir)
+ /* The user is trying to access a non-existent subdirectory of /proc. */
+ return FH_BAD;
+ else
+ /* Return FH_PROC so that we can return EROFS if the user is trying to create
+ a file. */
+ return FH_PROC;
+}
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+ * <0 if path is a file.
+ */
+int
+fhandler_proc::exists ()
+{
+ const char *path = get_name ();
+ debug_printf ("exists (%s)", path);
+ path += proc_len;
+ if (*path == 0)
+ return 2;
+ for (int i = 0; proc_listing[i]; i++)
+ if (pathmatch (path + 1, proc_listing[i]))
+ return (proc_fhandlers[i] == FH_PROC) ? -1 : 1;
+ return 0;
+}
+
+fhandler_proc::fhandler_proc ():
+ fhandler_virtual (FH_PROC)
+{
+}
+
+fhandler_proc::fhandler_proc (DWORD devtype):
+ fhandler_virtual (devtype)
+{
+}
+
+int
+fhandler_proc::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ const char *path = get_name ();
+ debug_printf ("fstat (%s)", path);
+
+ path += proc_len;
+ (void) fhandler_base::fstat (buf, pc);
+
+ buf->st_mode &= ~_IFMT & NO_W;
+
+ if (!*path)
+ {
+ buf->st_nlink = PROC_LINK_COUNT;
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ return 0;
+ }
+ else
+ {
+ path++;
+ for (int i = 0; proc_listing[i]; i++)
+ if (pathmatch (path, proc_listing[i]))
+ {
+ if (proc_fhandlers[i] != FH_PROC)
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ else
+ {
+ buf->st_mode &= NO_X;
+ buf->st_mode |= S_IFREG;
+ }
+ return 0;
+ }
+ }
+ set_errno (ENOENT);
+ return -1;
+}
+
+struct dirent *
+fhandler_proc::readdir (DIR * dir)
+{
+ if (dir->__d_position >= PROC_LINK_COUNT)
+ {
+ winpids pids;
+ int found = 0;
+ for (unsigned i = 0; i < pids.npids; i++)
+ if (found++ == dir->__d_position - PROC_LINK_COUNT)
+ {
+ __small_sprintf (dir->__d_dirent->d_name, "%d", pids[i]->pid);
+ dir->__d_position++;
+ return dir->__d_dirent;
+ }
+ set_errno (ENMFILE);
+ return NULL;
+ }
+
+ strcpy (dir->__d_dirent->d_name, proc_listing[dir->__d_position++]);
+ syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir,
+ dir->__d_dirent->d_name);
+ return dir->__d_dirent;
+}
+
+int
+fhandler_proc::open (path_conv *pc, int flags, mode_t mode)
+{
+ int proc_file_no = -1;
+
+ int res = fhandler_virtual::open (pc, flags, mode);
+ if (!res)
+ goto out;
+
+ set_nohandle (true);
+
+ const char *path;
+
+ path = get_name () + proc_len;
+
+ if (!*path)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+
+ proc_file_no = -1;
+ for (int i = 0; proc_listing[i]; i++)
+ if (path_prefix_p (proc_listing[i], path + 1, strlen (proc_listing[i])))
+ {
+ proc_file_no = i;
+ if (proc_fhandlers[i] != FH_PROC)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+ }
+
+ if (proc_file_no == -1)
+ {
+ if (flags & O_CREAT)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+ }
+ if (flags & O_WRONLY)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+
+ fileid = proc_file_no;
+ if (!fill_filebuf ())
+ {
+ res = 0;
+ goto out;
+ }
+
+ if (flags & O_APPEND)
+ position = filesize;
+ else
+ position = 0;
+
+success:
+ res = 1;
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ set_open_status ();
+out:
+ syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode);
+ return res;
+}
+
+bool
+fhandler_proc::fill_filebuf ()
+{
+ switch (fileid)
+ {
+ case PROC_VERSION:
+ {
+ if (!filebuf)
+ {
+ struct utsname uts_name;
+ uname (&uts_name);
+ bufalloc = strlen (uts_name.sysname) + 1 + strlen (uts_name.release) +
+ 1 + strlen (uts_name.version) + 2;
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
+ filesize = __small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname,
+ uts_name.release, uts_name.version);
+ }
+ break;
+ }
+ case PROC_UPTIME:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 80);
+ filesize = format_proc_uptime (filebuf, bufalloc);
+ break;
+ }
+ case PROC_STAT:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_proc_stat (filebuf, bufalloc);
+ break;
+ }
+ case PROC_LOADAVG:
+ {
+ /*
+ * not really supported - Windows doesn't keep track of these values
+ * Windows 95/98/me does have the KERNEL/CPUUsage performance counter
+ * which is similar.
+ */
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 16);
+ filesize = __small_sprintf (filebuf, "%u.%02u %u.%02u %u.%02u\n",
+ 0, 0, 0, 0, 0, 0);
+ break;
+ }
+ case PROC_MEMINFO:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_proc_meminfo (filebuf, bufalloc);
+ break;
+ }
+ }
+ return true;
+}
+
+static
+off_t
+format_proc_meminfo (char *destbuf, size_t maxsize)
+{
+ unsigned long mem_total = 0UL, mem_free = 0UL, swap_total = 0UL,
+ swap_free = 0UL;
+ MEMORYSTATUS memory_status;
+ GlobalMemoryStatus (&memory_status);
+ mem_total = memory_status.dwTotalPhys;
+ mem_free = memory_status.dwAvailPhys;
+ swap_total = memory_status.dwTotalPageFile;
+ swap_free = memory_status.dwAvailPageFile;
+ return __small_sprintf (destbuf, " total: used: free:\n"
+ "Mem: %10lu %10lu %10lu\n"
+ "Swap: %10lu %10lu %10lu\n"
+ "MemTotal: %10lu kB\n"
+ "MemFree: %10lu kB\n"
+ "MemShared: 0 kB\n"
+ "HighTotal: 0 kB\n"
+ "HighFree: 0 kB\n"
+ "LowTotal: %10lu kB\n"
+ "LowFree: %10lu kB\n"
+ "SwapTotal: %10lu kB\n"
+ "SwapFree: %10lu kB\n",
+ mem_total, mem_total - mem_free, mem_free,
+ swap_total, swap_total - swap_free, swap_free,
+ mem_total >> 10, mem_free >> 10,
+ mem_total >> 10, mem_free >> 10,
+ swap_total >> 10, swap_free >> 10);
+}
+
+static
+off_t
+format_proc_uptime (char *destbuf, size_t maxsize)
+{
+ unsigned long long uptime = 0ULL, idle_time = 0ULL;
+ SYSTEM_PROCESSOR_TIMES spt;
+
+ NTSTATUS ret = NtQuerySystemInformation (SystemProcessorTimes, (PVOID) &spt,
+ sizeof spt, NULL);
+ if (!ret && GetLastError () == ERROR_PROC_NOT_FOUND)
+ uptime = GetTickCount () / 10;
+ else if (ret != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return 0;
+ }
+ else
+ {
+ idle_time = spt.IdleTime.QuadPart / 100000ULL;
+ uptime = (spt.KernelTime.QuadPart +
+ spt.UserTime.QuadPart) / 100000ULL;
+ }
+
+ return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
+ uptime / 100, long (uptime % 100),
+ idle_time / 100, long (idle_time % 100));
+}
+
+static
+off_t
+format_proc_stat (char *destbuf, size_t maxsize)
+{
+ unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
+ unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
+ context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
+ time_t boot_time = 0;
+
+ if (wincap.is_winnt ())
+ {
+ NTSTATUS ret;
+ SYSTEM_PROCESSOR_TIMES spt;
+ SYSTEM_PERFORMANCE_INFORMATION spi;
+ SYSTEM_TIME_OF_DAY_INFORMATION stodi;
+ ret = NtQuerySystemInformation (SystemProcessorTimes,
+ (PVOID) &spt,
+ sizeof spt, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemPerformanceInformation,
+ (PVOID) &spi,
+ sizeof spi, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemTimeOfDayInformation,
+ (PVOID) &stodi,
+ sizeof stodi, NULL);
+ if (ret != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return 0;
+ }
+ kernel_time = (spt.KernelTime.QuadPart - spt.IdleTime.QuadPart) * HZ / 10000000ULL;
+ user_time = spt.UserTime.QuadPart * HZ / 10000000ULL;
+ idle_time = spt.IdleTime.QuadPart * HZ / 10000000ULL;
+ interrupt_count = spt.InterruptCount;
+ pages_in = spi.PagesRead;
+ pages_out = spi.PagefilePagesWritten + spi.MappedFilePagesWritten;
+ /*
+ * Note: there is no distinction made in this structure between pages
+ * read from the page file and pages read from mapped files, but there
+ * is such a distinction made when it comes to writing. Goodness knows
+ * why. The value of swap_in, then, will obviously be wrong but its our
+ * best guess.
+ */
+ swap_in = spi.PagesRead;
+ swap_out = spi.PagefilePagesWritten;
+ context_switches = spi.ContextSwitches;
+ boot_time = to_time_t ((FILETIME *) &stodi.BootTime.QuadPart);
+ }
+ /*
+ * else
+ * {
+ * There are only two relevant performance counters on Windows 95/98/me,
+ * VMM/cPageIns and VMM/cPageOuts. The extra effort needed to read these
+ * counters is by no means worth it.
+ * }
+ */
+ return __small_sprintf (destbuf, "cpu %U %U %U %U\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u\n"
+ "ctxt %u\n"
+ "btime %u\n",
+ user_time, 0ULL,
+ kernel_time, idle_time,
+ pages_in, pages_out,
+ swap_in, swap_out,
+ interrupt_count,
+ context_switches,
+ boot_time);
+}
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
new file mode 100644
index 000000000..0633b0ebc
--- /dev/null
+++ b/winsup/cygwin/fhandler_process.cc
@@ -0,0 +1,743 @@
+/* fhandler_process.cc: fhandler for /proc/<pid> virtual filesystem
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <ntdef.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "pinfo.h"
+#include "path.h"
+#include "shared_info.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "ntdll.h"
+#include <sys/param.h>
+#include <assert.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+static const int PROCESS_PPID = 2;
+static const int PROCESS_EXENAME = 3;
+static const int PROCESS_WINPID = 4;
+static const int PROCESS_WINEXENAME = 5;
+static const int PROCESS_STATUS = 6;
+static const int PROCESS_UID = 7;
+static const int PROCESS_GID = 8;
+static const int PROCESS_PGID = 9;
+static const int PROCESS_SID = 10;
+static const int PROCESS_CTTY = 11;
+static const int PROCESS_STAT = 12;
+static const int PROCESS_STATM = 13;
+
+static const char * const process_listing[] =
+{
+ ".",
+ "..",
+ "ppid",
+ "exename",
+ "winpid",
+ "winexename",
+ "status",
+ "uid",
+ "gid",
+ "pgid",
+ "sid",
+ "ctty",
+ "stat",
+ "statm",
+ NULL
+};
+
+static const int PROCESS_LINK_COUNT =
+ (sizeof(process_listing) / sizeof(const char *)) - 1;
+
+static off_t format_process_stat (_pinfo *p, char *destbuf, size_t maxsize);
+static off_t format_process_status (_pinfo *p, char *destbuf, size_t maxsize);
+static off_t format_process_statm (_pinfo *p, char *destbuf, size_t maxsize);
+static int get_process_state (DWORD dwProcessId);
+static bool get_mem_values (DWORD dwProcessId, unsigned long *vmsize,
+ unsigned long *vmrss, unsigned long *vmtext,
+ unsigned long *vmdata, unsigned long *vmlib,
+ unsigned long *vmshare);
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+ * <0 if path is a file.
+ */
+int
+fhandler_process::exists ()
+{
+ const char *path = get_name ();
+ debug_printf ("exists (%s)", path);
+ path += proc_len + 1;
+ while (*path != 0 && !SLASH_P (*path))
+ path++;
+ if (*path == 0)
+ return 2;
+
+ for (int i = 0; process_listing[i]; i++)
+ if (pathmatch (path + 1, process_listing[i]))
+ return -1;
+ return 0;
+}
+
+fhandler_process::fhandler_process ():
+ fhandler_proc (FH_PROCESS)
+{
+}
+
+int
+fhandler_process::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ const char *path = get_name ();
+ int file_type = exists ();
+ (void) fhandler_base::fstat (buf, pc);
+ path += proc_len + 1;
+ pid = atoi (path);
+ pinfo p (pid);
+ if (!p)
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+
+ buf->st_mode &= ~_IFMT & NO_W;
+
+ switch (file_type)
+ {
+ case 0:
+ set_errno (ENOENT);
+ return -1;
+ case 1:
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ return 0;
+ case 2:
+ buf->st_ctime = buf->st_mtime = p->start_time;
+ buf->st_ctim.tv_nsec = buf->st_mtim.tv_nsec = 0;
+ time_as_timestruc_t (&buf->st_atim);
+ buf->st_uid = p->uid;
+ buf->st_gid = p->gid;
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ buf->st_nlink = PROCESS_LINK_COUNT;
+ return 0;
+ default:
+ case -1:
+ buf->st_uid = p->uid;
+ buf->st_gid = p->gid;
+ buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
+ return 0;
+ }
+}
+
+struct dirent *
+fhandler_process::readdir (DIR * dir)
+{
+ if (dir->__d_position >= PROCESS_LINK_COUNT)
+ {
+ set_errno (ENMFILE);
+ return NULL;
+ }
+ strcpy (dir->__d_dirent->d_name, process_listing[dir->__d_position++]);
+ syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir,
+ dir->__d_dirent->d_name);
+ return dir->__d_dirent;
+}
+
+int
+fhandler_process::open (path_conv *pc, int flags, mode_t mode)
+{
+ int process_file_no = -1;
+
+ int res = fhandler_virtual::open (pc, flags, mode);
+ if (!res)
+ goto out;
+
+ set_nohandle (true);
+
+ const char *path;
+ path = get_name () + proc_len + 1;
+ pid = atoi (path);
+ while (*path != 0 && !SLASH_P (*path))
+ path++;
+
+ if (*path == 0)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+
+ process_file_no = -1;
+ for (int i = 0; process_listing[i]; i++)
+ {
+ if (path_prefix_p
+ (process_listing[i], path + 1, strlen (process_listing[i])))
+ process_file_no = i;
+ }
+ if (process_file_no == -1)
+ {
+ if (flags & O_CREAT)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+ }
+ if (flags & O_WRONLY)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+
+ fileid = process_file_no;
+ if (!fill_filebuf ())
+ {
+ res = 0;
+ goto out;
+ }
+
+ if (flags & O_APPEND)
+ position = filesize;
+ else
+ position = 0;
+
+success:
+ res = 1;
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ set_open_status ();
+out:
+ syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode);
+ return res;
+}
+
+bool
+fhandler_process::fill_filebuf ()
+{
+ pinfo p (pid);
+
+ if (!p)
+ {
+ set_errno (ENOENT);
+ return false;
+ }
+
+ switch (fileid)
+ {
+ case PROCESS_UID:
+ case PROCESS_GID:
+ case PROCESS_PGID:
+ case PROCESS_SID:
+ case PROCESS_CTTY:
+ case PROCESS_PPID:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40);
+ int num;
+ switch (fileid)
+ {
+ case PROCESS_PPID:
+ num = p->ppid;
+ break;
+ case PROCESS_UID:
+ num = p->uid;
+ break;
+ case PROCESS_PGID:
+ num = p->pgid;
+ break;
+ case PROCESS_SID:
+ num = p->sid;
+ break;
+ case PROCESS_GID:
+ num = p->gid;
+ break;
+ case PROCESS_CTTY:
+ num = p->ctty;
+ break;
+ default: // what's this here for?
+ num = 0;
+ break;
+ }
+ __small_sprintf (filebuf, "%d\n", num);
+ filesize = strlen (filebuf);
+ break;
+ }
+ case PROCESS_EXENAME:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = MAX_PATH);
+ if (p->process_state & (PID_ZOMBIE | PID_EXITED))
+ strcpy (filebuf, "<defunct>");
+ else
+ {
+ mount_table->conv_to_posix_path (p->progname, filebuf, 1);
+ int len = strlen (filebuf);
+ if (len > 4)
+ {
+ char *s = filebuf + len - 4;
+ if (strcasecmp (s, ".exe") == 0)
+ *s = 0;
+ }
+ }
+ filesize = strlen (filebuf);
+ break;
+ }
+ case PROCESS_WINPID:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40);
+ __small_sprintf (filebuf, "%d\n", p->dwProcessId);
+ filesize = strlen (filebuf);
+ break;
+ }
+ case PROCESS_WINEXENAME:
+ {
+ int len = strlen (p->progname);
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = (len + 2));
+ strcpy (filebuf, p->progname);
+ filebuf[len] = '\n';
+ filesize = len + 1;
+ break;
+ }
+ case PROCESS_STATUS:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_process_status (*p, filebuf, bufalloc);
+ break;
+ }
+ case PROCESS_STAT:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_process_stat (*p, filebuf, bufalloc);
+ break;
+ }
+ case PROCESS_STATM:
+ {
+ if (!filebuf)
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048);
+ filesize = format_process_statm (*p, filebuf, bufalloc);
+ break;
+ }
+ }
+
+ return true;
+}
+
+static
+off_t
+format_process_stat (_pinfo *p, char *destbuf, size_t maxsize)
+{
+ char cmd[MAX_PATH];
+ int state = 'R';
+ unsigned long fault_count = 0UL,
+ utime = 0UL, stime = 0UL,
+ start_time = 0UL,
+ vmsize = 0UL, vmrss = 0UL, vmmaxrss = 0UL;
+ int priority = 0;
+ if (p->process_state & (PID_ZOMBIE | PID_EXITED))
+ strcpy (cmd, "<defunct>");
+ else
+ {
+ strcpy (cmd, p->progname);
+ char *last_slash = strrchr (cmd, '\\');
+ if (last_slash != NULL)
+ strcpy (cmd, last_slash + 1);
+ int len = strlen (cmd);
+ if (len > 4)
+ {
+ char *s = cmd + len - 4;
+ if (strcasecmp (s, ".exe") == 0)
+ *s = 0;
+ }
+ }
+ /*
+ * Note: under Windows, a _process_ is always running - it's only _threads_
+ * that get suspended. Therefore the default state is R (runnable).
+ */
+ if (p->process_state & PID_ZOMBIE)
+ state = 'Z';
+ else if (p->process_state & PID_STOPPED)
+ state = 'T';
+ else if (wincap.is_winnt ())
+ state = get_process_state (p->dwProcessId);
+ if (wincap.is_winnt ())
+ {
+ NTSTATUS ret;
+ HANDLE hProcess;
+ VM_COUNTERS vmc;
+ KERNEL_USER_TIMES put;
+ PROCESS_BASIC_INFORMATION pbi;
+ QUOTA_LIMITS ql;
+ SYSTEM_TIME_OF_DAY_INFORMATION stodi;
+ SYSTEM_PROCESSOR_TIMES spt;
+ hProcess = OpenProcess (PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
+ FALSE, p->dwProcessId);
+ if (hProcess != NULL)
+ {
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessVmCounters,
+ (PVOID) &vmc,
+ sizeof vmc, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessTimes,
+ (PVOID) &put,
+ sizeof put, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessBasicInformation,
+ (PVOID) &pbi,
+ sizeof pbi, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessQuotaLimits,
+ (PVOID) &ql,
+ sizeof ql, NULL);
+ CloseHandle (hProcess);
+ }
+ else
+ {
+ DWORD error = GetLastError ();
+ __seterrno_from_win_error (error);
+ debug_printf ("OpenProcess: ret = %d",
+ error);
+ return 0;
+ }
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemTimeOfDayInformation,
+ (PVOID) &stodi,
+ sizeof stodi, NULL);
+ if (ret == STATUS_SUCCESS)
+ ret = NtQuerySystemInformation (SystemProcessorTimes,
+ (PVOID) &spt,
+ sizeof spt, NULL);
+ if (ret != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf ("NtQueryInformationProcess: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return 0;
+ }
+ fault_count = vmc.PageFaultCount;
+ utime = put.UserTime.QuadPart * HZ / 10000000ULL;
+ stime = put.KernelTime.QuadPart * HZ / 10000000ULL;
+ if (stodi.CurrentTime.QuadPart > put.CreateTime.QuadPart)
+ start_time = (spt.KernelTime.QuadPart + spt.UserTime.QuadPart -
+ stodi.CurrentTime.QuadPart + put.CreateTime.QuadPart) * HZ / 10000000ULL;
+ else
+ /*
+ * sometimes stodi.CurrentTime is a bit behind
+ * Note: some older versions of procps are broken and can't cope
+ * with process start times > time(NULL).
+ */
+ start_time = (spt.KernelTime.QuadPart + spt.UserTime.QuadPart) * HZ / 10000000ULL;
+ priority = pbi.BasePriority;
+ unsigned page_size = getpagesize ();
+ vmsize = vmc.VirtualSize;
+ vmrss = vmc.WorkingSetSize / page_size;
+ vmmaxrss = ql.MaximumWorkingSetSize / page_size;
+ }
+ else
+ {
+ start_time = (GetTickCount() / 1000 - time(NULL) + p->start_time) * HZ;
+ }
+ return __small_sprintf (destbuf, "%d (%s) %c "
+ "%d %d %d %d %d "
+ "%lu %lu %lu %lu %lu %lu %lu "
+ "%ld %ld %ld %ld %ld %ld "
+ "%lu %lu "
+ "%ld "
+ "%lu",
+ p->pid, cmd,
+ state,
+ p->ppid, p->pgid, p->sid, p->ctty, -1,
+ 0, fault_count, fault_count, 0, 0, utime, stime,
+ utime, stime, priority, 0, 0, 0,
+ start_time, vmsize,
+ vmrss, vmmaxrss
+ );
+}
+
+static
+off_t
+format_process_status (_pinfo *p, char *destbuf, size_t maxsize)
+{
+ char cmd[MAX_PATH];
+ int state = 'R';
+ const char *state_str = "unknown";
+ unsigned long vmsize = 0UL, vmrss = 0UL, vmdata = 0UL, vmlib = 0UL, vmtext = 0UL,
+ vmshare = 0UL;
+ if (p->process_state & (PID_ZOMBIE | PID_EXITED))
+ strcpy (cmd, "<defunct>");
+ else
+ {
+ strcpy (cmd, p->progname);
+ char *last_slash = strrchr (cmd, '\\');
+ if (last_slash != NULL)
+ strcpy (cmd, last_slash + 1);
+ int len = strlen (cmd);
+ if (len > 4)
+ {
+ char *s = cmd + len - 4;
+ if (strcasecmp (s, ".exe") == 0)
+ *s = 0;
+ }
+ }
+ /*
+ * Note: under Windows, a _process_ is always running - it's only _threads_
+ * that get suspended. Therefore the default state is R (runnable).
+ */
+ if (p->process_state & PID_ZOMBIE)
+ state = 'Z';
+ else if (p->process_state & PID_STOPPED)
+ state = 'T';
+ else if (wincap.is_winnt ())
+ state = get_process_state (p->dwProcessId);
+ switch (state)
+ {
+ case 'O':
+ state_str = "running";
+ break;
+ case 'D':
+ case 'S':
+ state_str = "sleeping";
+ break;
+ case 'R':
+ state_str = "runnable";
+ break;
+ case 'Z':
+ state_str = "zombie";
+ break;
+ case 'T':
+ state_str = "stopped";
+ break;
+ }
+ if (wincap.is_winnt ())
+ {
+ if (!get_mem_values (p->dwProcessId, &vmsize, &vmrss, &vmtext, &vmdata, &vmlib, &vmshare))
+ return 0;
+ unsigned page_size = getpagesize ();
+ vmsize *= page_size; vmrss *= page_size; vmdata *= page_size;
+ vmtext *= page_size; vmlib *= page_size;
+ }
+ return __small_sprintf (destbuf, "Name: %s\n"
+ "State: %c (%s)\n"
+ "Tgid: %d\n"
+ "Pid: %d\n"
+ "PPid: %d\n"
+ "Uid: %d %d %d %d\n"
+ "Gid: %d %d %d %d\n"
+ "VmSize: %8d kB\n"
+ "VmLck: %8d kB\n"
+ "VmRSS: %8d kB\n"
+ "VmData: %8d kB\n"
+ "VmStk: %8d kB\n"
+ "VmExe: %8d kB\n"
+ "VmLib: %8d kB\n"
+ "SigPnd: %016x\n"
+ "SigBlk: %016x\n"
+ "SigIgn: %016x\n",
+ cmd,
+ state, state_str,
+ p->pgid,
+ p->pid,
+ p->ppid,
+ p->uid, cygheap->user.real_uid, cygheap->user.real_uid, p->uid,
+ p->gid, cygheap->user.real_gid, cygheap->user.real_gid, p->gid,
+ vmsize >> 10, 0, vmrss >> 10, vmdata >> 10, 0, vmtext >> 10, vmlib >> 10,
+ 0, 0, p->getsigmask ()
+ );
+}
+
+static
+off_t
+format_process_statm (_pinfo *p, char *destbuf, size_t maxsize)
+{
+ unsigned long vmsize = 0UL, vmrss = 0UL, vmtext = 0UL, vmdata = 0UL,
+ vmlib = 0UL, vmshare = 0UL;
+ if (wincap.is_winnt ())
+ {
+ if (!get_mem_values (p->dwProcessId, &vmsize, &vmrss, &vmtext, &vmdata,
+ &vmlib, &vmshare))
+ return 0;
+ }
+ return __small_sprintf (destbuf, "%ld %ld %ld %ld %ld %ld %ld",
+ vmsize, vmrss, vmshare, vmtext, vmlib, vmdata, 0
+ );
+}
+
+static
+int
+get_process_state (DWORD dwProcessId)
+{
+ /*
+ * This isn't really heavy magic - just go through the processes'
+ * threads one by one and return a value accordingly
+ * Errors are silently ignored.
+ */
+ NTSTATUS ret;
+ SYSTEM_PROCESSES *sp;
+ ULONG n = 0x1000;
+ PULONG p = new ULONG[n];
+ int state =' ';
+ while (STATUS_INFO_LENGTH_MISMATCH ==
+ (ret = NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
+ (PVOID) p,
+ n * sizeof *p, NULL)))
+ delete [] p, p = new ULONG[n *= 2];
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf ("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ goto out;
+ }
+ state = 'Z';
+ sp = (SYSTEM_PROCESSES *) p;
+ for (;;)
+ {
+ if (sp->ProcessId == dwProcessId)
+ {
+ SYSTEM_THREADS *st;
+ if (wincap.has_process_io_counters ())
+ /*
+ * Windows 2000 and XP have an extra member in SYSTEM_PROCESSES
+ * which means the offset of the first SYSTEM_THREADS entry is
+ * different on these operating systems compared to NT 4.
+ */
+ st = &sp->Threads[0];
+ else
+ /*
+ * 136 is the offset of the first SYSTEM_THREADS entry on
+ * Windows NT 4.
+ */
+ st = (SYSTEM_THREADS *) ((char *) sp + 136);
+ state = 'S';
+ for (unsigned i = 0; i < sp->ThreadCount; i++)
+ {
+ if (st->State == StateRunning ||
+ st->State == StateReady)
+ {
+ state = 'R';
+ goto out;
+ }
+ st++;
+ }
+ break;
+ }
+ if (!sp->NextEntryDelta)
+ break;
+ sp = (SYSTEM_PROCESSES *) ((char *) sp + sp->NextEntryDelta);
+ }
+out:
+ delete [] p;
+ return state;
+}
+
+static
+bool
+get_mem_values (DWORD dwProcessId, unsigned long *vmsize, unsigned long *vmrss,
+ unsigned long *vmtext, unsigned long *vmdata,
+ unsigned long *vmlib, unsigned long *vmshare)
+{
+ bool res = true;
+ NTSTATUS ret;
+ HANDLE hProcess;
+ VM_COUNTERS vmc;
+ MEMORY_WORKING_SET_LIST *mwsl;
+ ULONG n = 0x1000, length;
+ PULONG p = new ULONG[n];
+ unsigned page_size = getpagesize ();
+ hProcess = OpenProcess (PROCESS_QUERY_INFORMATION,
+ FALSE, dwProcessId);
+ if (hProcess == NULL)
+ {
+ DWORD error = GetLastError ();
+ __seterrno_from_win_error (error);
+ debug_printf ("OpenProcess: ret = %d",
+ error);
+ return false;
+ }
+ while ((ret = NtQueryVirtualMemory (hProcess, 0,
+ MemoryWorkingSetList,
+ (PVOID) p,
+ n * sizeof *p, &length)),
+ (ret == STATUS_SUCCESS || ret == STATUS_INFO_LENGTH_MISMATCH) &&
+ length >= n * sizeof *p)
+ delete [] p, p = new ULONG[n *= 2];
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf ("NtQueryVirtualMemory: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ res = false;
+ goto out;
+ }
+ mwsl = (MEMORY_WORKING_SET_LIST *) p;
+ for (unsigned long i = 0; i < mwsl->NumberOfPages; i++)
+ {
+ ++*vmrss;
+ unsigned flags = mwsl->WorkingSetList[i] & 0x0FFF;
+ if (flags & (WSLE_PAGE_EXECUTE | WSLE_PAGE_SHAREABLE) == (WSLE_PAGE_EXECUTE | WSLE_PAGE_SHAREABLE))
+ ++*vmlib;
+ else if (flags & WSLE_PAGE_SHAREABLE)
+ ++*vmshare;
+ else if (flags & WSLE_PAGE_EXECUTE)
+ ++*vmtext;
+ else
+ ++*vmdata;
+ }
+ ret = NtQueryInformationProcess (hProcess,
+ ProcessVmCounters,
+ (PVOID) &vmc,
+ sizeof vmc, NULL);
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf ("NtQueryInformationProcess: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ res = false;
+ goto out;
+ }
+ *vmsize = vmc.VirtualSize / page_size;
+out:
+ delete [] p;
+ CloseHandle (hProcess);
+ return res;
+}
diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc
index 71e9d5822..2447b4e78 100644
--- a/winsup/cygwin/fhandler_random.cc
+++ b/winsup/cygwin/fhandler_random.cc
@@ -1,6 +1,6 @@
/* fhandler_random.cc: code to access /dev/random and /dev/urandom
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
Written by Corinna Vinschen (vinschen@cygnus.com)
@@ -23,18 +23,16 @@ details. */
#define PSEUDO_MULTIPLIER (6364136223846793005LL)
#define PSEUDO_SHIFTVAL (21)
-fhandler_dev_random::fhandler_dev_random (const char *name, int nunit)
- : fhandler_base (FH_RANDOM, name),
- unit(nunit),
- crypt_prov((HCRYPTPROV)NULL)
+fhandler_dev_random::fhandler_dev_random (int nunit)
+ : fhandler_base (FH_RANDOM), unit (nunit), crypt_prov ((HCRYPTPROV) NULL)
{
- set_cb (sizeof *this);
}
int
-fhandler_dev_random::open (const char *, int flags, mode_t)
+fhandler_dev_random::open (path_conv *, int flags, mode_t)
{
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ set_nohandle (true);
set_open_status ();
return 1;
}
@@ -112,7 +110,7 @@ fhandler_dev_random::pseudo_read (void *ptr, size_t len)
return len;
}
-int
+int __stdcall
fhandler_dev_random::read (void *ptr, size_t len)
{
if (!len)
@@ -135,8 +133,8 @@ fhandler_dev_random::read (void *ptr, size_t len)
return -1;
}
-off_t
-fhandler_dev_random::lseek (off_t, int)
+__off64_t
+fhandler_dev_random::lseek (__off64_t, int)
{
return 0;
}
@@ -147,7 +145,7 @@ fhandler_dev_random::close (void)
if (crypt_prov)
while (!CryptReleaseContext (crypt_prov, 0)
&& GetLastError () == ERROR_BUSY)
- Sleep(10);
+ Sleep (10);
return 0;
}
@@ -163,6 +161,6 @@ fhandler_dev_random::dup (fhandler_base *child)
void
fhandler_dev_random::dump ()
{
- paranoid_printf("here, fhandler_dev_random");
+ paranoid_printf ("here, fhandler_dev_random");
}
diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc
index 20f2de513..2b8470a36 100644
--- a/winsup/cygwin/fhandler_raw.cc
+++ b/winsup/cygwin/fhandler_raw.cc
@@ -1,6 +1,6 @@
/* fhandler_raw.cc. See fhandler.h for a description of the fhandler classes.
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -10,12 +10,12 @@
#include "winsup.h"
#include <sys/termios.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <cygwin/rdevio.h>
#include <sys/mtio.h>
+#include <ntdef.h>
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
@@ -23,6 +23,7 @@
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
+#include "ntdll.h"
/* static wrapper functions to hide the effect of media changes and
bus resets which occurs after a new media is inserted. This is
@@ -55,7 +56,7 @@ static BOOL read_file (HANDLE fh, void *buf, DWORD to_read,
BOOL ret;
*err = 0;
- if (!(ret = ReadFile(fh, buf, to_read, read, 0)))
+ if (!(ret = ReadFile (fh, buf, to_read, read, 0)))
{
if ((*err = GetLastError ()) == ERROR_MEDIA_CHANGED
|| *err == ERROR_BUS_RESET)
@@ -84,7 +85,6 @@ fhandler_dev_raw::clear (void)
eof_detected = 0;
lastblk_to_read = 0;
varblkop = 0;
- unit = 0;
}
int
@@ -116,10 +116,10 @@ fhandler_dev_raw::writebuf (void)
return ret;
}
-fhandler_dev_raw::fhandler_dev_raw (DWORD devtype, const char *name, int unit) : fhandler_base (devtype, name)
+fhandler_dev_raw::fhandler_dev_raw (DWORD devtype, int nunit)
+ : fhandler_base (devtype), unit (nunit)
{
clear ();
- this->unit = unit;
set_need_fork_fixup ();
}
@@ -131,25 +131,56 @@ fhandler_dev_raw::~fhandler_dev_raw (void)
}
int
-fhandler_dev_raw::open (const char *path, int flags, mode_t)
+fhandler_dev_raw::open (path_conv *real_path, int flags, mode_t)
{
- path_conv real_path (path, PC_SYM_IGNORE);
- int ret;
+ if (!wincap.has_raw_devices ())
+ {
+ set_errno (ENOENT);
+ debug_printf ("%s is accessible under NT/W2K only",real_path->get_win32());
+ return 0;
+ }
- set_name (path, real_path.get_win32 ());
+ /* Check for illegal flags. */
+ if (flags & (O_APPEND | O_EXCL))
+ {
+ set_errno (EINVAL);
+ return 0;
+ }
/* Always open a raw device existing and binary. */
flags &= ~(O_CREAT | O_TRUNC);
flags |= O_BINARY;
- ret = fhandler_base::open (path, flags);
- if (ret)
+
+ DWORD access = GENERIC_READ | SYNCHRONIZE;
+ if (get_device () == FH_TAPE
+ || (flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY
+ || (flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDWR)
+ access |= GENERIC_WRITE;
+
+ extern void str2buf2uni (UNICODE_STRING &, WCHAR *, const char *);
+ UNICODE_STRING dev;
+ WCHAR devname[MAX_PATH + 1];
+ str2buf2uni (dev, devname, real_path->get_win32 ());
+ OBJECT_ATTRIBUTES attr;
+ InitializeObjectAttributes (&attr, &dev, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ HANDLE h;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status = NtOpenFile (&h, access, &attr, &io, wincap.shared (),
+ FILE_SYNCHRONOUS_IO_NONALERT);
+ if (!NT_SUCCESS (status))
{
- if (devbufsiz > 1L)
- devbuf = new char [devbufsiz];
+ __seterrno_from_win_error (RtlNtStatusToDosError (status));
+ return 0;
}
- else
- devbufsiz = 0;
- return ret;
+
+ set_io_handle (h);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+
+ if (devbufsiz > 1L)
+ devbuf = new char [devbufsiz];
+
+ return 1;
}
int
@@ -159,27 +190,6 @@ fhandler_dev_raw::close (void)
}
int
-fhandler_dev_raw::fstat (struct stat *buf)
-{
- if (!buf)
- {
- set_errno (EINVAL);
- return -1;
- }
-
- memset (buf, 0, sizeof *buf);
- buf->st_mode = S_IFCHR |
- S_IRUSR | S_IWUSR |
- S_IRGRP | S_IWGRP |
- S_IROTH | S_IWOTH;
- buf->st_nlink = 1;
- buf->st_blksize = devbuf ? devbufsiz : 1;
- buf->st_dev = buf->st_rdev = get_device () << 8 | (unit & 0xff);
-
- return 0;
-}
-
-int
fhandler_dev_raw::raw_read (void *ptr, size_t ulen)
{
DWORD bytes_read = 0;
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
new file mode 100644
index 000000000..f2e5e2145
--- /dev/null
+++ b/winsup/cygwin/fhandler_registry.cc
@@ -0,0 +1,673 @@
+/* fhandler_registry.cc: fhandler for /proc/registry virtual filesystem
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/* FIXME: Access permissions are ignored at the moment. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <assert.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+static const int registry_len = sizeof ("registry") - 1;
+/* If this bit is set in __d_position then we are enumerating values,
+ * else sub-keys. keeping track of where we are is horribly messy
+ * the bottom 16 bits are the absolute position and the top 15 bits
+ * make up the value index if we are enuerating values.
+ */
+static const __off32_t REG_ENUM_VALUES_MASK = 0x8000000;
+static const __off32_t REG_POSITION_MASK = 0xffff;
+
+/* List of root keys in /proc/registry.
+ * Possibly we should filter out those not relevant to the flavour of Windows
+ * Cygwin is running on.
+ */
+static const char *registry_listing[] =
+{
+ ".",
+ "..",
+ "HKEY_CLASSES_ROOT",
+ "HKEY_CURRENT_CONFIG",
+ "HKEY_CURRENT_USER",
+ "HKEY_LOCAL_MACHINE",
+ "HKEY_USERS",
+ "HKEY_DYN_DATA", // 95/98/Me
+ "HKEY_PERFOMANCE_DATA", // NT/2000/XP
+ NULL
+};
+
+static const HKEY registry_keys[] =
+{
+ (HKEY) INVALID_HANDLE_VALUE,
+ (HKEY) INVALID_HANDLE_VALUE,
+ HKEY_CLASSES_ROOT,
+ HKEY_CURRENT_CONFIG,
+ HKEY_CURRENT_USER,
+ HKEY_LOCAL_MACHINE,
+ HKEY_USERS,
+ HKEY_DYN_DATA,
+ HKEY_PERFORMANCE_DATA
+};
+
+static const int ROOT_KEY_COUNT = sizeof (registry_keys) / sizeof (HKEY);
+
+/* These get added to each subdirectory in /proc/registry.
+ * If we wanted to implement writing, we could maybe add a '.writable' entry or
+ * suchlike.
+ */
+static const char *special_dot_files[] =
+{
+ ".",
+ "..",
+ NULL
+};
+
+static const int SPECIAL_DOT_FILE_COUNT =
+ (sizeof (special_dot_files) / sizeof (const char *)) - 1;
+
+/* Name given to default values */
+static const char *DEFAULT_VALUE_NAME = "@";
+
+static HKEY open_key (const char *name, REGSAM access, bool isValue);
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+ * <0 if path is a file.
+ *
+ * We open the last key but one and then enum it's sub-keys and values to see if the
+ * final component is there. This gets round the problem of not having security access
+ * to the final key in the path.
+ */
+int
+fhandler_registry::exists ()
+{
+ int file_type = 0, index = 0, pathlen;
+ DWORD buf_size = MAX_PATH;
+ LONG error;
+ char buf[buf_size];
+ const char *file;
+ HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
+
+ const char *path = get_name ();
+ debug_printf ("exists (%s)", path);
+ path += proc_len + registry_len + 2;
+ if (*path == 0)
+ {
+ file_type = 2;
+ goto out;
+ }
+ pathlen = strlen (path);
+ file = path + pathlen - 1;
+ if (SLASH_P (*file) && pathlen > 1)
+ file--;
+ while (!SLASH_P (*file))
+ file--;
+ file++;
+
+ if (file == path)
+ {
+ for (int i = 0; registry_listing[i]; i++)
+ if (path_prefix_p
+ (registry_listing[i], path, strlen (registry_listing[i])))
+ {
+ file_type = 1;
+ goto out;
+ }
+ goto out;
+ }
+
+ hKey = open_key (path, KEY_READ, false);
+ if (hKey != (HKEY) INVALID_HANDLE_VALUE)
+ file_type = 1;
+ else
+ {
+ hKey = open_key (path, KEY_READ, true);
+ if (hKey == (HKEY) INVALID_HANDLE_VALUE)
+ return 0;
+
+ while (ERROR_SUCCESS ==
+ (error = RegEnumKeyEx (hKey, index++, buf, &buf_size, NULL, NULL,
+ NULL, NULL))
+ || (error == ERROR_MORE_DATA))
+ {
+ if (pathmatch (buf, file))
+ {
+ file_type = 1;
+ goto out;
+ }
+ buf_size = MAX_PATH;
+ }
+ if (error != ERROR_NO_MORE_ITEMS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ goto out;
+ }
+ index = 0;
+ buf_size = MAX_PATH;
+ while (ERROR_SUCCESS ==
+ (error = RegEnumValue (hKey, index++, buf, &buf_size, NULL, NULL,
+ NULL, NULL))
+ || (error == ERROR_MORE_DATA))
+ {
+ if (pathmatch (buf, file) || (buf[0] == '\0' &&
+ pathmatch (file, DEFAULT_VALUE_NAME)))
+ {
+ file_type = -1;
+ goto out;
+ }
+ buf_size = MAX_PATH;
+ }
+ if (error != ERROR_NO_MORE_ITEMS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ goto out;
+ }
+ }
+out:
+ if (hKey != (HKEY) INVALID_HANDLE_VALUE)
+ RegCloseKey (hKey);
+ return file_type;
+}
+
+fhandler_registry::fhandler_registry ():
+fhandler_proc (FH_REGISTRY)
+{
+}
+
+int
+fhandler_registry::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ this->fhandler_base::fstat (buf, pc);
+ buf->st_mode &= ~_IFMT & NO_W;
+ int file_type = exists ();
+ switch (file_type)
+ {
+ case 0:
+ set_errno (ENOENT);
+ return -1;
+ case 1:
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ break;
+ case 2:
+ buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ buf->st_nlink = ROOT_KEY_COUNT;
+ break;
+ default:
+ case -1:
+ buf->st_mode |= S_IFREG;
+ buf->st_mode &= NO_X;
+ break;
+ }
+ if (file_type != 0 && file_type != 2)
+ {
+ HKEY hKey;
+ const char *path = get_name () + proc_len + registry_len + 2;
+ hKey =
+ open_key (path, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE,
+ (file_type < 0) ? true : false);
+
+ if (hKey != (HKEY) INVALID_HANDLE_VALUE)
+ {
+ FILETIME ftLastWriteTime;
+ DWORD subkey_count;
+ if (ERROR_SUCCESS ==
+ RegQueryInfoKey (hKey, NULL, NULL, NULL, &subkey_count, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ &ftLastWriteTime))
+ {
+ to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
+ buf->st_ctim = buf->st_mtim;
+ time_as_timestruc_t (&buf->st_atim);
+ if (file_type > 0)
+ buf->st_nlink = subkey_count;
+ else
+ {
+ int pathlen = strlen (path);
+ const char *value_name = path + pathlen - 1;
+ if (SLASH_P (*value_name) && pathlen > 1)
+ value_name--;
+ while (!SLASH_P (*value_name))
+ value_name--;
+ value_name++;
+ DWORD dwSize;
+ if (ERROR_SUCCESS ==
+ RegQueryValueEx (hKey, value_name, NULL, NULL, NULL,
+ &dwSize))
+ buf->st_size = dwSize;
+ }
+ __uid32_t uid;
+ __gid32_t gid;
+ if (get_object_attribute
+ ((HANDLE) hKey, SE_REGISTRY_KEY, &buf->st_mode, &uid,
+ &gid) == 0)
+ {
+ buf->st_uid = uid;
+ buf->st_gid = gid;
+ buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ if (file_type > 0)
+ buf->st_mode |= S_IFDIR;
+ else
+ buf->st_mode &= NO_X;
+ }
+ }
+ RegCloseKey (hKey);
+ }
+ }
+ return 0;
+}
+
+struct dirent *
+fhandler_registry::readdir (DIR * dir)
+{
+ DWORD buf_size = MAX_PATH;
+ char buf[buf_size];
+ HANDLE handle;
+ struct dirent *res = NULL;
+ const char *path = dir->__d_dirname + proc_len + 1 + registry_len;
+ LONG error;
+
+ if (*path == 0)
+ {
+ if (dir->__d_position >= ROOT_KEY_COUNT)
+ goto out;
+ strcpy (dir->__d_dirent->d_name, registry_listing[dir->__d_position++]);
+ res = dir->__d_dirent;
+ goto out;
+ }
+ if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE
+ && dir->__d_position == 0)
+ {
+ handle = open_key (path + 1, KEY_READ, false);
+ dir->__d_u.__d_data.__handle = handle;
+ }
+ if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE)
+ goto out;
+ if (dir->__d_position < SPECIAL_DOT_FILE_COUNT)
+ {
+ strcpy (dir->__d_dirent->d_name,
+ special_dot_files[dir->__d_position++]);
+ res = dir->__d_dirent;
+ goto out;
+ }
+retry:
+ if (dir->__d_position & REG_ENUM_VALUES_MASK)
+ /* For the moment, the type of key is ignored here. when write access is added,
+ * maybe add an extension for the type of each value?
+ */
+ error = RegEnumValue ((HKEY) dir->__d_u.__d_data.__handle,
+ (dir->__d_position & ~REG_ENUM_VALUES_MASK) >> 16,
+ buf, &buf_size, NULL, NULL, NULL, NULL);
+ else
+ error =
+ RegEnumKeyEx ((HKEY) dir->__d_u.__d_data.__handle, dir->__d_position -
+ SPECIAL_DOT_FILE_COUNT, buf, &buf_size, NULL, NULL, NULL,
+ NULL);
+ if (error == ERROR_NO_MORE_ITEMS
+ && (dir->__d_position & REG_ENUM_VALUES_MASK) == 0)
+ {
+ /* If we're finished with sub-keys, start on values under this key. */
+ dir->__d_position |= REG_ENUM_VALUES_MASK;
+ buf_size = MAX_PATH;
+ goto retry;
+ }
+ if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
+ {
+ RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle);
+ dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ goto out;
+ }
+
+ /* We get here if `buf' contains valid data. */
+ if (*buf == 0)
+ strcpy (dir->__d_dirent->d_name, DEFAULT_VALUE_NAME);
+ else
+ strcpy (dir->__d_dirent->d_name, buf);
+
+ dir->__d_position++;
+ if (dir->__d_position & REG_ENUM_VALUES_MASK)
+ dir->__d_position += 0x10000;
+ res = dir->__d_dirent;
+out:
+ syscall_printf ("%p = readdir (%p)", &dir->__d_dirent, dir);
+ return res;
+}
+
+__off64_t
+fhandler_registry::telldir (DIR * dir)
+{
+ return dir->__d_position & REG_POSITION_MASK;
+}
+
+void
+fhandler_registry::seekdir (DIR * dir, __off64_t loc)
+{
+ /* Unfortunately cannot simply set __d_position due to transition from sub-keys to
+ * values.
+ */
+ rewinddir (dir);
+ while (loc > (dir->__d_position & REG_POSITION_MASK))
+ if (!readdir (dir))
+ break;
+}
+
+void
+fhandler_registry::rewinddir (DIR * dir)
+{
+ if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE)
+ {
+ (void) RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle);
+ dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
+ }
+ dir->__d_position = 0;
+ return;
+}
+
+int
+fhandler_registry::closedir (DIR * dir)
+{
+ int res = 0;
+ if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE &&
+ RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle) != ERROR_SUCCESS)
+ {
+ __seterrno ();
+ res = -1;
+ }
+ syscall_printf ("%d = closedir (%p)", res, dir);
+ return 0;
+}
+
+int
+fhandler_registry::open (path_conv * pc, int flags, mode_t mode)
+{
+ int pathlen;
+ const char *file;
+ HKEY handle;
+
+ int res = fhandler_virtual::open (pc, flags, mode);
+ if (!res)
+ goto out;
+
+ const char *path;
+ path = get_name () + proc_len + 1 + registry_len;
+ if (!*path)
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+ path++;
+ pathlen = strlen (path);
+ file = path + pathlen - 1;
+ if (SLASH_P (*file) && pathlen > 1)
+ file--;
+ while (!SLASH_P (*file))
+ file--;
+ file++;
+
+ if (file == path)
+ {
+ for (int i = 0; registry_listing[i]; i++)
+ if (path_prefix_p
+ (registry_listing[i], path, strlen (registry_listing[i])))
+ {
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ {
+ set_errno (EEXIST);
+ res = 0;
+ goto out;
+ }
+ else if (flags & O_WRONLY)
+ {
+ set_errno (EISDIR);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ flags |= O_DIROPEN;
+ goto success;
+ }
+ }
+
+ if (flags & O_CREAT)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+ else
+ {
+ set_errno (ENOENT);
+ res = 0;
+ goto out;
+ }
+ }
+
+ if (flags & O_WRONLY)
+ {
+ set_errno (EROFS);
+ res = 0;
+ goto out;
+ }
+
+ handle = open_key (path, KEY_READ, true);
+ if (handle == (HKEY) INVALID_HANDLE_VALUE)
+ {
+ res = 0;
+ goto out;
+ }
+
+ set_io_handle (handle);
+
+ if (pathmatch (file, DEFAULT_VALUE_NAME))
+ value_name = cstrdup ("");
+ else
+ value_name = cstrdup (file);
+
+ if (!fill_filebuf ())
+ {
+ RegCloseKey (handle);
+ res = 0;
+ goto out;
+ }
+
+ if (flags & O_APPEND)
+ position = filesize;
+ else
+ position = 0;
+
+success:
+ res = 1;
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ set_open_status ();
+out:
+ syscall_printf ("%d = fhandler_registry::open (%p, %d)", res, flags, mode);
+ return res;
+}
+
+int
+fhandler_registry::close ()
+{
+ int res = fhandler_virtual::close ();
+ if (res != 0)
+ return res;
+ HKEY handle = (HKEY) get_handle ();
+ if (handle != (HKEY) INVALID_HANDLE_VALUE)
+ {
+ if (RegCloseKey (handle) != ERROR_SUCCESS)
+ {
+ __seterrno ();
+ res = -1;
+ }
+ }
+ if (value_name)
+ cfree (value_name);
+ return res;
+}
+
+bool
+fhandler_registry::fill_filebuf ()
+{
+ DWORD type, size;
+ LONG error;
+ HKEY handle = (HKEY) get_handle ();
+ if (handle != HKEY_PERFORMANCE_DATA)
+ {
+ error = RegQueryValueEx (handle, value_name, NULL, &type, NULL, &size);
+ if (error != ERROR_SUCCESS)
+ {
+ if (error != ERROR_FILE_NOT_FOUND)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ return false;
+ }
+ goto value_not_found;
+ }
+ bufalloc = size;
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
+ error =
+ RegQueryValueEx (handle, value_name, NULL, NULL, (BYTE *) filebuf,
+ &size);
+ if (error != ERROR_SUCCESS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ return true;
+ }
+ filesize = size;
+ }
+ else
+ {
+ bufalloc = 0;
+ do
+ {
+ bufalloc += 1000;
+ if (filebuf)
+ {
+ cfree (filebuf);
+ filebuf = (char *) cmalloc (HEAP_BUF, bufalloc);
+ }
+ error =
+ RegQueryValueEx (handle, value_name, NULL, &type,
+ (BYTE *) filebuf, &size);
+ if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA)
+ {
+ if (error != ERROR_FILE_NOT_FOUND)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ return true;
+ }
+ goto value_not_found;
+ }
+ }
+ while (error == ERROR_MORE_DATA);
+ filesize = size;
+ }
+ return true;
+value_not_found:
+ DWORD buf_size = MAX_PATH;
+ char buf[buf_size];
+ int index = 0;
+ while (ERROR_SUCCESS ==
+ (error = RegEnumKeyEx (handle, index++, buf, &buf_size, NULL, NULL,
+ NULL, NULL)) || (error == ERROR_MORE_DATA))
+ {
+ if (pathmatch (buf, value_name))
+ {
+ set_errno (EISDIR);
+ return false;
+ }
+ buf_size = MAX_PATH;
+ }
+ if (error != ERROR_NO_MORE_ITEMS)
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ return false;
+ }
+ set_errno (ENOENT);
+ return false;
+}
+
+/* Auxillary member function to open registry keys. */
+static HKEY
+open_key (const char *name, REGSAM access, bool isValue)
+{
+ HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
+ HKEY hParentKey = (HKEY) INVALID_HANDLE_VALUE;
+ bool parentOpened = false;
+ char component[MAX_PATH];
+
+ while (*name)
+ {
+ const char *anchor = name;
+ while (*name && !SLASH_P (*name))
+ name++;
+ strncpy (component, anchor, name - anchor);
+ component[name - anchor] = '\0';
+ if (*name)
+ name++;
+ if (*name == 0 && isValue == true)
+ goto out;
+
+ if (hParentKey != (HKEY) INVALID_HANDLE_VALUE)
+ {
+ REGSAM effective_access = KEY_READ;
+ if ((strchr (name, '/') == NULL && isValue == true) || *name == 0)
+ effective_access = access;
+ LONG
+ error =
+ RegOpenKeyEx (hParentKey, component, 0, effective_access, &hKey);
+ if (error != ERROR_SUCCESS)
+ {
+ hKey = (HKEY) INVALID_HANDLE_VALUE;
+ seterrno_from_win_error (__FILE__, __LINE__, error);
+ return hKey;
+ }
+ if (parentOpened)
+ RegCloseKey (hParentKey);
+ hParentKey = hKey;
+ parentOpened = true;
+ }
+ else
+ {
+ for (int i = 0; registry_listing[i]; i++)
+ if (pathmatch (component, registry_listing[i]))
+ hKey = registry_keys[i];
+ if (hKey == (HKEY) INVALID_HANDLE_VALUE)
+ return hKey;
+ hParentKey = hKey;
+ }
+ }
+out:
+ return hKey;
+}
diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc
index 20ad4d8e1..748eb4b28 100644
--- a/winsup/cygwin/fhandler_serial.cc
+++ b/winsup/cygwin/fhandler_serial.cc
@@ -1,6 +1,6 @@
/* fhandler_serial.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,14 +9,12 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include <sys/termios.h>
@@ -24,13 +22,9 @@ details. */
/**********************************************************************/
/* fhandler_serial */
-fhandler_serial::fhandler_serial (const char *name, DWORD devtype, int unit) :
- fhandler_base (devtype, name, unit)
+fhandler_serial::fhandler_serial (int unit)
+ : fhandler_base (FH_SERIAL, unit), vmin_ (0), vtime_ (0), pgrp_ (myself->pgid)
{
- set_cb (sizeof *this);
- vmin_ = 0;
- vtime_ = 0;
- pgrp_ = myself->pgid;
set_need_fork_fixup ();
}
@@ -64,7 +58,6 @@ fhandler_serial::raw_read (void *ptr, size_t ulen)
for (n = 0, tot = 0; ulen; ulen -= n, ptr = (char *)ptr + n)
{
- DWORD ev;
COMSTAT st;
DWORD inq = 1;
@@ -125,7 +118,7 @@ fhandler_serial::raw_read (void *ptr, size_t ulen)
if (inq > ulen)
inq = ulen;
debug_printf ("inq %d", inq);
- if (ReadFile (get_handle(), ptr, min (inq, ulen), &n, &io_status))
+ if (ReadFile (get_handle (), ptr, min (inq, ulen), &n, &io_status))
/* Got something */;
else if (GetLastError () != ERROR_IO_PENDING)
goto err;
@@ -169,7 +162,7 @@ fhandler_serial::raw_write (const void *ptr, size_t len)
for (;;)
{
- if (WriteFile (get_handle(), ptr, len, &bytes_written, &write_status))
+ if (WriteFile (get_handle (), ptr, len, &bytes_written, &write_status))
break;
switch (GetLastError ())
@@ -188,13 +181,13 @@ fhandler_serial::raw_write (const void *ptr, size_t len)
break;
}
- ForceCloseHandle(write_status.hEvent);
+ ForceCloseHandle (write_status.hEvent);
return bytes_written;
err:
__seterrno ();
- ForceCloseHandle(write_status.hEvent);
+ ForceCloseHandle (write_status.hEvent);
return -1;
}
@@ -207,12 +200,11 @@ fhandler_serial::dump (void)
void
fhandler_serial::init (HANDLE f, DWORD flags, mode_t bin)
{
- fhandler_base::init (f, flags, bin);
- (void) open (NULL, flags, bin ? O_BINARY : 0);
+ (void) open (NULL, flags, bin & (O_BINARY | O_TEXT));
}
int
-fhandler_serial::open (const char *name, int flags, mode_t mode)
+fhandler_serial::open (path_conv *, int flags, mode_t mode)
{
int res;
COMMTIMEOUTS to;
@@ -221,10 +213,10 @@ fhandler_serial::open (const char *name, int flags, mode_t mode)
syscall_printf ("fhandler_serial::open (%s, %p, %p)",
get_name (), flags, mode);
- if (name && !(res = this->fhandler_base::open (flags, mode)))
+ if (!(res = this->fhandler_base::open (NULL, flags, mode)))
return 0;
- else
- res = 1;
+
+ res = 1;
(void) SetCommMask (get_handle (), EV_RXCHAR);
@@ -276,6 +268,23 @@ fhandler_serial::open (const char *name, int flags, mode_t mode)
system_printf ("couldn't set initial state for %s, %E", get_name ());
}
+ /* setting rts and dtr to known state so that ioctl() function with
+ request TIOCMGET could return correct value of RTS and DTR lines.
+ Important only for Win 9x systems */
+
+ if (!wincap.supports_reading_modem_output_lines ())
+ {
+ if (EscapeCommFunction (get_handle (), SETDTR) == 0)
+ system_printf ("couldn't set initial state of DTR for %s, %E", get_name ());
+ if (EscapeCommFunction (get_handle (), SETRTS) == 0)
+ system_printf ("couldn't set initial state of RTS for %s, %E", get_name ());
+
+ /* even though one of above functions fail I have to set rts and dtr
+ variables to initial value. */
+ rts = TIOCM_RTS;
+ dtr = TIOCM_DTR;
+ }
+
SetCommMask (get_handle (), EV_RXCHAR);
set_open_status ();
syscall_printf ("%p = fhandler_serial::open (%s, %p, %p)",
@@ -366,6 +375,99 @@ fhandler_serial::tcflow (int action)
return 0;
}
+
+/* ioctl: */
+int
+fhandler_serial::ioctl (unsigned int cmd, void *buffer)
+{
+
+ DWORD ev;
+ COMSTAT st;
+ DWORD action;
+ DWORD modemLines;
+ DWORD mcr;
+ DWORD cbReturned;
+ bool result;
+ int modemStatus;
+ int request;
+
+ request = *(int *) buffer;
+ action = 0;
+ modemStatus = 0;
+ if (!ClearCommError (get_handle (), &ev, &st))
+ return -1;
+ switch (cmd)
+ {
+ case TIOCMGET:
+ if (GetCommModemStatus (get_handle (), &modemLines) == 0)
+ return -1;
+ if (modemLines & MS_CTS_ON)
+ modemStatus |= TIOCM_CTS;
+ if (modemLines & MS_DSR_ON)
+ modemStatus |= TIOCM_DSR;
+ if (modemLines & MS_RING_ON)
+ modemStatus |= TIOCM_RI;
+ if (modemLines & MS_RLSD_ON)
+ modemStatus |= TIOCM_CD;
+ if (!wincap.supports_reading_modem_output_lines ())
+ modemStatus |= rts | dtr;
+ else
+ {
+ result = DeviceIoControl (get_handle (),
+ 0x001B0078,
+ NULL, 0, &mcr, 4, &cbReturned, 0);
+ if (!result)
+ return -1;
+ if (cbReturned != 4)
+ return -1;
+ if (mcr & 2)
+ modemStatus |= TIOCM_RTS;
+ if (mcr & 1)
+ modemStatus |= TIOCM_DTR;
+ }
+ *(int *) buffer = modemStatus;
+ return 0;
+ case TIOCMSET:
+ if (request & TIOCM_RTS)
+ {
+ if (EscapeCommFunction (get_handle (), SETRTS) == 0)
+ return -1;
+ else
+ rts = TIOCM_RTS;
+ }
+ else
+ {
+ if (EscapeCommFunction (get_handle (), CLRRTS) == 0)
+ return -1;
+ else
+ rts = 0;
+ }
+ if (request & TIOCM_DTR)
+ {
+ if (EscapeCommFunction (get_handle (), SETDTR) == 0)
+ return -1;
+ else
+ dtr = TIOCM_DTR;
+ }
+ else
+ {
+ if (EscapeCommFunction (get_handle (), CLRDTR) == 0)
+ return -1;
+ else
+ dtr = 0;
+ }
+ return 0;
+ case TIOCINQ:
+ if (ev & CE_FRAME | ev & CE_IOE | ev & CE_OVERRUN |
+ ev & CE_RXOVER | ev & CE_RXPARITY)
+ return -1;
+ *(int *) buffer = st.cbInQue;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
/* tcflush: POSIX 7.2.2.1 */
int
fhandler_serial::tcflush (int queue)
@@ -373,12 +475,11 @@ fhandler_serial::tcflush (int queue)
if (queue == TCOFLUSH || queue == TCIOFLUSH)
PurgeComm (get_handle (), PURGE_TXABORT | PURGE_TXCLEAR);
- if (queue == TCIFLUSH | queue == TCIOFLUSH)
+ if (queue == TCIFLUSH || queue == TCIOFLUSH)
/* Input flushing by polling until nothing turns up
(we stop after 1000 chars anyway) */
for (int max = 1000; max > 0; max--)
{
- DWORD ev;
COMSTAT st;
if (!PurgeComm (get_handle (), PURGE_RXABORT | PURGE_RXCLEAR))
break;
@@ -404,6 +505,8 @@ fhandler_serial::tcsetattr (int action, const struct termios *t)
COMMTIMEOUTS to;
DCB ostate, state;
unsigned int ovtime = vtime_, ovmin = vmin_;
+ int tmpDtr, tmpRts;
+ tmpDtr = tmpRts = 0;
termios_printf ("action %d", action);
if ((action == TCSADRAIN) || (action == TCSAFLUSH))
@@ -569,6 +672,7 @@ fhandler_serial::tcsetattr (int action, const struct termios *t)
{ /* disable */
state.fRtsControl = RTS_CONTROL_ENABLE;
state.fOutxCtsFlow = FALSE;
+ tmpRts = TIOCM_RTS;
}
if (t->c_cflag & CRTSXOFF)
@@ -601,7 +705,10 @@ fhandler_serial::tcsetattr (int action, const struct termios *t)
set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);
if (dropDTR == TRUE)
- EscapeCommFunction (get_handle (), CLRDTR);
+ {
+ EscapeCommFunction (get_handle (), CLRDTR);
+ tmpDtr = 0;
+ }
else
{
/* FIXME: Sometimes when CLRDTR is set, setting
@@ -610,8 +717,12 @@ fhandler_serial::tcsetattr (int action, const struct termios *t)
parameters while DTR is still down. */
EscapeCommFunction (get_handle (), SETDTR);
+ tmpDtr = TIOCM_DTR;
}
+ rts = tmpRts;
+ dtr = tmpDtr;
+
/*
The following documentation on was taken from "Linux Serial Programming
HOWTO". It explains how MIN (t->c_cc[VMIN] || vmin_) and TIME
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index a34272f6a..95633e4b5 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -1,6 +1,6 @@
/* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -15,11 +15,12 @@
#include "winsup.h"
#include <errno.h>
#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
#include <asm/byteorder.h>
#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock2.h>
#include "cygerrno.h"
@@ -31,22 +32,73 @@
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
+#include "wsock_event.h"
#define SECRET_EVENT_NAME "cygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x"
#define ENTROPY_SOURCE_NAME "/dev/urandom"
#define ENTROPY_SOURCE_DEV_UNIT 9
+extern fhandler_socket *fdsock (int& fd, const char *name, SOCKET soc);
+extern "C" {
+int sscanf (const char *, const char *, ...);
+} /* End of "C" section */
+
fhandler_dev_random* entropy_source;
+/* cygwin internal: map sockaddr into internet domain address */
+static int
+get_inet_addr (const struct sockaddr *in, int inlen,
+ struct sockaddr_in *out, int *outlen, int* secret = 0)
+{
+ int secret_buf [4];
+ int* secret_ptr = (secret ? : secret_buf);
+
+ if (in->sa_family == AF_INET)
+ {
+ *out = * (sockaddr_in *)in;
+ *outlen = inlen;
+ return 1;
+ }
+ else if (in->sa_family == AF_LOCAL)
+ {
+ int fd = _open (in->sa_data, O_RDONLY);
+ if (fd == -1)
+ return 0;
+
+ int ret = 0;
+ char buf[128];
+ memset (buf, 0, sizeof buf);
+ if (read (fd, buf, sizeof buf) != -1)
+ {
+ sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",
+ &sin.sin_port,
+ secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3);
+ sin.sin_port = htons (sin.sin_port);
+ sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ *out = sin;
+ *outlen = sizeof sin;
+ ret = 1;
+ }
+ _close (fd);
+ return ret;
+ }
+ else
+ {
+ set_errno (EAFNOSUPPORT);
+ return 0;
+ }
+}
+
/**********************************************************************/
/* fhandler_socket */
-fhandler_socket::fhandler_socket (const char *name) :
- fhandler_base (FH_SOCKET, name)
+fhandler_socket::fhandler_socket ()
+ : fhandler_base (FH_SOCKET), sun_path (NULL)
{
- set_cb (sizeof *this);
set_need_fork_fixup ();
- prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF,
+ prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF,
sizeof (WSAPROTOCOL_INFOA));
}
@@ -54,6 +106,8 @@ fhandler_socket::~fhandler_socket ()
{
if (prot_info_ptr)
cfree (prot_info_ptr);
+ if (sun_path)
+ cfree (sun_path);
}
void
@@ -62,11 +116,10 @@ fhandler_socket::set_connect_secret ()
if (!entropy_source)
{
void *buf = malloc (sizeof (fhandler_dev_random));
- entropy_source = new (buf) fhandler_dev_random (ENTROPY_SOURCE_NAME,
- ENTROPY_SOURCE_DEV_UNIT);
+ entropy_source = new (buf) fhandler_dev_random (ENTROPY_SOURCE_DEV_UNIT);
}
if (entropy_source &&
- !entropy_source->open (ENTROPY_SOURCE_NAME, O_RDONLY))
+ !entropy_source->open (NULL, O_RDONLY))
{
delete entropy_source;
entropy_source = NULL;
@@ -93,7 +146,7 @@ fhandler_socket::create_secret_event (int* secret)
struct sockaddr_in sin;
int sin_len = sizeof (sin);
- if (getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
+ if (::getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
{
debug_printf ("error getting local socket name (%d)", WSAGetLastError ());
return NULL;
@@ -102,12 +155,17 @@ fhandler_socket::create_secret_event (int* secret)
__small_sprintf (buf, SECRET_EVENT_NAME, sin.sin_port,
secret_ptr [0], secret_ptr [1],
secret_ptr [2], secret_ptr [3]);
- secret_event = CreateEvent (get_inheritance(true), FALSE, FALSE, buf);
+ LPSECURITY_ATTRIBUTES sec = get_inheritance (true);
+ secret_event = CreateEvent (sec, FALSE, FALSE, buf);
if (!secret_event && GetLastError () == ERROR_ALREADY_EXISTS)
secret_event = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
- if (secret_event)
+ if (!secret_event)
+ /* nothing to do */;
+ else if (sec == &sec_all_nih || sec == &sec_none_nih)
ProtectHandle (secret_event);
+ else
+ ProtectHandleINH (secret_event);
return secret_event;
}
@@ -115,8 +173,13 @@ fhandler_socket::create_secret_event (int* secret)
void
fhandler_socket::signal_secret_event ()
{
- if (secret_event)
- SetEvent (secret_event);
+ if (!secret_event)
+ debug_printf ("no secret event?");
+ else
+ {
+ SetEvent (secret_event);
+ debug_printf ("signaled secret_event");
+ }
}
void
@@ -140,7 +203,7 @@ fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
ev = CreateEvent (&sec_all_nih, FALSE, FALSE, buf);
if (!ev && GetLastError () == ERROR_ALREADY_EXISTS)
{
- debug_printf ("%s event already exist");
+ debug_printf ("event \"%s\" already exists", buf);
ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
}
@@ -160,54 +223,51 @@ fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
void
fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
{
- int ret = 1;
-
- if (prot_info_ptr &&
- (ret = WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr)))
+ if (!winsock2_active)
{
- debug_printf ("WSADuplicateSocket error");
- set_winsock_errno ();
- }
- if (!ret && ws2_32_handle)
- {
- debug_printf ("WSADuplicateSocket went fine, dwServiceFlags1=%d",
- prot_info_ptr->dwServiceFlags1);
+ fhandler_base::fixup_before_fork_exec (win_proc_id);
+ debug_printf ("Without Winsock 2.0");
}
+ else if (!WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr))
+ debug_printf ("WSADuplicateSocket went fine, sock %p, win_proc_id %d, prot_info_ptr %p",
+ get_socket (), win_proc_id, prot_info_ptr);
else
{
- fhandler_base::fixup_before_fork_exec (win_proc_id);
- debug_printf ("Without Winsock 2.0");
+ debug_printf ("WSADuplicateSocket error, sock %p, win_proc_id %d, prot_info_ptr %p",
+ get_socket (), win_proc_id, prot_info_ptr);
+ set_winsock_errno ();
}
}
+extern "C" void __stdcall load_wsock32 ();
void
fhandler_socket::fixup_after_fork (HANDLE parent)
{
- SOCKET new_sock = INVALID_SOCKET;
+ SOCKET new_sock;
debug_printf ("WSASocket begin, dwServiceFlags1=%d",
prot_info_ptr->dwServiceFlags1);
- if (prot_info_ptr &&
- (new_sock = WSASocketA (FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- prot_info_ptr, 0, 0)) == INVALID_SOCKET)
+
+ if ((new_sock = WSASocketA (FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ prot_info_ptr, 0, 0)) == INVALID_SOCKET)
{
debug_printf ("WSASocket error");
set_winsock_errno ();
}
- if (new_sock != INVALID_SOCKET && ws2_32_handle)
+ else if (!new_sock && !winsock2_active)
{
- debug_printf ("WSASocket went fine");
- set_io_handle ((HANDLE) new_sock);
+ load_wsock32 ();
+ fhandler_base::fixup_after_fork (parent);
+ debug_printf ("Without Winsock 2.0");
}
else
{
-#if 0
- fhandler_base::fixup_after_fork (parent);
-#endif
- debug_printf ("Without Winsock 2.0");
+ debug_printf ("WSASocket went fine new_sock %p, old_sock %p", new_sock, get_io_handle ());
+ set_io_handle ((HANDLE) new_sock);
}
+
if (secret_event)
fork_fixup (parent, secret_event, "secret_event");
}
@@ -215,21 +275,27 @@ fhandler_socket::fixup_after_fork (HANDLE parent)
void
fhandler_socket::fixup_after_exec (HANDLE parent)
{
- extern WSADATA wsadata;
+ debug_printf ("here");
if (!get_close_on_exec ())
fixup_after_fork (parent);
- else if (wsadata.wVersion < 512) /* < Winsock 2.0 */
+#if 0
+ else if (!winsock2_active)
closesocket (get_socket ());
+#endif
}
int
fhandler_socket::dup (fhandler_base *child)
{
+ debug_printf ("here");
fhandler_socket *fhs = (fhandler_socket *) child;
fhs->addr_family = addr_family;
fhs->set_io_handle (get_io_handle ());
+ if (get_addr_family () == AF_LOCAL)
+ fhs->set_sun_path (get_sun_path ());
+
fhs->fixup_before_fork_exec (GetCurrentProcessId ());
- if (ws2_32_handle)
+ if (winsock2_active)
{
fhs->fixup_after_fork (hMainProc);
return 0;
@@ -237,38 +303,753 @@ fhandler_socket::dup (fhandler_base *child)
return fhandler_base::dup (child);
}
+int __stdcall
+fhandler_socket::fstat (struct __stat64 *buf, path_conv *pc)
+{
+ int res = fhandler_base::fstat (buf, pc);
+ if (!res)
+ {
+ buf->st_mode &= ~_IFMT;
+ buf->st_mode |= _IFSOCK;
+ buf->st_ino = (ino_t) get_handle ();
+ }
+ return res;
+}
+
+int
+fhandler_socket::bind (const struct sockaddr *name, int namelen)
+{
+ int res = -1;
+
+ if (name->sa_family == AF_LOCAL)
+ {
+#define un_addr ((struct sockaddr_un *) name)
+ struct sockaddr_in sin;
+ int len = sizeof sin;
+ int fd;
+
+ if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN)
+ {
+ set_errno (ENAMETOOLONG);
+ goto out;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ if (::bind (get_socket (), (sockaddr *) &sin, len))
+ {
+ syscall_printf ("AF_LOCAL: bind failed %d", get_errno ());
+ set_winsock_errno ();
+ goto out;
+ }
+ if (::getsockname (get_socket (), (sockaddr *) &sin, &len))
+ {
+ syscall_printf ("AF_LOCAL: getsockname failed %d", get_errno ());
+ set_winsock_errno ();
+ goto out;
+ }
+
+ sin.sin_port = ntohs (sin.sin_port);
+ debug_printf ("AF_LOCAL: socket bound to port %u", sin.sin_port);
+
+ /* bind must fail if file system socket object already exists
+ so _open () is called with O_EXCL flag. */
+ fd = _open (un_addr->sun_path,
+ O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
+ 0);
+ if (fd < 0)
+ {
+ if (get_errno () == EEXIST)
+ set_errno (EADDRINUSE);
+ goto out;
+ }
+
+ set_connect_secret ();
+
+ char buf[sizeof (SOCKET_COOKIE) + 80];
+ __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);
+ get_connect_secret (strchr (buf, '\0'));
+ len = strlen (buf) + 1;
+
+ /* Note that the terminating nul is written. */
+ if (_write (fd, buf, len) != len)
+ {
+ save_errno here;
+ _close (fd);
+ _unlink (un_addr->sun_path);
+ }
+ else
+ {
+ _close (fd);
+ chmod (un_addr->sun_path,
+ (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask);
+ set_sun_path (un_addr->sun_path);
+ res = 0;
+ }
+#undef un_addr
+ }
+ else if (::bind (get_socket (), name, namelen))
+ set_winsock_errno ();
+ else
+ res = 0;
+
+out:
+ return res;
+}
+
+int
+fhandler_socket::connect (const struct sockaddr *name, int namelen)
+{
+ int res = -1;
+ BOOL secret_check_failed = FALSE;
+ BOOL in_progress = FALSE;
+ sockaddr_in sin;
+ int secret [4];
+
+ if (!get_inet_addr (name, namelen, &sin, &namelen, secret))
+ return -1;
+
+ res = ::connect (get_socket (), (sockaddr *) &sin, namelen);
+ if (res)
+ {
+ /* Special handling for connect to return the correct error code
+ when called on a non-blocking socket. */
+ if (is_nonblocking ())
+ {
+ DWORD err = WSAGetLastError ();
+ if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
+ {
+ WSASetLastError (WSAEINPROGRESS);
+ in_progress = TRUE;
+ }
+ else if (err == WSAEINVAL)
+ WSASetLastError (WSAEISCONN);
+ }
+ set_winsock_errno ();
+ }
+ if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
+ {
+ if (!res || in_progress)
+ {
+ if (!create_secret_event (secret))
+ {
+ secret_check_failed = TRUE;
+ }
+ else if (in_progress)
+ signal_secret_event ();
+ }
+
+ if (!secret_check_failed && !res)
+ {
+ if (!check_peer_secret_event (&sin, secret))
+ {
+ debug_printf ( "accept from unauthorized server" );
+ secret_check_failed = TRUE;
+ }
+ }
+
+ if (secret_check_failed)
+ {
+ close_secret_event ();
+ if (res)
+ closesocket (res);
+ set_errno (ECONNREFUSED);
+ res = -1;
+ }
+ }
+
+ if (WSAGetLastError () == WSAEINPROGRESS)
+ set_connect_state (CONNECT_PENDING);
+ else
+ set_connect_state (CONNECTED);
+ return res;
+}
+
+int
+fhandler_socket::listen (int backlog)
+{
+ int res = ::listen (get_socket (), backlog);
+ if (res)
+ set_winsock_errno ();
+ else
+ set_connect_state (CONNECTED);
+ return res;
+}
+
+int
+fhandler_socket::accept (struct sockaddr *peer, int *len)
+{
+ int res = -1;
+ WSAEVENT ev[2] = { WSA_INVALID_EVENT, signal_arrived };
+ BOOL secret_check_failed = FALSE;
+ BOOL in_progress = FALSE;
+
+ /* Allows NULL peer and len parameters. */
+ struct sockaddr_in peer_dummy;
+ int len_dummy;
+ if (!peer)
+ peer = (struct sockaddr *) &peer_dummy;
+ if (!len)
+ {
+ len_dummy = sizeof (struct sockaddr_in);
+ len = &len_dummy;
+ }
+
+ /* accept on NT fails if len < sizeof (sockaddr_in)
+ * some programs set len to
+ * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain
+ */
+ if (len && ((unsigned) *len < sizeof (struct sockaddr_in)))
+ *len = sizeof (struct sockaddr_in);
+
+ if (!is_nonblocking ())
+ {
+ ev[0] = WSACreateEvent ();
+
+ if (ev[0] != WSA_INVALID_EVENT &&
+ !WSAEventSelect (get_socket (), ev[0], FD_ACCEPT))
+ {
+ WSANETWORKEVENTS sock_event;
+ int wait_result;
+
+ wait_result = WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE,
+ FALSE);
+ if (wait_result == WSA_WAIT_EVENT_0)
+ WSAEnumNetworkEvents (get_socket (), ev[0], &sock_event);
+
+ /* Unset events for listening socket and
+ switch back to blocking mode */
+ WSAEventSelect (get_socket (), ev[0], 0);
+ unsigned long nonblocking = 0;
+ ioctlsocket (get_socket (), FIONBIO, &nonblocking);
+
+ switch (wait_result)
+ {
+ case WSA_WAIT_EVENT_0:
+ if (sock_event.lNetworkEvents & FD_ACCEPT)
+ {
+ if (sock_event.iErrorCode[FD_ACCEPT_BIT])
+ {
+ WSASetLastError (sock_event.iErrorCode[FD_ACCEPT_BIT]);
+ set_winsock_errno ();
+ res = -1;
+ goto done;
+ }
+ }
+ /* else; : Should never happen since FD_ACCEPT is the only event
+ that has been selected */
+ break;
+ case WSA_WAIT_EVENT_0 + 1:
+ debug_printf ("signal received during accept");
+ set_errno (EINTR);
+ res = -1;
+ goto done;
+ case WSA_WAIT_FAILED:
+ default: /* Should never happen */
+ WSASetLastError (WSAEFAULT);
+ set_winsock_errno ();
+ res = -1;
+ goto done;
+ }
+ }
+ }
+
+ res = ::accept (get_socket (), peer, len);
+
+ if ((SOCKET) res == (SOCKET) INVALID_SOCKET &&
+ WSAGetLastError () == WSAEWOULDBLOCK)
+ in_progress = TRUE;
+
+ if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
+ {
+ if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress)
+ {
+ if (!create_secret_event ())
+ secret_check_failed = TRUE;
+ else if (in_progress)
+ signal_secret_event ();
+ }
+
+ if (!secret_check_failed &&
+ (SOCKET) res != (SOCKET) INVALID_SOCKET)
+ {
+ if (!check_peer_secret_event ((struct sockaddr_in*) peer))
+ {
+ debug_printf ("connect from unauthorized client");
+ secret_check_failed = TRUE;
+ }
+ }
+
+ if (secret_check_failed)
+ {
+ close_secret_event ();
+ if ((SOCKET) res != (SOCKET) INVALID_SOCKET)
+ closesocket (res);
+ set_errno (ECONNABORTED);
+ res = -1;
+ goto done;
+ }
+ }
+
+ {
+ cygheap_fdnew res_fd;
+ if (res_fd < 0)
+ /* FIXME: what is correct errno? */;
+ else if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
+ set_winsock_errno ();
+ else
+ {
+ fhandler_socket* res_fh = fdsock (res_fd, get_name (), res);
+ if (get_addr_family () == AF_LOCAL)
+ res_fh->set_sun_path (get_sun_path ());
+ res_fh->set_addr_family (get_addr_family ());
+ res_fh->set_socket_type (get_socket_type ());
+ res = res_fd;
+ }
+ }
+
+done:
+ if (ev[0] != WSA_INVALID_EVENT)
+ WSACloseEvent (ev[0]);
+
+ return res;
+}
+
+int
+fhandler_socket::getsockname (struct sockaddr *name, int *namelen)
+{
+ int res = -1;
+
+ if (get_addr_family () == AF_LOCAL)
+ {
+ struct sockaddr_un *sun = (struct sockaddr_un *) name;
+ memset (sun, 0, *namelen);
+ sun->sun_family = AF_LOCAL;
+
+ if (!get_sun_path ())
+ sun->sun_path[0] = '\0';
+ else
+ /* According to SUSv2 "If the actual length of the address is
+ greater than the length of the supplied sockaddr structure, the
+ stored address will be truncated." We play it save here so
+ that the path always has a trailing 0 even if it's truncated. */
+ strncpy (sun->sun_path, get_sun_path (),
+ *namelen - sizeof *sun + sizeof sun->sun_path - 1);
+
+ *namelen = sizeof *sun - sizeof sun->sun_path
+ + strlen (sun->sun_path) + 1;
+ res = 0;
+ }
+ else
+ {
+ res = ::getsockname (get_socket (), name, namelen);
+ if (res)
+ set_winsock_errno ();
+ }
+
+ return res;
+}
+
int
-fhandler_socket::read (void *ptr, size_t len)
+fhandler_socket::getpeername (struct sockaddr *name, int *namelen)
{
- sigframe thisframe (mainthread);
- int res = recv (get_socket (), (char *) ptr, len, 0);
+ int res = ::getpeername (get_socket (), name, namelen);
+ if (res)
+ set_winsock_errno ();
+
+ return res;
+}
+
+int
+fhandler_socket::readv (const struct iovec *const iov, const int iovcnt,
+ ssize_t tot)
+{
+ struct msghdr msg =
+ {
+ msg_name: NULL,
+ msg_namelen: 0,
+ msg_iov: (struct iovec *) iov, // const_cast
+ msg_iovlen: iovcnt,
+ msg_accrights: NULL,
+ msg_accrightslen: 0
+ };
+
+ return recvmsg (&msg, 0, tot);
+}
+
+int
+fhandler_socket::recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen)
+{
+ int res;
+ DWORD ret;
+
+ flags &= MSG_WINMASK;
+ if (!winsock2_active)
+ ret = res = ::recvfrom (get_socket (),
+ (char *) ptr, len, flags,
+ from, fromlen);
+ else
+ {
+ WSABUF wsabuf = { len, (char *) ptr };
+
+ if (is_nonblocking ())
+ res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags,
+ from, fromlen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags,
+ from, fromlen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+ }
+
if (res == SOCKET_ERROR)
{
+ res = -1;
set_winsock_errno ();
}
+ else
+ res = ret;
+
+ return res;
+}
+
+int
+fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot)
+{
+ if (get_addr_family () == AF_LOCAL)
+ {
+ /* On AF_LOCAL sockets the (fixed-size) name of the shared memory
+ area used for descriptor passing is transmitted first.
+ If this string is empty, no descriptors are passed and we can
+ go ahead recv'ing the normal data blocks. Otherwise start
+ special handling for descriptor passing. */
+ /*TODO*/
+ }
+
+ struct iovec *const iov = msg->msg_iov;
+ const int iovcnt = msg->msg_iovlen;
+
+ int res;
+
+ if (!winsock2_active)
+ {
+ if (iovcnt == 1)
+ res = recvfrom (iov->iov_base, iov->iov_len, flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen);
+ else
+ {
+ if (tot == -1) // i.e. if not pre-calculated by the caller.
+ {
+ tot = 0;
+ const struct iovec *iovptr = iov + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ tot += iovptr->iov_len;
+ }
+ while (iovptr != iov);
+ }
+
+ char *buf = (char *) alloca (tot);
+
+ if (!buf)
+ {
+ set_errno (ENOMEM);
+ res = -1;
+ }
+ else
+ {
+ res = recvfrom (buf, tot, flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen);
+
+ const struct iovec *iovptr = iov;
+ int nbytes = res;
+
+ while (nbytes > 0)
+ {
+ const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
+ memcpy (iovptr->iov_base, buf, frag);
+ buf += frag;
+ iovptr += 1;
+ nbytes -= frag;
+ }
+ }
+ }
+ }
+ else
+ {
+ WSABUF wsabuf[iovcnt];
+
+ {
+ const struct iovec *iovptr = iov + iovcnt;
+ WSABUF *wsaptr = wsabuf + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ wsaptr -= 1;
+ wsaptr->len = iovptr->iov_len;
+ wsaptr->buf = (char *) iovptr->iov_base;
+ }
+ while (wsaptr != wsabuf);
+ }
+
+ DWORD ret;
+
+ if (is_nonblocking ())
+ res = WSARecvFrom (get_socket (),
+ wsabuf, iovcnt, &ret, (DWORD *) &flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSARecvFrom (get_socket (),
+ wsabuf, iovcnt, &ret, (DWORD *) &flags,
+ (struct sockaddr *) msg->msg_name,
+ &msg->msg_namelen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+
+ if (res == SOCKET_ERROR)
+ {
+ res = -1;
+ set_winsock_errno ();
+ }
+ else
+ res = ret;
+ }
+
return res;
}
int
-fhandler_socket::write (const void *ptr, size_t len)
+fhandler_socket::writev (const struct iovec *const iov, const int iovcnt,
+ ssize_t tot)
+{
+ struct msghdr msg =
+ {
+ msg_name: NULL,
+ msg_namelen: 0,
+ msg_iov: (struct iovec *) iov, // const_cast
+ msg_iovlen: iovcnt,
+ msg_accrights: NULL,
+ msg_accrightslen: 0
+ };
+
+ return sendmsg (&msg, 0, tot);
+}
+
+int
+fhandler_socket::sendto (const void *ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen)
{
- sigframe thisframe (mainthread);
- int res = send (get_socket (), (const char *) ptr, len, 0);
+ sockaddr_in sin;
+
+ if (to && !get_inet_addr (to, tolen, &sin, &tolen))
+ return -1;
+
+ int res;
+ DWORD ret;
+
+ if (!winsock2_active)
+ res = ::sendto (get_socket (), (const char *) ptr, len,
+ flags & MSG_WINMASK,
+ (to ? (const struct sockaddr *) &sin : NULL), tolen);
+ else
+ {
+ WSABUF wsabuf = { len, (char *) ptr };
+
+ if (is_nonblocking ())
+ res = WSASendTo (get_socket (), &wsabuf, 1, &ret,
+ flags & MSG_WINMASK,
+ (to ? (const struct sockaddr *) &sin : NULL), tolen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSASendTo (get_socket (), &wsabuf, 1, &ret,
+ flags & MSG_WINMASK,
+ (to ? (const struct sockaddr *) &sin : NULL), tolen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+ }
+
if (res == SOCKET_ERROR)
{
+ res = -1;
set_winsock_errno ();
- if (get_errno () == ECONNABORTED || get_errno () == ECONNRESET)
+ }
+ else
+ res = ret;
+
+ /* Special handling for SIGPIPE */
+ if (res == -1 && get_errno () == ESHUTDOWN)
+ {
+ set_errno (EPIPE);
+ if (! (flags & MSG_NOSIGNAL))
_raise (SIGPIPE);
}
+
+ return res;
+}
+
+int
+fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot)
+{
+ if (get_addr_family () == AF_LOCAL)
+ {
+ /* For AF_LOCAL/AF_UNIX sockets, if descriptors are given, start
+ the special handling for descriptor passing. Otherwise just
+ transmit an empty string to tell the receiver that no
+ descriptor passing is done. */
+ /*TODO*/
+ }
+
+ struct iovec *const iov = msg->msg_iov;
+ const int iovcnt = msg->msg_iovlen;
+
+ int res;
+
+ if (!winsock2_active)
+ {
+ if (iovcnt == 1)
+ res = sendto (iov->iov_base, iov->iov_len, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen);
+ else
+ {
+ if (tot == -1) // i.e. if not pre-calculated by the caller.
+ {
+ tot = 0;
+ const struct iovec *iovptr = iov + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ tot += iovptr->iov_len;
+ }
+ while (iovptr != iov);
+ }
+
+ char *const buf = (char *) alloca (tot);
+
+ if (!buf)
+ {
+ set_errno (ENOMEM);
+ res = -1;
+ }
+ else
+ {
+ char *bufptr = buf;
+ const struct iovec *iovptr = iov;
+ int nbytes = tot;
+
+ while (nbytes != 0)
+ {
+ const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
+ memcpy (bufptr, iovptr->iov_base, frag);
+ bufptr += frag;
+ iovptr += 1;
+ nbytes -= frag;
+ }
+
+ res = sendto (buf, tot, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen);
+ }
+ }
+ }
+ else
+ {
+ WSABUF wsabuf[iovcnt];
+
+ {
+ const struct iovec *iovptr = iov + iovcnt;
+ WSABUF *wsaptr = wsabuf + iovcnt;
+ do
+ {
+ iovptr -= 1;
+ wsaptr -= 1;
+ wsaptr->len = iovptr->iov_len;
+ wsaptr->buf = (char *) iovptr->iov_base;
+ }
+ while (wsaptr != wsabuf);
+ }
+
+ DWORD ret;
+
+ if (is_nonblocking ())
+ res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen,
+ NULL, NULL);
+ else
+ {
+ wsock_event wsock_evt;
+ res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags,
+ (struct sockaddr *) msg->msg_name,
+ msg->msg_namelen,
+ wsock_evt.prepare (), NULL);
+
+ if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING)
+ ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags);
+ }
+
+ if (res == SOCKET_ERROR)
+ {
+ res = -1;
+ set_winsock_errno ();
+ }
+ else
+ res = ret;
+ }
+
+ return res;
+}
+
+int
+fhandler_socket::shutdown (int how)
+{
+ int res = ::shutdown (get_socket (), how);
+
+ if (res)
+ set_winsock_errno ();
+ else
+ switch (how)
+ {
+ case SHUT_RD:
+ set_shutdown_read ();
+ break;
+ case SHUT_WR:
+ set_shutdown_write ();
+ break;
+ case SHUT_RDWR:
+ set_shutdown_read ();
+ set_shutdown_write ();
+ break;
+ }
return res;
}
-/* Cygwin internal */
int
fhandler_socket::close ()
{
int res = 0;
- sigframe thisframe (mainthread);
/* HACK to allow a graceful shutdown even if shutdown() hasn't been
called by the application. Note that this isn't the ultimate
@@ -279,10 +1060,21 @@ fhandler_socket::close ()
setsockopt (get_socket (), SOL_SOCKET, SO_LINGER,
(const char *)&linger, sizeof linger);
- if (closesocket (get_socket ()))
+ while ((res = closesocket (get_socket ())) != 0)
{
- set_winsock_errno ();
- res = -1;
+ if (WSAGetLastError () != WSAEWOULDBLOCK)
+ {
+ set_winsock_errno ();
+ res = -1;
+ break;
+ }
+ if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0)
+ {
+ set_errno (EINTR);
+ res = -1;
+ break;
+ }
+ WSASetLastError (0);
}
close_secret_event ();
@@ -293,7 +1085,6 @@ fhandler_socket::close ()
#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
-/* Cygwin internal */
int
fhandler_socket::ioctl (unsigned int cmd, void *p)
{
@@ -301,7 +1092,6 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
int res;
struct ifconf ifc, *ifcp;
struct ifreq *ifr, *ifrp;
- sigframe thisframe (mainthread);
switch (cmd)
{
@@ -414,7 +1204,7 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
if (cmd == FIONBIO)
{
syscall_printf ("socket is now %sblocking",
- *(int *) p ? "un" : "");
+ *(int *) p ? "non" : "");
/* Start AsyncSelect if async socket unblocked */
if (*(int *) p && get_async ())
WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO, ASYNC_MASK);
@@ -460,11 +1250,14 @@ fhandler_socket::fcntl (int cmd, void *arg)
void
fhandler_socket::set_close_on_exec (int val)
{
-#if 0
- extern WSADATA wsadata;
- if (wsadata.wVersion < 512) /* < Winsock 2.0 */
+ if (!winsock2_active) /* < Winsock 2.0 */
set_inheritance (get_handle (), val);
-#endif
set_close_on_exec_flag (val);
debug_printf ("set close_on_exec for %s to %d", get_name (), val);
}
+
+void
+fhandler_socket::set_sun_path (const char *path)
+{
+ sun_path = path ? cstrdup (path) : NULL;
+}
diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc
index 48561351a..f5bb333bc 100644
--- a/winsup/cygwin/fhandler_tape.cc
+++ b/winsup/cygwin/fhandler_tape.cc
@@ -1,7 +1,7 @@
/* fhandler_tape.cc. See fhandler.h for a description of the fhandler
classes.
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,7 +11,6 @@ details. */
#include "winsup.h"
#include <sys/termios.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mtio.h>
@@ -29,7 +28,6 @@ details. */
void
fhandler_dev_tape::clear (void)
{
- norewind = 0;
lasterr = 0;
fhandler_dev_raw::clear ();
}
@@ -55,34 +53,27 @@ fhandler_dev_tape::is_eof (int win_error)
return ret;
}
-fhandler_dev_tape::fhandler_dev_tape (const char *name, int unit) : fhandler_dev_raw (FH_TAPE, name, unit)
+fhandler_dev_tape::fhandler_dev_tape (int unit)
+ : fhandler_dev_raw (FH_TAPE, unit)
{
- set_cb (sizeof *this);
+ debug_printf ("unit: %d", unit);
}
int
-fhandler_dev_tape::open (const char *path, int flags, mode_t)
+fhandler_dev_tape::open (path_conv *real_path, int flags, mode_t)
{
int ret;
- int minor;
- if (get_device_number (path, minor) != FH_TAPE)
- {
- set_errno (EINVAL);
- return -1;
- }
-
- norewind = (minor >= 128);
devbufsiz = 1L;
- ret = fhandler_dev_raw::open (path, flags);
+ ret = fhandler_dev_raw::open (real_path, flags);
if (ret)
{
struct mtget get;
struct mtop op;
struct mtpos pos;
- if (! ioctl (MTIOCGET, &get))
+ if (!ioctl (MTIOCGET, &get))
/* Tape drive supports and is set to variable block size. */
if (get.mt_dsreg == 0)
devbufsiz = get.mt_maxblksize;
@@ -138,7 +129,7 @@ fhandler_dev_tape::close (void)
// To protected reads on signaling (e.g. Ctrl-C)
eof_detected = 1;
- if (! norewind)
+ if (is_rewind_device ())
{
debug_printf ("rewinding\n");
op.mt_op = MTREW;
@@ -155,25 +146,23 @@ fhandler_dev_tape::close (void)
}
int
-fhandler_dev_tape::fstat (struct stat *buf)
+fhandler_dev_tape::fstat (struct __stat64 *buf, path_conv *pc)
{
int ret;
- if (! (ret = fhandler_dev_raw::fstat (buf)))
+ if (!(ret = fhandler_base::fstat (buf, pc)))
{
struct mtget get;
- if (! ioctl (MTIOCGET, &get))
- {
- buf->st_blocks = get.mt_capacity / buf->st_blksize;
- }
+ if (!ioctl (MTIOCGET, &get))
+ buf->st_blocks = get.mt_capacity / buf->st_blksize;
}
return ret;
}
-off_t
-fhandler_dev_tape::lseek (off_t offset, int whence)
+__off64_t
+fhandler_dev_tape::lseek (__off64_t offset, int whence)
{
struct mtop op;
struct mtpos pos;
@@ -187,7 +176,7 @@ fhandler_dev_tape::lseek (off_t offset, int whence)
if (ioctl (MTIOCPOS, &pos))
{
- return (off_t) -1;
+ return ILLEGAL_SEEK;
}
switch (whence)
@@ -233,7 +222,6 @@ fhandler_dev_tape::dup (fhandler_base *child)
{
fhandler_dev_tape *fhc = (fhandler_dev_tape *) child;
- fhc->norewind = norewind;
fhc->lasterr = lasterr;
return fhandler_dev_raw::dup (child);
}
@@ -359,8 +347,8 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
}
if (devbufsiz > 1L && size > 1L)
{
- memcpy(buf, devbuf + devbufstart,
- devbufend - devbufstart);
+ memcpy (buf, devbuf + devbufstart,
+ devbufend - devbufstart);
devbufend -= devbufstart;
}
else
@@ -701,7 +689,7 @@ fhandler_dev_tape::tape_set_blocksize (long count)
if (lasterr)
return lasterr;
- if (count < min || count > max)
+ if (count != 0 && (count < min || count > max))
return tape_error (ERROR_INVALID_PARAMETER, "tape_set_blocksize");
mp.BlockSize = count;
@@ -804,6 +792,7 @@ fhandler_dev_tape::tape_status (struct mtget *get)
get->mt_defblksize = dp.DefaultBlockSize;
get->mt_featureslow = dp.FeaturesLow;
get->mt_featureshigh = dp.FeaturesHigh;
+ get->mt_eotwarningzonesize = dp.EOTWarningZoneSize;
return 0;
}
diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc
index 4a8c23862..c1cca494c 100644
--- a/winsup/cygwin/fhandler_termios.cc
+++ b/winsup/cygwin/fhandler_termios.cc
@@ -1,6 +1,6 @@
/* fhandler_termios.cc
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -9,15 +9,14 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
+#include <sys/termios.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "tty.h"
@@ -83,6 +82,25 @@ fhandler_termios::tcgetpgrp ()
}
void
+tty_min::kill_pgrp (int sig)
+{
+ int killself = 0;
+ winpids pids;
+ for (unsigned i = 0; i < pids.npids; i++)
+ {
+ _pinfo *p = pids[i];
+ if (!proc_exists (p) || p->ctty != ntty || p->pgid != pgid)
+ continue;
+ if (p == myself)
+ killself++;
+ else
+ (void) sig_send (p, sig);
+ }
+ if (killself)
+ sig_send (myself, sig);
+}
+
+void
tty_min::set_ctty (int ttynum, int flags)
{
if ((myself->ctty < 0 || myself->ctty == ttynum) && !(flags & O_NOCTTY))
@@ -96,7 +114,7 @@ tty_min::set_ctty (int ttynum, int flags)
(p == myself || !proc_exists (p)))
{
paranoid_printf ("resetting tty%d sid. Was %d, now %d. pgid was %d, now %d.",
- ttynum, getsid(), myself->sid, getpgid (), myself->pgid);
+ ttynum, getsid (), myself->sid, getpgid (), myself->pgid);
/* We are the session leader */
setsid (myself->sid);
setpgid (myself->pgid);
@@ -119,7 +137,7 @@ fhandler_termios::bg_check (int sig)
if (sig < 0)
sig = -sig;
- termios_printf("bg I/O pgid %d, tpgid %d, ctty %d",
+ termios_printf ("bg I/O pgid %d, tpgid %d, ctty %d",
myself->pgid, tc->getpgid (), myself->ctty);
if (tc->getsid () == 0)
@@ -136,7 +154,7 @@ fhandler_termios::bg_check (int sig)
return with error */
int pgid_gone = !pid_exists (myself->pgid);
int sigs_ignored =
- ((void *) myself->getsig(sig).sa_handler == (void *) SIG_IGN) ||
+ ((void *) myself->getsig (sig).sa_handler == (void *) SIG_IGN) ||
(myself->getsigmask () & SIGTOMASK (sig));
if (pgid_gone)
@@ -151,7 +169,7 @@ fhandler_termios::bg_check (int sig)
/* Don't raise a SIGTT* signal if we have already been interrupted
by another signal. */
if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0)
- _raise (sig);
+ kill_pgrp (myself->pgid, sig);
return bg_signalled;
setEIO:
@@ -207,18 +225,18 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
if (tc->ti.c_lflag & ISIG)
{
int sig;
- if (c == tc->ti.c_cc[VINTR])
+ if (CCEQ(tc->ti.c_cc[VINTR], c))
sig = SIGINT;
- else if (c == tc->ti.c_cc[VQUIT])
+ else if (CCEQ(tc->ti.c_cc[VQUIT], c))
sig = SIGQUIT;
- else if (c == tc->ti.c_cc[VSUSP])
+ else if (CCEQ(tc->ti.c_cc[VSUSP], c))
sig = SIGTSTP;
else
goto not_a_sig;
termios_printf ("got interrupt %d, sending signal %d", c, sig);
eat_readahead (-1);
- kill_pgrp (tc->getpgid (), sig);
+ tc->kill_pgrp (sig);
tc->ti.c_lflag &= ~FLUSHO;
sawsig = 1;
goto restart_output;
@@ -226,7 +244,7 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
not_a_sig:
if (tc->ti.c_iflag & IXON)
{
- if (c == tc->ti.c_cc[VSTOP])
+ if (CCEQ(tc->ti.c_cc[VSTOP], c))
{
if (!tc->output_stopped)
{
@@ -235,7 +253,7 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
}
continue;
}
- else if (c == tc->ti.c_cc[VSTART])
+ else if (CCEQ(tc->ti.c_cc[VSTART], c))
{
restart_output:
tc->output_stopped = 0;
@@ -245,20 +263,20 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
else if ((tc->ti.c_iflag & IXANY) && tc->output_stopped)
goto restart_output;
}
- if (tc->ti.c_lflag & IEXTEN && c == tc->ti.c_cc[VDISCARD])
+ if (iscanon && tc->ti.c_lflag & IEXTEN && CCEQ(tc->ti.c_cc[VDISCARD], c))
{
tc->ti.c_lflag ^= FLUSHO;
continue;
}
if (!iscanon)
/* nothing */;
- else if (c == tc->ti.c_cc[VERASE])
+ else if (CCEQ(tc->ti.c_cc[VERASE], c))
{
if (eat_readahead (1))
echo_erase ();
continue;
}
- else if (c == tc->ti.c_cc[VWERASE])
+ else if (CCEQ(tc->ti.c_cc[VWERASE], c))
{
int ch;
do
@@ -269,7 +287,7 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
while ((ch = peek_readahead (1)) >= 0 && !isspace (ch));
continue;
}
- else if (c == tc->ti.c_cc[VKILL])
+ else if (CCEQ(tc->ti.c_cc[VKILL], c))
{
int nchars = eat_readahead (-1);
if (tc->ti.c_lflag & ECHO)
@@ -277,7 +295,7 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
echo_erase (1);
continue;
}
- else if (c == tc->ti.c_cc[VREPRINT])
+ else if (CCEQ(tc->ti.c_cc[VREPRINT], c))
{
if (tc->ti.c_lflag & ECHO)
{
@@ -286,14 +304,14 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept)
}
continue;
}
- else if (c == tc->ti.c_cc[VEOF])
+ else if (CCEQ(tc->ti.c_cc[VEOF], c))
{
termios_printf ("EOF");
input_done = 1;
continue;
}
- else if (c == tc->ti.c_cc[VEOL] ||
- c == tc->ti.c_cc[VEOL2] ||
+ else if (CCEQ(tc->ti.c_cc[VEOL], c) ||
+ CCEQ(tc->ti.c_cc[VEOL2], c) ||
c == '\n')
{
set_input_done (1);
@@ -325,3 +343,10 @@ fhandler_termios::fixup_after_fork (HANDLE parent)
this->fhandler_base::fixup_after_fork (parent);
fork_fixup (parent, get_output_handle (), "output_handle");
}
+
+__off64_t
+fhandler_termios::lseek (__off64_t, int)
+{
+ set_errno (ESPIPE);
+ return -1;
+}
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 62d0c91d9..9c2bb7f49 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -1,6 +1,6 @@
/* fhandler_tty.cc
- Copyright 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -10,7 +10,6 @@ details. */
#include "winsup.h"
#include <stdio.h>
-#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
@@ -21,13 +20,12 @@ details. */
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "cygheap.h"
#include "shared_info.h"
-#include "cygwin/cygserver_transport.h"
#include "cygwin/cygserver.h"
+#include "cygthread.h"
/* Tty master stuff */
@@ -37,18 +35,14 @@ static DWORD WINAPI process_input (void *); // Input queue thread
static DWORD WINAPI process_output (void *); // Output queue thread
static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread
-fhandler_tty_master::fhandler_tty_master (const char *name, int unit) :
- fhandler_pty_master (name, FH_TTYM, unit)
+fhandler_tty_master::fhandler_tty_master (int unit)
+ : fhandler_pty_master (FH_TTYM, unit), console (NULL), output_thread (NULL)
{
- set_cb (sizeof *this);
- console = NULL;
- hThread = NULL;
}
int
fhandler_tty_master::init (int ntty)
{
- HANDLE h;
termios_printf ("Creating master for tty%d", ntty);
if (init_console ())
@@ -67,38 +61,15 @@ fhandler_tty_master::init (int ntty)
inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
- h = makethread (process_input, NULL, 0, "ttyin");
- if (h == NULL)
- {
- termios_printf ("can't create input thread");
- return -1;
- }
- else
- {
- SetThreadPriority (h, THREAD_PRIORITY_HIGHEST);
- CloseHandle (h);
- }
+ cygthread *h;
+ h = new cygthread (process_input, NULL, "ttyin");
+ SetThreadPriority (*h, THREAD_PRIORITY_HIGHEST);
- h = makethread (process_ioctl, NULL, 0, "ttyioctl");
- if (h == NULL)
- {
- termios_printf ("can't create ioctl thread");
- return -1;
- }
- else
- {
- SetThreadPriority (h, THREAD_PRIORITY_HIGHEST);
- CloseHandle (h);
- }
+ h = new cygthread (process_ioctl, NULL, "ttyioctl");
+ SetThreadPriority (*h, THREAD_PRIORITY_HIGHEST);
- hThread = makethread (process_output, NULL, 0, "ttyout");
- if (hThread != NULL)
- SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
- else
- {
- termios_printf ("can't create output thread");
- return -1;
- }
+ output_thread = new cygthread (process_output, cygself, "ttyout");
+ SetThreadPriority (*output_thread, THREAD_PRIORITY_HIGHEST);
return 0;
}
@@ -130,7 +101,7 @@ fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,
#else
ostack[osi].fn = fn;
ostack[osi].ln = ln;
- ostack[osi].tname = threadname (0, 0);
+ ostack[osi].tname = cygthread::name ();
termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
osi++;
#endif
@@ -397,22 +368,20 @@ out:
}
static DWORD WINAPI
-process_output (void *)
+process_output (void *self)
{
char buf[OUT_BUFFER_SIZE*2];
for (;;)
{
int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);
- if (n < 0)
- {
- termios_printf ("ReadFile %E");
- ExitThread (0);
- }
- if (n == 0)
+ if (n <= 0)
{
- /* End of file. */
- ExitThread (0);
+ if (n < 0)
+ termios_printf ("ReadFile %E");
+ cygthread *t = (cygthread *) self;
+ tty_master->output_thread = NULL;
+ t->exit_thread ();
}
n = tty_master->console->write ((void *) buf, (size_t) n);
tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0;
@@ -439,33 +408,29 @@ process_ioctl (void *)
/**********************************************************************/
/* Tty slave stuff */
-fhandler_tty_slave::fhandler_tty_slave (int num, const char *name) :
- fhandler_tty_common (FH_TTYS, name, num)
+fhandler_tty_slave::fhandler_tty_slave (int num)
+ : fhandler_tty_common (FH_TTYS, num)
{
- set_cb (sizeof *this);
- ttynum = num;
- debug_printf ("unix '%s', win32 '%s'", unix_path_name, win32_path_name);
- inuse = NULL;
+ set_r_no_interrupt (1);
}
-fhandler_tty_slave::fhandler_tty_slave (const char *name) :
- fhandler_tty_common (FH_TTYS, name, 0)
+fhandler_tty_slave::fhandler_tty_slave ()
+ : fhandler_tty_common (FH_TTYS, 0)
{
- set_cb (sizeof *this);
- inuse = NULL;
+ set_r_no_interrupt (1);
}
/* FIXME: This function needs to close handles when it has
a failing condition. */
int
-fhandler_tty_slave::open (const char *, int flags, mode_t)
+fhandler_tty_slave::open (path_conv *, int flags, mode_t)
{
tcinit (cygwin_shared->tty[ttynum]);
attach_tty (ttynum);
tc->set_ctty (ttynum, flags);
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
/* Create synchronisation events */
char buf[40];
@@ -524,49 +489,49 @@ fhandler_tty_slave::open (const char *, int flags, mode_t)
HANDLE from_master_local, to_master_local;
if (!wincap.has_security () ||
- cygserver_running!=CYGSERVER_OK ||
- !cygserver_attach_tty ( &from_master_local, &to_master_local))
+ cygserver_running == CYGSERVER_UNAVAIL ||
+ !cygserver_attach_tty (&from_master_local, &to_master_local))
{
termios_printf ("cannot dup handles via server. using old method.");
HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
- get_ttyp ()->master_pid);
+ get_ttyp ()->master_pid);
+ termios_printf ("tty own handle %p",tty_owner);
if (tty_owner == NULL)
- {
- termios_printf ("can't open tty (%d) handle process %d",
- ttynum, get_ttyp ()->master_pid);
- __seterrno ();
- return 0;
- }
-
- if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
- hMainProc, &from_master_local, 0, TRUE,
+ {
+ termios_printf ("can't open tty (%d) handle process %d",
+ ttynum, get_ttyp ()->master_pid);
+ __seterrno ();
+ return 0;
+ }
+
+ if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
+ hMainProc, &from_master_local, 0, TRUE,
DUPLICATE_SAME_ACCESS))
- {
- termios_printf ("can't duplicate input, %E");
- __seterrno ();
- return 0;
- }
- termios_printf ("duplicated from_master %p->%p from tty_owner %p",
- get_ttyp ()->from_master, from_master_local, tty_owner);
-
- if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
+ {
+ termios_printf ("can't duplicate input, %E");
+ __seterrno ();
+ return 0;
+ }
+
+ if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
hMainProc, &to_master_local, 0, TRUE,
DUPLICATE_SAME_ACCESS))
- {
- termios_printf ("can't duplicate output, %E");
- __seterrno ();
- return 0;
- }
- termios_printf ("duplicated to_master %p->%p from tty_owner %p",
- get_ttyp ()->to_master, to_master_local, tty_owner);
+ {
+ termios_printf ("can't duplicate output, %E");
+ __seterrno ();
+ return 0;
+ }
CloseHandle (tty_owner);
}
+ termios_printf ("duplicated from_master %p->%p from tty_owner",
+ get_ttyp ()->from_master, from_master_local);
+ termios_printf ("duplicated to_master %p->%p from tty_owner",
+ get_ttyp ()->to_master, to_master_local);
+
set_io_handle (from_master_local);
- ProtectHandle1 (from_master_local, from_pty);
set_output_handle (to_master_local);
- ProtectHandle1 (to_master_local, to_pty);
set_open_status ();
termios_printf ("tty%d opened", ttynum);
@@ -576,34 +541,20 @@ fhandler_tty_slave::open (const char *, int flags, mode_t)
int
fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr,
- LPHANDLE to_master_ptr)
+ LPHANDLE to_master_ptr)
{
if (!from_master_ptr || !to_master_ptr)
return 0;
- client_request_attach_tty *request =
- new client_request_attach_tty ((DWORD) GetCurrentProcessId (),
- (DWORD) get_ttyp ()->master_pid,
- (HANDLE) get_ttyp ()->from_master,
- (HANDLE) get_ttyp ()->to_master);
+ client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid,
+ (HANDLE) get_ttyp ()->from_master,
+ (HANDLE) get_ttyp ()->to_master);
- if (cygserver_request (request) != 0 ||
- request->header.error_code != 0)
+ if (req.make_request () == -1 || req.error_code ())
return 0;
-/*
- struct request_attach_tty req;
- INIT_REQUEST (req, CYGSERVER_REQUEST_ATTACH_TTY);
- req.pid = GetCurrentProcessId ();
- req.master_pid = get_ttyp ()->master_pid;
- req.from_master = get_ttyp ()->from_master;
- req.to_master = get_ttyp ()->to_master;
- if (cygserver_request ((struct request_header*) &req) != 0)
- return 0;
-*/
- *from_master_ptr = request->from_master ();
- *to_master_ptr = request->to_master ();
- delete request;
+ *from_master_ptr = req.from_master ();
+ *to_master_ptr = req.to_master ();
return 1;
}
@@ -677,7 +628,7 @@ fhandler_tty_slave::write (const void *ptr, size_t len)
return towrite;
}
-int
+int __stdcall
fhandler_tty_slave::read (void *ptr, size_t len)
{
DWORD n;
@@ -692,18 +643,19 @@ fhandler_tty_slave::read (void *ptr, size_t len)
DWORD rc;
HANDLE w4[2];
- termios_printf ("read(%x, %d) handle %d", ptr, len, get_handle ());
+ termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ());
if (!(get_ttyp ()->ti.c_lflag & ICANON))
{
- vmin = min (INP_BUFFER_SIZE, get_ttyp ()->ti.c_cc[VMIN]);
+ vmin = get_ttyp ()->ti.c_cc[VMIN];
+ if (vmin > INP_BUFFER_SIZE)
+ vmin = INP_BUFFER_SIZE;
vtime = get_ttyp ()->ti.c_cc[VTIME];
- if (vmin < 0) vmin = 0;
- if (vtime < 0) vtime = 0;
- if (vmin == 0)
- time_to_wait = INFINITE;
- else
- time_to_wait = (vtime == 0 ? INFINITE : 100 * vtime);
+ if (vmin < 0)
+ vmin = 0;
+ if (vtime < 0)
+ vtime = 0;
+ time_to_wait = vtime == 0 ? INFINITE : 100 * vtime;
}
else
time_to_wait = INFINITE;
@@ -741,7 +693,7 @@ fhandler_tty_slave::read (void *ptr, size_t len)
termios_printf ("failed to acquire input mutex after input event arrived");
break;
}
- if (!PeekNamedPipe (get_handle (), peek_buf, sizeof(peek_buf), &bytes_in_pipe, NULL, NULL))
+ if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL))
{
termios_printf ("PeekNamedPipe failed, %E");
_raise (SIGHUP);
@@ -942,8 +894,8 @@ fhandler_tty_slave::ioctl (unsigned int cmd, void *arg)
{
termios_printf ("ioctl (%x)", cmd);
- if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid &&
- myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP))
+ if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid
+ && myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP))
{
/* background process */
termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d",
@@ -999,18 +951,13 @@ out:
/*******************************************************
fhandler_pty_master
*/
-fhandler_pty_master::fhandler_pty_master (const char *name, DWORD devtype, int unit) :
- fhandler_tty_common (devtype, name, unit)
+fhandler_pty_master::fhandler_pty_master (DWORD devtype, int unit)
+ : fhandler_tty_common (devtype, unit)
{
- set_cb (sizeof *this);
- ioctl_request_event = NULL;
- ioctl_done_event = NULL;
- pktmode = need_nl = 0;
- inuse = NULL;
}
int
-fhandler_pty_master::open (const char *, int flags, mode_t)
+fhandler_pty_master::open (path_conv *, int flags, mode_t)
{
ttynum = cygwin_shared->tty.allocate_tty (0);
if (ttynum < 0)
@@ -1018,7 +965,7 @@ fhandler_pty_master::open (const char *, int flags, mode_t)
cygwin_shared->tty[ttynum]->common_init (this);
inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE);
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
set_open_status ();
termios_printf ("opened pty master tty%d<%p>", ttynum, this);
@@ -1036,10 +983,10 @@ fhandler_tty_common::close ()
termios_printf ("CloseHandle (ioctl_request_event), %E");
if (inuse && !CloseHandle (inuse))
termios_printf ("CloseHandle (inuse), %E");
- if (!ForceCloseHandle (output_mutex))
- termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
if (!ForceCloseHandle (input_mutex))
termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
+ if (!ForceCloseHandle (output_mutex))
+ termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
/* Send EOF to slaves if master side is closed */
if (!get_ttyp ()->master_alive ())
@@ -1095,7 +1042,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
return len;
}
-int
+int __stdcall
fhandler_pty_master::read (void *ptr, size_t len)
{
return process_slave_output ((char *) ptr, len, pktmode);
@@ -1192,15 +1139,9 @@ fhandler_tty_common::fixup_after_fork (HANDLE parent)
if (ioctl_done_event)
fork_fixup (parent, ioctl_done_event, "ioctl_done_event");
if (output_mutex)
- {
- fork_fixup (parent, output_mutex, "output_mutex");
- ProtectHandle (output_mutex);
- }
+ fork_fixup (parent, output_mutex, "output_mutex");
if (input_mutex)
- {
- fork_fixup (parent, input_mutex, "input_mutex");
- ProtectHandle (input_mutex);
- }
+ fork_fixup (parent, input_mutex, "input_mutex");
if (input_available_event)
fork_fixup (parent, input_available_event, "input_available_event");
fork_fixup (parent, inuse, "inuse");
@@ -1226,6 +1167,7 @@ fhandler_tty_master::fixup_after_fork (HANDLE child)
{
this->fhandler_pty_master::fixup_after_fork (child);
console->fixup_after_fork (child);
+ output_thread = NULL; // It's unreachable now
}
void
@@ -1233,7 +1175,7 @@ fhandler_tty_master::fixup_after_exec (HANDLE)
{
console->close ();
init_console ();
- return;
+ output_thread = NULL; // It's unreachable now
}
int
diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc
new file mode 100644
index 000000000..05b9b0f6c
--- /dev/null
+++ b/winsup/cygwin/fhandler_virtual.cc
@@ -0,0 +1,226 @@
+/* fhandler_virtual.cc: base fhandler class for virtual filesystems
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "shared_info.h"
+#include "cygheap.h"
+#include <assert.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+fhandler_virtual::fhandler_virtual (DWORD devtype):
+ fhandler_base (devtype), filebuf (NULL), bufalloc ((size_t) -1),
+ fileid (-1)
+{
+}
+
+fhandler_virtual::~fhandler_virtual ()
+{
+ if (filebuf)
+ cfree (filebuf);
+ filebuf = NULL;
+}
+
+DIR *
+fhandler_virtual::opendir (path_conv& pc)
+{
+ DIR *dir;
+ DIR *res = NULL;
+ size_t len;
+
+ if (exists () <= 0)
+ set_errno (ENOTDIR);
+ else if ((len = strlen (get_name ())) > MAX_PATH - 3)
+ set_errno (ENAMETOOLONG);
+ else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
+ set_errno (ENOMEM);
+ else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
+ {
+ free (dir);
+ set_errno (ENOMEM);
+ }
+ else if ((dir->__d_dirent =
+ (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
+ {
+ free (dir);
+ set_errno (ENOMEM);
+ }
+ else
+ {
+ strcpy (dir->__d_dirname, get_name ());
+ dir->__d_dirent->d_version = __DIRENT_VERSION;
+ cygheap_fdnew fd;
+ fd = this;
+ fd->set_nohandle (true);
+ dir->__d_dirent->d_fd = fd;
+ dir->__d_u.__d_data.__fh = this;
+ dir->__d_cookie = __DIRENT_COOKIE;
+ dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE;
+ dir->__d_position = 0;
+ dir->__d_dirhash = get_namehash ();
+
+ res = dir;
+ }
+
+ syscall_printf ("%p = opendir (%s)", res, get_name ());
+ return res;
+}
+
+__off64_t fhandler_virtual::telldir (DIR * dir)
+{
+ return dir->__d_position;
+}
+
+void
+fhandler_virtual::seekdir (DIR * dir, __off64_t loc)
+{
+ dir->__d_position = loc;
+ return;
+}
+
+void
+fhandler_virtual::rewinddir (DIR * dir)
+{
+ dir->__d_position = 0;
+ return;
+}
+
+int
+fhandler_virtual::closedir (DIR * dir)
+{
+ return 0;
+}
+
+__off64_t
+fhandler_virtual::lseek (__off64_t offset, int whence)
+{
+ /*
+ * On Linux, when you lseek within a /proc file,
+ * the contents of the file are updated.
+ */
+ if (!fill_filebuf ())
+ return (__off64_t) -1;
+ switch (whence)
+ {
+ case SEEK_SET:
+ position = offset;
+ break;
+ case SEEK_CUR:
+ position += offset;
+ break;
+ case SEEK_END:
+ position = filesize + offset;
+ break;
+ default:
+ set_errno (EINVAL);
+ return (__off64_t) -1;
+ }
+ return position;
+}
+
+int
+fhandler_virtual::dup (fhandler_base * child)
+{
+ int ret = fhandler_base::dup (child);
+
+ if (!ret)
+ {
+ fhandler_virtual *fhproc_child = (fhandler_virtual *) child;
+ fhproc_child->filebuf = (char *) cmalloc (HEAP_BUF, filesize);
+ fhproc_child->bufalloc = fhproc_child->filesize = filesize;
+ fhproc_child->position = position;
+ memcpy (fhproc_child->filebuf, filebuf, filesize);
+ fhproc_child->set_flags (get_flags ());
+ }
+ return ret;
+}
+
+int
+fhandler_virtual::close ()
+{
+ if (filebuf)
+ cfree (filebuf);
+ filebuf = NULL;
+ bufalloc = (size_t) -1;
+ cygwin_shared->delqueue.process_queue ();
+ return 0;
+}
+
+int
+fhandler_virtual::read (void *ptr, size_t len)
+{
+ if (len == 0)
+ return 0;
+ if (openflags & O_DIROPEN)
+ {
+ set_errno (EISDIR);
+ return -1;
+ }
+ if (!filebuf)
+ return 0;
+ int read = len;
+ if (read > filesize - position)
+ read = filesize - position;
+ if (read < 0)
+ read = 0;
+ else
+ memcpy (ptr, filebuf + position, read);
+ position += read;
+ return read;
+}
+
+int
+fhandler_virtual::write (const void *ptr, size_t len)
+{
+ set_errno (EACCES);
+ return -1;
+}
+
+/* low-level open for all proc files */
+int
+fhandler_virtual::open (path_conv *, int flags, mode_t mode)
+{
+ set_r_binary (1);
+ set_w_binary (1);
+
+ set_has_acls (false);
+ set_isremote (false);
+
+ /* what to do about symlinks? */
+ set_symlink_p (false);
+ set_execable_p (not_executable);
+ set_socket_p (false);
+
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+
+ return 1;
+}
+
+int
+fhandler_virtual::exists ()
+{
+ return 0;
+}
+
+bool
+fhandler_virtual::fill_filebuf ()
+{
+ return true;
+}
diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc
index 7a5870f64..ac1fe044d 100644
--- a/winsup/cygwin/fhandler_windows.cc
+++ b/winsup/cygwin/fhandler_windows.cc
@@ -1,6 +1,6 @@
/* fhandler_windows.cc: code to access windows message queues.
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Sergey S. Okhapkin (sos@prospect.com.ru).
Feedback and testing by Andy Piper (andyp@parallax.co.uk).
@@ -46,18 +46,15 @@ The following unix-style calls are supported:
select () call marks read fd when any message posted to queue.
*/
-fhandler_windows::fhandler_windows (const char *name) :
- fhandler_base (FH_WINDOWS, name)
+fhandler_windows::fhandler_windows ()
+ : fhandler_base (FH_WINDOWS), hWnd_ (NULL), method_ (WINDOWS_POST)
{
- set_cb (sizeof *this);
- hWnd_ = NULL;
- method_ = WINDOWS_POST;
}
int
-fhandler_windows::open (const char *, int flags, mode_t)
+fhandler_windows::open (path_conv *, int flags, mode_t)
{
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
set_close_on_exec_flag (1);
set_open_status ();
return 1;
@@ -82,7 +79,7 @@ fhandler_windows::write (const void *buf, size_t)
return SendMessage (ptr->hwnd, ptr->message, ptr->wParam, ptr->lParam);
}
-int
+int __stdcall
fhandler_windows::read (void *buf, size_t len)
{
MSG *ptr = (MSG *) buf;
diff --git a/winsup/cygwin/fhandler_zero.cc b/winsup/cygwin/fhandler_zero.cc
index df864798d..86b84fb30 100644
--- a/winsup/cygwin/fhandler_zero.cc
+++ b/winsup/cygwin/fhandler_zero.cc
@@ -1,6 +1,6 @@
/* fhandler_dev_zero.cc: code to access /dev/zero
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
Written by DJ Delorie (dj@cygnus.com)
@@ -15,16 +15,16 @@ details. */
#include "security.h"
#include "fhandler.h"
-fhandler_dev_zero::fhandler_dev_zero (const char *name)
- : fhandler_base (FH_ZERO, name)
+fhandler_dev_zero::fhandler_dev_zero ()
+ : fhandler_base (FH_ZERO)
{
- set_cb (sizeof *this);
}
int
-fhandler_dev_zero::open (const char *, int flags, mode_t)
+fhandler_dev_zero::open (path_conv *, int flags, mode_t)
{
- set_flags (flags);
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+ set_nohandle (true);
set_open_status ();
return 1;
}
@@ -35,21 +35,15 @@ fhandler_dev_zero::write (const void *, size_t len)
return len;
}
-int
+int __stdcall
fhandler_dev_zero::read (void *ptr, size_t len)
{
- memset(ptr, 0, len);
+ memset (ptr, 0, len);
return len;
}
-off_t
-fhandler_dev_zero::lseek (off_t, int)
-{
- return 0;
-}
-
-int
-fhandler_dev_zero::close (void)
+__off64_t
+fhandler_dev_zero::lseek (__off64_t, int)
{
return 0;
}
@@ -57,5 +51,5 @@ fhandler_dev_zero::close (void)
void
fhandler_dev_zero::dump ()
{
- paranoid_printf("here, fhandler_dev_zero");
+ paranoid_printf ("here, fhandler_dev_zero");
}
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index e0d9445ac..daca12109 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -1,6 +1,6 @@
/* fork.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -12,7 +12,6 @@ details. */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include "security.h"
@@ -20,7 +19,6 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "cygheap.h"
@@ -29,6 +27,8 @@ details. */
#include "perthread.h"
#include "perprocess.h"
#include "dll_init.h"
+#include "sync.h"
+#include "cygmalloc.h"
#ifdef DEBUGGING
static int npid;
@@ -194,15 +194,15 @@ resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
Note that this has to be a macro since the parent may be messing with
our stack. */
static void __stdcall
-sync_with_parent(const char *s, bool hang_self)
+sync_with_parent (const char *s, bool hang_self)
{
debug_printf ("signalling parent: %s", s);
/* Tell our parent we're waiting. */
- if (!SetEvent (child_proc_info->subproc_ready))
+ if (!SetEvent (fork_info->subproc_ready))
api_fatal ("fork child - SetEvent for %s failed, %E", s);
if (hang_self)
{
- HANDLE h = child_proc_info->forker_finished;
+ HANDLE h = fork_info->forker_finished;
/* Wait for the parent to fill in our stack and heap.
Don't wait forever here. If our parent dies we don't want to clog
the system. If the wait fails, we really can't continue so exit. */
@@ -215,10 +215,10 @@ sync_with_parent(const char *s, bool hang_self)
break;
case WAIT_FAILED:
if (GetLastError () == ERROR_INVALID_HANDLE &&
- WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED)
+ WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED)
break;
api_fatal ("WFSO failed for %s, fork_finished %p, %E", s,
- child_proc_info->forker_finished);
+ fork_info->forker_finished);
break;
default:
debug_printf ("no problems");
@@ -245,7 +245,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
}
sync_with_parent ("after longjmp.", TRUE);
- ProtectHandle (hParent);
sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d\n", hParent,
first_dll, load_dlls);
@@ -259,7 +258,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
{
small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
- Sleep (atoi(buf));
+ Sleep (atoi (buf));
}
#endif
@@ -267,23 +266,27 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
fork() was invoked from other than the main thread. Make sure that
when the "main" thread exits it calls do_exit, like a normal process.
Exit with a status code of 0. */
- if (child_proc_info->stacksize)
+ if (fork_info->stacksize)
{
- ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
- ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
+ ((DWORD *)fork_info->stackbottom)[-17] = (DWORD)do_exit;
+ ((DWORD *)fork_info->stackbottom)[-15] = (DWORD)0;
}
set_file_api_mode (current_codepage);
MALLOC_CHECK;
- debug_fixup_after_fork ();
- pinfo_fixup_after_fork ();
cygheap->fdtab.fixup_after_fork (hParent);
+ ProtectHandleINH (hParent);
+
+ pinfo_fixup_after_fork ();
signal_fixup_after_fork ();
MALLOC_CHECK;
+ if (fixup_mmaps_after_fork (hParent))
+ api_fatal ("recreate_mmaps_after_fork_failed");
+
/* If we haven't dynamically loaded any dlls, just signal
the parent. Otherwise, load all the dlls, tell the parent
that we're done, and wait for the parent to fill in the.
@@ -297,11 +300,8 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
}
ForceCloseHandle (hParent);
- (void) ForceCloseHandle (child_proc_info->subproc_ready);
- (void) ForceCloseHandle (child_proc_info->forker_finished);
-
- if (fixup_mmaps_after_fork ())
- api_fatal ("recreate_mmaps_after_fork_failed");
+ (void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready);
+ (void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
if (fixup_shms_after_fork ())
api_fatal ("recreate_shm areas after fork failed");
@@ -313,11 +313,8 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
if ((*t)->clear_on_fork ())
(*t)->set ();
- user_data->threadinterface->fixup_after_fork ();
-
- /* Initialize signal/process handling */
- sigproc_init ();
- __pthread_atforkchild ();
+ wait_for_sigthread ();
+ pthread::atforkchild ();
cygbench ("fork-child");
return 0;
}
@@ -355,33 +352,22 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
DWORD rc;
PROCESS_INFORMATION pi = {0, NULL, 0, 0};
- /* call the pthread_atfork prepare functions */
- __pthread_atforkprepare ();
+ pthread::atforkprepare ();
subproc_init ();
-#ifdef DEBUGGING_NOTNEEDED
- /* The ProtectHandle call allocates memory so we need to make sure
- that enough is set aside here so that the sbrk pointer does not
- move when ProtectHandle is called after the child is started.
- Otherwise the sbrk pointers in the parent will not agree with
- the child and when user_data is (regrettably) copied over,
- the user_data->ptr field will not be accurate. */
- free (malloc (4096));
-#endif
-
int c_flags = GetPriorityClass (hMainProc) /*|
CREATE_NEW_PROCESS_GROUP*/;
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
/* If we don't have a console, then don't create a console for the
child either. */
- HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
- FILE_SHARE_WRITE, &sec_none_nih,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
- NULL);
+ HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE,
+ FILE_SHARE_WRITE, &sec_none_nih,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ NULL);
- if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
+ if (console_handle != INVALID_HANDLE_VALUE)
CloseHandle (console_handle);
else
c_flags |= DETACHED_PROCESS;
@@ -425,14 +411,14 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
{
CloseHandle (hParent);
CloseHandle (subproc_ready);
- system_printf ("unable to allocate subproc_ready event, %E");
+ system_printf ("unable to allocate forker_finished event, %E");
return -1;
}
- ProtectHandle (subproc_ready);
- ProtectHandle (forker_finished);
+ ProtectHandleINH (subproc_ready);
+ ProtectHandleINH (forker_finished);
- init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
+ init_child_info (PROC_FORK, &ch, 1, subproc_ready);
ch.forker_finished = forker_finished;
@@ -440,10 +426,10 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
si.cb = sizeof (STARTUPINFO);
si.lpReserved2 = (LPBYTE)&ch;
- si.cbReserved2 = sizeof(ch);
+ si.cbReserved2 = sizeof (ch);
/* Remove impersonation */
- if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
+ if (cygheap->user.issetuid ())
RevertToSelf ();
ch.parent = hParent;
@@ -466,15 +452,16 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
#endif
char sa_buf[1024];
+ PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf);
syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)",
myself->progname, myself->progname, c_flags, &si, &pi);
- __malloc_lock (_reent_clib ());
+ __malloc_lock ();
void *newheap;
newheap = cygheap_setup_for_child (&ch,cygheap->fdtab.need_fixup_before ());
rc = CreateProcess (myself->progname, /* image to run */
myself->progname, /* what we send in arg0 */
- allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
- allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
+ sec_attribs,
+ sec_attribs,
TRUE, /* inherit handles from parent */
c_flags,
NULL, /* environment filled in later */
@@ -488,11 +475,10 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
{
__seterrno ();
syscall_printf ("CreateProcessA failed, %E");
- ForceCloseHandle(subproc_ready);
- ForceCloseHandle(forker_finished);
+ ForceCloseHandle (subproc_ready);
+ ForceCloseHandle (forker_finished);
/* Restore impersonation */
- if (cygheap->user.impersonated
- && cygheap->user.token != INVALID_HANDLE_VALUE)
+ if (cygheap->user.issetuid ())
ImpersonateLoggedOnUser (cygheap->user.token);
cygheap_setup_for_child_cleanup (newheap, &ch, 0);
return -1;
@@ -517,10 +503,10 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
/* Initialize things that are done later in dll_crt0_1 that aren't done
for the forkee. */
- strcpy(forked->progname, myself->progname);
+ strcpy (forked->progname, myself->progname);
/* Restore impersonation */
- if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
+ if (cygheap->user.issetuid ())
ImpersonateLoggedOnUser (cygheap->user.token);
ProtectHandle (pi.hThread);
@@ -531,7 +517,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
/* Fill in fields in the child's process table entry. */
forked->hProcess = pi.hProcess;
forked->dwProcessId = pi.dwProcessId;
- forked->copysigs(myself);
+ forked->copysigs (myself);
/* Hopefully, this will succeed. The alternative to doing things this
way is to reserve space prior to calling CreateProcess and then fill
@@ -548,7 +534,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
slow_pid_reuse (pi.hProcess);
/* Wait for subproc to initialize itself. */
- if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp"))
+ if (!sync_with_child (pi, subproc_ready, TRUE, "waiting for longjmp"))
goto cleanup;
/* CHILD IS STOPPED */
@@ -568,7 +554,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
dll_data_start, dll_data_end,
dll_bss_start, dll_bss_end, NULL);
- __malloc_unlock (_reent_clib ());
+ __malloc_unlock ();
MALLOC_CHECK;
if (!rc)
goto cleanup;
@@ -612,7 +598,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
ForceCloseHandle (forker_finished);
forker_finished = NULL;
pi.hThread = NULL;
- __pthread_atforkparent ();
+ pthread::atforkparent ();
return forked->pid;
@@ -698,8 +684,7 @@ get_vfork_val ()
}
#endif
-extern "C"
-int
+extern "C" int
vfork ()
{
#ifndef NEWVFORK
@@ -722,6 +707,9 @@ vfork ()
for (pp = (char **)vf->frame, esp = vf->vfork_esp;
esp <= vf->vfork_ebp + 2; pp++, esp++)
*pp = *esp;
+ vf->ctty = myself->ctty;
+ vf->sid = myself->sid;
+ vf->pgid = myself->pgid;
int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
debug_printf ("%d = vfork()", res);
return res;
@@ -736,9 +724,13 @@ vfork ()
thisframe.init (mainthread);
cygheap->fdtab.vfork_parent_restore ();
+ myself->ctty = vf->ctty;
+ myself->sid = vf->sid;
+ myself->pgid = vf->pgid;
+
if (vf->pid < 0)
{
- int exitval = -vf->pid;
+ int exitval = vf->exitval;
vf->pid = 0;
if ((vf->pid = fork ()) == 0)
exit (exitval);
@@ -746,6 +738,7 @@ vfork ()
int pid = vf->pid;
vf->pid = 0;
+ debug_printf ("exiting vfork, pid %d", pid);
sig_dispatch_pending ();
return pid;
#endif
diff --git a/winsup/cygwin/glob.c b/winsup/cygwin/glob.c
index f50ef8e3c..971b3092e 100644
--- a/winsup/cygwin/glob.c
+++ b/winsup/cygwin/glob.c
@@ -63,10 +63,6 @@
* Number of matches in the current invocation of glob.
*/
-/* CYGNUS LOCAL: don't include */
-/* #include "namespace.h" */
-/* end CYGNUS LOCAL */
-
#include "winsup.h"
#include <sys/param.h>
@@ -98,8 +94,12 @@ __weak_alias(__globfree13,___globfree13);
#ifdef __LIBC12_SOURCE__
#define STAT stat12
#else
+#if defined (__INSIDE_CYGWIN__)
+#define STAT __stat64
+#else
#define STAT stat
#endif
+#endif
#define DOLLAR '$'
#define DOT '.'
@@ -649,7 +649,7 @@ glob3(pathbuf, pathend, pattern, restpattern, pglob)
/*
- * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
* add the new item, and update gl_pathc.
*
* This assumes the BSD realloc, which only copies the block when its size
@@ -807,18 +807,56 @@ g_opendir(str, pglob)
return(opendir(buf));
}
+static void
+stat32_to_STAT (struct __stat32 *src, struct STAT *dst)
+{
+ dst->st_dev = src->st_dev;
+ dst->st_ino = src->st_ino;
+ dst->st_mode = src->st_mode;
+ dst->st_nlink = src->st_nlink;
+ dst->st_uid = src->st_uid;
+ dst->st_gid = src->st_gid;
+ dst->st_rdev = src->st_rdev;
+ dst->st_size = src->st_size;
+ dst->st_atim = src->st_atim;
+ dst->st_mtim = src->st_mtim;
+ dst->st_ctim = src->st_ctim;
+ dst->st_blksize = src->st_blksize;
+ dst->st_blocks = src->st_blocks;
+}
+
static int
g_lstat(fn, sb, pglob)
register Char *fn;
struct STAT *sb;
glob_t *pglob;
{
+ /* FIXME: This only works as long as the application uses the old
+ struct stat with 32 bit off_t types!!!
+
+ As soon as we switch over to 64 bit, we have to decide by
+ the applications API minor version number, whether to use
+ a pointer to a __stat64 or a _stat32 struct to the
+ pglob->gl_lstat function. */
+#ifdef __CYGWIN_USE_BIG_TYPES__
+#error FIXME check apps API minor and use correct struct stat
+#endif
char buf[MAXPATHLEN];
g_Ctoc(fn, buf);
- if (pglob->gl_flags & GLOB_ALTDIRFUNC)
- return((*pglob->gl_lstat)(buf, sb));
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC) {
+ struct __stat32 lsb;
+ int ret;
+
+ if (!(ret = (*pglob->gl_lstat)(buf, &lsb)))
+ stat32_to_STAT (&lsb, sb);
+ return ret;
+ }
+#ifdef __INSIDE_CYGWIN__
+ return(lstat64(buf, sb));
+#else
return(lstat(buf, sb));
+#endif
}
static int
@@ -827,12 +865,32 @@ g_stat(fn, sb, pglob)
struct STAT *sb;
glob_t *pglob;
{
+ /* FIXME: This only works as long as the application uses the old
+ struct stat with 32 bit off_t types!!!
+
+ As soon as we switch over to 64 bit, we have to decide by
+ the applications API minor version number, whether to use
+ a pointer to a __stat64 or a _stat32 struct to the
+ pglob->gl_stat function. */
+#ifdef __CYGWIN_USE_BIG_TYPES__
+#error FIXME check apps API minor and use correct struct stat
+#endif
char buf[MAXPATHLEN];
g_Ctoc(fn, buf);
- if (pglob->gl_flags & GLOB_ALTDIRFUNC)
- return((*pglob->gl_stat)(buf, sb));
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC) {
+ struct __stat32 lsb;
+ int ret;
+
+ if (!(ret = (*pglob->gl_stat)(buf, &lsb)))
+ stat32_to_STAT (&lsb, sb);
+ return ret;
+ }
+#ifdef __INSIDE_CYGWIN__
+ return(stat64(buf, sb));
+#else
return(stat(buf, sb));
+#endif
}
static Char *
diff --git a/winsup/cygwin/gmon.c b/winsup/cygwin/gmon.c
index 95a7f430e..048ef0df1 100644
--- a/winsup/cygwin/gmon.c
+++ b/winsup/cygwin/gmon.c
@@ -44,6 +44,7 @@ static char rcsid[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp $
#include <gmon.h>
#include <profil.h>
+#include <windows.h>
/* XXX needed? */
//extern char *minbrk __asm ("minbrk");
@@ -61,7 +62,11 @@ void moncontrol __P((int));
static void *
fake_sbrk(int size)
{
- return malloc(size);
+ void *rv = malloc(size);
+ if (rv)
+ return rv;
+ else
+ return (void *) -1;
}
void
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index 87cc4b484..175fd241f 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -1,6 +1,6 @@
/* grp.cc
- Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com
First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de
@@ -17,28 +17,25 @@ details. */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "cygheap.h"
#include "cygerrno.h"
+#include "cygheap.h"
#include "pwdgrp.h"
/* Read /etc/group only once for better performance. This is done
on the first call that needs information from it. */
-static NO_COPY const char *etc_group = "/etc/group";
-static struct group *group_buf; /* group contents in memory */
+static struct __group32 *group_buf; /* group contents in memory */
static int curr_lines;
static int max_lines;
/* Position in the group cache */
#ifdef _MT_SAFE
-#define grp_pos _reent_winsup()->_grp_pos
+#define grp_pos _reent_winsup ()->_grp_pos
#else
static int grp_pos = 0;
#endif
@@ -46,22 +43,19 @@ static int grp_pos = 0;
static pwdgrp_check group_state;
static int
-parse_grp (struct group &grp, const char *line)
+parse_grp (struct __group32 &grp, char *line)
{
- int len = strlen(line);
- char *newline = (char *) malloc (len + 1);
- (void) memcpy (newline, line, len + 1);
-
- if (newline[--len] == '\n')
- newline[len] = '\0';
+ int len = strlen (line);
+ if (line[--len] == '\r')
+ line[len] = '\0';
- char *dp = strchr (newline, ':');
+ char *dp = strchr (line, ':');
if (!dp)
return 0;
*dp++ = '\0';
- grp.gr_name = newline;
+ grp.gr_name = line;
grp.gr_passwd = dp;
dp = strchr (grp.gr_passwd, ':');
@@ -106,12 +100,12 @@ parse_grp (struct group &grp, const char *line)
/* Read one line from /etc/group into the group cache */
static void
-add_grp_line (const char *line)
+add_grp_line (char *line)
{
if (curr_lines == max_lines)
{
max_lines += 10;
- group_buf = (struct group *) realloc (group_buf, max_lines * sizeof (struct group));
+ group_buf = (struct __group32 *) realloc (group_buf, max_lines * sizeof (struct __group32));
}
if (parse_grp (group_buf[curr_lines], line))
curr_lines++;
@@ -119,17 +113,23 @@ add_grp_line (const char *line)
class group_lock
{
- pthread_mutex_t mutex;
+ bool armed;
+ static NO_COPY pthread_mutex_t mutex;
public:
- group_lock (): mutex ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER) {}
- void arm () {pthread_mutex_lock (&mutex); }
+ group_lock (bool doit)
+ {
+ if (armed = doit)
+ pthread_mutex_lock (&mutex);
+ }
~group_lock ()
{
- if (mutex != (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)
+ if (armed)
pthread_mutex_unlock (&mutex);
}
};
+pthread_mutex_t NO_COPY group_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
+
/* Cygwin internal */
/* Read in /etc/group and save contents in the group cache */
/* This sets group_in_memory_p to 1 so functions in this file can
@@ -139,15 +139,9 @@ class group_lock
void
read_etc_group ()
{
- char linebuf [200];
- char group_name [UNLEN + 1];
- DWORD group_name_len = UNLEN + 1;
+ static pwdgrp_read gr;
- strncpy (group_name, "Administrators", sizeof (group_name));
-
- static NO_COPY group_lock here;
- if (cygwin_finished_initializing)
- here.arm ();
+ group_lock here (cygwin_finished_initializing);
/* if we got blocked by the mutex, then etc_group may have been processed */
if (group_state != uninitialized)
@@ -156,64 +150,100 @@ read_etc_group ()
if (group_state != initializing)
{
group_state = initializing;
- if (max_lines) /* When rereading, free allocated memory first. */
- {
- for (int i = 0; i < curr_lines; ++i)
- {
- free (group_buf[i].gr_name);
- free (group_buf[i].gr_mem);
- }
- curr_lines = 0;
- }
-
- FILE *f = fopen (etc_group, "rt");
-
- if (f)
+ if (gr.open ("/etc/group"))
{
- while (fgets (linebuf, sizeof (linebuf), f) != NULL)
- {
- if (strlen (linebuf))
- add_grp_line (linebuf);
- }
+ char *line;
+ while ((line = gr.gets ()) != NULL)
+ if (strlen (line))
+ add_grp_line (line);
- group_state.set_last_modified (f);
- fclose (f);
+ group_state.set_last_modified (gr.get_fhandle (), gr.get_fname ());
group_state = loaded;
+ gr.close ();
+ debug_printf ("Read /etc/group, %d lines", curr_lines);
}
else /* /etc/group doesn't exist -- create default one in memory */
{
+ char group_name [UNLEN + 1];
+ DWORD group_name_len = UNLEN + 1;
char domain_name [INTERNET_MAX_HOST_NAME_LENGTH + 1];
DWORD domain_name_len = INTERNET_MAX_HOST_NAME_LENGTH + 1;
SID_NAME_USE acType;
- debug_printf ("Emulating /etc/group");
- if (! LookupAccountSidA (NULL ,
- well_known_admins_sid,
- group_name,
- &group_name_len,
- domain_name,
- &domain_name_len,
- &acType))
+ static char linebuf [200];
+
+ if (wincap.has_security ())
{
- strcpy (group_name, "unknown");
- debug_printf ("Failed to get local admins group name. %E");
+ HANDLE ptok;
+ cygsid tg;
+ DWORD siz;
+
+ if (OpenProcessToken (hMainProc, TOKEN_QUERY, &ptok))
+ {
+ if (GetTokenInformation (ptok, TokenPrimaryGroup, &tg,
+ sizeof tg, &siz)
+ && LookupAccountSidA (NULL, tg, group_name,
+ &group_name_len, domain_name,
+ &domain_name_len, &acType))
+ {
+ char strbuf[100];
+ snprintf (linebuf, sizeof (linebuf), "%s:%s:%lu:",
+ group_name,
+ tg.string (strbuf),
+ *GetSidSubAuthority (tg,
+ *GetSidSubAuthorityCount (tg) - 1));
+ debug_printf ("Emulating /etc/group: %s", linebuf);
+ add_grp_line (linebuf);
+ group_state = emulated;
+ }
+ CloseHandle (ptok);
+ }
+ }
+ if (group_state != emulated)
+ {
+ strncpy (group_name, "Administrators", sizeof (group_name));
+ if (!LookupAccountSidA (NULL, well_known_admins_sid, group_name,
+ &group_name_len, domain_name,
+ &domain_name_len, &acType))
+ {
+ strcpy (group_name, "unknown");
+ debug_printf ("Failed to get local admins group name. %E");
+ }
+ snprintf (linebuf, sizeof (linebuf), "%s::%u:", group_name,
+ (unsigned) DEFAULT_GID);
+ debug_printf ("Emulating /etc/group: %s", linebuf);
+ add_grp_line (linebuf);
+ group_state = emulated;
}
-
- snprintf (linebuf, sizeof (linebuf), "%s::%u:\n", group_name, DEFAULT_GID);
- add_grp_line (linebuf);
- group_state = emulated;
}
}
return;
}
+static
+struct __group16 *
+grp32togrp16 (struct __group16 *gp16, struct __group32 *gp32)
+{
+ if (!gp16 || !gp32)
+ return NULL;
+
+ /* Copying the pointers is actually unnecessary. Just having the correct
+ return type is important. */
+ gp16->gr_name = gp32->gr_name;
+ gp16->gr_passwd = gp32->gr_passwd;
+ gp16->gr_gid = (__gid16_t) gp32->gr_gid; /* Not loss-free */
+ gp16->gr_mem = gp32->gr_mem;
+
+ return gp16;
+}
+
extern "C"
-struct group *
-getgrgid (gid_t gid)
+struct __group32 *
+getgrgid32 (__gid32_t gid)
{
- struct group * default_grp = NULL;
+ struct __group32 * default_grp = NULL;
if (group_state <= initializing)
- read_etc_group();
+ read_etc_group ();
for (int i = 0; i < curr_lines; i++)
{
@@ -223,15 +253,24 @@ getgrgid (gid_t gid)
return group_buf + i;
}
- return default_grp;
+ return allow_ntsec ? NULL : default_grp;
}
extern "C"
-struct group *
-getgrnam (const char *name)
+struct __group16 *
+getgrgid (__gid16_t gid)
+{
+ static struct __group16 g16;
+
+ return grp32togrp16 (&g16, getgrgid32 ((__gid32_t) gid));
+}
+
+extern "C"
+struct __group32 *
+getgrnam32 (const char *name)
{
if (group_state <= initializing)
- read_etc_group();
+ read_etc_group ();
for (int i = 0; i < curr_lines; i++)
if (strcasematch (group_buf[i].gr_name, name))
@@ -242,18 +281,27 @@ getgrnam (const char *name)
}
extern "C"
+struct __group16 *
+getgrnam (const char *name)
+{
+ static struct __group16 g16;
+
+ return grp32togrp16 (&g16, getgrnam32 (name));
+}
+
+extern "C"
void
-endgrent()
+endgrent ()
{
grp_pos = 0;
}
extern "C"
-struct group *
-getgrent()
+struct __group32 *
+getgrent32 ()
{
if (group_state <= initializing)
- read_etc_group();
+ read_etc_group ();
if (grp_pos < curr_lines)
return group_buf + grp_pos++;
@@ -262,6 +310,15 @@ getgrent()
}
extern "C"
+struct __group16 *
+getgrent ()
+{
+ static struct __group16 g16;
+
+ return grp32togrp16 (&g16, getgrent32 ());
+}
+
+extern "C"
void
setgrent ()
{
@@ -269,11 +326,11 @@ setgrent ()
}
/* Internal function. ONLY USE THIS INTERNALLY, NEVER `getgrent'!!! */
-struct group *
+struct __group32 *
internal_getgrent (int pos)
{
if (group_state <= initializing)
- read_etc_group();
+ read_etc_group ();
if (pos < curr_lines)
return group_buf + pos;
@@ -281,15 +338,16 @@ internal_getgrent (int pos)
}
int
-getgroups (int gidsetsize, gid_t *grouplist, gid_t gid, const char *username)
+getgroups32 (int gidsetsize, __gid32_t *grouplist, __gid32_t gid,
+ const char *username)
{
HANDLE hToken = NULL;
DWORD size;
int cnt = 0;
- struct group *gr;
+ struct __group32 *gr;
if (group_state <= initializing)
- read_etc_group();
+ read_etc_group ();
if (allow_ntsec &&
OpenProcessToken (hMainProc, TOKEN_QUERY, &hToken))
@@ -307,7 +365,8 @@ getgroups (int gidsetsize, gid_t *grouplist, gid_t gid, const char *username)
for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
if (sid.getfromgr (gr))
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
- if (sid == groups->Groups[pg].Sid)
+ if (sid == groups->Groups[pg].Sid &&
+ sid != well_known_world_sid)
{
if (cnt < gidsetsize)
grouplist[cnt] = gr->gr_gid;
@@ -356,14 +415,108 @@ error:
extern "C"
int
-getgroups (int gidsetsize, gid_t *grouplist)
+getgroups32 (int gidsetsize, __gid32_t *grouplist)
{
- return getgroups (gidsetsize, grouplist, myself->gid, cygheap->user.name ());
+ return getgroups32 (gidsetsize, grouplist, myself->gid,
+ cygheap->user.name ());
+}
+
+extern "C"
+int
+getgroups (int gidsetsize, __gid16_t *grouplist)
+{
+ __gid32_t *grouplist32 = NULL;
+
+ if (gidsetsize < 0)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ if (gidsetsize > 0 && grouplist)
+ grouplist32 = (__gid32_t *) alloca (gidsetsize * sizeof (__gid32_t));
+
+ int ret = getgroups32 (gidsetsize, grouplist32, myself->gid,
+ cygheap->user.name ());
+
+ if (gidsetsize > 0 && grouplist)
+ for (int i = 0; i < ret; ++ i)
+ grouplist[i] = grouplist32[i];
+
+ return ret;
}
extern "C"
int
-initgroups (const char *, gid_t)
+initgroups32 (const char *, __gid32_t)
{
+ if (wincap.has_security ())
+ cygheap->user.groups.clear_supp ();
return 0;
}
+
+extern "C"
+int
+initgroups (const char * name, __gid16_t gid)
+{
+ return initgroups32 (name, gid16togid32(gid));
+}
+
+/* setgroups32: standards? */
+extern "C"
+int
+setgroups32 (int ngroups, const __gid32_t *grouplist)
+{
+ if (ngroups < 0 || (ngroups > 0 && !grouplist))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ if (!wincap.has_security ())
+ return 0;
+
+ cygsidlist gsids (cygsidlist_alloc, ngroups);
+ struct __group32 *gr;
+
+ if (ngroups && !gsids.sids)
+ return -1;
+
+ for (int gidx = 0; gidx < ngroups; ++gidx)
+ {
+ for (int gidy = 0; gidy < gidx; gidy++)
+ if (grouplist[gidy] == grouplist[gidx])
+ goto found; /* Duplicate */
+ for (int gidy = 0; (gr = internal_getgrent (gidy)); ++gidy)
+ if (gr->gr_gid == (__gid32_t) grouplist[gidx])
+ {
+ if (gsids.addfromgr (gr))
+ goto found;
+ break;
+ }
+ debug_printf ("No sid found for gid %d", grouplist[gidx]);
+ gsids.free_sids ();
+ set_errno (EINVAL);
+ return -1;
+ found:
+ continue;
+ }
+ cygheap->user.groups.update_supp (gsids);
+ return 0;
+}
+
+extern "C"
+int
+setgroups (int ngroups, const __gid16_t *grouplist)
+{
+ __gid32_t *grouplist32 = NULL;
+
+ if (ngroups > 0 && grouplist)
+ {
+ grouplist32 = (__gid32_t *) alloca (ngroups * sizeof (__gid32_t));
+ if (grouplist32 == NULL)
+ return -1;
+ for (int i = 0; i < ngroups; i++)
+ grouplist32[i] = grouplist[i];
+ }
+ return setgroups32 (ngroups, grouplist32);
+}
diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc
index eaa500c62..139b1d5a0 100644
--- a/winsup/cygwin/heap.cc
+++ b/winsup/cygwin/heap.cc
@@ -1,6 +1,6 @@
/* heap.cc: Cygwin heap manager.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,7 +11,6 @@ details. */
#include "winsup.h"
#include <errno.h>
#include "cygerrno.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "heap.h"
@@ -69,15 +68,15 @@ heap_init ()
/* Initialize page mask and default heap size. Preallocate a heap
* to assure contiguous memory. */
cygheap->heapptr = cygheap->heaptop = cygheap->heapbase =
- VirtualAlloc(NULL, cygwin_shared->heap_chunk_size (), MEM_RESERVE,
- PAGE_NOACCESS);
+ VirtualAlloc (NULL, cygwin_shared->heap_chunk_size (), MEM_RESERVE,
+ PAGE_NOACCESS);
if (cygheap->heapbase == NULL)
api_fatal ("2. unable to allocate heap, heap_chunk_size %d, %E",
cygwin_shared->heap_chunk_size ());
}
debug_printf ("heap base %p, heap top %p", cygheap->heapbase,
- cygheap->heaptop);
+ cygheap->heaptop);
page_const--;
malloc_init ();
}
@@ -87,7 +86,7 @@ heap_init ()
/* FIXME: This function no longer handles "split heaps". */
extern "C" void *
-_sbrk(int n)
+_sbrk (int n)
{
sigframe thisframe (mainthread);
char *newtop, *newbrk;
@@ -105,21 +104,21 @@ _sbrk(int n)
if (n < 0)
{ /* Freeing memory */
- assert(newtop < cygheap->heaptop);
+ assert (newtop < cygheap->heaptop);
n = (char *) cygheap->heaptop - newtop;
- if (VirtualFree(newtop, n, MEM_DECOMMIT)) /* Give it back to OS */
+ if (VirtualFree (newtop, n, MEM_DECOMMIT)) /* Give it back to OS */
goto good; /* Didn't take */
else
goto err;
}
- assert(newtop > cygheap->heaptop);
+ assert (newtop > cygheap->heaptop);
/* Need to grab more pages from the OS. If this fails it may be because
* we have used up previously reserved memory. Or, we're just plumb out
* of memory. */
commitbytes = pround (newtop - (char *) cygheap->heaptop);
- if (VirtualAlloc(cygheap->heaptop, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)
+ if (VirtualAlloc (cygheap->heaptop, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)
goto good;
/* Couldn't allocate memory. Maybe we can reserve some more.
@@ -129,8 +128,8 @@ _sbrk(int n)
if ((newbrksize = cygwin_shared->heap_chunk_size ()) < commitbytes)
newbrksize = commitbytes;
- if ((VirtualAlloc(cygheap->heaptop, newbrksize, MEM_RESERVE, PAGE_NOACCESS) != NULL) &&
- (VirtualAlloc(cygheap->heaptop, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL))
+ if ((VirtualAlloc (cygheap->heaptop, newbrksize, MEM_RESERVE, PAGE_NOACCESS) != NULL) &&
+ (VirtualAlloc (cygheap->heaptop, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL))
goto good;
err:
diff --git a/winsup/cygwin/heap.h b/winsup/cygwin/heap.h
index df652ac22..bcea4bae0 100644
--- a/winsup/cygwin/heap.h
+++ b/winsup/cygwin/heap.h
@@ -15,5 +15,5 @@ void heap_init ();
void malloc_init ();
#define inheap(s) \
- (cygheap->heapptr && ((char *) (s) >= (char *) cygheap->heapbase) \
+ (cygheap->heapptr && s && ((char *) (s) >= (char *) cygheap->heapbase) \
&& ((char *) (s) <= (char *) cygheap->heaptop))
diff --git a/winsup/cygwin/hires.h b/winsup/cygwin/hires.h
new file mode 100644
index 000000000..611b2df0d
--- /dev/null
+++ b/winsup/cygwin/hires.h
@@ -0,0 +1,47 @@
+/* hires.h: Definitions for hires clock calculations
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef __HIRES_H__
+#define __HIRES_H__
+
+#include <mmsystem.h>
+
+class hires_base
+{
+ protected:
+ int inited;
+ virtual void prime () {}
+ public:
+ virtual LONGLONG usecs (bool justdelta) {return 0LL;}
+ virtual ~hires_base () {}
+};
+
+class hires_us : hires_base
+{
+ LARGE_INTEGER primed_ft;
+ LARGE_INTEGER primed_pc;
+ double freq;
+ void prime ();
+ public:
+ LONGLONG usecs (bool justdelta);
+};
+
+class hires_ms : hires_base
+{
+ DWORD initime_ms;
+ LARGE_INTEGER initime_us;
+ UINT minperiod;
+ void prime ();
+ public:
+ LONGLONG usecs (bool justdelta);
+ ~hires_ms ();
+};
+
+#endif /*__HIRES_H__*/
diff --git a/winsup/cygwin/how-autoload-works.txt b/winsup/cygwin/how-autoload-works.txt
new file mode 100644
index 000000000..27c2426d8
--- /dev/null
+++ b/winsup/cygwin/how-autoload-works.txt
@@ -0,0 +1,66 @@
+Copyright 2002 Red Hat Inc., Egor Duda
+
+How does function autoloading work?
+
+Cygwin has the ability to handle win32 functions which are present on
+some platforms and not present on others via autoload mechanism. It's
+essentially a lazy binding of symbols. It works as following. For
+(almost) every function from OS API which cygwin uses, a stub is created
+in file autoload.cc. Each reference to the such function from win32 API
+in cygwin dll source code is actually pointing to this stub.
+
+When the function, say GetConsoleWindow(), is called for the first time,
+the control is passed to its stub. The stub tries to load the
+appropriate system dll via LoadModule() and get the actual function
+address via GetProcAddress(). If this operation succeeds, the stub is
+"patched" to pass control to actual address of GetConsoleWindow() in
+appropriate system dll, so that next time we won't have to load dll and
+perform address lookup in it again. From this point on, the call to the
+function is performed as if the dll/function were linked statically.
+
+If LoadModule() or GetProcAddress() fail, (and on nt4 the latter indeed
+fails because GetConsoleWindow() is not available in kernel32.dll), then
+the application, depending on what kind of stub is created in
+autoload.cc, will either:
+
+1) Exit with fatal error.
+
+2) Or return a predefined value indicating an error; and set the windows
+error code to 127 (ERROR_PROC_NOT_FOUND).
+
+Almost all w32api functions are linked into the cygwin dll in this
+manner, dynamically, at runtime.
+
+The costs:
+1) A tiny overhead in the initial call to a function call as each call
+is performed, indirectly, via a stub. For the first lookup of a symbol
+of an unloaded dll, there is also some overhead in loading the dll for
+the first time. The dll is only loaded by the first call to a symbol
+in the dll. After the first call to a function, subsequent calls are
+as fast as a normal, statically loaded function.
+
+The benefits:
+1) Speedup at startup time. Applications only load those dlls which are
+actually needed. For example, if application never uses socket
+functions, winsock dlls are never loaded.
+
+2) Greatly simplify wincap system -- we don't need to have a separate
+capability for every win32 function which may or may not be present on
+particular win32 platform.
+
+3) Allows a single cygwin1.dll for all win32 platforms.
+
+If you're changing in cygwin1.dll source code and if you use some
+function that was not used there before, you should add a stub so it
+will be autoloaded. To do so, add one of the LoadDllfunc* macros to
+autoload.cc. All macros eventually resolve to the following form:
+
+LoadDLLfuncEx2 (function name, parameter block length, dll name,
+ non-fatality flag , value to return if function not available)
+
+Parameter block length is a sum of sizes (in bytes) of parameters which are
+being passed to the function. If non-fatality flag is set to 0, then failure
+to load dll and find a function will cause fatal error. If non fatality flag
+is set to 1, then call to the function will return default value.
+You can also use shorter versions -- LoadDLLfuncEx and LoadDLLfunc, if the
+defaults they provide suit your needs.
diff --git a/winsup/cygwin/how-cygheap-works.txt b/winsup/cygwin/how-cygheap-works.txt
index 53bd55d65..b60f88808 100644
--- a/winsup/cygwin/how-cygheap-works.txt
+++ b/winsup/cygwin/how-cygheap-works.txt
@@ -101,7 +101,7 @@ both the parent or the child.
for the cygheap. Unfortunately gcc does not support that feature, as of
this writing.)
-The reason for choosing a fixed, arbitrary location is to accomodate
+The reason for choosing a fixed, arbitrary location is to accommodate
Windows XP, although there were sporadic complaints of cygwin heap
failures in other pathological situations with both NT and 9x. In
Windows XP, Microsoft made the allocation of memory less deterministic.
diff --git a/winsup/cygwin/how-fhandlers-work.txt b/winsup/cygwin/how-fhandlers-work.txt
index 5e810a780..cef46fedc 100644
--- a/winsup/cygwin/how-fhandlers-work.txt
+++ b/winsup/cygwin/how-fhandlers-work.txt
@@ -63,3 +63,13 @@ cannot.
For an example step-by-step to create a new fhandler, see
../doc/fhandler-tut.txt
+
+Note: In most case, it is safe to assume that using new/delete (or
+malloc/free) in an fhandler is dangerous and to be avoided. The reason
+for this is that memory allocated to fhandlers is copied between execed
+processes in the cygwin heap. Memory allocated in new/delete is only
+copied to forked processes. So use cmalloc/cfree.
+
+Obviously it is possible to use new/delete in some situations but if you're
+seeing strange core dumps with usages like cat < /my/newfhandler then the
+above may well be the culprit.
diff --git a/winsup/cygwin/how-signals-work.txt b/winsup/cygwin/how-signals-work.txt
index 7ab85db8b..3b36badc8 100644
--- a/winsup/cygwin/how-signals-work.txt
+++ b/winsup/cygwin/how-signals-work.txt
@@ -77,7 +77,11 @@ function that is known to block (such as _read()), usually by calling
sets up information about the current stack frame of an executing cygwin
process. Any function which uses 'sigframe thisframe' should be signal
aware. It should detect when a signal has arrived and return
-immediately.
+immediately. This method is also used throughout the DLL to ensure
+accurate frame info for the executing function. So, you'll see it
+sprinkled liberally throughout the DLL, usually at places where
+empirical tests have indicated problems finding this address via the
+brute force method stack walking method employed in setup_handler.
So, if mainframe is active, that means that we have good information
about the state of the main thread. Cygwin uses the stack frame info
diff --git a/winsup/cygwin/how-spawn-works.txt b/winsup/cygwin/how-spawn-works.txt
new file mode 100644
index 000000000..e4e25eae9
--- /dev/null
+++ b/winsup/cygwin/how-spawn-works.txt
@@ -0,0 +1,32 @@
+Spawn.cc in cygwin handles spawn, vfork and exec calls. It does this via
+a mode parameter that determines its behaviour with respect to the
+child.
+
+Of particular interest is the exec behaviour.
+
+In general spawn_guts (where the action happens) does the following:
+* Finds the actual program being run (which may include path searching).
+* Determines the type (.exe, shell script, perl etc) and for non binary
+programs finds the correct interpreter.
+* Creates a commandline (based on the type and the user parameters).
+* Guesses at whether the binary that will be invoked is a cygwin program
+or not (if (real_path.iscygexec ())) and uses that information to copy
+the argv table, or to translate it for win32 program usage.
+* passes a handle to the parent to the child (note: this handle should
+have it's rights restricted the daemon is merged).
+* Start the process.
+* if the mode is _P_OVERLAY (we are doing an exec)
+wait for the child to
+a) if it's a cygwin process, signal us via an event.
+b) if it's a win32 process, exit.
+c) exit.
+
+If a) occurs, we 'reparent' the child which makes it look to the current
+process's parent in the pid and process group chains.
+b) is where the cygwin process hangs around as a 'stub' presenting it's
+pid as the win32 process's pid, to allow cygwin tools to kill the win32
+process.
+once a-c has occured, execution resumes.
+* If the mode is _P_OVERLAY, this process exits, otherwise it's
+behaviour depends on the mode parameter. See the last block of
+spawn_guts.
diff --git a/winsup/cygwin/how-to-debug-cygwin.txt b/winsup/cygwin/how-to-debug-cygwin.txt
index 731cc1d71..cf10bafe7 100644
--- a/winsup/cygwin/how-to-debug-cygwin.txt
+++ b/winsup/cygwin/how-to-debug-cygwin.txt
@@ -1,73 +1,128 @@
-Copyright 2001 Red Hat Inc., Egor Duda
-
-So, your favourite program has crashed? And did you say something about
-'stackdump'? Or it just prints its output from left to right and upside-down?
-Well, you can file an angry bug report and wait until some of the core
-developers try to reproduce your problem, try to find what's the matter
-with your program and cygwin and fix the bug, if any. But you can do something
-better than that. You can debug the problem yourself, and even if you can't
-fix it, your analysis may be very helpful. Here's the (incoplete) howto on
-cygwin debugging.
-
-1. The first thing you'll need to do is to build cygwin1.dll and your crashed
-application from sources. To debug them you'll need debug information, which
-is normally stripped from executables.
-
-2. Create known-working cygwin debugging environment.
-- create a separate directory, say, c:\cygdeb, and put known-working
- cygwin1.dll and gdb.exe in it.
-- create a wrapper c:\cygdeb\debug_wrapper.cmd:
+Copyright 2001, 2002 Red Hat Inc., Egor Duda
+
+So, your favorite program has crashed? And did you say something about
+'stackdump'? Or it just prints its output from left to right and
+upside-down? Well, you can file an angry bug report and wait until some
+of the core developers try to reproduce your problem, try to find what's
+the matter with your program and cygwin and fix the bug, if any. But
+you can do something better than that. You can debug the problem
+yourself, and even if you can't fix it, your analysis may be very
+helpful. Here's the (incomplete) howto on cygwin debugging.
+
+1. First things first
+
+ The first thing you'll need to do is to build cygwin1.dll and your
+ crashed application from sources. To debug them you'll need debug
+ information, which is normally stripped from executables. You probably
+ also want to build a version of the dll with more debugging capabilities
+ by reconfiguring your build directory, specifying the --enable-debugging
+ option to configure.
+
+2. Creating a known-working cygwin debugging environment
+
+ - create a separate directory, say, c:\cygdeb, and put known-working
+ cygwin1.dll and gdb.exe in it.
+ - create a wrapper c:\cygdeb\debug_wrapper.cmd:
========= debug_wrapper.cmd =========
-rem setting CYGWIN_TESTING environement variable makes cygwin application
+rem setting CYGWIN_TESTING environment variable makes cygwin application
rem not to interfere with other already running cygwin applications.
set CYGWIN_TESTING=1
c:\cygdeb\gdb.exe -nw %1 %2
===================================
-3. Try to use cygwin's JIT debugging facility:
-- add 'error_start=c:\cygdeb\debug_wrapper.cmd' to CYGWIN environment
- variable. When some application encounters critical error, cygwin will stop
- it and execute debug_wrapper.cmd, which will run gdb and make it to attach to
- the crashed application.
-
-4. Strace.
- You can run your program under 'strace' utility, described if user's manual.
- If you know where the problem approximately is, you can add a bunch of
- additional debug_printf()s in the source code and see what they print in
- strace log. There's one common problem with this method, that some bugs
- may misteriously disappear once the program is run under strace. Then the
- bug is likely a race condition. strace has two useful options to deal with
- such situation: -b enables buffering of output and reduces additional
- timeouts introduced by strace, and -m option allows you to mask certain
- classes of *_printf() functions, reducing timeouts even more.
-
-5. Problems at early startup.
- Sometimes, something crashes at the very early stages of application
- initialization, when JIT debugging facility is not yet active. Ok, there's
- another environment variable that may help. Create program_wrapper.cmd:
+3. Using cygwin's JIT debugging facility
+
+ add 'error_start=c:\cygdeb\debug_wrapper.cmd' to CYGWIN environment
+ variable. When some application encounters critical error, cygwin will stop
+ it and execute debug_wrapper.cmd, which will run gdb and make it to attach to
+ the crashed application.
+
+4. Strace
+
+ You can run your program under 'strace' utility, described if user's manual.
+ If you know where the problem approximately is, you can add a bunch of
+ additional debug_printf()s in the source code and see what they print in
+ strace log. There's one common problem with this method, that some bugs
+ may mysteriously disappear once the program is run under strace. Then the
+ bug is likely a race condition. strace has two useful options to deal with
+ such situation: -b enables buffering of output and reduces additional
+ timeouts introduced by strace, and -m option allows you to mask certain
+ classes of *_printf() functions, reducing timeouts even more.
+
+ Note that strace does not use the cygwin DLL and so any process that it
+ starts does not inherit a cygwin environment. It is equivalent to starting
+ a program from the command prompt.
+
+5. Problems at early startup
+
+ Sometimes, something crashes at the very early stages of application
+ initialization, when JIT debugging facility is not yet active. Ok, there's
+ another environment variable that may help. Create program_wrapper.cmd:
========= program_wrapper.cmd =========
-rem setting CYGWIN_SLEEP environement variable makes cygwin application
+rem setting CYGWIN_SLEEP environment variable makes cygwin application
rem to sleep for x milliseconds at startup
set CYGWIN_SLEEP=20000
c:\some\path\bad_program.exe some parameters
===================================
-
- Now, run program_wrapper.cmd. It should print running program pid.
- After starting program_wrapper.cmd you've got 20 seconds to open another
- window, cd to c:\cygdeb in it, run gdb there and in gdb prompt type
-
- (gdb) attach <pid>
-
- where <pid> is the pid that program_wrapper.cmd have printed.
- After that you can normally step through the code in cygwin1.dll and
- bad_program.exe
-
-6. Heap corruption.
- If your program crashes at malloc() or free() or when it references some
- malloc()'ed memory, it looks like heap corruption. You can configure and
- build special version of cygwin1.dll which includes heap sanity checking.
- To do it, just add --enable-malloc-debugging option to configure. Be warned,
- however, that this version of dll is _very_ slow (10-100 times slower than
- normal), so use it only when absolutely neccessary.
+
+ Now, run program_wrapper.cmd. It should print running program pid.
+ After starting program_wrapper.cmd you've got 20 seconds to open another
+ window, cd to c:\cygdeb in it, run gdb there and in gdb prompt type
+
+ (gdb) attach <pid>
+
+ where <pid> is the pid that program_wrapper.cmd have printed.
+ After that you can normally step through the code in cygwin1.dll and
+ bad_program.exe
+
+6. More problems at early startup
+
+ You can also set a CYGWIN_DEBUG variable to force the debugger to pop up
+ only when a certain program is run:
+
+set CYGWIN_DEBUG=cat.exe=gdb.exe
+
+ This will force gdb.exe to start when the program name contains the string
+ "cat.exe". The '=gdb.exe' isn't really needed, since it is the default.
+ It is just there to show how you can specify a program to run when the
+ program starts. You can optionally set a breakpoint on "break_here"
+ once the debugger pops up and then you can single step through the
+ initialization process.
+
+ Note that it bears repeating that both of the above options are *only*
+ available when configuring cygwin with --enable-debugging.
+
+7. Heap corruption
+
+ If your program crashes at malloc() or free() or when it references some
+ malloc()'ed memory, it looks like heap corruption. You can configure and
+ build special version of cygwin1.dll which includes heap sanity checking.
+ To do it, just add --enable-malloc-debugging option to configure. Be warned,
+ however, that this version of dll is _very_ slow (10-100 times slower than
+ normal), so use it only when absolutely necessary.
+
+8. Program dies when running under strace
+
+ If your program crashes when you run it using strace but runs ok (or has a
+ different problem) otherwise, then there may be a problem in one of the
+ strace *_printf statements. Usually this is caused by a change in arguments
+ resulting in a %s being used with something other than a pointer to a
+ string.
+
+ To debug this scenario, do something like this:
+
+ bash$ gdb -nw yourapp.exe
+ (gdb) dll cygwin1
+ (gdb) l dll_crt0_1
+ (gdb) bp <<first line in the function>>
+ (gdb) run
+ (gdb) set strace.active=1
+ (gdb) continue
+
+ The program will then run in "strace mode", calling each strace *_printf,
+ just like it does when run under the strace program. Eventually, the
+ program will crash, probably in small_printf. At that point, a 'bt'
+ command should show you the offending call to strace_printf with the
+ improper format string.
diff --git a/winsup/cygwin/include/cygwin/acl.h b/winsup/cygwin/include/cygwin/acl.h
index 3248b2e68..3ea5f91e5 100644
--- a/winsup/cygwin/include/cygwin/acl.h
+++ b/winsup/cygwin/include/cygwin/acl.h
@@ -1,6 +1,6 @@
/* cygwin/acl.h header file for Cygwin.
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by C. Vinschen.
This file is part of Cygwin.
@@ -58,12 +58,27 @@ extern "C" {
#define MASK CLASS_OBJ
#define OTHER OTHER_OBJ
+#ifdef __INSIDE_CYGWIN__
+typedef struct __acl16 {
+ int a_type;
+ __uid16_t a_id;
+ mode_t a_perm;
+} __aclent16_t;
+
+typedef struct __acl32 {
+ int a_type;
+ __uid32_t a_id;
+ mode_t a_perm;
+} __aclent32_t;
+#else
typedef struct acl {
- int a_type; /* entry type */
- uid_t a_id; /* UID | GID */
- mode_t a_perm; /* permissions */
+ int a_type; /* entry type */
+ uid_t a_id; /* UID | GID */
+ mode_t a_perm; /* permissions */
} aclent_t;
+#endif
+#ifndef __INSIDE_CYGWIN__
int _EXFUN(acl,(const char *path, int cmd, int nentries, aclent_t *aclbufp));
int _EXFUN(lacl,(const char *path, int cmd, int nentries, aclent_t *aclbufp));
int _EXFUN(facl,(int fd, int cmd, int nentries, aclent_t *aclbufp));
@@ -75,6 +90,7 @@ int _EXFUN(acltopbits,(aclent_t *aclbufp, int nentries, mode_t *pbitsp));
int _EXFUN(aclfrompbits,(aclent_t *aclbufp, int nentries, mode_t *pbitsp));
char *_EXFUN(acltotext,(aclent_t *aclbufp, int aclcnt));
aclent_t *_EXFUN(aclfromtext,(char *acltextp, int *aclcnt));
+#endif
#ifdef __cplusplus
}
diff --git a/winsup/cygwin/include/cygwin/cygserver.h b/winsup/cygwin/include/cygwin/cygserver.h
index 3751863f5..d4ea70fbb 100755
--- a/winsup/cygwin/include/cygwin/cygserver.h
+++ b/winsup/cygwin/include/cygwin/cygserver.h
@@ -1,6 +1,6 @@
/* cygserver.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Egor Duda <deo@logos-m.ru>
@@ -13,123 +13,172 @@ details. */
#ifndef _CYGSERVER_H_
#define _CYGSERVER_H_
-#define MAX_REQUEST_SIZE 128
+#ifdef __GNUC__
+#define CYGSERVER_PACKED __attribute__ ((packed))
+#else
+#define CYGSERVER_PACKED
+#endif
#define CYGWIN_SERVER_VERSION_MAJOR 1
#define CYGWIN_SERVER_VERSION_API 1
#define CYGWIN_SERVER_VERSION_MINOR 0
#define CYGWIN_SERVER_VERSION_PATCH 0
-
typedef enum {
- CYGSERVER_UNKNOWN=0,
- CYGSERVER_OK=1,
- CYGSERVER_DEAD=2
+ CYGSERVER_UNKNOWN = 0,
+ CYGSERVER_OK,
+ CYGSERVER_UNAVAIL
} cygserver_states;
-typedef enum {
- CYGSERVER_REQUEST_INVALID = 0,
- CYGSERVER_REQUEST_GET_VERSION,
- CYGSERVER_REQUEST_ATTACH_TTY,
- CYGSERVER_REQUEST_SHUTDOWN,
- CYGSERVER_REQUEST_SHM_GET,
- CYGSERVER_REQUEST_LAST
-} cygserver_request_code;
-
-class request_header
-{
- public:
- ssize_t cb;
- cygserver_request_code req_id;
- ssize_t error_code;
- request_header (cygserver_request_code id, ssize_t ncb) : cb (ncb), req_id (id), error_code (0) {} ;
-}
-#ifdef __GNUC__
- __attribute__ ((packed))
-#endif
-;
+/*---------------------------------------------------------------------------*
+ * class client_request
+ *---------------------------------------------------------------------------*/
-extern void cygserver_init ();
-
-#define INIT_REQUEST(req,id) \
- (req).header.cb = sizeof (req); \
- (req).header.req_id = id;
+class transport_layer_base;
-struct request_get_version
-{
- DWORD major, api, minor, patch;
-}
-#ifdef __GNUC__
- __attribute__ ((packed))
+#ifndef __INSIDE_CYGWIN__
+class process_cache;
#endif
-;
-struct request_shutdown
+class client_request
{
- int foo;
-}
-#ifdef __GNUC__
- __attribute__ ((packed))
+protected:
+ typedef enum {
+ CYGSERVER_REQUEST_INVALID,
+ CYGSERVER_REQUEST_GET_VERSION,
+ CYGSERVER_REQUEST_SHUTDOWN,
+ CYGSERVER_REQUEST_ATTACH_TTY,
+ CYGSERVER_REQUEST_SHM,
+ CYGSERVER_REQUEST_LAST
+ } request_code_t;
+
+ struct header_t
+ {
+ size_t msglen;
+ union
+ {
+ request_code_t request_code;
+ ssize_t error_code;
+ };
+
+ header_t () {};
+ header_t (request_code_t, size_t);
+ } CYGSERVER_PACKED;
+
+public:
+#ifndef __INSIDE_CYGWIN__
+ static void handle_request (transport_layer_base *, process_cache *);
#endif
-;
-struct request_attach_tty
-{
- DWORD pid, master_pid;
- HANDLE from_master, to_master;
-}
-#ifdef __GNUC__
- __attribute__ ((packed))
-#endif
-;
+ client_request (request_code_t request_code,
+ void *buf = NULL,
+ size_t bufsiz = 0);
+ virtual ~client_request ();
+
+ request_code_t request_code () const { return _header.request_code; }
+
+ ssize_t error_code () const { return _header.error_code; };
+ void error_code (ssize_t error_code) { _header.error_code = error_code; };
+
+ size_t msglen () const { return _header.msglen; };
+ void msglen (size_t len) { _header.msglen = len; };
+
+ int make_request ();
+
+protected:
+ virtual void send (transport_layer_base *);
+
+private:
+ header_t _header;
+ void * const _buf;
+ const size_t _buflen;
-class client_request
-{
- public:
- client_request (cygserver_request_code id, ssize_t data_size);
- virtual void send (transport_layer_base *conn);
#ifndef __INSIDE_CYGWIN__
- virtual void serve (transport_layer_base *conn, class process_cache *cache);
+ void handle (transport_layer_base *, process_cache *);
+ virtual void serve (transport_layer_base *, process_cache *) = 0;
#endif
- virtual operator struct request_header ();
- cygserver_request_code req_id () {return header.req_id;};
- virtual ~client_request();
- request_header header;
- char *buffer;
};
+/*---------------------------------------------------------------------------*
+ * class client_request_get_version
+ *---------------------------------------------------------------------------*/
+
class client_request_get_version : public client_request
{
- public:
+private:
+ struct request_get_version
+ {
+ DWORD major, api, minor, patch;
+ } CYGSERVER_PACKED;
+
+public:
+ client_request_get_version ();
+ bool check_version () const;
+
+private:
+ struct request_get_version version;
+
#ifndef __INSIDE_CYGWIN__
- virtual void serve (transport_layer_base *conn, class process_cache *cache);
+ virtual void serve (transport_layer_base *, process_cache *);
#endif
- client_request_get_version::client_request_get_version();
- struct request_get_version version;
};
+/*---------------------------------------------------------------------------*
+ * class client_request_shutdown
+ *
+ * Nb. This whole class is only !__INSIDE_CYGWIN__ since it is used
+ * solely by cygserver itself.
+ *---------------------------------------------------------------------------*/
+
+#ifndef __INSIDE_CYGWIN__
+
class client_request_shutdown : public client_request
{
- public:
-#ifndef __INSIDE_CYGWIN__
- virtual void serve (transport_layer_base *conn, class process_cache *cache);
-#endif
+public:
client_request_shutdown ();
+
+private:
+ virtual void serve (transport_layer_base *, process_cache *);
};
+#endif /* !__INSIDE_CYGWIN__ */
+
+/*---------------------------------------------------------------------------*
+ * class client_request_attach_tty
+ *---------------------------------------------------------------------------*/
+
class client_request_attach_tty : public client_request
{
- public:
-#ifndef __INSIDE_CYGWIN__
- virtual void serve (transport_layer_base *conn, class process_cache *cache);
-#endif
+private:
+ struct request_attach_tty
+ {
+ DWORD pid, master_pid;
+ HANDLE from_master, to_master;
+ } CYGSERVER_PACKED;
+
+public:
+#ifdef __INSIDE_CYGWIN__
+ client_request_attach_tty (DWORD nmaster_pid,
+ HANDLE nfrom_master, HANDLE nto_master);
+#else
client_request_attach_tty ();
- client_request_attach_tty (DWORD npid, DWORD nmaster_pid, HANDLE nfrom_master, HANDLE nto_master);
- HANDLE from_master () {return req.from_master;};
- HANDLE to_master () {return req.to_master;};
+#endif
+
+ HANDLE from_master () const { return req.from_master; };
+ HANDLE to_master () const { return req.to_master; };
+
+protected:
+ virtual void send (transport_layer_base *);
+
+private:
struct request_attach_tty req;
+
+#ifndef __INSIDE_CYGWIN__
+ virtual void serve (transport_layer_base *, process_cache *);
+#endif
};
-extern int cygserver_request (client_request *);
+extern bool check_cygserver_available ();
+extern void cygserver_init ();
-#endif /* _CYGSERVER+H+ */
+#endif /* _CYGSERVER_H_ */
diff --git a/winsup/cygwin/include/cygwin/cygserver_process.h b/winsup/cygwin/include/cygwin/cygserver_process.h
index 4a49212b2..25c634e9e 100755
--- a/winsup/cygwin/include/cygwin/cygserver_process.h
+++ b/winsup/cygwin/include/cygwin/cygserver_process.h
@@ -1,84 +1,164 @@
/* cygserver_process.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
#ifndef _CYGSERVER_PROCESS_
#define _CYGSERVER_PROCESS_
-/* needs threaded_queue.h */
+#include <assert.h>
-class process_cleanup:public queue_request
+#include "threaded_queue.h"
+
+class process_cleanup : public queue_request
{
public:
+ process_cleanup (class process *const theprocess)
+ : _process (theprocess)
+ {
+ assert (_process);
+ }
+
+ virtual ~process_cleanup ();
+
virtual void process ();
- process_cleanup (class process *nprocess) : theprocess (nprocess) {};
+
private:
- class process * theprocess;
+ class process *const _process;
};
-class process_process_param:public queue_process_param
-{
- class process_cache *cache;
-public:
- DWORD request_loop ();
- process_process_param ():queue_process_param (true) {};
-};
+class process;
class cleanup_routine
{
+ friend class process;
+
public:
- cleanup_routine () : next (NULL) {};
- class cleanup_routine * next;
+ cleanup_routine (void *const key)
+ : _key (key),
+ _next (NULL)
+ {}
+
+ virtual ~cleanup_routine ();
+
+ bool operator== (const cleanup_routine &rhs) const
+ {
+ return _key == rhs._key;
+ }
+
+ void *key () const { return _key; }
+
/* MUST BE SYNCHRONOUS */
- virtual void cleanup (long winpid);
+ virtual void cleanup (class process *) = 0;
+
+private:
+ void *const _key;
+ cleanup_routine *_next;
};
+class process_cache;
+
class process
{
+ friend class process_cache;
+ friend class process_cleanup;
+
public:
- HANDLE handle ();
- long winpid;
- process (long);
+ process (pid_t cygpid, DWORD winpid);
~process ();
- DWORD exit_code ();
- class process * next;
- long refcount;
- bool add_cleanup_routine (class cleanup_routine *);
- void cleanup ();
+
+ pid_t cygpid () const { return _cygpid; }
+ DWORD winpid () const { return _winpid; }
+ HANDLE handle () const { return _hProcess; }
+
+ bool is_active () const { return _exit_status == STILL_ACTIVE; }
+
+ void hold () { EnterCriticalSection (&_access); }
+ void release () { LeaveCriticalSection (&_access); }
+
+ bool add (cleanup_routine *);
+ bool remove (const cleanup_routine *);
+
private:
+ const pid_t _cygpid;
+ const DWORD _winpid;
+ HANDLE _hProcess;
+ long _cleaning_up;
+ DWORD _exit_status; // Set in the constructor and in exit_code ().
+ cleanup_routine *_routines_head;
/* used to prevent races-on-delete */
- CRITICAL_SECTION access;
- volatile long cleaning_up;
- class cleanup_routine *head;
- HANDLE thehandle;
- DWORD _exit_status;
+ CRITICAL_SECTION _access;
+ class process *_next;
+
+ DWORD check_exit_code ();
+ void cleanup ();
};
-class process_cache:public threaded_queue
+class process_cache
{
+ // Number of special (i.e., non-process) handles in _wait_array.
+ // See wait_for_processes () and sync_wait_array () for details.
+ enum {
+ SPECIALS_COUNT = 2
+ };
+
+ class submission_loop : public queue_submission_loop
+ {
+ public:
+ submission_loop (process_cache *const cache, threaded_queue *const queue)
+ : queue_submission_loop (queue, true),
+ _cache (cache)
+ {
+ assert (_cache);
+ }
+
+ private:
+ process_cache *const _cache;
+
+ virtual void request_loop ();
+ };
+
+ friend class submission_loop;
+
public:
process_cache (unsigned int initial_workers);
- virtual ~ process_cache ();
- class process *process (long);
- /* remove a process from the cache */
- int handle_snapshot (HANDLE *, class process **, ssize_t, int);
- void remove_process (class process *);
- /* threaded_queue methods */
- void process_requests ();
- HANDLE cache_add_trigger;
+ ~process_cache ();
+
+ class process *process (pid_t cygpid, DWORD winpid);
+
+ bool running () const { return _queue.running (); }
+
+ bool start () { return _queue.start (); }
+ bool stop () { return _queue.stop (); }
private:
- virtual void add_task (class process *);
- class process *head;
- CRITICAL_SECTION cache_write_access;
+ threaded_queue _queue;
+ submission_loop _submitter;
+
+ size_t _processes_count;
+ class process *_processes_head; // A list sorted by winpid.
+
+ // Access to the _wait_array and related fields is not thread-safe,
+ // since they are used solely by wait_for_processes () and its callees.
+
+ HANDLE _wait_array[MAXIMUM_WAIT_OBJECTS];
+ class process *_process_array[MAXIMUM_WAIT_OBJECTS];
+
+ HANDLE _cache_add_trigger; // Actually both add and remove.
+ CRITICAL_SECTION _cache_write_access; // Actually both read and write access.
+
+ void wait_for_processes (HANDLE interrupt);
+ size_t sync_wait_array (HANDLE interrupt);
+ void check_and_remove_process (const size_t index);
+
+ class process *find (DWORD winpid, class process **previous = NULL);
};
#endif /* _CYGSERVER_PROCESS_ */
diff --git a/winsup/cygwin/include/cygwin/cygserver_transport.h b/winsup/cygwin/include/cygwin/cygserver_transport.h
index 1ed16edf7..915f35e66 100755
--- a/winsup/cygwin/include/cygwin/cygserver_transport.h
+++ b/winsup/cygwin/include/cygwin/cygserver_transport.h
@@ -1,32 +1,39 @@
-/* cygserver.cc
+/* cygserver_transport.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
#ifndef _CYGSERVER_TRANSPORT_
#define _CYGSERVER_TRANSPORT_
-class transport_layer_base *create_server_transport();
-/* the base class does nothing. */
+class transport_layer_base *create_server_transport ();
+
class transport_layer_base
{
- public:
- virtual void listen ();
- virtual class transport_layer_base * accept ();
- virtual void close ();
- virtual ssize_t read (char *buf, size_t len);
- virtual ssize_t write (char *buf, size_t len);
- virtual bool connect();
- virtual void impersonate_client ();
- virtual void revert_to_self ();
- transport_layer_base ();
+public:
+#ifndef __INSIDE_CYGWIN__
+ virtual int listen () = 0;
+ virtual class transport_layer_base *accept (bool *recoverable) = 0;
+#endif
+
+ virtual void close () = 0;
+ virtual ssize_t read (void *buf, size_t len) = 0;
+ virtual ssize_t write (void *buf, size_t len) = 0;
+ virtual int connect () = 0;
+
+#ifndef __INSIDE_CYGWIN__
+ virtual void impersonate_client ();
+ virtual void revert_to_self ();
+#endif
+
+ virtual ~transport_layer_base ();
};
#endif /* _CYGSERVER_TRANSPORT_ */
diff --git a/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h b/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
index 9afeebfef..4bea2eb13 100755
--- a/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
+++ b/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
@@ -1,39 +1,53 @@
-/* cygserver.cc
+/* cygserver_transport_pipes.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
#ifndef _CYGSERVER_TRANSPORT_PIPES_
#define _CYGSERVER_TRANSPORT_PIPES_
+
/* Named pipes based transport, for security on NT */
class transport_layer_pipes : public transport_layer_base
{
- public:
- virtual void listen ();
- virtual class transport_layer_pipes * accept ();
- virtual void close ();
- virtual ssize_t read (char *buf, size_t len);
- virtual ssize_t write (char *buf, size_t len);
- virtual bool connect();
- virtual void impersonate_client ();
- virtual void revert_to_self ();
- transport_layer_pipes ();
-
- private:
- /* for pipe based communications */
- void init_security ();
- SECURITY_DESCRIPTOR sd;
- SECURITY_ATTRIBUTES sec_none_nih, sec_all_nih;
- char pipe_name [MAX_PATH];
- HANDLE pipe;
- bool inited;
- transport_layer_pipes (HANDLE new_pipe);
+public:
+#ifndef __INSIDE_CYGWIN__
+ virtual int listen ();
+ virtual class transport_layer_pipes *accept (bool *recoverable);
+#endif
+
+ virtual void close ();
+ virtual ssize_t read (void *buf, size_t len);
+ virtual ssize_t write (void *buf, size_t len);
+ virtual int connect ();
+
+#ifndef __INSIDE_CYGWIN__
+ virtual void impersonate_client ();
+ virtual void revert_to_self ();
+#endif
+
+ transport_layer_pipes ();
+ virtual ~transport_layer_pipes ();
+
+private:
+ /* for pipe based communications */
+ void init_security ();
+
+ //FIXME: allow inited, sd, all_nih_.. to be static members
+ SECURITY_DESCRIPTOR _sd;
+ SECURITY_ATTRIBUTES _sec_all_nih;
+ const char *const _pipe_name;
+ HANDLE _hPipe;
+ const bool _is_accepted_endpoint;
+ bool _is_listening_endpoint;
+
+ transport_layer_pipes (HANDLE hPipe);
};
+
#endif /* _CYGSERVER_TRANSPORT_PIPES_ */
diff --git a/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h b/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
index 94dc43e38..d960f9c2c 100755
--- a/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
+++ b/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
@@ -1,33 +1,46 @@
-/* cygserver.cc
+/* cygserver_transport_sockets.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
#ifndef _CYGSERVER_TRANSPORT_SOCKETS_
#define _CYGSERVER_TRANSPORT_SOCKETS_
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
class transport_layer_sockets : public transport_layer_base
{
- public:
- virtual void listen ();
- virtual class transport_layer_sockets * accept ();
- virtual void close ();
- virtual ssize_t read (char *buf, size_t len);
- virtual ssize_t write (char *buf, size_t len);
- virtual bool connect();
- transport_layer_sockets ();
-
- private:
- /* for socket based communications */
- int fd;
- struct sockaddr sockdetails;
- int sdlen;
- transport_layer_sockets (int newfd);
+public:
+#ifndef __INSIDE_CYGWIN__
+ virtual int listen ();
+ virtual class transport_layer_sockets *accept (bool *recoverable);
+#endif
+
+ virtual void close ();
+ virtual ssize_t read (void *buf, size_t len);
+ virtual ssize_t write (void *buf, size_t len);
+ virtual int connect ();
+
+ transport_layer_sockets ();
+ virtual ~transport_layer_sockets ();
+
+private:
+ /* for socket based communications */
+ int _fd;
+ struct sockaddr_un _addr;
+ socklen_t _addr_len;
+ const bool _is_accepted_endpoint;
+ bool _is_listening_endpoint;
+
+ transport_layer_sockets (int fd);
};
+
#endif /* _CYGSERVER_TRANSPORT_SOCKETS_ */
diff --git a/winsup/cygwin/include/cygwin/grp.h b/winsup/cygwin/include/cygwin/grp.h
new file mode 100644
index 000000000..7dcae637d
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/grp.h
@@ -0,0 +1,48 @@
+/* cygwin/grp.h
+
+ Copyright 2002 Red Hat Inc.
+ Written by Corinna Vinschen <corinna@vinschen.de>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _CYGWIN_GRP_H_
+#define _CYGWIN_GRP_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __INSIDE_CYGWIN__
+struct __group16
+{
+ char *gr_name;
+ char *gr_passwd;
+ __gid16_t gr_gid;
+ char **gr_mem;
+};
+
+struct __group32
+{
+ char *gr_name;
+ char *gr_passwd;
+ __gid32_t gr_gid;
+ char **gr_mem;
+};
+
+struct __group32 * getgrgid32 (__gid32_t gid);
+struct __group32 * getgrnam32 (const char *name);
+__gid32_t getgid32 ();
+__gid32_t getegid32 ();
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CYGWIN_GRP_H_ */
diff --git a/winsup/cygwin/include/cygwin/if.h b/winsup/cygwin/include/cygwin/if.h
index a743ed5ce..b0953de36 100644
--- a/winsup/cygwin/include/cygwin/if.h
+++ b/winsup/cygwin/include/cygwin/if.h
@@ -38,20 +38,20 @@ struct ifreq
{
#define IFNAMSIZ 16
#define IFHWADDRLEN 6
- union
- {
- char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
- } ifr_ifrn;
-
- union {
- struct sockaddr ifru_addr;
- struct sockaddr ifru_broadaddr;
- struct sockaddr ifru_netmask;
- struct sockaddr ifru_hwaddr;
- short ifru_flags;
- int ifru_metric;
- int ifru_mtu;
- } ifr_ifru;
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_metric;
+ int ifru_mtu;
+ } ifr_ifru;
};
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
@@ -73,12 +73,12 @@ struct ifreq
struct ifconf
{
- int ifc_len; /* size of buffer */
- union
- {
- caddr_t ifcu_buf;
- struct ifreq *ifcu_req;
- } ifc_ifcu;
+ int ifc_len; /* size of buffer */
+ union
+ {
+ caddr_t ifcu_buf;
+ struct ifreq *ifcu_req;
+ } ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
diff --git a/winsup/cygwin/include/cygwin/ip.h b/winsup/cygwin/include/cygwin/ip.h
deleted file mode 100644
index e4f23c753..000000000
--- a/winsup/cygwin/include/cygwin/ip.h
+++ /dev/null
@@ -1 +0,0 @@
-/* ip.h */
diff --git a/winsup/cygwin/include/cygwin/ipc.h b/winsup/cygwin/include/cygwin/ipc.h
new file mode 100644
index 000000000..8a88a1085
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/ipc.h
@@ -0,0 +1,53 @@
+/* sys/ipc.h
+
+ Copyright 2001, 2002 Red Hat Inc.
+ Written by Robert Collins <rbtcollins@hotmail.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _SYS_IPC_H
+#define _SYS_IPC_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct ipc_perm
+{
+ uid_t uid; /* Owner's user ID. */
+ gid_t gid; /* Owner's group ID. */
+ uid_t cuid; /* Creator's user ID. */
+ gid_t cgid; /* Creator's group ID. */
+ mode_t mode; /* Read/write permission. */
+ key_t key;
+};
+
+/* Mode bits:
+ */
+#define IPC_CREAT 0x0200 /* Create entry if key does not exist. */
+#define IPC_EXCL 0x0400 /* Fail if key exists. */
+#define IPC_NOWAIT 0x0800 /* Error if request must wait. */
+
+/* Keys:
+ */
+#define IPC_PRIVATE ((key_t) 0) /* Private key. */
+
+/* Control commands:
+ */
+#define IPC_RMID 0x1000 /* Remove identifier. */
+#define IPC_SET 0x1001 /* Set options. */
+#define IPC_STAT 0x1002 /* Get options. */
+#define IPC_INFO 0x1003 /* For ipcs(8). */
+
+key_t ftok (const char *path, int id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_IPC_H */
diff --git a/winsup/cygwin/include/cygwin/msg.h b/winsup/cygwin/include/cygwin/msg.h
new file mode 100644
index 000000000..14e89f556
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/msg.h
@@ -0,0 +1,92 @@
+/* sys/msg.h
+
+ Copyright 2002 Red Hat Inc.
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _SYS_MSG_H
+#define _SYS_MSG_H
+
+#include <cygwin/ipc.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Message operation flags:
+ */
+#define MSG_NOERROR 0x01 /* No error if big message. */
+
+/* Command definitions for the semctl () function:
+ */
+#define MSG_STAT 0x2000 /* For ipcs(8) */
+#define MSG_INFO 0x2001 /* For ipcs(8) */
+
+/* Used for the number of messages in the message queue.
+ */
+typedef long int msgqnum_t;
+
+/* Used for the number of bytes allowed in a message queue.
+ */
+typedef long int msglen_t;
+
+struct msqid_ds
+{
+ struct ipc_perm msg_perm; /* Operation permission structure. */
+ msglen_t msg_cbytes; /* Number of bytes currently on queue. */
+ msgqnum_t msg_qnum; /* Number of messages currently on queue. */
+ msglen_t msg_qbytes; /* Maximum number of bytes allowed on queue. */
+ pid_t msg_lspid; /* Process ID of last msgsnd (). */
+ pid_t msg_lrpid; /* Process ID of last msgrcv (). */
+ timestruc_t msg_stim; /* Time of last msgsnd (). */
+ timestruc_t msg_rtim; /* Time of last msgrcv (). */
+ timestruc_t msg_ctim; /* Time of last change. */
+ long msg_spare4[2];
+};
+
+#define msg_stime msg_stim.tv_sec
+#define msg_rtime msg_rtim.tv_sec
+#define msg_ctime msg_ctim.tv_sec
+
+/* Buffer type for msgctl (IPC_INFO, ...) as used by ipcs(8).
+ */
+struct msginfo
+{
+ unsigned long msgpool; /* Maximum number of message bytes,
+ system wide. */
+ unsigned long msgmax; /* Maximum number of bytes per
+ message. */
+ unsigned long msgmnb; /* Maximum number of bytes on any one
+ message queue. */
+ unsigned long msgmni; /* Maximum number of message queues,
+ system wide. */
+ unsigned long msgtql; /* Maximum number of messages, system
+ wide. */
+ unsigned long msg_spare[4];
+};
+
+/* Buffer type for msgctl (MSG_INFO, ...) as used by ipcs(8).
+ */
+struct msg_info
+{
+ unsigned long msg_ids; /* Number of allocated queues. */
+ unsigned long msg_num; /* Number of messages, system wide. */
+ unsigned long msg_tot; /* Size in bytes of messages, system wide. */
+};
+
+int msgctl (int msqid, int cmd, struct msqid_ds *buf);
+int msgget (key_t key, int msgflg);
+ssize_t msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
+int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MSG_H */
diff --git a/winsup/cygwin/include/cygwin/mtio.h b/winsup/cygwin/include/cygwin/mtio.h
index 213fc7dc0..04e65234c 100644
--- a/winsup/cygwin/include/cygwin/mtio.h
+++ b/winsup/cygwin/include/cygwin/mtio.h
@@ -20,6 +20,10 @@ details. */
#include <sys/ioctl.h>
#include <asm/socket.h>
+#ifndef DEFTAPE
+#define DEFTAPE "/dev/tape"
+#endif
+
/*
* Structures and definitions for mag tape io control commands
*/
@@ -85,7 +89,8 @@ struct mtget {
* Cygwin: remaining KB.
*/
/* the following registers are device dependent */
- long mt_dsreg; /* status register */
+ long mt_dsreg; /* status register, Cygwin returns current
+ blocksize here. */
long mt_gstat; /* generic (device independent) status */
long mt_erreg; /* error register */
/* The next two fields are not always used */
@@ -99,6 +104,7 @@ struct mtget {
int mt_defblksize;
unsigned long mt_featureslow;
unsigned long mt_featureshigh;
+ unsigned long mt_eotwarningzonesize;
};
/* structure for MTIOCPOS - mag tape get position command */
diff --git a/winsup/cygwin/include/cygwin/sem.h b/winsup/cygwin/include/cygwin/sem.h
new file mode 100644
index 000000000..a3ece9f8a
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/sem.h
@@ -0,0 +1,95 @@
+/* sys/sem.h
+
+ Copyright 2002 Red Hat Inc.
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _SYS_SEM_H
+#define _SYS_SEM_H
+
+#include <cygwin/ipc.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Semaphore operation flags:
+ */
+#define SEM_UNDO /* Set up adjust on exit entry. */
+
+/* Command definitions for the semctl () function:
+ */
+#define GETNCNT 0x3000 /* Get semncnt. */
+#define GETPID 0x3001 /* Get sempid. */
+#define GETVAL 0x3002 /* Get semval. */
+#define GETALL 0x3003 /* Get all cases of semval. */
+#define GETZCNT 0x3004 /* Get semzcnt. */
+#define SETVAL 0x3005 /* Set semval. */
+#define SETALL 0x3006 /* Set all cases of semval. */
+
+#define SEM_STAT 0x3010 /* For ipcs(8). */
+#define SEM_INFO 0x3011 /* For ipcs(8). */
+
+struct semid_ds
+{
+ struct ipc_perm sem_perm; /* Operation permission structure. */
+ unsigned short sem_nsems; /* Number of semaphores in set. */
+ timestruc_t sem_otim; /* Last semop () time. */
+ timestruc_t sem_ctim; /* Last time changed by semctl (). */
+ long sem_spare4[2];
+};
+
+#define sem_otime sem_otim.tv_sec
+#define sem_ctime sem_ctim.tv_sec
+
+struct sembuf
+{
+ unsigned short sem_num; /* Semaphore number. */
+ short sem_op; /* Semaphore operation. */
+ short sem_flg; /* Operation flags. */
+};
+
+/* Buffer type for semctl (IPC_INFO, ...) as used by ipcs(8).
+ */
+struct seminfo
+{
+ unsigned long semmni; /* Maximum number of unique semaphore
+ sets, system wide. */
+ unsigned long semmns; /* Maximum number of semaphores,
+ system wide. */
+ unsigned long semmsl; /* Maximum number of semaphores per
+ semaphore set. */
+ unsigned long semopm; /* Maximum number of operations per
+ semop call. */
+ unsigned long semmnu; /* Maximum number of undo structures,
+ system wide. */
+ unsigned long semume; /* Maximum number of undo entries per
+ undo structure. */
+ unsigned long semvmx; /* Maximum semaphore value. */
+ unsigned long semaem; /* Maximum adjust-on-exit value. */
+ unsigned long sem_spare[4];
+};
+
+/* Buffer type for semctl (SEM_INFO, ...) as used by ipcs(8).
+ */
+struct sem_info
+{
+ unsigned long sem_ids; /* Number of allocated semaphore sets. */
+ unsigned long sem_num; /* Number of allocated semaphores. */
+};
+
+int semctl (int semid, int semnum, int cmd, ...);
+int semget (key_t key, int nsems, int semflg);
+int semop (int semid, struct sembuf *sops, size_t nsops);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SEM_H */
diff --git a/winsup/cygwin/include/cygwin/shm.h b/winsup/cygwin/include/cygwin/shm.h
new file mode 100644
index 000000000..b6b2d447c
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/shm.h
@@ -0,0 +1,94 @@
+/* sys/shm.h
+
+ Copyright 2001, 2002 Red Hat Inc.
+ Written by Robert Collins <rbtcollins@hotmail.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _SYS_SHM_H
+#define _SYS_SHM_H
+
+#include <cygwin/ipc.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* 64 Kb was hardcoded for x86. MS states this may change, but we need
+ * it in the header file.
+ */
+#define SHMLBA 65536 /* Segment low boundary address multiple. */
+
+/* Shared memory operation flags:
+ */
+#define SHM_RDONLY 0x01 /* Attach read-only (else read-write). */
+#define SHM_RND 0x02 /* Round attach address to SHMLBA. */
+
+/* Command definitions for the semctl () function:
+ */
+#define SHM_STAT 0x4000 /* For ipcs(8) */
+#define SHM_INFO 0x4001 /* For ipcs(8) */
+
+/* Unsigned integer used for the number of current attaches.
+ */
+typedef unsigned int shmatt_t;
+
+struct shmid_ds
+{
+ struct ipc_perm shm_perm; /* Operation permission structure. */
+ size_t shm_segsz; /* Size of segment in bytes. */
+ pid_t shm_lpid; /* Process ID of last operation. */
+ pid_t shm_cpid; /* Process ID of creator. */
+ shmatt_t shm_nattch; /* Number of current attaches. */
+ timestruc_t shm_atim; /* Time of last shmat (). */
+ timestruc_t shm_dtim; /* Time of last shmdt (). */
+ timestruc_t shm_ctim; /* Time of last change by shmctl (). */
+ long shm_spare4[2];
+};
+
+#define shm_atime shm_atim.tv_sec
+#define shm_dtime shm_dtim.tv_sec
+#define shm_ctime shm_ctim.tv_sec
+
+/* Buffer type for shmctl (IPC_INFO, ...) as used by ipcs(8).
+ */
+struct shminfo
+{
+ unsigned long shmmax; /* Maximum size in bytes of a shared
+ memory segment. */
+ unsigned long shmmin; /* Minimum size in bytes of a shared
+ memory segment. */
+ unsigned long shmmni; /* Maximum number of shared memory
+ segments, system wide. */
+ unsigned long shmseg; /* Maximum number of shared memory
+ segments attached per process. */
+ unsigned long shmall; /* Maximum number of bytes of shared
+ memory, system wide. */
+ unsigned long shm_spare[4];
+};
+
+/* Buffer type for shmctl (SHM_INFO, ...) as used by ipcs(8).
+ */
+struct shm_info
+{
+ unsigned long shm_ids; /* Number of allocated segments. */
+ unsigned long shm_tot; /* Size in bytes of allocated segments. */
+ unsigned long shm_atts; /* Number of attached segments, system
+ wide. */
+};
+
+void *shmat (int shmid, const void *shmaddr, int shmflg);
+int shmctl (int shmid, int cmd, struct shmid_ds *buf);
+int shmdt (const void *shmaddr);
+int shmget (key_t key, size_t size, int shmflg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SHM_H */
diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h
index da747fd3d..3a40c12a3 100644
--- a/winsup/cygwin/include/cygwin/socket.h
+++ b/winsup/cygwin/include/cygwin/socket.h
@@ -112,6 +112,8 @@ struct msghdr
#define MSG_OOB 0x1 /* process out-of-band data */
#define MSG_PEEK 0x2 /* peek at incoming message */
#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define MSG_WINMASK 0x7 /* flags understood by WinSock calls */
+#define MSG_NOSIGNAL 0x20 /* Don't raise SIGPIPE */
/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
#define SOL_IP 0
@@ -123,9 +125,11 @@ struct msghdr
#define SOL_UDP 17
/* IP options */
+#ifndef IPTOS_LOWDELAY
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
+#endif
/* These need to appear somewhere around here */
#define IP_DEFAULT_MULTICAST_TTL 1
@@ -148,8 +152,10 @@ struct msghdr
#define IPX_TYPE 1
/* TCP options - this way around because someone left a set in the c library includes */
+#ifndef TCP_NODELAY
#define TCP_NODELAY 0x0001
#define TCP_MAXSEG 2
+#endif
/* The various priorities. */
#define SOPRI_INTERACTIVE 0
diff --git a/winsup/cygwin/include/cygwin/stat.h b/winsup/cygwin/include/cygwin/stat.h
new file mode 100644
index 000000000..5772a3754
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/stat.h
@@ -0,0 +1,88 @@
+/* cygwin/stat.h
+
+ Copyright 2002 Red Hat Inc.
+ Written by Corinna Vinschen <corinna@vinschen.de>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _CYGWIN_STAT_H
+#define _CYGWIN_STAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __INSIDE_CYGWIN__
+struct __stat32
+{
+ __dev16_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ __uid16_t st_uid;
+ __gid16_t st_gid;
+ __dev16_t st_rdev;
+ __off32_t st_size;
+ timestruc_t st_atim;
+ timestruc_t st_mtim;
+ timestruc_t st_ctim;
+ blksize_t st_blksize;
+ __blkcnt32_t st_blocks;
+ long st_spare4[2];
+};
+
+struct __stat64
+{
+ __dev32_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ __uid32_t st_uid;
+ __gid32_t st_gid;
+ __dev32_t st_rdev;
+ __off64_t st_size;
+ timestruc_t st_atim;
+ timestruc_t st_mtim;
+ timestruc_t st_ctim;
+ blksize_t st_blksize;
+ __blkcnt64_t st_blocks;
+ long st_spare4[2];
+};
+
+extern int fstat64 (int fd, struct __stat64 *buf);
+extern int stat64 (const char *file_name, struct __stat64 *buf);
+extern int lstat64 (const char *file_name, struct __stat64 *buf);
+
+#endif
+
+struct stat
+{
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ timestruc_t st_atim;
+ timestruc_t st_mtim;
+ timestruc_t st_ctim;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+ long st_spare4[2];
+};
+
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+#define st_ctime st_ctim.tv_sec
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CYGWIN_STAT_H */
diff --git a/winsup/cygwin/include/cygwin/types.h b/winsup/cygwin/include/cygwin/types.h
index 7114b7c4a..69bfa2056 100644
--- a/winsup/cygwin/include/cygwin/types.h
+++ b/winsup/cygwin/include/cygwin/types.h
@@ -1,6 +1,6 @@
/* types.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
This file is part of Cygwin.
@@ -17,6 +17,48 @@ extern "C"
#ifndef _CYGWIN_TYPES_H
#define _CYGWIN_TYPES_H
+#include <sys/sysmacros.h>
+
+typedef struct timespec timespec_t, timestruc_t;
+
+typedef long __off32_t;
+typedef long long __off64_t;
+#ifdef __CYGWIN_USE_BIG_TYPES__
+typedef __off64_t off_t;
+#else
+typedef __off32_t off_t;
+#endif
+
+typedef short __dev16_t;
+typedef unsigned long __dev32_t;
+#ifdef __CYGWIN_USE_BIG_TYPES__
+typedef __dev32_t dev_t;
+#else
+typedef __dev16_t dev_t;
+#endif
+
+typedef long blksize_t;
+
+typedef long __blkcnt32_t;
+typedef long long __blkcnt64_t;
+#ifdef __CYGWIN_USE_BIG_TYPES__
+typedef __blkcnt64_t blkcnt_t;
+#else
+typedef __blkcnt32_t blkcnt_t;
+#endif
+
+typedef unsigned short __uid16_t;
+typedef unsigned short __gid16_t;
+typedef unsigned long __uid32_t;
+typedef unsigned long __gid32_t;
+#ifdef __CYGWIN_USE_BIG_TYPES__
+typedef __uid32_t uid_t;
+typedef __gid32_t gid_t;
+#else
+typedef __uid16_t uid_t;
+typedef __gid16_t gid_t;
+#endif
+
#if !defined(__INSIDE_CYGWIN__) || !defined(__cplusplus)
typedef void *pthread_t;
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 65adf7c9a..da5591561 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -41,10 +41,10 @@ details. */
the Cygwin library". This version is used to track important
changes to the DLL and is mainly informative in nature. */
- /* The current cygwin version is 1.3.4 */
+ /* The current cygwin version is 1.3.6 */
#define CYGWIN_VERSION_DLL_MAJOR 1003
-#define CYGWIN_VERSION_DLL_MINOR 4
+#define CYGWIN_VERSION_DLL_MINOR 13
/* Major numbers before CYGWIN_VERSION_DLL_EPOCH are
incompatible. */
@@ -93,12 +93,12 @@ details. */
/* API_MAJOR 0.0: Initial version. API_MINOR changes:
1: Export cygwin32_ calls as cygwin_ as well.
2: Export j1, jn, y1, yn.
- 3: Export dll_noncygwin_dllcrt0.
- 4: New socket ioctls, revamped ifconf support.
- 5: Thread support/exports.
- 6: Change in termios handling.
- 7: Export scandir and alphasort.
- 8: Export _ctype_, _sys_errlist, _sys_nerr.
+ 3: Export dll_noncygwin_dllcrt0.
+ 4: New socket ioctls, revamped ifconf support.
+ 5: Thread support/exports.
+ 6: Change in termios handling.
+ 7: Export scandir and alphasort.
+ 8: Export _ctype_, _sys_errlist, _sys_nerr.
9: Mount-related changes, new cygwin_umount export.
Raw device support (tape, floppies).
10: Fast math routine support added.
@@ -114,10 +114,10 @@ details. */
20: regsub, inet_network
21: incompatible change to stdio cr/lf and buffering
22: Export cygwin_logon_user, cygwin_set_impersonation_token.
- geteuid, getegid return effective uid/gid.
- getuid, getgid return real uid/gid.
- seteuid, setegid set only effective uid/gid.
- setuid, setgid set effective and real uid/gid.
+ geteuid, getegid return effective uid/gid.
+ getuid, getgid return real uid/gid.
+ seteuid, setegid set only effective uid/gid.
+ setuid, setgid set effective and real uid/gid.
23: Export new dll_crt0 interface and cygwin_user_data for use
with crt0 startup code.
24: Export poll and _poll.
@@ -132,7 +132,7 @@ details. */
33: Export setlogmask
34: Separated out mount table
35: Export drand48, erand48, jrand48, lcong48, lrand48,
- mrand48, nrand48, seed48, and srand48.
+ mrand48, nrand48, seed48, and srand48.
36: Added _cygwin_S_IEXEC, et al
37: [f]pathconv support _PC_POSIX_PERMISSIONS and _PC_POSIX_SECURITY
38: vscanf, vscanf_r, and random pthread functions
@@ -144,10 +144,30 @@ details. */
44: Export dirfd
45: perprocess change, gamma_r, gammaf_r, lgamma_r, lgammaf_r
46: Remove cygwin_getshared
+ 47: Report EOTWarningZoneSize in struct mtget.
+ 48: Export "posix" regex functions
+ 49: Export setutent, endutent, utmpname, getutent, getutid, getutline.
+ 50: Export fnmatch.
+ 51: Export recvmsg, sendmsg.
+ 52: Export strptime
+ 53: Export strlcat, strlcpy.
+ 54: Export __fpclassifyd, __fpclassifyf, __signbitd, __signbitf.
+ 55: Export fcloseall, fcloseall_r.
+ 56: Make ntsec on by default.
+ 57: Export setgroups.
+ 58: Export memalign, valloc, malloc_trim, malloc_usable_size, mallopt,
+ malloc_stats
+ 59: getsid
+ 60: MSG_NOSIGNAL
+ 61: Export getc_unlocked, getchar_unlocked, putc_unlocked,
+ putchar_unlocked
+ 62: Erroneously bumped.
*/
+ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
+
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 46
+#define CYGWIN_VERSION_API_MINOR 62
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
@@ -212,3 +232,5 @@ details. */
cygwin_internal (CW_GETVERSIONINFO).
*/
+#define CYGWIN_VERSION_MAGIC(a, b) ((unsigned) (((unsigned short) a) | (unsigned short) b))
+#define CYGWIN_VERSION_MAGIC_VERSION(a) ((unsigned) ((unsigned)a & 0xffff))
diff --git a/winsup/cygwin/include/fnmatch.h b/winsup/cygwin/include/fnmatch.h
new file mode 100644
index 000000000..e4500abe2
--- /dev/null
+++ b/winsup/cygwin/include/fnmatch.h
@@ -0,0 +1,63 @@
+/* $OpenBSD: fnmatch.h,v 1.5 2000/03/24 17:13:23 millert Exp $ */
+/* $NetBSD: fnmatch.h,v 1.5 1994/10/26 00:55:53 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _FNMATCH_H_
+#define _FNMATCH_H_
+
+#define FNM_NOMATCH 1 /* Match failed. */
+#define FNM_NOSYS 2 /* Function not supported (unused). */
+
+#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
+#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
+#define FNM_PERIOD 0x04 /* Period must be matched by period. */
+#ifndef _POSIX_SOURCE
+#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
+#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
+#define FNM_IGNORECASE FNM_CASEFOLD
+#define FNM_FILE_NAME FNM_PATHNAME
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int fnmatch __P((const char *, const char *, int));
+__END_DECLS
+
+#endif /* !_FNMATCH_H_ */
+
+
diff --git a/winsup/cygwin/include/getopt.h b/winsup/cygwin/include/getopt.h
index b05b32fdd..6b6f643b7 100644
--- a/winsup/cygwin/include/getopt.h
+++ b/winsup/cygwin/include/getopt.h
@@ -38,13 +38,6 @@
extern "C" {
#endif
-struct option {
- const char *name;
- int has_arg;
- int *flag;
- int val;
-};
-
extern int opterr; /* if error message should be printed */
extern int optind; /* index into parent argv vector */
extern int optopt; /* character checked for validity */
@@ -53,7 +46,31 @@ extern char *optarg; /* argument associated with option */
int getopt (int, char * const *, const char *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GETOPT_H__ */
+
+#ifndef __UNISTD_GETOPT__
+#ifndef __GETOPT_LONG_H__
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
int getopt_long (int, char *const *, const char *, const struct option *, int *);
+#ifndef HAVE_DECL_GETOPT
+#define HAVE_DECL_GETOPT 1
+#endif
#define no_argument 0
#define required_argument 1
@@ -63,4 +80,5 @@ int getopt_long (int, char *const *, const char *, const struct option *, int *)
}
#endif
-#endif /* __GETOPT_H__ */
+#endif /* __GETOPT_LONG_H__ */
+#endif /* __UNISTD_GETOPT__ */
diff --git a/winsup/cygwin/include/glob.h b/winsup/cygwin/include/glob.h
index 3fdf3e8ae..6a393f004 100644
--- a/winsup/cygwin/include/glob.h
+++ b/winsup/cygwin/include/glob.h
@@ -41,8 +41,6 @@
#ifndef _GLOB_H_
#define _GLOB_H_
-/* CYGNUS LOCAL: end */
-
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -68,9 +66,14 @@ typedef struct {
int (*gl_lstat) __P((const char *, struct stat12 *));
int (*gl_stat) __P((const char *, struct stat12 *));
#else
+#if defined (__INSIDE_CYGWIN__)
+ int (*gl_lstat) ();
+ int (*gl_stat) ();
+#else
int (*gl_lstat) __P((const char *, struct stat *));
int (*gl_stat) __P((const char *, struct stat *));
#endif
+#endif
} glob_t;
#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
@@ -93,7 +96,6 @@ typedef struct {
#define GLOB_ABEND (-2) /* Unignored error. */
__BEGIN_DECLS
-/* CYGNUS LOCAL: normal protos */
#undef DLLEXPORT
#ifdef __INSIDE_CYGWIN__
@@ -105,7 +107,6 @@ int DLLEXPORT glob(const char *, int, int (*)(const char *, int), glob_t *);
void DLLEXPORT globfree(glob_t *);
#undef DLLEXPORT
-/* end CYGNUS LOCAL */
__END_DECLS
#endif /* !_GLOB_H_ */
diff --git a/winsup/cygwin/include/limits.h b/winsup/cygwin/include/limits.h
index 715a49ac3..78c475170 100644
--- a/winsup/cygwin/include/limits.h
+++ b/winsup/cygwin/include/limits.h
@@ -88,11 +88,12 @@ details. */
#undef ULONG_MAX
#define ULONG_MAX (LONG_MAX * 2UL + 1)
-#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__)
/* Minimum and maximum values a `signed long long int' can hold. */
#ifndef __LONG_LONG_MAX__
#define __LONG_LONG_MAX__ 9223372036854775807LL
#endif
+
+#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__)
#undef LONG_LONG_MIN
#define LONG_LONG_MIN (-LONG_LONG_MAX-1)
#undef LONG_LONG_MAX
@@ -103,6 +104,18 @@ details. */
#define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1)
#endif
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+/* Minimum and maximum values a `signed long long int' can hold. */
+#undef LLONG_MIN
+#define LLONG_MIN (-LLONG_MAX-1)
+#undef LLONG_MAX
+#define LLONG_MAX __LONG_LONG_MAX__
+
+/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
+#undef ULLONG_MAX
+#define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+#endif
+
/* Maximum number of iovcnt in a writev */
#undef IOV_MAX
#define IOV_MAX (__INT_MAX__-1)
diff --git a/winsup/cygwin/include/netinet/ip.h b/winsup/cygwin/include/netinet/ip.h
index 33c59f87a..a8dac5b67 100644
--- a/winsup/cygwin/include/netinet/ip.h
+++ b/winsup/cygwin/include/netinet/ip.h
@@ -1,16 +1,199 @@
-/* netinet/ip.h
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ip.h 8.2 (Berkeley) 6/1/94
+ * $FreeBSD: src/sys/netinet/ip.h,v 1.17 1999/12/22 19:13:20 shin Exp $
+ */
- Copyright 1998, 2001 Red Hat, Inc.
+#ifndef _NETINET_IP_H
+#define _NETINET_IP_H
-This file is part of Cygwin.
+/* Added by Wu Yongwei */
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#define BIG_ENDIAN 4321
+#endif
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
+/*
+ * Definitions for internet protocol version 4.
+ * Per RFC 791, September 1981.
+ */
+#define IPVERSION 4
-#ifndef _NETINET_IP_H
-#define _NETINET_IP_H
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip {
+#ifdef _IP_VHL
+ u_char ip_vhl; /* version << 4 | header length >> 2 */
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int ip_hl:4, /* header length */
+ ip_v:4; /* version */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int ip_v:4, /* version */
+ ip_hl:4; /* header length */
+#endif
+#endif /* not _IP_VHL */
+ u_char ip_tos; /* type of service */
+ u_short ip_len; /* total length */
+ u_short ip_id; /* identification */
+ u_short ip_off; /* fragment offset field */
+#define IP_RF 0x8000 /* reserved fragment flag */
+#define IP_DF 0x4000 /* dont fragment flag */
+#define IP_MF 0x2000 /* more fragments flag */
+#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
+ u_char ip_ttl; /* time to live */
+ u_char ip_p; /* protocol */
+ u_short ip_sum; /* checksum */
+ struct in_addr ip_src,ip_dst; /* source and dest address */
+};
+
+#ifdef _IP_VHL
+#define IP_MAKE_VHL(v, hl) ((v) << 4 | (hl))
+#define IP_VHL_HL(vhl) ((vhl) & 0x0f)
+#define IP_VHL_V(vhl) ((vhl) >> 4)
+#define IP_VHL_BORING 0x45
+#endif
+
+#define IP_MAXPACKET 65535 /* maximum packet size */
+
+/*
+ * Definitions for IP type of service (ip_tos)
+ */
+#ifndef IPTOS_LOWDELAY
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#endif
+#define IPTOS_MINCOST 0x02
+/* ECN bits proposed by Sally Floyd */
+#define IPTOS_CE 0x01 /* congestion experienced */
+#define IPTOS_ECT 0x02 /* ECN-capable transport */
+
+
+/*
+ * Definitions for IP precedence (also in ip_tos) (hopefully unused)
+ */
+#define IPTOS_PREC_NETCONTROL 0xe0
+#define IPTOS_PREC_INTERNETCONTROL 0xc0
+#define IPTOS_PREC_CRITIC_ECP 0xa0
+#define IPTOS_PREC_FLASHOVERRIDE 0x80
+#define IPTOS_PREC_FLASH 0x60
+#define IPTOS_PREC_IMMEDIATE 0x40
+#define IPTOS_PREC_PRIORITY 0x20
+#define IPTOS_PREC_ROUTINE 0x00
+
+/*
+ * Definitions for options.
+ */
+#define IPOPT_COPIED(o) ((o)&0x80)
+#define IPOPT_CLASS(o) ((o)&0x60)
+#define IPOPT_NUMBER(o) ((o)&0x1f)
+
+#define IPOPT_CONTROL 0x00
+#define IPOPT_RESERVED1 0x20
+#define IPOPT_DEBMEAS 0x40
+#define IPOPT_RESERVED2 0x60
+
+#define IPOPT_EOL 0 /* end of option list */
+#define IPOPT_NOP 1 /* no operation */
+
+#define IPOPT_RR 7 /* record packet route */
+#define IPOPT_TS 68 /* timestamp */
+#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
+#define IPOPT_LSRR 131 /* loose source route */
+#define IPOPT_SATID 136 /* satnet id */
+#define IPOPT_SSRR 137 /* strict source route */
+#define IPOPT_RA 148 /* router alert */
+
+/*
+ * Offsets to fields in options other than EOL and NOP.
+ */
+#define IPOPT_OPTVAL 0 /* option ID */
+#define IPOPT_OLEN 1 /* option length */
+#define IPOPT_OFFSET 2 /* offset within option */
+#define IPOPT_MINOFF 4 /* min value of above */
+
+/*
+ * Time stamp option structure.
+ */
+struct ip_timestamp {
+ u_char ipt_code; /* IPOPT_TS */
+ u_char ipt_len; /* size of structure (variable) */
+ u_char ipt_ptr; /* index of current entry */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int ipt_flg:4, /* flags, see below */
+ ipt_oflw:4; /* overflow counter */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int ipt_oflw:4, /* overflow counter */
+ ipt_flg:4; /* flags, see below */
+#endif
+ union ipt_timestamp {
+ n_long ipt_time[1];
+ struct ipt_ta {
+ struct in_addr ipt_addr;
+ n_long ipt_time;
+ } ipt_ta[1];
+ } ipt_timestamp;
+};
+
+/* flag bits for ipt_flg */
+#define IPOPT_TS_TSONLY 0 /* timestamps only */
+#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
+#define IPOPT_TS_PRESPEC 3 /* specified modules only */
+
+/* bits for security (not byte swapped) */
+#define IPOPT_SECUR_UNCLASS 0x0000
+#define IPOPT_SECUR_CONFID 0xf135
+#define IPOPT_SECUR_EFTO 0x789a
+#define IPOPT_SECUR_MMMM 0xbc4d
+#define IPOPT_SECUR_RESTR 0xaf13
+#define IPOPT_SECUR_SECRET 0xd788
+#define IPOPT_SECUR_TOPSECRET 0x6bc5
+
+/*
+ * Internet implementation parameters.
+ */
+#define MAXTTL 255 /* maximum time to live (seconds) */
+#define IPDEFTTL 64 /* default ttl, from RFC 1340 */
+#define IPFRAGTTL 60 /* time to live for frags, slowhz */
+#define IPTTLDEC 1 /* subtracted when forwarding */
-#include <cygwin/ip.h>
+#define IP_MSS 576 /* default maximum segment size */
-#endif /* _NETINET_IP_H */
+#endif
diff --git a/winsup/cygwin/include/netinet/tcp.h b/winsup/cygwin/include/netinet/tcp.h
index eef9a6116..9fcee6c71 100644
--- a/winsup/cygwin/include/netinet/tcp.h
+++ b/winsup/cygwin/include/netinet/tcp.h
@@ -1,16 +1,144 @@
-/* netinet/tcp.h
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tcp.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/netinet/tcp.h,v 1.13 2000/01/09 19:17:25 shin Exp $
+ */
- Copyright 2000, 2001 Red Hat, Inc.
+#ifndef _NETINET_TCP_H
+#define _NETINET_TCP_H
-This file is part of Cygwin.
+/* Added by Wu Yongwei */
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#define BIG_ENDIAN 4321
+#endif
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
+typedef u_int32_t tcp_seq;
+typedef u_int32_t tcp_cc; /* connection count per rfc1644 */
-#ifndef _NETINET_TCP_H
-#define _NETINET_TCP_H
+#define tcp6_seq tcp_seq /* for KAME src sync over BSD*'s */
+#define tcp6hdr tcphdr /* for KAME src sync over BSD*'s */
+
+/*
+ * TCP header.
+ * Per RFC 793, September, 1981.
+ */
+struct tcphdr {
+ u_short th_sport; /* source port */
+ u_short th_dport; /* destination port */
+ tcp_seq th_seq; /* sequence number */
+ tcp_seq th_ack; /* acknowledgement number */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int th_x2:4, /* (unused) */
+ th_off:4; /* data offset */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int th_off:4, /* data offset */
+ th_x2:4; /* (unused) */
+#endif
+ u_char th_flags;
+#define TH_FIN 0x01
+#define TH_SYN 0x02
+#define TH_RST 0x04
+#define TH_PUSH 0x08
+#define TH_ACK 0x10
+#define TH_URG 0x20
+#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG)
-/* Maybe add some definitions, someday */
+ u_short th_win; /* window */
+ u_short th_sum; /* checksum */
+ u_short th_urp; /* urgent pointer */
+};
+
+#define TCPOPT_EOL 0
+#define TCPOPT_NOP 1
+#define TCPOPT_MAXSEG 2
+#define TCPOLEN_MAXSEG 4
+#define TCPOPT_WINDOW 3
+#define TCPOLEN_WINDOW 3
+#define TCPOPT_SACK_PERMITTED 4 /* Experimental */
+#define TCPOLEN_SACK_PERMITTED 2
+#define TCPOPT_SACK 5 /* Experimental */
+#define TCPOPT_TIMESTAMP 8
+#define TCPOLEN_TIMESTAMP 10
+#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */
+#define TCPOPT_TSTAMP_HDR \
+ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+
+#define TCPOPT_CC 11 /* CC options: RFC-1644 */
+#define TCPOPT_CCNEW 12
+#define TCPOPT_CCECHO 13
+#define TCPOLEN_CC 6
+#define TCPOLEN_CC_APPA (TCPOLEN_CC+2)
+#define TCPOPT_CC_HDR(ccopt) \
+ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|(ccopt)<<8|TCPOLEN_CC)
+
+/*
+ * Default maximum segment size for TCP.
+ * With an IP MSS of 576, this is 536,
+ * but 512 is probably more convenient.
+ * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+ */
+#define TCP_MSS 512
+
+/*
+ * Default maximum segment size for TCP6.
+ * With an IP6 MSS of 1280, this is 1220,
+ * but 1024 is probably more convenient. (xxx kazu in doubt)
+ * This should be defined as MIN(1024, IP6_MSS - sizeof (struct tcpip6hdr))
+ */
+#define TCP6_MSS 1024
+
+#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */
+#define TTCP_CLIENT_SND_WND 4096 /* dflt send window for T/TCP client */
+
+#define TCP_MAX_WINSHIFT 14 /* maximum window shift */
+
+#define TCP_MAXHLEN (0xf<<2) /* max length of header in bytes */
+#define TCP_MAXOLEN (TCP_MAXHLEN - sizeof(struct tcphdr))
+ /* max space left for options */
+
+/*
+ * User-settable options (used with setsockopt).
+ */
+#ifndef TCP_NODELAY
+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
+#define TCP_MAXSEG 0x02 /* set maximum segment size */
+#endif
+#define TCP_NOPUSH 0x04 /* don't push last block of write */
+#define TCP_NOOPT 0x08 /* don't use TCP options */
#endif
diff --git a/winsup/cygwin/include/netinet/udp.h b/winsup/cygwin/include/netinet/udp.h
new file mode 100644
index 000000000..61932720b
--- /dev/null
+++ b/winsup/cygwin/include/netinet/udp.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)udp.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/netinet/udp.h,v 1.7 1999/08/28 00:49:34 peter Exp $
+ */
+
+#ifndef _NETINET_UDP_H
+#define _NETINET_UDP_H
+
+/*
+ * Udp protocol header.
+ * Per RFC 768, September, 1981.
+ */
+struct udphdr {
+ u_short uh_sport; /* source port */
+ u_short uh_dport; /* destination port */
+ u_short uh_ulen; /* udp length */
+ u_short uh_sum; /* udp checksum */
+};
+
+#endif
diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h
index 486635da7..96aa4deea 100644
--- a/winsup/cygwin/include/pthread.h
+++ b/winsup/cygwin/include/pthread.h
@@ -42,8 +42,9 @@ extern "C"
#define PTHREAD_CANCEL_ENABLE 0
#define PTHREAD_CANCEL_DEFERRED 0
#define PTHREAD_CANCEL_DISABLE 1
-#define PTHREAD_CANCELED
-#define PTHREAD_COND_INITIALIZER
+#define PTHREAD_CANCELED ((void *)-1)
+/* this should be a value that can never be a valid address */
+#define PTHREAD_COND_INITIALIZER (void *)21
#define PTHREAD_CREATE_DETACHED 1
/* the default : joinable */
#define PTHREAD_CREATE_JOINABLE 0
@@ -83,7 +84,7 @@ int pthread_attr_setscope (pthread_attr_t *, int);
#ifdef _POSIX_THREAD_ATTR_STACKADDR
/* These functions may be implementable via some low level trickery. For now they are
- * Not supported or implemented. The prototypes are here so if someone greps the
+ * Not supported or implemented. The prototypes are here so if someone greps the
* source they will see these comments
*/
int pthread_attr_getstackaddr (const pthread_attr_t *, void **);
@@ -96,16 +97,26 @@ int pthread_attr_setstacksize (pthread_attr_t *, size_t);
#endif
int pthread_cancel (pthread_t);
-/* Macros for cleanup_push and pop;
+/* Macros for cleanup_push and pop;
* The function definitions are
void pthread_cleanup_push (void (*routine)(void*), void *arg);
void pthread_cleanup_pop (int execute);
*/
typedef void (*__cleanup_routine_type) (void *);
-
-#define pthread_cleanup_push(fn, arg) { __cleanup_routine_type __cleanup_routine=fn; \
-void *__cleanup_param=arg;
-#define pthread_cleanup_pop(execute) if (execute) __cleanup_routine(__cleanup_param); }
+typedef struct _pthread_cleanup_handler
+{
+ __cleanup_routine_type function;
+ void *arg;
+ struct _pthread_cleanup_handler *next;
+} __pthread_cleanup_handler;
+
+void _pthread_cleanup_push (__pthread_cleanup_handler *handler);
+void _pthread_cleanup_pop (int execute);
+
+#define pthread_cleanup_push(_fn, _arg) { __pthread_cleanup_handler __cleanup_handler = \
+ { _fn, _arg, NULL }; \
+ _pthread_cleanup_push( &__cleanup_handler );
+#define pthread_cleanup_pop(_execute) _pthread_cleanup_pop( _execute ); }
/* Condition variables */
int pthread_cond_broadcast (pthread_cond_t *);
diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h
index 1d53f636b..f8feda4c7 100644
--- a/winsup/cygwin/include/sys/cygwin.h
+++ b/winsup/cygwin/include/sys/cygwin.h
@@ -1,6 +1,6 @@
/* sys/cygwin.h
- Copyright 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -64,7 +64,13 @@ typedef enum
CW_GET_CYGDRIVE_PREFIXES,
CW_GETPINFO_FULL,
CW_INIT_EXCEPTIONS,
- CW_GET_CYGDRIVE_INFO
+ CW_GET_CYGDRIVE_INFO,
+ CW_SET_CYGWIN_REGISTRY_NAME,
+ CW_GET_CYGWIN_REGISTRY_NAME,
+ CW_STRACE_TOGGLE,
+ CW_STRACE_ACTIVE,
+ CW_CYGWIN_PID_TO_WINPID,
+ CW_EXTRACT_DOMAIN_AND_USER
} cygwin_getinfo_types;
#define CW_NEXTPID 0x80000000 // or with pid to get next one
@@ -89,7 +95,7 @@ enum
PID_USETTY = 0x1000, // Setting this enables or disables cygwin's
// tty support. This is inherited by
// all execed or forked processes.
- PID_UNUSED2 = 0x2000, // child has execed
+ PID_ALLPIDS = 0x2000, // child has execed
PID_EXECED = 0x4000, // redirect to original pid info block
PID_NOREDIR = 0x8000, // don't redirect if execed
PID_EXITED = 0x80000000 // Free entry.
@@ -203,14 +209,25 @@ extern int cygwin_attach_handle_to_fd (char *, int, HANDLE, mode_t, DWORD);
#define TTY_CONSOLE 0x40000000
+#define EXTERNAL_PINFO_VERSION_16_BIT 0
+#define EXTERNAL_PINFO_VERSION_32_BIT 1
+#define EXTERNAL_PINFO_VERSION EXTERNAL_PINFO_VERSION_32_BIT
+
+#ifndef _SYS_TYPES_H
+typedef unsigned short __uid16_t;
+typedef unsigned short __gid16_t;
+typedef unsigned long __uid32_t;
+typedef unsigned long __gid32_t;
+#endif
+
struct external_pinfo
{
pid_t pid;
pid_t ppid;
HANDLE hProcess;
DWORD dwProcessId, dwSpawnedProcessId;
- uid_t uid;
- gid_t gid;
+ __uid16_t uid;
+ __gid16_t gid;
pid_t pgid;
pid_t sid;
int ctty;
@@ -223,9 +240,13 @@ struct external_pinfo
char progname[MAX_PATH];
DWORD strace_mask;
- HANDLE strace_file;
+ DWORD version;
DWORD process_state;
+
+ /* Only available if version >= EXTERNAL_PINFO_VERSION_32_BIT */
+ __uid32_t uid32;
+ __gid32_t gid32;
};
DWORD cygwin_internal (cygwin_getinfo_types, ...);
diff --git a/winsup/cygwin/include/sys/ioctl.h b/winsup/cygwin/include/sys/ioctl.h
index 93f73a69c..fd9515fb1 100644
--- a/winsup/cygwin/include/sys/ioctl.h
+++ b/winsup/cygwin/include/sys/ioctl.h
@@ -1,6 +1,6 @@
/* sys/ioctl.h
- Copyright 1998, 2001 Red Hat, Inc.
+ Copyright 1998, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -23,7 +23,7 @@ details. */
__BEGIN_DECLS
-int ioctl (int __fd, int __cmd, void *);
+int ioctl (int __fd, int __cmd, ...);
__END_DECLS
diff --git a/winsup/cygwin/include/sys/ipc.h b/winsup/cygwin/include/sys/ipc.h
deleted file mode 100644
index 8ddec6d50..000000000
--- a/winsup/cygwin/include/sys/ipc.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* sys/ipc.h
-
- Copyright 2001 Red Hat Inc.
- Written by Robert Collins <rbtcollins@hotmail.com>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#ifndef _SYS_IPC_H
-#define _SYS_IPC_H
-
-/* sys/types must be included before sys/ipc.h. We aren't meant to automatically
- * include it however
- */
-
-struct ipc_perm {
- uid_t uid;
- gid_t gid;
- uid_t cuid;
- gid_t cgid;
- mode_t mode;
-};
-
-/* the mode flags used with the _get functions use the low order 9 bits for a mode
- * request
- */
-#define IPC_CREAT 0x0200
-#define IPC_EXCL 0x0400
-#define IPC_NOWAIT 0x0800
-
-/* this is a value that will _never_ be a valid key from ftok */
-#define IPC_PRIVATE -2
-
-#define IPC_RMID 0x0003
-#define IPC_SET 0x0002
-#define IPC_STAT 0x0001
-
-key_t ftok(const char *, int);
-
-#endif /* _SYS_IPC_H */
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/winsup/cygwin/include/sys/mount.h b/winsup/cygwin/include/sys/mount.h
index 00b7a0137..26e02cba2 100644
--- a/winsup/cygwin/include/sys/mount.h
+++ b/winsup/cygwin/include/sys/mount.h
@@ -21,10 +21,14 @@ enum
MOUNT_BINARY = 0x002, /* "binary" format read/writes */
MOUNT_SYSTEM = 0x008, /* mount point came from system table */
MOUNT_EXEC = 0x010, /* Any file in the mounted directory gets 'x' bit */
- MOUNT_AUTO = 0x020, /* mount point refers to auto device mount */
+ MOUNT_CYGDRIVE = 0x020, /* mount point refers to cygdriv device mount */
MOUNT_CYGWIN_EXEC = 0x040, /* file or directory is or contains a cygwin
executable */
- MOUNT_MIXED = 0x080, /* reads are text, writes are binary */
+ MOUNT_MIXED = 0x080, /* reads are text, writes are binary
+ not yet implemented */
+ MOUNT_NOTEXEC = 0x100, /* don't check files for executable magic */
+ MOUNT_DEVFS = 0x200, /* /device "filesystem" */
+ MOUNT_PROC = 0x400 /* /proc "filesystem" */
};
int mount (const char *, const char *, unsigned __flags);
diff --git a/winsup/cygwin/include/sys/resource.h b/winsup/cygwin/include/sys/resource.h
index c68a206e1..c1fe544a9 100644
--- a/winsup/cygwin/include/sys/resource.h
+++ b/winsup/cygwin/include/sys/resource.h
@@ -50,16 +50,16 @@ struct rusage {
long ru_ixrss; /* XXX: 0 */
long ru_idrss; /* XXX: sum of rm_asrss */
long ru_isrss; /* XXX: 0 */
- long ru_minflt; /* any page faults not requiring I/O */
- long ru_majflt; /* any page faults requiring I/O */
- long ru_nswap; /* swaps */
- long ru_inblock; /* block input operations */
- long ru_oublock; /* block output operations */
- long ru_msgsnd; /* messages sent */
- long ru_msgrcv; /* messages received */
- long ru_nsignals; /* signals received */
- long ru_nvcsw; /* voluntary context switches */
- long ru_nivcsw; /* involuntary " */
+ long ru_minflt; /* any page faults not requiring I/O */
+ long ru_majflt; /* any page faults requiring I/O */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary " */
#define ru_last ru_nivcsw
};
diff --git a/winsup/cygwin/include/sys/shm.h b/winsup/cygwin/include/sys/shm.h
deleted file mode 100644
index 208c5f29f..000000000
--- a/winsup/cygwin/include/sys/shm.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* sys/shm.h
-
- Copyright 2001 Red Hat Inc.
- Written by Robert Collins <rbtcollins@hotmail.com>
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#ifndef _SYS_SHM_H
-#define _SYS_SHM_H
-
-#include <sys/ipc.h>
-
-#define SHM_RDONLY 1
-/* 64 Kb was hardcoded for x86. MS states this may change, but we need it in the header
- * file.
- */
-#define SHMLBA 65536
-#define SHM_RND 1
-
-typedef long int shmatt_t;
-
-#if defined(__INSIDE_CYGWIN__) && defined(__cplusplus)
-
-class _shmattach {
-public:
- void *data;
- int shmflg;
- class _shmattach *next;
-};
-
-class shmid_ds {
-public:
- struct ipc_perm shm_perm;
- size_t shm_segsz;
- pid_t shm_lpid;
- pid_t shm_cpid;
- shmatt_t shm_nattch;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
- void *mapptr;
-};
-
-class shmnode {
-public:
- class shmid_ds * shmds;
- int shm_id;
- class shmnode *next;
- key_t key;
- HANDLE filemap;
- HANDLE attachmap;
- class _shmattach *attachhead;
-};
-
-#else
-/* this is what we return when queried. It has no bitwise correspondence
- * the internal structures
- */
-struct shmid_ds {
- struct ipc_perm shm_perm;
- size_t shm_segsz;
- pid_t shm_lpid;
- pid_t shm_cpid;
- shmatt_t shm_nattch;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
-};
-#endif /* __INSIDE_CYGWIN__ */
-
-void *shmat(int, const void *, int);
-int shmctl(int, int, struct shmid_ds *);
-int shmdt(const void *);
-int shmget(key_t, size_t, int);
-
-#endif /* _SYS_SHM_H */
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/winsup/cygwin/include/sys/socket.h b/winsup/cygwin/include/sys/socket.h
index ca76419eb..3bda9f9bf 100644
--- a/winsup/cygwin/include/sys/socket.h
+++ b/winsup/cygwin/include/sys/socket.h
@@ -32,11 +32,14 @@ extern "C"
int getpeername (int, struct sockaddr *__peer, int *);
int getsockname (int, struct sockaddr *__addr, int *);
int listen (int, int __n);
- int recv (int, void *__buff, int __len, unsigned int __flags);
- int recvfrom (int, char *__buff, int __len, int __flags,
- struct sockaddr *__from, int *__fromlen);
- int send (int, const void *__buff, int __len, unsigned int __flags);
- int sendto (int, const void *, int, unsigned int, const struct sockaddr *, int);
+ int recv (int, void *__buff, int __len, int __flags);
+ int recvfrom (int, void *__buff, int __len, int __flags,
+ struct sockaddr *__from, int *__fromlen);
+ int recvmsg(int s, struct msghdr *msg, int flags);
+ int send (int, const void *__buff, int __len, int __flags);
+ int sendmsg(int s, const struct msghdr *msg, int flags);
+ int sendto (int, const void *, int __len, int __flags,
+ const struct sockaddr *__to, int __tolen);
int setsockopt (int __s, int __level, int __optname, const void *optval, int __optlen);
int getsockopt (int __s, int __level, int __optname, void *__optval, int *__optlen);
int shutdown (int, int);
diff --git a/winsup/cygwin/include/sys/soundcard.h b/winsup/cygwin/include/sys/soundcard.h
index 1a40bff61..79341c547 100644
--- a/winsup/cygwin/include/sys/soundcard.h
+++ b/winsup/cygwin/include/sys/soundcard.h
@@ -53,10 +53,10 @@
#define SNDCARD_UART6850 8
#define SNDCARD_GUS16 9
#define SNDCARD_MSS 10
-#define SNDCARD_PSS 11
+#define SNDCARD_PSS 11
#define SNDCARD_SSCAPE 12
-#define SNDCARD_PSS_MPU 13
-#define SNDCARD_PSS_MSS 14
+#define SNDCARD_PSS_MPU 13
+#define SNDCARD_PSS_MSS 14
#define SNDCARD_SSCAPE_MSS 15
#define SNDCARD_TRXPRO 16
#define SNDCARD_TRXPRO_SB 17
@@ -112,7 +112,7 @@
#define _SIOW(x,y,t) ((int)(SIOC_IN|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
/* this should be _SIORW, but stdio got there first */
#define _SIOWR(x,y,t) ((int)(SIOC_INOUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
-#define _SIOC_SIZE(x) ((x>>16)&SIOCPARM_MASK)
+#define _SIOC_SIZE(x) ((x>>16)&SIOCPARM_MASK)
#define _SIOC_DIR(x) (x & 0xf0000000)
#define _SIOC_NONE SIOC_VOID
#define _SIOC_READ SIOC_OUT
@@ -194,7 +194,7 @@ typedef struct seq_event_rec {
* Gravis UltraSound. It tries to be universal format for uploading
* sample based patches but is probably too limited.
*
- * (PBD) As Hannu guessed, the GUS structure is too limited for
+ * (PBD) As Hannu guessed, the GUS structure is too limited for
* the WaveFront, but this is the right place for a constant definition.
*/
@@ -220,7 +220,7 @@ struct patch_info {
#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */
#define WAVE_FAST_RELEASE 0x80 /* bit 7 = Shut off immediately after note off */
- /* (use the env_rate/env_offs fields). */
+ /* (use the env_rate/env_offs fields). */
/* Linux specific bits */
#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */
#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */
@@ -234,7 +234,7 @@ struct patch_info {
int len; /* Size of the wave data in bytes */
int loop_start, loop_end; /* Byte offsets from the beginning */
-/*
+/*
* The base_freq and base_note fields are used when computing the
* playback speed for a note. The base_note defines the tone frequency
* which is heard if the sample is played using the base_freq as the
@@ -263,7 +263,7 @@ struct patch_info {
unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
unsigned char env_offset[ 6 ]; /* 255 == 100% */
- /*
+ /*
* The tremolo, vibrato and scale info are not supported yet.
* Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
* WAVE_SCALE
@@ -272,18 +272,18 @@ struct patch_info {
unsigned char tremolo_sweep;
unsigned char tremolo_rate;
unsigned char tremolo_depth;
-
+
unsigned char vibrato_sweep;
unsigned char vibrato_rate;
unsigned char vibrato_depth;
int scale_frequency;
unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
-
- int volume;
+
+ int volume;
int fractions;
int reserved1;
- int spare[2];
+ int spare[2];
char data[1]; /* The waveform data starts here */
};
@@ -300,7 +300,7 @@ struct sysex_info {
* /dev/sequencer input events.
*
* The data written to the /dev/sequencer is a stream of events. Events
- * are records of 4 or 8 bytes. The first byte defines the size.
+ * are records of 4 or 8 bytes. The first byte defines the size.
* Any number of events can be written with a write call. There
* is a set of macros for sending these events. Use these macros if you
* want to maximize portability of your program.
@@ -408,7 +408,7 @@ struct sysex_info {
#define CTRL_EXPRESSION 253 /* Obsolete */
#define CTRL_MAIN_VOLUME 252 /* Obsolete */
#define SEQ_BALANCE 11
-#define SEQ_VOLMODE 12
+#define SEQ_VOLMODE 12
/*
* Volume mode decides how volumes are used
@@ -433,13 +433,13 @@ struct sysex_info {
* of the associated synthesizer device. There is no limit to the size
* of the extended events. These events are not queued but executed
* immediately when the write() is called (execution can take several
- * seconds of time).
+ * seconds of time).
*
* When a SEQ_FULLSIZE message is written to the device, it must
* be written using exactly one write() call. Other events cannot
* be mixed to the same write.
- *
- * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the
+ *
+ * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the
* /dev/sequencer. Don't write other data together with the instrument structure
* Set the key field of the structure to FM_PATCH. The device field is used to
* route the patch to the corresponding device.
@@ -461,7 +461,7 @@ struct sbi_instrument {
#define FM_PATCH _PATCHKEY(0x01)
#define OPL3_PATCH _PATCHKEY(0x03)
short device; /* Synth# (0-4) */
- int channel; /* Program# to be initialized */
+ int channel; /* Program# to be initialized */
sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
};
@@ -480,13 +480,13 @@ struct synth_info { /* Read only */
#define SAMPLE_TYPE_BASIC 0x10
#define SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC
-#define SAMPLE_TYPE_WAVEFRONT 0x11
+#define SAMPLE_TYPE_WAVEFRONT 0x11
int perc_mode; /* No longer supported */
int nr_voices;
int nr_drums; /* Obsolete field */
int instr_bank_size;
- unsigned int capabilities;
+ unsigned int capabilities;
#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */
#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */
#define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */
@@ -625,7 +625,7 @@ typedef struct buffmem_desc {
/*
* Application's profile defines the way how playback underrun situations should be handled.
- *
+ *
* APF_NORMAL (the default) and APF_NETWORK make the driver to cleanup the
* playback buffer whenever an underrun occurs. This consumes some time
* prevents looping the existing buffer.
@@ -687,7 +687,7 @@ typedef struct copr_debug_buf {
int command; /* Used internally. Set to 0 */
int parm1;
int parm2;
- int flags;
+ int flags;
int len; /* Length of data in bytes */
} copr_debug_buf;
@@ -696,7 +696,7 @@ typedef struct copr_msg {
unsigned char data[4000];
} copr_msg;
-#define SNDCTL_COPR_RESET _SIO ('C', 0)
+#define SNDCTL_COPR_RESET _SIO ('C', 0)
#define SNDCTL_COPR_LOAD _SIOWR('C', 1, copr_buffer)
#define SNDCTL_COPR_RDATA _SIOWR('C', 2, copr_debug_buf)
#define SNDCTL_COPR_RCODE _SIOWR('C', 3, copr_debug_buf)
@@ -710,12 +710,12 @@ typedef struct copr_msg {
/*********************************************
* IOCTL commands for /dev/mixer
*/
-
-/*
+
+/*
* Mixer devices
*
* There can be up to 20 different analog mixer channels. The
- * SOUND_MIXER_NRDEVICES gives the currently supported maximum.
+ * SOUND_MIXER_NRDEVICES gives the currently supported maximum.
* The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
* the devices supported by the particular mixer.
*/
@@ -735,7 +735,7 @@ typedef struct copr_msg {
#define SOUND_MIXER_RECLEV 11 /* Recording level */
#define SOUND_MIXER_IGAIN 12 /* Input gain */
#define SOUND_MIXER_OGAIN 13 /* Output gain */
-/*
+/*
* The AD1848 codec and compatibles have three line level inputs
* (line, aux1 and aux2). Since each card manufacturer have assigned
* different meanings to these inputs, it's inpractical to assign
@@ -940,7 +940,7 @@ typedef struct mixer_vol_table {
#define SOUND_MIXER_GETLEVELS _SIOWR('M', 116, mixer_vol_table)
#define SOUND_MIXER_SETLEVELS _SIOWR('M', 117, mixer_vol_table)
-/*
+/*
* An ioctl for identifying the driver version. It will return value
* of the SOUND_VERSION macro used when compiling the driver.
* This call was introduced in OSS version 3.6 and it will not work
@@ -954,7 +954,7 @@ typedef struct mixer_vol_table {
/*
* The 4 most significant bits of byte 0 specify the class of
- * the event:
+ * the event:
*
* 0x8X = system level events,
* 0x9X = device/port specific events, event[1] = device/port,
@@ -1014,7 +1014,7 @@ typedef struct mixer_vol_table {
*/
#define LOCL_STARTAUDIO 1
-#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS)
+#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS)
/*
* Some convenience macros to simplify programming of the
* /dev/sequencer interface
@@ -1087,16 +1087,16 @@ extern int OSS_write_patch2(int fd, unsigned char *buf, int len);
/*
* This variation of the sequencer macros is used just to format one event
* using fixed buffer.
- *
+ *
* The program using the macro library must define the following macros before
* using this library.
*
- * #define _seqbuf name of the buffer (unsigned char[])
+ * #define _seqbuf name of the buffer (unsigned char[])
* #define _SEQ_ADVBUF(len) If the applic needs to know the exact
* size of the event, this macro can be used.
* Otherwise this must be defined as empty.
* #define _seqbufptr Define the name of index variable or 0 if
- * not required.
+ * not required.
*/
#define _SEQ_NEEDBUF(len) /* empty */
#endif
@@ -1157,7 +1157,7 @@ extern int OSS_write_patch2(int fd, unsigned char *buf, int len);
* sending any MIDI bytes but it's absolutely not possible. Trying to do
* so _will_ cause problems with MPU401 intelligent mode).
*
- * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be
+ * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be
* sent by calling SEQ_SYSEX() several times (there must be no other events
* between them). First sysex fragment must have 0xf0 in the first byte
* and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte
@@ -1225,11 +1225,11 @@ extern int OSS_write_patch2(int fd, unsigned char *buf, int len);
*/
#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr+0] = EV_TIMING; \
- _seqbuf[_seqbufptr+1] = (ev); \
+ _seqbuf[_seqbufptr+0] = EV_TIMING; \
+ _seqbuf[_seqbufptr+1] = (ev); \
_seqbuf[_seqbufptr+2] = 0;\
_seqbuf[_seqbufptr+3] = 0;\
- *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
+ *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
_SEQ_ADVBUF(8);}
#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0)
@@ -1247,16 +1247,16 @@ extern int OSS_write_patch2(int fd, unsigned char *buf, int len);
*/
#define _LOCAL_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
- _seqbuf[_seqbufptr+1] = (ev); \
+ _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
+ _seqbuf[_seqbufptr+1] = (ev); \
_seqbuf[_seqbufptr+2] = 0;\
_seqbuf[_seqbufptr+3] = 0;\
- *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
+ *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
_SEQ_ADVBUF(8);}
#define SEQ_PLAYAUDIO(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO, devmask)
/*
- * Events for the level 1 interface only
+ * Events for the level 1 interface only
*/
#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\
diff --git a/winsup/cygwin/include/sys/statfs.h b/winsup/cygwin/include/sys/statfs.h
new file mode 100644
index 000000000..51ad3c6b1
--- /dev/null
+++ b/winsup/cygwin/include/sys/statfs.h
@@ -0,0 +1,11 @@
+/* sys/statfs.h
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <sys/vfs.h>
diff --git a/winsup/cygwin/include/sys/strace.h b/winsup/cygwin/include/sys/strace.h
index 87cc1d785..b43ab886f 100644
--- a/winsup/cygwin/include/sys/strace.h
+++ b/winsup/cygwin/include/sys/strace.h
@@ -43,7 +43,8 @@ public:
int active;
int lmicrosec;
int execing;
- strace() : version(1) {}
+ int inited;
+ void hello ();
void prntf (unsigned, const char *func, const char *, ...) /*__attribute__ ((regparm(3)))*/;
void vprntf (unsigned, const char *func, const char *, va_list ap) /*__attribute__ ((regparm(3)))*/;
void wm (int message, int word, int lon) __attribute__ ((regparm(3)));
@@ -77,6 +78,13 @@ extern strace strace;
#define _STRACE_MALLOC 0x20000 // trace malloc calls
#define _STRACE_THREAD 0x40000 // thread-locking calls
#define _STRACE_NOTALL 0x80000 // don't include if _STRACE_ALL
+#if defined (DEBUGGING)
+# define _STRACE_ON strace.active = 1;
+# define _STRACE_OFF strace.active = 0;
+#else
+# define _STRACE_ON
+# define _STRACE_OFF
+#endif
#ifdef __cplusplus
extern "C" {
diff --git a/winsup/cygwin/include/sys/sysmacros.h b/winsup/cygwin/include/sys/sysmacros.h
index cc3a69160..2c9c69923 100644
--- a/winsup/cygwin/include/sys/sysmacros.h
+++ b/winsup/cygwin/include/sys/sysmacros.h
@@ -11,8 +11,14 @@ details. */
#ifndef _SYS_SYSMACROS_H
#define _SYS_SYSMACROS_H
+#ifdef __CYGWIN_USE_BIG_TYPES__
+#define major(dev) ((int)(((dev) >> 16) & 0xffff))
+#define minor(dev) ((int)((dev) & 0xffff))
+#define makedev(major, minor) (((major) << 16) | ((minor) & 0xffff))
+#else
#define major(dev) ((int)(((dev) >> 8) & 0xff))
#define minor(dev) ((int)((dev) & 0xff))
-#define makedev(major, minor) (((major) << 8) | (minor))
+#define makedev(major, minor) (((major) << 8) | ((minor) & 0xff))
+#endif
#endif /* _SYS_SYSMACROS_H */
diff --git a/winsup/cygwin/include/sys/termios.h b/winsup/cygwin/include/sys/termios.h
index a87f10627..20a84aa78 100644
--- a/winsup/cygwin/include/sys/termios.h
+++ b/winsup/cygwin/include/sys/termios.h
@@ -13,6 +13,26 @@ details. */
#ifndef _SYS_TERMIOS_H
#define _SYS_TERMIOS_H
+#define TIOCMGET 0x5415
+#define TIOCMSET 0x5418
+#define TIOCINQ 0x541B
+
+/* TIOCINQ is utilized instead of FIONREAD which has been
+accupied for other purposes under CYGWIN.
+Other UNIX ioctl requests has been omited because
+effects of their work one can achive by standard
+POSIX commands */
+
+
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
@@ -195,6 +215,14 @@ details. */
#define NCCS 18
+/* `c_cc' member of 'struct termios' structure can be disabled by
+ using the value _POSIX_VDISABLE. */
+#define _POSIX_VDISABLE '\0'
+
+/* Compare a character C to a value VAL from the `c_cc' array in a
+ `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it. */
+#define CCEQ(val, c) ((c) == (val) && (val) != _POSIX_VDISABLE)
+
typedef unsigned char cc_t;
typedef unsigned int tcflag_t;
typedef unsigned int speed_t;
diff --git a/winsup/cygwin/include/sys/uio.h b/winsup/cygwin/include/sys/uio.h
index d355ac5b6..e28f14e7e 100644
--- a/winsup/cygwin/include/sys/uio.h
+++ b/winsup/cygwin/include/sys/uio.h
@@ -1,6 +1,6 @@
/* sys/uio.h
- Copyright 1996, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -24,9 +24,10 @@ __BEGIN_DECLS
* Define the uio buffers used for writev, readv.
*/
-struct iovec {
- caddr_t iov_base;
- int iov_len;
+struct iovec
+{
+ void *iov_base;
+ size_t iov_len;
};
extern ssize_t readv __P ((int filedes, const struct iovec *vector, int count));
diff --git a/winsup/cygwin/include/sys/un.h b/winsup/cygwin/include/sys/un.h
index 25588e2b2..4e3eee82b 100644
--- a/winsup/cygwin/include/sys/un.h
+++ b/winsup/cygwin/include/sys/un.h
@@ -21,6 +21,6 @@ struct sockaddr_un {
/* Evaluates the actual length of `sockaddr_un' structure. */
#define SUN_LEN(p) ((size_t)(((struct sockaddr_un *) NULL)->sun_path) \
- + strlen ((p)->sun_path))
+ + strlen ((p)->sun_path))
#endif
diff --git a/winsup/cygwin/include/sys/vfs.h b/winsup/cygwin/include/sys/vfs.h
index f0f3eb96c..57b6f9232 100644
--- a/winsup/cygwin/include/sys/vfs.h
+++ b/winsup/cygwin/include/sys/vfs.h
@@ -12,7 +12,7 @@ details. */
#define _SYS_VFS_H_
struct statfs {
- long f_type; /* type of filesystem (see below) */
+ long f_type; /* type of filesystem */
long f_bsize; /* optimal transfer block size */
long f_blocks; /* total data blocks in file system */
long f_bfree; /* free blocks in fs */
diff --git a/winsup/cygwin/include/wchar.h b/winsup/cygwin/include/wchar.h
deleted file mode 100644
index eabdaa725..000000000
--- a/winsup/cygwin/include/wchar.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* wchar.h
-
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifndef _WCHAR_H
-#define _WCHAR_H
-
-#include <sys/cdefs.h>
-
-/* Get wchar_t and wint_t from <stddef.h>. */
-#define __need_wchar_t
-#define __need_wint_t
-#include <stddef.h>
-
-__BEGIN_DECLS
-
-int wcscmp (const wchar_t *__s1, const wchar_t *__s2);
-size_t wcslen (const wchar_t *__s1);
-
-__END_DECLS
-
-#endif /* _WCHAR_H */
diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc
index 5d2c75056..9c942f270 100644
--- a/winsup/cygwin/init.cc
+++ b/winsup/cygwin/init.cc
@@ -1,6 +1,6 @@
/* init.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -13,8 +13,6 @@ details. */
#include "thread.h"
#include "perprocess.h"
-extern HMODULE cygwin_hmodule;
-
int NO_COPY dynamically_loaded;
extern "C" int
@@ -29,26 +27,22 @@ WINAPI dll_entry (HANDLE h, DWORD reason, void *static_load)
case DLL_THREAD_ATTACH:
if (user_data->threadinterface)
{
- if (!TlsSetValue(user_data->threadinterface->reent_index,
- &user_data->threadinterface->reents))
- api_fatal("Sig proc MT init failed\n");
+ if (!TlsSetValue (user_data->threadinterface->reent_index,
+ &user_data->threadinterface->reents))
+ api_fatal ("Sig proc MT init failed\n");
}
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
-#if 0 // FIXME: REINSTATE SOON
- waitq *w;
- if ((w = waitq_storage.get ()) != NULL)
- {
- if (w->thread_ev != NULL)
- {
- system_printf ("closing %p", w->thread_ev);
- (void) CloseHandle (w->thread_ev);
- }
- memset (w, 0, sizeof(*w)); // FIXME: memory leak
- }
- // FIXME: Need to add other per_thread stuff here
+#if 0
+ pthread *thisthread = (pthread *)
+ TlsGetValue (user_data->threadinterface->thread_self_dwTlsIndex);
+ if (thisthread) {
+ /* Some non-pthread call created this thread,
+ * but we need to clean it up */
+ thisthread->exit (0);
+ }
#endif
break;
}
diff --git a/winsup/cygwin/ioctl.cc b/winsup/cygwin/ioctl.cc
index 93fe9ddf5..6b12a2ec3 100644
--- a/winsup/cygwin/ioctl.cc
+++ b/winsup/cygwin/ioctl.cc
@@ -1,6 +1,6 @@
/* ioctl.cc: ioctl routines.
- Copyright 1996, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Doug Evans of Cygnus Support
dje@cygnus.com
@@ -20,31 +20,37 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
+#include "sigproc.h"
#include <sys/termios.h>
extern "C" int
-ioctl (int fd, int cmd, void *buf)
+ioctl (int fd, int cmd, ...)
{
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- return -1;
- }
+ sigframe thisframe (mainthread);
+
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
+
+ /* check for optional mode argument */
+ va_list ap;
+ va_start (ap, cmd);
+ char *argp = va_arg (ap, char *);
+ va_end (ap);
debug_printf ("fd %d, cmd %x\n", fd, cmd);
- fhandler_base *fh = cygheap->fdtab[fd];
- if (fh->is_tty () && fh->get_device () != FH_PTYM)
+ if (cfd->is_tty () && cfd->get_device () != FH_PTYM)
switch (cmd)
{
case TCGETA:
- return tcgetattr (fd, (struct termios *) buf);
+ return tcgetattr (fd, (struct termios *) argp);
case TCSETA:
- return tcsetattr (fd, TCSANOW, (struct termios *) buf);
+ return tcsetattr (fd, TCSANOW, (struct termios *) argp);
case TCSETAW:
- return tcsetattr (fd, TCSADRAIN, (struct termios *) buf);
+ return tcsetattr (fd, TCSADRAIN, (struct termios *) argp);
case TCSETAF:
- return tcsetattr (fd, TCSAFLUSH, (struct termios *) buf);
+ return tcsetattr (fd, TCSAFLUSH, (struct termios *) argp);
}
- return fh->ioctl (cmd, buf);
+ return cfd->ioctl (cmd, argp);
}
diff --git a/winsup/cygwin/ipc.cc b/winsup/cygwin/ipc.cc
index 192a124d5..4665fd84a 100644
--- a/winsup/cygwin/ipc.cc
+++ b/winsup/cygwin/ipc.cc
@@ -1,6 +1,6 @@
/* ipc.cc: Single unix specification IPC interface for Cygwin
- Copyright 2001 Red Hat, Inc.
+ Copyright 2001, 2002 Red Hat, Inc.
Originally written by Robert Collins <robert.collins@hotmail.com>
@@ -11,7 +11,7 @@
details. */
#include "winsup.h"
-#include <sys/ipc.h>
+#include <cygwin/ipc.h>
#include <sys/stat.h>
extern "C"
@@ -27,11 +27,11 @@ ftok(const char *path, int id)
/* stat set the appropriate errno for us */
return (key_t) -1;
}
-
- /* dev_t is short for cygwin
+
+ /* dev_t is short for cygwin
* ino_t is long for cygwin
* and we need 8 bits for the id.
- * thus key_t is long long.
+ * thus key_t is long long.
*/
return ((long long) statbuf.st_dev << (5*8)) | (statbuf.st_ino << (8) ) | (id & 0x00ff);
}
diff --git a/winsup/cygwin/lib/_cygwin_S_IEXEC.cc b/winsup/cygwin/lib/_cygwin_S_IEXEC.cc
deleted file mode 100644
index 371126073..000000000
--- a/winsup/cygwin/lib/_cygwin_S_IEXEC.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-/* _cygwin_S_IEXEC.cc: stat helper stuff
-
- Copyright 2001 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-extern "C" {
-#include "winsup.h"
-#include <sys/stat.h>
-#include <sys/unistd.h>
-
-unsigned _cygwin_S_IEXEC = S_IEXEC;
-unsigned _cygwin_S_IXUSR = S_IXUSR;
-unsigned _cygwin_S_IXGRP = S_IXGRP;
-unsigned _cygwin_S_IXOTH = S_IXOTH;
-unsigned _cygwin_X_OK = X_OK;
-};
diff --git a/winsup/cygwin/lib/cygwin_crt0.c b/winsup/cygwin/lib/cygwin_crt0.c
index d8f781746..fb2a84b18 100644
--- a/winsup/cygwin/lib/cygwin_crt0.c
+++ b/winsup/cygwin/lib/cygwin_crt0.c
@@ -11,10 +11,9 @@ details. */
#undef __INSIDE_CYGWIN__
#include <windows.h>
#include <sys/cygwin.h>
+#include <stdlib.h>
#include "crt0.h"
-#define alloca __builtin_alloca
-
extern void dll_crt0__FP11per_process (struct per_process *) __declspec (dllimport) __attribute ((noreturn));
/* for main module */
diff --git a/winsup/cygwin/lib/dll_main.cc b/winsup/cygwin/lib/dll_main.cc
index e4486a3d8..a224a0a2f 100644
--- a/winsup/cygwin/lib/dll_main.cc
+++ b/winsup/cygwin/lib/dll_main.cc
@@ -15,7 +15,7 @@ details. */
extern "C"
BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason,
- LPVOID reserved /* Not used. */);
+ LPVOID reserved /* Not used. */);
BOOL APIENTRY
DllMain (
diff --git a/winsup/cygwin/lib/getopt.c b/winsup/cygwin/lib/getopt.c
index 12763ea9b..effa5d774 100644
--- a/winsup/cygwin/lib/getopt.c
+++ b/winsup/cygwin/lib/getopt.c
@@ -147,7 +147,7 @@ gcd(a, b)
b = c;
c = a % b;
}
-
+
return b;
}
@@ -214,7 +214,7 @@ getopt_internal(int nargc, char *const * nargv, const char *options)
* XXX re-initialize optind to 0 and have getopt_long(3)
* XXX properly function again. Work around this braindamage.
*/
- if (optind == 0)
+ if (optind == 0 && optreset == 0)
optind = 1;
if (optreset)
@@ -245,7 +245,7 @@ start:
place = EMSG;
if (IN_ORDER) {
/*
- * GNU extension:
+ * GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
@@ -291,7 +291,7 @@ start:
}
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
- if (*place)
+ if (*place)
return -2;
if (++optind >= nargc) { /* no arg */
@@ -411,7 +411,7 @@ getopt_long(int nargc, char * const *nargv, const char *options,
has_equal++;
} else
current_argv_len = strlen(current_argv);
-
+
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
@@ -436,7 +436,7 @@ getopt_long(int nargc, char * const *nargv, const char *options,
}
}
if (match != -1) { /* option found */
- if (long_options[match].has_arg == no_argument
+ if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
@@ -492,7 +492,7 @@ getopt_long(int nargc, char * const *nargv, const char *options,
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
retval = 0;
- } else
+ } else
retval = long_options[match].val;
if (idx)
*idx = match;
diff --git a/winsup/cygwin/libc/fnmatch.c b/winsup/cygwin/libc/fnmatch.c
new file mode 100644
index 000000000..709bc78c8
--- /dev/null
+++ b/winsup/cygwin/libc/fnmatch.c
@@ -0,0 +1,230 @@
+/* $OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
+#else
+static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+ * Compares a filename or pathname to a pattern.
+ */
+
+/* Just this single line added for Cygwin. */
+#include "winsup.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#define EOS '\0'
+
+#define RANGE_MATCH 1
+#define RANGE_NOMATCH 0
+#define RANGE_ERROR (-1)
+
+static int rangematch __P((const char *, char, int, char **));
+
+int
+fnmatch(pattern, string, flags)
+ const char *pattern, *string;
+ int flags;
+{
+ const char *stringstart;
+ char *newp;
+ char c, test;
+
+ for (stringstart = string;;)
+ switch (c = *pattern++) {
+ case EOS:
+ if ((flags & FNM_LEADING_DIR) && *string == '/')
+ return (0);
+ return (*string == EOS ? 0 : FNM_NOMATCH);
+ case '?':
+ if (*string == EOS)
+ return (FNM_NOMATCH);
+ if (*string == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+ ++string;
+ break;
+ case '*':
+ c = *pattern;
+ /* Collapse multiple stars. */
+ while (c == '*')
+ c = *++pattern;
+
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+
+ /* Optimize for pattern with * at end or before /. */
+ if (c == EOS) {
+ if (flags & FNM_PATHNAME)
+ return ((flags & FNM_LEADING_DIR) ||
+ strchr(string, '/') == NULL ?
+ 0 : FNM_NOMATCH);
+ else
+ return (0);
+ } else if (c == '/' && (flags & FNM_PATHNAME)) {
+ if ((string = strchr(string, '/')) == NULL)
+ return (FNM_NOMATCH);
+ break;
+ }
+
+ /* General case, use recursion. */
+ while ((test = *string) != EOS) {
+ if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
+ return (0);
+ if (test == '/' && (flags & FNM_PATHNAME))
+ break;
+ ++string;
+ }
+ return (FNM_NOMATCH);
+ case '[':
+ if (*string == EOS)
+ return (FNM_NOMATCH);
+ if (*string == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ return (FNM_NOMATCH);
+
+ switch (rangematch(pattern, *string, flags, &newp)) {
+ case RANGE_ERROR:
+ /* not a good range, treat as normal text */
+ goto normal;
+ case RANGE_MATCH:
+ pattern = newp;
+ break;
+ case RANGE_NOMATCH:
+ return (FNM_NOMATCH);
+ }
+ ++string;
+ break;
+ case '\\':
+ if (!(flags & FNM_NOESCAPE)) {
+ if ((c = *pattern++) == EOS) {
+ c = '\\';
+ --pattern;
+ }
+ }
+ /* FALLTHROUGH */
+ default:
+ normal:
+ if (c != *string && !((flags & FNM_CASEFOLD) &&
+ (tolower((unsigned char)c) ==
+ tolower((unsigned char)*string))))
+ return (FNM_NOMATCH);
+ ++string;
+ break;
+ }
+ /* NOTREACHED */
+}
+
+static int
+#ifdef __STDC__
+rangematch(const char *pattern, char test, int flags, char **newp)
+#else
+rangematch(pattern, test, flags, newp)
+ char *pattern;
+ char test;
+ int flags;
+ char **newp;
+#endif
+{
+ int negate, ok;
+ char c, c2;
+
+ /*
+ * A bracket expression starting with an unquoted circumflex
+ * character produces unspecified results (IEEE 1003.2-1992,
+ * 3.13.2). This implementation treats it like '!', for
+ * consistency with the regular expression syntax.
+ * J.T. Conklin (conklin@ngai.kaleida.com)
+ */
+ if ((negate = (*pattern == '!' || *pattern == '^')))
+ ++pattern;
+
+ if (flags & FNM_CASEFOLD)
+ test = tolower((unsigned char)test);
+
+ /*
+ * A right bracket shall lose its special meaning and represent
+ * itself in a bracket expression if it occurs first in the list.
+ * -- POSIX.2 2.8.3.2
+ */
+ ok = 0;
+ c = *pattern++;
+ do {
+ if (c == '\\' && !(flags & FNM_NOESCAPE))
+ c = *pattern++;
+ if (c == EOS)
+ return (RANGE_ERROR);
+ if (c == '/' && (flags & FNM_PATHNAME))
+ return (RANGE_NOMATCH);
+ if ((flags & FNM_CASEFOLD))
+ c = tolower((unsigned char)c);
+ if (*pattern == '-'
+ && (c2 = *(pattern+1)) != EOS && c2 != ']') {
+ pattern += 2;
+ if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ c2 = *pattern++;
+ if (c2 == EOS)
+ return (RANGE_ERROR);
+ if (flags & FNM_CASEFOLD)
+ c2 = tolower((unsigned char)c2);
+ if (c <= test && test <= c2)
+ ok = 1;
+ } else if (c == test)
+ ok = 1;
+ } while ((c = *pattern++) != ']');
+
+ *newp = (char *)pattern;
+ return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
+}
diff --git a/winsup/cygwin/localtime.cc b/winsup/cygwin/localtime.cc
index 43c64ce3c..8267bdebb 100644
--- a/winsup/cygwin/localtime.cc
+++ b/winsup/cygwin/localtime.cc
@@ -4,7 +4,6 @@
*/
/* Temporarily merged private.h and tzfile.h for ease of management - DJ */
-/* CYGNUS LOCAL */
#include "winsup.h"
#include "cygerrno.h"
#include <windows.h>
@@ -12,8 +11,6 @@
#define USG_COMPAT
-/* END CYGNUS LOCAL */
-
#ifndef lint
#ifndef NOID
static char elsieid[] = "@(#)localtime.c 7.66";
@@ -501,7 +498,7 @@ struct tzhead {
static char wildabbr[] NO_COPY = WILDABBR;
-static const char gmt[] NO_COPY = "GMT";
+static char gmt[] NO_COPY = "GMT";
struct ttinfo { /* time type information */
long tt_gmtoff; /* UTC offset in seconds */
@@ -1399,10 +1396,10 @@ tzsetwall P((void))
dst = cp = buf;
for (src = tz.StandardName; *src; src++)
if (is_upper(*src)) *dst++ = *src;
- if (cp == dst)
+ if ((dst - cp) < 3)
{
- /* In Asian Windows, tz.StandardName may not contain
- the timezone name. */
+ /* In non-english Windows, converted tz.StandardName
+ may not contain a valid standard timezone name. */
strcpy(cp, wildabbr);
cp += strlen(wildabbr);
}
@@ -1417,11 +1414,11 @@ tzsetwall P((void))
dst = cp;
for (src = tz.DaylightName; *src; src++)
if (is_upper(*src)) *dst++ = *src;
- if (cp == dst)
+ if ((dst - cp) < 3)
{
- /* In Asian Windows, tz.StandardName may not contain
- the daylight name. */
- strcpy(buf, wildabbr);
+ /* In non-english Windows, converted tz.DaylightName
+ may not contain a valid daylight timezone name. */
+ strcpy(cp, wildabbr);
cp += strlen(wildabbr);
}
else
diff --git a/winsup/cygwin/malloc.cc b/winsup/cygwin/malloc.cc
new file mode 100644
index 000000000..2e0a5cce0
--- /dev/null
+++ b/winsup/cygwin/malloc.cc
@@ -0,0 +1,5582 @@
+/*
+ This is a version (aka dlmalloc) of malloc/free/realloc written by
+ Doug Lea and released to the public domain. Use, modify, and
+ redistribute this code without permission or acknowledgement in any
+ way you wish. Send questions, comments, complaints, performance
+ data, etc to dl@cs.oswego.edu
+
+* VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Quickstart
+
+ This library is all in one file to simplify the most common usage:
+ ftp it, compile it (-O), and link it into another program. All
+ of the compile-time options default to reasonable values for use on
+ most unix platforms. Compile -DWIN32 for reasonable defaults on windows.
+ You might later want to step through various compile-time and dynamic
+ tuning options.
+
+ For convenience, an include file for code using this malloc is at:
+ ftp://gee.cs.oswego.edu/pub/misc/malloc-2.7.1.h
+ You don't really need this .h file unless you call functions not
+ defined in your system include files. The .h file contains only the
+ excerpts from this file needed for using this malloc on ANSI C/C++
+ systems, so long as you haven't changed compile-time options about
+ naming and tuning parameters. If you do, then you can create your
+ own malloc.h that does include all settings by cutting at the point
+ indicated below.
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator for malloc-intensive programs.
+
+ The main properties of the algorithms are:
+ * For large (>= 512 bytes) requests, it is a pure best-fit allocator,
+ with ties normally decided via FIFO (i.e. least recently used).
+ * For small (<= 64 bytes by default) requests, it is a caching
+ allocator, that maintains pools of quickly recycled chunks.
+ * In between, and for combinations of large and small requests, it does
+ the best it can trying to meet both goals at once.
+ * For very large requests (>= 128KB by default), it relies on system
+ memory mapping facilities, if supported.
+
+ For a longer but slightly out of date high-level description, see
+ http://gee.cs.oswego.edu/dl/html/malloc.html
+
+ You may already by default be using a C library containing a malloc
+ that is based on some version of this malloc (for example in
+ linux). You might still want to use the one in this file in order to
+ customize settings or to avoid overheads associated with library
+ versions.
+
+* Contents, described in more detail in "description of public routines" below.
+
+ Standard (ANSI/SVID/...) functions:
+ malloc(size_t n);
+ calloc(size_t n_elements, size_t element_size);
+ free(Void_t* p);
+ realloc(Void_t* p, size_t n);
+ memalign(size_t alignment, size_t n);
+ valloc(size_t n);
+ mallinfo()
+ mallopt(int parameter_number, int parameter_value)
+
+ Additional functions:
+ independent_calloc(size_t n_elements, size_t size, Void_t* chunks[]);
+ independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);
+ pvalloc(size_t n);
+ cfree(Void_t* p);
+ malloc_trim(size_t pad);
+ malloc_usable_size(Void_t* p);
+ malloc_stats();
+
+* Vital statistics:
+
+ Supported pointer representation: 4 or 8 bytes
+ Supported size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+ You can adjust this by defining INTERNAL_SIZE_T
+
+ Alignment: 2 * sizeof(size_t) (default)
+ (i.e., 8 byte alignment with 4byte size_t). This suffices for
+ nearly all current machines and C compilers. However, you can
+ define MALLOC_ALIGNMENT to be wider than this if necessary.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden word of overhead holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field and 8 (16) bytes for
+ free list pointers. Thus, the minimum allocatable size is
+ 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ The maximum overhead wastage (i.e., number of extra bytes
+ allocated than were requested in malloc) is less than or equal
+ to the minimum size, except for requests >= mmap_threshold that
+ are serviced via mmap(), where the worst case wastage is 2 *
+ sizeof(size_t) bytes plus the remainder from a system page (the
+ minimal mmap unit); typically 4096 or 8192 bytes.
+
+ Maximum allocated size: 4-byte size_t: 2^32 minus about two pages
+ 8-byte size_t: 2^64 minus about two pages
+
+ It is assumed that (possibly signed) size_t values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. The ISO C standard says that it must be
+ unsigned, but a few systems are known not to adhere to this.
+ Additionally, even when size_t is unsigned, sbrk (which is by
+ default used to obtain memory from system) accepts signed
+ arguments, and may not be able to handle size_t-wide arguments
+ with negative sign bit. Generally, values that would
+ appear as negative after accounting for overhead and alignment
+ are supported only via mmap(), which does not have this
+ limitation.
+
+ Requests for sizes outside the allowed range will perform an optional
+ failure action and then return null. (Requests may also
+ also fail because a system is out of memory.)
+
+ Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined
+
+ When USE_MALLOC_LOCK is defined, wrappers are created to
+ surround every public call with either a pthread mutex or
+ a win32 spinlock (depending on WIN32). This is not
+ especially fast, and can be a major bottleneck.
+ It is designed only to provide minimal protection
+ in concurrent environments, and to provide a basis for
+ extensions. If you are using malloc in a concurrent program,
+ you would be far better off obtaining ptmalloc, which is
+ derived from a version of this malloc, and is well-tuned for
+ concurrent programs. (See http://www.malloc.de) Note that
+ even when USE_MALLOC_LOCK is defined, you can can guarantee
+ full thread-safety only if no threads acquire memory through
+ direct calls to MORECORE or other system-level allocators.
+
+ Compliance: I believe it is compliant with the 1997 Single Unix Specification
+ (See http://www.opennc.org). Also SVID/XPG, ANSI C, and probably
+ others as well.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People also report using it in stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. It is not
+ at all modular. (Sorry!) It uses a lot of macros. To be at all
+ usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O3) that can simplify expressions and control
+ paths. (FAQ: some macros import variables as arguments rather than
+ declare locals because people reported that some debuggers
+ otherwise get confused.)
+
+ OPTION DEFAULT VALUE
+
+ Compilation Environment options:
+
+ __STD_C derived from C compiler defines
+ WIN32 NOT defined
+ HAVE_MEMCPY defined
+ USE_MEMCPY 1 if HAVE_MEMCPY is defined
+ HAVE_MMAP defined as 1
+ MMAP_CLEARS 1
+ HAVE_MREMAP 0 unless linux defined
+ malloc_getpagesize derived from system #includes, or 4096 if not
+ HAVE_USR_INCLUDE_MALLOC_H NOT defined
+ LACKS_UNISTD_H NOT defined unless WIN32
+ LACKS_SYS_PARAM_H NOT defined unless WIN32
+ LACKS_SYS_MMAN_H NOT defined unless WIN32
+ LACKS_FCNTL_H NOT defined
+
+ Changing default word sizes:
+
+ INTERNAL_SIZE_T size_t
+ MALLOC_ALIGNMENT 2 * sizeof(INTERNAL_SIZE_T)
+ PTR_UINT unsigned long
+ CHUNK_SIZE_T unsigned long
+
+ Configuration and functionality options:
+
+ USE_DL_PREFIX NOT defined
+ USE_PUBLIC_MALLOC_WRAPPERS NOT defined
+ USE_MALLOC_LOCK NOT defined
+ DEBUG NOT defined
+ REALLOC_ZERO_BYTES_FREES NOT defined
+ MALLOC_FAILURE_ACTION errno = ENOMEM, if __STD_C defined, else no-op
+ TRIM_FASTBINS 0
+ FIRST_SORTED_BIN_SIZE 512
+
+ Options for customizing MORECORE:
+
+ MORECORE sbrk
+ MORECORE_CONTIGUOUS 1
+ MORECORE_CANNOT_TRIM NOT defined
+ MMAP_AS_MORECORE_SIZE (1024 * 1024)
+
+ Tuning options that are also dynamically changeable via mallopt:
+
+ DEFAULT_MXFAST 64
+ DEFAULT_TRIM_THRESHOLD 256 * 1024
+ DEFAULT_TOP_PAD 0
+ DEFAULT_MMAP_THRESHOLD 256 * 1024
+ DEFAULT_MMAP_MAX 65536
+
+ There are several other #defined constants and macros that you
+ probably don't want to touch unless you are extending or adapting malloc.
+*/
+
+/*
+ WIN32 sets up defaults for MS environment and compilers.
+ Otherwise defaults are for unix.
+*/
+
+/* #define WIN32 */
+
+#ifdef WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* Win32 doesn't supply or need the following headers */
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+
+/* Use the supplied emulation of sbrk */
+#define MORECORE sbrk
+#define MORECORE_CONTIGUOUS 1
+#define MORECORE_FAILURE ((void*)(-1))
+
+/* Use the supplied emulation of mmap and munmap */
+#define HAVE_MMAP 1
+#define MUNMAP_FAILURE (-1)
+#define MMAP_CLEARS 1
+
+/* These values don't really matter in windows mmap emulation */
+#define MAP_PRIVATE 1
+#define MAP_ANONYMOUS 2
+#define PROT_READ 1
+#define PROT_WRITE 2
+
+/* Emulation functions defined at the end of this file */
+
+/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */
+#ifdef USE_MALLOC_LOCK
+static int slwait(int *sl);
+static int slrelease(int *sl);
+#endif
+
+static long getpagesize(void);
+static long getregionsize(void);
+static void *sbrk(long size);
+static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg);
+static long munmap(void *ptr, long size);
+
+static void vminfo (unsigned long*free, unsigned long*reserved, unsigned long*committed);
+static int cpuinfo (int whole, unsigned long*kernel, unsigned long*user);
+
+#endif
+
+/*
+ __STD_C should be nonzero if using ANSI-standard C compiler, a C++
+ compiler, or a C compiler sufficiently close to ANSI to get away
+ with it.
+*/
+
+#ifndef __STD_C
+#if defined(__STDC__) || defined(_cplusplus)
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif
+#endif /*__STD_C*/
+
+
+/*
+ Void_t* is the pointer type that malloc should say it returns
+*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#include "cygmalloc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define LACKS_UNISTD_H if your system does not have a <unistd.h>. */
+
+/* #define LACKS_UNISTD_H */
+
+#ifndef LACKS_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* define LACKS_SYS_PARAM_H if your system does not have a <sys/param.h>. */
+
+/* #define LACKS_SYS_PARAM_H */
+
+
+#include <stdio.h> /* needed for malloc_stats */
+#include <errno.h> /* needed for optional MALLOC_FAILURE_ACTION */
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with bookkeeping fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+ Setting DEBUG does NOT provide an automated mechanism for checking
+ that all accesses to malloced memory stay within their
+ bounds. However, there are several add-ons and adaptations of this
+ or other mallocs available that do this.
+*/
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+/*
+ The unsigned integer type used for comparing any two chunk sizes.
+ This should be at least as wide as size_t, but should not be signed.
+*/
+
+#ifndef CHUNK_SIZE_T
+#define CHUNK_SIZE_T unsigned long
+#endif
+
+/*
+ The unsigned integer type used to hold addresses when they are are
+ manipulated as integers. Except that it is not defined on all
+ systems, intptr_t would suffice.
+*/
+#ifndef PTR_UINT
+#define PTR_UINT unsigned long
+#endif
+
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes.
+
+ The default version is the same as size_t.
+
+ While not strictly necessary, it is best to define this as an
+ unsigned type, even if size_t is a signed type. This may avoid some
+ artificial size limitations on some systems.
+
+ On a 64-bit machine, you may be able to reduce malloc overhead by
+ defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the
+ expense of not being able to handle more than 2^32 of malloced
+ space. If this limitation is acceptable, you are encouraged to set
+ this unless you are on a platform requiring 16byte alignments. In
+ this case the alignment requirements turn out to negate any
+ potential advantages of decreasing size_t word size.
+
+ Implementors: Beware of the possible combinations of:
+ - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits,
+ and might be the same width as int or as long
+ - size_t might have different width and signedness as INTERNAL_SIZE_T
+ - int and long might be 32 or 64 bits, and might be the same width
+ To deal with this, most comparisons and difference computations
+ among INTERNAL_SIZE_Ts should cast them to CHUNK_SIZE_T, being
+ aware of the fact that casting an unsigned int to a wider long does
+ not sign-extend. (This also makes checking for negative numbers
+ awkward.) Some of these casts result in harmless compiler warnings
+ on some systems.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/* The corresponding word size */
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+
+
+
+/*
+ MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.
+ It must be a power of two at least 2 * SIZE_SZ, even on machines
+ for which smaller alignments would suffice. It may be defined as
+ larger than this though. Note however that code and data structures
+ are optimized for the case of 8-byte alignment.
+*/
+
+
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT (2 * SIZE_SZ)
+#endif
+
+/* The corresponding bit mask value */
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+
+
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+/* #define REALLOC_ZERO_BYTES_FREES */
+
+/*
+ TRIM_FASTBINS controls whether free() of a very small chunk can
+ immediately lead to trimming. Setting to true (1) can reduce memory
+ footprint, but will almost always slow down programs that use a lot
+ of small chunks.
+
+ Define this only if you are willing to give up some speed to more
+ aggressively reduce system-level memory footprint when releasing
+ memory in programs that use many small chunks. You can get
+ essentially the same effect by setting MXFAST to 0, but this can
+ lead to even greater slowdowns in programs using many small chunks.
+ TRIM_FASTBINS is an in-between compile-time option, that disables
+ only those chunks bordering topmost memory from being placed in
+ fastbins.
+*/
+
+#ifndef TRIM_FASTBINS
+#define TRIM_FASTBINS 0
+#endif
+
+
+/*
+ USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+ This is necessary when you only want to use this malloc in one part
+ of a program, using your regular system malloc elsewhere.
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+ USE_MALLOC_LOCK causes wrapper functions to surround each
+ callable routine with pthread mutex lock/unlock.
+
+ USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined
+*/
+
+
+/* #define USE_MALLOC_LOCK */
+
+
+/*
+ If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is
+ actually a wrapper function that first calls MALLOC_PREACTION, then
+ calls the internal routine, and follows it with
+ MALLOC_POSTACTION. This is needed for locking, but you can also use
+ this, without USE_MALLOC_LOCK, for purposes of interception,
+ instrumentation, etc. It is a sad fact that using wrappers often
+ noticeably degrades performance of malloc-intensive programs.
+*/
+
+#ifdef USE_MALLOC_LOCK
+#define USE_PUBLIC_MALLOC_WRAPPERS
+#else
+/* #define USE_PUBLIC_MALLOC_WRAPPERS */
+#endif
+
+
+/*
+ Two-phase name translation.
+ All of the actual routines are given mangled names.
+ When wrappers are used, they become the public callable versions.
+ When DL_PREFIX is used, the callable names are prefixed.
+*/
+
+#ifndef USE_PUBLIC_MALLOC_WRAPPERS
+#define cALLOc public_cALLOc
+#define fREe public_fREe
+#define cFREe public_cFREe
+#define mALLOc public_mALLOc
+#define mEMALIGn public_mEMALIGn
+#define rEALLOc public_rEALLOc
+#define vALLOc public_vALLOc
+#define pVALLOc public_pVALLOc
+#define mALLINFo public_mALLINFo
+#define mALLOPt public_mALLOPt
+#define mTRIm public_mTRIm
+#define mSTATs public_mSTATs
+#define mUSABLe public_mUSABLe
+#define iCALLOc public_iCALLOc
+#define iCOMALLOc public_iCOMALLOc
+#endif
+
+#ifdef USE_DL_PREFIX
+#define public_cALLOc dlcalloc
+#define public_fREe dlfree
+#define public_cFREe dlcfree
+#define public_mALLOc dlmalloc
+#define public_mEMALIGn dlmemalign
+#define public_rEALLOc dlrealloc
+#define public_vALLOc dlvalloc
+#define public_pVALLOc dlpvalloc
+#define public_mALLINFo dlmallinfo
+#define public_mALLOPt dlmallopt
+#define public_mTRIm dlmalloc_trim
+#define public_mSTATs dlmalloc_stats
+#define public_mUSABLe dlmalloc_usable_size
+#define public_iCALLOc dlindependent_calloc
+#define public_iCOMALLOc dlindependent_comalloc
+#else /* USE_DL_PREFIX */
+#define public_cALLOc calloc
+#define public_fREe free
+#define public_cFREe cfree
+#define public_mALLOc malloc
+#define public_mEMALIGn memalign
+#define public_rEALLOc realloc
+#define public_vALLOc valloc
+#define public_pVALLOc pvalloc
+#define public_mALLINFo mallinfo
+#define public_mALLOPt mallopt
+#define public_mTRIm malloc_trim
+#define public_mSTATs malloc_stats
+#define public_mUSABLe malloc_usable_size
+#define public_iCALLOc independent_calloc
+#define public_iCOMALLOc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined below.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are faster than libc versions on some systems.
+
+ Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks
+ (of <= 36 bytes) are manually unrolled in realloc and calloc.
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#ifdef WIN32
+/* On Win32 memset and memcpy are already declared in windows.h */
+#else
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+/*
+ MALLOC_FAILURE_ACTION is the action to take before "return 0" when
+ malloc fails to be able to return memory, either because memory is
+ exhausted or because of illegal arguments.
+
+ By default, sets errno if running on STD_C platform, else does nothing.
+*/
+
+#ifndef MALLOC_FAILURE_ACTION
+#if __STD_C
+#define MALLOC_FAILURE_ACTION \
+ errno = ENOMEM;
+
+#else
+#define MALLOC_FAILURE_ACTION
+#endif
+#endif
+
+/*
+ MORECORE-related declarations. By default, rely on sbrk
+*/
+
+
+#ifdef LACKS_UNISTD_H
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+#if __STD_C
+extern Void_t* sbrk(ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+#endif
+#endif
+
+/*
+ MORECORE is the name of the routine to call to obtain more memory
+ from the system. See below for general guidance on writing
+ alternative MORECORE functions, as well as a version for WIN32 and a
+ sample version for pre-OSX macos.
+*/
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+/*
+ MORECORE_FAILURE is the value returned upon failure of MORECORE
+ as well as mmap. Since it cannot be an otherwise valid memory address,
+ and must reflect values of standard sys calls, you probably ought not
+ try to redefine it.
+*/
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE (-1)
+#endif
+
+/*
+ If MORECORE_CONTIGUOUS is true, take advantage of fact that
+ consecutive calls to MORECORE with positive arguments always return
+ contiguous increasing addresses. This is true of unix sbrk. Even
+ if not defined, when regions happen to be contiguous, malloc will
+ permit allocations spanning regions obtained from different
+ calls. But defining this when applicable enables some stronger
+ consistency checks and space efficiencies.
+*/
+
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif
+
+/*
+ Define MORECORE_CANNOT_TRIM if your version of MORECORE
+ cannot release space back to the system when given negative
+ arguments. This is generally necessary only if you are using
+ a hand-crafted MORECORE function that cannot handle negative arguments.
+*/
+
+/* #define MORECORE_CANNOT_TRIM */
+
+
+/*
+ Define HAVE_MMAP as true to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free(). Also, if mmap
+ is available, it is used as a backup strategy in cases where
+ MORECORE fails to provide space from system.
+
+ This malloc is best tuned to work with mmap for large requests.
+ If you do not have mmap, operations involving very large chunks (1MB
+ or so) may be slower than you'd like.
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+#if HAVE_MMAP
+/*
+ Standard unix mmap using /dev/zero clears memory so calloc doesn't
+ need to.
+*/
+
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif
+
+#else /* no mmap */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 0
+#endif
+#endif
+
+
+/*
+ MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if
+ sbrk fails, and mmap is used as a backup (which is done only if
+ HAVE_MMAP). The value must be a multiple of page size. This
+ backup strategy generally applies only when systems have "holes" in
+ address space, so sbrk cannot perform contiguous expansion, but
+ there is still space available on system. On systems for which
+ this is known to be useful (i.e. most linux kernels), this occurs
+ only when programs allocate huge amounts of memory. Between this,
+ and the fact that mmap regions tend to be limited, the size should
+ be large, to avoid too many mmap calls and thus avoid running out
+ of kernel resources.
+*/
+
+#ifndef MMAP_AS_MORECORE_SIZE
+#define MMAP_AS_MORECORE_SIZE (1024 * 1024)
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+
+#endif /* HAVE_MMAP */
+
+
+/*
+ The system page size. To the extent possible, this malloc manages
+ memory from the system in page-size units. Note that this value is
+ cached during initialization into a field of malloc_state. So even
+ if malloc_getpagesize is a function, it is only called once.
+
+ The following mechanics for getpagesize were adapted from bsd/gnu
+ getpagesize.h. If none of the system-probes here apply, a value of
+ 4096 is used, which should be OK: If they don't apply, then using
+ the actual value probably doesn't impact performance.
+*/
+
+
+#ifndef malloc_getpagesize
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32 /* use supplied emulation of getpagesize */
+# define malloc_getpagesize getpagesize()
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else /* just guess */
+# define malloc_getpagesize (4096)
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/*
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing usage properties and
+ statistics. It should work on any SVID/XPG compliant system that has
+ a /usr/include/malloc.h defining struct mallinfo. (If you'd like to
+ install such a thing yourself, cut out the preliminary declarations
+ as described above and below and save them in a malloc.h file. But
+ there's no compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields that are not even meaningful in this version of
+ malloc. These fields are are instead filled by mallinfo() with
+ other numbers that might be of interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work. The original SVID version of this struct,
+ defined on most systems with mallinfo, declares all fields as
+ ints. But some others define as unsigned long. If your system
+ defines the fields using a type of different width than listed here,
+ you must #include your system version and #define
+ HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* non-mmapped space allocated from system */
+ int ordblks; /* number of free chunks */
+ int smblks; /* number of fastbin blocks */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* space in mmapped regions */
+ int usmblks; /* maximum total allocated space */
+ int fsmblks; /* space available in freed fastbin blocks */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total free space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/*
+ SVID/XPG defines four standard parameter numbers for mallopt,
+ normally defined in malloc.h. Only one of these (M_MXFAST) is used
+ in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt described below.
+*/
+#endif
+
+
+/* ---------- description of public routines ------------ */
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available. Additionally, on failure, errno is
+ set to ENOMEM on ANSI C systems.
+
+ If n is zero, malloc returns a minumum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
+ systems.) On most systems, size_t is an unsigned type, so calls
+ with negative arguments are interpreted as requests for huge amounts
+ of space, which will often fail. The maximum supported value of n
+ differs across systems, but is in all cases less than the maximum
+ representable value of a size_t.
+*/
+#if __STD_C
+Void_t* public_mALLOc(size_t);
+#else
+Void_t* public_mALLOc();
+#endif
+
+/*
+ free(Void_t* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. It can have arbitrary (i.e., bad!)
+ effects if p has already been freed.
+
+ Unless disabled (using mallopt), freeing very large spaces will
+ when possible, automatically trigger operations that give
+ back unused memory to the system, thus reducing program footprint.
+*/
+#if __STD_C
+void public_fREe(Void_t*);
+#else
+void public_fREe();
+#endif
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+#if __STD_C
+Void_t* public_cALLOc(size_t, size_t);
+#else
+Void_t* public_cALLOc();
+#endif
+
+/*
+ realloc(Void_t* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p when possible, otherwise it employs the
+ equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. Unless the #define
+ REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
+ zero (re)allocates a minimum-sized chunk.
+
+ Large chunks that were internally obtained via mmap will always
+ be reallocated using malloc-copy-free sequences unless
+ the system supports MREMAP (currently only linux).
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+#if __STD_C
+Void_t* public_rEALLOc(Void_t*, size_t);
+#else
+Void_t* public_rEALLOc();
+#endif
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+#if __STD_C
+Void_t* public_mEMALIGn(size_t, size_t);
+#else
+Void_t* public_mEMALIGn();
+#endif
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+#if __STD_C
+Void_t* public_vALLOc(size_t);
+#else
+Void_t* public_vALLOc();
+#endif
+
+
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. Only one of these (M_MXFAST) is used
+ in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+ so setting them has no effect. But this malloc also supports four
+ other options in mallopt. See below for details. Briefly, supported
+ parameters are as follows (listed defaults are for "typical"
+ configurations).
+
+ Symbol param # default allowed param values
+ M_MXFAST 1 64 0-80 (0 disables fastbins)
+ M_TRIM_THRESHOLD -1 256*1024 any (-1U disables trimming)
+ M_TOP_PAD -2 0 any
+ M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
+ M_MMAP_MAX -4 65536 any (0 disables use of mmap)
+*/
+#if __STD_C
+int public_mALLOPt(int, int);
+#else
+int public_mALLOPt();
+#endif
+
+
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: the number of fastbin blocks (i.e., small chunks that
+ have been freed but not use resused or consolidated)
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: total bytes held in fastbin blocks
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+#if __STD_C
+struct mallinfo public_mALLINFo(void);
+#else
+struct mallinfo public_mALLINFo();
+#endif
+
+/*
+ independent_calloc(size_t n_elements, size_t element_size, Void_t* chunks[]);
+
+ independent_calloc is similar to calloc, but instead of returning a
+ single cleared space, it returns an array of pointers to n_elements
+ independent elements that can hold contents of size elem_size, each
+ of which starts out cleared, and can be independently freed,
+ realloc'ed etc. The elements are guaranteed to be adjacently
+ allocated (this is not guaranteed to occur with multiple callocs or
+ mallocs), which may also improve cache locality in some
+ applications.
+
+ The "chunks" argument is optional (i.e., may be null, which is
+ probably the most typical usage). If it is null, the returned array
+ is itself dynamically allocated and should also be freed when it is
+ no longer needed. Otherwise, the chunks array must be of at least
+ n_elements in length. It is filled in with the pointers to the
+ chunks.
+
+ In either case, independent_calloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and "chunks"
+ is null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use regular calloc and assign pointers into this
+ space to represent elements. (In this case though, you cannot
+ independently free elements.)
+
+ independent_calloc simplifies and speeds up implementations of many
+ kinds of pools. It may also be useful when constructing large data
+ structures that initially have a fixed number of fixed-sized nodes,
+ but the number is not known at compile time, and some of the nodes
+ may later need to be freed. For example:
+
+ struct Node { int item; struct Node* next; };
+
+ struct Node* build_list() {
+ struct Node** pool;
+ int n = read_number_of_nodes_needed();
+ if (n <= 0) return 0;
+ pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+ if (pool == 0) die();
+ // organize into a linked list...
+ struct Node* first = pool[0];
+ for (i = 0; i < n-1; ++i)
+ pool[i]->next = pool[i+1];
+ free(pool); // Can now free the array (or not, if it is needed later)
+ return first;
+ }
+*/
+#if __STD_C
+Void_t** public_iCALLOc(size_t, size_t, Void_t**);
+#else
+Void_t** public_iCALLOc();
+#endif
+
+/*
+ independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]);
+
+ independent_comalloc allocates, all at once, a set of n_elements
+ chunks with sizes indicated in the "sizes" array. It returns
+ an array of pointers to these elements, each of which can be
+ independently freed, realloc'ed etc. The elements are guaranteed to
+ be adjacently allocated (this is not guaranteed to occur with
+ multiple callocs or mallocs), which may also improve cache locality
+ in some applications.
+
+ The "chunks" argument is optional (i.e., may be null). If it is null
+ the returned array is itself dynamically allocated and should also
+ be freed when it is no longer needed. Otherwise, the chunks array
+ must be of at least n_elements in length. It is filled in with the
+ pointers to the chunks.
+
+ In either case, independent_comalloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and chunks is
+ null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use a single regular malloc, and assign pointers at
+ particular offsets in the aggregate space. (In this case though, you
+ cannot independently free elements.)
+
+ independent_comallac differs from independent_calloc in that each
+ element may have a different size, and also that it does not
+ automatically clear elements.
+
+ independent_comalloc can be used to speed up allocation in cases
+ where several structs or objects must always be allocated at the
+ same time. For example:
+
+ struct Head { ... }
+ struct Foot { ... }
+
+ void send_message(char* msg) {
+ int msglen = strlen(msg);
+ size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+ void* chunks[3];
+ if (independent_comalloc(3, sizes, chunks) == 0)
+ die();
+ struct Head* head = (struct Head*)(chunks[0]);
+ char* body = (char*)(chunks[1]);
+ struct Foot* foot = (struct Foot*)(chunks[2]);
+ // ...
+ }
+
+ In general though, independent_comalloc is worth using only for
+ larger values of n_elements. For small values, you probably won't
+ detect enough difference from series of malloc calls to bother.
+
+ Overuse of independent_comalloc can increase overall memory usage,
+ since it cannot reuse existing noncontiguous small chunks that
+ might be available for some of the elements.
+*/
+#if __STD_C
+Void_t** public_iCOMALLOc(size_t, size_t*, Void_t**);
+#else
+Void_t** public_iCOMALLOc();
+#endif
+
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+#if __STD_C
+Void_t* public_pVALLOc(size_t);
+#else
+Void_t* public_pVALLOc();
+#endif
+
+/*
+ cfree(Void_t* p);
+ Equivalent to free(p).
+
+ cfree is needed/defined on some systems that pair it with calloc,
+ for odd historical reasons (such as: cfree is used in example
+ code in the first edition of K&R).
+*/
+#if __STD_C
+void public_cFREe(Void_t*);
+#else
+void public_cFREe();
+#endif
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+ On systems that do not support "negative sbrks", it will always
+ rreturn 0.
+*/
+#if __STD_C
+int public_mTRIm(size_t);
+#else
+int public_mTRIm();
+#endif
+
+/*
+ malloc_usable_size(Void_t* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+
+*/
+#if __STD_C
+size_t public_mUSABLe(Void_t*);
+#else
+size_t public_mUSABLe();
+#endif
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+
+*/
+#if __STD_C
+void public_mSTATs();
+#else
+void public_mSTATs();
+#endif
+
+/* mallopt tuning options */
+
+/*
+ M_MXFAST is the maximum request size used for "fastbins", special bins
+ that hold returned chunks without consolidating their spaces. This
+ enables future requests for chunks of the same size to be handled
+ very quickly, but can increase fragmentation, and thus increase the
+ overall memory footprint of a program.
+
+ This malloc manages fastbins very conservatively yet still
+ efficiently, so fragmentation is rarely a problem for values less
+ than or equal to the default. The maximum supported value of MXFAST
+ is 80. You wouldn't want it any higher than this anyway. Fastbins
+ are designed especially for use with many small structs, objects or
+ strings -- the default handles structs/objects/arrays with sizes up
+ to 16 4byte fields, or small strings representing words, tokens,
+ etc. Using fastbins for larger objects normally worsens
+ fragmentation without improving speed.
+
+ M_MXFAST is set in REQUEST size units. It is internally used in
+ chunksize units, which adds padding and alignment. You can reduce
+ M_MXFAST to 0 to disable all use of fastbins. This causes the malloc
+ algorithm to be a closer approximation of fifo-best-fit in all cases,
+ not just for larger requests, but will generally cause it to be
+ slower.
+*/
+
+
+/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */
+#ifndef M_MXFAST
+#define M_MXFAST 1
+#endif
+
+#ifndef DEFAULT_MXFAST
+#define DEFAULT_MXFAST 64
+#endif
+
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing this much memory.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The trim value must be greater than page size to have any useful
+ effect. To disable trimming completely, you can set to
+ (unsigned long)(-1)
+
+ Trim settings interact with fastbin (MXFAST) settings: Unless
+ TRIM_FASTBINS is defined, automatic trimming never takes place upon
+ freeing a chunk with size less than or equal to MXFAST. Trimming is
+ instead delayed until subsequent freeing of larger chunks. However,
+ you can still force an attempted trim by calling malloc_trim.
+
+ Also, trimming is not generally possible in cases where
+ the main arena is obtained via mmap.
+
+ Note that the trick some people use of mallocing a huge space and
+ then freeing it at program startup, in an attempt to reserve system
+ memory, doesn't have the intended effect under automatic trimming,
+ since that memory will immediately be returned to the system.
+*/
+
+#define M_TRIM_THRESHOLD -1
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (256 * 1024)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+*/
+
+#define M_TOP_PAD -2
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefits that:
+
+ 1. Mmapped space can ALWAYS be individually released back
+ to the system, which helps keep the system level memory
+ demands of a long-lived program low.
+ 2. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ means that even trimming via malloc_trim would not release them.
+ 3. On some systems with "holes" in address spaces, mmap can obtain
+ memory that sbrk cannot.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ The advantages of mmap nearly always outweigh disadvantages for
+ "large" chunks, but the value of "large" varies across systems. The
+ default is an empirically derived value that works well in most
+ systems.
+*/
+
+#define M_MMAP_THRESHOLD -3
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (256 * 1024)
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because
+. Some systems have a limited number of internal tables for
+ use by mmap, and using more than a few of them may degrade
+ performance.
+
+ The default is set to a value that serves only as a safeguard.
+ Setting to 0 disables use of mmap for servicing large requests. If
+ HAVE_MMAP is not set, the default value is 0, and attempts to set it
+ to non-zero values in mallopt will fail.
+*/
+
+#define M_MMAP_MAX -4
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (65536)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/*
+ ========================================================================
+ To make a fully customizable malloc.h header file, cut everything
+ above this line, put into file malloc.h, edit to suit, and #include it
+ on the next line, as well as in programs that use this malloc.
+ ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/* --------------------- public wrappers ---------------------- */
+
+#ifdef USE_PUBLIC_MALLOC_WRAPPERS
+
+/* Declare all routines as internal */
+#if __STD_C
+static Void_t* mALLOc(size_t);
+static void fREe(Void_t*);
+static Void_t* rEALLOc(Void_t*, size_t);
+static Void_t* mEMALIGn(size_t, size_t);
+static Void_t* vALLOc(size_t);
+static Void_t* pVALLOc(size_t);
+static Void_t* cALLOc(size_t, size_t);
+static Void_t** iCALLOc(size_t, size_t, Void_t**);
+static Void_t** iCOMALLOc(size_t, size_t*, Void_t**);
+static void cFREe(Void_t*);
+static int mTRIm(size_t);
+static size_t mUSABLe(Void_t*);
+static void mSTATs();
+static int mALLOPt(int, int);
+static struct mallinfo mALLINFo(void);
+#else
+static Void_t* mALLOc();
+static void fREe();
+static Void_t* rEALLOc();
+static Void_t* mEMALIGn();
+static Void_t* vALLOc();
+static Void_t* pVALLOc();
+static Void_t* cALLOc();
+static Void_t** iCALLOc();
+static Void_t** iCOMALLOc();
+static void cFREe();
+static int mTRIm();
+static size_t mUSABLe();
+static void mSTATs();
+static int mALLOPt();
+static struct mallinfo mALLINFo();
+#endif
+
+/*
+ MALLOC_PREACTION and MALLOC_POSTACTION should be
+ defined to return 0 on success, and nonzero on failure.
+ The return value of MALLOC_POSTACTION is currently ignored
+ in wrapper functions since there is no reasonable default
+ action to take on failure.
+*/
+
+
+#ifdef USE_MALLOC_LOCK
+
+#ifdef WIN32
+
+static int mALLOC_MUTEx;
+#define MALLOC_PREACTION slwait(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx)
+
+#else
+
+#include <pthread.h>
+
+static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER;
+
+#define MALLOC_PREACTION pthread_mutex_lock(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION pthread_mutex_unlock(&mALLOC_MUTEx)
+
+#endif /* USE_MALLOC_LOCK */
+
+#else
+
+/* Substitute anything you like for these */
+
+#define MALLOC_PREACTION (0)
+#define MALLOC_POSTACTION (0)
+
+#endif
+
+Void_t* public_mALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = mALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+void public_fREe(Void_t* m) {
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ fREe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+}
+
+Void_t* public_rEALLOc(Void_t* m, size_t bytes) {
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = rEALLOc(m, bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t* public_mEMALIGn(size_t alignment, size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = mEMALIGn(alignment, bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t* public_vALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = vALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+#ifdef NEED_PVALLOC
+Void_t* public_pVALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = pVALLOc(bytes);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+#endif
+
+Void_t* public_cALLOc(size_t n, size_t elem_size) {
+ Void_t* m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = cALLOc(n, elem_size);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+
+Void_t** public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks) {
+ Void_t** m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = iCALLOc(n, elem_size, chunks);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+Void_t** public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks) {
+ Void_t** m;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ m = iCOMALLOc(n, sizes, chunks);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+void public_cFREe(Void_t* m) {
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ cFREe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+}
+
+int public_mTRIm(size_t s) {
+ int result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mTRIm(s);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+}
+
+size_t public_mUSABLe(Void_t* m) {
+ size_t result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mUSABLe(m);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+}
+
+void public_mSTATs() {
+ if (MALLOC_PREACTION != 0) {
+ return;
+ }
+ mSTATs();
+ if (MALLOC_POSTACTION != 0) {
+ }
+}
+
+struct mallinfo public_mALLINFo() {
+ struct mallinfo m;
+ if (MALLOC_PREACTION != 0) {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ return nm;
+ }
+ m = mALLINFo();
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return m;
+}
+
+int public_mALLOPt(int p, int v) {
+ int result;
+ if (MALLOC_PREACTION != 0) {
+ return 0;
+ }
+ result = mALLOPt(p, v);
+ if (MALLOC_POSTACTION != 0) {
+ }
+ return result;
+}
+
+#endif
+
+
+
+/* ------------- Optional versions of memcopy ---------------- */
+
+
+#if USE_MEMCPY
+
+/*
+ Note: memcpy is ONLY invoked with non-overlapping regions,
+ so the (usually slower) memmove is not needed.
+*/
+
+#define MALLOC_COPY(dest, src, nbytes) memcpy(dest, src, nbytes)
+#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ CHUNK_SIZE_T mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \
+ long mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ CHUNK_SIZE_T mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \
+ long mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+/* ------------------ MMAP support ------------------ */
+
+
+#if HAVE_MMAP
+
+#ifndef LACKS_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifndef LACKS_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/*
+ Nearly all versions of mmap support MAP_ANONYMOUS,
+ so the following is unlikely to be needed, but is
+ supplied just in case.
+*/
+
+#ifndef MAP_ANONYMOUS
+
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+
+#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \
+ (dev_zero_fd = open("/dev/zero", O_RDWR), \
+ mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \
+ mmap((addr), (size), (prot), (flags), dev_zero_fd, 0))
+
+#else
+
+#define MMAP(addr, size, prot, flags) \
+ (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0))
+
+#endif
+
+
+#endif /* HAVE_MMAP */
+
+
+/*
+ ----------------------- Chunk representations -----------------------
+*/
+
+
+/*
+ This struct declaration is misleading (but accurate and necessary).
+ It declares a "view" into memory allowing access to necessary
+ fields at known offsets from a given base. See explanation below.
+*/
+
+struct malloc_chunk {
+
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus at least double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory. If
+ prev_inuse is set for any given chunk, then you CANNOT determine
+ the size of the previous chunk, and might even get a memory
+ addressing fault when trying to do so.
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. This makes it easier to
+ deal with alignments etc but can be very confusing when trying
+ to extend or adapt this code.
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top' doesn't bother using the
+ trailing size field since there is no next contiguous chunk
+ that would have to index off it. After initialization, `top'
+ is forced to always exist. If it would become less than
+ MINSIZE bytes long, it is replenished.
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ allocated one-by-one, each must contain its own trailing size field.
+
+*/
+
+/*
+ ---------- Size and alignment checks and conversions ----------
+*/
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* The smallest possible chunk */
+#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk))
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+
+#define MINSIZE \
+ (CHUNK_SIZE_T)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((PTR_UINT)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+/*
+ Check if a request is so large that it would wrap around zero when
+ padded and aligned. To simplify some other code, the bound is made
+ low enough so that adding MINSIZE will also not wrap around sero.
+*/
+
+#define REQUEST_OUT_OF_RANGE(req) \
+ ((CHUNK_SIZE_T)(req) >= \
+ (CHUNK_SIZE_T)(INTERNAL_SIZE_T)(-2 * MINSIZE))
+
+/* pad request bytes into a usable size -- internal version */
+
+#define request2size(req) \
+ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
+ MINSIZE : \
+ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
+
+/* Same, except also perform argument check */
+
+#define checked_request2size(req, sz) \
+ if (REQUEST_OUT_OF_RANGE(req)) { \
+ MALLOC_FAILURE_ACTION; \
+ return 0; \
+ } \
+ (sz) = request2size(req);
+
+/*
+ --------------- Physical chunk operations ---------------
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+#define PREV_INUSE 0x1
+
+/* extract inuse bit of previous chunk */
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+#define IS_MMAPPED 0x2
+
+/* check for mmap()'ed chunk */
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/*
+ Bits to mask off when extracting size
+
+ Note: IS_MMAPPED is intentionally not masked off from size field in
+ macros for which mmapped chunks should never be seen. This should
+ cause helpful core dumps to occur if it is tried by accident by
+ people extending or adapting this malloc.
+*/
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+/* Get size, ignoring use bits */
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+
+/* Ptr to next physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+/* Treat space at ptr + offset as a chunk */
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+/* extract p's inuse bit */
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* set/clear chunk as being inuse without otherwise disturbing */
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+
+/* check/set/clear inuse bits in known places */
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+/* Set size at head, without disturbing its use bit */
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use field */
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+/*
+ -------------------- Internal data structures --------------------
+
+ All internal state is held in an instance of malloc_state defined
+ below. There are no other static variables, except in two optional
+ cases:
+ * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above.
+ * If HAVE_MMAP is true, but mmap doesn't support
+ MAP_ANONYMOUS, a dummy file descriptor for mmap.
+
+ Beware of lots of tricks that minimize the total bookkeeping space
+ requirements. The result is a little over 1K bytes (for 4byte
+ pointers and size_t.)
+*/
+
+/*
+ Bins
+
+ An array of bin headers for free chunks. Each bin is doubly
+ linked. The bins are approximately proportionally (log) spaced.
+ There are a lot of these bins (128). This may look excessive, but
+ works very well in practice. Most bins hold sizes that are
+ unusual as malloc request sizes, but are more usual for fragments
+ and consolidated sets of chunks, which is what these bins hold, so
+ they can be found quickly. All procedures maintain the invariant
+ that no consolidated chunk physically borders another one, so each
+ chunk in a list is known to be preceeded and followed by either
+ inuse chunks or the ends of memory.
+
+ Chunks in bins are kept in size order, with ties going to the
+ approximately least recently used chunk. Ordering isn't needed
+ for the small bins, which all contain the same-sized chunks, but
+ facilitates best-fit allocation for larger chunks. These lists
+ are just sequential. Keeping them in order almost never requires
+ enough traversal to warrant using fancier ordered data
+ structures.
+
+ Chunks of the same size are linked with the most
+ recently freed at the front, and allocations are taken from the
+ back. This results in LRU (FIFO) allocation order, which tends
+ to give each chunk an equal opportunity to be consolidated with
+ adjacent freed chunks, resulting in larger free chunks and less
+ fragmentation.
+
+ To simplify use in double-linked lists, each bin header acts
+ as a malloc_chunk. This avoids special-casing for headers.
+ But to conserve space and improve locality, we allocate
+ only the fd/bk pointers of bins, and then use repositioning tricks
+ to treat these as the fields of a malloc_chunk*.
+*/
+
+typedef struct malloc_chunk* mbinptr;
+
+/* addressing -- note that bin_at(0) does not exist */
+#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1)))
+
+/* analog of ++bin */
+#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1)))
+
+/* Reminders about list directionality within bins */
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/* Take a chunk off a bin list */
+#define unlink(P, BK, FD) { \
+ FD = P->fd; \
+ BK = P->bk; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+}
+
+/*
+ Indexing
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically spaced:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ The bins top out around 1MB because we expect to service large
+ requests via mmap.
+*/
+
+#define NBINS 96
+#define NSMALLBINS 32
+#define SMALLBIN_WIDTH 8
+#define MIN_LARGE_SIZE 256
+
+#define in_smallbin_range(sz) \
+ ((CHUNK_SIZE_T)(sz) < (CHUNK_SIZE_T)MIN_LARGE_SIZE)
+
+#define smallbin_index(sz) (((unsigned)(sz)) >> 3)
+
+/*
+ Compute index for size. We expect this to be inlined when
+ compiled with optimization, else not, which works out well.
+*/
+static int largebin_index(unsigned int sz) {
+ unsigned int x = sz >> SMALLBIN_WIDTH;
+ unsigned int m; /* bit position of highest set bit of m */
+
+ if (x >= 0x10000) return NBINS-1;
+
+ /* On intel, use BSRL instruction to find highest bit */
+#if defined(__GNUC__) && defined(i386)
+
+ __asm__("bsrl %1,%0\n\t"
+ : "=r" (m)
+ : "g" (x));
+
+#else
+ {
+ /*
+ Based on branch-free nlz algorithm in chapter 5 of Henry
+ S. Warren Jr's book "Hacker's Delight".
+ */
+
+ unsigned int n = ((x - 0x100) >> 16) & 8;
+ x <<= n;
+ m = ((x - 0x1000) >> 16) & 4;
+ n += m;
+ x <<= m;
+ m = ((x - 0x4000) >> 16) & 2;
+ n += m;
+ x = (x << m) >> 14;
+ m = 13 - n + (x & ~(x>>1));
+ }
+#endif
+
+ /* Use next 2 bits to create finer-granularity bins */
+ return NSMALLBINS + (m << 2) + ((sz >> (m + 6)) & 3);
+}
+
+#define bin_index(sz) \
+ ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz))
+
+/*
+ FIRST_SORTED_BIN_SIZE is the chunk size corresponding to the
+ first bin that is maintained in sorted order. This must
+ be the smallest size corresponding to a given bin.
+
+ Normally, this should be MIN_LARGE_SIZE. But you can weaken
+ best fit guarantees to sometimes speed up malloc by increasing value.
+ Doing this means that malloc may choose a chunk that is
+ non-best-fitting by up to the width of the bin.
+
+ Some useful cutoff values:
+ 512 - all bins sorted
+ 2560 - leaves bins <= 64 bytes wide unsorted
+ 12288 - leaves bins <= 512 bytes wide unsorted
+ 65536 - leaves bins <= 4096 bytes wide unsorted
+ 262144 - leaves bins <= 32768 bytes wide unsorted
+ -1 - no bins sorted (not recommended!)
+*/
+
+#define FIRST_SORTED_BIN_SIZE MIN_LARGE_SIZE
+/* #define FIRST_SORTED_BIN_SIZE 65536 */
+
+/*
+ Unsorted chunks
+
+ All remainders from chunk splits, as well as all returned chunks,
+ are first placed in the "unsorted" bin. They are then placed
+ in regular bins after malloc gives them ONE chance to be used before
+ binning. So, basically, the unsorted_chunks list acts as a queue,
+ with chunks being placed on it in free (and malloc_consolidate),
+ and taken off (to be either used or placed in bins) in malloc.
+*/
+
+/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
+#define unsorted_chunks(M) (bin_at(M, 1))
+
+/*
+ Top
+
+ The top-most available chunk (i.e., the one bordering the end of
+ available memory) is treated specially. It is never included in
+ any bin, is used only if no other chunk is available, and is
+ released back to the system if it is very large (see
+ M_TRIM_THRESHOLD). Because top initially
+ points to its own bin with initial zero size, thus forcing
+ extension on the first malloc request, we avoid having any special
+ code in malloc to check whether it even exists yet. But we still
+ need to do so when getting memory from system, so we make
+ initial_top treat the bin as a legal but unusable chunk during the
+ interval between initialization and the first call to
+ sYSMALLOc. (This is somewhat delicate, since it relies on
+ the 2 preceding words to be zero during this interval as well.)
+*/
+
+/* Conveniently, the unsorted bin can be used as dummy top on first call */
+#define initial_top(M) (unsorted_chunks(M))
+
+/*
+ Binmap
+
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binmap' is a
+ bitvector recording whether bins are definitely empty so they can
+ be skipped over during during traversals. The bits are NOT always
+ cleared as soon as bins are empty, but instead only
+ when they are noticed to be empty during traversal in malloc.
+*/
+
+/* Conservatively use 32 bits per map word, even if on 64bit system */
+#define BINMAPSHIFT 5
+#define BITSPERMAP (1U << BINMAPSHIFT)
+#define BINMAPSIZE (NBINS / BITSPERMAP)
+
+#define idx2block(i) ((i) >> BINMAPSHIFT)
+#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1))))
+
+#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i))
+#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i)))
+#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i))
+
+/*
+ Fastbins
+
+ An array of lists holding recently freed small chunks. Fastbins
+ are not doubly linked. It is faster to single-link them, and
+ since chunks are never removed from the middles of these lists,
+ double linking is not necessary. Also, unlike regular bins, they
+ are not even processed in FIFO order (they use faster LIFO) since
+ ordering doesn't much matter in the transient contexts in which
+ fastbins are normally used.
+
+ Chunks in fastbins keep their inuse bit set, so they cannot
+ be consolidated with other free chunks. malloc_consolidate
+ releases all chunks in fastbins and consolidates them with
+ other free chunks.
+*/
+
+typedef struct malloc_chunk* mfastbinptr;
+
+/* offset 2 to use otherwise unindexable first 2 bins */
+#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2)
+
+/* The maximum fastbin request size we support */
+#define MAX_FAST_SIZE 80
+
+#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1)
+
+/*
+ FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free()
+ that triggers automatic consolidation of possibly-surrounding
+ fastbin chunks. This is a heuristic, so the exact value should not
+ matter too much. It is defined at half the default trim threshold as a
+ compromise heuristic to only attempt consolidation if it is likely
+ to lead to trimming. However, it is not dynamically tunable, since
+ consolidation reduces fragmentation surrounding loarge chunks even
+ if trimming is not used.
+*/
+
+#define FASTBIN_CONSOLIDATION_THRESHOLD \
+ ((unsigned long)(DEFAULT_TRIM_THRESHOLD) >> 1)
+
+/*
+ Since the lowest 2 bits in max_fast don't matter in size comparisons,
+ they are used as flags.
+*/
+
+/*
+ ANYCHUNKS_BIT held in max_fast indicates that there may be any
+ freed chunks at all. It is set true when entering a chunk into any
+ bin.
+*/
+
+#define ANYCHUNKS_BIT (1U)
+
+#define have_anychunks(M) (((M)->max_fast & ANYCHUNKS_BIT))
+#define set_anychunks(M) ((M)->max_fast |= ANYCHUNKS_BIT)
+#define clear_anychunks(M) ((M)->max_fast &= ~ANYCHUNKS_BIT)
+
+/*
+ FASTCHUNKS_BIT held in max_fast indicates that there are probably
+ some fastbin chunks. It is set true on entering a chunk into any
+ fastbin, and cleared only in malloc_consolidate.
+*/
+
+#define FASTCHUNKS_BIT (2U)
+
+#define have_fastchunks(M) (((M)->max_fast & FASTCHUNKS_BIT))
+#define set_fastchunks(M) ((M)->max_fast |= (FASTCHUNKS_BIT|ANYCHUNKS_BIT))
+#define clear_fastchunks(M) ((M)->max_fast &= ~(FASTCHUNKS_BIT))
+
+/*
+ Set value of max_fast.
+ Use impossibly small value if 0.
+*/
+
+#define set_max_fast(M, s) \
+ (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \
+ ((M)->max_fast & (FASTCHUNKS_BIT|ANYCHUNKS_BIT))
+
+#define get_max_fast(M) \
+ ((M)->max_fast & ~(FASTCHUNKS_BIT | ANYCHUNKS_BIT))
+
+
+/*
+ morecore_properties is a status word holding dynamically discovered
+ or controlled properties of the morecore function
+*/
+
+#define MORECORE_CONTIGUOUS_BIT (1U)
+
+#define contiguous(M) \
+ (((M)->morecore_properties & MORECORE_CONTIGUOUS_BIT))
+#define noncontiguous(M) \
+ (((M)->morecore_properties & MORECORE_CONTIGUOUS_BIT) == 0)
+#define set_contiguous(M) \
+ ((M)->morecore_properties |= MORECORE_CONTIGUOUS_BIT)
+#define set_noncontiguous(M) \
+ ((M)->morecore_properties &= ~MORECORE_CONTIGUOUS_BIT)
+
+
+/*
+ ----------- Internal state representation and initialization -----------
+*/
+
+struct malloc_state {
+
+ /* The maximum chunk size to be eligible for fastbin */
+ INTERNAL_SIZE_T max_fast; /* low 2 bits used as flags */
+
+ /* Fastbins */
+ mfastbinptr fastbins[NFASTBINS];
+
+ /* Base of the topmost chunk -- not otherwise kept in a bin */
+ mchunkptr top;
+
+ /* The remainder from the most recent split of a small request */
+ mchunkptr last_remainder;
+
+ /* Normal bins packed as described above */
+ mchunkptr bins[NBINS * 2];
+
+ /* Bitmap of bins. Trailing zero map handles cases of largest binned size */
+ unsigned int binmap[BINMAPSIZE+1];
+
+ /* Tunable parameters */
+ CHUNK_SIZE_T trim_threshold;
+ INTERNAL_SIZE_T top_pad;
+ INTERNAL_SIZE_T mmap_threshold;
+
+ /* Memory map support */
+ int n_mmaps;
+ int n_mmaps_max;
+ int max_n_mmaps;
+
+ /* Cache malloc_getpagesize */
+ unsigned int pagesize;
+
+ /* Track properties of MORECORE */
+ unsigned int morecore_properties;
+
+ /* Statistics */
+ INTERNAL_SIZE_T mmapped_mem;
+ INTERNAL_SIZE_T sbrked_mem;
+ INTERNAL_SIZE_T max_sbrked_mem;
+ INTERNAL_SIZE_T max_mmapped_mem;
+ INTERNAL_SIZE_T max_total_mem;
+};
+
+typedef struct malloc_state *mstate;
+
+/*
+ There is exactly one instance of this struct in this malloc.
+ If you are adapting this malloc in a way that does NOT use a static
+ malloc_state, you MUST explicitly zero-fill it before using. This
+ malloc relies on the property that malloc_state is initialized to
+ all zeroes (as is true of C statics).
+*/
+
+static struct malloc_state av_; /* never directly referenced */
+
+/*
+ All uses of av_ are via get_malloc_state().
+ At most one "call" to get_malloc_state is made per invocation of
+ the public versions of malloc and free, but other routines
+ that in turn invoke malloc and/or free may call more then once.
+ Also, it is called in check* routines if DEBUG is set.
+*/
+
+#define get_malloc_state() (&(av_))
+
+/*
+ Initialize a malloc_state struct.
+
+ This is called only from within malloc_consolidate, which needs
+ be called in the same contexts anyway. It is never called directly
+ outside of malloc_consolidate because some optimizing compilers try
+ to inline it at all call points, which turns out not to be an
+ optimization at all. (Inlining it in malloc_consolidate is fine though.)
+*/
+
+#if __STD_C
+static void malloc_init_state(mstate av)
+#else
+static void malloc_init_state(av) mstate av;
+#endif
+{
+ int i;
+ mbinptr bin;
+
+ /* Establish circular links for normal bins */
+ for (i = 1; i < NBINS; ++i) {
+ bin = bin_at(av,i);
+ bin->fd = bin->bk = bin;
+ }
+
+ av->top_pad = DEFAULT_TOP_PAD;
+ av->n_mmaps_max = DEFAULT_MMAP_MAX;
+ av->mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+ av->trim_threshold = DEFAULT_TRIM_THRESHOLD;
+
+#if MORECORE_CONTIGUOUS
+ set_contiguous(av);
+#else
+ set_noncontiguous(av);
+#endif
+
+
+ set_max_fast(av, DEFAULT_MXFAST);
+
+ av->top = initial_top(av);
+ av->pagesize = malloc_getpagesize;
+}
+
+/*
+ Other internal utilities operating on mstates
+*/
+
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T, mstate);
+#ifndef MORECORE_CANNOT_TRIM
+static int sYSTRIm(size_t, mstate);
+#endif
+static void malloc_consolidate(mstate);
+#ifdef NEED_INDEPENDENT
+static Void_t** iALLOc(size_t, size_t*, int, Void_t**);
+#endif
+#else
+static Void_t* sYSMALLOc();
+#ifndef MORECORE_CANNOT_TRIM
+static int sYSTRIm();
+#endif
+static void malloc_consolidate();
+#ifdef NEED_INDEPENDENT
+static Void_t** iALLOc();
+#endif
+#endif
+
+/*
+ Debugging support
+
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#if ! DEBUG
+
+#define check_chunk(P)
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N)
+#define check_malloc_state()
+
+#else
+#define check_chunk(P) do_check_chunk(P)
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#define check_malloc_state() do_check_malloc_state()
+
+/*
+ Properties of all chunks
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ mstate av = get_malloc_state();
+ CHUNK_SIZE_T sz = chunksize(p);
+ /* min and max possible addresses assuming contiguous allocation */
+ char* max_address = (char*)(av->top) + chunksize(av->top);
+ char* min_address = max_address - av->sbrked_mem;
+
+ if (!chunk_is_mmapped(p)) {
+
+ /* Has legal address ... */
+ if (p != av->top) {
+ if (contiguous(av)) {
+ assert(((char*)p) >= min_address);
+ assert(((char*)p + sz) <= ((char*)(av->top)));
+ }
+ }
+ else {
+ /* top size is always at least MINSIZE */
+ assert((CHUNK_SIZE_T)(sz) >= MINSIZE);
+ /* top predecessor always marked inuse */
+ assert(prev_inuse(p));
+ }
+
+ }
+ else {
+#if HAVE_MMAP
+ /* address is outside main heap */
+ if (contiguous(av) && av->top != initial_top(av)) {
+ assert(((char*)p) < min_address || ((char*)p) > max_address);
+ }
+ /* chunk is page-aligned */
+ assert(((p->prev_size + sz) & (av->pagesize-1)) == 0);
+ /* mem is aligned */
+ assert(aligned_OK(chunk2mem(p)));
+#else
+ /* force an appropriate assert violation if debug set */
+ assert(!chunk_is_mmapped(p));
+#endif
+ }
+}
+
+/*
+ Properties of free chunks
+*/
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Chunk must claim to be free ... */
+ assert(!inuse(p));
+ assert (!chunk_is_mmapped(p));
+
+ /* Unless a special marker, must have OK fields */
+ if ((CHUNK_SIZE_T)(sz) >= MINSIZE)
+ {
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert(aligned_OK(chunk2mem(p)));
+ /* ... matching footer field */
+ assert(next->prev_size == sz);
+ /* ... and is fully consolidated */
+ assert(prev_inuse(p));
+ assert (next == av->top || inuse(next));
+
+ /* ... and has minimally sane links */
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ assert(sz == SIZE_SZ);
+}
+
+/*
+ Properties of inuse chunks
+*/
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mstate av = get_malloc_state();
+ mchunkptr next;
+ do_check_chunk(p);
+
+ if (chunk_is_mmapped(p))
+ return; /* mmapped chunks have no next/prev */
+
+ /* Check whether it claims to be in use ... */
+ assert(inuse(p));
+
+ next = next_chunk(p);
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p)) {
+ /* Note that we cannot even look at prev unless it is not inuse */
+ mchunkptr prv = prev_chunk(p);
+ assert(next_chunk(prv) == p);
+ do_check_free_chunk(prv);
+ }
+
+ if (next == av->top) {
+ assert(prev_inuse(next));
+ assert(chunksize(next) >= MINSIZE);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+}
+
+/*
+ Properties of chunks recycled from fastbins
+*/
+
+#if __STD_C
+static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ assert((sz & MALLOC_ALIGN_MASK) == 0);
+ assert((CHUNK_SIZE_T)(sz) >= MINSIZE);
+ /* ... and alignment */
+ assert(aligned_OK(chunk2mem(p)));
+ /* chunk is less than MINSIZE more than request */
+ assert((long)(sz) - (long)(s) >= 0);
+ assert((long)(sz) - (long)(s + MINSIZE) < 0);
+}
+
+/*
+ Properties of nonrecycled chunks at the point they are malloced
+*/
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ /* same as recycled case ... */
+ do_check_remalloced_chunk(p, s);
+
+ /*
+ ... plus, must obey implementation invariant that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use
+ chunk, or the base of its memory arena. This is ensured
+ by making all allocations from the the `lowest' part of any found
+ chunk. This does not necessarily hold however for chunks
+ recycled via fastbins.
+ */
+
+ assert(prev_inuse(p));
+}
+
+
+/*
+ Properties of malloc_state.
+
+ This may be useful for debugging malloc, as well as detecting user
+ programmer errors that somehow write into malloc_state.
+
+ If you are extending or experimenting with this malloc, you can
+ probably figure out how to hack this routine to print out or
+ display chunk addresses, sizes, bins, and other instrumentation.
+*/
+
+static void do_check_malloc_state()
+{
+ mstate av = get_malloc_state();
+ int i;
+ mchunkptr p;
+ mchunkptr q;
+ mbinptr b;
+ unsigned int binbit;
+ int empty;
+ unsigned int idx;
+ INTERNAL_SIZE_T size;
+ CHUNK_SIZE_T total = 0;
+ int max_fast_bin;
+
+ /* internal size_t must be no wider than pointer type */
+ assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*));
+
+ /* alignment is a power of 2 */
+ assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0);
+
+ /* cannot run remaining checks until fully initialized */
+ if (av->top == 0 || av->top == initial_top(av))
+ return;
+
+ /* pagesize is a power of 2 */
+ assert((av->pagesize & (av->pagesize-1)) == 0);
+
+ /* properties of fastbins */
+
+ /* max_fast is in allowed range */
+ assert(get_max_fast(av) <= request2size(MAX_FAST_SIZE));
+
+ max_fast_bin = fastbin_index(av->max_fast);
+
+ for (i = 0; i < NFASTBINS; ++i) {
+ p = av->fastbins[i];
+
+ /* all bins past max_fast are empty */
+ if (i > max_fast_bin)
+ assert(p == 0);
+
+ while (p != 0) {
+ /* each chunk claims to be inuse */
+ do_check_inuse_chunk(p);
+ total += chunksize(p);
+ /* chunk belongs in this bin */
+ assert(fastbin_index(chunksize(p)) == i);
+ p = p->fd;
+ }
+ }
+
+ if (total != 0)
+ assert(have_fastchunks(av));
+ else if (!have_fastchunks(av))
+ assert(total == 0);
+
+ /* check normal bins */
+ for (i = 1; i < NBINS; ++i) {
+ b = bin_at(av,i);
+
+ /* binmap is accurate (except for bin 1 == unsorted_chunks) */
+ if (i >= 2) {
+ binbit = get_binmap(av,i);
+ empty = last(b) == b;
+ if (!binbit)
+ assert(empty);
+ else if (!empty)
+ assert(binbit);
+ }
+
+ for (p = last(b); p != b; p = p->bk) {
+ /* each chunk claims to be free */
+ do_check_free_chunk(p);
+ size = chunksize(p);
+ total += size;
+ if (i >= 2) {
+ /* chunk belongs in bin */
+ idx = bin_index(size);
+ assert(idx == i);
+ /* lists are sorted */
+ if ((CHUNK_SIZE_T) size >= (CHUNK_SIZE_T)(FIRST_SORTED_BIN_SIZE)) {
+ assert(p->bk == b ||
+ (CHUNK_SIZE_T)chunksize(p->bk) >=
+ (CHUNK_SIZE_T)chunksize(p));
+ }
+ }
+ /* chunk is followed by a legal chain of inuse chunks */
+ for (q = next_chunk(p);
+ (q != av->top && inuse(q) &&
+ (CHUNK_SIZE_T)(chunksize(q)) >= MINSIZE);
+ q = next_chunk(q))
+ do_check_inuse_chunk(q);
+ }
+ }
+
+ /* top chunk is OK */
+ check_chunk(av->top);
+
+ /* sanity checks for statistics */
+
+ assert(total <= (CHUNK_SIZE_T)(av->max_total_mem));
+ assert(av->n_mmaps >= 0);
+ assert(av->n_mmaps <= av->max_n_mmaps);
+
+ assert((CHUNK_SIZE_T)(av->sbrked_mem) <=
+ (CHUNK_SIZE_T)(av->max_sbrked_mem));
+
+ assert((CHUNK_SIZE_T)(av->mmapped_mem) <=
+ (CHUNK_SIZE_T)(av->max_mmapped_mem));
+
+ assert((CHUNK_SIZE_T)(av->max_total_mem) >=
+ (CHUNK_SIZE_T)(av->mmapped_mem) + (CHUNK_SIZE_T)(av->sbrked_mem));
+}
+#endif
+
+
+/* ----------- Routines dealing with system allocation -------------- */
+
+/*
+ sysmalloc handles malloc cases requiring more memory from the system.
+ On entry, it is assumed that av->top does not have enough
+ space to service request for nb bytes, thus requiring that av->top
+ be extended or replaced.
+*/
+
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av)
+#else
+static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+#endif
+{
+ mchunkptr old_top; /* incoming value of av->top */
+ INTERNAL_SIZE_T old_size; /* its size */
+ char* old_end; /* its end address */
+
+ long size; /* arg to first MORECORE or mmap call */
+ char* brk; /* return value from MORECORE */
+
+ long correction; /* arg to 2nd MORECORE call */
+ char* snd_brk; /* 2nd return val */
+
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */
+ INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */
+ char* aligned_brk; /* aligned offset into brk */
+
+ mchunkptr p; /* the allocated/returned chunk */
+ mchunkptr remainder; /* remainder from allocation */
+ CHUNK_SIZE_T remainder_size; /* its size */
+
+ CHUNK_SIZE_T sum; /* for updating stats */
+
+ size_t pagemask = av->pagesize - 1;
+
+ /*
+ If there is space available in fastbins, consolidate and retry
+ malloc from scratch rather than getting memory from system. This
+ can occur only if nb is in smallbin range so we didn't consolidate
+ upon entry to malloc. It is much easier to handle this case here
+ than in malloc proper.
+ */
+
+ if (have_fastchunks(av)) {
+ assert(in_smallbin_range(nb));
+ malloc_consolidate(av);
+ return mALLOc(nb - MALLOC_ALIGN_MASK);
+ }
+
+
+#if HAVE_MMAP
+
+ /*
+ If have mmap, and the request size meets the mmap threshold, and
+ the system supports mmap, and there are few enough currently
+ allocated mmapped regions, try to directly map this request
+ rather than expanding top.
+ */
+
+ if ((CHUNK_SIZE_T)(nb) >= (CHUNK_SIZE_T)(av->mmap_threshold) &&
+ (av->n_mmaps < av->n_mmaps_max)) {
+
+ char* mm; /* return value from mmap call*/
+
+ /*
+ Round up size to nearest page. For mmapped chunks, the overhead
+ is one SIZE_SZ unit larger than for normal chunks, because there
+ is no following chunk whose prev_size field could be used.
+ */
+ size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask;
+
+ /* Don't try if size wraps around 0 */
+ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) {
+
+ mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+
+ if (mm != (char*)(MORECORE_FAILURE)) {
+
+ /*
+ The offset to the start of the mmapped region is stored
+ in the prev_size field of the chunk. This allows us to adjust
+ returned start address to meet alignment requirements here
+ and in memalign(), and still be able to compute proper
+ address argument for later munmap in free() and realloc().
+ */
+
+ front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0) {
+ correction = MALLOC_ALIGNMENT - front_misalign;
+ p = (mchunkptr)(mm + correction);
+ p->prev_size = correction;
+ set_head(p, (size - correction) |IS_MMAPPED);
+ }
+ else {
+ p = (mchunkptr)mm;
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+ }
+
+ /* update statistics */
+
+ if (++av->n_mmaps > av->max_n_mmaps)
+ av->max_n_mmaps = av->n_mmaps;
+
+ sum = av->mmapped_mem += size;
+ if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem))
+ av->max_mmapped_mem = sum;
+ sum += av->sbrked_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ check_chunk(p);
+
+ return chunk2mem(p);
+ }
+ }
+ }
+#endif
+
+ /* Record incoming configuration of top */
+
+ old_top = av->top;
+ old_size = chunksize(old_top);
+ old_end = (char*)(chunk_at_offset(old_top, old_size));
+
+ brk = snd_brk = (char*)(MORECORE_FAILURE);
+
+ /*
+ If not the first time through, we require old_size to be
+ at least MINSIZE and to have prev_inuse set.
+ */
+
+ assert((old_top == initial_top(av) && old_size == 0) ||
+ ((CHUNK_SIZE_T) (old_size) >= MINSIZE &&
+ prev_inuse(old_top)));
+
+ /* Precondition: not enough current space to satisfy nb request */
+ assert((CHUNK_SIZE_T)(old_size) < (CHUNK_SIZE_T)(nb + MINSIZE));
+
+ /* Precondition: all fastbins are consolidated */
+ assert(!have_fastchunks(av));
+
+
+ /* Request enough space for nb + pad + overhead */
+
+ size = nb + av->top_pad + MINSIZE;
+
+ /*
+ If contiguous, we can subtract out existing space that we hope to
+ combine with new space. We add it back later only if
+ we don't actually get contiguous space.
+ */
+
+ if (contiguous(av))
+ size -= old_size;
+
+ /*
+ Round to a multiple of page size.
+ If MORECORE is not contiguous, this ensures that we only call it
+ with whole-page arguments. And if MORECORE is contiguous and
+ this is not first time through, this preserves page-alignment of
+ previous calls. Otherwise, we correct to page-align below.
+ */
+
+ size = (size + pagemask) & ~pagemask;
+
+ /*
+ Don't try to call MORECORE if argument is so big as to appear
+ negative. Note that since mmap takes size_t arg, it may succeed
+ below even if we cannot call MORECORE.
+ */
+
+ if (size > 0)
+ brk = (char*)(MORECORE(size));
+
+ /*
+ If have mmap, try using it as a backup when MORECORE fails or
+ cannot be used. This is worth doing on systems that have "holes" in
+ address space, so sbrk cannot extend to give contiguous space, but
+ space is available elsewhere. Note that we ignore mmap max count
+ and threshold limits, since the space will not be used as a
+ segregated mmap region.
+ */
+
+#if HAVE_MMAP
+ if (brk == (char*)(MORECORE_FAILURE)) {
+
+ /* Cannot merge with old top, so add its size back in */
+ if (contiguous(av))
+ size = (size + old_size + pagemask) & ~pagemask;
+
+ /* If we are relying on mmap as backup, then use larger units */
+ if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(MMAP_AS_MORECORE_SIZE))
+ size = MMAP_AS_MORECORE_SIZE;
+
+ /* Don't try if size wraps around 0 */
+ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) {
+
+ brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+
+ if (brk != (char*)(MORECORE_FAILURE)) {
+
+ /* We do not need, and cannot use, another sbrk call to find end */
+ snd_brk = brk + size;
+
+ /*
+ Record that we no longer have a contiguous sbrk region.
+ After the first time mmap is used as backup, we do not
+ ever rely on contiguous space since this could incorrectly
+ bridge regions.
+ */
+ set_noncontiguous(av);
+ }
+ }
+ }
+#endif
+
+ if (brk != (char*)(MORECORE_FAILURE)) {
+ av->sbrked_mem += size;
+
+ /*
+ If MORECORE extends previous space, we can likewise extend top size.
+ */
+
+ if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) {
+ set_head(old_top, (size + old_size) | PREV_INUSE);
+ }
+
+ /*
+ Otherwise, make adjustments:
+
+ * If the first time through or noncontiguous, we need to call sbrk
+ just to find out where the end of memory lies.
+
+ * We need to ensure that all returned chunks from malloc will meet
+ MALLOC_ALIGNMENT
+
+ * If there was an intervening foreign sbrk, we need to adjust sbrk
+ request size to account for fact that we will not be able to
+ combine new space with existing space in old_top.
+
+ * Almost all systems internally allocate whole pages at a time, in
+ which case we might as well use the whole last page of request.
+ So we allocate enough more memory to hit a page boundary now,
+ which in turn causes future contiguous calls to page-align.
+ */
+
+ else {
+ front_misalign = 0;
+ end_misalign = 0;
+ correction = 0;
+ aligned_brk = brk;
+
+ /*
+ If MORECORE returns an address lower than we have seen before,
+ we know it isn't really contiguous. This and some subsequent
+ checks help cope with non-conforming MORECORE functions and
+ the presence of "foreign" calls to MORECORE from outside of
+ malloc or by other threads. We cannot guarantee to detect
+ these in all cases, but cope with the ones we do detect.
+ */
+ if (contiguous(av) && old_size != 0 && brk < old_end) {
+ set_noncontiguous(av);
+ }
+
+ /* handle contiguous cases */
+ if (contiguous(av)) {
+
+ /*
+ We can tolerate forward non-contiguities here (usually due
+ to foreign calls) but treat them as part of our space for
+ stats reporting.
+ */
+ if (old_size != 0)
+ av->sbrked_mem += brk - old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+
+ front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0) {
+
+ /*
+ Skip over some bytes to arrive at an aligned position.
+ We don't need to specially mark these wasted front bytes.
+ They will never be accessed anyway because
+ prev_inuse of av->top (and any chunk created from its start)
+ is always true after initialization.
+ */
+
+ correction = MALLOC_ALIGNMENT - front_misalign;
+ aligned_brk += correction;
+ }
+
+ /*
+ If this isn't adjacent to existing space, then we will not
+ be able to merge with old_top space, so must add to 2nd request.
+ */
+
+ correction += old_size;
+
+ /* Extend the end address to hit a page boundary */
+ end_misalign = (INTERNAL_SIZE_T)(brk + size + correction);
+ correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign;
+
+ assert(correction >= 0);
+ snd_brk = (char*)(MORECORE(correction));
+
+ if (snd_brk == (char*)(MORECORE_FAILURE)) {
+ /*
+ If can't allocate correction, try to at least find out current
+ brk. It might be enough to proceed without failing.
+ */
+ correction = 0;
+ snd_brk = (char*)(MORECORE(0));
+ }
+ else if (snd_brk < brk) {
+ /*
+ If the second call gives noncontiguous space even though
+ it says it won't, the only course of action is to ignore
+ results of second call, and conservatively estimate where
+ the first call left us. Also set noncontiguous, so this
+ won't happen again, leaving at most one hole.
+
+ Note that this check is intrinsically incomplete. Because
+ MORECORE is allowed to give more space than we ask for,
+ there is no reliable way to detect a noncontiguity
+ producing a forward gap for the second call.
+ */
+ snd_brk = brk + size;
+ correction = 0;
+ set_noncontiguous(av);
+ }
+
+ }
+
+ /* handle non-contiguous cases */
+ else {
+ /* MORECORE/mmap must correctly align */
+ assert(aligned_OK(chunk2mem(brk)));
+
+ /* Find out current end of memory */
+ if (snd_brk == (char*)(MORECORE_FAILURE)) {
+ snd_brk = (char*)(MORECORE(0));
+ av->sbrked_mem += snd_brk - brk - size;
+ }
+ }
+
+ /* Adjust top based on results of second sbrk */
+ if (snd_brk != (char*)(MORECORE_FAILURE)) {
+ av->top = (mchunkptr)aligned_brk;
+ set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE);
+ av->sbrked_mem += correction;
+
+ /*
+ If not the first time through, we either have a
+ gap due to foreign sbrk or a non-contiguous region. Insert a
+ double fencepost at old_top to prevent consolidation with space
+ we don't own. These fenceposts are artificial chunks that are
+ marked as inuse and are in any case too small to use. We need
+ two to make sizes and alignments work out.
+ */
+
+ if (old_size != 0) {
+ /*
+ Shrink old_top to insert fenceposts, keeping size a
+ multiple of MALLOC_ALIGNMENT. We know there is at least
+ enough space in old_top to do this.
+ */
+ old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head(old_top, old_size | PREV_INUSE);
+
+ /*
+ Note that the following assignments completely overwrite
+ old_top when old_size was previously MINSIZE. This is
+ intentional. We need the fencepost, even if old_top otherwise gets
+ lost.
+ */
+ chunk_at_offset(old_top, old_size )->size =
+ SIZE_SZ|PREV_INUSE;
+
+ chunk_at_offset(old_top, old_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+
+ /*
+ If possible, release the rest, suppressing trimming.
+ */
+ if (old_size >= MINSIZE) {
+ INTERNAL_SIZE_T tt = av->trim_threshold;
+ av->trim_threshold = (INTERNAL_SIZE_T)(-1);
+ fREe(chunk2mem(old_top));
+ av->trim_threshold = tt;
+ }
+ }
+ }
+ }
+
+ /* Update statistics */
+ sum = av->sbrked_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_sbrked_mem))
+ av->max_sbrked_mem = sum;
+
+ sum += av->mmapped_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ check_malloc_state();
+
+ /* finally, do the allocation */
+
+ p = av->top;
+ size = chunksize(p);
+
+ /* check that one of the above allocation paths succeeded */
+ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(p, nb);
+ av->top = remainder;
+ set_head(p, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ check_malloced_chunk(p, nb);
+ return chunk2mem(p);
+ }
+
+ }
+
+ /* catch all failure paths */
+ MALLOC_FAILURE_ACTION;
+ return 0;
+}
+
+
+
+#ifndef MORECORE_CANNOT_TRIM
+/*
+ sYSTRIm is an inverse of sorts to sYSMALLOc. It gives memory back
+ to the system (via negative arguments to sbrk) if there is unused
+ memory at the `high' end of the malloc pool. It is called
+ automatically by free() when top space exceeds the trim
+ threshold. It is also called by the public malloc_trim routine. It
+ returns 1 if it actually released any memory, else 0.
+*/
+
+#if __STD_C
+static int sYSTRIm(size_t pad, mstate av)
+#else
+static int sYSTRIm(pad, av) size_t pad; mstate av;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ long released; /* Amount actually released */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by post-check sbrk call */
+ size_t pagesz;
+
+ pagesz = av->pagesize;
+ top_size = chunksize(av->top);
+
+ /* Release in pagesize units, keeping at least one page */
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra > 0) {
+
+ /*
+ Only proceed if end of memory is where we last set it.
+ This avoids problems if there were foreign sbrk calls.
+ */
+ current_brk = (char*)(MORECORE(0));
+ if (current_brk == (char*)(av->top) + top_size) {
+
+ /*
+ Attempt to release memory. We ignore MORECORE return value,
+ and instead call again to find out where new end of memory is.
+ This avoids problems if first call releases less than we asked,
+ of if failure somehow altered brk value. (We could still
+ encounter problems if it altered brk in some very bad way,
+ but the only thing we can do is adjust anyway, which will cause
+ some downstream failure.)
+ */
+
+ MORECORE(-extra);
+ new_brk = (char*)(MORECORE(0));
+
+ if (new_brk != (char*)MORECORE_FAILURE) {
+ released = (long)(current_brk - new_brk);
+
+ if (released != 0) {
+ /* Success. Adjust top. */
+ av->sbrked_mem -= released;
+ set_head(av->top, (top_size - released) | PREV_INUSE);
+ check_malloc_state();
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif /*MORECORE_CANNOT_TRIM*/
+
+/*
+ ------------------------------ malloc ------------------------------
+*/
+
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+ Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T nb; /* normalized request size */
+ unsigned int idx; /* associated bin index */
+ mbinptr bin; /* associated bin */
+ mfastbinptr* fb; /* associated fastbin */
+
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T size; /* its size */
+ int victim_index; /* its bin index */
+
+ mchunkptr remainder; /* remainder from a split */
+ CHUNK_SIZE_T remainder_size; /* its size */
+
+ unsigned int block; /* bit map traverser */
+ unsigned int bit; /* bit map traverser */
+ unsigned int map; /* current word of binmap */
+
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+
+ /*
+ Convert request size to internal form by adding SIZE_SZ bytes
+ overhead plus possibly more to obtain necessary alignment and/or
+ to obtain a size of at least MINSIZE, the smallest allocatable
+ size. Also, checked_request2size traps (returning 0) request sizes
+ that are so large that they wrap around zero when padded and
+ aligned.
+ */
+
+ checked_request2size(bytes, nb);
+
+ /*
+ Bypass search if no frees yet
+ */
+ if (!have_anychunks(av)) {
+ if (av->max_fast == 0) /* initialization check */
+ malloc_consolidate(av);
+ goto use_top;
+ }
+
+ /*
+ If the size qualifies as a fastbin, first check corresponding bin.
+ */
+
+ if ((CHUNK_SIZE_T)(nb) <= (CHUNK_SIZE_T)(av->max_fast)) {
+ fb = &(av->fastbins[(fastbin_index(nb))]);
+ if ( (victim = *fb) != 0) {
+ *fb = victim->fd;
+ check_remalloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ /*
+ If a small request, check regular bin. Since these "smallbins"
+ hold one size each, no searching within bins is necessary.
+ (For a large request, we need to wait until unsorted chunks are
+ processed to find best fit. But for small ones, fits are exact
+ anyway, so we can check now, which is faster.)
+ */
+
+ if (in_smallbin_range(nb)) {
+ idx = smallbin_index(nb);
+ bin = bin_at(av,idx);
+
+ if ( (victim = last(bin)) != bin) {
+ bck = victim->bk;
+ set_inuse_bit_at_offset(victim, nb);
+ bin->bk = bck;
+ bck->fd = bin;
+
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ /*
+ If this is a large request, consolidate fastbins before continuing.
+ While it might look excessive to kill all fastbins before
+ even seeing if there is space available, this avoids
+ fragmentation problems normally associated with fastbins.
+ Also, in practice, programs tend to have runs of either small or
+ large requests, but less often mixtures, so consolidation is not
+ invoked all that often in most programs. And the programs that
+ it is called frequently in otherwise tend to fragment.
+ */
+
+ else {
+ idx = largebin_index(nb);
+ if (have_fastchunks(av))
+ malloc_consolidate(av);
+ }
+
+ /*
+ Process recently freed or remaindered chunks, taking one only if
+ it is exact fit, or, if this a small request, the chunk is remainder from
+ the most recent non-exact fit. Place other traversed chunks in
+ bins. Note that this step is the only place in any routine where
+ chunks are placed in bins.
+ */
+
+ while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {
+ bck = victim->bk;
+ size = chunksize(victim);
+
+ /*
+ If a small request, try to use last remainder if it is the
+ only chunk in unsorted bin. This helps promote locality for
+ runs of consecutive small requests. This is the only
+ exception to best-fit, and applies only when there is
+ no exact fit for a small chunk.
+ */
+
+ if (in_smallbin_range(nb) &&
+ bck == unsorted_chunks(av) &&
+ victim == av->last_remainder &&
+ (CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE)) {
+
+ /* split and reattach remainder */
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(victim, nb);
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ av->last_remainder = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* remove from unsorted list */
+ unsorted_chunks(av)->bk = bck;
+ bck->fd = unsorted_chunks(av);
+
+ /* Take now instead of binning if exact fit */
+
+ if (size == nb) {
+ set_inuse_bit_at_offset(victim, size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* place chunk in bin */
+
+ if (in_smallbin_range(size)) {
+ victim_index = smallbin_index(size);
+ bck = bin_at(av, victim_index);
+ fwd = bck->fd;
+ }
+ else {
+ victim_index = largebin_index(size);
+ bck = bin_at(av, victim_index);
+ fwd = bck->fd;
+
+ if (fwd != bck) {
+ /* if smaller than smallest, place first */
+ if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(bck->bk->size)) {
+ fwd = bck;
+ bck = bck->bk;
+ }
+ else if ((CHUNK_SIZE_T)(size) >=
+ (CHUNK_SIZE_T)(FIRST_SORTED_BIN_SIZE)) {
+
+ /* maintain large bins in sorted order */
+ size |= PREV_INUSE; /* Or with inuse bit to speed comparisons */
+ while ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(fwd->size))
+ fwd = fwd->fd;
+ bck = fwd->bk;
+ }
+ }
+ }
+
+ mark_bin(av, victim_index);
+ victim->bk = bck;
+ victim->fd = fwd;
+ fwd->bk = victim;
+ bck->fd = victim;
+ }
+
+ /*
+ If a large request, scan through the chunks of current bin to
+ find one that fits. (This will be the smallest that fits unless
+ FIRST_SORTED_BIN_SIZE has been changed from default.) This is
+ the only step where an unbounded number of chunks might be
+ scanned without doing anything useful with them. However the
+ lists tend to be short.
+ */
+
+ if (!in_smallbin_range(nb)) {
+ bin = bin_at(av, idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk) {
+ size = chunksize(victim);
+
+ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb)) {
+ remainder_size = size - nb;
+ unlink(victim, bck, fwd);
+
+ /* Exhaust */
+ if (remainder_size < MINSIZE) {
+ set_inuse_bit_at_offset(victim, size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ /* Split */
+ else {
+ remainder = chunk_at_offset(victim, nb);
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+ }
+ }
+
+ /*
+ Search for a chunk by scanning bins, starting with next largest
+ bin. This search is strictly by best-fit; i.e., the smallest
+ (with ties going to approximately the least recently used) chunk
+ that fits is selected.
+
+ The bitmap avoids needing to check that most blocks are nonempty.
+ */
+
+ ++idx;
+ bin = bin_at(av,idx);
+ block = idx2block(idx);
+ map = av->binmap[block];
+ bit = idx2bit(idx);
+
+ for (;;) {
+
+ /* Skip rest of block if there are no more set bits in this block. */
+ if (bit > map || bit == 0) {
+ do {
+ if (++block >= BINMAPSIZE) /* out of bins */
+ goto use_top;
+ } while ( (map = av->binmap[block]) == 0);
+
+ bin = bin_at(av, (block << BINMAPSHIFT));
+ bit = 1;
+ }
+
+ /* Advance to bin with set bit. There must be one. */
+ while ((bit & map) == 0) {
+ bin = next_bin(bin);
+ bit <<= 1;
+ assert(bit != 0);
+ }
+
+ /* Inspect the bin. It is likely to be non-empty */
+ victim = last(bin);
+
+ /* If a false alarm (empty bin), clear the bit. */
+ if (victim == bin) {
+ av->binmap[block] = map &= ~bit; /* Write through */
+ bin = next_bin(bin);
+ bit <<= 1;
+ }
+
+ else {
+ size = chunksize(victim);
+
+ /* We know the first chunk in this bin is big enough to use. */
+ assert((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb));
+
+ remainder_size = size - nb;
+
+ /* unlink */
+ bck = victim->bk;
+ bin->bk = bck;
+ bck->fd = bin;
+
+ /* Exhaust */
+ if (remainder_size < MINSIZE) {
+ set_inuse_bit_at_offset(victim, size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Split */
+ else {
+ remainder = chunk_at_offset(victim, nb);
+
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+ /* advertise as last remainder */
+ if (in_smallbin_range(nb))
+ av->last_remainder = remainder;
+
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+ }
+
+ use_top:
+ /*
+ If large enough, split off the chunk bordering the end of memory
+ (held in av->top). Note that this is in accord with the best-fit
+ search rule. In effect, av->top is treated as larger (and thus
+ less well fitting) than any other available chunk since it can
+ be extended to be as large as necessary (up to system
+ limitations).
+
+ We require that av->top always exists (i.e., has size >=
+ MINSIZE) after initialization, so if it would otherwise be
+ exhuasted by current request, it is replenished. (The main
+ reason for ensuring it exists is that we may need MINSIZE space
+ to put in fenceposts in sysmalloc.)
+ */
+
+ victim = av->top;
+ size = chunksize(victim);
+
+ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(victim, nb);
+ av->top = remainder;
+ set_head(victim, nb | PREV_INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /*
+ If no space in top, relay to handle system-dependent cases
+ */
+ return sYSMALLOc(nb, av);
+}
+
+/*
+ ------------------------------ free ------------------------------
+*/
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T size; /* its size */
+ mfastbinptr* fb; /* associated fastbin */
+ mchunkptr nextchunk; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsize; /* its size */
+ int nextinuse; /* true if nextchunk is used */
+ INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+ /* free(0) has no effect */
+ if (mem != 0) {
+ p = mem2chunk(mem);
+ size = chunksize(p);
+
+ check_inuse_chunk(p);
+
+ /*
+ If eligible, place chunk on a fastbin so it can be found
+ and used quickly in malloc.
+ */
+
+ if ((CHUNK_SIZE_T)(size) <= (CHUNK_SIZE_T)(av->max_fast)
+
+#if TRIM_FASTBINS
+ /*
+ If TRIM_FASTBINS set, don't place chunks
+ bordering top into fastbins
+ */
+ && (chunk_at_offset(p, size) != av->top)
+#endif
+ ) {
+
+ set_fastchunks(av);
+ fb = &(av->fastbins[fastbin_index(size)]);
+ p->fd = *fb;
+ *fb = p;
+ }
+
+ /*
+ Consolidate other non-mmapped chunks as they arrive.
+ */
+
+ else if (!chunk_is_mmapped(p)) {
+ set_anychunks(av);
+
+ nextchunk = chunk_at_offset(p, size);
+ nextsize = chunksize(nextchunk);
+
+ /* consolidate backward */
+ if (!prev_inuse(p)) {
+ prevsize = p->prev_size;
+ size += prevsize;
+ p = chunk_at_offset(p, -((long) prevsize));
+ unlink(p, bck, fwd);
+ }
+
+ if (nextchunk != av->top) {
+ /* get and clear inuse bit */
+ nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+ set_head(nextchunk, nextsize);
+
+ /* consolidate forward */
+ if (!nextinuse) {
+ unlink(nextchunk, bck, fwd);
+ size += nextsize;
+ }
+
+ /*
+ Place the chunk in unsorted chunk list. Chunks are
+ not placed into regular bins until after they have
+ been given one chance to be used in malloc.
+ */
+
+ bck = unsorted_chunks(av);
+ fwd = bck->fd;
+ p->bk = bck;
+ p->fd = fwd;
+ bck->fd = p;
+ fwd->bk = p;
+
+ set_head(p, size | PREV_INUSE);
+ set_foot(p, size);
+
+ check_free_chunk(p);
+ }
+
+ /*
+ If the chunk borders the current high end of memory,
+ consolidate into top
+ */
+
+ else {
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ av->top = p;
+ check_chunk(p);
+ }
+
+ /*
+ If freeing a large space, consolidate possibly-surrounding
+ chunks. Then, if the total unused topmost memory exceeds trim
+ threshold, ask malloc_trim to reduce top.
+
+ Unless max_fast is 0, we don't know if there are fastbins
+ bordering top, so we cannot tell for sure whether threshold
+ has been reached unless fastbins are consolidated. But we
+ don't want to consolidate on each free. As a compromise,
+ consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
+ is reached.
+ */
+
+ if ((CHUNK_SIZE_T)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
+ if (have_fastchunks(av))
+ malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM
+ if ((CHUNK_SIZE_T)(chunksize(av->top)) >=
+ (CHUNK_SIZE_T)(av->trim_threshold))
+ sYSTRIm(av->top_pad, av);
+#endif
+ }
+
+ }
+ /*
+ If the chunk was allocated via mmap, release via munmap()
+ Note that if HAVE_MMAP is false but chunk_is_mmapped is
+ true, then user must have overwritten memory. There's nothing
+ we can do to catch this error unless DEBUG is set, in which case
+ check_inuse_chunk (above) will have triggered error.
+ */
+
+ else {
+#if HAVE_MMAP
+ int ret;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ av->n_mmaps--;
+ av->mmapped_mem -= (size + offset);
+ ret = munmap((char*)p - offset, size + offset);
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+#endif
+ }
+ }
+}
+
+/*
+ ------------------------- malloc_consolidate -------------------------
+
+ malloc_consolidate is a specialized version of free() that tears
+ down chunks held in fastbins. Free itself cannot be used for this
+ purpose since, among other things, it might place chunks back onto
+ fastbins. So, instead, we need to use a minor variant of the same
+ code.
+
+ Also, because this routine needs to be called the first time through
+ malloc anyway, it turns out to be the perfect place to trigger
+ initialization code.
+*/
+
+#if __STD_C
+static void malloc_consolidate(mstate av)
+#else
+static void malloc_consolidate(av) mstate av;
+#endif
+{
+ mfastbinptr* fb; /* current fastbin being consolidated */
+ mfastbinptr* maxfb; /* last fastbin (for loop control) */
+ mchunkptr p; /* current chunk being consolidated */
+ mchunkptr nextp; /* next chunk to consolidate */
+ mchunkptr unsorted_bin; /* bin header */
+ mchunkptr first_unsorted; /* chunk to link to */
+
+ /* These have same use as in free() */
+ mchunkptr nextchunk;
+ INTERNAL_SIZE_T size;
+ INTERNAL_SIZE_T nextsize;
+ INTERNAL_SIZE_T prevsize;
+ int nextinuse;
+ mchunkptr bck;
+ mchunkptr fwd;
+
+ /*
+ If max_fast is 0, we know that av hasn't
+ yet been initialized, in which case do so below
+ */
+
+ if (av->max_fast != 0) {
+ clear_fastchunks(av);
+
+ unsorted_bin = unsorted_chunks(av);
+
+ /*
+ Remove each chunk from fast bin and consolidate it, placing it
+ then in unsorted bin. Among other reasons for doing this,
+ placing in unsorted bin avoids needing to calculate actual bins
+ until malloc is sure that chunks aren't immediately going to be
+ reused anyway.
+ */
+
+ maxfb = &(av->fastbins[fastbin_index(av->max_fast)]);
+ fb = &(av->fastbins[0]);
+ do {
+ if ( (p = *fb) != 0) {
+ *fb = 0;
+
+ do {
+ check_inuse_chunk(p);
+ nextp = p->fd;
+
+ /* Slightly streamlined version of consolidation code in free() */
+ size = p->size & ~PREV_INUSE;
+ nextchunk = chunk_at_offset(p, size);
+ nextsize = chunksize(nextchunk);
+
+ if (!prev_inuse(p)) {
+ prevsize = p->prev_size;
+ size += prevsize;
+ p = chunk_at_offset(p, -((long) prevsize));
+ unlink(p, bck, fwd);
+ }
+
+ if (nextchunk != av->top) {
+ nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+ set_head(nextchunk, nextsize);
+
+ if (!nextinuse) {
+ size += nextsize;
+ unlink(nextchunk, bck, fwd);
+ }
+
+ first_unsorted = unsorted_bin->fd;
+ unsorted_bin->fd = p;
+ first_unsorted->bk = p;
+
+ set_head(p, size | PREV_INUSE);
+ p->bk = unsorted_bin;
+ p->fd = first_unsorted;
+ set_foot(p, size);
+ }
+
+ else {
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ av->top = p;
+ }
+
+ } while ( (p = nextp) != 0);
+
+ }
+ } while (fb++ != maxfb);
+ }
+ else {
+ malloc_init_state(av);
+ check_malloc_state();
+ }
+}
+
+/*
+ ------------------------------ realloc ------------------------------
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+
+ mchunkptr remainder; /* extra space at end of newp */
+ CHUNK_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+ CHUNK_SIZE_T copysize; /* bytes to copy */
+ unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */
+ INTERNAL_SIZE_T* s; /* copy source */
+ INTERNAL_SIZE_T* d; /* copy destination */
+
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ fREe(oldmem);
+ return 0;
+ }
+#endif
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ checked_request2size(bytes, nb);
+
+ oldp = mem2chunk(oldmem);
+ oldsize = chunksize(oldp);
+
+ check_inuse_chunk(oldp);
+
+ if (!chunk_is_mmapped(oldp)) {
+
+ if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb)) {
+ /* already big enough; split below */
+ newp = oldp;
+ newsize = oldsize;
+ }
+
+ else {
+ next = chunk_at_offset(oldp, oldsize);
+
+ /* Try to expand forward into top */
+ if (next == av->top &&
+ (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >=
+ (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ set_head_size(oldp, nb);
+ av->top = chunk_at_offset(oldp, nb);
+ set_head(av->top, (newsize - nb) | PREV_INUSE);
+ return chunk2mem(oldp);
+ }
+
+ /* Try to expand forward into next chunk; split off remainder below */
+ else if (next != av->top &&
+ !inuse(next) &&
+ (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >=
+ (CHUNK_SIZE_T)(nb)) {
+ newp = oldp;
+ unlink(next, bck, fwd);
+ }
+
+ /* allocate, copy, free */
+ else {
+ newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+ if (newmem == 0)
+ return 0; /* propagate failure */
+
+ newp = mem2chunk(newmem);
+ newsize = chunksize(newp);
+
+ /*
+ Avoid copy if newp is next chunk after oldp.
+ */
+ if (newp == next) {
+ newsize += oldsize;
+ newp = oldp;
+ }
+ else {
+ /*
+ Unroll copy of <= 36 bytes (72 if 8byte sizes)
+ We know that contents have an odd number of
+ INTERNAL_SIZE_T-sized words; minimally 3.
+ */
+
+ copysize = oldsize - SIZE_SZ;
+ s = (INTERNAL_SIZE_T*)(oldmem);
+ d = (INTERNAL_SIZE_T*)(newmem);
+ ncopies = copysize / sizeof(INTERNAL_SIZE_T);
+ assert(ncopies >= 3);
+
+ if (ncopies > 9)
+ MALLOC_COPY(d, s, copysize);
+
+ else {
+ *(d+0) = *(s+0);
+ *(d+1) = *(s+1);
+ *(d+2) = *(s+2);
+ if (ncopies > 4) {
+ *(d+3) = *(s+3);
+ *(d+4) = *(s+4);
+ if (ncopies > 6) {
+ *(d+5) = *(s+5);
+ *(d+6) = *(s+6);
+ if (ncopies > 8) {
+ *(d+7) = *(s+7);
+ *(d+8) = *(s+8);
+ }
+ }
+ }
+ }
+
+ fREe(oldmem);
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+ }
+ }
+ }
+
+ /* If possible, free extra space in old or extended chunk */
+
+ assert((CHUNK_SIZE_T)(newsize) >= (CHUNK_SIZE_T)(nb));
+
+ remainder_size = newsize - nb;
+
+ if (remainder_size < MINSIZE) { /* not enough extra to split off */
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+ else { /* split remainder */
+ remainder = chunk_at_offset(newp, nb);
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ /* Mark remainder as inuse so free() won't complain */
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ fREe(chunk2mem(remainder));
+ }
+
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+ }
+
+ /*
+ Handle mmap cases
+ */
+
+ else {
+#if HAVE_MMAP
+
+#if HAVE_MREMAP
+ INTERNAL_SIZE_T offset = oldp->prev_size;
+ size_t pagemask = av->pagesize - 1;
+ char *cp;
+ CHUNK_SIZE_T sum;
+
+ /* Note the extra SIZE_SZ overhead */
+ newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask;
+
+ /* don't need to remap if still within same page */
+ if (oldsize == newsize - offset)
+ return oldmem;
+
+ cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1);
+
+ if (cp != (char*)MORECORE_FAILURE) {
+
+ newp = (mchunkptr)(cp + offset);
+ set_head(newp, (newsize - offset)|IS_MMAPPED);
+
+ assert(aligned_OK(chunk2mem(newp)));
+ assert((newp->prev_size == offset));
+
+ /* update statistics */
+ sum = av->mmapped_mem += newsize - oldsize;
+ if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem))
+ av->max_mmapped_mem = sum;
+ sum += av->sbrked_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* Note the extra SIZE_SZ overhead. */
+ if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb + SIZE_SZ))
+ newmem = oldmem; /* do nothing */
+ else {
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+ if (newmem != 0) {
+ MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ fREe(oldmem);
+ }
+ }
+ return newmem;
+
+#else
+ /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */
+ check_malloc_state();
+ MALLOC_FAILURE_ACTION;
+ return 0;
+#endif
+ }
+}
+
+/*
+ ------------------------------ memalign ------------------------------
+*/
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space before alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ CHUNK_SIZE_T remainder_size; /* its size */
+ INTERNAL_SIZE_T size;
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Make sure alignment is power of 2 (in case MINSIZE is not). */
+ if ((alignment & (alignment - 1)) != 0) {
+ size_t a = MALLOC_ALIGNMENT * 2;
+ while ((CHUNK_SIZE_T)a < (CHUNK_SIZE_T)alignment) a <<= 1;
+ alignment = a;
+ }
+
+ checked_request2size(bytes, nb);
+
+ /*
+ Strategy: find a spot within that chunk that meets the alignment
+ request, and then possibly free the leading and trailing space.
+ */
+
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((PTR_UINT)(m)) % alignment) != 0) { /* misaligned */
+
+ /*
+ Find an aligned spot inside chunk. Since we need to give back
+ leading space in a chunk of at least MINSIZE, if the first
+ calculation places us at a spot with less than MINSIZE leader,
+ we can move to the next aligned spot -- we've allocated enough
+ total room so that this is always possible.
+ */
+
+ brk = (char*)mem2chunk((PTR_UINT)(((PTR_UINT)(m + alignment - 1)) &
+ -((signed long) alignment)));
+ if ((CHUNK_SIZE_T)(brk - (char*)(p)) < MINSIZE)
+ brk += alignment;
+
+ newp = (mchunkptr)brk;
+ leadsize = brk - (char*)(p);
+ newsize = chunksize(p) - leadsize;
+
+ /* For mmapped chunks, just adjust offset */
+ if (chunk_is_mmapped(p)) {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ return chunk2mem(newp);
+ }
+
+ /* Otherwise, give back leader, use the rest */
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb &&
+ (((PTR_UINT)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+ if (!chunk_is_mmapped(p)) {
+ size = chunksize(p);
+ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ fREe(chunk2mem(remainder));
+ }
+ }
+
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+}
+
+/*
+ ------------------------------ calloc ------------------------------
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n_elements, size_t elem_size)
+#else
+Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ CHUNK_SIZE_T clearsize;
+ CHUNK_SIZE_T nclears;
+ INTERNAL_SIZE_T* d;
+
+ Void_t* mem = mALLOc(n_elements * elem_size);
+
+ if (mem != 0) {
+ p = mem2chunk(mem);
+
+ if (!chunk_is_mmapped(p))
+ {
+ /*
+ Unroll clear of <= 36 bytes (72 if 8byte sizes)
+ We know that contents have an odd number of
+ INTERNAL_SIZE_T-sized words; minimally 3.
+ */
+
+ d = (INTERNAL_SIZE_T*)mem;
+ clearsize = chunksize(p) - SIZE_SZ;
+ nclears = clearsize / sizeof(INTERNAL_SIZE_T);
+ assert(nclears >= 3);
+
+ if (nclears > 9)
+ MALLOC_ZERO(d, clearsize);
+
+ else {
+ *(d+0) = 0;
+ *(d+1) = 0;
+ *(d+2) = 0;
+ if (nclears > 4) {
+ *(d+3) = 0;
+ *(d+4) = 0;
+ if (nclears > 6) {
+ *(d+5) = 0;
+ *(d+6) = 0;
+ if (nclears > 8) {
+ *(d+7) = 0;
+ *(d+8) = 0;
+ }
+ }
+ }
+ }
+ }
+#if ! MMAP_CLEARS
+ else
+ {
+ d = (INTERNAL_SIZE_T*)mem;
+ /*
+ Note the additional SIZE_SZ
+ */
+ clearsize = chunksize(p) - 2*SIZE_SZ;
+ MALLOC_ZERO(d, clearsize);
+ }
+#endif
+ }
+ return mem;
+}
+
+/*
+ ------------------------------ cfree ------------------------------
+*/
+
+#if __STD_C
+void cFREe(Void_t *mem)
+#else
+void cFREe(mem) Void_t *mem;
+#endif
+{
+ fREe(mem);
+}
+
+#ifdef NEED_INDEPENDENT
+/*
+ ------------------------- independent_calloc -------------------------
+*/
+
+#if __STD_C
+Void_t** iCALLOc(size_t n_elements, size_t elem_size, Void_t* chunks[])
+#else
+Void_t** iCALLOc(n_elements, elem_size, chunks) size_t n_elements; size_t elem_size; Void_t* chunks[];
+#endif
+{
+ size_t sz = elem_size; /* serves as 1-element array */
+ /* opts arg of 3 means all elements are same size, and should be cleared */
+ return iALLOc(n_elements, &sz, 3, chunks);
+}
+
+/*
+ ------------------------- independent_comalloc -------------------------
+*/
+
+#if __STD_C
+Void_t** iCOMALLOc(size_t n_elements, size_t sizes[], Void_t* chunks[])
+#else
+Void_t** iCOMALLOc(n_elements, sizes, chunks) size_t n_elements; size_t sizes[]; Void_t* chunks[];
+#endif
+{
+ return iALLOc(n_elements, sizes, 0, chunks);
+}
+
+/*
+ ------------------------------ ialloc ------------------------------
+ ialloc provides common support for independent_X routines, handling all of
+ the combinations that can result.
+
+ The opts arg has:
+ bit 0 set if all elements are same size (using sizes[0])
+ bit 1 set if elements should be zeroed
+*/
+
+
+#if __STD_C
+static Void_t** iALLOc(size_t n_elements,
+ size_t* sizes,
+ int opts,
+ Void_t* chunks[])
+#else
+static Void_t** iALLOc(n_elements, sizes, opts, chunks) size_t n_elements; size_t* sizes; int opts; Void_t* chunks[];
+#endif
+{
+ mstate av = get_malloc_state();
+ INTERNAL_SIZE_T element_size; /* chunksize of each element, if all same */
+ INTERNAL_SIZE_T contents_size; /* total size of elements */
+ INTERNAL_SIZE_T array_size; /* request size of pointer array */
+ Void_t* mem; /* malloced aggregate space */
+ mchunkptr p; /* corresponding chunk */
+ INTERNAL_SIZE_T remainder_size; /* remaining bytes while splitting */
+ Void_t** marray; /* either "chunks" or malloced ptr array */
+ mchunkptr array_chunk; /* chunk for malloced ptr array */
+ int mmx; /* to disable mmap */
+ INTERNAL_SIZE_T size;
+ size_t i;
+
+ /* Ensure initialization */
+ if (av->max_fast == 0) malloc_consolidate(av);
+
+ /* compute array length, if needed */
+ if (chunks != 0) {
+ if (n_elements == 0)
+ return chunks; /* nothing to do */
+ marray = chunks;
+ array_size = 0;
+ }
+ else {
+ /* if empty req, must still return chunk representing empty array */
+ if (n_elements == 0)
+ return (Void_t**) mALLOc(0);
+ marray = 0;
+ array_size = request2size(n_elements * (sizeof(Void_t*)));
+ }
+
+ /* compute total element size */
+ if (opts & 0x1) { /* all-same-size */
+ element_size = request2size(*sizes);
+ contents_size = n_elements * element_size;
+ }
+ else { /* add up all the sizes */
+ element_size = 0;
+ contents_size = 0;
+ for (i = 0; i != n_elements; ++i)
+ contents_size += request2size(sizes[i]);
+ }
+
+ /* subtract out alignment bytes from total to minimize overallocation */
+ size = contents_size + array_size - MALLOC_ALIGN_MASK;
+
+ /*
+ Allocate the aggregate chunk.
+ But first disable mmap so malloc won't use it, since
+ we would not be able to later free/realloc space internal
+ to a segregated mmap region.
+ */
+ mmx = av->n_mmaps_max; /* disable mmap */
+ av->n_mmaps_max = 0;
+ mem = mALLOc(size);
+ av->n_mmaps_max = mmx; /* reset mmap */
+ if (mem == 0)
+ return 0;
+
+ p = mem2chunk(mem);
+ assert(!chunk_is_mmapped(p));
+ remainder_size = chunksize(p);
+
+ if (opts & 0x2) { /* optionally clear the elements */
+ MALLOC_ZERO(mem, remainder_size - SIZE_SZ - array_size);
+ }
+
+ /* If not provided, allocate the pointer array as final part of chunk */
+ if (marray == 0) {
+ array_chunk = chunk_at_offset(p, contents_size);
+ marray = (Void_t**) (chunk2mem(array_chunk));
+ set_head(array_chunk, (remainder_size - contents_size) | PREV_INUSE);
+ remainder_size = contents_size;
+ }
+
+ /* split out elements */
+ for (i = 0; ; ++i) {
+ marray[i] = chunk2mem(p);
+ if (i != n_elements-1) {
+ if (element_size != 0)
+ size = element_size;
+ else
+ size = request2size(sizes[i]);
+ remainder_size -= size;
+ set_head(p, size | PREV_INUSE);
+ p = chunk_at_offset(p, size);
+ }
+ else { /* the final element absorbs any overallocation slop */
+ set_head(p, remainder_size | PREV_INUSE);
+ break;
+ }
+ }
+
+#if DEBUG
+ if (marray != chunks) {
+ /* final element must have exactly exhausted chunk */
+ if (element_size != 0)
+ assert(remainder_size == element_size);
+ else
+ assert(remainder_size == request2size(sizes[i]));
+ check_inuse_chunk(mem2chunk(marray));
+ }
+
+ for (i = 0; i != n_elements; ++i)
+ check_inuse_chunk(mem2chunk(marray[i]));
+#endif
+
+ return marray;
+}
+#endif /* NEED_INDEPENDENT */
+
+
+/*
+ ------------------------------ valloc ------------------------------
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ /* Ensure initialization */
+ mstate av = get_malloc_state();
+ if (av->max_fast == 0) malloc_consolidate(av);
+ return mEMALIGn(av->pagesize, bytes);
+}
+
+#ifdef NEED_PVALLOC
+/*
+ ------------------------------ pvalloc ------------------------------
+*/
+
+
+#if __STD_C
+Void_t* pVALLOc(size_t bytes)
+#else
+Void_t* pVALLOc(bytes) size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+ size_t pagesz;
+
+ /* Ensure initialization */
+ if (av->max_fast == 0) malloc_consolidate(av);
+ pagesz = av->pagesize;
+ return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
+}
+#endif /*NEED_PVALLOC*/
+
+
+/*
+ ------------------------------ malloc_trim ------------------------------
+*/
+
+#if __STD_C
+int mTRIm(size_t pad)
+#else
+int mTRIm(pad) size_t pad;
+#endif
+{
+ mstate av = get_malloc_state();
+ /* Ensure initialization/consolidation */
+ malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM
+ return sYSTRIm(pad, av);
+#else
+ return 0;
+#endif
+}
+
+
+/*
+ ------------------------- malloc_usable_size -------------------------
+*/
+
+#if __STD_C
+size_t mUSABLe(Void_t* mem)
+#else
+size_t mUSABLe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem != 0) {
+ p = mem2chunk(mem);
+ if (chunk_is_mmapped(p))
+ return chunksize(p) - 2*SIZE_SZ;
+ else if (inuse(p))
+ return chunksize(p) - SIZE_SZ;
+ }
+ return 0;
+}
+
+/*
+ ------------------------------ mallinfo ------------------------------
+*/
+
+struct mallinfo mALLINFo()
+{
+ mstate av = get_malloc_state();
+ struct mallinfo mi;
+ unsigned i;
+ mbinptr b;
+ mchunkptr p;
+ INTERNAL_SIZE_T avail;
+ INTERNAL_SIZE_T fastavail;
+ int nblocks;
+ int nfastblocks;
+
+ /* Ensure initialization */
+ if (av->top == 0) malloc_consolidate(av);
+
+ check_malloc_state();
+
+ /* Account for top */
+ avail = chunksize(av->top);
+ nblocks = 1; /* top always exists */
+
+ /* traverse fastbins */
+ nfastblocks = 0;
+ fastavail = 0;
+
+ for (i = 0; i < NFASTBINS; ++i) {
+ for (p = av->fastbins[i]; p != 0; p = p->fd) {
+ ++nfastblocks;
+ fastavail += chunksize(p);
+ }
+ }
+
+ avail += fastavail;
+
+ /* traverse regular bins */
+ for (i = 1; i < NBINS; ++i) {
+ b = bin_at(av, i);
+ for (p = last(b); p != b; p = p->bk) {
+ ++nblocks;
+ avail += chunksize(p);
+ }
+ }
+
+ mi.smblks = nfastblocks;
+ mi.ordblks = nblocks;
+ mi.fordblks = avail;
+ mi.uordblks = av->sbrked_mem - avail;
+ mi.arena = av->sbrked_mem;
+ mi.hblks = av->n_mmaps;
+ mi.hblkhd = av->mmapped_mem;
+ mi.fsmblks = fastavail;
+ mi.keepcost = chunksize(av->top);
+ mi.usmblks = av->max_total_mem;
+ return mi;
+}
+
+/*
+ ------------------------------ malloc_stats ------------------------------
+*/
+
+void mSTATs()
+{
+ struct mallinfo mi = mALLINFo();
+
+#ifdef WIN32
+ {
+ CHUNK_SIZE_T free, reserved, committed;
+ vminfo (&free, &reserved, &committed);
+ fprintf(stderr, "free bytes = %10lu\n",
+ free);
+ fprintf(stderr, "reserved bytes = %10lu\n",
+ reserved);
+ fprintf(stderr, "committed bytes = %10lu\n",
+ committed);
+ }
+#endif
+
+
+ fprintf(stderr, "max system bytes = %10lu\n",
+ (CHUNK_SIZE_T)(mi.usmblks));
+ fprintf(stderr, "system bytes = %10lu\n",
+ (CHUNK_SIZE_T)(mi.arena + mi.hblkhd));
+ fprintf(stderr, "in use bytes = %10lu\n",
+ (CHUNK_SIZE_T)(mi.uordblks + mi.hblkhd));
+
+#ifdef WIN32
+ {
+ CHUNK_SIZE_T kernel, user;
+ if (cpuinfo (TRUE, &kernel, &user)) {
+ fprintf(stderr, "kernel ms = %10lu\n",
+ kernel);
+ fprintf(stderr, "user ms = %10lu\n",
+ user);
+ }
+ }
+#endif
+}
+
+
+/*
+ ------------------------------ mallopt ------------------------------
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ mstate av = get_malloc_state();
+ /* Ensure initialization/consolidation */
+ malloc_consolidate(av);
+
+ switch(param_number) {
+ case M_MXFAST:
+ if (value >= 0 && value <= MAX_FAST_SIZE) {
+ set_max_fast(av, value);
+ return 1;
+ }
+ else
+ return 0;
+
+ case M_TRIM_THRESHOLD:
+ av->trim_threshold = value;
+ return 1;
+
+ case M_TOP_PAD:
+ av->top_pad = value;
+ return 1;
+
+ case M_MMAP_THRESHOLD:
+ av->mmap_threshold = value;
+ return 1;
+
+ case M_MMAP_MAX:
+#if !HAVE_MMAP
+ if (value != 0)
+ return 0;
+#endif
+ av->n_mmaps_max = value;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ -------------------- Alternative MORECORE functions --------------------
+*/
+
+
+/*
+ General Requirements for MORECORE.
+
+ The MORECORE function must have the following properties:
+
+ If MORECORE_CONTIGUOUS is false:
+
+ * MORECORE must allocate in multiples of pagesize. It will
+ only be called with arguments that are multiples of pagesize.
+
+ * MORECORE(0) must return an address that is at least
+ MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.)
+
+ else (i.e. If MORECORE_CONTIGUOUS is true):
+
+ * Consecutive calls to MORECORE with positive arguments
+ return increasing addresses, indicating that space has been
+ contiguously extended.
+
+ * MORECORE need not allocate in multiples of pagesize.
+ Calls to MORECORE need not have args of multiples of pagesize.
+
+ * MORECORE need not page-align.
+
+ In either case:
+
+ * MORECORE may allocate more memory than requested. (Or even less,
+ but this will generally result in a malloc failure.)
+
+ * MORECORE must not allocate memory when given argument zero, but
+ instead return one past the end address of memory from previous
+ nonzero call. This malloc does NOT call MORECORE(0)
+ until at least one call with positive arguments is made, so
+ the initial value returned is not important.
+
+ * Even though consecutive calls to MORECORE need not return contiguous
+ addresses, it must be OK for malloc'ed chunks to span multiple
+ regions in those cases where they do happen to be contiguous.
+
+ * MORECORE need not handle negative arguments -- it may instead
+ just return MORECORE_FAILURE when given negative arguments.
+ Negative arguments are always multiples of pagesize. MORECORE
+ must not misinterpret negative args as large positive unsigned
+ args. You can suppress all such calls from even occurring by defining
+ MORECORE_CANNOT_TRIM,
+
+ There is some variation across systems about the type of the
+ argument to sbrk/MORECORE. If size_t is unsigned, then it cannot
+ actually be size_t, because sbrk supports negative args, so it is
+ normally the signed type of the same width as size_t (sometimes
+ declared as "intptr_t", and sometimes "ptrdiff_t"). It doesn't much
+ matter though. Internally, we use "long" as arguments, which should
+ work across all reasonable possibilities.
+
+ Additionally, if MORECORE ever returns failure for a positive
+ request, and HAVE_MMAP is true, then mmap is used as a noncontiguous
+ system allocator. This is a useful backup strategy for systems with
+ holes in address spaces -- in this case sbrk cannot contiguously
+ expand the heap, but mmap may be able to map noncontiguous space.
+
+ If you'd like mmap to ALWAYS be used, you can define MORECORE to be
+ a function that always returns MORECORE_FAILURE.
+
+ Malloc only has limited ability to detect failures of MORECORE
+ to supply contiguous space when it says it can. In particular,
+ multithreaded programs that do not use locks may result in
+ rece conditions across calls to MORECORE that result in gaps
+ that cannot be detected as such, and subsequent corruption.
+
+ If you are using this malloc with something other than sbrk (or its
+ emulation) to supply memory regions, you probably want to set
+ MORECORE_CONTIGUOUS as false. As an example, here is a custom
+ allocator kindly contributed for pre-OSX macOS. It uses virtually
+ but not necessarily physically contiguous non-paged memory (locked
+ in, present and won't get swapped out). You can use it by
+ uncommenting this section, adding some #includes, and setting up the
+ appropriate defines above:
+
+ #define MORECORE osMoreCore
+ #define MORECORE_CONTIGUOUS 0
+
+ There is also a shutdown routine that should somehow be called for
+ cleanup upon program exit.
+
+ #define MAX_POOL_ENTRIES 100
+ #define MINIMUM_MORECORE_SIZE (64 * 1024)
+ static int next_os_pool;
+ void *our_os_pools[MAX_POOL_ENTRIES];
+
+ void *osMoreCore(int size)
+ {
+ void *ptr = 0;
+ static void *sbrk_top = 0;
+
+ if (size > 0)
+ {
+ if (size < MINIMUM_MORECORE_SIZE)
+ size = MINIMUM_MORECORE_SIZE;
+ if (CurrentExecutionLevel() == kTaskLevel)
+ ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+ if (ptr == 0)
+ {
+ return (void *) MORECORE_FAILURE;
+ }
+ // save ptrs so they can be freed during cleanup
+ our_os_pools[next_os_pool] = ptr;
+ next_os_pool++;
+ ptr = (void *) ((((CHUNK_SIZE_T) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+ sbrk_top = (char *) ptr + size;
+ return ptr;
+ }
+ else if (size < 0)
+ {
+ // we don't currently support shrink behavior
+ return (void *) MORECORE_FAILURE;
+ }
+ else
+ {
+ return sbrk_top;
+ }
+ }
+
+ // cleanup any allocated memory pools
+ // called as last thing before shutting down driver
+
+ void osCleanupMem(void)
+ {
+ void **ptr;
+
+ for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+ if (*ptr)
+ {
+ PoolDeallocate(*ptr);
+ *ptr = 0;
+ }
+ }
+
+*/
+
+
+/*
+ --------------------------------------------------------------
+
+ Emulation of sbrk for win32.
+ Donated by J. Walter <Walter@GeNeSys-e.de>.
+ For additional information about this code, and malloc on Win32, see
+ http://www.genesys-e.de/jwalter/
+*/
+
+
+#ifdef WIN32
+
+#ifdef _DEBUG
+/* #define TRACE */
+#endif
+
+/* Support for USE_MALLOC_LOCK */
+#ifdef USE_MALLOC_LOCK
+
+/* Wait for spin lock */
+static int slwait (int *sl) {
+ while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0)
+ Sleep (0);
+ return 0;
+}
+
+/* Release spin lock */
+static int slrelease (int *sl) {
+ InterlockedExchange (sl, 0);
+ return 0;
+}
+
+#ifdef NEEDED
+/* Spin lock for emulation code */
+static int g_sl;
+#endif
+
+#endif /* USE_MALLOC_LOCK */
+
+/* getpagesize for windows */
+static long getpagesize (void) {
+ static long g_pagesize = 0;
+ if (! g_pagesize) {
+ SYSTEM_INFO system_info;
+ GetSystemInfo (&system_info);
+ g_pagesize = system_info.dwPageSize;
+ }
+ return g_pagesize;
+}
+static long getregionsize (void) {
+ static long g_regionsize = 0;
+ if (! g_regionsize) {
+ SYSTEM_INFO system_info;
+ GetSystemInfo (&system_info);
+ g_regionsize = system_info.dwAllocationGranularity;
+ }
+ return g_regionsize;
+}
+
+/* A region list entry */
+typedef struct _region_list_entry {
+ void *top_allocated;
+ void *top_committed;
+ void *top_reserved;
+ long reserve_size;
+ struct _region_list_entry *previous;
+} region_list_entry;
+
+/* Allocate and link a region entry in the region list */
+static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) {
+ region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry));
+ if (! next)
+ return FALSE;
+ next->top_allocated = (char *) base_reserved;
+ next->top_committed = (char *) base_reserved;
+ next->top_reserved = (char *) base_reserved + reserve_size;
+ next->reserve_size = reserve_size;
+ next->previous = *last;
+ *last = next;
+ return TRUE;
+}
+/* Free and unlink the last region entry from the region list */
+static int region_list_remove (region_list_entry **last) {
+ region_list_entry *previous = (*last)->previous;
+ if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last))
+ return FALSE;
+ *last = previous;
+ return TRUE;
+}
+
+#define CEIL(size,to) (((size)+(to)-1)&~((to)-1))
+#define FLOOR(size,to) ((size)&~((to)-1))
+
+#define SBRK_SCALE 0
+/* #define SBRK_SCALE 1 */
+/* #define SBRK_SCALE 2 */
+/* #define SBRK_SCALE 4 */
+
+/* sbrk for windows */
+static void *sbrk (long size) {
+ static long g_pagesize, g_my_pagesize;
+ static long g_regionsize, g_my_regionsize;
+ static region_list_entry *g_last;
+ void *result = (void *) MORECORE_FAILURE;
+#ifdef TRACE
+ printf ("sbrk %d\n", size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Wait for spin lock */
+ slwait (&g_sl);
+#endif
+ /* First time initialization */
+ if (! g_pagesize) {
+ g_pagesize = getpagesize ();
+ g_my_pagesize = g_pagesize << SBRK_SCALE;
+ }
+ if (! g_regionsize) {
+ g_regionsize = getregionsize ();
+ g_my_regionsize = g_regionsize << SBRK_SCALE;
+ }
+ if (! g_last) {
+ if (! region_list_append (&g_last, 0, 0))
+ goto sbrk_exit;
+ }
+ /* Assert invariants */
+ assert (g_last);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&
+ g_last->top_allocated <= g_last->top_committed);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&
+ g_last->top_committed <= g_last->top_reserved &&
+ (unsigned) g_last->top_committed % g_pagesize == 0);
+ assert ((unsigned) g_last->top_reserved % g_regionsize == 0);
+ assert ((unsigned) g_last->reserve_size % g_regionsize == 0);
+ /* Allocation requested? */
+ if (size >= 0) {
+ /* Allocation size is the requested size */
+ long allocate_size = size;
+ /* Compute the size to commit */
+ long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+ /* Do we reach the commit limit? */
+ if (to_commit > 0) {
+ /* Round size to commit */
+ long commit_size = CEIL (to_commit, g_my_pagesize);
+ /* Compute the size to reserve */
+ long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved;
+ /* Do we reach the reserve limit? */
+ if (to_reserve > 0) {
+ /* Compute the remaining size to commit in the current region */
+ long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed;
+ if (remaining_commit_size > 0) {
+ /* Assert preconditions */
+ assert ((unsigned) g_last->top_committed % g_pagesize == 0);
+ assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); {
+ /* Commit this */
+ void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size,
+ MEM_COMMIT, PAGE_READWRITE);
+ /* Check returned pointer for consistency */
+ if (base_committed != g_last->top_committed)
+ goto sbrk_exit;
+ /* Assert postconditions */
+ assert ((unsigned) base_committed % g_pagesize == 0);
+#ifdef TRACE
+ printf ("Commit %p %d\n", base_committed, remaining_commit_size);
+#endif
+ /* Adjust the regions commit top */
+ g_last->top_committed = (char *) base_committed + remaining_commit_size;
+ }
+ } {
+ /* Now we are going to search and reserve. */
+ int contiguous = -1;
+ int found = FALSE;
+ MEMORY_BASIC_INFORMATION memory_info;
+ void *base_reserved;
+ long reserve_size;
+ do {
+ /* Assume contiguous memory */
+ contiguous = TRUE;
+ /* Round size to reserve */
+ reserve_size = CEIL (to_reserve, g_my_regionsize);
+ /* Start with the current region's top */
+ memory_info.BaseAddress = g_last->top_reserved;
+ /* Assert preconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+ assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+ while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {
+ /* Assert postconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+#ifdef TRACE
+ printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize,
+ memory_info.State == MEM_FREE ? "FREE":
+ (memory_info.State == MEM_RESERVE ? "RESERVED":
+ (memory_info.State == MEM_COMMIT ? "COMMITTED": "?")));
+#endif
+ /* Region is free, well aligned and big enough: we are done */
+ if (memory_info.State == MEM_FREE &&
+ (unsigned) memory_info.BaseAddress % g_regionsize == 0 &&
+ memory_info.RegionSize >= (unsigned) reserve_size) {
+ found = TRUE;
+ break;
+ }
+ /* From now on we can't get contiguous memory! */
+ contiguous = FALSE;
+ /* Recompute size to reserve */
+ reserve_size = CEIL (allocate_size, g_my_regionsize);
+ memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;
+ /* Assert preconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0);
+ assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+ }
+ /* Search failed? */
+ if (! found)
+ goto sbrk_exit;
+ /* Assert preconditions */
+ assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0);
+ assert (0 < reserve_size && reserve_size % g_regionsize == 0);
+ /* Try to reserve this */
+ base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ if (! base_reserved) {
+ int rc = GetLastError ();
+ if (rc != ERROR_INVALID_ADDRESS)
+ goto sbrk_exit;
+ }
+ /* A null pointer signals (hopefully) a race condition with another thread. */
+ /* In this case, we try again. */
+ } while (! base_reserved);
+ /* Check returned pointer for consistency */
+ if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress)
+ goto sbrk_exit;
+ /* Assert postconditions */
+ assert ((unsigned) base_reserved % g_regionsize == 0);
+#ifdef TRACE
+ printf ("Reserve %p %d\n", base_reserved, reserve_size);
+#endif
+ /* Did we get contiguous memory? */
+ if (contiguous) {
+ long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated;
+ /* Adjust allocation size */
+ allocate_size -= start_size;
+ /* Adjust the regions allocation top */
+ g_last->top_allocated = g_last->top_committed;
+ /* Recompute the size to commit */
+ to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+ /* Round size to commit */
+ commit_size = CEIL (to_commit, g_my_pagesize);
+ }
+ /* Append the new region to the list */
+ if (! region_list_append (&g_last, base_reserved, reserve_size))
+ goto sbrk_exit;
+ /* Didn't we get contiguous memory? */
+ if (! contiguous) {
+ /* Recompute the size to commit */
+ to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed;
+ /* Round size to commit */
+ commit_size = CEIL (to_commit, g_my_pagesize);
+ }
+ }
+ }
+ /* Assert preconditions */
+ assert ((unsigned) g_last->top_committed % g_pagesize == 0);
+ assert (0 < commit_size && commit_size % g_pagesize == 0); {
+ /* Commit this */
+ void *base_committed = VirtualAlloc (g_last->top_committed, commit_size,
+ MEM_COMMIT, PAGE_READWRITE);
+ /* Check returned pointer for consistency */
+ if (base_committed != g_last->top_committed)
+ goto sbrk_exit;
+ /* Assert postconditions */
+ assert ((unsigned) base_committed % g_pagesize == 0);
+#ifdef TRACE
+ printf ("Commit %p %d\n", base_committed, commit_size);
+#endif
+ /* Adjust the regions commit top */
+ g_last->top_committed = (char *) base_committed + commit_size;
+ }
+ }
+ /* Adjust the regions allocation top */
+ g_last->top_allocated = (char *) g_last->top_allocated + allocate_size;
+ result = (char *) g_last->top_allocated - size;
+ /* Deallocation requested? */
+ } else if (size < 0) {
+ long deallocate_size = - size;
+ /* As long as we have a region to release */
+ while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) {
+ /* Get the size to release */
+ long release_size = g_last->reserve_size;
+ /* Get the base address */
+ void *base_reserved = (char *) g_last->top_reserved - release_size;
+ /* Assert preconditions */
+ assert ((unsigned) base_reserved % g_regionsize == 0);
+ assert (0 < release_size && release_size % g_regionsize == 0); {
+ /* Release this */
+ int rc = VirtualFree (base_reserved, 0,
+ MEM_RELEASE);
+ /* Check returned code for consistency */
+ if (! rc)
+ goto sbrk_exit;
+#ifdef TRACE
+ printf ("Release %p %d\n", base_reserved, release_size);
+#endif
+ }
+ /* Adjust deallocation size */
+ deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved;
+ /* Remove the old region from the list */
+ if (! region_list_remove (&g_last))
+ goto sbrk_exit;
+ } {
+ /* Compute the size to decommit */
+ long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size);
+ if (to_decommit >= g_my_pagesize) {
+ /* Compute the size to decommit */
+ long decommit_size = FLOOR (to_decommit, g_my_pagesize);
+ /* Compute the base address */
+ void *base_committed = (char *) g_last->top_committed - decommit_size;
+ /* Assert preconditions */
+ assert ((unsigned) base_committed % g_pagesize == 0);
+ assert (0 < decommit_size && decommit_size % g_pagesize == 0); {
+ /* Decommit this */
+ int rc = VirtualFree ((char *) base_committed, decommit_size,
+ MEM_DECOMMIT);
+ /* Check returned code for consistency */
+ if (! rc)
+ goto sbrk_exit;
+#ifdef TRACE
+ printf ("Decommit %p %d\n", base_committed, decommit_size);
+#endif
+ }
+ /* Adjust deallocation size and regions commit and allocate top */
+ deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed;
+ g_last->top_committed = base_committed;
+ g_last->top_allocated = base_committed;
+ }
+ }
+ /* Adjust regions allocate top */
+ g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size;
+ /* Check for underflow */
+ if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated ||
+ g_last->top_allocated > g_last->top_committed) {
+ /* Adjust regions allocate top */
+ g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size;
+ goto sbrk_exit;
+ }
+ result = g_last->top_allocated;
+ }
+ /* Assert invariants */
+ assert (g_last);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated &&
+ g_last->top_allocated <= g_last->top_committed);
+ assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed &&
+ g_last->top_committed <= g_last->top_reserved &&
+ (unsigned) g_last->top_committed % g_pagesize == 0);
+ assert ((unsigned) g_last->top_reserved % g_regionsize == 0);
+ assert ((unsigned) g_last->reserve_size % g_regionsize == 0);
+
+sbrk_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Release spin lock */
+ slrelease (&g_sl);
+#endif
+ return result;
+}
+
+/* mmap for windows */
+static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) {
+ static long g_pagesize;
+ static long g_regionsize;
+#ifdef TRACE
+ printf ("mmap %d\n", size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Wait for spin lock */
+ slwait (&g_sl);
+#endif
+ /* First time initialization */
+ if (! g_pagesize)
+ g_pagesize = getpagesize ();
+ if (! g_regionsize)
+ g_regionsize = getregionsize ();
+ /* Assert preconditions */
+ assert ((unsigned) ptr % g_regionsize == 0);
+ assert (size % g_pagesize == 0);
+ /* Allocate this */
+ ptr = VirtualAlloc (ptr, size,
+ MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
+ if (! ptr) {
+ ptr = (void *) MORECORE_FAILURE;
+ goto mmap_exit;
+ }
+ /* Assert postconditions */
+ assert ((unsigned) ptr % g_regionsize == 0);
+#ifdef TRACE
+ printf ("Commit %p %d\n", ptr, size);
+#endif
+mmap_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Release spin lock */
+ slrelease (&g_sl);
+#endif
+ return ptr;
+}
+
+/* munmap for windows */
+static long munmap (void *ptr, long size) {
+ static long g_pagesize;
+ static long g_regionsize;
+ int rc = MUNMAP_FAILURE;
+#ifdef TRACE
+ printf ("munmap %p %d\n", ptr, size);
+#endif
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Wait for spin lock */
+ slwait (&g_sl);
+#endif
+ /* First time initialization */
+ if (! g_pagesize)
+ g_pagesize = getpagesize ();
+ if (! g_regionsize)
+ g_regionsize = getregionsize ();
+ /* Assert preconditions */
+ assert ((unsigned) ptr % g_regionsize == 0);
+ assert (size % g_pagesize == 0);
+ /* Free this */
+ if (! VirtualFree (ptr, 0,
+ MEM_RELEASE))
+ goto munmap_exit;
+ rc = 0;
+#ifdef TRACE
+ printf ("Release %p %d\n", ptr, size);
+#endif
+munmap_exit:
+#if defined (USE_MALLOC_LOCK) && defined (NEEDED)
+ /* Release spin lock */
+ slrelease (&g_sl);
+#endif
+ return rc;
+}
+
+static void vminfo (CHUNK_SIZE_T *free, CHUNK_SIZE_T *reserved, CHUNK_SIZE_T *committed) {
+ MEMORY_BASIC_INFORMATION memory_info;
+ memory_info.BaseAddress = 0;
+ *free = *reserved = *committed = 0;
+ while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) {
+ switch (memory_info.State) {
+ case MEM_FREE:
+ *free += memory_info.RegionSize;
+ break;
+ case MEM_RESERVE:
+ *reserved += memory_info.RegionSize;
+ break;
+ case MEM_COMMIT:
+ *committed += memory_info.RegionSize;
+ break;
+ }
+ memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize;
+ }
+}
+
+static int cpuinfo (int whole, CHUNK_SIZE_T *kernel, CHUNK_SIZE_T *user) {
+ if (whole) {
+ __int64 creation64, exit64, kernel64, user64;
+ int rc = GetProcessTimes (GetCurrentProcess (),
+ (FILETIME *) &creation64,
+ (FILETIME *) &exit64,
+ (FILETIME *) &kernel64,
+ (FILETIME *) &user64);
+ if (! rc) {
+ *kernel = 0;
+ *user = 0;
+ return FALSE;
+ }
+ *kernel = (CHUNK_SIZE_T) (kernel64 / 10000);
+ *user = (CHUNK_SIZE_T) (user64 / 10000);
+ return TRUE;
+ } else {
+ __int64 creation64, exit64, kernel64, user64;
+ int rc = GetThreadTimes (GetCurrentThread (),
+ (FILETIME *) &creation64,
+ (FILETIME *) &exit64,
+ (FILETIME *) &kernel64,
+ (FILETIME *) &user64);
+ if (! rc) {
+ *kernel = 0;
+ *user = 0;
+ return FALSE;
+ }
+ *kernel = (CHUNK_SIZE_T) (kernel64 / 10000);
+ *user = (CHUNK_SIZE_T) (user64 / 10000);
+ return TRUE;
+ }
+}
+
+#endif /* WIN32 */
+
+/* ------------------------------------------------------------
+History:
+ V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
+ * Fix malloc_state bitmap array misdeclaration
+
+ V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee)
+ * Allow tuning of FIRST_SORTED_BIN_SIZE
+ * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
+ * Better detection and support for non-contiguousness of MORECORE.
+ Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
+ * Bypass most of malloc if no frees. Thanks To Emery Berger.
+ * Fix freeing of old top non-contiguous chunk im sysmalloc.
+ * Raised default trim and map thresholds to 256K.
+ * Fix mmap-related #defines. Thanks to Lubos Lunak.
+ * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
+ * Branch-free bin calculation
+ * Default trim and mmap thresholds now 256K.
+
+ V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
+ * Introduce independent_comalloc and independent_calloc.
+ Thanks to Michael Pachos for motivation and help.
+ * Make optional .h file available
+ * Allow > 2GB requests on 32bit systems.
+ * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
+ Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+ and Anonymous.
+ * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+ helping test this.)
+ * memalign: check alignment arg
+ * realloc: don't try to shift chunks backwards, since this
+ leads to more fragmentation in some programs and doesn't
+ seem to help in any others.
+ * Collect all cases in malloc requiring system memory into sYSMALLOc
+ * Use mmap as backup to sbrk
+ * Place all internal state in malloc_state
+ * Introduce fastbins (although similar to 2.5.1)
+ * Many minor tunings and cosmetic improvements
+ * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+ * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+ Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
+ * Include errno.h to support default failure action.
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/winsup/cygwin/malloc_wrapper.cc b/winsup/cygwin/malloc_wrapper.cc
index 2fa93b1a1..51cc81832 100644
--- a/winsup/cygwin/malloc_wrapper.cc
+++ b/winsup/cygwin/malloc_wrapper.cc
@@ -1,6 +1,6 @@
-/* malloc.cc
+/* malloc_wrapper.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Originally written by Steve Chamberlain of Cygnus Support
sac@cygnus.com
@@ -18,10 +18,13 @@ details. */
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
+#include <errno.h>
+#include "cygerrno.h"
#include "cygheap.h"
#include "heap.h"
#include "sync.h"
#include "perprocess.h"
+#include "cygmalloc.h"
/* we provide these stubs to call into a user's
provided malloc if there is one - otherwise
@@ -101,105 +104,191 @@ strdup (const char *s)
return strdup_dbg (s, __FILE__, __LINE__);
}
#else
-/* Call though the application pointer,
- which either points to export_malloc, or the application's
- own version. */
+#endif
+/* These routines are used by the application if it
+ doesn't provide its own malloc. */
-void *
-malloc (size_t size)
+extern "C" void
+free (void *p)
{
- void *res;
- res = user_data->malloc (size);
- return res;
+ malloc_printf ("(%p), called by %p", p, __builtin_return_address (0));
+ if (!use_internal_malloc)
+ user_data->free (p);
+ else
+ {
+ __malloc_lock ();
+ dlfree (p);
+ __malloc_unlock ();
+ }
}
-void
-free (void *p)
+extern "C" void *
+malloc (size_t size)
{
- user_data->free (p);
+ void *res;
+ export_malloc_called = 1;
+ if (!use_internal_malloc)
+ res = user_data->malloc (size);
+ else
+ {
+ __malloc_lock ();
+ res = dlmalloc (size);
+ __malloc_unlock ();
+ }
+ malloc_printf ("(%d) = %x, called by %p", size, res, __builtin_return_address (0));
+ return res;
}
-void *
+extern "C" void *
realloc (void *p, size_t size)
{
void *res;
- res = user_data->realloc (p, size);
+ if (!use_internal_malloc)
+ res = user_data->realloc (p, size);
+ else
+ {
+ __malloc_lock ();
+ res = dlrealloc (p, size);
+ __malloc_unlock ();
+ }
+ malloc_printf ("(%x, %d) = %x, called by %x", p, size, res, __builtin_return_address (0));
return res;
}
-void *
+extern "C" void *
calloc (size_t nmemb, size_t size)
{
void *res;
- res = user_data->calloc (nmemb, size);
+ if (!use_internal_malloc)
+ res = user_data->calloc (nmemb, size);
+ else
+ {
+ __malloc_lock ();
+ res = dlcalloc (nmemb, size);
+ __malloc_unlock ();
+ }
+ malloc_printf ("(%d, %d) = %x, called by %x", nmemb, size, res, __builtin_return_address (0));
return res;
}
-extern "C" char *
-strdup (const char *s)
+extern "C" void *
+memalign (size_t alignment, size_t bytes)
{
- char *p;
- size_t len = strlen (s) + 1;
- if ((p = (char *) malloc (len)) != NULL)
- memcpy (p, s, len);
- return p;
+ void *res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = NULL;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlmemalign (alignment, bytes);
+ __malloc_unlock ();
+ }
+
+ return res;
}
-extern "C" char *
-_strdup_r (struct _reent *, const char *s)
+extern "C" void *
+valloc (size_t bytes)
{
- return strdup (s);
-}
-#endif
+ void *res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = NULL;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlvalloc (bytes);
+ __malloc_unlock ();
+ }
-/* These routines are used by the application if it
- doesn't provide its own malloc. */
+ return res;
+}
-extern "C" void
-export_free (void *p)
+extern "C" size_t
+malloc_usable_size (void *p)
{
- malloc_printf ("(%p), called by %x", p, ((int *)&p)[-1]);
- if (use_internal_malloc)
- _free_r (_impure_ptr, p);
+ size_t res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = 0;
+ }
else
- user_data->free (p);
+ {
+ __malloc_lock ();
+ res = dlmalloc_usable_size (p);
+ __malloc_unlock ();
+ }
+
+ return res;
}
-extern "C" void *
-export_malloc (int size)
+extern "C" int
+malloc_trim (size_t pad)
{
- void *res;
- export_malloc_called = 1;
- if (use_internal_malloc)
- res = _malloc_r (_impure_ptr, size);
+ size_t res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = 0;
+ }
else
- res = user_data->malloc (size);
- malloc_printf ("(%d) = %x, called by %x", size, res, ((int *)&size)[-1]);
+ {
+ __malloc_lock ();
+ res = dlmalloc_trim (pad);
+ __malloc_unlock ();
+ }
+
return res;
}
-extern "C" void *
-export_realloc (void *p, int size)
+extern "C" int
+mallopt (int p, int v)
{
- void *res;
- if (use_internal_malloc)
- res = _realloc_r (_impure_ptr, p, size);
+ int res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = 0;
+ }
else
- res = user_data->realloc (p, size);
- malloc_printf ("(%x, %d) = %x, called by %x", p, size, res, ((int *)&p)[-1]);
+ {
+ __malloc_lock ();
+ res = dlmallopt (p, v);
+ __malloc_unlock ();
+ }
+
return res;
}
-extern "C" void *
-export_calloc (size_t nmemb, size_t size)
+extern "C" void
+malloc_stats ()
{
- void *res;
- if (use_internal_malloc)
- res = _calloc_r (_impure_ptr, nmemb, size);
+ if (!use_internal_malloc)
+ set_errno (ENOSYS);
else
- res = user_data->calloc (nmemb, size);
- malloc_printf ("(%d, %d) = %x, called by %x", nmemb, size, res, ((int *)&nmemb)[-1]);
- return res;
+ {
+ __malloc_lock ();
+ dlmalloc_stats ();
+ __malloc_unlock ();
+ }
+
+ return;
+}
+
+extern "C" char *
+strdup (const char *s)
+{
+ char *p;
+ size_t len = strlen (s) + 1;
+ if ((p = (char *) malloc (len)) != NULL)
+ memcpy (p, s, len);
+ return p;
}
/* We use a critical section to lock access to the malloc data
@@ -209,14 +298,14 @@ export_calloc (size_t nmemb, size_t size)
newlib will call __malloc_lock and __malloc_unlock at appropriate
times. */
-static NO_COPY muto *mprotect = NULL;
+NO_COPY muto *mallock = NULL;
void
malloc_init ()
{
- mprotect = new_muto (FALSE, "mprotect");
+ new_muto (mallock);
/* Check if mallock is provided by application. If so, redirect all
- calls to export_malloc/free/realloc to application provided. This may
+ calls to malloc/free/realloc to application provided. This may
happen if some other dll calls cygwin's malloc, but main code provides
its own malloc */
if (!user_data->forkee)
@@ -224,21 +313,9 @@ malloc_init ()
#ifdef MALLOC_DEBUG
_free_r (NULL, _malloc_r (NULL, 16));
#else
- free (malloc (16));
+ user_data->free (user_data->malloc (16));
#endif
if (!export_malloc_called)
use_internal_malloc = 0;
}
}
-
-extern "C" void
-__malloc_lock (struct _reent *)
-{
- mprotect->acquire ();
-}
-
-extern "C" void
-__malloc_unlock (struct _reent *)
-{
- mprotect->release ();
-}
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index c5d46fbf0..a6fec0ddc 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -11,8 +11,13 @@ details. */
#include "winsup.h"
#include "cygerrno.h"
#include <sys/errno.h>
+#include <sys/uio.h>
+#include <assert.h>
+#include <limits.h>
+#include <winbase.h>
+#include <winnls.h>
-/********************** String Helper Functions ************************/
+long tls_ix = -1;
const char case_folded_lower[] NO_COPY = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
@@ -116,15 +121,21 @@ strcasestr (const char *searchee, const char *lookfor)
}
int __stdcall
-check_null_empty_str (const char *name)
+check_null_str (const char *name)
{
- if (!name || IsBadStringPtr (name, MAX_PATH))
- return EFAULT;
+ if (name && !IsBadStringPtr (name, MAX_PATH))
+ return 0;
+
+ return EFAULT;
+}
- if (!*name)
- return ENOENT;
+int __stdcall
+check_null_empty_str (const char *name)
+{
+ if (name && !IsBadStringPtr (name, MAX_PATH))
+ return !*name ? ENOENT : 0;
- return 0;
+ return EFAULT;
}
int __stdcall
@@ -137,19 +148,124 @@ check_null_empty_str_errno (const char *name)
}
int __stdcall
-__check_null_invalid_struct (const void *s, unsigned sz)
+check_null_str_errno (const char *name)
+{
+ int __err;
+ if ((__err = check_null_str (name)))
+ set_errno (__err);
+ return __err;
+}
+
+int __stdcall
+__check_null_invalid_struct (void *s, unsigned sz)
{
- if (!s || IsBadWritePtr ((void *) s, sz))
- return EFAULT;
+ if (s && !IsBadWritePtr (s, sz))
+ return 0;
- return 0;
+ return EFAULT;
}
int __stdcall
-__check_null_invalid_struct_errno (const void *s, unsigned sz)
+__check_null_invalid_struct_errno (void *s, unsigned sz)
{
- int __err;
- if ((__err = __check_null_invalid_struct (s, sz)))
- set_errno (__err);
- return __err;
+ int err;
+ if ((err = __check_null_invalid_struct (s, sz)))
+ set_errno (err);
+ return err;
+}
+
+int __stdcall
+__check_invalid_read_ptr_errno (const void *s, unsigned sz)
+{
+ if (s && !IsBadReadPtr (s, sz))
+ return 0;
+ return set_errno (EFAULT);
+}
+
+ssize_t
+check_iovec_for_read (const struct iovec *iov, int iovcnt)
+{
+ if (iovcnt <= 0 || iovcnt > IOV_MAX)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ if (__check_invalid_read_ptr_errno (iov, iovcnt * sizeof (*iov)))
+ return -1;
+
+ size_t tot = 0;
+
+ while (iovcnt != 0)
+ {
+ if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ if (iov->iov_len
+ && __check_null_invalid_struct_errno (iov->iov_base, iov->iov_len))
+ return -1;
+
+ iov += 1;
+ iovcnt -= 1;
+ }
+
+ assert (tot <= SSIZE_MAX);
+
+ return (ssize_t) tot;
+}
+
+ssize_t
+check_iovec_for_write (const struct iovec *iov, int iovcnt)
+{
+ if (iovcnt <= 0 || iovcnt > IOV_MAX)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ if (__check_invalid_read_ptr_errno (iov, iovcnt * sizeof (*iov)))
+ return -1;
+
+ size_t tot = 0;
+
+ while (iovcnt != 0)
+ {
+ if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ if (iov->iov_len
+ && __check_invalid_read_ptr_errno (iov->iov_base, iov->iov_len))
+ return -1;
+
+ iov += 1;
+ iovcnt -= 1;
+ }
+
+ assert (tot <= SSIZE_MAX);
+
+ return (ssize_t) tot;
+}
+
+UINT
+get_cp ()
+{
+ return current_codepage == ansi_cp ? GetACP() : GetOEMCP();
+}
+
+int __stdcall
+sys_wcstombs (char *tgt, const WCHAR *src, int len)
+{
+ return WideCharToMultiByte (get_cp (), 0, src, -1, tgt, len, NULL, NULL);
+}
+
+int __stdcall
+sys_mbstowcs (WCHAR *tgt, const char *src, int len)
+{
+ return MultiByteToWideChar (get_cp (), 0, src, -1, tgt, len);
}
diff --git a/winsup/cygwin/mkvers.sh b/winsup/cygwin/mkvers.sh
index 6d54b4fca..3296b569a 100755
--- a/winsup/cygwin/mkvers.sh
+++ b/winsup/cygwin/mkvers.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# mkvers.sh - Make version information for cygwin DLL
#
-# Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+# Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
#
# This file is part of Cygwin.
#
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc
index c13a3f365..e2684630e 100644
--- a/winsup/cygwin/mmap.cc
+++ b/winsup/cygwin/mmap.cc
@@ -1,6 +1,6 @@
/* mmap.cc
- Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -20,15 +20,13 @@ details. */
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "sys/cygwin.h"
-#define PAGE_CNT(bytes) howmany(bytes,getpagesize())
+#define PAGE_CNT(bytes) howmany((bytes),getpagesize())
#define PGBITS (sizeof(DWORD)*8)
-#define MAPSIZE(pages) howmany(pages,PGBITS)
+#define MAPSIZE(pages) howmany((pages),PGBITS)
#define MAP_SET(n) (map_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS)))
#define MAP_CLR(n) (map_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS)))
@@ -47,13 +45,13 @@ class mmap_record
HANDLE mapping_handle_;
int devtype_;
DWORD access_mode_;
- DWORD offset_;
+ __off64_t offset_;
DWORD size_to_map_;
caddr_t base_address_;
DWORD *map_map_;
public:
- mmap_record (int fd, HANDLE h, DWORD ac, DWORD o, DWORD s, caddr_t b) :
+ mmap_record (int fd, HANDLE h, DWORD ac, __off64_t o, DWORD s, caddr_t b) :
fdesc_ (fd),
mapping_handle_ (h),
devtype_ (0),
@@ -95,9 +93,10 @@ class mmap_record
void free_map () { if (map_map_) free (map_map_); }
DWORD find_empty (DWORD pages);
- DWORD map_map (DWORD off, DWORD len);
+ __off64_t map_map (__off64_t off, DWORD len);
BOOL unmap_map (caddr_t addr, DWORD len);
void fixup_map (void);
+ int access (char *address);
fhandler_base *alloc_fh ();
void free_fh (fhandler_base *fh);
@@ -109,6 +108,8 @@ mmap_record::find_empty (DWORD pages)
DWORD mapped_pages = PAGE_CNT (size_to_map_);
DWORD start;
+ if (pages > mapped_pages)
+ return (DWORD)-1;
for (start = 0; start <= mapped_pages - pages; ++start)
if (!MAP_ISSET (start))
{
@@ -122,8 +123,8 @@ mmap_record::find_empty (DWORD pages)
return (DWORD)-1;
}
-DWORD
-mmap_record::map_map (DWORD off, DWORD len)
+__off64_t
+mmap_record::map_map (__off64_t off, DWORD len)
{
DWORD prot, old_prot;
switch (access_mode_)
@@ -148,7 +149,10 @@ mmap_record::map_map (DWORD off, DWORD len)
if (wincap.virtual_protect_works_on_shared_pages ()
&& !VirtualProtect (base_address_ + off * getpagesize (),
len * getpagesize (), prot, &old_prot))
- syscall_printf ("-1 = map_map (): %E");
+ {
+ debug_printf ("-1 = map_map (): %E");
+ return (__off64_t)-1;
+ }
while (len-- > 0)
MAP_SET (off + len);
@@ -161,7 +165,10 @@ mmap_record::map_map (DWORD off, DWORD len)
if (wincap.virtual_protect_works_on_shared_pages ()
&& !VirtualProtect (base_address_ + start * getpagesize (),
len * getpagesize (), prot, &old_prot))
- syscall_printf ("-1 = map_map (): %E");
+ {
+ debug_printf ("-1 = map_map (): %E");
+ return (__off64_t)-1;
+ }
for (; len-- > 0; ++start)
MAP_SET (start);
@@ -217,7 +224,16 @@ mmap_record::fixup_map ()
&old_prot);
}
-static fhandler_disk_file fh_paging_file (NULL);
+int
+mmap_record::access (char *address)
+{
+ if (address < base_address_ || address >= base_address_ + size_to_map_)
+ return 0;
+ DWORD off = (address - base_address_) / getpagesize ();
+ return MAP_ISSET (off);
+}
+
+static fhandler_disk_file fh_paging_file;
fhandler_base *
mmap_record::alloc_fh ()
@@ -233,7 +249,7 @@ mmap_record::alloc_fh ()
the call to fork(). This requires creating a fhandler
of the correct type to be sure to call the method of the
correct class. */
- return cygheap->fdtab.build_fhandler (-1, get_device (), "", 0);
+ return cygheap->fdtab.build_fhandler (-1, get_device ());
}
void
@@ -253,8 +269,9 @@ public:
~list ();
mmap_record *add_record (mmap_record r);
void erase (int i);
- mmap_record *match (DWORD off, DWORD len);
- off_t match (caddr_t addr, DWORD len, off_t start);
+ void erase ();
+ mmap_record *match (__off64_t off, DWORD len);
+ long match (caddr_t addr, DWORD len, long start);
};
list::list ()
@@ -285,7 +302,7 @@ list::add_record (mmap_record r)
/* Used in mmap() */
mmap_record *
-list::match (DWORD off, DWORD len)
+list::match (__off64_t off, DWORD len)
{
if (fd == -1 && !off)
{
@@ -298,21 +315,23 @@ list::match (DWORD off, DWORD len)
{
for (int i = 0; i < nrecs; ++i)
if (off >= recs[i].get_offset ()
- && off + len <= recs[i].get_offset () + recs[i].get_size ())
+ && off + len <= recs[i].get_offset ()
+ + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()))
return recs + i;
}
return NULL;
}
/* Used in munmap() */
-off_t
-list::match (caddr_t addr, DWORD len, off_t start)
+long
+list::match (caddr_t addr, DWORD len, __off32_t start)
{
for (int i = start + 1; i < nrecs; ++i)
if (addr >= recs[i].get_address ()
- && addr + len <= recs[i].get_address () + recs[i].get_size ())
+ && addr + len <= recs[i].get_address ()
+ + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()))
return i;
- return (off_t)-1;
+ return -1;
}
void
@@ -324,6 +343,12 @@ list::erase (int i)
nrecs--;
}
+void
+list::erase ()
+{
+ erase (nrecs-1);
+}
+
class map {
public:
list **lists;
@@ -398,9 +423,9 @@ static map *mmapped_areas;
extern "C"
caddr_t
-mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
+mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, __off64_t off)
{
- syscall_printf ("addr %x, len %d, prot %x, flags %x, fd %d, off %d",
+ syscall_printf ("addr %x, len %d, prot %x, flags %x, fd %d, off %D",
addr, len, prot, flags, fd, off);
static DWORD granularity;
@@ -423,7 +448,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
return MAP_FAILED;
}
- SetResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ SetResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
if (mmapped_areas == NULL)
{
@@ -433,7 +458,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
{
set_errno (ENOMEM);
syscall_printf ("-1 = mmap(): ENOMEM");
- ReleaseResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return MAP_FAILED;
}
}
@@ -442,27 +467,29 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
fd = -1;
/* Map always in multipliers of `granularity'-sized chunks. */
- DWORD gran_off = off & ~(granularity - 1);
+ __off64_t gran_off = off & ~(granularity - 1);
DWORD gran_len = howmany (len, granularity) * granularity;
- fhandler_base *fh = NULL;
+ fhandler_base *fh;
caddr_t base = addr;
HANDLE h;
if (fd != -1)
{
/* Ensure that fd is open */
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
{
- set_errno (EBADF);
syscall_printf ("-1 = mmap(): EBADF");
- ReleaseResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return MAP_FAILED;
}
- fh = cygheap->fdtab[fd];
+ fh = cfd;
if (fh->get_device () == FH_DISK)
{
- DWORD fsiz = GetFileSize (fh->get_handle (), NULL);
+ DWORD high;
+ DWORD low = GetFileSize (fh->get_handle (), &high);
+ __off64_t fsiz = ((__off64_t)high << 32) + low;
fsiz -= gran_off;
if (gran_len > fsiz)
gran_len = fsiz;
@@ -487,10 +514,16 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
mmap_record *rec;
if ((rec = l->match (off, len)) != NULL)
{
- off = rec->map_map (off, len);
+ if ((off = rec->map_map (off, len)) == (__off64_t)-1)
+ {
+ set_errno (ENOMEM);
+ syscall_printf ("-1 = mmap(): ENOMEM");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap");
+ return MAP_FAILED;
+ }
caddr_t ret = rec->get_address () + off;
syscall_printf ("%x = mmap() succeeded", ret);
- ReleaseResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return ret;
}
}
@@ -503,7 +536,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
While the changes are not propagated to the file, they are
visible to other processes sharing the same file mapping object.
Workaround: Don't use named file mapping. That should work since
- sharing file mappings only works reliable using named
+ sharing file mappings only works reliable using named
file mapping on 9x.
*/
if ((flags & MAP_PRIVATE)
@@ -514,7 +547,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
if (h == INVALID_HANDLE_VALUE)
{
- ReleaseResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return MAP_FAILED;
}
@@ -537,7 +570,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
fh->munmap (h, base, gran_len);
set_errno (ENOMEM);
syscall_printf ("-1 = mmap(): ENOMEM");
- ReleaseResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return MAP_FAILED;
}
l = mmapped_areas->add_list (l, fd);
@@ -545,13 +578,28 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
/* Insert into the list */
mmap_record *rec = l->add_record (mmap_rec);
- off = rec->map_map (off, len);
+ if ((off = rec->map_map (off, len)) == (__off64_t)-1)
+ {
+ fh->munmap (h, base, gran_len);
+ l->erase ();
+ set_errno (ENOMEM);
+ syscall_printf ("-1 = mmap(): ENOMEM");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ return MAP_FAILED;
+ }
caddr_t ret = rec->get_address () + off;
syscall_printf ("%x = mmap() succeeded", ret);
- ReleaseResourceLock(LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return ret;
}
+extern "C"
+caddr_t
+mmap (caddr_t addr, size_t len, int prot, int flags, int fd, __off32_t off)
+{
+ return mmap64 (addr, len, prot, flags, fd, (__off64_t)off);
+}
+
/* munmap () removes an mmapped area. It insists that base area
requested is the same as that mmapped, error if not. */
@@ -569,13 +617,13 @@ munmap (caddr_t addr, size_t len)
return -1;
}
- SetResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
+ SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
/* Check if a mmap'ed area was ever created */
if (mmapped_areas == NULL)
{
syscall_printf ("-1 = munmap(): mmapped_areas == NULL");
set_errno (EINVAL);
- ReleaseResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
return -1;
}
@@ -587,7 +635,7 @@ munmap (caddr_t addr, size_t len)
list *l = mmapped_areas->lists[it];
if (l)
{
- off_t li = -1;
+ long li = -1;
if ((li = l->match(addr, len, li)) >= 0)
{
mmap_record *rec = l->recs + li;
@@ -601,7 +649,7 @@ munmap (caddr_t addr, size_t len)
l->erase (li);
}
syscall_printf ("0 = munmap(): %x", addr);
- ReleaseResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
return 0;
}
}
@@ -610,7 +658,7 @@ munmap (caddr_t addr, size_t len)
set_errno (EINVAL);
syscall_printf ("-1 = munmap(): EINVAL");
- ReleaseResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
+ ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
return -1;
}
@@ -632,13 +680,13 @@ msync (caddr_t addr, size_t len, int flags)
return -1;
}
- SetResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
+ SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
/* Check if a mmap'ed area was ever created */
if (mmapped_areas == NULL)
{
syscall_printf ("-1 = msync(): mmapped_areas == NULL");
set_errno (EINVAL);
- ReleaseResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
+ ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
return -1;
}
@@ -653,8 +701,12 @@ msync (caddr_t addr, size_t len, int flags)
for (int li = 0; li < l->nrecs; ++li)
{
mmap_record *rec = l->recs + li;
- if (rec->get_address () == addr)
+ if (rec->access (addr))
{
+ /* Check whole area given by len. */
+ for (DWORD i = getpagesize (); i < len; ++i)
+ if (!rec->access (addr + i))
+ goto invalid_address_range;
fhandler_base *fh = rec->alloc_fh ();
int ret = fh->msync (rec->get_handle (), addr, len, flags);
rec->free_fh (fh);
@@ -664,18 +716,19 @@ msync (caddr_t addr, size_t len, int flags)
else
syscall_printf ("0 = msync()");
- ReleaseResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
+ ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
return 0;
}
- }
- }
- }
+ }
+ }
+ }
+invalid_address_range:
/* SUSv2: Return code if indicated memory was not mapped is ENOMEM. */
set_errno (ENOMEM);
syscall_printf ("-1 = msync(): ENOMEM");
- ReleaseResourceLock(LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
+ ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "msync");
return -1;
}
@@ -693,7 +746,7 @@ msync (caddr_t addr, size_t len, int flags)
*/
HANDLE
fhandler_base::mmap (caddr_t *addr, size_t len, DWORD access,
- int flags, off_t off)
+ int flags, __off64_t off)
{
set_errno (ENODEV);
return INVALID_HANDLE_VALUE;
@@ -724,7 +777,7 @@ fhandler_base::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
/* Implementation for disk files. */
HANDLE
fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access,
- int flags, off_t off)
+ int flags, __off64_t off)
{
DWORD protect;
@@ -754,7 +807,7 @@ fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access,
debug_printf ("named sharing");
if (!(h = OpenFileMapping (access, TRUE, namebuf)))
- h = CreateFileMapping (get_handle(), &sec_none, protect, 0, 0, namebuf);
+ h = CreateFileMapping (get_handle (), &sec_none, protect, 0, 0, namebuf);
}
else
h = CreateFileMapping (get_handle (), &sec_none, protect, 0,
@@ -767,9 +820,10 @@ fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access,
return INVALID_HANDLE_VALUE;
}
- void *base = MapViewOfFileEx (h, access, 0, off, len,
+ DWORD high = off >> 32, low = off & 0xffffffff;
+ void *base = MapViewOfFileEx (h, access, high, low, len,
(flags & MAP_FIXED) ? *addr : NULL);
- debug_printf ("%x = MapViewOfFileEx (h:%x, access:%x, 0, off:%d, len:%d, addr:%x)", base, h, access, off, len, (flags & MAP_FIXED) ? *addr : NULL);
+ debug_printf ("%x = MapViewOfFileEx (h:%x, access:%x, 0, off:%D, len:%d, addr:%x)", base, h, access, off, len, (flags & MAP_FIXED) ? *addr : NULL);
if (!base || ((flags & MAP_FIXED) && base != *addr))
{
if (!base)
@@ -875,7 +929,7 @@ mprotect (caddr_t addr, size_t len, int prot)
*/
int __stdcall
-fixup_mmaps_after_fork ()
+fixup_mmaps_after_fork (HANDLE parent)
{
debug_printf ("recreate_mmaps_after_fork, mmapped_areas %p", mmapped_areas);
@@ -913,6 +967,20 @@ fixup_mmaps_after_fork ()
rec->get_address ());
return -1;
}
+ if (rec->get_access () == FILE_MAP_COPY)
+ {
+ for (char *address = rec->get_address ();
+ address < rec->get_address () + rec->get_size ();
+ address += getpagesize ())
+ if (rec->access (address)
+ && !ReadProcessMemory (parent, address, address,
+ getpagesize (), NULL))
+ {
+ system_printf ("ReadProcessMemory failed for MAP_PRIVATE address %p, %E",
+ rec->get_address ());
+ return -1;
+ }
+ }
rec->fixup_map ();
}
}
diff --git a/winsup/cygwin/msg.cc b/winsup/cygwin/msg.cc
new file mode 100644
index 000000000..c76fd8ee7
--- /dev/null
+++ b/winsup/cygwin/msg.cc
@@ -0,0 +1,48 @@
+/* msg.cc: Single unix specification IPC interface for Cygwin.
+
+ Copyright 2002 Red Hat, Inc.
+
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+
+#include <sys/types.h>
+#include <cygwin/msg.h>
+
+#include <errno.h>
+
+#include "cygerrno.h"
+
+extern "C" int
+msgctl (int msqid, int cmd, struct msqid_ds *buf)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
+
+extern "C" int
+msgget (key_t key, int msgflg)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
+
+extern "C" ssize_t
+msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
+
+extern "C" int
+msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index c310c78b3..32b4b2ef1 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -1,6 +1,6 @@
/* net.cc: network-related routines.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -21,7 +21,6 @@ details. */
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
-#include <fcntl.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock2.h>
#include "cygerrno.h"
@@ -30,10 +29,10 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "registry.h"
+#include "wsock_event.h"
extern "C" {
int h_errno;
@@ -46,23 +45,6 @@ int __stdcall rresvport (int *);
int sscanf (const char *, const char *, ...);
} /* End of "C" section */
-class wsock_event
-{
- WSAEVENT event;
- WSAOVERLAPPED ovr;
-public:
- wsock_event () : event (NULL) {};
- ~wsock_event ()
- {
- if (event)
- WSACloseEvent (event);
- event = NULL;
- };
-
- LPWSAOVERLAPPED prepare ();
- int wait (int socket, LPDWORD flags);
-};
-
LPWSAOVERLAPPED
wsock_event::prepare ()
{
@@ -88,18 +70,18 @@ wsock_event::wait (int socket, LPDWORD flags)
int ret = -1;
WSAEVENT ev[2] = { event, signal_arrived };
- switch (WSAWaitForMultipleEvents(2, ev, FALSE, WSA_INFINITE, FALSE))
+ switch (WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE, FALSE))
{
case WSA_WAIT_EVENT_0:
DWORD len;
- if (WSAGetOverlappedResult(socket, &ovr, &len, FALSE, flags))
+ if (WSAGetOverlappedResult (socket, &ovr, &len, FALSE, flags))
ret = (int) len;
break;
case WSA_WAIT_EVENT_0 + 1:
if (!CancelIo ((HANDLE)socket))
{
debug_printf ("CancelIo() %E, fallback to blocking io");
- WSAGetOverlappedResult(socket, &ovr, &len, TRUE, flags);
+ WSAGetOverlappedResult (socket, &ovr, &len, TRUE, flags);
}
else
WSASetLastError (WSAEINTR);
@@ -118,23 +100,30 @@ wsock_event::wait (int socket, LPDWORD flags)
WSADATA wsadata;
/* Cygwin internal */
+static fhandler_socket *
+get (const int fd)
+{
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return 0;
+
+ fhandler_socket *const fh = cfd->is_socket ();
+ if (!fh)
+ set_errno (ENOTSOCK);
+
+ return fh;
+}
+
+/* Cygwin internal */
static SOCKET __stdcall
set_socket_inheritance (SOCKET sock)
{
- if (wincap.has_set_handle_information ())
- (void) SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+ SOCKET osock = sock;
+ if (!DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &sock,
+ 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+ system_printf ("DuplicateHandle failed %E");
else
- {
- SOCKET newsock;
- if (!DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &newsock,
- 0, TRUE, DUPLICATE_SAME_ACCESS))
- small_printf ("DuplicateHandle failed %E");
- else
- {
- closesocket (sock);
- sock = newsock;
- }
- }
+ debug_printf ("DuplicateHandle succeeded osock %p, sock %p", osock, sock);
return sock;
}
@@ -203,6 +192,8 @@ cygwin_inet_ntoa (struct in_addr in)
extern "C" unsigned long
cygwin_inet_addr (const char *cp)
{
+ if (check_null_str_errno (cp))
+ return INADDR_NONE;
unsigned long res = inet_addr (cp);
return res;
}
@@ -213,6 +204,9 @@ cygwin_inet_addr (const char *cp)
extern "C" int
cygwin_inet_aton (const char *cp, struct in_addr *inp)
{
+ if (check_null_str_errno (cp) || check_null_invalid_struct_errno (inp))
+ return 0;
+
unsigned long res = inet_addr (cp);
if (res == INADDR_NONE && strcmp (cp, "255.255.255.255"))
return 0;
@@ -227,6 +221,8 @@ extern "C" unsigned int WINAPI inet_network (const char *);
extern "C" unsigned int
cygwin_inet_network (const char *cp)
{
+ if (check_null_str_errno (cp))
+ return INADDR_NONE;
unsigned int res = inet_network (cp);
return res;
}
@@ -240,7 +236,6 @@ inet_netof (struct in_addr in)
{
unsigned long i, res;
-
i = ntohl (in.s_addr);
if (IN_CLASSA (i))
res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT;
@@ -263,7 +258,6 @@ inet_makeaddr (int net, int lna)
unsigned long i;
struct in_addr in;
-
if (net < IN_CLASSA_MAX)
i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST);
else if (net < IN_CLASSB_MAX)
@@ -356,7 +350,7 @@ __set_winsock_errno (const char *fn, int ln)
* Since the member `s' isn't used for debug output we can use it
* for the error text returned by herror and hstrerror.
*/
-const static NO_COPY struct tl host_errmap[] =
+static NO_COPY struct tl host_errmap[] =
{
{WSAHOST_NOT_FOUND, "Unknown host", HOST_NOT_FOUND},
{WSATRY_AGAIN, "Host name lookup failure", TRY_AGAIN},
@@ -423,9 +417,9 @@ dup_addr_list (char **src, unsigned int size)
return NULL;
while (cnt-- > 0)
{
- if (!(dst[cnt] = (char *) malloc(size)))
+ if (!(dst[cnt] = (char *) malloc (size)))
return NULL;
- memcpy(dst[cnt], src[cnt], size);
+ memcpy (dst[cnt], src[cnt], size);
}
return dst;
}
@@ -481,6 +475,8 @@ out:
extern "C" struct protoent *
cygwin_getprotobyname (const char *p)
{
+ if (check_null_str_errno (p))
+ return NULL;
free_protoent_ptr (protoent_buf);
protoent_buf = dup_protoent_ptr (getprotobyname (p));
if (!protoent_buf)
@@ -504,14 +500,23 @@ cygwin_getprotobynumber (int number)
}
fhandler_socket *
-fdsock (int fd, const char *name, SOCKET soc)
+fdsock (int& fd, const char *name, SOCKET soc)
{
- if (wsadata.wVersion < 512) /* < Winsock 2.0 */
+ if (!winsock2_active)
soc = set_socket_inheritance (soc);
+ else if (wincap.has_set_handle_information ())
+ {
+ /* NT systems apparently set sockets to inheritable by default */
+ SetHandleInformation ((HANDLE)soc, HANDLE_FLAG_INHERIT, 0);
+ debug_printf ("reset socket inheritance since winsock2_active %d", winsock2_active);
+ }
+ else
+ debug_printf ("not setting socket inheritance since winsock2_active %d", winsock2_active);
fhandler_socket *fh = (fhandler_socket *) cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name);
fh->set_io_handle ((HANDLE) soc);
- fh->set_flags (O_RDWR);
- cygheap->fdtab.inc_need_fixup_before ();
+ fh->set_flags (O_RDWR | O_BINARY);
+ fh->set_r_no_interrupt (winsock2_active);
+ debug_printf ("fd %d, name '%s', soc %p", fd, name, soc);
return fh;
}
@@ -520,19 +525,16 @@ extern "C" int
cygwin_socket (int af, int type, int protocol)
{
int res = -1;
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socket");
-
- SOCKET soc;
+ SOCKET soc = 0;
+ fhandler_socket* fh = NULL;
- int fd = cygheap->fdtab.find_unused_handle ();
+ cygheap_fdnew fd;
- if (fd < 0)
- set_errno (EMFILE);
- else
+ if (fd >= 0)
{
debug_printf ("socket (%d, %d, %d)", af, type, protocol);
- soc = socket (AF_INET, type, af == AF_UNIX ? 0 : protocol);
+ soc = socket (AF_INET, type, af == AF_LOCAL ? 0 : protocol);
if (soc == INVALID_SOCKET)
{
@@ -546,222 +548,118 @@ cygwin_socket (int af, int type, int protocol)
else
name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket");
- fdsock (fd, name, soc)->set_addr_family (af);
+ fh = fdsock (fd, name, soc);
+ if (fh)
+ {
+ fh->set_addr_family (af);
+ fh->set_socket_type (type);
+ }
res = fd;
}
done:
syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol);
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socket");
return res;
}
-/* cygwin internal: map sockaddr into internet domain address */
-
-static int get_inet_addr (const struct sockaddr *in, int inlen,
- struct sockaddr_in *out, int *outlen, int* secret = 0)
-{
- int secret_buf [4];
- int* secret_ptr = (secret ? : secret_buf);
-
- if (in->sa_family == AF_INET)
- {
- *out = * (sockaddr_in *)in;
- *outlen = inlen;
- return 1;
- }
- else if (in->sa_family == AF_UNIX)
- {
- int fd = _open (in->sa_data, O_RDONLY);
- if (fd == -1)
- return 0;
-
- int ret = 0;
- char buf[128];
- memset (buf, 0, sizeof buf);
- if (read (fd, buf, sizeof buf) != -1)
- {
- sockaddr_in sin;
- sin.sin_family = AF_INET;
- sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",
- &sin.sin_port,
- secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3);
- sin.sin_port = htons (sin.sin_port);
- sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- *out = sin;
- *outlen = sizeof sin;
- ret = 1;
- }
- _close (fd);
- return ret;
- }
- else
- {
- set_errno (EAFNOSUPPORT);
- return 0;
- }
-}
-
/* exported as sendto: standards? */
extern "C" int
-cygwin_sendto (int fd,
- const void *buf,
- int len,
- unsigned int flags,
- const struct sockaddr *to,
- int tolen)
+cygwin_sendto (int fd, const void *buf, int len, int flags,
+ const struct sockaddr *to, int tolen)
{
int res;
- wsock_event wsock_evt;
- LPWSAOVERLAPPED ovr;
- fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd];
- sockaddr_in sin;
sigframe thisframe (mainthread);
- if (get_inet_addr (to, tolen, &sin, &tolen) == 0)
- return -1;
+ fhandler_socket *fh = get (fd);
- if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ()))
- {
- debug_printf ("Fallback to winsock 1 sendto call");
- if ((res = sendto (h->get_socket (), (const char *) buf, len, flags,
- to, tolen)) == SOCKET_ERROR)
- {
- set_winsock_errno ();
- res = -1;
- }
- }
- else
- {
- WSABUF wsabuf = { len, (char *) buf };
- DWORD ret = 0;
- if (WSASendTo (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags,
- to, tolen, ovr, NULL) != SOCKET_ERROR)
- res = ret;
- else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
- {
- set_winsock_errno ();
- res = -1;
- }
- else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1)
- set_winsock_errno ();
- }
+ if ((len && __check_invalid_read_ptr_errno (buf, (unsigned) len))
+ || (to &&__check_invalid_read_ptr_errno (to, tolen))
+ || !fh)
+ res = -1;
+ else if ((res = len) != 0)
+ res = fh->sendto (buf, len, flags, to, tolen);
- syscall_printf ("%d = sendto (%d, %x, %x, %x)", res, fd, buf, len, flags);
+ syscall_printf ("%d = sendto (%d, %p, %d, %x, %p, %d)",
+ res, fd, buf, len, flags, to, tolen);
return res;
}
/* exported as recvfrom: standards? */
extern "C" int
-cygwin_recvfrom (int fd,
- char *buf,
- int len,
- int flags,
- struct sockaddr *from,
- int *fromlen)
+cygwin_recvfrom (int fd, void *buf, int len, int flags,
+ struct sockaddr *from, int *fromlen)
{
int res;
- wsock_event wsock_evt;
- LPWSAOVERLAPPED ovr;
- fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd];
sigframe thisframe (mainthread);
- if (h->is_nonblocking () ||!(ovr = wsock_evt.prepare ()))
- {
- debug_printf ("Fallback to winsock 1 recvfrom call");
- if ((res = recvfrom (h->get_socket (), buf, len, flags, from, fromlen))
- == SOCKET_ERROR)
- {
- set_winsock_errno ();
- res = -1;
- }
- }
- else
- {
- WSABUF wsabuf = { len, (char *) buf };
- DWORD ret = 0;
- if (WSARecvFrom (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags,
- from, fromlen, ovr, NULL) != SOCKET_ERROR)
- res = ret;
- else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
- {
- set_winsock_errno ();
- res = -1;
- }
- else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1)
- set_winsock_errno ();
- }
+ fhandler_socket *fh = get (fd);
- syscall_printf ("%d = recvfrom (%d, %x, %x, %x)", res, fd, buf, len, flags);
+ if ((len && __check_null_invalid_struct_errno (buf, (unsigned) len))
+ || (from
+ && (check_null_invalid_struct_errno (fromlen)
+ ||__check_null_invalid_struct_errno (from, (unsigned) *fromlen)))
+ || !fh)
+ res = -1;
+ else if ((res = len) != 0)
+ res = fh->recvfrom (buf, len, flags, from, fromlen);
- return res;
-}
+ syscall_printf ("%d = recvfrom (%d, %p, %d, %x, %p, %p)",
+ res, fd, buf, len, flags, from, fromlen);
-/* Cygwin internal */
-fhandler_socket *
-get (int fd)
-{
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EINVAL);
- return 0;
- }
-
- return cygheap->fdtab[fd]->is_socket ();
+ return res;
}
/* exported as setsockopt: standards? */
extern "C" int
-cygwin_setsockopt (int fd,
- int level,
- int optname,
- const void *optval,
- int optlen)
+cygwin_setsockopt (int fd, int level, int optname, const void *optval,
+ int optlen)
{
- fhandler_socket *h = get (fd);
- int res = -1;
+ int res;
+ fhandler_socket *fh = get (fd);
const char *name = "error";
- if (h)
+ /* For the following debug_printf */
+ switch (optname)
{
- /* For the following debug_printf */
- switch (optname)
- {
- case SO_DEBUG:
- name="SO_DEBUG";
- break;
- case SO_ACCEPTCONN:
- name="SO_ACCEPTCONN";
- break;
- case SO_REUSEADDR:
- name="SO_REUSEADDR";
- break;
- case SO_KEEPALIVE:
- name="SO_KEEPALIVE";
- break;
- case SO_DONTROUTE:
- name="SO_DONTROUTE";
- break;
- case SO_BROADCAST:
- name="SO_BROADCAST";
- break;
- case SO_USELOOPBACK:
- name="SO_USELOOPBACK";
- break;
- case SO_LINGER:
- name="SO_LINGER";
- break;
- case SO_OOBINLINE:
- name="SO_OOBINLINE";
- break;
- case SO_ERROR:
- name="SO_ERROR";
- break;
- }
+ case SO_DEBUG:
+ name="SO_DEBUG";
+ break;
+ case SO_ACCEPTCONN:
+ name="SO_ACCEPTCONN";
+ break;
+ case SO_REUSEADDR:
+ name="SO_REUSEADDR";
+ break;
+ case SO_KEEPALIVE:
+ name="SO_KEEPALIVE";
+ break;
+ case SO_DONTROUTE:
+ name="SO_DONTROUTE";
+ break;
+ case SO_BROADCAST:
+ name="SO_BROADCAST";
+ break;
+ case SO_USELOOPBACK:
+ name="SO_USELOOPBACK";
+ break;
+ case SO_LINGER:
+ name="SO_LINGER";
+ break;
+ case SO_OOBINLINE:
+ name="SO_OOBINLINE";
+ break;
+ case SO_ERROR:
+ name="SO_ERROR";
+ break;
+ }
- res = setsockopt (h->get_socket (), level, optname,
- (const char *) optval, optlen);
+ if ((optval && __check_invalid_read_ptr_errno (optval, optlen)) || !fh)
+ res = -1;
+ else
+ {
+ res = setsockopt (fh->get_socket (), level, optname,
+ (const char *) optval, optlen);
if (optlen == 4)
syscall_printf ("setsockopt optval=%x", *(long *) optval);
@@ -770,61 +668,63 @@ cygwin_setsockopt (int fd,
set_winsock_errno ();
}
- syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %x, %d)",
+ syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %p, %d)",
res, fd, level, optname, name, optval, optlen);
return res;
}
/* exported as getsockopt: standards? */
extern "C" int
-cygwin_getsockopt (int fd,
- int level,
- int optname,
- void *optval,
- int *optlen)
+cygwin_getsockopt (int fd, int level, int optname, void *optval, int *optlen)
{
- fhandler_socket *h = get (fd);
- int res = -1;
+ int res;
+ fhandler_socket *fh = get (fd);
const char *name = "error";
- if (h)
+
+ /* For the following debug_printf */
+ switch (optname)
{
- /* For the following debug_printf */
- switch (optname)
- {
- case SO_DEBUG:
- name="SO_DEBUG";
- break;
- case SO_ACCEPTCONN:
- name="SO_ACCEPTCONN";
- break;
- case SO_REUSEADDR:
- name="SO_REUSEADDR";
- break;
- case SO_KEEPALIVE:
- name="SO_KEEPALIVE";
- break;
- case SO_DONTROUTE:
- name="SO_DONTROUTE";
- break;
- case SO_BROADCAST:
- name="SO_BROADCAST";
- break;
- case SO_USELOOPBACK:
- name="SO_USELOOPBACK";
- break;
- case SO_LINGER:
- name="SO_LINGER";
- break;
- case SO_OOBINLINE:
- name="SO_OOBINLINE";
- break;
- case SO_ERROR:
- name="SO_ERROR";
- break;
- }
+ case SO_DEBUG:
+ name="SO_DEBUG";
+ break;
+ case SO_ACCEPTCONN:
+ name="SO_ACCEPTCONN";
+ break;
+ case SO_REUSEADDR:
+ name="SO_REUSEADDR";
+ break;
+ case SO_KEEPALIVE:
+ name="SO_KEEPALIVE";
+ break;
+ case SO_DONTROUTE:
+ name="SO_DONTROUTE";
+ break;
+ case SO_BROADCAST:
+ name="SO_BROADCAST";
+ break;
+ case SO_USELOOPBACK:
+ name="SO_USELOOPBACK";
+ break;
+ case SO_LINGER:
+ name="SO_LINGER";
+ break;
+ case SO_OOBINLINE:
+ name="SO_OOBINLINE";
+ break;
+ case SO_ERROR:
+ name="SO_ERROR";
+ break;
+ }
- res = getsockopt (h->get_socket (), level, optname,
- (char *) optval, (int *) optlen);
+ if ((optval
+ && (check_null_invalid_struct_errno (optlen)
+ || __check_null_invalid_struct_errno (optval, (unsigned) *optlen)))
+ || !fh)
+ res = -1;
+ else
+ {
+ res = getsockopt (fh->get_socket (), level, optname, (char *) optval,
+ (int *) optlen);
if (optname == SO_ERROR)
{
@@ -836,83 +736,27 @@ cygwin_getsockopt (int fd,
set_winsock_errno ();
}
- syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %x, %d)",
+ syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %p, %p)",
res, fd, level, optname, name, optval, optlen);
return res;
}
/* exported as connect: standards? */
extern "C" int
-cygwin_connect (int fd,
- const struct sockaddr *name,
- int namelen)
+cygwin_connect (int fd, const struct sockaddr *name, int namelen)
{
int res;
- BOOL secret_check_failed = FALSE;
- BOOL in_progress = FALSE;
- fhandler_socket *sock = get (fd);
- sockaddr_in sin;
- int secret [4];
sigframe thisframe (mainthread);
- if (get_inet_addr (name, namelen, &sin, &namelen, secret) == 0)
- return -1;
+ fhandler_socket *fh = get (fd);
- if (!sock)
- {
- res = -1;
- }
+ if (__check_invalid_read_ptr_errno (name, namelen) || !fh)
+ res = -1;
else
- {
- res = connect (sock->get_socket (), (sockaddr *) &sin, namelen);
- if (res)
- {
- /* Special handling for connect to return the correct error code
- when called on a non-blocking socket. */
- if (sock->is_nonblocking ())
- {
- DWORD err = WSAGetLastError ();
- if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
- {
- WSASetLastError (WSAEINPROGRESS);
- in_progress = TRUE;
- }
- else if (err == WSAEINVAL)
- WSASetLastError (WSAEISCONN);
- }
- set_winsock_errno ();
- }
- if (sock->get_addr_family () == AF_UNIX)
- {
- if (!res || in_progress)
- {
- if (!sock->create_secret_event (secret))
- {
- secret_check_failed = TRUE;
- }
- else if (in_progress)
- sock->signal_secret_event ();
- }
+ res = fh->connect (name, namelen);
- if (!secret_check_failed && !res)
- {
- if (!sock->check_peer_secret_event (&sin, secret))
- {
- debug_printf ( "accept from unauthorized server" );
- secret_check_failed = TRUE;
- }
- }
+ syscall_printf ("%d = connect (%d, %p, %d)", res, fd, name, namelen);
- if (secret_check_failed)
- {
- sock->close_secret_event ();
- if (res)
- closesocket (res);
- set_errno (ECONNREFUSED);
- res = -1;
- }
- }
- }
return res;
}
@@ -987,6 +831,10 @@ out:
extern "C" struct servent *
cygwin_getservbyname (const char *name, const char *proto)
{
+ if (check_null_str_errno (name)
+ || (proto != NULL && check_null_str_errno (proto)))
+ return NULL;
+
free_servent_ptr (servent_buf);
servent_buf = dup_servent_ptr (getservbyname (name, proto));
if (!servent_buf)
@@ -1000,6 +848,9 @@ cygwin_getservbyname (const char *name, const char *proto)
extern "C" struct servent *
cygwin_getservbyport (int port, const char *proto)
{
+ if (proto != NULL && check_null_str_errno (proto))
+ return NULL;
+
free_servent_ptr (servent_buf);
servent_buf = dup_servent_ptr (getservbyport (port, proto));
if (!servent_buf)
@@ -1014,6 +865,9 @@ cygwin_gethostname (char *name, size_t len)
{
int PASCAL win32_gethostname (char*, int);
+ if (__check_null_invalid_struct_errno (name, len))
+ return -1;
+
if (wsock32_handle == NULL ||
win32_gethostname (name, len) == SOCKET_ERROR)
{
@@ -1092,6 +946,9 @@ cygwin_gethostbyname (const char *name)
static char *tmp_addr_list[2];
static int a, b, c, d;
+ if (check_null_str_errno (name))
+ return NULL;
+
if (sscanf (name, "%d.%d.%d.%d", &a, &b, &c, &d) == 4)
{
/* In case you don't have DNS, at least x.x.x.x still works */
@@ -1100,7 +957,7 @@ cygwin_gethostbyname (const char *name)
tmp_addr[1] = b;
tmp_addr[2] = c;
tmp_addr[3] = d;
- tmp_addr_list[0] = (char *)tmp_addr;
+ tmp_addr_list[0] = (char *) tmp_addr;
tmp.h_name = name;
tmp.h_aliases = tmp_aliases;
tmp.h_addrtype = 2;
@@ -1128,6 +985,9 @@ cygwin_gethostbyname (const char *name)
extern "C" struct hostent *
cygwin_gethostbyaddr (const char *addr, int len, int type)
{
+ if (__check_invalid_read_ptr_errno (addr, len))
+ return NULL;
+
free_hostent_ptr (hostent_buf);
hostent_buf = dup_hostent_ptr (gethostbyaddr (addr, len, type));
if (!hostent_buf)
@@ -1147,91 +1007,19 @@ cygwin_gethostbyaddr (const char *addr, int len, int type)
extern "C" int
cygwin_accept (int fd, struct sockaddr *peer, int *len)
{
- int res = -1;
- BOOL secret_check_failed = FALSE;
- BOOL in_progress = FALSE;
+ int res;
sigframe thisframe (mainthread);
- fhandler_socket *sock = get (fd);
- if (sock)
- {
- /* Allows NULL peer and len parameters. */
- struct sockaddr_in peer_dummy;
- int len_dummy;
- if (!peer)
- peer = (struct sockaddr *) &peer_dummy;
- if (!len)
- {
- len_dummy = sizeof (struct sockaddr_in);
- len = &len_dummy;
- }
-
- /* accept on NT fails if len < sizeof (sockaddr_in)
- * some programs set len to
- * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain
- */
- if (len && ((unsigned) *len < sizeof (struct sockaddr_in)))
- *len = sizeof (struct sockaddr_in);
-
- res = accept (sock->get_socket (), peer, len); // can't use a blocking call inside a lock
+ fhandler_socket *fh = get (fd);
- if ((SOCKET) res == (SOCKET) INVALID_SOCKET &&
- WSAGetLastError () == WSAEWOULDBLOCK)
- in_progress = TRUE;
-
- if (sock->get_addr_family () == AF_UNIX)
- {
- if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress)
- {
- if (!sock->create_secret_event ())
- secret_check_failed = TRUE;
- else if (in_progress)
- sock->signal_secret_event ();
- }
-
- if (!secret_check_failed &&
- (SOCKET) res != (SOCKET) INVALID_SOCKET)
- {
- if (!sock->check_peer_secret_event ((struct sockaddr_in*) peer))
- {
- debug_printf ("connect from unauthorized client");
- secret_check_failed = TRUE;
- }
- }
-
- if (secret_check_failed)
- {
- sock->close_secret_event ();
- if ((SOCKET) res != (SOCKET) INVALID_SOCKET)
- closesocket (res);
- set_errno (ECONNABORTED);
- res = -1;
- goto done;
- }
- }
-
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
+ if ((peer && (check_null_invalid_struct_errno (len)
+ || __check_null_invalid_struct_errno (peer, (unsigned) *len)))
+ || !fh)
+ res = -1;
+ else
+ res = fh->accept (peer, len);
- int res_fd = cygheap->fdtab.find_unused_handle ();
- if (res_fd == -1)
- {
- /* FIXME: what is correct errno? */
- set_errno (EMFILE);
- goto lock_done;
- }
- if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
- set_winsock_errno ();
- else
- {
- fhandler_socket* res_fh = fdsock (res_fd, sock->get_name (), res);
- res_fh->set_addr_family (sock->get_addr_family ());
- res = res_fd;
- }
- }
-lock_done:
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
-done:
- syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len);
+ syscall_printf ("%d = accept (%d, %p, %p)", res, fd, peer, len);
return res;
}
@@ -1239,85 +1027,15 @@ done:
extern "C" int
cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen)
{
- int res = -1;
-
- fhandler_socket *sock = get (fd);
- if (sock)
- {
- if (my_addr->sa_family == AF_UNIX)
- {
-#define un_addr ((struct sockaddr_un *) my_addr)
- struct sockaddr_in sin;
- int len = sizeof sin;
- int fd;
-
- if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN)
- {
- set_errno (ENAMETOOLONG);
- goto out;
- }
- sin.sin_family = AF_INET;
- sin.sin_port = 0;
- sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- if (bind (sock->get_socket (), (sockaddr *) &sin, len))
- {
- syscall_printf ("AF_UNIX: bind failed %d", get_errno ());
- set_winsock_errno ();
- goto out;
- }
- if (getsockname (sock->get_socket (), (sockaddr *) &sin, &len))
- {
- syscall_printf ("AF_UNIX: getsockname failed %d", get_errno ());
- set_winsock_errno ();
- goto out;
- }
-
- sin.sin_port = ntohs (sin.sin_port);
- debug_printf ("AF_UNIX: socket bound to port %u", sin.sin_port);
-
- /* bind must fail if file system socket object already exists
- so _open () is called with O_EXCL flag. */
- fd = _open (un_addr->sun_path,
- O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
- 0);
- if (fd < 0)
- {
- if (get_errno () == EEXIST)
- set_errno (EADDRINUSE);
- goto out;
- }
-
- sock->set_connect_secret ();
-
- char buf[sizeof (SOCKET_COOKIE) + 80];
- __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);
- sock->get_connect_secret (strchr (buf, '\0'));
- len = strlen (buf) + 1;
+ int res;
+ fhandler_socket *fh = get (fd);
- /* Note that the terminating nul is written. */
- if (_write (fd, buf, len) != len)
- {
- save_errno here;
- _close (fd);
- _unlink (un_addr->sun_path);
- }
- else
- {
- _close (fd);
- chmod (un_addr->sun_path,
- (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask);
- res = 0;
- }
-#undef un_addr
- }
- else if (bind (sock->get_socket (), my_addr, addrlen))
- set_winsock_errno ();
- else
- res = 0;
- }
+ if (__check_invalid_read_ptr_errno (my_addr, addrlen) || !fh)
+ res = -1;
+ else
+ res = fh->bind (my_addr, addrlen);
-out:
- syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen);
+ syscall_printf ("%d = bind (%d, %p, %d)", res, fd, my_addr, addrlen);
return res;
}
@@ -1325,17 +1043,19 @@ out:
extern "C" int
cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen)
{
- int res = -1;
+ int res;
+ sigframe thisframe (mainthread);
- fhandler_socket *sock = get (fd);
- if (sock)
- {
- res = getsockname (sock->get_socket (), addr, namelen);
- if (res)
- set_winsock_errno ();
+ fhandler_socket *fh = get (fd);
- }
- syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen);
+ if (check_null_invalid_struct_errno (namelen)
+ || __check_null_invalid_struct_errno (addr, (unsigned) *namelen)
+ || !fh)
+ res = -1;
+ else
+ res = fh->getsockname (addr, namelen);
+
+ syscall_printf ("%d = getsockname (%d, %p, %p)", res, fd, addr, namelen);
return res;
}
@@ -1343,16 +1063,14 @@ cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen)
extern "C" int
cygwin_listen (int fd, int backlog)
{
- int res = -1;
+ int res;
+ fhandler_socket *fh = get (fd);
+ if (!fh)
+ res = -1;
+ else
+ res = fh->listen (backlog);
- fhandler_socket *sock = get (fd);
- if (sock)
- {
- res = listen (sock->get_socket (), backlog);
- if (res)
- set_winsock_errno ();
- }
syscall_printf ("%d = listen (%d, %d)", res, fd, backlog);
return res;
}
@@ -1361,30 +1079,16 @@ cygwin_listen (int fd, int backlog)
extern "C" int
cygwin_shutdown (int fd, int how)
{
- int res = -1;
+ int res;
sigframe thisframe (mainthread);
- fhandler_socket *sock = get (fd);
- if (sock)
- {
- res = shutdown (sock->get_socket (), how);
- if (res)
- set_winsock_errno ();
- else
- switch (how)
- {
- case SHUT_RD:
- sock->set_shutdown_read ();
- break;
- case SHUT_WR:
- sock->set_shutdown_write ();
- break;
- case SHUT_RDWR:
- sock->set_shutdown_read ();
- sock->set_shutdown_write ();
- break;
- }
- }
+ fhandler_socket *fh = get (fd);
+
+ if (!fh)
+ res = -1;
+ else
+ res = fh->shutdown (how);
+
syscall_printf ("%d = shutdown (%d, %d)", res, fd, how);
return res;
}
@@ -1406,6 +1110,8 @@ cygwin_hstrerror (int err)
extern "C" void
cygwin_herror (const char *s)
{
+ if (s && check_null_str (s))
+ return;
if (cygheap->fdtab.not_open (2))
return;
@@ -1438,102 +1144,39 @@ cygwin_herror (const char *s)
extern "C" int
cygwin_getpeername (int fd, struct sockaddr *name, int *len)
{
- fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd];
+ int res;
+ sigframe thisframe (mainthread);
- debug_printf ("getpeername %d", h->get_socket ());
- int res = getpeername (h->get_socket (), name, len);
- if (res)
- set_winsock_errno ();
+ fhandler_socket *fh = get (fd);
+
+ if (check_null_invalid_struct_errno (len)
+ || __check_null_invalid_struct_errno (name, (unsigned) *len)
+ || !fh)
+ res = -1;
+ else
+ res = fh->getpeername (name, len);
- debug_printf ("%d = getpeername %d", res, h->get_socket ());
+ syscall_printf ("%d = getpeername %d", res, (fh ? fh->get_socket () : -1));
return res;
}
/* exported as recv: standards? */
extern "C" int
-cygwin_recv (int fd, void *buf, int len, unsigned int flags)
+cygwin_recv (int fd, void *buf, int len, int flags)
{
- int res;
- wsock_event wsock_evt;
- LPWSAOVERLAPPED ovr;
- fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd];
- sigframe thisframe (mainthread);
-
- if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ()))
- {
- debug_printf ("Fallback to winsock 1 recv call");
- if ((res = recv (h->get_socket (), (char *) buf, len, flags))
- == SOCKET_ERROR)
- {
- set_winsock_errno ();
- res = -1;
- }
- }
- else
- {
- WSABUF wsabuf = { len, (char *) buf };
- DWORD ret = 0;
- if (WSARecv (h->get_socket (), &wsabuf, 1, &ret, (DWORD *)&flags,
- ovr, NULL) != SOCKET_ERROR)
- res = ret;
- else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
- {
- set_winsock_errno ();
- res = -1;
- }
- else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1)
- set_winsock_errno ();
- }
-
- syscall_printf ("%d = recv (%d, %x, %x, %x)", res, fd, buf, len, flags);
-
- return res;
+ return cygwin_recvfrom (fd, buf, len, flags, NULL, NULL);
}
/* exported as send: standards? */
extern "C" int
-cygwin_send (int fd, const void *buf, int len, unsigned int flags)
+cygwin_send (int fd, const void *buf, int len, int flags)
{
- int res;
- wsock_event wsock_evt;
- LPWSAOVERLAPPED ovr;
- fhandler_socket *h = (fhandler_socket *) cygheap->fdtab[fd];
- sigframe thisframe (mainthread);
-
- if (h->is_nonblocking () || !(ovr = wsock_evt.prepare ()))
- {
- debug_printf ("Fallback to winsock 1 send call");
- if ((res = send (h->get_socket (), (const char *) buf, len, flags))
- == SOCKET_ERROR)
- {
- set_winsock_errno ();
- res = -1;
- }
- }
- else
- {
- WSABUF wsabuf = { len, (char *) buf };
- DWORD ret = 0;
- if (WSASend (h->get_socket (), &wsabuf, 1, &ret, (DWORD)flags,
- ovr, NULL) != SOCKET_ERROR)
- res = ret;
- else if ((res = WSAGetLastError ()) != WSA_IO_PENDING)
- {
- set_winsock_errno ();
- res = -1;
- }
- else if ((res = wsock_evt.wait (h->get_socket (), (DWORD *)&flags)) == -1)
- set_winsock_errno ();
- }
-
- syscall_printf ("%d = send (%d, %x, %d, %x)", res, fd, buf, len, flags);
-
- return res;
+ return cygwin_sendto (fd, buf, len, flags, NULL, 0);
}
/* getdomainname: standards? */
extern "C" int
-getdomainname (char *domain, int len)
+getdomainname (char *domain, size_t len)
{
/*
* This works for Win95 only if the machine is configured to use MS-TCP.
@@ -1542,10 +1185,14 @@ getdomainname (char *domain, int len)
* in use and include paths for the Domain name in each ?
* Punt for now and assume MS-TCP on Win95.
*/
+ if (__check_null_invalid_struct_errno (domain, len))
+ return -1;
+
reg_key r (HKEY_LOCAL_MACHINE, KEY_READ,
(!wincap.is_winnt ()) ? "System" : "SYSTEM",
"CurrentControlSet", "Services",
- (!wincap.is_winnt ()) ? "MSTCP" : "Tcpip",
+ (!wincap.is_winnt ()) ? "VxD" : "Tcpip",
+ (!wincap.is_winnt ()) ? "MSTCP" : "Parameters",
NULL);
/* FIXME: Are registry keys case sensitive? */
@@ -1569,7 +1216,7 @@ static void
get_2k_ifconf (struct ifconf *ifc, int what)
{
int cnt = 0;
- char eth[2] = "/", ppp[2] = "/", slp[2] = "/";
+ char eth[2] = "/", ppp[2] = "/", slp[2] = "/", sub[2] = "0", tok[2] = "/";
/* Union maps buffer to correct struct */
struct ifreq *ifr = ifc->ifc_req;
@@ -1582,91 +1229,110 @@ get_2k_ifconf (struct ifconf *ifc, int what)
struct sockaddr_in *sa = NULL;
struct sockaddr *so = NULL;
- if (GetIfTable(NULL, &siz_if_table, TRUE) == ERROR_INSUFFICIENT_BUFFER &&
- GetIpAddrTable(NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER &&
+ if (GetIfTable (NULL, &siz_if_table, TRUE) == ERROR_INSUFFICIENT_BUFFER &&
+ GetIpAddrTable (NULL, &siz_ip_table, TRUE) == ERROR_INSUFFICIENT_BUFFER &&
(ift = (PMIB_IFTABLE) alloca (siz_if_table)) &&
(ipt = (PMIB_IPADDRTABLE) alloca (siz_ip_table)) &&
- !GetIfTable(ift, &siz_if_table, TRUE) &&
- !GetIpAddrTable(ipt, &siz_ip_table, TRUE))
+ !GetIfTable (ift, &siz_if_table, TRUE) &&
+ !GetIpAddrTable (ipt, &siz_ip_table, TRUE))
{
+ /* Iterate over all known interfaces */
for (if_cnt = 0; if_cnt < ift->dwNumEntries; ++if_cnt)
{
- switch (ift->table[if_cnt].dwType)
- {
- case MIB_IF_TYPE_ETHERNET:
- ++*eth;
- strcpy (ifr->ifr_name, "eth");
- strcat (ifr->ifr_name, eth);
- break;
- case MIB_IF_TYPE_PPP:
- ++*ppp;
- strcpy (ifr->ifr_name, "ppp");
- strcat (ifr->ifr_name, ppp);
- break;
- case MIB_IF_TYPE_SLIP:
- ++*slp;
- strcpy (ifr->ifr_name, "slp");
- strcat (ifr->ifr_name, slp);
- break;
- case MIB_IF_TYPE_LOOPBACK:
- strcpy (ifr->ifr_name, "lo");
- break;
- default:
- continue;
- }
+ *sub = '0';
+ /* Iterate over all configured IP-addresses */
for (ip_cnt = 0; ip_cnt < ipt->dwNumEntries; ++ip_cnt)
- if (ipt->table[ip_cnt].dwIndex == ift->table[if_cnt].dwIndex)
- {
- switch (what)
- {
- case SIOCGIFCONF:
- case SIOCGIFADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_addr;
- sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFBRDADDR:
- sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
+ {
+ /* Does the IP address belong to the interface? */
+ if (ipt->table[ip_cnt].dwIndex == ift->table[if_cnt].dwIndex)
+ {
+ /* Setup the interface name */
+ switch (ift->table[if_cnt].dwType)
+ {
+ case MIB_IF_TYPE_TOKENRING:
+ ++*tok;
+ strcpy (ifr->ifr_name, "tok");
+ strcat (ifr->ifr_name, tok);
+ break;
+ case MIB_IF_TYPE_ETHERNET:
+ if (*sub == '0')
+ ++*eth;
+ strcpy (ifr->ifr_name, "eth");
+ strcat (ifr->ifr_name, eth);
+ break;
+ case MIB_IF_TYPE_PPP:
+ ++*ppp;
+ strcpy (ifr->ifr_name, "ppp");
+ strcat (ifr->ifr_name, ppp);
+ break;
+ case MIB_IF_TYPE_SLIP:
+ ++*slp;
+ strcpy (ifr->ifr_name, "slp");
+ strcat (ifr->ifr_name, slp);
+ break;
+ case MIB_IF_TYPE_LOOPBACK:
+ strcpy (ifr->ifr_name, "lo");
+ break;
+ default:
+ continue;
+ }
+ if (*sub > '0')
+ {
+ strcat (ifr->ifr_name, ":");
+ strcat (ifr->ifr_name, sub);
+ }
+ ++*sub;
+ /* setup sockaddr struct */
+ switch (what)
+ {
+ case SIOCGIFCONF:
+ case SIOCGIFADDR:
+ sa = (struct sockaddr_in *) &ifr->ifr_addr;
+ sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr;
+ sa->sin_family = AF_INET;
+ sa->sin_port = 0;
+ break;
+ case SIOCGIFBRDADDR:
+ sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
#if 0
- /* Unfortunately, the field returns only crap. */
- sa->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr;
+ /* Unfortunately, the field returns only crap. */
+ sa->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr;
#else
- lip = ipt->table[ip_cnt].dwAddr;
- lnp = ipt->table[ip_cnt].dwMask;
- sa->sin_addr.s_addr = lip & lnp | ~lnp;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
+ lip = ipt->table[ip_cnt].dwAddr;
+ lnp = ipt->table[ip_cnt].dwMask;
+ sa->sin_addr.s_addr = lip & lnp | ~lnp;
+ sa->sin_family = AF_INET;
+ sa->sin_port = 0;
#endif
- break;
- case SIOCGIFNETMASK:
- sa = (struct sockaddr_in *) &ifr->ifr_netmask;
- sa->sin_addr.s_addr = ipt->table[ip_cnt].dwMask;
- sa->sin_family = AF_INET;
- sa->sin_port = 0;
- break;
- case SIOCGIFHWADDR:
- so = &ifr->ifr_hwaddr;
- for (UINT i = 0; i < IFHWADDRLEN; ++i)
- if (i >= ift->table[if_cnt].dwPhysAddrLen)
- so->sa_data[i] = '\0';
- else
- so->sa_data[i] = ift->table[if_cnt].bPhysAddr[i];
- so->sa_family = AF_INET;
- break;
- case SIOCGIFMETRIC:
- ifr->ifr_metric = 1;
- break;
- case SIOCGIFMTU:
- ifr->ifr_mtu = ift->table[if_cnt].dwMtu;
- break;
- }
- ++cnt;
- if ((caddr_t) ++ifr >
- ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
- goto done;
- break;
- }
+ break;
+ case SIOCGIFNETMASK:
+ sa = (struct sockaddr_in *) &ifr->ifr_netmask;
+ sa->sin_addr.s_addr = ipt->table[ip_cnt].dwMask;
+ sa->sin_family = AF_INET;
+ sa->sin_port = 0;
+ break;
+ case SIOCGIFHWADDR:
+ so = &ifr->ifr_hwaddr;
+ for (UINT i = 0; i < IFHWADDRLEN; ++i)
+ if (i >= ift->table[if_cnt].dwPhysAddrLen)
+ so->sa_data[i] = '\0';
+ else
+ so->sa_data[i] = ift->table[if_cnt].bPhysAddr[i];
+ so->sa_family = AF_INET;
+ break;
+ case SIOCGIFMETRIC:
+ ifr->ifr_metric = 1;
+ break;
+ case SIOCGIFMTU:
+ ifr->ifr_mtu = ift->table[if_cnt].dwMtu;
+ break;
+ }
+ ++cnt;
+ if ((caddr_t) ++ifr >
+ ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
+ goto done;
+ }
+ }
}
}
done:
@@ -1921,7 +1587,7 @@ get_95_ifconf (struct ifconf *ifc, int what)
++i)
{
HKEY ifkey, subkey;
- char driver[256], classname[256], bindname[256], netname[256];
+ char driver[256], classname[256], netname[256];
char adapter[256], ip[256], np[256];
if (res != ERROR_SUCCESS
@@ -1997,57 +1663,34 @@ get_95_ifconf (struct ifconf *ifc, int what)
RegCloseKey (subkey);
- if (RegOpenKeyEx (ifkey, "Bindings",
- 0, KEY_READ, &subkey) != ERROR_SUCCESS)
- {
+ strcpy (netname, "System\\CurrentControlSet\\Services\\Class\\Net\\");
+ strcat (netname, ifname);
+
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, netname,
+ 0, KEY_READ, &subkey) != ERROR_SUCCESS)
+ {
RegCloseKey (ifkey);
--ifr;
continue;
- }
-
- for (int j = 0;
- (res = RegEnumValue (subkey, j, bindname,
- (size = sizeof bindname, &size),
- 0, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS;
- ++j)
- if (!strncasecmp (bindname, "VREDIR\\", 7))
- break;
-
- RegCloseKey (subkey);
-
- if (res == ERROR_SUCCESS)
- {
- strcpy (netname, "System\\CurrentControlSet\\Services\\Class\\Net\\");
- strcat (netname, bindname + 7);
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, netname,
- 0, KEY_READ, &subkey) != ERROR_SUCCESS)
- {
- RegCloseKey (ifkey);
- --ifr;
- continue;
- }
+ }
- if (RegQueryValueEx (subkey, "AdapterName", 0,
- NULL, (unsigned char *) adapter,
- (size = sizeof adapter, &size)) == ERROR_SUCCESS
+ if (RegQueryValueEx (subkey, "AdapterName", 0,
+ NULL, (unsigned char *) adapter,
+ (size = sizeof adapter, &size)) == ERROR_SUCCESS
&& strcasematch (adapter, "MS$PPP"))
- {
- ++*ppp;
- strcpy (ifr->ifr_name, "ppp");
- strcat (ifr->ifr_name, ppp);
- }
- else
- {
- ++*eth;
- strcpy (ifr->ifr_name, "eth");
- strcat (ifr->ifr_name, eth);
- }
-
- RegCloseKey (subkey);
-
- }
+ {
+ ++*ppp;
+ strcpy (ifr->ifr_name, "ppp");
+ strcat (ifr->ifr_name, ppp);
+ }
+ else
+ {
+ ++*eth;
+ strcpy (ifr->ifr_name, "eth");
+ strcat (ifr->ifr_name, eth);
+ }
+ RegCloseKey (subkey);
RegCloseKey (ifkey);
++cnt;
@@ -2067,6 +1710,9 @@ get_ifconf (struct ifconf *ifc, int what)
unsigned long lip, lnp;
struct sockaddr_in *sa;
+ if (check_null_invalid_struct_errno (ifc))
+ return -1;
+
/* Union maps buffer to correct struct */
struct ifreq *ifr = ifc->ifc_req;
@@ -2141,18 +1787,25 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser,
SOCKET fd2s;
sigframe thisframe (mainthread);
- int res_fd = cygheap->fdtab.find_unused_handle ();
- if (res_fd == -1)
+ if (check_null_invalid_struct_errno (ahost) ||
+ check_null_empty_str_errno (*ahost) ||
+ (locuser && check_null_empty_str_errno (locuser)) ||
+ (remuser && check_null_str_errno (remuser)))
+ return (int) INVALID_SOCKET;
+
+ cygheap_fdnew res_fd;
+ if (res_fd < 0)
goto done;
if (fd2p)
{
- *fd2p = cygheap->fdtab.find_unused_handle (res_fd + 1);
- if (*fd2p == -1)
+ cygheap_fdnew newfd (res_fd, false);
+ if (*fd2p < 0)
goto done;
+ *fd2p = newfd;
}
- res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p? &fd2s: NULL);
+ res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p ? &fd2s : NULL);
if (res == (int) INVALID_SOCKET)
goto done;
else
@@ -2160,10 +1813,10 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser,
fdsock (res_fd, "/dev/tcp", res);
res = res_fd;
}
+
if (fd2p)
- {
- fdsock (*fd2p, "/dev/tcp", fd2s);
- }
+ fdsock (*fd2p, "/dev/tcp", fd2s);
+
done:
syscall_printf ("%d = rcmd (...)", res);
return res;
@@ -2173,22 +1826,26 @@ done:
extern "C" int
cygwin_rresvport (int *port)
{
- int res = -1;
+ int res;
sigframe thisframe (mainthread);
- int res_fd = cygheap->fdtab.find_unused_handle ();
- if (res_fd == -1)
- goto done;
- res = rresvport (port);
+ if (check_null_invalid_struct_errno (port))
+ return -1;
- if (res == (int) INVALID_SOCKET)
- goto done;
+ cygheap_fdnew res_fd;
+ if (res_fd < 0)
+ res = -1;
else
{
- fdsock (res_fd, "/dev/tcp", res);
- res = res_fd;
+ res = rresvport (port);
+
+ if (res != (int) INVALID_SOCKET)
+ {
+ fdsock (res_fd, "/dev/tcp", res);
+ res = res_fd;
+ }
}
-done:
+
syscall_printf ("%d = rresvport (%d)", res, port ? *port : 0);
return res;
}
@@ -2202,14 +1859,21 @@ cygwin_rexec (char **ahost, unsigned short inport, char *locuser,
SOCKET fd2s;
sigframe thisframe (mainthread);
- int res_fd = cygheap->fdtab.find_unused_handle ();
- if (res_fd == -1)
+ if (check_null_invalid_struct_errno (ahost) ||
+ check_null_empty_str_errno (*ahost) ||
+ (locuser && check_null_empty_str_errno (locuser)) ||
+ (password && check_null_str_errno (password)))
+ return (int) INVALID_SOCKET;
+
+ cygheap_fdnew res_fd;
+ if (res_fd < 0)
goto done;
if (fd2p)
{
- *fd2p = cygheap->fdtab.find_unused_handle (res_fd + 1);
- if (*fd2p == -1)
+ cygheap_fdnew newfd (res_fd);
+ if (newfd < 0)
goto done;
+ *fd2p = newfd;
}
res = rexec (ahost, inport, locuser, password, cmd, fd2p ? &fd2s : NULL);
if (res == (int) INVALID_SOCKET)
@@ -2230,29 +1894,48 @@ done:
/* socketpair: standards? */
/* Win32 supports AF_INET only, so ignore domain and protocol arguments */
extern "C" int
-socketpair (int, int type, int, int *sb)
+socketpair (int family, int type, int protocol, int *sb)
{
int res = -1;
SOCKET insock, outsock, newsock;
- struct sockaddr_in sock_in;
- int len = sizeof (sock_in);
+ struct sockaddr_in sock_in, sock_out;
+ int len;
+ cygheap_fdnew sb0;
+ fhandler_socket *fh;
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socketpair");
+ if (__check_null_invalid_struct_errno (sb, 2 * sizeof (int)))
+ return -1;
- sb[0] = cygheap->fdtab.find_unused_handle ();
- if (sb[0] == -1)
+ if (family != AF_LOCAL && family != AF_INET)
+ {
+ set_errno (EAFNOSUPPORT);
+ goto done;
+ }
+ if (type != SOCK_STREAM && type != SOCK_DGRAM)
{
- set_errno (EMFILE);
+ set_errno (EPROTOTYPE);
goto done;
}
- sb[1] = cygheap->fdtab.find_unused_handle (sb[0] + 1);
- if (sb[1] == -1)
+ if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL)
+ || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET))
{
- set_errno (EMFILE);
+ set_errno (EPROTONOSUPPORT);
goto done;
}
- /* create a listening socket */
+ if (sb0 < 0)
+ goto done;
+ else
+ {
+ sb[0] = sb0;
+ cygheap_fdnew sb1 (sb0, false);
+ if (sb1 < 0)
+ goto done;
+
+ sb[1] = sb1;
+ }
+
+ /* create the first socket */
newsock = socket (AF_INET, type, 0);
if (newsock == INVALID_SOCKET)
{
@@ -2265,7 +1948,6 @@ socketpair (int, int type, int, int *sb)
sock_in.sin_family = AF_INET;
sock_in.sin_port = 0;
sock_in.sin_addr.s_addr = INADDR_ANY;
-
if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
{
debug_printf ("bind failed");
@@ -2273,7 +1955,7 @@ socketpair (int, int type, int, int *sb)
closesocket (newsock);
goto done;
}
-
+ len = sizeof (sock_in);
if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0)
{
debug_printf ("getsockname error");
@@ -2282,7 +1964,9 @@ socketpair (int, int type, int, int *sb)
goto done;
}
- listen (newsock, 2);
+ /* For stream sockets, create a listener */
+ if (type == SOCK_STREAM)
+ listen (newsock, 2);
/* create a connecting socket */
outsock = socket (AF_INET, type, 0);
@@ -2294,9 +1978,37 @@ socketpair (int, int type, int, int *sb)
goto done;
}
+ /* For datagram sockets, bind the 2nd socket to an unused address, too */
+ if (type == SOCK_DGRAM)
+ {
+ sock_out.sin_family = AF_INET;
+ sock_out.sin_port = 0;
+ sock_out.sin_addr.s_addr = INADDR_ANY;
+ if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0)
+ {
+ debug_printf ("bind failed");
+ set_winsock_errno ();
+ closesocket (newsock);
+ closesocket (outsock);
+ goto done;
+ }
+ len = sizeof (sock_out);
+ if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0)
+ {
+ debug_printf ("getsockname error");
+ set_winsock_errno ();
+ closesocket (newsock);
+ closesocket (outsock);
+ goto done;
+ }
+ }
+
+ /* Force IP address to loopback */
sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ if (type == SOCK_DGRAM)
+ sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- /* Do a connect and accept the connection */
+ /* Do a connect */
if (connect (outsock, (struct sockaddr *) &sock_in,
sizeof (sock_in)) < 0)
{
@@ -2307,26 +2019,68 @@ socketpair (int, int type, int, int *sb)
goto done;
}
- insock = accept (newsock, (struct sockaddr *) &sock_in, &len);
- if (insock == INVALID_SOCKET)
+ if (type == SOCK_STREAM)
{
- debug_printf ("accept error");
- set_winsock_errno ();
+ /* For stream sockets, accept the connection and close the listener */
+ len = sizeof (sock_in);
+ insock = accept (newsock, (struct sockaddr *) &sock_in, &len);
+ if (insock == INVALID_SOCKET)
+ {
+ debug_printf ("accept error");
+ set_winsock_errno ();
+ closesocket (newsock);
+ closesocket (outsock);
+ goto done;
+ }
closesocket (newsock);
- closesocket (outsock);
- goto done;
+ }
+ else
+ {
+ /* For datagram sockets, connect the 2nd socket */
+ if (connect (newsock, (struct sockaddr *) &sock_out,
+ sizeof (sock_out)) < 0)
+ {
+ debug_printf ("connect error");
+ set_winsock_errno ();
+ closesocket (newsock);
+ closesocket (outsock);
+ goto done;
+ }
+ insock = newsock;
}
- closesocket (newsock);
res = 0;
- fdsock (sb[0], "/dev/tcp", insock);
+ if (family == AF_LOCAL)
+ {
- fdsock (sb[1], "/dev/tcp", outsock);
+ fh = fdsock (sb[0],
+ type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket",
+ insock);
+ fh->set_sun_path ("");
+ fh->set_addr_family (AF_LOCAL);
+ fh->set_socket_type (type);
+ fh = fdsock (sb[1],
+ type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket",
+ outsock);
+ fh->set_sun_path ("");
+ fh->set_addr_family (AF_LOCAL);
+ fh->set_socket_type (type);
+ }
+ else
+ {
+ fh = fdsock (sb[0], type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp",
+ insock);
+ fh->set_addr_family (AF_INET);
+ fh->set_socket_type (type);
+ fh = fdsock (sb[1], type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp",
+ outsock);
+ fh->set_addr_family (AF_INET);
+ fh->set_socket_type (type);
+ }
done:
syscall_printf ("%d = socketpair (...)", res);
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "socketpair");
return res;
}
@@ -2341,3 +2095,55 @@ extern "C" void
endhostent (void)
{
}
+
+/* exported as recvmsg: standards? */
+extern "C" int
+cygwin_recvmsg (int fd, struct msghdr *msg, int flags)
+{
+ int res;
+ sigframe thisframe (mainthread);
+
+ fhandler_socket *fh = get (fd);
+
+ if (check_null_invalid_struct_errno (msg)
+ || (msg->msg_name
+ && __check_null_invalid_struct_errno (msg->msg_name,
+ (unsigned) msg->msg_namelen))
+ || !fh)
+ res = -1;
+ else
+ {
+ res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen);
+ if (res > 0)
+ res = fh->recvmsg (msg, flags, res); // res == iovec tot
+ }
+
+ syscall_printf ("%d = recvmsg (%d, %p, %x)", res, fd, msg, flags);
+ return res;
+}
+
+/* exported as sendmsg: standards? */
+extern "C" int
+cygwin_sendmsg (int fd, const struct msghdr *msg, int flags)
+{
+ int res;
+ sigframe thisframe (mainthread);
+
+ fhandler_socket *fh = get (fd);
+
+ if (__check_invalid_read_ptr_errno (msg, sizeof msg)
+ || (msg->msg_name
+ && __check_invalid_read_ptr_errno (msg->msg_name,
+ (unsigned) msg->msg_namelen))
+ || !fh)
+ res = -1;
+ else
+ {
+ res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen);
+ if (res > 0)
+ res = fh->sendmsg (msg, flags, res); // res == iovec tot
+ }
+
+ syscall_printf ("%d = sendmsg (%d, %p, %x)", res, fd, msg, flags);
+ return res;
+}
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 6dd617c60..00a0ac717 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -9,11 +9,29 @@
details. */
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
+#define FILE_SYNCHRONOUS_IO_NONALERT 32
+#define PDI_MODULES 0x01
+#define PDI_HEAPS 0x04
+#define LDRP_IMAGE_DLL 0x00000004
+#define WSLE_PAGE_READONLY 0x001
+#define WSLE_PAGE_EXECUTE 0x002
+#define WSLE_PAGE_EXECUTE_READ 0x003
+#define WSLE_PAGE_READWRITE 0x004
+#define WSLE_PAGE_WRITECOPY 0x005
+#define WSLE_PAGE_EXECUTE_READWRITE 0x006
+#define WSLE_PAGE_EXECUTE_WRITECOPY 0x007
+#define WSLE_PAGE_SHARE_COUNT_MASK 0x0E0
+#define WSLE_PAGE_SHAREABLE 0x100
+
+typedef ULONG KAFFINITY;
typedef enum _SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation = 0,
+ SystemPerformanceInformation = 2,
+ SystemTimeOfDayInformation = 3,
SystemProcessesAndThreadsInformation = 5,
+ SystemProcessorTimes = 8,
/* There are a lot more of these... */
} SYSTEM_INFORMATION_CLASS;
@@ -29,9 +47,19 @@ typedef struct _SYSTEM_BASIC_INFORMATION
ULONG LowestUserAddress;
ULONG HighestUserAddress;
ULONG ActiveProcessors;
- ULONG NumberProcessors;
+ UCHAR NumberProcessors;
} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
+typedef struct __attribute__ ((aligned (8))) _SYSTEM_PROCESSOR_TIMES
+{
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER DpcTime;
+ LARGE_INTEGER InterruptTime;
+ ULONG InterruptCount;
+} SYSTEM_PROCESSOR_TIMES, *PSYSTEM_PROCESSOR_TIMES;
+
typedef LONG KPRIORITY;
typedef struct _VM_COUNTERS
{
@@ -111,12 +139,13 @@ typedef struct _SYSTEM_THREADS
ULONG ContextSwitchCount;
THREAD_STATE State;
KWAIT_REASON WaitReason;
+ DWORD Reserved;
} SYSTEM_THREADS, *PSYSTEM_THREADS;
typedef struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
- ULONG Threadcount;
+ ULONG ThreadCount;
ULONG Reserved1[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
@@ -132,6 +161,206 @@ typedef struct _SYSTEM_PROCESSES
SYSTEM_THREADS Threads[1];
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
+typedef struct _IO_STATUS_BLOCK
+{
+ NTSTATUS Status;
+ ULONG Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef struct _SYSTEM_PERFORMANCE_INFORMATION
+{
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER ReadTransferCount;
+ LARGE_INTEGER WriteTransferCount;
+ LARGE_INTEGER OtherTransferCount;
+ ULONG ReadOperationCount;
+ ULONG WriteOperationCount;
+ ULONG OtherOperationCount;
+ ULONG AvailablePages;
+ ULONG TotalCommittedPages;
+ ULONG TotalCommitLimit;
+ ULONG PeakCommitment;
+ ULONG PageFaults;
+ ULONG WriteCopyFaults;
+ ULONG TransitionFaults;
+ ULONG Reserved1;
+ ULONG DemandZeroFaults;
+ ULONG PagesRead;
+ ULONG PageReadIos;
+ ULONG Reserved2[2];
+ ULONG PagefilePagesWritten;
+ ULONG PagefilePageWriteIos;
+ ULONG MappedFilePagesWritten;
+ ULONG MappedFilePageWriteIos;
+ ULONG PagedPoolUsage;
+ ULONG NonPagedPoolUsage;
+ ULONG PagedPoolAllocs;
+ ULONG PagedPoolFrees;
+ ULONG NonPagedPoolAllocs;
+ ULONG NonPagedPoolFrees;
+ ULONG TotalFreeSystemPtes;
+ ULONG SystemCodePage;
+ ULONG TotalSystemDriverPages;
+ ULONG TotalSystemCodePages;
+ ULONG SmallNonPagedLookasideListAllocateHits;
+ ULONG SmallPagedLookasideListAllocateHits;
+ ULONG Reserved3;
+ ULONG MmSystemCachePage;
+ ULONG PagedPoolPage;
+ ULONG SystemDriverPage;
+ ULONG FastReadNoWait;
+ ULONG FastReadWait;
+ ULONG FastReadResourceMiss;
+ ULONG FastReadNotPossible;
+ ULONG FastMdlReadNoWait;
+ ULONG FastMdlReadWait;
+ ULONG FastMdlReadResourceMiss;
+ ULONG FastMdlReadNotPossible;
+ ULONG MapDataNoWait;
+ ULONG MapDataWait;
+ ULONG MapDataNoWaitMiss;
+ ULONG MapDataWaitMiss;
+ ULONG PinMappedDataCount;
+ ULONG PinReadNoWait;
+ ULONG PinReadWait;
+ ULONG PinReadNoWaitMiss;
+ ULONG PinReadWaitMiss;
+ ULONG CopyReadNoWait;
+ ULONG CopyReadWait;
+ ULONG CopyReadNoWaitMiss;
+ ULONG CopyReadWaitMiss;
+ ULONG MdlReadNoWait;
+ ULONG MdlReadWait;
+ ULONG MdlReadNoWaitMiss;
+ ULONG MdlReadWaitMiss;
+ ULONG ReadAheadIos;
+ ULONG LazyWriteIos;
+ ULONG LazyWritePages;
+ ULONG DataFlushes;
+ ULONG DataPages;
+ ULONG ContextSwitches;
+ ULONG FirstLevelTbFills;
+ ULONG SecondLevelTbFills;
+ ULONG SystemCalls;
+} SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION;
+
+typedef struct __attribute__ ((aligned(8))) _SYSTEM_TIME_OF_DAY_INFORMATION
+{
+ LARGE_INTEGER BootTime;
+ LARGE_INTEGER CurrentTime;
+ LARGE_INTEGER TimeZoneBias;
+ ULONG CurrentTimeZoneId;
+} SYSTEM_TIME_OF_DAY_INFORMATION, *PSYSTEM_TIME_OF_DAY_INFORMATION;
+
+typedef enum _PROCESSINFOCLASS
+{
+ ProcessBasicInformation = 0,
+ ProcessQuotaLimits = 1,
+ ProcessVmCounters = 3,
+ ProcessTimes =4,
+} PROCESSINFOCLASS;
+
+typedef struct _DEBUG_BUFFER
+{
+ HANDLE SectionHandle;
+ PVOID SectionBase;
+ PVOID RemoteSectionBase;
+ ULONG SectionBaseDelta;
+ HANDLE EventPairHandle;
+ ULONG Unknown[2];
+ HANDLE RemoteThreadHandle;
+ ULONG InfoClassMask;
+ ULONG SizeOfInfo;
+ ULONG AllocatedSize;
+ ULONG SectionSize;
+ PVOID ModuleInformation;
+ PVOID BackTraceInformation;
+ PVOID HeapInformation;
+ PVOID LockInformation;
+ PVOID Reserved[9];
+} DEBUG_BUFFER, *PDEBUG_BUFFER;
+
+typedef struct _DEBUG_HEAP_INFORMATION
+{
+ ULONG Base;
+ ULONG Flags;
+ USHORT Granularity;
+ USHORT Unknown;
+ ULONG Allocated;
+ ULONG Committed;
+ ULONG TagCount;
+ ULONG BlockCount;
+ ULONG Reserved[7];
+ PVOID Tags;
+ PVOID Blocks;
+} DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION;
+
+typedef struct _DEBUG_MODULE_INFORMATION
+{
+ ULONG Reserved[2];
+ ULONG Base;
+ ULONG Size;
+ ULONG Flags;
+ USHORT Index;
+ USHORT Unknown;
+ USHORT LoadCount;
+ USHORT ModuleNameOffset;
+ CHAR ImageName[256];
+} DEBUG_MODULE_INFORMATION, *PDEBUG_MODULE_INFORMATION;
+
+typedef struct _KERNEL_USER_TIMES
+{
+ LARGE_INTEGER CreateTime;
+ LARGE_INTEGER ExitTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES;
+
+typedef void *PPEB;
+
+typedef struct _PROCESS_BASIC_INFORMATION
+{
+ NTSTATUS ExitStatus;
+ PPEB PebBaseAddress;
+ KAFFINITY AffinityMask;
+ KPRIORITY BasePriority;
+ ULONG UniqueProcessId;
+ ULONG InheritedFromUniqueProcessId;
+} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
+
+typedef enum _MEMORY_INFORMATION_CLASS
+{
+ MemoryBasicInformation,
+ MemoryWorkingSetList,
+ MemorySectionName,
+ MemoryBaiscVlmInformation
+} MEMORY_INFORMATION_CLASS;
+
+typedef struct _MEMORY_WORKING_SET_LIST
+{
+ ULONG NumberOfPages;
+ ULONG WorkingSetList[1];
+} MEMORY_WORKING_SET_LIST, *PMEMORY_WORKING_SET_LIST;
+
+typedef struct _FILE_NAME_INFORMATION
+{
+ DWORD FileNameLength;
+ WCHAR FileName[MAX_PATH + 100];
+} FILE_NAME_INFORMATION;
+
+typedef enum _OBJECT_INFORMATION_CLASS
+{
+ ObjectBasicInformation = 0,
+ ObjectNameInformation = 1,
+ ObjectHandleInformation = 4
+ // and many more
+} OBJECT_INFORMATION_CLASS;
+
+typedef struct _OBJECT_NAME_INFORMATION
+{
+ UNICODE_STRING Name;
+} OBJECT_NAME_INFORMATION;
+
/* Function declarations for ntdll.dll. These don't appear in any
standard Win32 header. */
extern "C"
@@ -144,13 +373,20 @@ extern "C"
NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG,
PLARGE_INTEGER, PULONG, SECTION_INHERIT,
ULONG, ULONG);
+ NTSTATUS NTAPI NtOpenFile (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
+ PIO_STATUS_BLOCK, ULONG, ULONG);
NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+ NTSTATUS NTAPI NtQueryInformationFile (HANDLE, IO_STATUS_BLOCK *, VOID *,
+ DWORD, DWORD);
+ NTSTATUS NTAPI NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS,
+ PVOID, ULONG, PULONG);
+ NTSTATUS NTAPI NtQueryObject (HANDLE, OBJECT_INFORMATION_CLASS, VOID *,
+ ULONG, ULONG *);
NTSTATUS NTAPI NtQuerySystemInformation (SYSTEM_INFORMATION_CLASS,
PVOID, ULONG, PULONG);
+ NTSTATUS NTAPI NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS,
+ PVOID, ULONG, PULONG);
NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID);
VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR);
ULONG NTAPI RtlNtStatusToDosError (NTSTATUS);
- NTSTATUS NTAPI ZwQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS,
- IN OUT PVOID, IN ULONG,
- OUT PULONG);
}
diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc
index 224478b16..95b5444a3 100644
--- a/winsup/cygwin/ntea.cc
+++ b/winsup/cygwin/ntea.cc
@@ -91,12 +91,11 @@ NTReadEA (const char *file, const char *attrname, char *attrbuf, int len)
int easize;
hFileSource = CreateFile (file, FILE_READ_EA,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_none_nih, // sa
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- NULL
- );
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sec_none_nih, // sa
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
if (hFileSource == INVALID_HANDLE_VALUE)
return 0;
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc
index 2f52473c7..22e8b3e20 100644
--- a/winsup/cygwin/passwd.cc
+++ b/winsup/cygwin/passwd.cc
@@ -1,6 +1,6 @@
/* passwd.cc: getpwnam () and friends
- Copyright 1996, 1997, 1998, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -18,8 +18,6 @@ details. */
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "cygheap.h"
#include <sys/termios.h>
@@ -82,19 +80,17 @@ parse_pwd (struct passwd &res, char *buf)
/* Allocate enough room for the passwd struct and all the strings
in it in one go */
size_t len = strlen (buf);
- char *mybuf = (char *) malloc (len + 1);
- (void) memcpy (mybuf, buf, len + 1);
- if (mybuf[--len] == '\n')
- mybuf[len] = '\0';
-
- res.pw_name = grab_string (&mybuf);
- res.pw_passwd = grab_string (&mybuf);
- res.pw_uid = grab_int (&mybuf);
- res.pw_gid = grab_int (&mybuf);
+ if (buf[--len] == '\r')
+ buf[len] = '\0';
+
+ res.pw_name = grab_string (&buf);
+ res.pw_passwd = grab_string (&buf);
+ res.pw_uid = grab_int (&buf);
+ res.pw_gid = grab_int (&buf);
res.pw_comment = 0;
- res.pw_gecos = grab_string (&mybuf);
- res.pw_dir = grab_string (&mybuf);
- res.pw_shell = grab_string (&mybuf);
+ res.pw_gecos = grab_string (&buf);
+ res.pw_dir = grab_string (&buf);
+ res.pw_shell = grab_string (&buf);
}
/* Add one line from /etc/passwd into the password cache */
@@ -111,71 +107,102 @@ add_pwd_line (char *line)
class passwd_lock
{
- pthread_mutex_t mutex;
+ bool armed;
+ static NO_COPY pthread_mutex_t mutex;
public:
- passwd_lock (): mutex ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER) {}
- void arm () {pthread_mutex_lock (&mutex); }
+ passwd_lock (bool doit)
+ {
+ if (doit)
+ pthread_mutex_lock (&mutex);
+ armed = doit;
+ }
~passwd_lock ()
{
- if (mutex != (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)
+ if (armed)
pthread_mutex_unlock (&mutex);
}
};
+pthread_mutex_t NO_COPY passwd_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
+
/* Read in /etc/passwd and save contents in the password cache.
This sets passwd_state to loaded or emulated so functions in this file can
tell that /etc/passwd has been read in or will be emulated. */
void
read_etc_passwd ()
{
- char linebuf[1024];
- /* A mutex is ok for speed here - pthreads will use critical sections not mutex's
- * for non-shared mutexs in the future. Also, this function will at most be called
- * once from each thread, after that the passwd_state test will succeed
- */
- static NO_COPY passwd_lock here;
+ static pwdgrp_read pr;
- if (cygwin_finished_initializing)
- here.arm ();
+ /* A mutex is ok for speed here - pthreads will use critical sections not
+ * mutexes for non-shared mutexes in the future. Also, this function will
+ * at most be called once from each thread, after that the passwd_state
+ * test will succeed */
+ passwd_lock here (cygwin_finished_initializing);
- /* if we got blocked by the mutex, then etc_passwd may have been processed */
- if (passwd_state != uninitialized)
- return;
+ /* if we got blocked by the mutex, then etc_passwd may have been processed */
+ if (passwd_state != uninitialized)
+ return;
- if (passwd_state != initializing)
- {
- passwd_state = initializing;
- if (max_lines) /* When rereading, free allocated memory first. */
- {
- for (int i = 0; i < curr_lines; ++i)
- free (passwd_buf[i].pw_name);
- curr_lines = 0;
- }
-
- FILE *f = fopen ("/etc/passwd", "rt");
-
- if (f)
- {
- while (fgets (linebuf, sizeof (linebuf), f) != NULL)
- {
- if (strlen (linebuf))
- add_pwd_line (linebuf);
- }
-
- passwd_state.set_last_modified (f);
- fclose (f);
- passwd_state = loaded;
- }
- else
- {
- debug_printf ("Emulating /etc/passwd");
- snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", cygheap->user.name (),
- DEFAULT_UID, DEFAULT_GID, getenv ("HOME") ?: "/");
- add_pwd_line (linebuf);
- passwd_state = emulated;
- }
+ if (passwd_state != initializing)
+ {
+ passwd_state = initializing;
+ if (pr.open ("/etc/passwd"))
+ {
+ char *line;
+ while ((line = pr.gets ()) != NULL)
+ if (strlen (line))
+ add_pwd_line (line);
+
+ passwd_state.set_last_modified (pr.get_fhandle (), pr.get_fname ());
+ passwd_state = loaded;
+ pr.close ();
+ debug_printf ("Read /etc/passwd, %d lines", curr_lines);
+ }
+ else
+ {
+ static char linebuf[1024];
+
+ if (wincap.has_security ())
+ {
+ HANDLE ptok;
+ cygsid tu, tg;
+ DWORD siz;
+
+ if (OpenProcessToken (hMainProc, TOKEN_QUERY, &ptok))
+ {
+ if (GetTokenInformation (ptok, TokenUser, &tu, sizeof tu,
+ &siz)
+ && GetTokenInformation (ptok, TokenPrimaryGroup, &tg,
+ sizeof tg, &siz))
+ {
+ char strbuf[100];
+ snprintf (linebuf, sizeof (linebuf),
+ "%s::%lu:%lu:%s:%s:/bin/sh",
+ cygheap->user.name (),
+ *GetSidSubAuthority (tu,
+ *GetSidSubAuthorityCount(tu) - 1),
+ *GetSidSubAuthority (tg,
+ *GetSidSubAuthorityCount(tg) - 1),
+ tu.string (strbuf), getenv ("HOME") ?: "/");
+ debug_printf ("Emulating /etc/passwd: %s", linebuf);
+ add_pwd_line (linebuf);
+ passwd_state = emulated;
+ }
+ CloseHandle (ptok);
+ }
+ }
+ if (passwd_state != emulated)
+ {
+ snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh",
+ cygheap->user.name (), (unsigned) DEFAULT_UID,
+ (unsigned) DEFAULT_GID, getenv ("HOME") ?: "/");
+ debug_printf ("Emulating /etc/passwd: %s", linebuf);
+ add_pwd_line (linebuf);
+ passwd_state = emulated;
+ }
+ }
- }
+ }
return;
}
@@ -183,7 +210,7 @@ read_etc_passwd ()
/* Cygwin internal */
/* If this ever becomes non-reentrant, update all the getpw*_r functions */
static struct passwd *
-search_for (uid_t uid, const char *name)
+search_for (__uid32_t uid, const char *name)
{
struct passwd *res = 0;
struct passwd *default_pw = 0;
@@ -199,7 +226,7 @@ search_for (uid_t uid, const char *name)
if (strcasematch (name, res->pw_name))
return res;
}
- else if (uid == res->pw_uid)
+ else if (uid == (__uid32_t) res->pw_uid)
return res;
}
@@ -214,18 +241,24 @@ search_for (uid_t uid, const char *name)
}
extern "C" struct passwd *
-getpwuid (uid_t uid)
+getpwuid32 (__uid32_t uid)
{
if (passwd_state <= initializing)
read_etc_passwd ();
- pthread_testcancel();
+ pthread_testcancel ();
return search_for (uid, 0);
}
+extern "C" struct passwd *
+getpwuid (__uid16_t uid)
+{
+ return getpwuid32 (uid16touid32 (uid));
+}
+
extern "C" int
-getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
+getpwuid_r32 (__uid32_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
{
*result = NULL;
@@ -235,7 +268,7 @@ getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct
if (passwd_state <= initializing)
read_etc_passwd ();
- pthread_testcancel();
+ pthread_testcancel ();
struct passwd *temppw = search_for (uid, 0);
@@ -266,13 +299,19 @@ getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct
return 0;
}
+extern "C" int
+getpwuid_r (__uid16_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result)
+{
+ return getpwuid_r32 (uid16touid32 (uid), pwd, buffer, bufsize, result);
+}
+
extern "C" struct passwd *
getpwnam (const char *name)
{
if (passwd_state <= initializing)
read_etc_passwd ();
- pthread_testcancel();
+ pthread_testcancel ();
return search_for (0, name);
}
@@ -293,7 +332,7 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s
if (passwd_state <= initializing)
read_etc_passwd ();
- pthread_testcancel();
+ pthread_testcancel ();
struct passwd *temppw = search_for (0, nam);
@@ -337,7 +376,7 @@ getpwent (void)
}
extern "C" struct passwd *
-getpwduid (uid_t)
+getpwduid (__uid16_t)
{
return NULL;
}
@@ -385,14 +424,12 @@ getpass (const char * prompt)
if (passwd_state <= initializing)
read_etc_passwd ();
- if (cygheap->fdtab.not_open (0))
- {
- set_errno (EBADF);
- pass[0] = '\0';
- }
+ cygheap_fdget fhstdin (0);
+
+ if (fhstdin < 0)
+ pass[0] = '\0';
else
{
- fhandler_base *fhstdin = cygheap->fdtab[0];
fhstdin->tcgetattr (&ti);
newti = ti;
newti.c_lflag &= ~ECHO;
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 2aa19e1aa..a185e60e9 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1,6 +1,6 @@
/* path.cc: path support.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -52,7 +52,6 @@ details. */
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
-#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
@@ -64,7 +63,6 @@ details. */
#include <sys/cygwin.h>
#include <cygwin/version.h>
#include "cygerrno.h"
-#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
@@ -76,7 +74,6 @@ details. */
#include "shared_info.h"
#include "registry.h"
#include <assert.h>
-#include "shortcut.h"
#ifdef _MT_SAFE
#define iteration _reent_winsup ()->_iteration
@@ -100,22 +97,50 @@ struct symlink_info
int is_symlink;
bool ext_tacked_on;
int error;
- BOOL case_clash;
+ bool case_clash;
int check (char *path, const suffix_info *suffixes, unsigned opt);
BOOL case_check (char *path);
};
int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */
+static char shortcut_header[SHORTCUT_HDR_SIZE];
+static BOOL shortcut_initalized;
+
+static void
+create_shortcut_header (void)
+{
+ if (!shortcut_initalized)
+ {
+ shortcut_header[0] = 'L';
+ shortcut_header[4] = '\001';
+ shortcut_header[5] = '\024';
+ shortcut_header[6] = '\002';
+ shortcut_header[12] = '\300';
+ shortcut_header[19] = 'F';
+ shortcut_header[20] = '\f';
+ shortcut_header[60] = '\001';
+ shortcut_initalized = TRUE;
+ }
+}
+
+#define CYGWIN_REGNAME (cygheap->cygwin_regname ?: CYGWIN_INFO_CYGWIN_REGISTRY_NAME)
+
/* Determine if path prefix matches current cygdrive */
#define iscygdrive(path) \
(path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len))
#define iscygdrive_device(path) \
- (iscygdrive(path) && isalpha(path[mount_table->cygdrive_len]) && \
- (isdirsep(path[mount_table->cygdrive_len + 1]) || \
+ (isalpha (path[mount_table->cygdrive_len]) && \
+ (isdirsep (path[mount_table->cygdrive_len + 1]) || \
!path[mount_table->cygdrive_len + 1]))
+#define isproc(path) \
+ (path_prefix_p (proc, (path), proc_len))
+
+#define isvirtual_dev(devn) \
+ (devn == FH_CYGDRIVE || devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS)
+
/* Return non-zero if PATH1 is a prefix of PATH2.
Both are assumed to be of the same path style and / vs \ usage.
Neither may be "".
@@ -171,7 +196,7 @@ pathmatch (const char *path1, const char *path2)
#define isslash(c) ((c) == '/')
-int
+static int
normalize_posix_path (const char *src, char *dst)
{
const char *src_start = src;
@@ -209,6 +234,12 @@ normalize_posix_path (const char *src, char *dst)
*dst++ = '/';
src = src_start + 1;
}
+ else if (src[0] == '.' && isslash (src[1]))
+ {
+ *dst++ = '.';
+ *dst++ = '/';
+ src += 2;
+ }
}
else
*dst = '\0';
@@ -241,7 +272,11 @@ normalize_posix_path (const char *src, char *dst)
break;
}
else if (src[2] && !isslash (src[2]))
- break;
+ {
+ if (src[2] == '.')
+ return ENOENT;
+ break;
+ }
else
{
while (dst > dst_start && !isslash (*--dst))
@@ -306,8 +341,8 @@ mkrelpath (char *path)
strcpy (path, ".");
}
-void
-path_conv::update_fs_info (const char* win32_path)
+bool
+fs_info::update (const char *win32_path)
{
char tmp_buf [MAX_PATH];
strncpy (tmp_buf, win32_path, MAX_PATH);
@@ -315,39 +350,62 @@ path_conv::update_fs_info (const char* win32_path)
if (!rootdir (tmp_buf))
{
debug_printf ("Cannot get root component of path %s", win32_path);
- root_dir [0] = fs_name [0] = '\0';
- fs_flags = fs_serial = 0;
- sym_opt = 0;
- return;
+ name [0] = '\0';
+ sym_opt = flags = serial = 0;
+ return false;
}
- if (strcmp (tmp_buf, root_dir) != 0)
+ if (strcmp (tmp_buf, root_dir) == 0)
+ return 1;
+
+ strncpy (root_dir, tmp_buf, MAX_PATH);
+ drive_type = GetDriveType (root_dir);
+ if (drive_type == DRIVE_REMOTE || (drive_type == DRIVE_UNKNOWN && (root_dir[0] == '\\' && root_dir[1] == '\\')))
+ is_remote_drive = 1;
+ else
+ is_remote_drive = 0;
+
+ if (!GetVolumeInformation (root_dir, NULL, 0, &serial, NULL, &flags,
+ name, sizeof (name)))
{
- strncpy (root_dir, tmp_buf, MAX_PATH);
- drive_type = GetDriveType (root_dir);
- if (drive_type == DRIVE_REMOTE || (drive_type == DRIVE_UNKNOWN && (root_dir[0] == '\\' && root_dir[1] == '\\')))
- is_remote_drive = 1;
- else
- is_remote_drive = 0;
+ debug_printf ("Cannot get volume information (%s), %E", root_dir);
+ name [0] = '\0';
+ sym_opt = flags = serial = 0;
+ return false;
+ }
+ /* FIXME: Samba by default returns "NTFS" in file system name, but
+ * doesn't support Extended Attributes. If there's some fast way to
+ * distinguish between samba and real ntfs, it should be implemented
+ * here.
+ */
+ sym_opt = (!is_remote_drive && strcmp (name, "NTFS") == 0) ? PC_CHECK_EA : 0;
- if (!GetVolumeInformation (root_dir, NULL, 0, &fs_serial, NULL, &fs_flags,
- fs_name, sizeof (fs_name)))
- {
- debug_printf ("Cannot get volume information (%s), %E", root_dir);
- fs_name [0] = '\0';
- fs_flags = fs_serial = 0;
- sym_opt = 0;
- }
- else
- {
- /* FIXME: Samba by default returns "NTFS" in file system name, but
- * doesn't support Extended Attributes. If there's some fast way to
- * distinguish between samba and real ntfs, it should be implemented
- * here.
- */
- sym_opt = (!is_remote_drive && strcmp (fs_name, "NTFS") == 0) ? PC_CHECK_EA : 0;
- }
+ return true;
+}
+
+char *
+path_conv::return_and_clear_normalized_path ()
+{
+ char *s = normalized_path;
+ normalized_path = NULL;
+ return s;
+}
+
+void
+path_conv::fillin (HANDLE h)
+{
+ BY_HANDLE_FILE_INFORMATION local;
+ if (!GetFileInformationByHandle (h, &local))
+ {
+ fileattr = INVALID_FILE_ATTRIBUTES;
+ fs.serial = 0;
}
+ else
+ {
+ fileattr = local.dwFileAttributes;
+ fs.serial = local.dwVolumeSerialNumber;
+ }
+ fs.drive_type = DRIVE_UNKNOWN;
}
/* Convert an arbitrary path SRC to a pure Win32 path, suitable for
@@ -376,6 +434,7 @@ path_conv::check (const char *src, unsigned opt,
bool need_directory = 0;
bool saw_symlinks = 0;
int is_relpath;
+ char *tail;
sigframe thisframe (mainthread);
#if 0
@@ -392,21 +451,21 @@ path_conv::check (const char *src, unsigned opt,
int loop = 0;
path_flags = 0;
known_suffix = NULL;
- fileattr = (DWORD) -1;
- case_clash = FALSE;
+ fileattr = INVALID_FILE_ATTRIBUTES;
+ case_clash = false;
devn = unit = 0;
- root_dir[0] = '\0';
- fs_name[0] = '\0';
- fs_flags = fs_serial = 0;
- sym_opt = 0;
- drive_type = 0;
- is_remote_drive = 0;
+ fs.root_dir[0] = '\0';
+ fs.name[0] = '\0';
+ fs.flags = fs.serial = 0;
+ fs.sym_opt = 0;
+ fs.drive_type = 0;
+ fs.is_remote_drive = 0;
+ normalized_path = NULL;
if (!(opt & PC_NULLEMPTY))
error = 0;
else if ((error = check_null_empty_str (src)))
return;
-
/* This loop handles symlink expansion. */
for (;;)
{
@@ -430,7 +489,7 @@ path_conv::check (const char *src, unsigned opt,
if (error)
return;
- char *tail = strchr (path_copy, '\0'); // Point to end of copy
+ tail = strchr (path_copy, '\0'); // Point to end of copy
char *path_end = tail;
tail[1] = '\0';
@@ -471,21 +530,62 @@ path_conv::check (const char *src, unsigned opt,
if (error)
return;
- update_fs_info (full_path);
-
+ if (devn == FH_CYGDRIVE)
+ {
+ if (!component)
+ fileattr = FILE_ATTRIBUTE_DIRECTORY;
+ else
+ {
+ devn = FH_BAD;
+ fileattr = GetFileAttributes (this->path);
+ }
+ goto out;
+ }
+ else if (isvirtual_dev (devn))
+ {
+ /* FIXME: Calling build_fhandler here is not the right way to handle this. */
+ fhandler_virtual *fh =
+ (fhandler_virtual *) cygheap->fdtab.build_fhandler (-1, devn, (const char *) path_copy, NULL, unit);
+ int file_type = fh->exists ();
+ switch (file_type)
+ {
+ case 1:
+ case 2:
+ fileattr = FILE_ATTRIBUTE_DIRECTORY;
+ break;
+ case -1:
+ fileattr = 0;
+ break;
+ default:
+ fileattr = INVALID_FILE_ATTRIBUTES;
+ break;
+ }
+ delete fh;
+ goto out;
+ }
/* devn should not be a device. If it is, then stop parsing now. */
- if (devn != FH_BAD)
+ else if (devn != FH_BAD)
{
fileattr = 0;
+ path_flags = sym.pflags;
+ if (component)
+ {
+ error = ENOTDIR;
+ return;
+ }
goto out; /* Found a device. Stop parsing. */
}
+ if (!fs.update (full_path))
+ fs.root_dir[0] = '\0';
+
/* Eat trailing slashes */
char *dostail = strchr (full_path, '\0');
- /* If path is only a drivename, Windows interprets it as the current working
- directory on this drive instead of the root dir which is what we want. So
- we need the trailing backslash in this case. */
+ /* If path is only a drivename, Windows interprets it as the
+ current working directory on this drive instead of the root
+ dir which is what we want. So we need the trailing backslash
+ in this case. */
while (dostail > full_path + 3 && (*--dostail == '\\'))
*tail = '\0';
@@ -497,11 +597,11 @@ path_conv::check (const char *src, unsigned opt,
if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED)
{
- fileattr = GetFileAttributesA (full_path);
+ fileattr = GetFileAttributes (this->path);
goto out;
}
- int len = sym.check (full_path, suff, opt | sym_opt);
+ int len = sym.check (full_path, suff, opt | fs.sym_opt);
if (sym.case_clash)
{
@@ -518,23 +618,22 @@ path_conv::check (const char *src, unsigned opt,
if (!component)
case_clash = TRUE;
}
-
if (!(opt & PC_SYM_IGNORE))
{
if (!component)
- path_flags = sym.pflags;
+ {
+ fileattr = sym.fileattr;
+ path_flags = sym.pflags;
+ }
/* If symlink.check found an existing non-symlink file, then
it sets the appropriate flag. It also sets any suffix found
into `ext_here'. */
- if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
+ if (!sym.is_symlink && sym.fileattr != INVALID_FILE_ATTRIBUTES)
{
error = sym.error;
if (component == 0)
- {
- fileattr = sym.fileattr;
- add_ext_from_sym (sym);
- }
+ add_ext_from_sym (sym);
if (pcheck_case == PCHECK_RELAXED)
goto out; // file found
/* Avoid further symlink evaluation. Only case checks are
@@ -552,7 +651,6 @@ path_conv::check (const char *src, unsigned opt,
if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
{
set_symlink (); // last component of path is a symlink.
- fileattr = sym.fileattr;
if (opt & PC_SYM_CONTENTS)
{
strcpy (path, sym.contents);
@@ -655,6 +753,12 @@ path_conv::check (const char *src, unsigned opt,
add_ext_from_sym (sym);
out:
+ if (opt & PC_POSIX)
+ {
+ if (tail[1] != '\0')
+ *tail = '/';
+ normalized_path = cstrdup (path_copy);
+ }
/* Deal with Windows stupidity which considers filename\. to be valid
even when "filename" is not a directory. */
if (!need_directory || error)
@@ -668,25 +772,32 @@ out:
return;
}
- update_fs_info (path);
- if (!fs_name[0])
- {
- set_has_acls (FALSE);
- set_has_buggy_open (FALSE);
- }
- else
+ if (devn == FH_BAD)
{
- set_isdisk ();
- debug_printf ("root_dir(%s), this->path(%s), set_has_acls(%d)",
- root_dir, this->path, fs_flags & FS_PERSISTENT_ACLS);
- if (!allow_smbntsec && is_remote_drive)
- set_has_acls (FALSE);
+ if (!fs.update (path))
+ {
+ fs.root_dir[0] = '\0';
+ set_has_acls (false);
+ set_has_buggy_open (false);
+ }
else
- set_has_acls (fs_flags & FS_PERSISTENT_ACLS);
- /* Known file systems with buggy open calls. Further explanation
- in fhandler.cc (fhandler_disk_file::open). */
- set_has_buggy_open (strcmp (fs_name, "SUNWNFS") == 0);
+ {
+ set_isdisk ();
+ debug_printf ("root_dir(%s), this->path(%s), set_has_acls(%d)",
+ fs.root_dir, this->path, fs.flags & FS_PERSISTENT_ACLS);
+ if (!allow_smbntsec && fs.is_remote_drive)
+ set_has_acls (false);
+ else
+ set_has_acls (fs.flags & FS_PERSISTENT_ACLS);
+ /* Known file systems with buggy open calls. Further explanation
+ in fhandler.cc (fhandler_disk_file::open). */
+ set_has_buggy_open (strcmp (fs.name, "SUNWNFS") == 0);
+ }
}
+#if 0
+ if (issocket ())
+ devn = FH_SOCKET;
+#endif
if (!(opt & PC_FULL))
{
@@ -709,7 +820,7 @@ out:
if (saw_symlinks)
set_has_symlinks ();
- if (!error && !(path_flags & (PATH_ALL_EXEC | PATH_NOTEXEC)))
+ if (!error && !isdir () && !(path_flags & PATH_ALL_EXEC))
{
const char *p = strchr (path, '\0') - 4;
if (p >= path &&
@@ -728,14 +839,11 @@ out:
#endif
}
-#define deveq(s) (strcasematch (name, (s)))
-#define deveqn(s, n) (strncasematch (name, (s), (n)))
-
static __inline int
digits (const char *name)
{
char *p;
- int n = strtol(name, &p, 10);
+ int n = strtol (name, &p, 10);
return p > name && !*p ? n : -1;
}
@@ -769,106 +877,220 @@ const char *windows_device_names[] NO_COPY =
"\\dev\\dsp"
};
-static int
-get_raw_device_number (const char *uxname, const char *w32path, int &unit)
-{
- DWORD devn = FH_BAD;
+#define deveq(s) (strcasematch (name, (s)))
+#define deveqn(s, n) (strncasematch (name, (s), (n)))
+#define wdeveq(s) (strcasematch (w32_path, (s)))
+#define wdeveqn(s, n) (strncasematch (w32_path, (s), (n)))
+#define udeveq(s) (strcasematch (unix_path, (s)))
+#define udeveqn(s, n) (strncasematch (unix_path, (s), (n)))
- if (strncasematch (w32path, "\\\\.\\tape", 8))
- {
- devn = FH_TAPE;
- unit = digits (w32path + 8);
- // norewind tape devices have leading n in name
- if (strncasematch (uxname, "/dev/n", 6))
- unit += 128;
- }
- else if (isdrive (w32path + 4))
+static int __stdcall
+get_devn (const char *name, int &unit)
+{
+ int devn = FH_BAD;
+ name += 5;
+ if (deveq ("tty"))
{
- devn = FH_FLOPPY;
- unit = cyg_tolower (w32path[4]) - 'a';
- }
- else if (strncasematch (w32path, "\\\\.\\physicaldrive", 17))
+ if (real_tty_attached (myself))
+ {
+ unit = myself->ctty;
+ devn = FH_TTYS;
+ }
+ else if (myself->ctty > 0)
+ devn = FH_CONSOLE;
+ }
+ else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
+ devn = FH_TTYS;
+ else if (deveq ("ttym"))
+ devn = FH_TTYM;
+ else if (deveq ("ptmx"))
+ devn = FH_PTYM;
+ else if (deveq ("windows"))
+ devn = FH_WINDOWS;
+ else if (deveq ("dsp"))
+ devn = FH_OSS_DSP;
+ else if (deveq ("conin"))
+ devn = FH_CONIN;
+ else if (deveq ("conout"))
+ devn = FH_CONOUT;
+ else if (deveq ("null"))
+ devn = FH_NULL;
+ else if (deveq ("zero"))
+ devn = FH_ZERO;
+ else if (deveq ("random") || deveq ("urandom"))
+ {
+ devn = FH_RANDOM;
+ unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
+ }
+ else if (deveq ("mem"))
+ {
+ devn = FH_MEM;
+ unit = 1;
+ }
+ else if (deveq ("clipboard"))
+ devn = FH_CLIPBOARD;
+ else if (deveq ("port"))
+ {
+ devn = FH_MEM;
+ unit = 4;
+ }
+ else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0 && unit < 100)
+ devn = FH_SERIAL;
+ else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0)
{
- devn = FH_FLOPPY;
- unit = digits (w32path + 17) + 128;
+ devn = FH_SERIAL;
+ unit++;
}
+ else if (deveq ("pipe"))
+ devn = FH_PIPE;
+ else if (deveq ("piper"))
+ devn = FH_PIPER;
+ else if (deveq ("pipew"))
+ devn = FH_PIPEW;
+ else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
+ || deveq ("dgsocket"))
+ devn = FH_SOCKET;
+
return devn;
}
-int __stdcall
-get_device_number (const char *name, int &unit, BOOL from_conv)
+/*
+ major minor POSIX filename NT filename
+ ----- ----- -------------- -------------------------
+ FH_TAPE 0 /dev/st0 \device\tape0
+ FH_TAPE 1 /dev/st1 \device\tape1
+ ...
+ FH_TAPE 128 /dev/nst0 \device\tape0
+ FH_TAPE 129 /dev/nst1 \device\tape1
+ ...
+
+ FH_FLOPPY 0 /dev/fd0 \device\floppy0
+ FH_FLOPPY 1 /dev/fd1 \device\floppy1
+ ...
+
+ FH_FLOPPY 16 /dev/scd0 \device\cdrom0
+ FH_FLOPPY 17 /dev/scd0 \device\cdrom1
+ ...
+
+ FH_FLOPPY 32 /dev/sda \device\harddisk0\partition0
+ FH_FLOPPY 33 /dev/sda1 \device\harddisk0\partition1
+ ...
+ FH_FLOPPY 47 /dev/sda15 \device\harddisk0\partition15
+
+ FH_FLOPPY 48 /dev/sdb \device\harddisk1\partition0
+ FH_FLOPPY 33 /dev/sdb1 \device\harddisk1\partition1
+ ...
+ FH_FLOPPY 208 /dev/sdl \device\harddisk11\partition0
+ ...
+ FH_FLOPPY 223 /dev/sdl15 \device\harddisk11\partition15
+
+ The following are needed to maintain backward compatibility with
+ the old Win32 partitioning scheme on W2K/XP.
+
+ FH_FLOPPY 224 from mount tab \\.\A:
+ ...
+ FH_FLOPPY 250 from mount tab \\.\Z:
+*/
+static int
+get_raw_device_number (const char *name, const char *w32_path, int &unit)
{
DWORD devn = FH_BAD;
- unit = 0;
- if ((*name == '/' && deveqn ("/dev/", 5)) ||
- (*name == '\\' && deveqn ("\\dev\\", 5)))
+ if (!w32_path) /* New approach using fixed device names. */
{
- name += 5;
- if (deveq ("tty"))
+ if (deveqn ("st", 2))
{
- if (real_tty_attached (myself))
- {
- unit = myself->ctty;
- devn = FH_TTYS;
- }
- else if (myself->ctty > 0)
- devn = FH_CONSOLE;
+ unit = digits (name + 2);
+ if (unit >= 0 && unit < 128)
+ devn = FH_TAPE;
}
- else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
- devn = FH_TTYS;
- else if (deveq ("ttym"))
- devn = FH_TTYM;
- else if (deveq ("ptmx"))
- devn = FH_PTYM;
- else if (deveq ("windows"))
- devn = FH_WINDOWS;
- else if (deveq ("dsp"))
- devn = FH_OSS_DSP;
- else if (deveq ("conin"))
- devn = FH_CONIN;
- else if (deveq ("conout"))
- devn = FH_CONOUT;
- else if (deveq ("null"))
- devn = FH_NULL;
- else if (deveq ("zero"))
- devn = FH_ZERO;
- else if (deveq ("random") || deveq ("urandom"))
+ else if (deveqn ("nst", 3))
{
- devn = FH_RANDOM;
- unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
+ unit = digits (name + 3) + 128;
+ if (unit >= 128 && unit < 256)
+ devn = FH_TAPE;
}
- else if (deveq ("mem"))
+ else if (deveqn ("fd", 2))
{
- devn = FH_MEM;
- unit = 1;
+ unit = digits (name + 2);
+ if (unit >= 0 && unit < 16)
+ devn = FH_FLOPPY;
}
- else if (deveq ("clipboard"))
- devn = FH_CLIPBOARD;
- else if (deveq ("port"))
+ else if (deveqn ("scd", 3))
{
- devn = FH_MEM;
- unit = 4;
+ unit = digits (name + 3) + 16;
+ if (unit >= 16 && unit < 32)
+ devn = FH_FLOPPY;
}
- else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
- devn = FH_SERIAL;
- else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0)
+ else if (deveqn ("sd", 2) && isalpha (name[2]))
+ {
+ unit = (cyg_tolower (name[2]) - 'a') * 16 + 32;
+ if (unit >= 32 && unit < 224)
+ if (!name[3])
+ devn = FH_FLOPPY;
+ else
+ {
+ int d = digits (name + 3);
+ if (d >= 1 && d < 16)
+ {
+ unit += d;
+ devn = FH_FLOPPY;
+ }
+ }
+ }
+ }
+ else /* Backward compatible checking of mount table device mapping. */
+ {
+ if (wdeveqn ("tape", 4))
+ {
+ unit = digits (w32_path + 4);
+ /* Norewind tape devices have leading n in name. */
+ if (deveqn ("n", 1))
+ unit += 128;
+ devn = FH_TAPE;
+ }
+ else if (wdeveqn ("physicaldrive", 13))
+ {
+ unit = digits (w32_path + 13) * 16 + 32;
+ devn = FH_FLOPPY;
+ }
+ else if (isdrive (w32_path))
+ {
+ unit = cyg_tolower (w32_path[0]) - 'a' + 224;
+ devn = FH_FLOPPY;
+ }
+ }
+ return devn;
+}
+
+static int __stdcall get_device_number (const char *unix_path,
+ const char *w32_path, int &unit)
+ __attribute__ ((regparm(3)));
+static int __stdcall
+get_device_number (const char *unix_path, const char *w32_path, int &unit)
+{
+ DWORD devn = FH_BAD;
+ unit = 0;
+
+ if (*unix_path == '/' && udeveqn ("/dev/", 5))
+ {
+ devn = get_devn (unix_path, unit);
+ if (devn == FH_BAD && *w32_path == '\\' && wdeveqn ("\\dev\\", 5))
+ devn = get_devn (w32_path, unit);
+ if (devn == FH_BAD && wdeveqn ("\\\\.\\", 4))
+ devn = get_raw_device_number (unix_path + 5, w32_path + 4, unit);
+ if (devn == FH_BAD)
+ devn = get_raw_device_number (unix_path + 5, NULL, unit);
+ }
+ else
+ {
+ char *p = strrchr (unix_path, '/');
+ if (p)
+ unix_path = p + 1;
+ if (udeveqn ("com", 3)
+ && (unit = digits (unix_path + 3)) >= 0 && unit < 100)
devn = FH_SERIAL;
- else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
- devn = FH_PIPE;
- else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
- || deveq ("dgsocket"))
- devn = FH_SOCKET;
- else if (!from_conv)
- devn = get_raw_device_number (name - 5,
- path_conv (name - 5,
- PC_SYM_IGNORE).get_win32 (),
- unit);
- }
- else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
- devn = FH_SERIAL;
- else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0)
- devn = FH_SERIAL;
+ }
return devn;
}
@@ -882,17 +1104,36 @@ win32_device_name (const char *src_path, char *win32_path,
{
const char *devfmt;
- devn = get_device_number (src_path, unit, TRUE);
+ devn = get_device_number (src_path, win32_path, unit);
if (devn == FH_BAD)
- return FALSE;
+ return false;
if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
- return FALSE;
- if (devn == FH_RANDOM)
- __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
- else
- __small_sprintf (win32_path, devfmt, unit);
+ return false;
+ switch (devn)
+ {
+ case FH_RANDOM:
+ __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
+ break;
+ case FH_TAPE:
+ __small_sprintf (win32_path, "\\Device\\Tape%d", unit % 128);
+ break;
+ case FH_FLOPPY:
+ if (unit < 16)
+ __small_sprintf (win32_path, "\\Device\\Floppy%d", unit);
+ else if (unit < 32)
+ __small_sprintf (win32_path, "\\Device\\CdRom%d", unit - 16);
+ else if (unit < 224)
+ __small_sprintf (win32_path, "\\Device\\Harddisk%d\\Partition%d",
+ (unit - 32) / 16, unit % 16);
+ else
+ __small_sprintf (win32_path, "\\DosDevices\\%c:", unit - 224 + 'A');
+ break;
+ default:
+ __small_sprintf (win32_path, devfmt, unit);
+ break;
+ }
return TRUE;
}
@@ -913,7 +1154,13 @@ normalize_win32_path (const char *src, char *dst)
if (beg_src_slash && isdirsep (src[1]))
{
*dst++ = '\\';
- ++src;
+ src++;
+ if (src[1] == '.' && isdirsep (src[2]))
+ {
+ *dst++ = '\\';
+ *dst++ = '.';
+ src += 2;
+ }
}
else if (strchr (src, ':') == NULL && *src != '/')
{
@@ -1063,14 +1310,7 @@ slash_unc_prefix_p (const char *path)
return ret && isalnum (p[1]);
}
-/* conv_path_list: Convert a list of path names to/from Win32/POSIX.
-
- SRC is not a const char * because we temporarily modify it to ease
- the implementation.
-
- I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
- We certainly don't want to handle that here, but it is something for
- the caller to think about. */
+/* conv_path_list: Convert a list of path names to/from Win32/POSIX. */
static void
conv_path_list (const char *src, char *dst, int to_posix_p)
@@ -1083,25 +1323,20 @@ conv_path_list (const char *src, char *dst, int to_posix_p)
? cygwin_conv_to_posix_path
: cygwin_conv_to_win32_path);
- do
+ char *srcbuf = (char *) alloca (strlen (src) + 1);
+
+ for (;;)
{
- s = strchr (src, src_delim);
- if (s)
- {
- *s = 0;
- (*conv_fn) (src[0] != 0 ? src : ".", d);
- d += strlen (d);
- *d++ = dst_delim;
- *s = src_delim;
- src = s + 1;
- }
- else
- {
- /* Last one. */
- (*conv_fn) (src[0] != 0 ? src : ".", d);
- }
+ s = strccpy (srcbuf, &src, src_delim);
+ int len = s - srcbuf;
+ if (len >= MAX_PATH)
+ srcbuf[MAX_PATH - 1] = '\0';
+ (*conv_fn) (len ? srcbuf : ".", d);
+ if (!*src++)
+ break;
+ d = strchr (d, '\0');
+ *d++ = dst_delim;
}
- while (s != NULL);
}
/* init: Initialize the mount table. */
@@ -1110,13 +1345,28 @@ void
mount_info::init ()
{
nmounts = 0;
- had_to_create_mount_areas = 0;
/* Fetch the mount table and cygdrive-related information from
the registry. */
from_registry ();
}
+static void
+set_flags (unsigned *flags, unsigned val)
+{
+ *flags = val;
+ if (!(*flags & PATH_BINARY))
+ {
+ *flags |= PATH_TEXT;
+ debug_printf ("flags: text (%p)", *flags & (PATH_TEXT | PATH_BINARY));
+ }
+ else
+ {
+ *flags |= PATH_BINARY;
+ debug_printf ("flags: binary (%p)", *flags & (PATH_TEXT | PATH_BINARY));
+ }
+}
+
/* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
the result in win32_path.
@@ -1179,7 +1429,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst,
return rc;
}
- *flags = set_flags_from_win32_path (dst);
+ set_flags (flags, (unsigned) set_flags_from_win32_path (dst));
goto out;
}
@@ -1208,7 +1458,6 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst,
if (rc)
{
debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
- *flags = 0;
return rc;
}
}
@@ -1224,12 +1473,30 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst,
/* Check if the cygdrive prefix was specified. If so, just strip
off the prefix and transform it into an MS-DOS path. */
MALLOC_CHECK;
- if (iscygdrive_device (pathbuf))
+ if (isproc (pathbuf))
{
- if (!cygdrive_win32_path (pathbuf, dst, 0))
+ devn = fhandler_proc::get_proc_fhandler (pathbuf);
+ if (devn == FH_BAD)
+ return ENOENT;
+ }
+ else if (iscygdrive (pathbuf))
+ {
+ int n = mount_table->cygdrive_len - 1;
+ if (!pathbuf[n] ||
+ (pathbuf[n] == '/' && pathbuf[n + 1] == '.' && !pathbuf[n + 2]))
+ {
+ unit = 0;
+ dst[0] = '\0';
+ if (mount_table->cygdrive_len > 1)
+ devn = FH_CYGDRIVE;
+ }
+ else if (cygdrive_win32_path (pathbuf, dst, unit))
+ {
+ set_flags (flags, (unsigned) cygdrive_flags);
+ goto out;
+ }
+ else if (mount_table->cygdrive_len > 1)
return ENOENT;
- *flags = cygdrive_flags;
- goto out;
}
int chrooted_path_len;
@@ -1265,7 +1532,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst,
if (i >= nmounts)
{
backslashify (pathbuf, dst, 0); /* just convert */
- *flags = 0;
+ set_flags (flags, PATH_BINARY);
}
else
{
@@ -1295,9 +1562,12 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst,
dst[n++] = '\\';
strcpy (dst + n, p);
backslashify (dst, dst, 0);
- *flags = mi->flags;
+ set_flags (flags, (unsigned) mi->flags);
}
+ if (!isvirtual_dev (devn))
+ win32_device_name (src_path, dst, devn, unit);
+
out:
MALLOC_CHECK;
if (chroot_ok || cygheap->root.ischroot_native (dst))
@@ -1345,17 +1615,27 @@ mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_
}
int
-mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
+mount_info::cygdrive_win32_path (const char *src, char *dst, int& unit)
{
+ int res;
const char *p = src + cygdrive_len;
if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
- return 0;
- dst[0] = *p;
- dst[1] = ':';
- strcpy (dst + 2, p + 1);
- backslashify (dst, dst, trailing_slash_p || !dst[2]);
+ {
+ unit = -1;
+ dst[0] = '\0';
+ res = 0;
+ }
+ else
+ {
+ dst[0] = cyg_tolower (*p);
+ dst[1] = ':';
+ strcpy (dst + 2, p + 1);
+ backslashify (dst, dst, !dst[2]);
+ unit = dst[0];
+ res = 1;
+ }
debug_printf ("src '%s', dst '%s'", src, dst);
- return 1;
+ return res;
}
/* conv_to_posix_path: Ensure src_path is a POSIX path.
@@ -1496,7 +1776,7 @@ mount_info::set_flags_from_win32_path (const char *p)
if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
return mi.flags;
}
- return 0;
+ return PATH_BINARY;
}
/* read_mounts: Given a specific regkey, read mounts from under its
@@ -1542,7 +1822,7 @@ mount_info::read_mounts (reg_key& r)
mount_flags = subkey.get_int ("flags", 0);
/* Add mount_item corresponding to registry mount point. */
- res = mount_table->add_item (native_path, posix_path, mount_flags, FALSE);
+ res = mount_table->add_item (native_path, posix_path, mount_flags, false);
if (res && get_errno () == EMFILE)
break; /* The number of entries exceeds MAX_MOUNTS */
}
@@ -1569,16 +1849,10 @@ mount_info::from_registry ()
/* Then read mounts from system-wide mount table. */
reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
read_mounts (r1);
-
- /* If we had to create both user and system mount areas, import
- old mounts. */
- if (had_to_create_mount_areas == 2)
- import_v1_mounts ();
}
/* add_reg_mount: Add mount item to registry. Return zero on success,
@@ -1615,8 +1889,7 @@ mount_info::add_reg_mount (const char * native_path, const char * posix_path, un
{
/* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
@@ -1664,8 +1937,7 @@ mount_info::del_reg_mount (const char * posix_path, unsigned flags)
sys_mount_table_counter++;
cygwin_shared->sys_mount_table_counter++;
reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
res = reg_sys.kill (posix_path);
@@ -1690,42 +1962,30 @@ mount_info::read_cygdrive_info_from_registry ()
/* reg_key for user path prefix in HKEY_CURRENT_USER. */
reg_key r;
- if (r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
- "") != 0)
+ if (r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive), "") != 0)
{
/* Didn't find the user path prefix so check the system path prefix. */
/* reg_key for system path prefix in HKEY_LOCAL_MACHINE. */
reg_key r2 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
- if (r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
- "") != 0)
- {
- /* Didn't find either so write the default to the registry and use it.
- NOTE: We are writing and using the user path prefix. */
- write_cygdrive_info_to_registry (CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX,
- MOUNT_AUTO);
- }
- else
- {
- /* Fetch system cygdrive_flags from registry; returns MOUNT_AUTO on
- error. */
- cygdrive_flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
- slashify (cygdrive, cygdrive, 1);
- cygdrive_len = strlen(cygdrive);
- }
+ if (r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive,
+ sizeof (cygdrive), ""))
+ strcpy (cygdrive, CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX);
+ cygdrive_flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_CYGDRIVE);
+ slashify (cygdrive, cygdrive, 1);
+ cygdrive_len = strlen (cygdrive);
}
else
{
- /* Fetch user cygdrive_flags from registry; returns MOUNT_AUTO on
+ /* Fetch user cygdrive_flags from registry; returns MOUNT_CYGDRIVE on
error. */
- cygdrive_flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
+ cygdrive_flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_CYGDRIVE);
slashify (cygdrive, cygdrive, 1);
- cygdrive_len = strlen(cygdrive);
+ cygdrive_len = strlen (cygdrive);
}
}
@@ -1748,8 +2008,7 @@ mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsign
/* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
HKEY_LOCAL_MACHINE. */
reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
@@ -1784,7 +2043,7 @@ mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsign
{
slashify (cygdrive_prefix, mount_table->cygdrive, 1);
mount_table->cygdrive_flags = flags;
- mount_table->cygdrive_len = strlen(mount_table->cygdrive);
+ mount_table->cygdrive_len = strlen (mount_table->cygdrive);
}
return 0;
@@ -1805,8 +2064,7 @@ mount_info::remove_cygdrive_info_from_registry (const char *cygdrive_prefix, uns
/* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
HKEY_LOCAL_MACHINE. */
reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
@@ -1832,14 +2090,13 @@ mount_info::get_cygdrive_info (char *user, char *system, char* user_flags,
/* Get the user flags, if appropriate */
if (res == ERROR_SUCCESS)
{
- int flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
+ int flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_CYGDRIVE);
strcpy (user_flags, (flags & MOUNT_BINARY) ? "binmode" : "textmode");
}
/* Get the system path prefix from HKEY_LOCAL_MACHINE. */
reg_key r2 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
- CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
- CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
NULL);
int res2 = r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, system, MAX_PATH, "");
@@ -1847,7 +2104,7 @@ mount_info::get_cygdrive_info (char *user, char *system, char* user_flags,
/* Get the system flags, if appropriate */
if (res2 == ERROR_SUCCESS)
{
- int flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
+ int flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_CYGDRIVE);
strcpy (system_flags, (flags & MOUNT_BINARY) ? "binmode" : "textmode");
}
@@ -2023,7 +2280,7 @@ int
mount_info::del_item (const char *path, unsigned flags, int reg_p)
{
char pathtmp[MAX_PATH];
- int posix_path_p = FALSE;
+ int posix_path_p = false;
/* Something's wrong if path is NULL or empty. */
if (path == NULL || *path == 0 || !isabspath (path))
@@ -2071,88 +2328,13 @@ mount_info::del_item (const char *path, unsigned flags, int reg_p)
return -1;
}
-/* read_v1_mounts: Given a reg_key to an old mount table registry area,
- read in the mounts. The "which" arg contains zero if we're reading
- the user area and MOUNT_SYSTEM if we're reading the system area.
- This way we can store the mounts read in the appropriate place when
- they are written back to the new registry layout. */
-
-void
-mount_info::read_v1_mounts (reg_key r, unsigned which)
-{
- unsigned mountflags = 0;
-
- /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
- for (int i = 0; i < 30; i++)
- {
- char key_name[10];
- char win32path[MAX_PATH];
- char unixpath[MAX_PATH];
-
- __small_sprintf (key_name, "%02x", i);
-
- reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
-
- /* The registry names are historical but useful so are left alone. */
- k.get_string ("native", win32path, sizeof (win32path), "");
- k.get_string ("unix", unixpath, sizeof (unixpath), "");
-
- /* Does this entry contain something? */
- if (*win32path != 0)
- {
- mountflags = 0;
-
- if (k.get_int ("fbinary", 0))
- mountflags |= MOUNT_BINARY;
-
- /* Or in zero or MOUNT_SYSTEM depending on which table
- we're reading. */
- mountflags |= which;
-
- int res = mount_table->add_item (win32path, unixpath, mountflags, TRUE);
- if (res && get_errno () == EMFILE)
- break; /* The number of entries exceeds MAX_MOUNTS */
- }
- }
-}
-
-/* import_v1_mounts: If v1 mounts are present, load them and write
- the new entries to the new registry area. */
-
-void
-mount_info::import_v1_mounts ()
-{
- reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
- "SOFTWARE",
- "Cygnus Solutions",
- "CYGWIN.DLL setup",
- "b15.0",
- "mounts",
- NULL);
-
- nmounts = 0;
-
- /* First read mounts from user's table. */
- read_v1_mounts (r, 0);
-
- /* Then read mounts from system-wide mount table. */
- reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
- "SOFTWARE",
- "Cygnus Solutions",
- "CYGWIN.DLL setup",
- "b15.0",
- "mounts",
- NULL);
- read_v1_mounts (r1, MOUNT_SYSTEM);
-}
-
/************************* mount_item class ****************************/
static mntent *
fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
{
#ifdef _MT_SAFE
- struct mntent &ret=_reent_winsup()->mntbuf;
+ struct mntent &ret=_reent_winsup ()->mntbuf;
#else
static NO_COPY struct mntent ret;
#endif
@@ -2160,7 +2342,7 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
/* Remove drivenum from list if we see a x: style path */
if (strlen (native_path) == 2 && native_path[1] == ':')
{
- int drivenum = tolower (native_path[0]) - 'a';
+ int drivenum = cyg_tolower (native_path[0]) - 'a';
if (drivenum >= 0 && drivenum <= 31)
available_drives &= ~(1 << drivenum);
}
@@ -2195,8 +2377,10 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
strcat (_reent_winsup ()->mnt_opts, (char *) ",cygexec");
else if (flags & MOUNT_EXEC)
strcat (_reent_winsup ()->mnt_opts, (char *) ",exec");
+ else if (flags & MOUNT_NOTEXEC)
+ strcat (_reent_winsup ()->mnt_opts, (char *) ",noexec");
- if ((flags & MOUNT_AUTO)) /* cygdrive */
+ if ((flags & MOUNT_CYGDRIVE)) /* cygdrive */
strcat (_reent_winsup ()->mnt_opts, (char *) ",noumount");
ret.mnt_opts = _reent_winsup ()->mnt_opts;
@@ -2228,7 +2412,7 @@ cygdrive_getmntent ()
__small_sprintf (native_path, "%c:\\", drive);
if (GetDriveType (native_path) == DRIVE_REMOVABLE ||
- GetFileAttributes (native_path) == (DWORD) -1)
+ GetFileAttributes (native_path) == INVALID_FILE_ATTRIBUTES)
{
available_drives &= ~mask;
continue;
@@ -2274,15 +2458,14 @@ mount_item::init (const char *native, const char *posix, unsigned mountflags)
that will cause paths under win32_path to be translated to paths
under posix_path. */
-extern "C"
-int
+extern "C" int
mount (const char *win32_path, const char *posix_path, unsigned flags)
{
int res = -1;
- if (flags & MOUNT_AUTO) /* normal mount */
+ if (flags & MOUNT_CYGDRIVE) /* normal mount */
{
- /* When flags include MOUNT_AUTO, take this to mean that
+ /* When flags include MOUNT_CYGDRIVE, take this to mean that
we actually want to change the cygdrive prefix and flags
without actually mounting anything. */
res = mount_table->write_cygdrive_info_to_registry (posix_path, flags);
@@ -2300,8 +2483,7 @@ mount (const char *win32_path, const char *posix_path, unsigned flags)
mount from the user or global mount registry table, assume the user
table. */
-extern "C"
-int
+extern "C" int
umount (const char *path)
{
return cygwin_umount (path, 0);
@@ -2311,15 +2493,14 @@ umount (const char *path)
parameter that specifies whether to umount from the user or system-wide
registry area. */
-extern "C"
-int
+extern "C" int
cygwin_umount (const char *path, unsigned flags)
{
int res = -1;
- if (flags & MOUNT_AUTO)
+ if (flags & MOUNT_CYGDRIVE)
{
- /* When flags include MOUNT_AUTO, take this to mean that we actually want
+ /* When flags include MOUNT_CYGDRIVE, take this to mean that we actually want
to remove the cygdrive prefix and flags without actually unmounting
anything. */
res = mount_table->remove_cygdrive_info_from_registry (path, flags);
@@ -2333,8 +2514,7 @@ cygwin_umount (const char *path, unsigned flags)
return res;
}
-extern "C"
-FILE *
+extern "C" FILE *
setmntent (const char *filep, const char *)
{
iteration = 0;
@@ -2342,15 +2522,13 @@ setmntent (const char *filep, const char *)
return (FILE *) filep;
}
-extern "C"
-struct mntent *
+extern "C" struct mntent *
getmntent (FILE *)
{
return mount_table->getmntent (iteration++);
}
-extern "C"
-int
+extern "C" int
endmntent (FILE *)
{
return 1;
@@ -2375,19 +2553,18 @@ set_symlink_ea (const char* frompath, const char* topath)
if (!NTWriteEA (frompath, SYMLINK_EA_NAME, topath, strlen (topath) + 1))
{
debug_printf ("Cannot save symlink in EA");
- return FALSE;
+ return false;
}
return TRUE;
}
/* Create a symlink from FROMPATH to TOPATH. */
-/* If TRUE create symlinks as Windows shortcuts, if FALSE create symlinks
+/* If TRUE create symlinks as Windows shortcuts, if false create symlinks
as normal files with magic number and system bit set. */
int allow_winsymlinks = TRUE;
-extern "C"
-int
+extern "C" int
symlink (const char *topath, const char *frompath)
{
HANDLE h;
@@ -2401,7 +2578,7 @@ symlink (const char *topath, const char *frompath)
/* POSIX says that empty 'frompath' is invalid input whlie empty
'topath' is valid -- it's symlink resolver job to verify if
- symlink contents point to existing filesystem object */
+ symlink contents point to existing filesystem object */
if (check_null_empty_str_errno (topath) == EFAULT ||
check_null_empty_str_errno (frompath))
goto done;
@@ -2413,7 +2590,7 @@ symlink (const char *topath, const char *frompath)
}
win32_path.check (frompath, PC_SYM_NOFOLLOW);
- if (allow_winsymlinks && !win32_path.error)
+ if (allow_winsymlinks && !win32_path.exists ())
{
strcpy (from, frompath);
strcat (from, ".lnk");
@@ -2447,7 +2624,7 @@ symlink (const char *topath, const char *frompath)
}
backslashify (topath, w32topath, 0);
}
- if (!cp || GetFileAttributes (w32topath) == (DWORD)-1)
+ if (!cp || GetFileAttributes (w32topath) == INVALID_FILE_ATTRIBUTES)
{
win32_topath.check (topath, PC_SYM_NOFOLLOW);
if (!cp || win32_topath.error != ENOENT)
@@ -2464,10 +2641,10 @@ symlink (const char *topath, const char *frompath)
set_security_attribute (S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO,
&sa, alloca (4096), 4096);
- h = CreateFileA(win32_path, GENERIC_WRITE, 0, &sa,
+ h = CreateFile (win32_path, GENERIC_WRITE, 0, &sa,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
- __seterrno ();
+ __seterrno ();
else
{
BOOL success;
@@ -2511,9 +2688,16 @@ symlink (const char *topath, const char *frompath)
set_file_attribute (win32_path.has_acls (),
win32_path.get_win32 (),
S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
- SetFileAttributesA (win32_path.get_win32 (),
- allow_winsymlinks ? FILE_ATTRIBUTE_READONLY
- : FILE_ATTRIBUTE_SYSTEM);
+
+ DWORD attr = allow_winsymlinks ? FILE_ATTRIBUTE_READONLY
+ : FILE_ATTRIBUTE_SYSTEM;
+#ifdef HIDDEN_DOT_FILES
+ cp = strrchr (win32_path, '\\');
+ if ((cp && cp[1] == '.') || *win32_path == '.')
+ attr |= FILE_ATTRIBUTE_HIDDEN;
+#endif
+ SetFileAttributes (win32_path.get_win32 (), attr);
+
if (win32_path.fs_fast_ea ())
set_symlink_ea (win32_path, topath);
res = 0;
@@ -2531,6 +2715,68 @@ done:
return res;
}
+static BOOL
+cmp_shortcut_header (const char *file_header)
+{
+ create_shortcut_header ();
+ return memcmp (shortcut_header, file_header, SHORTCUT_HDR_SIZE);
+}
+
+static int
+check_shortcut (const char *path, DWORD fileattr, HANDLE h,
+ char *contents, int *error, unsigned *pflags)
+{
+ char file_header[SHORTCUT_HDR_SIZE];
+ unsigned short len;
+ int res = 0;
+ DWORD got = 0;
+
+ /* Valid Cygwin & U/WIN shortcuts are R/O. */
+ if (!(fileattr & FILE_ATTRIBUTE_READONLY))
+ goto file_not_symlink;
+ /* Read the files header information. This is used to check for a
+ Cygwin or U/WIN shortcut or later to check for executable files. */
+ if (!ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0))
+ {
+ *error = EIO;
+ goto close_it;
+ }
+ /* Check header if the shortcut is really created by Cygwin or U/WIN. */
+ if (got != SHORTCUT_HDR_SIZE || cmp_shortcut_header (file_header))
+ goto file_not_symlink;
+ /* Next 2 byte are USHORT, containing length of description entry. */
+ if (!ReadFile (h, &len, sizeof len, &got, 0))
+ {
+ *error = EIO;
+ goto close_it;
+ }
+ if (got != sizeof len || len == 0 || len > MAX_PATH)
+ goto file_not_symlink;
+ /* Now read description entry. */
+ if (!ReadFile (h, contents, len, &got, 0))
+ {
+ *error = EIO;
+ goto close_it;
+ }
+ if (got != len)
+ goto file_not_symlink;
+ contents[len] = '\0';
+ res = len;
+ if (res) /* It's a symlink. */
+ *pflags = PATH_SYMLINK;
+ goto close_it;
+
+file_not_symlink:
+ /* Not a symlink, see if executable. */
+ if (!(*pflags & PATH_ALL_EXEC) && has_exec_chars (file_header, got))
+ *pflags |= PATH_EXEC;
+
+close_it:
+ CloseHandle (h);
+ return res;
+}
+
+
static int
check_sysfile (const char *path, DWORD fileattr, HANDLE h,
char *contents, int *error, unsigned *pflags)
@@ -2655,8 +2901,43 @@ suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
int
suffix_scan::next ()
{
- if (suffixes)
+ for (;;)
{
+ if (!suffixes)
+ switch (nextstate)
+ {
+ case SCAN_BEG:
+ suffixes = suffixes_start;
+ if (!suffixes)
+ {
+ nextstate = SCAN_LNK;
+ return 1;
+ }
+ if (!*suffixes->name)
+ suffixes++;
+ nextstate = SCAN_EXTRALNK;
+ /* fall through to suffix checking below */
+ break;
+ case SCAN_HASLNK:
+ nextstate = SCAN_EXTRALNK; /* Skip SCAN_BEG */
+ return 1;
+ case SCAN_LNK:
+ case SCAN_EXTRALNK:
+ strcpy (eopath, ".lnk");
+ nextstate = SCAN_DONE;
+ return 1;
+ case SCAN_JUSTCHECK:
+ nextstate = SCAN_APPENDLNK;
+ return 1;
+ case SCAN_APPENDLNK:
+ strcat (eopath, ".lnk");
+ nextstate = SCAN_DONE;
+ return 1;
+ default:
+ *eopath = '\0';
+ return 0;
+ }
+
while (suffixes && suffixes->name)
if (!suffixes->addon)
suffixes++;
@@ -2670,39 +2951,6 @@ suffix_scan::next ()
}
suffixes = NULL;
}
-
- switch (nextstate)
- {
- case SCAN_BEG:
- suffixes = suffixes_start;
- if (!suffixes)
- nextstate = SCAN_LNK;
- else
- {
- if (!*suffixes->name)
- suffixes++;
- nextstate = SCAN_EXTRALNK;
- }
- return 1;
- case SCAN_HASLNK:
- nextstate = SCAN_EXTRALNK; /* Skip SCAN_BEG */
- return 1;
- case SCAN_LNK:
- case SCAN_EXTRALNK:
- strcpy (eopath, ".lnk");
- nextstate = SCAN_DONE;
- return 1;
- case SCAN_JUSTCHECK:
- nextstate = SCAN_APPENDLNK;
- return 1;
- case SCAN_APPENDLNK:
- strcat (eopath, ".lnk");
- nextstate = SCAN_DONE;
- return 1;
- default:
- *eopath = '\0';
- return 0;
- }
}
/* Check if PATH is a symlink. PATH must be a valid Win32 path name.
@@ -2736,18 +2984,18 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
pflags &= ~PATH_SYMLINK;
- case_clash = FALSE;
+ case_clash = false;
while (suffix.next ())
{
error = 0;
- fileattr = GetFileAttributesA (suffix.path);
- if (fileattr == (DWORD) -1)
+ fileattr = GetFileAttributes (suffix.path);
+ if (fileattr == INVALID_FILE_ATTRIBUTES)
{
- /* The GetFileAttributesA call can fail for reasons that don't
+ /* The GetFileAttributes call can fail for reasons that don't
matter, so we just return 0. For example, getting the
attributes of \\HOST will typically fail. */
- debug_printf ("GetFileAttributesA (%s) failed", suffix.path);
+ debug_printf ("GetFileAttributes (%s) failed", suffix.path);
error = geterrno_from_win_error (GetLastError (), EACCES);
continue;
}
@@ -2789,8 +3037,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
/* Open the file. */
- h = CreateFileA (suffix.path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, 0);
+ h = CreateFile (suffix.path, GENERIC_READ, FILE_SHARE_READ,
+ &sec_none_nih, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
res = -1;
if (h == INVALID_HANDLE_VALUE)
goto file_not_symlink;
@@ -2809,7 +3057,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
if (!suffix.lnk_match () || !ext_tacked_on)
goto file_not_symlink;
- fileattr = (DWORD) -1;
+ fileattr = INVALID_FILE_ATTRIBUTES;
continue; /* in case we're going to tack *another* .lnk on this filename. */
case 2:
res = check_sysfile (suffix.path, fileattr, h, contents, &error, &pflags);
@@ -2820,7 +3068,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
break;
file_not_symlink:
- is_symlink = FALSE;
+ is_symlink = false;
syscall_printf ("not a symlink");
res = 0;
break;
@@ -2833,7 +3081,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
/* Check the correct case of the last path component (given in DOS style).
Adjust the case in this->path if pcheck_case == PCHECK_ADJUST or return
- FALSE if pcheck_case == PCHECK_STRICT.
+ false if pcheck_case == PCHECK_STRICT.
Dont't call if pcheck_case == PCHECK_RELAXED.
*/
@@ -2863,7 +3111,7 @@ symlink_info::case_check (char *path)
/* If check is set to STRICT, a wrong case results
in returning a ENOENT. */
if (pcheck_case == PCHECK_STRICT)
- return FALSE;
+ return false;
/* PCHECK_ADJUST adjusts the case in the incoming
path which points to the path in *this. */
@@ -2875,8 +3123,7 @@ symlink_info::case_check (char *path)
/* readlink system call */
-extern "C"
-int
+extern "C" int
readlink (const char *path, char *buf, int buflen)
{
extern suffix_info stat_suffixes[];
@@ -2904,7 +3151,7 @@ readlink (const char *path, char *buf, int buflen)
if (!pathbuf.issymlink ())
{
- if (pathbuf.fileattr != (DWORD) -1)
+ if (pathbuf.exists ())
set_errno (EINVAL);
return -1;
}
@@ -2964,7 +3211,7 @@ hash_path_name (unsigned long hash, const char *name)
hash = cygheap->cwd.get_hash ();
if (name[0] == '.' && name[1] == '\0')
return hash;
- hash += hash_path_name (hash, "\\");
+ hash = (hash << 5) - hash + '\\';
}
}
@@ -2973,9 +3220,8 @@ hashit:
\a\b\. but allow a single \ if that's all there is. */
do
{
- int ch = cyg_tolower(*name);
- hash += ch + (ch << 17);
- hash ^= hash >> 2;
+ int ch = cyg_tolower (*name);
+ hash = (hash << 5) - hash + ch;
}
while (*++name != '\0' &&
!(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
@@ -2986,16 +3232,15 @@ char *
getcwd (char *buf, size_t ulen)
{
char* res = NULL;
- if (ulen == 0)
+ if (ulen == 0 && buf)
set_errno (EINVAL);
- else if (!__check_null_invalid_struct_errno (buf, ulen))
+ else if (buf == NULL || !__check_null_invalid_struct_errno (buf, ulen))
res = cygheap->cwd.get (buf, 1, 1, ulen);
return res;
}
/* getwd: standards? */
-extern "C"
-char *
+extern "C" char *
getwd (char *buf)
{
return getcwd (buf, MAX_PATH);
@@ -3054,7 +3299,7 @@ chdir (const char *in_dir)
return -1;
}
- char *native_dir = path.get_win32 ();
+ const char *native_dir = path.get_win32 ();
/* Check to see if path translates to something like C:.
If it does, append a \ to the native directory specification to
@@ -3062,12 +3307,30 @@ chdir (const char *in_dir)
the last directory visited on the given drive. */
if (isdrive (native_dir) && !native_dir[2])
{
- native_dir[2] = '\\';
- native_dir[3] = '\0';
+ path.get_win32 ()[2] = '\\';
+ path.get_win32 ()[3] = '\0';
+ }
+ int res;
+ int devn = path.get_devn ();
+ if (!isvirtual_dev (devn))
+ res = SetCurrentDirectory (native_dir) ? 0 : -1;
+ else if (!path.exists ())
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+ else if (!path.isdir ())
+ {
+ set_errno (ENOTDIR);
+ return -1;
+ }
+ else
+ {
+ native_dir = "c:\\";
+ res = 0;
}
- int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
- /* If res < 0, we didn't change to a new directory.
+ /* If res != 0, we didn't change to a new directory.
Otherwise, set the current windows and posix directory cache from input.
If the specified directory is a MS-DOS style directory or if the directory
was symlinked, convert the MS-DOS path back to posix style. Otherwise just
@@ -3077,13 +3340,13 @@ chdir (const char *in_dir)
do when we detect a symlink? Should we instead rebuild the posix path from
the input by traversing links? This would be an expensive operation but
we'll see if Cygwin mailing list users whine about the current behavior. */
- if (res == -1)
+ if (res)
__seterrno ();
- else if (!path.has_symlinks () && strpbrk (dir, ":\\") == NULL
- && pcheck_case == PCHECK_RELAXED)
- cygheap->cwd.set (path, dir);
+ else if ((!path.has_symlinks () && strpbrk (dir, ":\\") == NULL
+ && pcheck_case == PCHECK_RELAXED) || isvirtual_dev (devn))
+ cygheap->cwd.set (native_dir, dir);
else
- cygheap->cwd.set (path, NULL);
+ cygheap->cwd.set (native_dir, NULL);
/* Note that we're accessing cwd.posix without a lock here. I didn't think
it was worth locking just for strace. */
@@ -3093,39 +3356,20 @@ chdir (const char *in_dir)
return res;
}
-extern "C"
-int
+extern "C" int
fchdir (int fd)
{
+ int res;
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
- {
- syscall_printf ("-1 = fchdir (%d)", fd);
- set_errno (EBADF);
- return -1;
- }
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fchdir");
- int ret = chdir (cygheap->fdtab[fd]->get_name ());
- if (ret == 0)
- {
- /* The name in the fhandler is explicitely overwritten with the full path.
- Otherwise fchmod() to a path originally given as a relative path could
- end up in a completely different directory. Imagine:
-
- fd = open ("..");
- fchmod(fd);
- fchmod(fd);
-
- The 2nd fchmod should chdir to the same dir as the first call, not
- to it's parent dir. */
- char posix_path[MAX_PATH];
- cygheap->fdtab.reset_unix_path_name (fd, cygheap->cwd.get (posix_path, 1, 1));
- }
+ cygheap_fdget cfd (fd);
+ if (cfd >= 0)
+ res = chdir (cfd->get_win32_name ());
+ else
+ res = -1;
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fchdir");
- syscall_printf ("%d = fchdir (%d)", ret, fd);
- return ret;
+ syscall_printf ("%d = fchdir (%d)", res, fd);
+ return res;
}
/******************** Exported Path Routines *********************/
@@ -3133,40 +3377,39 @@ fchdir (int fd)
/* Cover functions to the path conversion routines.
These are exported to the world as cygwin_foo by cygwin.din. */
-extern "C"
-int
+extern "C" int
cygwin_conv_to_win32_path (const char *path, char *win32_path)
{
path_conv p (path, PC_SYM_FOLLOW);
if (p.error)
{
+ win32_path[0] = '\0';
set_errno (p.error);
return -1;
}
- strcpy (win32_path, p.get_win32 ());
+ strcpy (win32_path, p);
return 0;
}
-extern "C"
-int
+extern "C" int
cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
{
path_conv p (path, PC_SYM_FOLLOW | PC_FULL);
if (p.error)
{
+ win32_path[0] = '\0';
set_errno (p.error);
return -1;
}
- strcpy (win32_path, p.get_win32 ());
+ strcpy (win32_path, p);
return 0;
}
/* This is exported to the world as cygwin_foo by cygwin.din. */
-extern "C"
-int
+extern "C" int
cygwin_conv_to_posix_path (const char *path, char *posix_path)
{
if (check_null_empty_str_errno (path))
@@ -3175,8 +3418,7 @@ cygwin_conv_to_posix_path (const char *path, char *posix_path)
return 0;
}
-extern "C"
-int
+extern "C" int
cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
{
if (check_null_empty_str_errno (path))
@@ -3187,8 +3429,7 @@ cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
/* The realpath function is supported on some UNIX systems. */
-extern "C"
-char *
+extern "C" char *
realpath (const char *path, char *resolved)
{
int err;
@@ -3228,8 +3469,7 @@ DOCTOOL-START
DOCTOOL-END
*/
-extern "C"
-int
+extern "C" int
cygwin_posix_path_list_p (const char *path)
{
int posix_p = !(strchr (path, ';') || isdrive (path));
@@ -3270,30 +3510,26 @@ conv_path_list_buf_size (const char *path_list, int to_posix_p)
return size;
}
-extern "C"
-int
+extern "C" int
cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
{
return conv_path_list_buf_size (path_list, 1);
}
-extern "C"
-int
+extern "C" int
cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
{
return conv_path_list_buf_size (path_list, 0);
}
-extern "C"
-int
+extern "C" int
cygwin_win32_to_posix_path_list (const char *win32, char *posix)
{
conv_path_list (win32, posix, 1);
return 0;
}
-extern "C"
-int
+extern "C" int
cygwin_posix_to_win32_path_list (const char *posix, char *win32)
{
conv_path_list (posix, win32, 0);
@@ -3319,8 +3555,7 @@ cygwin_posix_to_win32_path_list (const char *posix, char *win32)
c:/foo -> `c:/' / `foo'
*/
-extern "C"
-void
+extern "C" void
cygwin_split_path (const char *path, char *dir, char *file)
{
int dir_started_p = 0;
@@ -3390,9 +3625,9 @@ DWORD
cwdstuff::get_hash ()
{
DWORD hashnow;
- lock->acquire ();
+ cwd_lock->acquire ();
hashnow = hash;
- lock->release ();
+ cwd_lock->release ();
return hashnow;
}
@@ -3400,7 +3635,7 @@ cwdstuff::get_hash ()
void
cwdstuff::init ()
{
- lock = new_muto (FALSE, "cwd");
+ new_muto (cwd_lock);
}
/* Get initial cwd. Should only be called once in a
@@ -3408,7 +3643,7 @@ cwdstuff::init ()
bool
cwdstuff::get_initial ()
{
- lock->acquire ();
+ cwd_lock->acquire ();
if (win32)
return 1;
@@ -3425,9 +3660,9 @@ cwdstuff::get_initial ()
if (len == 0)
{
__seterrno ();
- lock->release ();
+ cwd_lock->release ();
debug_printf ("get_initial_cwd failed, %E");
- lock->release ();
+ cwd_lock->release ();
return 0;
}
set (NULL);
@@ -3444,7 +3679,7 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd)
if (win32_cwd)
{
- lock->acquire ();
+ cwd_lock->acquire ();
win32 = (char *) crealloc (win32, strlen (win32_cwd) + 1);
strcpy (win32, win32_cwd);
}
@@ -3460,7 +3695,7 @@ cwdstuff::set (const char *win32_cwd, const char *posix_cwd)
hash = hash_path_name (0, win32);
if (win32_cwd)
- lock->release ();
+ cwd_lock->release ();
return;
}
@@ -3490,7 +3725,7 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
else
tocopy = posix;
- debug_printf("posix %s", posix);
+ debug_printf ("posix %s", posix);
if (strlen (tocopy) >= ulen)
{
set_errno (ERANGE);
@@ -3505,7 +3740,7 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
strcpy (buf, "/");
}
- lock->release ();
+ cwd_lock->release ();
out:
syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index 1052debda..c8bb7cead 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -1,6 +1,6 @@
/* path.h: path data structures
- Copyright 1996, 1997, 1998, 2000 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -23,7 +23,8 @@ enum pathconv_arg
PC_SYM_CONTENTS = 0x0008,
PC_FULL = 0x0010,
PC_NULLEMPTY = 0x0020,
- PC_CHECK_EA = 0x0040
+ PC_CHECK_EA = 0x0040,
+ PC_POSIX = 0x0080
};
enum case_checking
@@ -43,10 +44,11 @@ enum path_types
PATH_SYMLINK = MOUNT_SYMLINK,
PATH_BINARY = MOUNT_BINARY,
PATH_EXEC = MOUNT_EXEC,
+ PATH_NOTEXEC = MOUNT_NOTEXEC,
PATH_CYGWIN_EXEC = MOUNT_CYGWIN_EXEC,
PATH_ALL_EXEC = (PATH_CYGWIN_EXEC | PATH_EXEC),
+ PATH_TEXT = 0x02000000,
PATH_ISDISK = 0x04000000,
- PATH_NOTEXEC = 0x08000000,
PATH_HAS_SYMLINKS = 0x10000000,
PATH_HASBUGGYOPEN = 0x20000000,
PATH_SOCKET = 0x40000000,
@@ -54,18 +56,23 @@ enum path_types
};
class symlink_info;
-class path_conv
+struct fs_info
{
- char path[MAX_PATH];
+ char name[MAX_PATH];
char root_dir[MAX_PATH];
- char fs_name[MAX_PATH];
- DWORD fs_flags;
- DWORD fs_serial;
+ DWORD flags;
+ DWORD serial;
DWORD sym_opt; /* additional options to pass to symlink_info resolver */
- void add_ext_from_sym (symlink_info&);
- void update_fs_info (const char*);
+ DWORD is_remote_drive;
DWORD drive_type;
- bool is_remote_drive;
+ bool update (const char *);
+};
+class path_conv
+{
+ char path[MAX_PATH];
+ DWORD fileattr;
+ fs_info fs;
+ void add_ext_from_sym (symlink_info&);
public:
unsigned path_flags;
@@ -73,20 +80,27 @@ class path_conv
int error;
DWORD devn;
int unit;
- DWORD fileattr;
BOOL case_clash;
+ char *normalized_path;
int isdisk () const { return path_flags & PATH_ISDISK;}
- int isremote () const {return is_remote_drive;}
+ int isremote () const {return fs.is_remote_drive;}
int has_acls () const {return path_flags & PATH_HASACLS;}
int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;}
int hasgood_inode () const {return path_flags & PATH_HASACLS;} // Not strictly correct
int has_buggy_open () const {return path_flags & PATH_HASBUGGYOPEN;}
- int isbinary () const {return path_flags & PATH_BINARY;}
+ int binmode () const
+ {
+ if (path_flags & PATH_BINARY)
+ return O_BINARY;
+ if (path_flags & PATH_TEXT)
+ return O_TEXT;
+ return 0;
+ }
int issymlink () const {return path_flags & PATH_SYMLINK;}
int issocket () const {return path_flags & PATH_SOCKET;}
int iscygexec () const {return path_flags & PATH_CYGWIN_EXEC;}
- bool exists () const {return fileattr != (DWORD) -1;}
+ bool exists () const {return fileattr != INVALID_FILE_ATTRIBUTES;}
bool has_attribute (DWORD x) const {return exists () && (fileattr & x);}
int isdir () const {return has_attribute (FILE_ATTRIBUTE_DIRECTORY);}
executable_states exec_state ()
@@ -124,18 +138,28 @@ class path_conv
check (src, opt | PC_NULLEMPTY, suffixes);
}
- path_conv (): path_flags (0), known_suffix (NULL), error (0), devn (0), unit (0), fileattr (0xffffffff) {path[0] = '\0';}
+ path_conv (): fileattr (INVALID_FILE_ATTRIBUTES), path_flags (0),
+ known_suffix (NULL), error (0), devn (0), unit (0),
+ normalized_path (NULL) {path[0] = '\0';}
inline char *get_win32 () { return path; }
- operator char *() {return path; }
- operator DWORD &() {return fileattr; }
+ operator char *() {return path;}
+ operator const char *() {return path;}
+ operator DWORD &() {return fileattr;}
operator int &() {return (int) fileattr; }
+ char operator [](int i) const {return path[i];}
BOOL is_device () {return devn != FH_BAD && devn != FH_DISK;}
DWORD get_devn () {return devn == FH_BAD ? (DWORD) FH_DISK : devn;}
short get_unitn () {return devn == FH_BAD ? 0 : unit;}
DWORD file_attributes () {return fileattr;}
- DWORD get_drive_type () {return drive_type;}
- BOOL fs_fast_ea () {return sym_opt & PC_CHECK_EA;}
+ DWORD drive_type () {return fs.drive_type;}
+ BOOL fs_fast_ea () {return fs.sym_opt & PC_CHECK_EA;}
+ void set_path (const char *p) {strcpy (path, p);}
+ char *return_and_clear_normalized_path ();
+ const char * root_dir () { return fs.root_dir; }
+ DWORD volser () { return fs.serial; }
+ const char *volname () {return fs.name; }
+ void fillin (HANDLE h);
};
/* Symlink marker */
@@ -146,14 +170,25 @@ class path_conv
/* Socket marker */
#define SOCKET_COOKIE "!<socket >"
+/* The sizeof header written to a shortcut by Cygwin or U/WIN. */
+#define SHORTCUT_HDR_SIZE 76
+
/* Maximum depth of symlinks (after which ELOOP is issued). */
#define MAX_LINK_DEPTH 10
-
-int __stdcall get_device_number (const char *name, int &unit, BOOL from_conv = FALSE) __attribute__ ((regparm(3)));
int __stdcall slash_unc_prefix_p (const char *path) __attribute__ ((regparm(1)));
-const char * __stdcall find_exec (const char *name, path_conv& buf, const char *winenv = "PATH=",
- int null_if_notfound = 0, const char **known_suffix = NULL) __attribute__ ((regparm(3)));
+enum fe_types
+{
+ FE_NADA = 0, /* Nothing special */
+ FE_NNF = 1, /* Return NULL if not found */
+ FE_NATIVE = 2, /* Return native path in path_conv struct */
+ FE_CWD = 4 /* Search CWD for program */
+};
+const char * __stdcall find_exec (const char *name, path_conv& buf,
+ const char *winenv = "PATH=",
+ unsigned opt = FE_NADA,
+ const char **known_suffix = NULL)
+ __attribute__ ((regparm(3)));
/* Common macros for checking for invalid path names */
#define isdrive(s) (isalpha (*(s)) && (s)[1] == ':')
@@ -169,3 +204,5 @@ has_exec_chars (const char *buf, int len)
int pathmatch (const char *path1, const char *path2) __attribute__ ((regparm (2)));
int pathnmatch (const char *path1, const char *path2, int len) __attribute__ ((regparm (2)));
+
+int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__ ((regparm (3)));
diff --git a/winsup/cygwin/perthread.h b/winsup/cygwin/perthread.h
index 185cc04d6..f8682ae55 100644
--- a/winsup/cygwin/perthread.h
+++ b/winsup/cygwin/perthread.h
@@ -15,27 +15,6 @@ details. */
struct _reent;
extern struct _reent reent_data;
-extern DWORD *__stackbase __asm__ ("%fs:4");
-
-extern __inline struct _reent *
-get_reent ()
-{
- DWORD *base = __stackbase - 1;
-
- if (*base != PTMAGIC)
- return &reent_data;
- return (struct _reent *) base[-1];
-}
-
-extern inline void
-set_reent (struct _reent *r)
-{
- DWORD *base = __stackbase - 1;
-
- *base = PTMAGIC;
- base[-1] = (DWORD) r;
-}
-
#define PER_THREAD_FORK_CLEAR ((void *)0xffffffff)
class per_thread
{
@@ -69,14 +48,30 @@ public:
};
#if defined (NEED_VFORK)
-struct vfork_save
+class vfork_save
{
- int pid;
jmp_buf j;
+ int exitval;
+ public:
+ int pid;
DWORD frame[100];
char **vfork_ebp;
char **vfork_esp;
+ int ctty;
+ pid_t sid;
+ pid_t pgid;
int is_active () { return pid < 0; }
+ void restore_pid (int val)
+ {
+ pid = val;
+ longjmp (j, 1);
+ }
+ void restore_exit (int val)
+ {
+ exitval = val;
+ longjmp (j, 1);
+ }
+ friend int vfork ();
};
class per_thread_vfork : public per_thread
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 6e66e47a1..4591feded 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -1,6 +1,6 @@
/* pinfo.cc: process table support
- Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -18,7 +18,6 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "cygwin_version.h"
@@ -28,7 +27,7 @@ details. */
#include <ntdef.h>
#include "ntdll.h"
-static char NO_COPY pinfo_dummy[sizeof(pinfo)] = {0};
+static char NO_COPY pinfo_dummy[sizeof (_pinfo)] = {0};
pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks
@@ -62,33 +61,14 @@ set_myself (pid_t pid, HANDLE h)
myself->process_state |= PID_IN_USE;
myself->start_time = time (NULL); /* Register our starting time. */
- char buf[30];
- __small_sprintf (buf, "cYg%8x %x", _STRACE_INTERFACE_ACTIVATE_ADDR,
- &strace.active);
- OutputDebugString (buf);
-
- (void) GetModuleFileName (NULL, myself->progname,
- sizeof(myself->progname));
- if (strace.active)
- {
- strace.prntf (1, NULL, "**********************************************");
- strace.prntf (1, NULL, "Program name: %s (%d)", myself->progname, myself->pid);
- strace.prntf (1, NULL, "App version: %d.%d, api: %d.%d",
- user_data->dll_major, user_data->dll_minor,
- user_data->api_major, user_data->api_minor);
- strace.prntf (1, NULL, "DLL version: %d.%d, api: %d.%d",
- cygwin_version.dll_major, cygwin_version.dll_minor,
- cygwin_version.api_major, cygwin_version.api_minor);
- strace.prntf (1, NULL, "DLL build: %s", cygwin_version.dll_build_date);
- strace.prntf (1, NULL, "OS version: Windows %s", wincap.osname ());
- strace.prntf (1, NULL, "**********************************************");
- }
-
+ (void) GetModuleFileName (NULL, myself->progname, sizeof (myself->progname));
+ if (!strace.active)
+ strace.hello ();
return;
}
/* Initialize the process table entry for the current task.
- This is not called for fork'd tasks, only exec'd ones. */
+ This is not called for forked tasks, only execed ones. */
void __stdcall
pinfo_init (char **envp, int envc)
{
@@ -106,7 +86,7 @@ pinfo_init (char **envp, int envc)
myself->ppid = 1;
myself->pgid = myself->sid = myself->pid;
myself->ctty = -1;
- myself->uid = USHRT_MAX;
+ myself->uid = ILLEGAL_UID;
environ_init (NULL, 0); /* call after myself has been set up */
}
@@ -117,14 +97,17 @@ pinfo_init (char **envp, int envc)
void
_pinfo::exit (UINT n, bool norecord)
{
- if (!norecord)
- process_state = PID_EXITED;
-
- /* FIXME: There is a potential race between an execed process and its
- parent here. I hated to add a mutex just for this, though. */
- struct rusage r;
- fill_rusage (&r, hMainProc);
- add_rusage (&rusage_self, &r);
+ if (this)
+ {
+ if (!norecord)
+ process_state = PID_EXITED;
+
+ /* FIXME: There is a potential race between an execed process and its
+ parent here. I hated to add a mutex just for this, though. */
+ struct rusage r;
+ fill_rusage (&r, hMainProc);
+ add_rusage (&rusage_self, &r);
+ }
sigproc_printf ("Calling ExitProcess %d", n);
ExitProcess (n);
@@ -133,7 +116,7 @@ _pinfo::exit (UINT n, bool norecord)
void
pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
{
- if (n == myself->pid)
+ if (myself && n == myself->pid)
{
procinfo = myself;
destroy = 0;
@@ -182,7 +165,8 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
procinfo = (_pinfo *) MapViewOfFile (h, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
ProtectHandle1 (h, pinfo_shared_handle);
- if ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR))
+ if ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR)
+ && cygwin_pid (procinfo->dwProcessId) != procinfo->pid)
{
release ();
set_errno (ENOENT);
@@ -198,6 +182,11 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
api_fatal ("retrieval of execed process info for pid %d failed due to recursion.", n);
n = realpid;
release ();
+ if (flag & PID_ALLPIDS)
+ {
+ set_errno (ENOENT);
+ break;
+ }
continue;
}
@@ -272,7 +261,7 @@ a cygwin pid.</para>
extern "C" pid_t
cygwin_winpid_to_pid (int winpid)
{
- pinfo p (winpid);
+ pinfo p (cygwin_pid (winpid));
if (p)
return p->pid;
@@ -293,11 +282,11 @@ winpids::add (DWORD& nelem, bool winpid, DWORD pid)
if (nelem >= npidlist)
{
npidlist += slop_pidlist;
- pidlist = (DWORD *) realloc (pidlist, size_pidlist (npidlist));
- pinfolist = (pinfo *) realloc (pinfolist, size_pinfolist (npidlist));
+ pidlist = (DWORD *) realloc (pidlist, size_pidlist (npidlist + 1));
+ pinfolist = (pinfo *) realloc (pinfolist, size_pinfolist (npidlist + 1));
}
- pinfolist[nelem].init (cygpid, PID_NOREDIR);
+ pinfolist[nelem].init (cygpid, PID_NOREDIR | (winpid ? PID_ALLPIDS : 0));
if (winpid)
/* nothing to do */;
else if (!pinfolist[nelem])
@@ -324,12 +313,12 @@ winpids::enumNT (bool winpid)
DWORD nelem = 0;
if (!szprocs)
- procs = (SYSTEM_PROCESSES *) malloc (szprocs = 200 * sizeof (*procs));
+ procs = (SYSTEM_PROCESSES *) malloc (sizeof (*procs) + (szprocs = 200 * sizeof (*procs)));
NTSTATUS res;
for (;;)
{
- res = ZwQuerySystemInformation (SystemProcessesAndThreadsInformation,
+ res = NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
procs, szprocs, NULL);
if (res == 0)
break;
@@ -387,7 +376,8 @@ void
winpids::init (bool winpid)
{
npids = (this->*enum_processes) (winpid);
- pidlist[npids] = 0;
+ if (pidlist)
+ pidlist[npids] = 0;
}
DWORD
diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h
index f62614d58..dcb814bcc 100644
--- a/winsup/cygwin/pinfo.h
+++ b/winsup/cygwin/pinfo.h
@@ -1,6 +1,6 @@
/* pinfo.h: process table info
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -8,6 +8,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#ifndef _PINFO_H
+#define _PINFO_H
/* Signal constants (have to define them here, unfortunately) */
enum
@@ -39,7 +41,7 @@ public:
we only use this handle from the parent. */
HANDLE hProcess;
-#define PINFO_REDIR_SIZE ((DWORD) &(((_pinfo *)NULL)->hProcess) + sizeof (DWORD))
+#define PINFO_REDIR_SIZE ((char *) &myself.procinfo->hProcess - (char *) myself.procinfo)
/* Handle associated with initial Windows pid which started it all. */
HANDLE pid_handle;
@@ -65,8 +67,8 @@ public:
if not found. This data resides in the shared data area (allowing
tasks to store whatever they want here) so it's for informational
purposes only. */
- uid_t uid; /* User ID */
- gid_t gid; /* Group ID */
+ __uid32_t uid; /* User ID */
+ __gid32_t gid; /* Group ID */
pid_t pgid; /* Process group ID */
pid_t sid; /* Session ID */
int ctty; /* Control tty */
@@ -95,7 +97,7 @@ public:
return thread2signal ? thread2signal->sigs[sig] : sigs[sig];
}
- inline void copysigs (_pinfo *p) {sigs = p->sigs;}
+ inline void copysigs (_pinfo *p) {memcpy (sigs, p->sigs, sizeof (sigs));}
inline sigset_t& getsigmask ()
{
@@ -129,7 +131,7 @@ class pinfo
{
HANDLE h;
_pinfo *procinfo;
- int destroy;
+ bool destroy;
public:
void init (pid_t n, DWORD create = 0, HANDLE h = NULL) __attribute__ ((regparm(3)));
pinfo () {}
@@ -152,7 +154,16 @@ public:
_pinfo *operator * () const {return procinfo;}
operator _pinfo * () const {return procinfo;}
// operator bool () const {return (int) h;}
- int remember () {destroy = 0; return proc_subproc (PROC_ADDCHILD, (DWORD) this);}
+#ifndef _SIGPROC_H
+ int remember () {system_printf ("remember is not here"); return 0;}
+#else
+ int remember ()
+ {
+ int res = proc_subproc (PROC_ADDCHILD, (DWORD) this);
+ destroy = res ? false : true;
+ return res;
+ }
+#endif
HANDLE shared_handle () {return h;}
};
@@ -193,16 +204,14 @@ void __stdcall set_myself (pid_t pid, HANDLE h = NULL);
extern pinfo myself;
#define _P_VFORK 0
-extern "C" int _spawnve (HANDLE hToken, int mode, const char *path,
- const char *const *argv, const char *const *envp);
-
extern void __stdcall pinfo_fixup_after_fork ();
extern HANDLE hexec_proc;
/* For mmaps across fork(). */
-int __stdcall fixup_mmaps_after_fork ();
+int __stdcall fixup_mmaps_after_fork (HANDLE parent);
/* for shm areas across fork (). */
int __stdcall fixup_shms_after_fork ();
void __stdcall fill_rusage (struct rusage *, HANDLE);
void __stdcall add_rusage (struct rusage *, struct rusage *);
+#endif /*_PINFO_H*/
diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc
index 099aa37b3..b37a7751e 100644
--- a/winsup/cygwin/pipe.cc
+++ b/winsup/cygwin/pipe.cc
@@ -1,6 +1,6 @@
/* pipe.cc: pipe for Cygwin.
- Copyright 1996, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -8,9 +8,10 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+/* FIXME: Should this really be fhandler_pipe.cc? */
+
#include "winsup.h"
#include <unistd.h>
-#include <sys/fcntl.h>
#include <errno.h>
#include "cygerrno.h"
#include "security.h"
@@ -19,21 +20,19 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "thread.h"
-#include "sigproc.h"
#include "pinfo.h"
static unsigned pipecount;
static const NO_COPY char pipeid_fmt[] = "stupid_pipe.%u.%u";
-fhandler_pipe::fhandler_pipe (const char *name, DWORD devtype) :
- fhandler_base (devtype, name),
- guard (0), writepipe_exists(0), orig_pid (0), id (0)
+fhandler_pipe::fhandler_pipe (DWORD devtype)
+ : fhandler_base (devtype), guard (NULL), broken_pipe (false), writepipe_exists(0),
+ orig_pid (0), id (0)
{
- set_cb (sizeof *this);
}
-off_t
-fhandler_pipe::lseek (off_t offset, int whence)
+__off64_t
+fhandler_pipe::lseek (__off64_t offset, int whence)
{
debug_printf ("(%d, %d)", offset, whence);
set_errno (ESPIPE);
@@ -50,11 +49,13 @@ fhandler_pipe::set_close_on_exec (int val)
set_inheritance (writepipe_exists, val);
}
-int
+int __stdcall
fhandler_pipe::read (void *in_ptr, size_t in_len)
{
+ if (broken_pipe)
+ return 0;
int res = this->fhandler_base::read (in_ptr, in_len);
- ReleaseMutex (guard);
+ (void) ReleaseMutex (guard);
return res;
}
@@ -73,6 +74,8 @@ fhandler_pipe::hit_eof ()
{
char buf[80];
HANDLE ev;
+ if (broken_pipe)
+ return 1;
if (!orig_pid)
return false;
__small_sprintf (buf, pipeid_fmt, orig_pid, id);
@@ -125,55 +128,54 @@ fhandler_pipe::dup (fhandler_base *child)
return 0;
}
-
int
make_pipe (int fildes[2], unsigned int psize, int mode)
{
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "make_pipe");
-
HANDLE r, w;
- int fdr = -1, fdw = -1;
SECURITY_ATTRIBUTES *sa = (mode & O_NOINHERIT) ? &sec_none_nih : &sec_none;
int res = -1;
- if ((fdr = cygheap->fdtab.find_unused_handle ()) < 0)
- set_errno (ENMFILE);
- else if ((fdw = cygheap->fdtab.find_unused_handle (fdr + 1)) < 0)
- set_errno (ENMFILE);
- else if (!CreatePipe (&r, &w, sa, psize))
- __seterrno ();
- else
+ cygheap_fdnew fdr;
+ if (fdr >= 0)
{
- fhandler_pipe *fhr = (fhandler_pipe *) cygheap->fdtab.build_fhandler (fdr, FH_PIPER, "/dev/piper");
- fhandler_pipe *fhw = (fhandler_pipe *) cygheap->fdtab.build_fhandler (fdw, FH_PIPEW, "/dev/pipew");
-
- int binmode = mode & O_TEXT ? 0 : 1;
- fhr->init (r, GENERIC_READ, binmode);
- fhw->init (w, GENERIC_WRITE, binmode);
- if (mode & O_NOINHERIT)
- {
- fhr->set_close_on_exec_flag (1);
- fhw->set_close_on_exec_flag (1);
- }
-
- fildes[0] = fdr;
- fildes[1] = fdw;
-
- res = 0;
- fhr->create_guard (sa);
- if (wincap.has_unreliable_pipes ())
+ cygheap_fdnew fdw (fdr, false);
+ if (fdw < 0)
+ /* out of fds? */;
+ else if (!CreatePipe (&r, &w, sa, psize))
+ __seterrno ();
+ else
{
- char buf[80];
- int count = pipecount++; /* FIXME: Should this be InterlockedIncrement? */
- __small_sprintf (buf, pipeid_fmt, myself->pid, count);
- fhw->writepipe_exists = CreateEvent (sa, TRUE, FALSE, buf);
- fhr->orig_pid = myself->pid;
- fhr->id = count;
+ fhandler_pipe *fhr = (fhandler_pipe *) cygheap->fdtab.build_fhandler (fdr, FH_PIPER, "/dev/piper");
+ fhandler_pipe *fhw = (fhandler_pipe *) cygheap->fdtab.build_fhandler (fdw, FH_PIPEW, "/dev/pipew");
+
+ int binmode = mode & O_TEXT ?: O_BINARY;
+ fhr->init (r, GENERIC_READ, binmode);
+ fhw->init (w, GENERIC_WRITE, binmode);
+ if (mode & O_NOINHERIT)
+ {
+ fhr->set_close_on_exec_flag (1);
+ fhw->set_close_on_exec_flag (1);
+ }
+
+ fildes[0] = fdr;
+ fildes[1] = fdw;
+
+ res = 0;
+ fhr->create_guard (sa);
+ if (wincap.has_unreliable_pipes ())
+ {
+ char buf[80];
+ int count = pipecount++; /* FIXME: Should this be InterlockedIncrement? */
+ __small_sprintf (buf, pipeid_fmt, myself->pid, count);
+ fhw->writepipe_exists = CreateEvent (sa, TRUE, FALSE, buf);
+ fhr->orig_pid = myself->pid;
+ fhr->id = count;
+ }
}
}
- syscall_printf ("%d = make_pipe ([%d, %d], %d, %p)", res, fdr, fdw, psize, mode);
- ReleaseResourceLock(LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "make_pipe");
+ syscall_printf ("%d = make_pipe ([%d, %d], %d, %p)", res, fildes[0],
+ fildes[1], psize, mode);
return res;
}
diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc
index 2ac606849..3c61c565e 100644
--- a/winsup/cygwin/poll.cc
+++ b/winsup/cygwin/poll.cc
@@ -1,6 +1,6 @@
/* poll.cc. Implements poll(2) via usage of select(2) call.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,13 +11,15 @@
#include "winsup.h"
#include <sys/time.h>
#include <sys/poll.h>
+#include <sys/socket.h>
#include <errno.h>
+#include <stdlib.h>
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "cygheap.h"
#include "cygerrno.h"
+#include "cygheap.h"
#include "sigproc.h"
extern "C"
@@ -25,7 +27,7 @@ int
poll (struct pollfd *fds, unsigned int nfds, int timeout)
{
int max_fd = 0;
- fd_set *open_fds, *read_fds, *write_fds, *except_fds;
+ fd_set *read_fds, *write_fds, *except_fds;
struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
sigframe thisframe (mainthread);
@@ -33,66 +35,85 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
if (fds[i].fd > max_fd)
max_fd = fds[i].fd;
- size_t fds_size = howmany(max_fd + 1, NFDBITS) * sizeof (fd_mask);
+ size_t fds_size = howmany (max_fd + 1, NFDBITS) * sizeof (fd_mask);
- open_fds = (fd_set *) alloca (fds_size);
read_fds = (fd_set *) alloca (fds_size);
write_fds = (fd_set *) alloca (fds_size);
except_fds = (fd_set *) alloca (fds_size);
- if (!open_fds || !read_fds || !write_fds || !except_fds)
+ if (!read_fds || !write_fds || !except_fds)
{
set_errno (ENOMEM);
return -1;
}
- memset (open_fds, 0, fds_size);
memset (read_fds, 0, fds_size);
memset (write_fds, 0, fds_size);
memset (except_fds, 0, fds_size);
- bool invalid_fds = false;
- for (unsigned int i = 0; i < nfds; ++i)
- if (!cygheap->fdtab.not_open (fds[i].fd))
- {
- FD_SET (fds[i].fd, open_fds);
- if (fds[i].events & POLLIN)
- FD_SET (fds[i].fd, read_fds);
- if (fds[i].events & POLLOUT)
- FD_SET (fds[i].fd, write_fds);
- if (fds[i].events & POLLPRI)
- FD_SET (fds[i].fd, except_fds);
- }
- else
- invalid_fds = true;
-
- int ret = 0;
- if (!invalid_fds)
- ret = cygwin_select (max_fd + 1, read_fds, write_fds, except_fds,
- timeout < 0 ? NULL : &tv);
-
+ int invalid_fds = 0;
for (unsigned int i = 0; i < nfds; ++i)
{
- if (!FD_ISSET (fds[i].fd, open_fds))
+ fds[i].revents = 0;
+ if (!cygheap->fdtab.not_open (fds[i].fd))
{
- fds[i].revents = POLLNVAL;
- ret++;
+ if (fds[i].events & POLLIN)
+ FD_SET(fds[i].fd, read_fds);
+ if (fds[i].events & POLLOUT)
+ FD_SET(fds[i].fd, write_fds);
+ if (fds[i].events & POLLPRI)
+ FD_SET(fds[i].fd, except_fds);
}
- else if (cygheap->fdtab.not_open(fds[i].fd))
- fds[i].revents = POLLHUP;
- else if (ret < 0)
- fds[i].revents = POLLERR;
- else
+ else if (fds[i].fd >= 0)
{
- fds[i].revents = 0;
- if (FD_ISSET (fds[i].fd, read_fds))
- fds[i].revents |= POLLIN;
- if (FD_ISSET (fds[i].fd, write_fds))
- fds[i].revents |= POLLOUT;
- if (FD_ISSET (fds[i].fd, except_fds))
- fds[i].revents |= POLLPRI;
+ ++invalid_fds;
+ fds[i].revents = POLLNVAL;
}
}
+ if (invalid_fds)
+ return invalid_fds;
+
+ int ret = cygwin_select (max_fd + 1, read_fds, write_fds, except_fds, timeout < 0 ? NULL : &tv);
+
+ if (ret > 0)
+ for (unsigned int i = 0; i < nfds; ++i)
+ {
+ if (fds[i].fd >= 0)
+ {
+ if (cygheap->fdtab.not_open (fds[i].fd))
+ fds[i].revents = POLLHUP;
+ else
+ {
+ if (FD_ISSET(fds[i].fd, read_fds))
+ {
+ char peek[1];
+ fhandler_socket *sock =
+ cygheap->fdtab[fds[i].fd]->is_socket ();
+ if (!sock)
+ fds[i].revents |= POLLIN;
+ else
+ switch (sock->recvfrom (peek, sizeof (peek), MSG_PEEK,
+ NULL, NULL))
+ {
+ case -1: /* Something weird happened */
+ fds[i].revents |= POLLERR;
+ break;
+ case 0: /* Closed on the read side. */
+ fds[i].revents |= POLLHUP;
+ break;
+ default:
+ fds[i].revents |= POLLIN;
+ break;
+ }
+ }
+ if (FD_ISSET(fds[i].fd, write_fds))
+ fds[i].revents |= POLLOUT;
+ if (FD_ISSET(fds[i].fd, except_fds))
+ fds[i].revents |= POLLPRI;
+ }
+ }
+ }
+
return ret;
}
diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc
index 7d8ca1ae6..cfa0c28ea 100644
--- a/winsup/cygwin/pthread.cc
+++ b/winsup/cygwin/pthread.cc
@@ -1,6 +1,6 @@
/* pthread.cc: posix pthread interface for Cygwin
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Originally written by Marco Fuykschot <marco@ddi.nl>
@@ -12,6 +12,7 @@
#include "winsup.h"
#include "thread.h"
+#include "errno.h"
extern "C"
{
@@ -20,19 +21,19 @@ int
pthread_create (pthread_t * thread, const pthread_attr_t * attr,
void *(*start_routine) (void *), void *arg)
{
- return __pthread_create (thread, attr, start_routine, arg);
+ return pthread::create (thread, attr, start_routine, arg);
}
int
pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
{
- return __pthread_once (once_control, init_routine);
+ return pthread::once (once_control, init_routine);
}
int
-pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void))
{
- return __pthread_atfork(prepare, parent, child);
+ return pthread::atfork (prepare, parent, child);
}
int
@@ -140,19 +141,19 @@ pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr)
void
pthread_exit (void *value_ptr)
{
- return __pthread_exit (value_ptr);
+ return pthread::self ()->exit (value_ptr);
}
int
pthread_join (pthread_t thread, void **return_val)
{
- return __pthread_join (&thread, (void **) return_val);
+ return pthread::join (&thread, (void **) return_val);
}
int
pthread_detach (pthread_t thread)
{
- return __pthread_detach (&thread);
+ return pthread::detach (&thread);
}
@@ -160,20 +161,22 @@ pthread_detach (pthread_t thread)
int
pthread_suspend (pthread_t thread)
{
- return __pthread_suspend (&thread);
+ return pthread::suspend (&thread);
}
/* same */
int
pthread_continue (pthread_t thread)
{
- return __pthread_continue (&thread);
+ return pthread::resume (&thread);
}
unsigned long
pthread_getsequence_np (pthread_t * thread)
{
- return __pthread_getsequence_np (thread);
+ if (!pthread::isGoodObject (thread))
+ return EINVAL;
+ return (*thread)->getsequence_np ();
}
/* Thread SpecificData */
@@ -218,7 +221,7 @@ pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set)
pthread_t pthread_self ()
{
- return __pthread_self ();
+ return pthread::self ();
}
int
@@ -422,58 +425,68 @@ pthread_setschedparam (pthread_t thread, int policy,
int
pthread_cancel (pthread_t thread)
{
- return __pthread_cancel (thread);
+ return pthread::cancel (thread);
}
-
-
int
pthread_setcancelstate (int state, int *oldstate)
{
- return __pthread_setcancelstate (state, oldstate);
+ return pthread::self ()->setcancelstate (state, oldstate);
}
int
pthread_setcanceltype (int type, int *oldtype)
{
- return __pthread_setcanceltype (type, oldtype);
+ return pthread::self ()->setcanceltype (type, oldtype);
}
void
pthread_testcancel (void)
{
- __pthread_testcancel ();
+ pthread::self ()->testcancel ();
+}
+
+void
+_pthread_cleanup_push (__pthread_cleanup_handler *handler)
+{
+ pthread::self ()->push_cleanup_handler (handler);
+}
+
+void
+_pthread_cleanup_pop (int execute)
+{
+ pthread::self ()->pop_cleanup_handler (execute);
}
/* Semaphores */
int
sem_init (sem_t * sem, int pshared, unsigned int value)
{
- return __sem_init (sem, pshared, value);
+ return semaphore::init (sem, pshared, value);
}
int
sem_destroy (sem_t * sem)
{
- return __sem_destroy (sem);
+ return semaphore::destroy (sem);
}
int
sem_wait (sem_t * sem)
{
- return __sem_wait (sem);
+ return semaphore::wait (sem);
}
int
sem_trywait (sem_t * sem)
{
- return __sem_trywait (sem);
+ return semaphore::trywait (sem);
}
int
sem_post (sem_t * sem)
{
- return __sem_post (sem);
+ return semaphore::post (sem);
}
}
diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h
index 38a7c80f4..530adf63a 100644
--- a/winsup/cygwin/pwdgrp.h
+++ b/winsup/cygwin/pwdgrp.h
@@ -27,29 +27,89 @@ public:
operator pwdgrp_state ()
{
if (state != uninitialized && file_w32[0] && cygheap->etc_changed ())
- {
- HANDLE h;
- WIN32_FIND_DATA data;
-
- if ((h = FindFirstFile (file_w32, &data)) != INVALID_HANDLE_VALUE)
- {
- if (CompareFileTime (&data.ftLastWriteTime, &last_modified) > 0)
- state = uninitialized;
- FindClose (h);
- }
- }
+ {
+ HANDLE h;
+ WIN32_FIND_DATA data;
+
+ if ((h = FindFirstFile (file_w32, &data)) != INVALID_HANDLE_VALUE)
+ {
+ if (CompareFileTime (&data.ftLastWriteTime, &last_modified) > 0)
+ state = uninitialized;
+ FindClose (h);
+ }
+ }
return state;
}
void operator = (pwdgrp_state nstate)
{
state = nstate;
}
- void set_last_modified (FILE *f)
+ void set_last_modified (HANDLE fh, const char *name)
{
if (!file_w32[0])
- strcpy (file_w32, cygheap->fdtab[fileno (f)]->get_win32_name ());
-
- GetFileTime (cygheap->fdtab[fileno (f)]->get_handle (),
- NULL, NULL, &last_modified);
+ strcpy (file_w32, name);
+ GetFileTime (fh, NULL, NULL, &last_modified);
}
};
+
+class pwdgrp_read {
+ path_conv pc;
+ HANDLE fh;
+ char *buf;
+ char *lptr, *eptr;
+
+public:
+ bool open (const char *posix_fname)
+ {
+ if (buf)
+ free (buf);
+ buf = lptr = eptr = NULL;
+
+ pc.check (posix_fname);
+ if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
+ return false;
+
+ fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if (fh)
+ {
+ DWORD size = GetFileSize (fh, NULL), read_bytes;
+ buf = (char *) malloc (size + 1);
+ if (!ReadFile (fh, buf, size, &read_bytes, NULL))
+ {
+ if (buf)
+ free (buf);
+ buf = NULL;
+ CloseHandle (fh);
+ fh = NULL;
+ return false;
+ }
+ buf[read_bytes] = '\0';
+ return true;
+ }
+ return false;
+ }
+ char *gets ()
+ {
+ if (!buf)
+ return NULL;
+ if (!lptr)
+ lptr = buf;
+ else if (!eptr)
+ return lptr = NULL;
+ else
+ lptr = eptr;
+ eptr = strchr (lptr, '\n');
+ if (eptr)
+ *eptr++ = '\0';
+ return lptr;
+ }
+ inline HANDLE get_fhandle () { return fh; }
+ inline const char *get_fname () { return pc; }
+ void close ()
+ {
+ if (fh)
+ CloseHandle (fh);
+ fh = NULL;
+ }
+};
diff --git a/winsup/cygwin/regex/regcomp.c b/winsup/cygwin/regex/regcomp.c
index 34c1f2e5c..52f9037de 100644
--- a/winsup/cygwin/regex/regcomp.c
+++ b/winsup/cygwin/regex/regcomp.c
@@ -52,7 +52,7 @@ static char nuls[10]; /* place to point scanner in event of error */
#define NEXTn(n) (p->next += (n))
#define GETNEXT() (*p->next++)
#define SETERROR(e) seterr(p, (e))
-#define REQUIRE(co, e) ((co) || SETERROR(e))
+#define REQUIRE(co, e) (void) ((co) || SETERROR(e))
#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
diff --git a/winsup/cygwin/regexp/regerror.c b/winsup/cygwin/regexp/regerror.c
deleted file mode 100644
index 0f6159bb7..000000000
--- a/winsup/cygwin/regexp/regerror.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* regerror.c
-
- Copyright 1996, 1998, 2001 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#include "winsup.h"
-#include "regexp.h"
-#include <stdio.h>
-
-void
-regerror(const char *s __attribute__ ((unused)))
-{
-#ifdef ERRAVAIL
- error("regexp: %s", s);
-#else
-/*
- fprintf(stderr, "regexp(3): %s\n", s);
- exit(1);
-*/
- return; /* let std. egrep handle errors */
-#endif
- /* NOTREACHED */
-}
diff --git a/winsup/cygwin/regexp/regexp.3 b/winsup/cygwin/regexp/regexp.3
deleted file mode 100644
index d1a3a000d..000000000
--- a/winsup/cygwin/regexp/regexp.3
+++ /dev/null
@@ -1,321 +0,0 @@
-.\" Copyright (c) 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" @(#)regexp.3 8.1 (Berkeley) 6/4/93
-.\"
-.Dd June 4, 1993
-.Dt REGEXP 3
-.Os
-.Sh NAME
-.Nm regcomp ,
-.Nm regexec ,
-.Nm regsub ,
-.Nm regerror
-.Nd regular expression handlers
-.Sh SYNOPSIS
-.Fd #include <regexp.h>
-.Ft regexp *
-.Fn regcomp "const char *exp"
-.Ft int
-.Fn regexec "const regexp *prog" "const char *string"
-.Ft void
-.Fn regsub "const regexp *prog" "const char *source" "char *dest"
-.Sh DESCRIPTION
-.Bf -symbolic
-This interface is made obsolete by
-.Xr regex 3 .
-It is available from the compatibility library, libcompat.
-.Ef
-.Pp
-The
-.Fn regcomp ,
-.Fn regexec ,
-.Fn regsub ,
-and
-.Fn regerror
-functions
-implement
-.Xr egrep 1 Ns -style
-regular expressions and supporting facilities.
-.Pp
-The
-.Fn regcomp
-function
-compiles a regular expression into a structure of type
-.Xr regexp ,
-and returns a pointer to it.
-The space has been allocated using
-.Xr malloc 3
-and may be released by
-.Xr free .
-.Pp
-The
-.Fn regexec
-function
-matches a
-.Dv NUL Ns -terminated
-.Fa string
-against the compiled regular expression
-in
-.Fa prog .
-It returns 1 for success and 0 for failure, and adjusts the contents of
-.Fa prog Ns 's
-.Em startp
-and
-.Em endp
-(see below) accordingly.
-.Pp
-The members of a
-.Xr regexp
-structure include at least the following (not necessarily in order):
-.Bd -literal -offset indent
-char *startp[NSUBEXP];
-char *endp[NSUBEXP];
-.Ed
-.Pp
-where
-.Dv NSUBEXP
-is defined (as 10) in the header file.
-Once a successful
-.Fn regexec
-has been done using the
-.Fn regexp ,
-each
-.Em startp Ns - Em endp
-pair describes one substring
-within the
-.Fa string ,
-with the
-.Em startp
-pointing to the first character of the substring and
-the
-.Em endp
-pointing to the first character following the substring.
-The 0th substring is the substring of
-.Fa string
-that matched the whole
-regular expression.
-The others are those substrings that matched parenthesized expressions
-within the regular expression, with parenthesized expressions numbered
-in left-to-right order of their opening parentheses.
-.Pp
-The
-.Fn regsub
-function
-copies
-.Fa source
-to
-.Fa dest ,
-making substitutions according to the
-most recent
-.Fn regexec
-performed using
-.Fa prog .
-Each instance of `&' in
-.Fa source
-is replaced by the substring
-indicated by
-.Em startp Ns Bq
-and
-.Em endp Ns Bq .
-Each instance of
-.Sq \e Ns Em n ,
-where
-.Em n
-is a digit, is replaced by
-the substring indicated by
-.Em startp Ns Bq Em n
-and
-.Em endp Ns Bq Em n .
-To get a literal `&' or
-.Sq \e Ns Em n
-into
-.Fa dest ,
-prefix it with `\e';
-to get a literal `\e' preceding `&' or
-.Sq \e Ns Em n ,
-prefix it with
-another `\e'.
-.Pp
-The
-.Fn regerror
-function
-is called whenever an error is detected in
-.Fn regcomp ,
-.Fn regexec ,
-or
-.Fn regsub .
-The default
-.Fn regerror
-writes the string
-.Fa msg ,
-with a suitable indicator of origin,
-on the standard
-error output
-and invokes
-.Xr exit 2 .
-The
-.Fn regerror
-function
-can be replaced by the user if other actions are desirable.
-.Sh REGULAR EXPRESSION SYNTAX
-A regular expression is zero or more
-.Em branches ,
-separated by `|'.
-It matches anything that matches one of the branches.
-.Pp
-A branch is zero or more
-.Em pieces ,
-concatenated.
-It matches a match for the first, followed by a match for the second, etc.
-.Pp
-A piece is an
-.Em atom
-possibly followed by `*', `+', or `?'.
-An atom followed by `*' matches a sequence of 0 or more matches of the atom.
-An atom followed by `+' matches a sequence of 1 or more matches of the atom.
-An atom followed by `?' matches a match of the atom, or the null string.
-.Pp
-An atom is a regular expression in parentheses (matching a match for the
-regular expression), a
-.Em range
-(see below), `.'
-(matching any single character), `^' (matching the null string at the
-beginning of the input string), `$' (matching the null string at the
-end of the input string), a `\e' followed by a single character (matching
-that character), or a single character with no other significance
-(matching that character).
-.Pp
-A
-.Em range
-is a sequence of characters enclosed in `[]'.
-It normally matches any single character from the sequence.
-If the sequence begins with `^',
-it matches any single character
-.Em not
-from the rest of the sequence.
-If two characters in the sequence are separated by `\-', this is shorthand
-for the full list of
-.Tn ASCII
-characters between them
-(e.g. `[0-9]' matches any decimal digit).
-To include a literal `]' in the sequence, make it the first character
-(following a possible `^').
-To include a literal `\-', make it the first or last character.
-.Sh AMBIGUITY
-If a regular expression could match two different parts of the input string,
-it will match the one which begins earliest.
-If both begin in the same place but match different lengths, or match
-the same length in different ways, life gets messier, as follows.
-.Pp
-In general, the possibilities in a list of branches are considered in
-left-to-right order, the possibilities for `*', `+', and `?' are
-considered longest-first, nested constructs are considered from the
-outermost in, and concatenated constructs are considered leftmost-first.
-The match that will be chosen is the one that uses the earliest
-possibility in the first choice that has to be made.
-If there is more than one choice, the next will be made in the same manner
-(earliest possibility) subject to the decision on the first choice.
-And so forth.
-.Pp
-For example,
-.Sq Li (ab|a)b*c
-could match
-`abc' in one of two ways.
-The first choice is between `ab' and `a'; since `ab' is earlier, and does
-lead to a successful overall match, it is chosen.
-Since the `b' is already spoken for,
-the `b*' must match its last possibility\(emthe empty string\(emsince
-it must respect the earlier choice.
-.Pp
-In the particular case where no `|'s are present and there is only one
-`*', `+', or `?', the net effect is that the longest possible
-match will be chosen.
-So
-.Sq Li ab* ,
-presented with `xabbbby', will match `abbbb'.
-Note that if
-.Sq Li ab* ,
-is tried against `xabyabbbz', it
-will match `ab' just after `x', due to the begins-earliest rule.
-(In effect, the decision on where to start the match is the first choice
-to be made, hence subsequent choices must respect it even if this leads them
-to less-preferred alternatives.)
-.Sh RETURN VALUES
-The
-.Fn regcomp
-function
-returns
-.Dv NULL
-for a failure
-.Pf ( Fn regerror
-permitting),
-where failures are syntax errors, exceeding implementation limits,
-or applying `+' or `*' to a possibly-null operand.
-.Sh SEE ALSO
-.Xr ed 1 ,
-.Xr ex 1 ,
-.Xr expr 1 ,
-.Xr egrep 1 ,
-.Xr fgrep 1 ,
-.Xr grep 1 ,
-.Xr regex 3
-.Sh HISTORY
-Both code and manual page for
-.Fn regcomp ,
-.Fn regexec ,
-.Fn regsub ,
-and
-.Fn regerror
-were written at the University of Toronto
-and appeared in
-.Bx 4.3 tahoe .
-They are intended to be compatible with the Bell V8
-.Xr regexp 3 ,
-but are not derived from Bell code.
-.Sh BUGS
-Empty branches and empty regular expressions are not portable to V8.
-.Pp
-The restriction against
-applying `*' or `+' to a possibly-null operand is an artifact of the
-simplistic implementation.
-.Pp
-Does not support
-.Xr egrep Ns 's
-newline-separated branches;
-neither does the V8
-.Xr regexp 3 ,
-though.
-.Pp
-Due to emphasis on
-compactness and simplicity,
-it's not strikingly fast.
-It does give special attention to handling simple cases quickly.
diff --git a/winsup/cygwin/regexp/regexp.c b/winsup/cygwin/regexp/regexp.c
deleted file mode 100644
index 2f60d6463..000000000
--- a/winsup/cygwin/regexp/regexp.c
+++ /dev/null
@@ -1,1321 +0,0 @@
-/*
- * regcomp and regexec -- regsub and regerror are elsewhere
- *
- * Copyright (c) 1986 by University of Toronto.
- * Written by Henry Spencer. Not derived from licensed software.
- *
- * Permission is granted to anyone to use this software for any
- * purpose on any computer system, and to redistribute it freely,
- * subject to the following restrictions:
- *
- * 1. The author is not responsible for the consequences of use of
- * this software, no matter how awful, even if they arise
- * from defects in it.
- *
- * 2. The origin of this software must not be misrepresented, either
- * by explicit claim or by omission.
- *
- * 3. Altered versions must be plainly marked as such, and must not
- * be misrepresented as being the original software.
- *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
- *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
- *** to assist in implementing egrep.
- *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
- *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
- *** as in BSD grep and ex.
- *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
- *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
- *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
- *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
- *** THIS IS AN ALTERED VERSION. It was altered by Geoffrey Noer,
- *** noer@cygnus.com, on 6 Oct 1997, to change the prototype format
- *** for inclusion in the Cygwin32 library.
- *
- * Beware that some of this code is subtly aware of the way operator
- * precedence is structured in regular expressions. Serious changes in
- * regular-expression syntax might require a total rethink.
- */
-
-#include "winsup.h"
-#include "regexp.h"
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "regmagic.h"
-
-/*
- * The "internal use only" fields in regexp.h are present to pass info from
- * compile to execute that permits the execute phase to run lots faster on
- * simple cases. They are:
- *
- * regstart char that must begin a match; '\0' if none obvious
- * reganch is the match anchored (at beginning-of-line only)?
- * regmust string (pointer into program) that match must include, or NULL
- * regmlen length of regmust string
- *
- * Regstart and reganch permit very fast decisions on suitable starting points
- * for a match, cutting down the work a lot. Regmust permits fast rejection
- * of lines that cannot possibly match. The regmust tests are costly enough
- * that regcomp() supplies a regmust only if the r.e. contains something
- * potentially expensive (at present, the only such thing detected is * or +
- * at the start of the r.e., which can involve a lot of backup). Regmlen is
- * supplied because the test in regexec() needs it and regcomp() is computing
- * it anyway.
- */
-
-/*
- * Structure for regexp "program". This is essentially a linear encoding
- * of a nondeterministic finite-state machine (aka syntax charts or
- * "railroad normal form" in parsing technology). Each node is an opcode
- * plus a "next" pointer, possibly plus an operand. "Next" pointers of
- * all nodes except BRANCH implement concatenation; a "next" pointer with
- * a BRANCH on both ends of it is connecting two alternatives. (Here we
- * have one of the subtle syntax dependencies: an individual BRANCH (as
- * opposed to a collection of them) is never concatenated with anything
- * because of operator precedence.) The operand of some types of node is
- * a literal string; for others, it is a node leading into a sub-FSM. In
- * particular, the operand of a BRANCH node is the first node of the branch.
- * (NB this is *not* a tree structure: the tail of the branch connects
- * to the thing following the set of BRANCHes.) The opcodes are:
- */
-
-/* definition number opnd? meaning */
-#define END 0 /* no End of program. */
-#define BOL 1 /* no Match "" at beginning of line. */
-#define EOL 2 /* no Match "" at end of line. */
-#define ANY 3 /* no Match any one character. */
-#define ANYOF 4 /* str Match any character in this string. */
-#define ANYBUT 5 /* str Match any character not in this string. */
-#define BRANCH 6 /* node Match this alternative, or the next... */
-#define BACK 7 /* no Match "", "next" ptr points backward. */
-#define EXACTLY 8 /* str Match this string. */
-#define NOTHING 9 /* no Match empty string. */
-#define STAR 10 /* node Match this (simple) thing 0 or more times. */
-#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
-#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
-#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
-#define OPEN 20 /* no Mark this point in input as start of #n. */
- /* OPEN+1 is number 1, etc. */
-#define CLOSE 30 /* no Analogous to OPEN. */
-
-/*
- * Opcode notes:
- *
- * BRANCH The set of branches constituting a single choice are hooked
- * together with their "next" pointers, since precedence prevents
- * anything being concatenated to any individual branch. The
- * "next" pointer of the last BRANCH in a choice points to the
- * thing following the whole choice. This is also where the
- * final "next" pointer of each individual branch points; each
- * branch starts with the operand node of a BRANCH node.
- *
- * BACK Normal "next" pointers all implicitly point forward; BACK
- * exists to make loop structures possible.
- *
- * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
- * BRANCH structures using BACK. Simple cases (one character
- * per match) are implemented with STAR and PLUS for speed
- * and to minimize recursive plunges.
- *
- * OPEN,CLOSE ...are numbered at compile time.
- */
-
-/*
- * A node is one char of opcode followed by two chars of "next" pointer.
- * "Next" pointers are stored as two 8-bit pieces, high order first. The
- * value is a positive offset from the opcode of the node containing it.
- * An operand, if any, simply follows the node. (Note that much of the
- * code generation knows about this implicit relationship.)
- *
- * Using two bytes for the "next" pointer is vast overkill for most things,
- * but allows patterns to get big without disasters.
- */
-#define OP(p) (*(p))
-#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
-#define OPERAND(p) ((p) + 3)
-
-/*
- * See regmagic.h for one further detail of program structure.
- */
-
-
-/*
- * Utility definitions.
- */
-#ifndef CHARBITS
-#define UCHARAT(p) ((int)*(unsigned char *)(p))
-#else
-#define UCHARAT(p) ((int)*(p)&CHARBITS)
-#endif
-
-#define FAIL(m) { regerror(m); return(NULL); }
-#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
-
-/*
- * Flags to be passed up and down.
- */
-#define HASWIDTH 01 /* Known never to match null string. */
-#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
-#define SPSTART 04 /* Starts with * or +. */
-#define WORST 0 /* Worst case. */
-
-/*
- * Global work variables for regcomp().
- */
-static char *regparse; /* Input-scan pointer. */
-static int regnpar; /* () count. */
-static char regdummy;
-static char *regcode; /* Code-emit pointer; &regdummy = don't. */
-static long regsize; /* Code size. */
-
-/*
- * Forward declarations for regcomp()'s friends.
- */
-#ifndef STATIC
-#define STATIC static
-#endif
-STATIC char *reg (int, int *);
-STATIC char *regbranch (int *);
-STATIC char *regpiece (int *);
-STATIC char *regatom (int *);
-STATIC char *regnode (char);
-STATIC char *regnext (char *);
-STATIC void regc (char);
-STATIC void reginsert (char, char *);
-STATIC void regtail (char *, char *);
-STATIC void regoptail (char *, char *);
-#ifdef STRCSPN
-STATIC int strcspn (char *, char *);
-#endif
-
-/*
- - regcomp - compile a regular expression into internal code
- *
- * We can't allocate space until we know how big the compiled form will be,
- * but we can't compile it (and thus know how big it is) until we've got a
- * place to put the code. So we cheat: we compile it twice, once with code
- * generation turned off and size counting turned on, and once "for real".
- * This also means that we don't allocate space until we are sure that the
- * thing really will compile successfully, and we never have to move the
- * code and thus invalidate pointers into it. (Note that it has to be in
- * one piece because free() must be able to free it all.)
- *
- * Beware that the optimization-preparation code in here knows about some
- * of the structure of the compiled regexp.
- */
-regexp *
-regcomp(exp)
-const char *exp;
-{
- register regexp *r;
- register char *scan;
- register char *longest;
- register int len;
- int flags;
-
- if (exp == NULL)
- FAIL("NULL argument");
-
- /* First pass: determine size, legality. */
-#ifdef notdef
- if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
-#endif
- regparse = (char *)exp;
- regnpar = 1;
- regsize = 0L;
- regcode = &regdummy;
- regc(MAGIC);
- if (reg(0, &flags) == NULL)
- return(NULL);
-
- /* Small enough for pointer-storage convention? */
- if (regsize >= 32767L) /* Probably could be 65535L. */
- FAIL("regexp too big");
-
- /* Allocate space. */
- r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
- if (r == NULL)
- FAIL("out of space");
-
- /* Second pass: emit code. */
- regparse = (char *)exp;
- regnpar = 1;
- regcode = r->program;
- regc(MAGIC);
- if (reg(0, &flags) == NULL)
- return(NULL);
-
- /* Dig out information for optimizations. */
- r->regstart = '\0'; /* Worst-case defaults. */
- r->reganch = 0;
- r->regmust = NULL;
- r->regmlen = 0;
- scan = r->program+1; /* First BRANCH. */
- if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
- scan = OPERAND(scan);
-
- /* Starting-point info. */
- if (OP(scan) == EXACTLY)
- r->regstart = *OPERAND(scan);
- else if (OP(scan) == BOL)
- r->reganch++;
-
- /*
- * If there's something expensive in the r.e., find the
- * longest literal string that must appear and make it the
- * regmust. Resolve ties in favor of later strings, since
- * the regstart check works with the beginning of the r.e.
- * and avoiding duplication strengthens checking. Not a
- * strong reason, but sufficient in the absence of others.
- */
- if (flags&SPSTART) {
- longest = NULL;
- len = 0;
- for (; scan != NULL; scan = regnext(scan))
- if (OP(scan) == EXACTLY && (int) strlen(OPERAND(scan)) >= len) {
- longest = OPERAND(scan);
- len = strlen(OPERAND(scan));
- }
- r->regmust = longest;
- r->regmlen = len;
- }
- }
-
- return(r);
-}
-
-/*
- - reg - regular expression, i.e. main body or parenthesized thing
- *
- * Caller must absorb opening parenthesis.
- *
- * Combining parenthesis handling with the base level of regular expression
- * is a trifle forced, but the need to tie the tails of the branches to what
- * follows makes it hard to avoid.
- */
-static char *
-reg(paren, flagp)
-int paren; /* Parenthesized? */
-int *flagp;
-{
- register char *ret;
- register char *br;
- register char *ender;
- register int parno = 0;
- int flags;
-
- *flagp = HASWIDTH; /* Tentatively. */
-
- /* Make an OPEN node, if parenthesized. */
- if (paren) {
- if (regnpar >= NSUBEXP)
- FAIL("too many ()");
- parno = regnpar;
- regnpar++;
- ret = regnode(OPEN+parno);
- } else
- ret = NULL;
-
- /* Pick up the branches, linking them together. */
- br = regbranch(&flags);
- if (br == NULL)
- return(NULL);
- if (ret != NULL)
- regtail(ret, br); /* OPEN -> first. */
- else
- ret = br;
- if (!(flags&HASWIDTH))
- *flagp &= ~HASWIDTH;
- *flagp |= flags&SPSTART;
- while (*regparse == '|' || *regparse == '\n') {
- regparse++;
- br = regbranch(&flags);
- if (br == NULL)
- return(NULL);
- regtail(ret, br); /* BRANCH -> BRANCH. */
- if (!(flags&HASWIDTH))
- *flagp &= ~HASWIDTH;
- *flagp |= flags&SPSTART;
- }
-
- /* Make a closing node, and hook it on the end. */
- ender = regnode((paren) ? CLOSE+parno : END);
- regtail(ret, ender);
-
- /* Hook the tails of the branches to the closing node. */
- for (br = ret; br != NULL; br = regnext(br))
- regoptail(br, ender);
-
- /* Check for proper termination. */
- if (paren && *regparse++ != ')') {
- FAIL("unmatched ()");
- } else if (!paren && *regparse != '\0') {
- if (*regparse == ')') {
- FAIL("unmatched ()");
- } else
- FAIL("junk on end"); /* "Can't happen". */
- /* NOTREACHED */
- }
-
- return(ret);
-}
-
-/*
- - regbranch - one alternative of an | operator
- *
- * Implements the concatenation operator.
- */
-static char *
-regbranch(flagp)
-int *flagp;
-{
- register char *ret;
- register char *chain;
- register char *latest;
- int flags;
-
- *flagp = WORST; /* Tentatively. */
-
- ret = regnode(BRANCH);
- chain = NULL;
- while (*regparse != '\0' && *regparse != ')' &&
- *regparse != '\n' && *regparse != '|') {
- latest = regpiece(&flags);
- if (latest == NULL)
- return(NULL);
- *flagp |= flags&HASWIDTH;
- if (chain == NULL) /* First piece. */
- *flagp |= flags&SPSTART;
- else
- regtail(chain, latest);
- chain = latest;
- }
- if (chain == NULL) /* Loop ran zero times. */
- (void) regnode(NOTHING);
-
- return(ret);
-}
-
-/*
- - regpiece - something followed by possible [*+?]
- *
- * Note that the branching code sequences used for ? and the general cases
- * of * and + are somewhat optimized: they use the same NOTHING node as
- * both the endmarker for their branch list and the body of the last branch.
- * It might seem that this node could be dispensed with entirely, but the
- * endmarker role is not redundant.
- */
-static char *
-regpiece(flagp)
-int *flagp;
-{
- register char *ret;
- register char op;
- register char *next;
- int flags;
-
- ret = regatom(&flags);
- if (ret == NULL)
- return(NULL);
-
- op = *regparse;
- if (!ISMULT(op)) {
- *flagp = flags;
- return(ret);
- }
-
- if (!(flags&HASWIDTH) && op != '?')
- FAIL("*+ operand could be empty");
- *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
-
- if (op == '*' && (flags&SIMPLE))
- reginsert(STAR, ret);
- else if (op == '*') {
- /* Emit x* as (x&|), where & means "self". */
- reginsert(BRANCH, ret); /* Either x */
- regoptail(ret, regnode(BACK)); /* and loop */
- regoptail(ret, ret); /* back */
- regtail(ret, regnode(BRANCH)); /* or */
- regtail(ret, regnode(NOTHING)); /* null. */
- } else if (op == '+' && (flags&SIMPLE))
- reginsert(PLUS, ret);
- else if (op == '+') {
- /* Emit x+ as x(&|), where & means "self". */
- next = regnode(BRANCH); /* Either */
- regtail(ret, next);
- regtail(regnode(BACK), ret); /* loop back */
- regtail(next, regnode(BRANCH)); /* or */
- regtail(ret, regnode(NOTHING)); /* null. */
- } else if (op == '?') {
- /* Emit x? as (x|) */
- reginsert(BRANCH, ret); /* Either x */
- regtail(ret, regnode(BRANCH)); /* or */
- next = regnode(NOTHING); /* null. */
- regtail(ret, next);
- regoptail(ret, next);
- }
- regparse++;
- if (ISMULT(*regparse))
- FAIL("nested *?+");
-
- return(ret);
-}
-
-/*
- - regatom - the lowest level
- *
- * Optimization: gobbles an entire sequence of ordinary characters so that
- * it can turn them into a single node, which is smaller to store and
- * faster to run. Backslashed characters are exceptions, each becoming a
- * separate node; the code is simpler that way and it's not worth fixing.
- */
-static char *
-regatom(flagp)
-int *flagp;
-{
- register char *ret;
- int flags;
-
- *flagp = WORST; /* Tentatively. */
-
- switch (*regparse++) {
- /* FIXME: these chars only have meaning at beg/end of pat? */
- case '^':
- ret = regnode(BOL);
- break;
- case '$':
- ret = regnode(EOL);
- break;
- case '.':
- ret = regnode(ANY);
- *flagp |= HASWIDTH|SIMPLE;
- break;
- case '[': {
- register int class;
- register int classend;
-
- if (*regparse == '^') { /* Complement of range. */
- ret = regnode(ANYBUT);
- regparse++;
- } else
- ret = regnode(ANYOF);
- if (*regparse == ']' || *regparse == '-')
- regc(*regparse++);
- while (*regparse != '\0' && *regparse != ']') {
- if (*regparse == '-') {
- regparse++;
- if (*regparse == ']' || *regparse == '\0')
- regc('-');
- else {
- class = UCHARAT(regparse-2)+1;
- classend = UCHARAT(regparse);
- if (class > classend+1)
- FAIL("invalid [] range");
- for (; class <= classend; class++)
- regc(class);
- regparse++;
- }
- } else
- regc(*regparse++);
- }
- regc('\0');
- if (*regparse != ']')
- FAIL("unmatched []");
- regparse++;
- *flagp |= HASWIDTH|SIMPLE;
- }
- break;
- case '(':
- ret = reg(1, &flags);
- if (ret == NULL)
- return(NULL);
- *flagp |= flags&(HASWIDTH|SPSTART);
- break;
- case '\0':
- case '|':
- case '\n':
- case ')':
- FAIL("internal urp"); /* Supposed to be caught earlier. */
- break;
- case '?':
- case '+':
- case '*':
- FAIL("?+* follows nothing");
- break;
- case '\\':
- switch (*regparse++) {
- case '\0':
- FAIL("trailing \\");
- break;
- case '<':
- ret = regnode(WORDA);
- break;
- case '>':
- ret = regnode(WORDZ);
- break;
- /* FIXME: Someday handle \1, \2, ... */
- default:
- /* Handle general quoted chars in exact-match routine */
- goto de_fault;
- }
- break;
- de_fault:
- default:
- /*
- * Encode a string of characters to be matched exactly.
- *
- * This is a bit tricky due to quoted chars and due to
- * '*', '+', and '?' taking the SINGLE char previous
- * as their operand.
- *
- * On entry, the char at regparse[-1] is going to go
- * into the string, no matter what it is. (It could be
- * following a \ if we are entered from the '\' case.)
- *
- * Basic idea is to pick up a good char in ch and
- * examine the next char. If it's *+? then we twiddle.
- * If it's \ then we frozzle. If it's other magic char
- * we push ch and terminate the string. If none of the
- * above, we push ch on the string and go around again.
- *
- * regprev is used to remember where "the current char"
- * starts in the string, if due to a *+? we need to back
- * up and put the current char in a separate, 1-char, string.
- * When regprev is NULL, ch is the only char in the
- * string; this is used in *+? handling, and in setting
- * flags |= SIMPLE at the end.
- */
- {
- char *regprev;
- register char ch = 0;
-
- regparse--; /* Look at cur char */
- ret = regnode(EXACTLY);
- for ( regprev = 0 ; ; ) {
- ch = *regparse++; /* Get current char */
- switch (*regparse) { /* look at next one */
-
- default:
- regc(ch); /* Add cur to string */
- break;
-
- case '.': case '[': case '(':
- case ')': case '|': case '\n':
- case '$': case '^':
- case '\0':
- /* FIXME, $ and ^ should not always be magic */
- magic:
- regc(ch); /* dump cur char */
- goto done; /* and we are done */
-
- case '?': case '+': case '*':
- if (!regprev) /* If just ch in str, */
- goto magic; /* use it */
- /* End mult-char string one early */
- regparse = regprev; /* Back up parse */
- goto done;
-
- case '\\':
- regc(ch); /* Cur char OK */
- switch (regparse[1]){ /* Look after \ */
- case '\0':
- case '<':
- case '>':
- /* FIXME: Someday handle \1, \2, ... */
- goto done; /* Not quoted */
- default:
- /* Backup point is \, scan * point is after it. */
- regprev = regparse;
- regparse++;
- continue; /* NOT break; */
- }
- }
- regprev = regparse; /* Set backup point */
- }
- done:
- regc('\0');
- *flagp |= HASWIDTH;
- if (!regprev) /* One char? */
- *flagp |= SIMPLE;
- }
- break;
- }
-
- return(ret);
-}
-
-/*
- - regnode - emit a node
- */
-static char * /* Location. */
-regnode(op)
-char op;
-{
- register char *ret;
- register char *ptr;
-
- ret = regcode;
- if (ret == &regdummy) {
- regsize += 3;
- return(ret);
- }
-
- ptr = ret;
- *ptr++ = op;
- *ptr++ = '\0'; /* Null "next" pointer. */
- *ptr++ = '\0';
- regcode = ptr;
-
- return(ret);
-}
-
-/*
- - regc - emit (if appropriate) a byte of code
- */
-static void
-regc(b)
-char b;
-{
- if (regcode != &regdummy)
- *regcode++ = b;
- else
- regsize++;
-}
-
-/*
- - reginsert - insert an operator in front of already-emitted operand
- *
- * Means relocating the operand.
- */
-static void
-reginsert(op, opnd)
-char op;
-char *opnd;
-{
- register char *src;
- register char *dst;
- register char *place;
-
- if (regcode == &regdummy) {
- regsize += 3;
- return;
- }
-
- src = regcode;
- regcode += 3;
- dst = regcode;
- while (src > opnd)
- *--dst = *--src;
-
- place = opnd; /* Op node, where operand used to be. */
- *place++ = op;
- *place++ = '\0';
- *place++ = '\0';
-}
-
-/*
- - regtail - set the next-pointer at the end of a node chain
- */
-static void
-regtail(p, val)
-char *p;
-char *val;
-{
- register char *scan;
- register char *temp;
- register int offset;
-
- if (p == &regdummy)
- return;
-
- /* Find last node. */
- scan = p;
- for (;;) {
- temp = regnext(scan);
- if (temp == NULL)
- break;
- scan = temp;
- }
-
- if (OP(scan) == BACK)
- offset = scan - val;
- else
- offset = val - scan;
- *(scan+1) = (offset>>8)&0377;
- *(scan+2) = offset&0377;
-}
-
-/*
- - regoptail - regtail on operand of first argument; nop if operandless
- */
-static void
-regoptail(p, val)
-char *p;
-char *val;
-{
- /* "Operandless" and "op != BRANCH" are synonymous in practice. */
- if (p == NULL || p == &regdummy || OP(p) != BRANCH)
- return;
- regtail(OPERAND(p), val);
-}
-
-/*
- * regexec and friends
- */
-
-/*
- * Global work variables for regexec().
- */
-static char *reginput; /* String-input pointer. */
-static char *regbol; /* Beginning of input, for ^ check. */
-static char **regstartp; /* Pointer to startp array. */
-static char **regendp; /* Ditto for endp. */
-
-/*
- * Forwards.
- */
-STATIC int regtry (const regexp *, const char *);
-STATIC int regmatch (char *);
-STATIC int regrepeat (char *);
-
-#ifdef DEBUG
-int regnarrate = 0;
-void regdump __P((regexp *));
-STATIC char *regprop __P((char *));
-#endif
-
-/*
- - regexec - match a regexp against a string
- */
-int
-regexec(prog, string)
-register const regexp *prog;
-register const char *string;
-{
- register char *s;
-
- /* Be paranoid... */
- if (prog == NULL || string == NULL) {
- regerror("NULL parameter");
- return(0);
- }
-
- /* Check validity of program. */
- if (UCHARAT(prog->program) != MAGIC) {
- regerror("corrupted program");
- return(0);
- }
-
- /* If there is a "must appear" string, look for it. */
- if (prog->regmust != NULL) {
- s = (char *)string;
- while ((s = strchr(s, prog->regmust[0])) != NULL) {
- if (strncmp(s, prog->regmust, prog->regmlen) == 0)
- break; /* Found it. */
- s++;
- }
- if (s == NULL) /* Not present. */
- return(0);
- }
-
- /* Mark beginning of line for ^ . */
- regbol = (char *)string;
-
- /* Simplest case: anchored match need be tried only once. */
- if (prog->reganch)
- return(regtry(prog, string));
-
- /* Messy cases: unanchored match. */
- s = (char *)string;
- if (prog->regstart != '\0')
- /* We know what char it must start with. */
- while ((s = strchr(s, prog->regstart)) != NULL) {
- if (regtry(prog, s))
- return(1);
- s++;
- }
- else
- /* We don't -- general case. */
- do {
- if (regtry(prog, s))
- return(1);
- } while (*s++ != '\0');
-
- /* Failure. */
- return(0);
-}
-
-/*
- - regtry - try match at specific point
- */
-static int /* 0 failure, 1 success */
-regtry(prog, string)
-const regexp *prog;
-const char *string;
-{
- register int i;
- register char **sp;
- register char **ep;
-
- reginput = (char *)string; /* XXX */
- regstartp = (char **)prog->startp; /* XXX */
- regendp = (char **)prog->endp; /* XXX */
-
- sp = (char **)prog->startp; /* XXX */
- ep = (char **)prog->endp; /* XXX */
- for (i = NSUBEXP; i > 0; i--) {
- *sp++ = NULL;
- *ep++ = NULL;
- }
- if (regmatch((char *)prog->program + 1)) { /* XXX */
- ((regexp *)prog)->startp[0] = (char *)string; /* XXX */
- ((regexp *)prog)->endp[0] = reginput; /* XXX */
- return(1);
- } else
- return(0);
-}
-
-/*
- - regmatch - main matching routine
- *
- * Conceptually the strategy is simple: check to see whether the current
- * node matches, call self recursively to see whether the rest matches,
- * and then act accordingly. In practice we make some effort to avoid
- * recursion, in particular by going through "ordinary" nodes (that don't
- * need to know whether the rest of the match failed) by a loop instead of
- * by recursion.
- */
-static int /* 0 failure, 1 success */
-regmatch(prog)
-char *prog;
-{
- register char *scan; /* Current node. */
- char *next; /* Next node. */
-
- scan = prog;
-#ifdef DEBUG
- if (scan != NULL && regnarrate)
- fprintf(stderr, "%s(\n", regprop(scan));
-#endif
- while (scan != NULL) {
-#ifdef DEBUG
- if (regnarrate)
- fprintf(stderr, "%s...\n", regprop(scan));
-#endif
- next = regnext(scan);
-
- switch (OP(scan)) {
- case BOL:
- if (reginput != regbol)
- return(0);
- break;
- case EOL:
- if (*reginput != '\0')
- return(0);
- break;
- case WORDA:
- /* Must be looking at a letter, digit, or _ */
- if ((!isalnum(*reginput)) && *reginput != '_')
- return(0);
- /* Prev must be BOL or nonword */
- if (reginput > regbol &&
- (isalnum(reginput[-1]) || reginput[-1] == '_'))
- return(0);
- break;
- case WORDZ:
- /* Must be looking at non letter, digit, or _ */
- if (isalnum(*reginput) || *reginput == '_')
- return(0);
- /* We don't care what the previous char was */
- break;
- case ANY:
- if (*reginput == '\0')
- return(0);
- reginput++;
- break;
- case EXACTLY: {
- register int len;
- register char *opnd;
-
- opnd = OPERAND(scan);
- /* Inline the first character, for speed. */
- if (*opnd != *reginput)
- return(0);
- len = strlen(opnd);
- if (len > 1 && strncmp(opnd, reginput, len) != 0)
- return(0);
- reginput += len;
- }
- break;
- case ANYOF:
- if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
- return(0);
- reginput++;
- break;
- case ANYBUT:
- if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
- return(0);
- reginput++;
- break;
- case NOTHING:
- break;
- case BACK:
- break;
- case OPEN+1:
- case OPEN+2:
- case OPEN+3:
- case OPEN+4:
- case OPEN+5:
- case OPEN+6:
- case OPEN+7:
- case OPEN+8:
- case OPEN+9: {
- register int no;
- register char *save;
-
- no = OP(scan) - OPEN;
- save = reginput;
-
- if (regmatch(next)) {
- /*
- * Don't set startp if some later
- * invocation of the same parentheses
- * already has.
- */
- if (regstartp[no] == NULL)
- regstartp[no] = save;
- return(1);
- } else
- return(0);
- }
- break;
- case CLOSE+1:
- case CLOSE+2:
- case CLOSE+3:
- case CLOSE+4:
- case CLOSE+5:
- case CLOSE+6:
- case CLOSE+7:
- case CLOSE+8:
- case CLOSE+9: {
- register int no;
- register char *save;
-
- no = OP(scan) - CLOSE;
- save = reginput;
-
- if (regmatch(next)) {
- /*
- * Don't set endp if some later
- * invocation of the same parentheses
- * already has.
- */
- if (regendp[no] == NULL)
- regendp[no] = save;
- return(1);
- } else
- return(0);
- }
- break;
- case BRANCH: {
- register char *save;
-
- if (OP(next) != BRANCH) /* No choice. */
- next = OPERAND(scan); /* Avoid recursion. */
- else {
- do {
- save = reginput;
- if (regmatch(OPERAND(scan)))
- return(1);
- reginput = save;
- scan = regnext(scan);
- } while (scan != NULL && OP(scan) == BRANCH);
- return(0);
- /* NOTREACHED */
- }
- }
- break;
- case STAR:
- case PLUS: {
- register char nextch;
- register int no;
- register char *save;
- register int min;
-
- /*
- * Lookahead to avoid useless match attempts
- * when we know what character comes next.
- */
- nextch = '\0';
- if (OP(next) == EXACTLY)
- nextch = *OPERAND(next);
- min = (OP(scan) == STAR) ? 0 : 1;
- save = reginput;
- no = regrepeat(OPERAND(scan));
- while (no >= min) {
- /* If it could work, try it. */
- if (nextch == '\0' || *reginput == nextch)
- if (regmatch(next))
- return(1);
- /* Couldn't or didn't -- back up. */
- no--;
- reginput = save + no;
- }
- return(0);
- }
- break;
- case END:
- return(1); /* Success! */
- break;
- default:
- regerror("memory corruption");
- return(0);
- break;
- }
-
- scan = next;
- }
-
- /*
- * We get here only if there's trouble -- normally "case END" is
- * the terminating point.
- */
- regerror("corrupted pointers");
- return(0);
-}
-
-/*
- - regrepeat - repeatedly match something simple, report how many
- */
-static int
-regrepeat(p)
-char *p;
-{
- register int count = 0;
- register char *scan;
- register char *opnd;
-
- scan = reginput;
- opnd = OPERAND(p);
- switch (OP(p)) {
- case ANY:
- count = strlen(scan);
- scan += count;
- break;
- case EXACTLY:
- while (*opnd == *scan) {
- count++;
- scan++;
- }
- break;
- case ANYOF:
- while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
- count++;
- scan++;
- }
- break;
- case ANYBUT:
- while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
- count++;
- scan++;
- }
- break;
- default: /* Oh dear. Called inappropriately. */
- regerror("internal foulup");
- count = 0; /* Best compromise. */
- break;
- }
- reginput = scan;
-
- return(count);
-}
-
-/*
- - regnext - dig the "next" pointer out of a node
- */
-static char *
-regnext(p)
-register char *p;
-{
- register int offset;
-
- if (p == &regdummy)
- return(NULL);
-
- offset = NEXT(p);
- if (offset == 0)
- return(NULL);
-
- if (OP(p) == BACK)
- return(p-offset);
- else
- return(p+offset);
-}
-
-#ifdef DEBUG
-
-/*
- - regdump - dump a regexp onto stdout in vaguely comprehensible form
- */
-void
-regdump(r)
-regexp *r;
-{
- register char *s;
- register char op = EXACTLY; /* Arbitrary non-END op. */
- register char *next;
- extern char *strchr();
-
-
- s = r->program + 1;
- while (op != END) { /* While that wasn't END last time... */
- op = OP(s);
- printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
- next = regnext(s);
- if (next == NULL) /* Next ptr. */
- printf("(0)");
- else
- printf("(%d)", (s-r->program)+(next-s));
- s += 3;
- if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
- /* Literal string, where present. */
- while (*s != '\0') {
- putchar(*s);
- s++;
- }
- s++;
- }
- putchar('\n');
- }
-
- /* Header fields of interest. */
- if (r->regstart != '\0')
- printf("start `%c' ", r->regstart);
- if (r->reganch)
- printf("anchored ");
- if (r->regmust != NULL)
- printf("must have \"%s\"", r->regmust);
- printf("\n");
-}
-
-/*
- - regprop - printable representation of opcode
- */
-static char *
-regprop(op)
-char *op;
-{
- register char *p;
- static char buf[50];
-
- (void) strcpy(buf, ":");
-
- switch (OP(op)) {
- case BOL:
- p = "BOL";
- break;
- case EOL:
- p = "EOL";
- break;
- case ANY:
- p = "ANY";
- break;
- case ANYOF:
- p = "ANYOF";
- break;
- case ANYBUT:
- p = "ANYBUT";
- break;
- case BRANCH:
- p = "BRANCH";
- break;
- case EXACTLY:
- p = "EXACTLY";
- break;
- case NOTHING:
- p = "NOTHING";
- break;
- case BACK:
- p = "BACK";
- break;
- case END:
- p = "END";
- break;
- case OPEN+1:
- case OPEN+2:
- case OPEN+3:
- case OPEN+4:
- case OPEN+5:
- case OPEN+6:
- case OPEN+7:
- case OPEN+8:
- case OPEN+9:
- sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
- p = NULL;
- break;
- case CLOSE+1:
- case CLOSE+2:
- case CLOSE+3:
- case CLOSE+4:
- case CLOSE+5:
- case CLOSE+6:
- case CLOSE+7:
- case CLOSE+8:
- case CLOSE+9:
- sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
- p = NULL;
- break;
- case STAR:
- p = "STAR";
- break;
- case PLUS:
- p = "PLUS";
- break;
- case WORDA:
- p = "WORDA";
- break;
- case WORDZ:
- p = "WORDZ";
- break;
- default:
- regerror("corrupted opcode");
- break;
- }
- if (p != NULL)
- (void) strcat(buf, p);
- return(buf);
-}
-#endif
-
-/*
- * The following is provided for those people who do not have strcspn() in
- * their C libraries. They should get off their butts and do something
- * about it; at least one public-domain implementation of those (highly
- * useful) string routines has been published on Usenet.
- */
-#ifdef STRCSPN
-/*
- * strcspn - find length of initial segment of s1 consisting entirely
- * of characters not from s2
- */
-
-static int
-strcspn(s1, s2)
-char *s1;
-char *s2;
-{
- register char *scan1;
- register char *scan2;
- register int count;
-
- count = 0;
- for (scan1 = s1; *scan1 != '\0'; scan1++) {
- for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
- if (*scan1 == *scan2++)
- return(count);
- count++;
- }
- return(count);
-}
-#endif
diff --git a/winsup/cygwin/regexp/regsub.c b/winsup/cygwin/regexp/regsub.c
deleted file mode 100644
index e544072c1..000000000
--- a/winsup/cygwin/regexp/regsub.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * regsub
- *
- * Copyright (c) 1986 by University of Toronto.
- * Written by Henry Spencer. Not derived from licensed software.
- *
- * Permission is granted to anyone to use this software for any
- * purpose on any computer system, and to redistribute it freely,
- * subject to the following restrictions:
- *
- * 1. The author is not responsible for the consequences of use of
- * this software, no matter how awful, even if they arise
- * from defects in it.
- *
- * 2. The origin of this software must not be misrepresented, either
- * by explicit claim or by omission.
- *
- * 3. Altered versions must be plainly marked as such, and must not
- * be misrepresented as being the original software.
- */
-
-#if 0
-#ifndef lint
-static char *rcsid = "$Id$";
-#endif /* not lint */
-#endif
-
-#include "regexp.h"
-#include <stdio.h>
-#include <string.h>
-#include "regmagic.h"
-
-#ifndef CHARBITS
-#define UCHARAT(p) ((int)*(unsigned char *)(p))
-#else
-#define UCHARAT(p) ((int)*(p)&CHARBITS)
-#endif
-
-/*
- - regsub - perform substitutions after a regexp match
- */
-void
-regsub(prog, source, dest)
-const regexp *prog;
-const char *source;
-char *dest;
-{
- register char *src;
- register char *dst;
- register char c;
- register int no;
- register int len;
-
- if (prog == NULL || source == NULL || dest == NULL) {
- regerror("NULL parm to regsub");
- return;
- }
- if (UCHARAT(prog->program) != MAGIC) {
- regerror("damaged regexp fed to regsub");
- return;
- }
-
- src = (char *)source;
- dst = dest;
- while ((c = *src++) != '\0') {
- if (c == '&')
- no = 0;
- else if (c == '\\' && '0' <= *src && *src <= '9')
- no = *src++ - '0';
- else
- no = -1;
- if (no < 0) { /* Ordinary character. */
- if (c == '\\' && (*src == '\\' || *src == '&'))
- c = *src++;
- *dst++ = c;
- } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
- len = prog->endp[no] - prog->startp[no];
- (void) strncpy(dst, prog->startp[no], len);
- dst += len;
- if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
- regerror("damaged match string");
- return;
- }
- }
- }
- *dst++ = '\0';
-}
diff --git a/winsup/cygwin/registry.cc b/winsup/cygwin/registry.cc
index 3ed1a80bb..22fa511a7 100644
--- a/winsup/cygwin/registry.cc
+++ b/winsup/cygwin/registry.cc
@@ -1,6 +1,6 @@
/* registry.cc: registry interface
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -235,12 +235,13 @@ load_registry_hive (PSID psid)
/* Check if user hive is already loaded. */
cygsid csid (psid);
csid.string (sid);
- if (!RegOpenKeyExA (HKEY_USERS, csid.string (sid), 0, KEY_READ, &hkey))
+ if (!RegOpenKeyExA (HKEY_USERS, sid, 0, KEY_READ, &hkey))
{
debug_printf ("User registry hive for %s already exists", sid);
RegCloseKey (hkey);
return;
}
+ set_process_privilege (SE_RESTORE_NAME);
if (get_registry_hive_path (psid, path))
{
strcat (path, "\\NTUSER.DAT");
diff --git a/winsup/cygwin/resource.cc b/winsup/cygwin/resource.cc
index 8dd373b6f..0db6cd5b8 100644
--- a/winsup/cygwin/resource.cc
+++ b/winsup/cygwin/resource.cc
@@ -1,6 +1,6 @@
/* resource.cc: getrusage () and friends.
- Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
Written by Steve Chamberlain (sac@cygnus.com), Doug Evans (dje@cygnus.com),
Geoffrey Noer (noer@cygnus.com) of Cygnus Support.
@@ -17,9 +17,8 @@ details. */
#include <unistd.h>
#include <limits.h>
#include "cygerrno.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
+#include "psapi.h"
/* add timeval values */
static void
@@ -73,6 +72,15 @@ fill_rusage (struct rusage *r, HANDLE h)
add_timeval (&r->ru_stime, &tv);
totimeval (&tv, &user_time, 0, 0);
add_timeval (&r->ru_utime, &tv);
+
+ PROCESS_MEMORY_COUNTERS pmc;
+
+ memset (&pmc, 0, sizeof (pmc));
+ if (GetProcessMemoryInfo (h, &pmc, sizeof (pmc)))
+ {
+ r->ru_maxrss += (long) (pmc.WorkingSetSize /1024);
+ r->ru_majflt += pmc.PageFaultCount;
+ }
}
extern "C"
@@ -102,8 +110,7 @@ getrusage (int intwho, struct rusage *rusage_in)
unsigned long rlim_core = RLIM_INFINITY;
-extern "C"
-int
+extern "C" int
getrlimit (int resource, struct rlimit *rlp)
{
MEMORY_BASIC_INFORMATION m;
@@ -147,11 +154,10 @@ getrlimit (int resource, struct rlimit *rlp)
return 0;
}
-extern "C"
-int
+extern "C" int
setrlimit (int resource, const struct rlimit *rlp)
{
- if (check_null_invalid_struct_errno (rlp))
+ if (__check_invalid_read_ptr_errno (rlp, sizeof (*rlp)))
return -1;
struct rlimit oldlimits;
@@ -159,7 +165,7 @@ setrlimit (int resource, const struct rlimit *rlp)
// Check if the request is to actually change the resource settings.
// If it does not result in a change, take no action and do not
// fail.
- if (getrlimit(resource, &oldlimits) < 0)
+ if (getrlimit (resource, &oldlimits) < 0)
return -1;
if (oldlimits.rlim_cur == rlp->rlim_cur &&
diff --git a/winsup/cygwin/safe_memory.h b/winsup/cygwin/safe_memory.h
new file mode 100644
index 000000000..b5f3d95d6
--- /dev/null
+++ b/winsup/cygwin/safe_memory.h
@@ -0,0 +1,53 @@
+/* safe_memory.h
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef __SAFE_MEMORY_H__
+#define __SAFE_MEMORY_H__
+
+/*****************************************************************************/
+
+/* Temporary hack to get around the thread-unsafe new/delete in cygwin
+ * gcc 2.95.3. This should all be binned at the first opportunity,
+ * e.g. gcc 3.1 or sooner.
+ *
+ * The trick here is to do contruction via malloc(3) and then the
+ * placement new operator, and destruction via an explicit call to the
+ * destructor and then free(3).
+ */
+
+#include <stdlib.h>
+
+inline void *operator new (size_t, void *__p) throw () { return __p; }
+
+#define safe_new0(T) (new (malloc (sizeof (T))) T)
+
+#ifdef NEW_MACRO_VARARGS
+
+#define safe_new(T, ...) \
+ (new (malloc (sizeof (T))) T (__VA_ARGS__))
+
+#else /* !NEW_MACRO_VARARGS */
+
+#define safe_new(T, args...) \
+ (new (malloc (sizeof (T))) T (## args))
+
+#endif /* !NEW_MACRO_VARARGS */
+
+template <typename T> void
+safe_delete (T *const object)
+{
+ if (object)
+ {
+ object->~T ();
+ free (object);
+ }
+}
+
+#endif /* __SAFE_MEMORY_H__ */
diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc
index 522fb0c02..7b4074d7f 100644
--- a/winsup/cygwin/sched.cc
+++ b/winsup/cygwin/sched.cc
@@ -22,7 +22,6 @@
#include <stdlib.h>
#include <syslog.h>
#include <sched.h>
-#include "sigproc.h"
#include "pinfo.h"
/* for getpid */
#include <unistd.h>
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index 36bff09c2..90b6ef082 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -1,6 +1,6 @@
/* secacl.cc: Sun compatible ACL functions.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
Written by Corinna Vinschen <corinna@vinschen.de>
@@ -24,18 +24,18 @@ details. */
#include <wingdi.h>
#include <winuser.h>
#include "cygerrno.h"
-#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "cygheap.h"
+extern "C" int aclsort (int nentries, int, __aclent16_t *aclbufp);
+extern "C" int acl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp);
+
static int
-searchace (aclent_t *aclp, int nentries, int type, int id = -1)
+searchace (__aclent16_t *aclp, int nentries, int type, int id = -1)
{
int i;
@@ -47,7 +47,7 @@ searchace (aclent_t *aclp, int nentries, int type, int id = -1)
}
static int
-setacl (const char *file, int nentries, aclent_t *aclbufp)
+setacl (const char *file, int nentries, __aclent16_t *aclbufp)
{
DWORD sd_size = 4096;
char sd_buf[4096];
@@ -86,13 +86,13 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
__seterrno ();
return -1;
}
- if (!SetSecurityDescriptorOwner(&sd, owner, FALSE))
+ if (!SetSecurityDescriptorOwner (&sd, owner, FALSE))
{
__seterrno ();
return -1;
}
if (group
- && !SetSecurityDescriptorGroup(&sd, group, FALSE))
+ && !SetSecurityDescriptorGroup (&sd, group, FALSE))
{
__seterrno ();
return -1;
@@ -106,7 +106,7 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
cygsid sid;
struct passwd *pw;
- struct group *gr;
+ struct __group32 *gr;
int pos;
if (!InitializeAcl (acl, 3072, ACL_REVISION))
@@ -128,7 +128,8 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
allow |= FILE_DELETE_CHILD;
/* Set inherit property. */
DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
- ? INHERIT_ONLY : DONT_INHERIT;
+ ? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY)
+ : NO_INHERITANCE;
/*
* If a specific acl contains a corresponding default entry with
* identical permissions, only one Windows ACE with proper
@@ -142,7 +143,7 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
&& pos < nentries
&& aclbufp[i].a_perm == aclbufp[pos].a_perm)
{
- inheritance = INHERIT_ALL;
+ inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
/* This eliminates the corresponding default entry. */
aclbufp[pos].a_type = 0;
}
@@ -157,7 +158,7 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
break;
case USER:
case DEF_USER:
- if (!(pw = getpwuid (aclbufp[i].a_id))
+ if (!(pw = getpwuid32 (aclbufp[i].a_id))
|| !sid.getfrompw (pw)
|| !add_access_allowed_ace (acl, ace_off++, allow,
sid, acl_len, inheritance))
@@ -171,7 +172,7 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
break;
case GROUP:
case DEF_GROUP:
- if (!(gr = getgrgid (aclbufp[i].a_id))
+ if (!(gr = getgrgid32 (aclbufp[i].a_id))
|| !sid.getfromgr (gr)
|| !add_access_allowed_ace (acl, ace_off++, allow,
sid, acl_len, inheritance))
@@ -213,7 +214,7 @@ setacl (const char *file, int nentries, aclent_t *aclbufp)
}
static void
-getace (aclent_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type)
+getace (__aclent16_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type)
{
acl.a_type = type;
acl.a_id = id;
@@ -238,7 +239,7 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type)
}
static int
-getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
+getacl (const char *file, DWORD attr, int nentries, __aclent16_t *aclbufp)
{
DWORD sd_size = 4096;
char sd_buf[4096];
@@ -254,8 +255,8 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
PSID owner_sid;
PSID group_sid;
BOOL dummy;
- uid_t uid;
- gid_t gid;
+ __uid32_t uid;
+ __gid32_t gid;
if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy))
{
@@ -273,8 +274,8 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
}
gid = cygsid (group_sid).get_gid ();
- aclent_t lacl[MAX_ACL_ENTRIES];
- memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t));
+ __aclent16_t lacl[MAX_ACL_ENTRIES];
+ memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (__aclent16_t));
lacl[0].a_type = USER_OBJ;
lacl[0].a_id = uid;
lacl[1].a_type = GROUP_OBJ;
@@ -298,7 +299,7 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos)
lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
pos = nentries < MIN_ACL_ENTRIES ? nentries : MIN_ACL_ENTRIES;
- memcpy (aclbufp, lacl, pos * sizeof (aclent_t));
+ memcpy (aclbufp, lacl, pos * sizeof (__aclent16_t));
return pos;
}
@@ -313,7 +314,12 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
int id;
int type = 0;
- if (ace_sid == owner_sid)
+ if (ace_sid == well_known_world_sid)
+ {
+ type = OTHER_OBJ;
+ id = 0;
+ }
+ else if (ace_sid == owner_sid)
{
type = USER_OBJ;
id = uid;
@@ -323,11 +329,6 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
type = GROUP_OBJ;
id = gid;
}
- else if (ace_sid == well_known_world_sid)
- {
- type = OTHER_OBJ;
- id = 0;
- }
else
{
id = ace_sid.get_id (FALSE, &type);
@@ -344,12 +345,12 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
}
if (!type)
continue;
- if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE))
+ if (!(ace->Header.AceFlags & INHERIT_ONLY))
{
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
}
- if ((ace->Header.AceFlags & INHERIT_ALL)
+ if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
&& (attr & FILE_ATTRIBUTE_DIRECTORY))
{
type |= ACL_DEFAULT;
@@ -389,7 +390,7 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
if (pos > nentries)
pos = nentries;
if (aclbufp)
- memcpy (aclbufp, lacl, pos * sizeof (aclent_t));
+ memcpy (aclbufp, lacl, pos * sizeof (__aclent16_t));
aclsort (pos, 0, aclbufp);
syscall_printf ("%d = getacl (%s)", pos, file);
return pos;
@@ -398,7 +399,7 @@ getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp)
int
acl_access (const char *path, int flags)
{
- aclent_t acls[MAX_ACL_ENTRIES];
+ __aclent16_t acls[MAX_ACL_ENTRIES];
int cnt;
if ((cnt = acl (path, GETACL, MAX_ACL_ENTRIES, acls)) < 1)
@@ -423,9 +424,9 @@ acl_access (const char *path, int flags)
cygsid owner;
cygsid group;
struct passwd *pw;
- struct group *gr = NULL;
+ struct __group32 *gr = NULL;
- if ((pw = getpwuid (acls[i].a_id)) != NULL
+ if ((pw = getpwuid32 (acls[i].a_id)) != NULL
&& owner.getfrompw (pw))
{
for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
@@ -460,7 +461,7 @@ acl_access (const char *path, int flags)
static
int
-acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp,
+acl_worker (const char *path, int cmd, int nentries, __aclent16_t *aclbufp,
int nofollow)
{
extern suffix_info stat_suffixes[];
@@ -473,7 +474,7 @@ acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp,
}
if (!real_path.has_acls ())
{
- struct stat st;
+ struct __stat64 st;
int ret = -1;
switch (cmd)
@@ -484,10 +485,10 @@ acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp,
case GETACL:
if (nentries < 1)
set_errno (EINVAL);
- else if ((nofollow && !lstat (path, &st))
- || (!nofollow && !stat (path, &st)))
+ else if ((nofollow && !lstat64 (path, &st))
+ || (!nofollow && !stat64 (path, &st)))
{
- aclent_t lacl[4];
+ __aclent16_t lacl[4];
if (nentries > 0)
{
lacl[0].a_type = USER_OBJ;
@@ -523,7 +524,7 @@ acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp,
if (nentries > 4)
nentries = 4;
if (aclbufp)
- memcpy (aclbufp, lacl, nentries * sizeof (aclent_t));
+ memcpy (aclbufp, lacl, nentries * sizeof (__aclent16_t));
ret = nentries;
}
break;
@@ -537,7 +538,7 @@ acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp,
switch (cmd)
{
case SETACL:
- if (!aclsort(nentries, 0, aclbufp))
+ if (!aclsort (nentries, 0, aclbufp))
return setacl (real_path.get_win32 (),
nentries, aclbufp);
break;
@@ -561,29 +562,29 @@ acl_worker (const char *path, int cmd, int nentries, aclent_t *aclbufp,
extern "C"
int
-acl (const char *path, int cmd, int nentries, aclent_t *aclbufp)
+acl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
{
return acl_worker (path, cmd, nentries, aclbufp, 0);
}
extern "C"
int
-lacl (const char *path, int cmd, int nentries, aclent_t *aclbufp)
+lacl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
{
return acl_worker (path, cmd, nentries, aclbufp, 1);
}
extern "C"
int
-facl (int fd, int cmd, int nentries, aclent_t *aclbufp)
+facl (int fd, int cmd, int nentries, __aclent16_t *aclbufp)
{
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
{
syscall_printf ("-1 = facl (%d)", fd);
- set_errno (EBADF);
return -1;
}
- const char *path = cygheap->fdtab[fd]->get_name ();
+ const char *path = cfd->get_name ();
if (path == NULL)
{
syscall_printf ("-1 = facl (%d) (no name)", fd);
@@ -596,7 +597,7 @@ facl (int fd, int cmd, int nentries, aclent_t *aclbufp)
extern "C"
int
-aclcheck (aclent_t *aclbufp, int nentries, int *which)
+aclcheck (__aclent16_t *aclbufp, int nentries, int *which)
{
BOOL has_user_obj = FALSE;
BOOL has_group_obj = FALSE;
@@ -730,17 +731,17 @@ aclcheck (aclent_t *aclbufp, int nentries, int *which)
extern "C"
int acecmp (const void *a1, const void *a2)
{
-#define ace(i) ((const aclent_t *) a##i)
- int ret = ace(1)->a_type - ace(2)->a_type;
+#define ace(i) ((const __aclent16_t *) a##i)
+ int ret = ace (1)->a_type - ace (2)->a_type;
if (!ret)
- ret = ace(1)->a_id - ace(2)->a_id;
+ ret = ace (1)->a_id - ace (2)->a_id;
return ret;
#undef ace
}
extern "C"
int
-aclsort (int nentries, int, aclent_t *aclbufp)
+aclsort (int nentries, int, __aclent16_t *aclbufp)
{
if (aclcheck (aclbufp, nentries, NULL))
return -1;
@@ -749,13 +750,13 @@ aclsort (int nentries, int, aclent_t *aclbufp)
set_errno (EINVAL);
return -1;
}
- qsort((void *) aclbufp, nentries, sizeof (aclent_t), acecmp);
+ qsort ((void *) aclbufp, nentries, sizeof (__aclent16_t), acecmp);
return 0;
}
extern "C"
int
-acltomode (aclent_t *aclbufp, int nentries, mode_t *modep)
+acltomode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
{
int pos;
@@ -790,7 +791,7 @@ acltomode (aclent_t *aclbufp, int nentries, mode_t *modep)
extern "C"
int
-aclfrommode(aclent_t *aclbufp, int nentries, mode_t *modep)
+aclfrommode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
{
int pos;
@@ -830,14 +831,14 @@ aclfrommode(aclent_t *aclbufp, int nentries, mode_t *modep)
extern "C"
int
-acltopbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp)
+acltopbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
{
return acltomode (aclbufp, nentries, pbitsp);
}
extern "C"
int
-aclfrompbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp)
+aclfrompbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
{
return aclfrommode (aclbufp, nentries, pbitsp);
}
@@ -856,7 +857,7 @@ permtostr (mode_t perm)
extern "C"
char *
-acltotext (aclent_t *aclbufp, int aclcnt)
+acltotext (__aclent16_t *aclbufp, int aclcnt)
{
if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES
|| aclcheck (aclbufp, aclcnt, NULL))
@@ -932,7 +933,7 @@ permfromstr (char *perm)
}
extern "C"
-aclent_t *
+__aclent16_t *
aclfromtext (char *acltextp, int *)
{
if (!acltextp)
@@ -941,7 +942,7 @@ aclfromtext (char *acltextp, int *)
return NULL;
}
char buf[strlen (acltextp) + 1];
- aclent_t lacl[MAX_ACL_ENTRIES];
+ __aclent16_t lacl[MAX_ACL_ENTRIES];
memset (lacl, 0, sizeof lacl);
int pos = 0;
strcpy (buf, acltextp);
@@ -993,7 +994,7 @@ aclfromtext (char *acltextp, int *)
c += 5;
if (isalpha (*c))
{
- struct group *gr = getgrnam (c);
+ struct __group32 *gr = getgrnam32 (c);
if (!gr)
{
set_errno (EINVAL);
@@ -1038,9 +1039,9 @@ aclfromtext (char *acltextp, int *)
}
++pos;
}
- aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t));
+ __aclent16_t *aclp = (__aclent16_t *) malloc (pos * sizeof (__aclent16_t));
if (aclp)
- memcpy (aclp, lacl, pos * sizeof (aclent_t));
+ memcpy (aclp, lacl, pos * sizeof (__aclent16_t));
return aclp;
}
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index b618cf32d..fa0519371 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -1,6 +1,6 @@
/* sec_helper.cc: NT security helper functions
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
Written by Corinna Vinschen <corinna@vinschen.de>
@@ -25,16 +25,19 @@ details. */
#include <winuser.h>
#include <wininet.h>
#include "cygerrno.h"
-#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "cygheap.h"
+/* General purpose security attribute objects for global use. */
+SECURITY_ATTRIBUTES NO_COPY sec_none;
+SECURITY_ATTRIBUTES NO_COPY sec_none_nih;
+SECURITY_ATTRIBUTES NO_COPY sec_all;
+SECURITY_ATTRIBUTES NO_COPY sec_all_nih;
+
SID_IDENTIFIER_AUTHORITY sid_auth[] = {
{SECURITY_NULL_SID_AUTHORITY},
{SECURITY_WORLD_SID_AUTHORITY},
@@ -66,11 +69,11 @@ cygsid::string (char *nsidstr) const
if (!psid || !nsidstr)
return NULL;
strcpy (nsidstr, "S-1-");
- __small_sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]);
+ __small_sprintf (t, "%u", GetSidIdentifierAuthority (psid)->Value[5]);
strcat (nsidstr, t);
for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i)
{
- __small_sprintf(t, "-%lu", *GetSidSubAuthority (psid, i));
+ __small_sprintf (t, "-%lu", *GetSidSubAuthority (psid, i));
strcat (nsidstr, t);
}
return nsidstr;
@@ -87,7 +90,7 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r)
return NULL;
}
set ();
- InitializeSid(psid, &sid_auth[s], cnt);
+ InitializeSid (psid, &sid_auth[s], cnt);
for (i = 0; i < cnt; ++i)
memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD));
return psid;
@@ -129,7 +132,7 @@ cygsid::getfrompw (const struct passwd *pw)
}
BOOL
-cygsid::getfromgr (const struct group *gr)
+cygsid::getfromgr (const struct __group32 *gr)
{
char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL;
return (*this = sp ?: "") != NULL;
@@ -146,7 +149,7 @@ cygsid::get_id (BOOL search_grp, int *type)
if (!IsValidSid (psid))
{
__seterrno ();
- small_printf ("IsValidSid failed with %E");
+ system_printf ("IsValidSid failed with %E");
return -1;
}
@@ -176,7 +179,7 @@ cygsid::get_id (BOOL search_grp, int *type)
}
if (search_grp || type)
{
- struct group *gr;
+ struct __group32 *gr;
for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
{
if (sid.getfromgr (gr) && sid == psid)
@@ -195,7 +198,7 @@ cygsid::get_id (BOOL search_grp, int *type)
}
/* We use the RID as default UID/GID */
- int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 1);
+ int id = *GetSidSubAuthority (psid, *GetSidSubAuthorityCount (psid) - 1);
/*
* The RID maybe -1 if accountname == computername.
@@ -226,7 +229,7 @@ cygsid::get_id (BOOL search_grp, int *type)
*type = GROUP;
if (id == -1)
{
- struct group *gr = getgrnam (account);
+ struct __group32 *gr = getgrnam32 (account);
if (gr)
id = gr->gr_gid;
}
@@ -246,21 +249,21 @@ cygsid::get_id (BOOL search_grp, int *type)
}
}
if (id == -1)
- id = getuid ();
+ id = getuid32 ();
return id;
}
BOOL
-is_grp_member (uid_t uid, gid_t gid)
+is_grp_member (__uid32_t uid, __gid32_t gid)
{
- extern int getgroups (int, gid_t *, gid_t, const char *);
+ extern int getgroups32 (int, __gid32_t *, __gid32_t, const char *);
BOOL grp_member = TRUE;
- struct passwd *pw = getpwuid (uid);
- gid_t grps[NGROUPS_MAX];
- int cnt = getgroups (NGROUPS_MAX, grps,
- pw ? pw->pw_gid : myself->gid,
- pw ? pw->pw_name : cygheap->user.name ());
+ struct passwd *pw = getpwuid32 (uid);
+ __gid32_t grps[NGROUPS_MAX];
+ int cnt = getgroups32 (NGROUPS_MAX, grps,
+ pw ? pw->pw_gid : myself->gid,
+ pw ? pw->pw_name : cygheap->user.name ());
int i;
for (i = 0; i < cnt; ++i)
if (grps[i] == gid)
@@ -269,6 +272,7 @@ is_grp_member (uid_t uid, gid_t gid)
return grp_member;
}
+#if 0 // unused
#define SIDLEN (sidlen = MAX_SID_LEN, &sidlen)
#define DOMLEN (domlen = INTERNET_MAX_HOST_NAME_LENGTH, &domlen)
@@ -321,13 +325,13 @@ lookup_name (const char *name, const char *logsrv, PSID ret_sid)
if (LookupAccountName (NULL, domuser, sid, SIDLEN, dom, DOMLEN,&acc_type))
goto got_it;
}
- debug_printf ("LookupAccountName(%s) %E", name);
+ debug_printf ("LookupAccountName (%s) %E", name);
__seterrno ();
return FALSE;
got_it:
- debug_printf ("sid : [%d]", *GetSidSubAuthority((PSID) sid,
- *GetSidSubAuthorityCount((PSID) sid) - 1));
+ debug_printf ("sid : [%d]", *GetSidSubAuthority ((PSID) sid,
+ *GetSidSubAuthorityCount ((PSID) sid) - 1));
if (ret_sid)
memcpy (ret_sid, sid, sidlen);
@@ -337,6 +341,7 @@ got_it:
#undef SIDLEN
#undef DOMLEN
+#endif //unused
int
set_process_privilege (const char *privilege, BOOL enable)
@@ -371,7 +376,7 @@ set_process_privilege (const char *privilege, BOOL enable)
goto out;
}
/* AdjustTokenPrivileges returns TRUE even if the privilege could not
- be enabled. GetLastError() returns an correct error code, though. */
+ be enabled. GetLastError () returns an correct error code, though. */
if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED)
{
debug_printf ("Privilege %s couldn't be assigned", privilege);
@@ -385,6 +390,96 @@ out:
if (hToken)
CloseHandle (hToken);
- syscall_printf ("%d = set_process_privilege (%s, %d)",ret, privilege, enable);
+ syscall_printf ("%d = set_process_privilege (%s, %d)", ret, privilege, enable);
return ret;
}
+
+/*
+ * Function to return a common SECURITY_DESCRIPTOR * that
+ * allows all access.
+ */
+
+static NO_COPY SECURITY_DESCRIPTOR *null_sdp = 0;
+
+SECURITY_DESCRIPTOR *__stdcall
+get_null_sd ()
+{
+ static NO_COPY SECURITY_DESCRIPTOR sd;
+
+ if (null_sdp == 0)
+ {
+ InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
+ null_sdp = &sd;
+ }
+ return null_sdp;
+}
+
+BOOL
+sec_acl (PACL acl, BOOL admins, PSID sid1, PSID sid2)
+{
+ size_t acl_len = MAX_DACL_LEN(5);
+
+ if (!InitializeAcl (acl, acl_len, ACL_REVISION))
+ {
+ debug_printf ("InitializeAcl %E");
+ return FALSE;
+ }
+ if (sid2)
+ if (!AddAccessAllowedAce (acl, ACL_REVISION,
+ GENERIC_ALL, sid2))
+ debug_printf ("AddAccessAllowedAce(sid2) %E");
+ if (sid1)
+ if (!AddAccessAllowedAce (acl, ACL_REVISION,
+ GENERIC_ALL, sid1))
+ debug_printf ("AddAccessAllowedAce(sid1) %E");
+ if (admins)
+ if (!AddAccessAllowedAce (acl, ACL_REVISION,
+ GENERIC_ALL, well_known_admins_sid))
+ debug_printf ("AddAccessAllowedAce(admin) %E");
+ if (!AddAccessAllowedAce (acl, ACL_REVISION,
+ GENERIC_ALL, well_known_system_sid))
+ debug_printf ("AddAccessAllowedAce(system) %E");
+#if 0 /* Does not seem to help */
+ if (!AddAccessAllowedAce (acl, ACL_REVISION,
+ GENERIC_ALL, well_known_creator_owner_sid))
+ debug_printf ("AddAccessAllowedAce(creator_owner) %E");
+#endif
+ return TRUE;
+}
+
+PSECURITY_ATTRIBUTES __stdcall
+__sec_user (PVOID sa_buf, PSID sid2, BOOL inherit)
+{
+ PSECURITY_ATTRIBUTES psa = (PSECURITY_ATTRIBUTES) sa_buf;
+ PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)
+ ((char *) sa_buf + sizeof (*psa));
+ PACL acl = (PACL) ((char *) sa_buf + sizeof (*psa) + sizeof (*psd));
+
+ cygsid sid;
+
+ if (!(sid = cygheap->user.orig_sid ()) ||
+ (!sec_acl (acl, TRUE, sid, sid2)))
+ return inherit ? &sec_none : &sec_none_nih;
+
+ if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION))
+ debug_printf ("InitializeSecurityDescriptor %E");
+
+/*
+ * Setting the owner lets the created security attribute not work
+ * on NT4 SP3 Server. Don't know why, but the function still does
+ * what it should do also if the owner isn't set.
+*/
+#if 0
+ if (!SetSecurityDescriptorOwner (psd, sid, FALSE))
+ debug_printf ("SetSecurityDescriptorOwner %E");
+#endif
+
+ if (!SetSecurityDescriptorDacl (psd, TRUE, acl, FALSE))
+ debug_printf ("SetSecurityDescriptorDacl %E");
+
+ psa->nLength = sizeof (SECURITY_ATTRIBUTES);
+ psa->lpSecurityDescriptor = psd;
+ psa->bInheritHandle = inherit;
+ return psa;
+}
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index d4dd03c70..e9e8877a1 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -1,6 +1,6 @@
/* security.cc: NT security functions
- Copyright 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
@@ -28,30 +28,45 @@ details. */
#include <wininet.h>
#include <ntsecapi.h>
#include <subauth.h>
+#include <aclapi.h>
#include "cygerrno.h"
-#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "cygheap.h"
#include <ntdef.h>
#include "ntdll.h"
#include "lm.h"
-
extern BOOL allow_ntea;
-BOOL allow_ntsec;
+BOOL allow_ntsec = true;
/* allow_smbntsec is handled exclusively in path.cc (path_conv::check).
It's defined here because of it's strong relationship to allow_ntsec.
The default is TRUE to reflect the old behaviour. */
-BOOL allow_smbntsec = TRUE;
+BOOL allow_smbntsec;
+
+cygsid *
+cygsidlist::alloc_sids (int n)
+{
+ if (n > 0)
+ return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid));
+ else
+ return NULL;
+}
-extern "C"
void
+cygsidlist::free_sids ()
+{
+ if (sids)
+ cfree (sids);
+ sids = NULL;
+ count = maxcount = 0;
+ type = cygsidlist_empty;
+}
+
+extern "C" void
cygwin_set_impersonation_token (const HANDLE hToken)
{
debug_printf ("set_impersonation_token (%d)", hToken);
@@ -65,47 +80,37 @@ cygwin_set_impersonation_token (const HANDLE hToken)
void
extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
{
- cygsid psid;
- DWORD ulen = UNLEN + 1;
- DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- SID_NAME_USE use;
- char buf[INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 2];
- char *c;
+ char *d, *u, *c;
- strcpy (domain, "");
- strcpy (buf, pw->pw_name);
+ domain[0] = 0;
+ strlcpy (user, pw->pw_name, UNLEN + 1);
debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos);
- if (psid.getfrompw (pw) &&
- LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use))
- return;
-
- if (pw->pw_gecos)
- {
- if ((c = strstr (pw->pw_gecos, "U-")) != NULL &&
- (c == pw->pw_gecos || c[-1] == ','))
- {
- buf[0] = '\0';
- strncat (buf, c + 2, INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 1);
- if ((c = strchr (buf, ',')) != NULL)
- *c = '\0';
- }
- }
- if ((c = strchr (buf, '\\')) != NULL)
- {
- *c++ = '\0';
- strcpy (domain, buf);
- strcpy (user, c);
- }
- else
+ if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
+ (d == pw->pw_gecos || d[-1] == ','))
{
- strcpy (domain, "");
- strcpy (user, buf);
+ c = strchr (d + 2, ',');
+ if ((u = strchr (d + 2, '\\')) == NULL || (c != NULL && u > c))
+ u = d + 1;
+ else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2)
+ strlcpy (domain, d + 2, u - d - 1);
+ if (c == NULL)
+ c = u + UNLEN + 1;
+ if (c - u <= UNLEN + 1)
+ strlcpy (user, u + 1, c - u);
}
+ if (domain[0])
+ return;
+
+ cygsid psid;
+ DWORD ulen = UNLEN + 1;
+ DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ SID_NAME_USE use;
+ if (psid.getfrompw (pw))
+ LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use);
}
-extern "C"
-HANDLE
+extern "C" HANDLE
cygwin_logon_user (const struct passwd *pw, const char *password)
{
if (!wincap.has_security ())
@@ -126,9 +131,9 @@ cygwin_logon_user (const struct passwd *pw, const char *password)
extract_nt_dom_user (pw, nt_domain, nt_user);
debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
- LOGON32_LOGON_INTERACTIVE,
- LOGON32_PROVIDER_DEFAULT,
- &hToken)
+ LOGON32_LOGON_INTERACTIVE,
+ LOGON32_PROVIDER_DEFAULT,
+ &hToken)
|| !SetHandleInformation (hToken,
HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT))
@@ -154,18 +159,19 @@ str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
tgt.Length = strlen (srcstr);
tgt.MaximumLength = tgt.Length + 1;
tgt.Buffer = (PCHAR) buf;
- memcpy(buf, srcstr, tgt.MaximumLength);
+ memcpy (buf, srcstr, tgt.MaximumLength);
}
-static void
+void
str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
{
tgt.Length = strlen (srcstr) * sizeof (WCHAR);
- tgt.MaximumLength = tgt.Length + sizeof(WCHAR);
+ tgt.MaximumLength = tgt.Length + sizeof (WCHAR);
tgt.Buffer = (PWCHAR) buf;
sys_mbstowcs (buf, srcstr, tgt.MaximumLength);
}
+#if 0 /* unused */
static void
lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size)
{
@@ -176,6 +182,16 @@ lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size)
size >>= 1;
tgt[size] = 0;
}
+#endif
+
+static void
+lsa2str (char *tgt, LSA_UNICODE_STRING &src, int size)
+{
+ if (src.Length / 2 < size)
+ size = src.Length / 2;
+ sys_wcstombs (tgt, src.Buffer, size);
+ tgt[size] = 0;
+}
static LSA_HANDLE
open_local_policy ()
@@ -183,9 +199,9 @@ open_local_policy ()
LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
- NTSTATUS ret = LsaOpenPolicy(NULL, &oa, POLICY_ALL_ACCESS, &lsa);
+ NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
if (ret != STATUS_SUCCESS)
- set_errno (LsaNtStatusToWinError (ret));
+ __seterrno_from_win_error (LsaNtStatusToWinError (ret));
return lsa;
}
@@ -197,12 +213,12 @@ close_local_policy (LSA_HANDLE &lsa)
lsa = INVALID_HANDLE_VALUE;
}
+#if 0 /* unused */
static BOOL
get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain)
{
NET_API_STATUS ret;
- LPSERVER_INFO_101 buf;
- DWORD cnt, tot;
+ WCHAR *buf;
char name[INTERNET_MAX_HOST_NAME_LENGTH + 1];
WCHAR account[INTERNET_MAX_HOST_NAME_LENGTH + 1];
WCHAR primary[INTERNET_MAX_HOST_NAME_LENGTH + 1];
@@ -212,7 +228,7 @@ get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain)
if ((ret = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation,
(PVOID *) &adi)) != STATUS_SUCCESS)
{
- set_errno (LsaNtStatusToWinError(ret));
+ __seterrno_from_win_error (LsaNtStatusToWinError (ret));
return FALSE;
}
lsa2wchar (account, adi->DomainName, INTERNET_MAX_HOST_NAME_LENGTH + 1);
@@ -220,97 +236,111 @@ get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain)
if ((ret = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation,
(PVOID *) &pdi)) != STATUS_SUCCESS)
{
- set_errno (LsaNtStatusToWinError(ret));
+ __seterrno_from_win_error (LsaNtStatusToWinError (ret));
return FALSE;
}
lsa2wchar (primary, pdi->Name, INTERNET_MAX_HOST_NAME_LENGTH + 1);
LsaFreeMemory (pdi);
- if ((ret = NetServerEnum (NULL, 101, (LPBYTE *) &buf, MAX_PREFERRED_LENGTH,
- &cnt, &tot, SV_TYPE_DOMAIN_CTRL, primary, NULL))
- == STATUS_SUCCESS && cnt > 0)
- {
- sys_wcstombs (name, buf[0].sv101_name, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ /* If the SID given in the primary domain info is NULL, the machine is
+ not member of a domain. The name in the primary domain info is the
+ name of the workgroup then. */
+ if (pdi->Sid &&
+ (ret =
+ NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS)
+ {
+ sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ strcpy (logonserver, name);
if (domain)
sys_wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1);
}
else
{
sys_wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ strcpy (logonserver, "\\\\");
+ strcat (logonserver, name);
if (domain)
sys_wcstombs (domain, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
}
if (ret == STATUS_SUCCESS)
NetApiBufferFree (buf);
- strcpy (logonserver, "\\\\");
- strcat (logonserver, name);
return TRUE;
}
-
-static BOOL
-get_logon_server (LSA_HANDLE lsa, char *logonserver)
-{
- return get_lsa_srv_inf (lsa, logonserver, NULL);
-}
+#endif
BOOL
-get_logon_server_and_user_domain (char *logonserver, char *userdomain)
+get_logon_server (const char *domain, char *server, WCHAR *wserver)
{
- BOOL ret = FALSE;
- LSA_HANDLE lsa = open_local_policy ();
- if (lsa)
+ WCHAR wdomain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ NET_API_STATUS ret;
+ WCHAR *buf;
+ DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+
+ /* Empty domain is interpreted as local system */
+ if ((GetComputerName (server + 2, &size)) &&
+ (strcasematch (domain, server + 2) || !domain[0]))
{
- ret = get_lsa_srv_inf (lsa, logonserver, userdomain);
- close_local_policy (lsa);
+ server[0] = server[1] = '\\';
+ if (wserver)
+ sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ return TRUE;
}
- return ret;
+
+ /* Try to get the primary domain controller for the domain */
+ sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if ((ret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf)) == STATUS_SUCCESS)
+ {
+ sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if (wserver)
+ for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
+ ;
+ NetApiBufferFree (buf);
+ return TRUE;
+ }
+ __seterrno_from_win_error (ret);
+ return FALSE;
}
static BOOL
-get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user)
+get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
+ char *domain)
{
+ char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
WCHAR wuser[UNLEN + 1];
sys_mbstowcs (wuser, user, UNLEN + 1);
LPGROUP_USERS_INFO_0 buf;
- DWORD cnt, tot;
+ DWORD cnt, tot, len;
NET_API_STATUS ret;
+ /* Look only on logonserver */
ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
MAX_PREFERRED_LENGTH, &cnt, &tot);
- if (ret == ERROR_BAD_NETPATH || ret == RPC_S_SERVER_UNAVAILABLE)
- ret = NetUserGetGroups (NULL, wuser, 0, (LPBYTE *) &buf,
- MAX_PREFERRED_LENGTH, &cnt, &tot);
if (ret)
{
- debug_printf ("%d = NetUserGetGroups ()", ret);
- set_errno (ret);
+ __seterrno_from_win_error (ret);
/* It's no error when the user name can't be found. */
return ret == NERR_UserNotFound;
}
+ len = strlen (domain);
+ strcpy (dgroup, domain);
+ dgroup[len++] = '\\';
+
for (DWORD i = 0; i < cnt; ++i)
{
cygsid gsid;
- char group[UNLEN + 1];
+ DWORD glen = sizeof (gsid);
char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- DWORD glen = UNLEN + 1;
- DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ DWORD dlen = sizeof (domain);
SID_NAME_USE use = SidTypeInvalid;
- sys_wcstombs (group, buf[i].grui0_name, UNLEN + 1);
- if (!LookupAccountName (NULL, group, gsid, &glen, domain, &dlen, &use))
- debug_printf ("LookupAccountName(%s): %lu\n", group, GetLastError ());
- if (!legal_sid_type (use))
- {
- strcat (strcpy (group, domain), "\\");
- sys_wcstombs (group + strlen (group), buf[i].grui0_name,
- UNLEN + 1 - strlen (group));
- glen = UNLEN + 1;
- dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- if (!LookupAccountName(NULL, group, gsid, &glen, domain, &dlen, &use))
- debug_printf ("LookupAccountName(%s): %lu\n", group,GetLastError());
- }
- if (legal_sid_type (use))
+ sys_wcstombs (dgroup + len, buf[i].grui0_name, GNLEN + 1);
+ if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
+ debug_printf ("LookupAccountName(%s): %E", dgroup);
+ else if (legal_sid_type (use))
grp_list += gsid;
+ else
+ debug_printf ("Global group %s invalid. Domain: %s Use: %d",
+ dgroup, domain, use);
}
NetApiBufferFree (buf);
@@ -318,24 +348,21 @@ get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user)
}
static BOOL
-is_group_member (WCHAR *wlogonserver, WCHAR *wgroup,
- cygsid &usersid, cygsidlist &grp_list)
+is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
{
LPLOCALGROUP_MEMBERS_INFO_0 buf;
DWORD cnt, tot;
NET_API_STATUS ret;
BOOL retval = FALSE;
- ret = NetLocalGroupGetMembers (wlogonserver, wgroup, 0, (LPBYTE *) &buf,
+ /* Members can be users or global groups */
+ ret = NetLocalGroupGetMembers (NULL, wgroup, 0, (LPBYTE *) &buf,
MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
- if (ret == ERROR_BAD_NETPATH || ret == RPC_S_SERVER_UNAVAILABLE)
- ret = NetLocalGroupGetMembers (NULL, wgroup, 0, (LPBYTE *) &buf,
- MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
if (ret)
return FALSE;
for (DWORD bidx = 0; !retval && bidx < cnt; ++bidx)
- if (EqualSid (usersid, buf[bidx].lgrmi0_sid))
+ if (EqualSid (pusersid, buf[bidx].lgrmi0_sid))
retval = TRUE;
else
for (int glidx = 0; !retval && glidx < grp_list.count; ++glidx)
@@ -347,61 +374,55 @@ is_group_member (WCHAR *wlogonserver, WCHAR *wgroup,
}
static BOOL
-get_user_local_groups (WCHAR *wlogonserver, const char *logonserver,
- cygsidlist &grp_list, cygsid &usersid)
+get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
{
LPLOCALGROUP_INFO_0 buf;
DWORD cnt, tot;
NET_API_STATUS ret;
- ret = NetLocalGroupEnum (wlogonserver, 0, (LPBYTE *) &buf,
+ ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
- if (ret == ERROR_BAD_NETPATH || ret == RPC_S_SERVER_UNAVAILABLE)
- ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
- MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
if (ret)
{
- debug_printf ("%d = NetLocalGroupEnum ()", ret);
- set_errno (ret);
+ __seterrno_from_win_error (ret);
+ return FALSE;
+ }
+
+ char bgroup[sizeof ("BUILTIN\\") + GNLEN] = "BUILTIN\\";
+ char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
+ const DWORD blen = sizeof ("BUILTIN\\") - 1;
+ DWORD llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ if (!GetComputerNameA (lgroup, &llen))
+ {
+ __seterrno ();
return FALSE;
}
+ lgroup[llen++] = '\\';
for (DWORD i = 0; i < cnt; ++i)
- if (is_group_member (wlogonserver, buf[i].lgrpi0_name, usersid, grp_list))
+ if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
{
cygsid gsid;
- char group[UNLEN + 1];
+ DWORD glen = sizeof (gsid);
char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- DWORD glen = UNLEN + 1;
- DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ DWORD dlen = sizeof (domain);
SID_NAME_USE use = SidTypeInvalid;
- sys_wcstombs (group, buf[i].lgrpi0_name, UNLEN + 1);
- if (!LookupAccountName (NULL, group, gsid, &glen, domain, &dlen, &use))
+ sys_wcstombs (bgroup + blen, buf[i].lgrpi0_name, GNLEN + 1);
+ if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
{
- glen = UNLEN + 1;
- dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- if (!LookupAccountName (logonserver + 2, group,
- gsid, &glen, domain, &dlen, &use))
- debug_printf ("LookupAccountName(%s): %lu\n", group,
- GetLastError ());
- }
- else if (!legal_sid_type (use))
- {
- strcat (strcpy (group, domain), "\\");
- sys_wcstombs (group + strlen (group), buf[i].lgrpi0_name,
- UNLEN + 1 - strlen (group));
- glen = UNLEN + 1;
- dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- if (!LookupAccountName (NULL, group, gsid, &glen,
+ if (GetLastError () != ERROR_NONE_MAPPED)
+ debug_printf ("LookupAccountName(%s): %E", bgroup);
+ strcpy (lgroup + llen, bgroup + blen);
+ if (!LookupAccountName (NULL, lgroup, gsid, &glen,
domain, &dlen, &use))
- debug_printf ("LookupAccountName(%s): %lu\n", group,
- GetLastError ());
+ debug_printf ("LookupAccountName(%s): %E", lgroup);
}
- if (legal_sid_type (use))
+ if (!legal_sid_type (use))
+ debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
+ else if (!grp_list.contains (gsid))
grp_list += gsid;
}
-
NetApiBufferFree (buf);
return TRUE;
}
@@ -417,9 +438,10 @@ sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid)
return FALSE;
}
+#if 0 /* Unused */
static BOOL
get_user_primary_group (WCHAR *wlogonserver, const char *user,
- cygsid &usersid, cygsid &pgrpsid)
+ PSID pusersid, cygsid &pgrpsid)
{
LPUSER_INFO_3 buf;
WCHAR wuser[UNLEN + 1];
@@ -427,7 +449,7 @@ get_user_primary_group (WCHAR *wlogonserver, const char *user,
BOOL retval = FALSE;
UCHAR count = 0;
- if (usersid == well_known_system_sid)
+ if (pusersid == well_known_system_sid)
{
pgrpsid = well_known_system_sid;
return TRUE;
@@ -435,17 +457,15 @@ get_user_primary_group (WCHAR *wlogonserver, const char *user,
sys_mbstowcs (wuser, user, UNLEN + 1);
ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf);
- if (ret == ERROR_BAD_NETPATH || ret == RPC_S_SERVER_UNAVAILABLE)
- ret = NetUserGetInfo (NULL, wuser, 3, (LPBYTE *) &buf);
if (ret)
{
- debug_printf ("%d = NetUserGetInfo ()", ret);
- set_errno (ret);
+ __seterrno_from_win_error (ret);
return FALSE;
}
- pgrpsid = usersid;
- if (IsValidSid (pgrpsid) && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1)
+ pgrpsid = pusersid;
+ if (IsValidSid (pgrpsid)
+ && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1)
{
*GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id;
retval = TRUE;
@@ -453,76 +473,114 @@ get_user_primary_group (WCHAR *wlogonserver, const char *user,
NetApiBufferFree (buf);
return retval;
}
+#endif
-static BOOL
-get_group_sidlist (const char *logonserver, cygsidlist &grp_list,
- cygsid &usersid, cygsid &pgrpsid,
- PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
+static void
+get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
{
- WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- char user[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- DWORD ulen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- SID_NAME_USE use;
+ struct __group32 *gr;
+ cygsid gsid;
+
+ for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+ {
+ if (gr->gr_gid == (__gid32_t) pw->pw_gid)
+ goto found;
+ else if (gr->gr_mem)
+ for (int gi = 0; gr->gr_mem[gi]; ++gi)
+ if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
+ goto found;
+ continue;
+ found:
+ if (gsid.getfromgr (gr) && !grp_list.contains (gsid))
+ grp_list += gsid;
+ }
+}
+
+static void
+get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
+ LUID auth_luid, int &auth_pos)
+{
auth_pos = -1;
- sys_mbstowcs (wserver, logonserver, INTERNET_MAX_HOST_NAME_LENGTH + 1);
- if (!LookupAccountSid (NULL, usersid, user, &ulen, domain, &dlen, &use))
+ if (my_grps)
{
- debug_printf ("LookupAccountSid () %E");
- __seterrno ();
- return FALSE;
+ if (sid_in_token_groups (my_grps, well_known_local_sid))
+ grp_list += well_known_local_sid;
+ if (sid_in_token_groups (my_grps, well_known_dialup_sid))
+ grp_list += well_known_dialup_sid;
+ if (sid_in_token_groups (my_grps, well_known_network_sid))
+ grp_list += well_known_network_sid;
+ if (sid_in_token_groups (my_grps, well_known_batch_sid))
+ grp_list += well_known_batch_sid;
+ if (sid_in_token_groups (my_grps, well_known_interactive_sid))
+ grp_list += well_known_interactive_sid;
+ if (sid_in_token_groups (my_grps, well_known_service_sid))
+ grp_list += well_known_service_sid;
+ }
+ else
+ {
+ grp_list += well_known_local_sid;
+ grp_list += well_known_interactive_sid;
}
+ if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
+ {
+ char buf[64];
+ __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
+ auth_luid.LowPart);
+ grp_list += buf;
+ auth_pos = grp_list.count - 1;
+ }
+}
+
+static BOOL
+get_initgroups_sidlist (cygsidlist &grp_list,
+ PSID usersid, PSID pgrpsid, struct passwd *pw,
+ PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos,
+ BOOL &special_pgrp)
+{
grp_list += well_known_world_sid;
+ grp_list += well_known_authenticated_users_sid;
if (usersid == well_known_system_sid)
{
- grp_list += well_known_system_sid;
+ auth_pos = -1;
grp_list += well_known_admins_sid;
+ get_unix_group_sidlist (pw, grp_list);
}
else
{
- if (my_grps)
- {
- if (sid_in_token_groups (my_grps, well_known_local_sid))
- grp_list += well_known_local_sid;
- if (sid_in_token_groups (my_grps, well_known_dialup_sid))
- grp_list += well_known_dialup_sid;
- if (sid_in_token_groups (my_grps, well_known_network_sid))
- grp_list += well_known_network_sid;
- if (sid_in_token_groups (my_grps, well_known_batch_sid))
- grp_list += well_known_batch_sid;
- if (sid_in_token_groups (my_grps, well_known_interactive_sid))
- grp_list += well_known_interactive_sid;
- if (sid_in_token_groups (my_grps, well_known_service_sid))
- grp_list += well_known_service_sid;
- grp_list += well_known_authenticated_users_sid;
- }
- else
- {
- grp_list += well_known_local_sid;
- grp_list += well_known_interactive_sid;
- grp_list += well_known_authenticated_users_sid;
- }
- if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
- {
- char buf[64];
- __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
- auth_luid.LowPart);
- grp_list += buf;
- auth_pos = grp_list.count - 1;
- }
- }
- if (!pgrpsid)
- get_user_primary_group (wserver, user, usersid, pgrpsid);
- if (!get_user_groups (wserver, grp_list, user) ||
- !get_user_local_groups (wserver, logonserver, grp_list, usersid))
- return FALSE;
- if (!grp_list.contains (pgrpsid))
+ char user[UNLEN + 1];
+ char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+ char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+
+ get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
+ extract_nt_dom_user (pw, domain, user);
+ if (get_logon_server (domain, server, wserver))
+ get_user_groups (wserver, grp_list, user, domain);
+ get_unix_group_sidlist (pw, grp_list);
+ if (!get_user_local_groups (grp_list, usersid))
+ return FALSE;
+ }
+ /* special_pgrp true if pgrpsid is not in normal groups */
+ if ((special_pgrp = !grp_list.contains (pgrpsid)))
grp_list += pgrpsid;
return TRUE;
}
+static void
+get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps,
+ user_groups &groups, LUID auth_luid, int &auth_pos)
+{
+ PSID pgpsid = groups.pgsid;
+ tmp_list += well_known_world_sid;
+ tmp_list += well_known_authenticated_users_sid;
+ get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
+ for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
+ tmp_list += groups.sgsids.sids[gidx];
+ if (!groups.sgsids.contains (pgpsid))
+ tmp_list += pgpsid;
+}
+
static const char *sys_privs[] = {
SE_TCB_NAME,
SE_ASSIGNPRIMARYTOKEN_NAME,
@@ -551,8 +609,8 @@ PTOKEN_PRIVILEGES
get_system_priv_list (cygsidlist &grp_list)
{
LUID priv;
- PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (sizeof (ULONG) +
- 20 * sizeof (LUID_AND_ATTRIBUTES));
+ PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES)
+ malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES));
if (!privs)
{
debug_printf ("malloc (system_privs) failed.");
@@ -565,7 +623,7 @@ get_system_priv_list (cygsidlist &grp_list)
{
privs->Privileges[privs->PrivilegeCount].Luid = priv;
privs->Privileges[privs->PrivilegeCount].Attributes =
- SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
+ SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
++privs->PrivilegeCount;
}
return privs;
@@ -587,8 +645,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
{
if (grp == -1)
{
- if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt))
- != STATUS_SUCCESS)
+ if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
+ &cnt)) != STATUS_SUCCESS)
continue;
}
else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
@@ -601,8 +659,7 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
PTOKEN_PRIVILEGES tmp;
DWORD tmp_count;
- sys_wcstombs (buf, privstrs[i].Buffer,
- INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ lsa2str (buf, privstrs[i], sizeof (buf) - 1);
if (!LookupPrivilegeValue (NULL, buf, &priv))
continue;
@@ -612,8 +669,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
tmp_count = privs ? privs->PrivilegeCount : 0;
tmp = (PTOKEN_PRIVILEGES)
- realloc (privs, sizeof (ULONG) +
- (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES));
+ realloc (privs, sizeof (ULONG) +
+ (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES));
if (!tmp)
{
if (privs)
@@ -626,7 +683,7 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
privs = tmp;
privs->Privileges[privs->PrivilegeCount].Luid = priv;
privs->Privileges[privs->PrivilegeCount].Attributes =
- SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
+ SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
++privs->PrivilegeCount;
next_account_right:
@@ -637,76 +694,150 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
return privs;
}
-#define token_acl_size (sizeof (ACL) + \
- 2 * (sizeof (ACCESS_ALLOWED_ACE) + MAX_SID_LEN))
-
-static BOOL
-get_dacl (PACL acl, cygsid usersid, cygsidlist &grp_list)
+/* Accept a token if
+ - the requested usersid matches the TokenUser and
+ - if setgroups has been called:
+ the token groups that are listed in /etc/group match the union of
+ the requested primary and supplementary groups in gsids.
+ - else the (unknown) implicitly requested supplementary groups and those
+ in the token are the groups associated with the usersid. We assume
+ they match and verify only the primary groups.
+ The requested primary group must appear in the token.
+ The primary group in the token is a group associated with the usersid,
+ except if the token is internal and the group is in the token SD
+ (see create_token). In that latter case that group must match the
+ requested primary group. */
+BOOL
+verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern)
{
- if (!InitializeAcl(acl, token_acl_size, ACL_REVISION))
+ DWORD size;
+ BOOL intern = FALSE;
+
+ if (pintern)
{
- __seterrno ();
- return FALSE;
- }
- if (grp_list.contains (well_known_admins_sid))
+ TOKEN_SOURCE ts;
+ if (!GetTokenInformation (cygheap->user.token, TokenSource,
+ &ts, sizeof ts, &size))
+ debug_printf ("GetTokenInformation(): %E");
+ else
+ *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
+ }
+ /* Verify usersid */
+ cygsid tok_usersid = NO_SID;
+ if (!GetTokenInformation (token, TokenUser,
+ &tok_usersid, sizeof tok_usersid, &size))
+ debug_printf ("GetTokenInformation(): %E");
+ if (usersid != tok_usersid)
+ return FALSE;
+
+ /* For an internal token, if setgroups was not called and if the sd group
+ is not well_known_null_sid, it must match pgrpsid */
+ if (intern && !groups.issetgroups ())
{
- if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL,
- well_known_admins_sid))
- {
- __seterrno ();
- return FALSE;
- }
+ char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)];
+ PSID gsid = NO_SID;
+ if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
+ (PSECURITY_DESCRIPTOR) sd_buf,
+ sizeof sd_buf, &size))
+ debug_printf ("GetKernelObjectSecurity(): %E");
+ else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf,
+ &gsid, (BOOL *) &size))
+ debug_printf ("GetSecurityDescriptorGroup(): %E");
+ if (well_known_null_sid != gsid)
+ return gsid == groups.pgsid;
}
- else if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL, usersid))
+
+ PTOKEN_GROUPS my_grps = NULL;
+ BOOL ret = FALSE;
+ char saw_buf[NGROUPS_MAX] = {};
+ char *saw = saw_buf, sawpg = FALSE;
+
+ if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
+ GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ debug_printf ("GetTokenInformation(token, TokenGroups): %E\n");
+ else if (!(my_grps = (PTOKEN_GROUPS) malloc (size)))
+ debug_printf ("malloc (my_grps) failed.");
+ else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
+ debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
+ else if (!groups.issetgroups ()) /* setgroups was never called */
{
- __seterrno ();
- return FALSE;
+ ret = sid_in_token_groups (my_grps, groups.pgsid);
+ if (ret == FALSE)
+ ret = (groups.pgsid == tok_usersid);
}
- if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL,
- well_known_system_sid))
+ else /* setgroups was called */
{
- __seterrno ();
- return FALSE;
- }
- return TRUE;
+ struct __group32 *gr;
+ cygsid gsid;
+ if (groups.sgsids.count > (int) sizeof (saw_buf) &&
+ !(saw = (char *) calloc (groups.sgsids.count, sizeof (char))))
+ goto done;
+
+ /* token groups found in /etc/group match the user.gsids ? */
+ for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+ if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
+ {
+ int pos = groups.sgsids.position (gsid);
+ if (pos >= 0)
+ saw[pos] = TRUE;
+ else if (groups.pgsid == gsid)
+ sawpg = TRUE;
+ else if (gsid != well_known_world_sid &&
+ gsid != usersid)
+ goto done;
+ }
+ for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
+ if (!saw[gidx])
+ goto done;
+ if (sawpg ||
+ groups.sgsids.contains (groups.pgsid) ||
+ groups.pgsid == usersid)
+ ret = TRUE;
+ }
+done:
+ if (my_grps)
+ free (my_grps);
+ if (saw != saw_buf)
+ free (saw);
+ return ret;
}
HANDLE
-create_token (cygsid &usersid, cygsid &pgrpsid)
+create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
{
NTSTATUS ret;
- LSA_HANDLE lsa = NULL;
- char logonserver[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
int old_priv_state;
- cygsidlist grpsids;
+ cygsidlist tmp_gsids (cygsidlist_auto, 12);
SECURITY_QUALITY_OF_SERVICE sqos =
{ sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
- OBJECT_ATTRIBUTES oa =
- { sizeof oa, 0, 0, 0, 0, &sqos };
- SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
+ OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
+ PSECURITY_ATTRIBUTES psa;
+ BOOL special_pgrp = FALSE;
+ char sa_buf[1024];
LUID auth_luid = SYSTEM_LUID;
- LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL };
+ LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL };
TOKEN_USER user;
- PTOKEN_GROUPS grps = NULL;
+ PTOKEN_GROUPS new_tok_gsids = NULL;
PTOKEN_PRIVILEGES privs = NULL;
TOKEN_OWNER owner;
TOKEN_PRIMARY_GROUP pgrp;
- char acl_buf[token_acl_size];
+ char acl_buf[MAX_DACL_LEN (5)];
TOKEN_DEFAULT_DACL dacl;
TOKEN_SOURCE source;
TOKEN_STATISTICS stats;
- memcpy(source.SourceName, "Cygwin.1", 8);
+ memcpy (source.SourceName, "Cygwin.1", 8);
source.SourceIdentifier.HighPart = 0;
source.SourceIdentifier.LowPart = 0x0101;
- HANDLE token;
+ HANDLE token = INVALID_HANDLE_VALUE;
HANDLE primary_token = INVALID_HANDLE_VALUE;
HANDLE my_token = INVALID_HANDLE_VALUE;
- PTOKEN_GROUPS my_grps = NULL;
+ PTOKEN_GROUPS my_tok_gsids = NULL;
DWORD size;
/* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
@@ -717,17 +848,13 @@ create_token (cygsid &usersid, cygsid &pgrpsid)
if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
goto out;
- /* Get logon server. */
- if (!get_logon_server (lsa, logonserver))
- goto out;
-
/* User, owner, primary group. */
user.User.Sid = usersid;
user.User.Attributes = 0;
owner.Owner = usersid;
/* Retrieve authentication id and group list from own process. */
- if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &my_token))
+ if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &my_token))
debug_printf ("OpenProcessToken(my_token): %E\n");
else
{
@@ -736,7 +863,8 @@ create_token (cygsid &usersid, cygsid &pgrpsid)
if (usersid != well_known_system_sid)
if (!GetTokenInformation (my_token, TokenStatistics,
&stats, sizeof stats, &size))
- debug_printf ("GetTokenInformation(my_token, TokenStatistics): %E\n");
+ debug_printf
+ ("GetTokenInformation(my_token, TokenStatistics): %E\n");
else
auth_luid = stats.AuthenticationId;
@@ -745,66 +873,85 @@ create_token (cygsid &usersid, cygsid &pgrpsid)
if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) &&
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
- else if (!(my_grps = (PTOKEN_GROUPS) malloc (size)))
- debug_printf ("malloc (my_grps) failed.");
- else if (!GetTokenInformation (my_token, TokenGroups, my_grps,
+ else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
+ debug_printf ("malloc (my_tok_gsids) failed.");
+ else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids,
size, &size))
{
debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
- free (my_grps);
- my_grps = NULL;
+ free (my_tok_gsids);
+ my_tok_gsids = NULL;
}
+ CloseHandle (my_token);
}
/* Create list of groups, the user is member in. */
int auth_pos;
- if (!get_group_sidlist (logonserver, grpsids, usersid, pgrpsid,
- my_grps, auth_luid, auth_pos))
+ if (new_groups.issetgroups ())
+ get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid,
+ auth_pos);
+ else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
+ my_tok_gsids, auth_luid, auth_pos,
+ special_pgrp))
goto out;
/* Primary group. */
- pgrp.PrimaryGroup = pgrpsid;
+ pgrp.PrimaryGroup = new_groups.pgsid;
/* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
- char grps_buf[sizeof (ULONG) + grpsids.count * sizeof (SID_AND_ATTRIBUTES)];
- grps = (PTOKEN_GROUPS) grps_buf;
- grps->GroupCount = grpsids.count;
- for (DWORD i = 0; i < grps->GroupCount; ++i)
+ char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)];
+ new_tok_gsids = (PTOKEN_GROUPS) grps_buf;
+ new_tok_gsids->GroupCount = tmp_gsids.count;
+ for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
{
- grps->Groups[i].Sid = grpsids.sids[i];
- grps->Groups[i].Attributes = SE_GROUP_MANDATORY |
- SE_GROUP_ENABLED_BY_DEFAULT |
- SE_GROUP_ENABLED;
- if (auth_pos >= 0 && i == (DWORD) auth_pos)
- grps->Groups[i].Attributes |= SE_GROUP_LOGON_ID;
+ new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
+ new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY |
+ SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
}
+ if (auth_pos >= 0)
+ new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
/* Retrieve list of privileges of that user. */
- if (!(privs = get_priv_list (lsa, usersid, grpsids)))
+ if (!(privs = get_priv_list (lsa, usersid, tmp_gsids)))
goto out;
/* Create default dacl. */
- if (!get_dacl ((PACL) acl_buf, usersid, grpsids))
+ if (!sec_acl ((PACL) acl_buf, FALSE,
+ tmp_gsids.contains (well_known_admins_sid) ?
+ well_known_admins_sid : usersid))
goto out;
dacl.DefaultDacl = (PACL) acl_buf;
/* Let's be heroic... */
ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
- &auth_luid, &exp, &user, grps, privs, &owner, &pgrp,
- &dacl, &source);
+ &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
+ &pgrp, &dacl, &source);
if (ret)
- set_errno (RtlNtStatusToDosError (ret));
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
else if (GetLastError () == ERROR_PROC_NOT_FOUND)
{
__seterrno ();
debug_printf ("Loading NtCreateToken failed.");
}
-
- /* Convert to primary token. */
- if (!DuplicateTokenEx (token, TOKEN_ALL_ACCESS, &sa,
- SecurityImpersonation, TokenPrimary,
- &primary_token))
- __seterrno ();
+ else
+ {
+ /* Set security descriptor and primary group */
+ psa = __sec_user (sa_buf, usersid, TRUE);
+ if (psa->lpSecurityDescriptor &&
+ !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR)
+ psa->lpSecurityDescriptor,
+ special_pgrp ? new_groups.pgsid
+ : well_known_null_sid,
+ FALSE))
+ debug_printf ("SetSecurityDescriptorGroup %E");
+ /* Convert to primary token. */
+ if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation,
+ TokenPrimary, &primary_token))
+ {
+ __seterrno ();
+ debug_printf ("DuplicateTokenEx %E");
+ }
+ }
out:
if (old_priv_state >= 0)
@@ -813,8 +960,8 @@ out:
CloseHandle (token);
if (privs)
free (privs);
- if (my_grps)
- free (my_grps);
+ if (my_tok_gsids)
+ free (my_tok_gsids);
close_local_policy (lsa);
debug_printf ("%d = create_token ()", primary_token);
@@ -854,17 +1001,17 @@ subauth (struct passwd *pw)
HANDLE primary_token = INVALID_HANDLE_VALUE;
int old_tcb_state;
- if ((old_tcb_state = set_process_privilege(SE_TCB_NAME)) < 0)
+ if ((old_tcb_state = set_process_privilege (SE_TCB_NAME)) < 0)
return INVALID_HANDLE_VALUE;
/* Register as logon process. */
str2lsa (name, "Cygwin");
SetLastError (0);
- ret = LsaRegisterLogonProcess(&name, &lsa_hdl, &sec_mode);
+ ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
if (ret != STATUS_SUCCESS)
{
debug_printf ("LsaRegisterLogonProcess: %d", ret);
- set_errno (LsaNtStatusToWinError(ret));
+ __seterrno_from_win_error (LsaNtStatusToWinError (ret));
goto out;
}
else if (GetLastError () == ERROR_PROC_NOT_FOUND)
@@ -874,52 +1021,51 @@ subauth (struct passwd *pw)
}
/* Get handle to MSV1_0 package. */
str2lsa (name, MSV1_0_PACKAGE_NAME);
- ret = LsaLookupAuthenticationPackage(lsa_hdl, &name, &package_id);
+ ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
if (ret != STATUS_SUCCESS)
{
debug_printf ("LsaLookupAuthenticationPackage: %d", ret);
- set_errno (LsaNtStatusToWinError(ret));
- LsaDeregisterLogonProcess(lsa_hdl);
+ __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+ LsaDeregisterLogonProcess (lsa_hdl);
goto out;
}
/* Create origin. */
str2buf2lsa (origin.str, origin.buf, "Cygwin");
/* Create token source. */
- memcpy(ts.SourceName, "Cygwin.1", 8);
+ memcpy (ts.SourceName, "Cygwin.1", 8);
ts.SourceIdentifier.HighPart = 0;
ts.SourceIdentifier.LowPart = 0x0100;
/* Get user information. */
extract_nt_dom_user (pw, nt_domain, nt_user);
/* Fill subauth with values. */
subbuf.auth.MessageType = MsV1_0NetworkLogon;
- str2buf2uni(subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain);
- str2buf2uni(subbuf.auth.UserName, subbuf.usrbuf, nt_user);
- str2buf2uni(subbuf.auth.Workstation, subbuf.wkstbuf, "");
- memcpy(subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH);
- str2buf2lsa(subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, "");
- str2buf2lsa(subbuf.auth.CaseInsensitiveChallengeResponse, subbuf.authinf2,"");
+ str2buf2uni (subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain);
+ str2buf2uni (subbuf.auth.UserName, subbuf.usrbuf, nt_user);
+ str2buf2uni (subbuf.auth.Workstation, subbuf.wkstbuf, "");
+ memcpy (subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH);
+ str2buf2lsa (subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, "");
+ str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse,subbuf.authinf2,"");
subbuf.auth.ParameterControl = 0 | (subauth_id << 24);
/* Try to logon... */
- ret = LsaLogonUser(lsa_hdl, (PLSA_STRING) &origin, Network,
- package_id, &subbuf, sizeof subbuf,
- NULL, &ts, (PVOID *)&profile, &size,
- &luid, &user_token, &quota, &ret2);
+ ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Network,
+ package_id, &subbuf, sizeof subbuf,
+ NULL, &ts, (PVOID *) &profile, &size,
+ &luid, &user_token, &quota, &ret2);
if (ret != STATUS_SUCCESS)
{
debug_printf ("LsaLogonUser: %d", ret);
- set_errno (LsaNtStatusToWinError(ret));
- LsaDeregisterLogonProcess(lsa_hdl);
+ __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+ LsaDeregisterLogonProcess (lsa_hdl);
goto out;
}
- LsaFreeReturnBuffer(profile);
+ LsaFreeReturnBuffer (profile);
/* Convert to primary token. */
if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa,
- SecurityImpersonation, TokenPrimary,
- &primary_token))
+ SecurityImpersonation, TokenPrimary, &primary_token))
__seterrno ();
out:
- set_process_privilege(SE_TCB_NAME, old_tcb_state);
+ set_process_privilege (SE_TCB_NAME, old_tcb_state);
if (user_token != INVALID_HANDLE_VALUE)
CloseHandle (user_token);
return primary_token;
@@ -942,7 +1088,7 @@ out:
*/
LONG
-read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size)
+read_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size)
{
/* Check parameters */
if (!sd_size)
@@ -951,29 +1097,29 @@ read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size)
return -1;
}
- debug_printf("file = %s", file);
+ debug_printf ("file = %s", file);
DWORD len = 0;
const char *pfile = file;
- char fbuf [PATH_MAX];
+ char fbuf[PATH_MAX];
if (current_codepage == oem_cp)
{
DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file));
bzero (fbuf, sizeof (fbuf));
- OemToCharBuff(file, fbuf, fname_len);
+ OemToCharBuff (file, fbuf, fname_len);
pfile = fbuf;
}
if (!GetFileSecurity (pfile,
OWNER_SECURITY_INFORMATION
- | GROUP_SECURITY_INFORMATION
- | DACL_SECURITY_INFORMATION,
- sd_buf, *sd_size, &len))
+ | GROUP_SECURITY_INFORMATION
+ | DACL_SECURITY_INFORMATION,
+ sd_buf, *sd_size, &len))
{
__seterrno ();
return -1;
}
- debug_printf("file = %s: len=%d", file, len);
+ debug_printf ("file = %s: len=%d", file, len);
if (len > *sd_size)
{
*sd_size = len;
@@ -983,7 +1129,7 @@ read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size)
}
LONG
-write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size)
+write_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size)
{
/* Check parameters */
if (!sd_buf || !sd_size)
@@ -1059,69 +1205,10 @@ write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size)
return 0;
}
-static int
-get_nt_attribute (const char *file, int *attribute,
- uid_t *uidret, gid_t *gidret)
+static void
+get_attribute_from_acl (int * attribute, PACL acl, PSID owner_sid,
+ PSID group_sid, BOOL grp_member)
{
- if (!wincap.has_security ())
- return 0;
-
- syscall_printf ("file: %s", file);
-
- /* Yeah, sounds too much, but I've seen SDs of 2100 bytes!*/
- DWORD sd_size = 4096;
- char sd_buf[4096];
- PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
-
- int ret;
- if ((ret = read_sd (file, psd, &sd_size)) <= 0)
- {
- debug_printf ("read_sd %E");
- return ret;
- }
-
- PSID owner_sid;
- PSID group_sid;
- BOOL dummy;
-
- if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy))
- debug_printf ("GetSecurityDescriptorOwner %E");
- if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy))
- debug_printf ("GetSecurityDescriptorGroup %E");
-
- PACL acl;
- BOOL acl_exists;
-
- if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy))
- {
- __seterrno ();
- debug_printf ("GetSecurityDescriptorDacl %E");
- return -1;
- }
-
- uid_t uid = cygsid(owner_sid).get_uid ();
- gid_t gid = cygsid(group_sid).get_gid ();
- if (uidret)
- *uidret = uid;
- if (gidret)
- *gidret = gid;
-
- if (!attribute)
- {
- syscall_printf ("file: %s uid %d, gid %d", file, uid, gid);
- return 0;
- }
-
- BOOL grp_member = is_grp_member (uid, gid);
-
- if (!acl_exists || !acl)
- {
- *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
- syscall_printf ("file: %s No ACL = %x, uid %d, gid %d",
- file, *attribute, uid, gid);
- return 0;
- }
-
ACCESS_ALLOWED_ACE *ace;
int allow = 0;
int deny = 0;
@@ -1131,7 +1218,7 @@ get_nt_attribute (const char *file, int *attribute,
{
if (!GetAce (acl, i, (PVOID *) &ace))
continue;
- if (ace->Header.AceFlags & INHERIT_ONLY_ACE)
+ if (ace->Header.AceFlags & INHERIT_ONLY)
continue;
switch (ace->Header.AceType)
{
@@ -1148,28 +1235,7 @@ get_nt_attribute (const char *file, int *attribute,
}
cygsid ace_sid ((PSID) &ace->SidStart);
- if (owner_sid && ace_sid == owner_sid)
- {
- if (ace->Mask & FILE_READ_DATA)
- *flags |= S_IRUSR;
- if (ace->Mask & FILE_WRITE_DATA)
- *flags |= S_IWUSR;
- if (ace->Mask & FILE_EXECUTE)
- *flags |= S_IXUSR;
- }
- else if (group_sid && ace_sid == group_sid)
- {
- if (ace->Mask & FILE_READ_DATA)
- *flags |= S_IRGRP
- | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0);
- if (ace->Mask & FILE_WRITE_DATA)
- *flags |= S_IWGRP
- | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0);
- if (ace->Mask & FILE_EXECUTE)
- *flags |= S_IXGRP
- | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
- }
- else if (ace_sid == well_known_world_sid)
+ if (ace_sid == well_known_world_sid)
{
if (ace->Mask & FILE_READ_DATA)
*flags |= S_IROTH
@@ -1200,17 +1266,105 @@ get_nt_attribute (const char *file, int *attribute,
if (ace->Mask & FILE_APPEND_DATA)
*flags |= S_ISUID;
}
+ else if (owner_sid && ace_sid == owner_sid)
+ {
+ if (ace->Mask & FILE_READ_DATA)
+ *flags |= S_IRUSR;
+ if (ace->Mask & FILE_WRITE_DATA)
+ *flags |= S_IWUSR;
+ if (ace->Mask & FILE_EXECUTE)
+ *flags |= S_IXUSR;
+ }
+ else if (group_sid && ace_sid == group_sid)
+ {
+ if (ace->Mask & FILE_READ_DATA)
+ *flags |= S_IRGRP
+ | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0);
+ if (ace->Mask & FILE_WRITE_DATA)
+ *flags |= S_IWGRP
+ | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0);
+ if (ace->Mask & FILE_EXECUTE)
+ *flags |= S_IXGRP
+ | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
+ }
}
*attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID);
*attribute |= allow;
*attribute &= ~deny;
+ return;
+}
+
+static int
+get_nt_attribute (const char *file, int *attribute,
+ __uid32_t *uidret, __gid32_t *gidret)
+{
+ if (!wincap.has_security ())
+ return 0;
+
+ syscall_printf ("file: %s", file);
+
+ /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */
+ DWORD sd_size = 4096;
+ char sd_buf[4096];
+ PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
+
+ int ret;
+ if ((ret = read_sd (file, psd, &sd_size)) <= 0)
+ {
+ debug_printf ("read_sd %E");
+ return ret;
+ }
+
+ PSID owner_sid;
+ PSID group_sid;
+ BOOL dummy;
+
+ if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy))
+ debug_printf ("GetSecurityDescriptorOwner %E");
+ if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy))
+ debug_printf ("GetSecurityDescriptorGroup %E");
+
+ PACL acl;
+ BOOL acl_exists;
+
+ if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy))
+ {
+ __seterrno ();
+ debug_printf ("GetSecurityDescriptorDacl %E");
+ return -1;
+ }
+
+ __uid32_t uid = cygsid (owner_sid).get_uid ();
+ __gid32_t gid = cygsid (group_sid).get_gid ();
+ if (uidret)
+ *uidret = uid;
+ if (gidret)
+ *gidret = gid;
+
+ if (!attribute)
+ {
+ syscall_printf ("file: %s uid %d, gid %d", file, uid, gid);
+ return 0;
+ }
+
+ BOOL grp_member = is_grp_member (uid, gid);
+
+ if (!acl_exists || !acl)
+ {
+ *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+ syscall_printf ("file: %s No ACL = %x, uid %d, gid %d",
+ file, *attribute, uid, gid);
+ return 0;
+ }
+ get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member);
+
syscall_printf ("file: %s %x, uid %d, gid %d", file, *attribute, uid, gid);
return 0;
}
int
get_file_attribute (int use_ntsec, const char *file,
- int *attribute, uid_t *uidret, gid_t *gidret)
+ int *attribute, __uid32_t *uidret, __gid32_t *gidret)
{
int res;
@@ -1223,9 +1377,9 @@ get_file_attribute (int use_ntsec, const char *file,
}
if (uidret)
- *uidret = getuid ();
+ *uidret = getuid32 ();
if (gidret)
- *gidret = getgid ();
+ *gidret = getgid32 ();
if (!attribute)
return 0;
@@ -1233,19 +1387,103 @@ get_file_attribute (int use_ntsec, const char *file,
if (allow_ntea)
{
int oatt = *attribute;
- res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute));
+ res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof (*attribute));
*attribute |= oatt;
}
else
res = 0;
- /* symlinks are everything for everyone!*/
+ /* symlinks are everything for everyone! */
if ((*attribute & S_IFLNK) == S_IFLNK)
*attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
return res > 0 ? 0 : -1;
}
+static int
+get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
+ int *attribute, __uid32_t *uidret, __gid32_t *gidret)
+{
+ if (!wincap.has_security ())
+ return 0;
+
+ PSECURITY_DESCRIPTOR psd = NULL;
+ PSID owner_sid;
+ PSID group_sid;
+ PACL acl;
+
+ if (ERROR_SUCCESS != GetSecurityInfo (handle, object_type,
+ DACL_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION,
+ &owner_sid, &group_sid,
+ &acl, NULL, &psd))
+ {
+ __seterrno ();
+ debug_printf ("GetSecurityInfo %E");
+ return -1;
+ }
+
+ __uid32_t uid = cygsid (owner_sid).get_uid ();
+ __gid32_t gid = cygsid (group_sid).get_gid ();
+ if (uidret)
+ *uidret = uid;
+ if (gidret)
+ *gidret = gid;
+
+ if (!attribute)
+ {
+ syscall_printf ("uid %d, gid %d", uid, gid);
+ LocalFree (psd);
+ return 0;
+ }
+
+ BOOL grp_member = is_grp_member (uid, gid);
+
+ if (!acl)
+ {
+ *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+ syscall_printf ("No ACL = %x, uid %d, gid %d", *attribute, uid, gid);
+ LocalFree (psd);
+ return 0;
+ }
+
+ get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member);
+
+ LocalFree (psd);
+
+ syscall_printf ("%x, uid %d, gid %d", *attribute, uid, gid);
+ return 0;
+}
+
+int
+get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
+ int *attribute, __uid32_t *uidret, __gid32_t *gidret)
+{
+ if (allow_ntsec)
+ {
+ int res = get_nt_object_attribute (handle, object_type, attribute,
+ uidret, gidret);
+ if (attribute && (*attribute & S_IFLNK) == S_IFLNK)
+ *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+ return res;
+ }
+
+ if (uidret)
+ *uidret = getuid32 ();
+ if (gidret)
+ *gidret = getgid32 ();
+
+ if (!attribute)
+ return 0;
+
+ /* symlinks are everything for everyone! */
+ if ((*attribute & S_IFLNK) == S_IFLNK)
+ *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+
+ return 0;
+}
+
BOOL
add_access_allowed_ace (PACL acl, int offset, DWORD attributes,
PSID sid, size_t &len_add, DWORD inherit)
@@ -1256,10 +1494,9 @@ add_access_allowed_ace (PACL acl, int offset, DWORD attributes,
return FALSE;
}
ACCESS_ALLOWED_ACE *ace;
- if (GetAce(acl, offset, (PVOID *) &ace))
+ if (GetAce (acl, offset, (PVOID *) &ace))
ace->Header.AceFlags |= inherit;
- len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD)
- + GetLengthSid (sid);
+ len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid);
return TRUE;
}
@@ -1273,15 +1510,14 @@ add_access_denied_ace (PACL acl, int offset, DWORD attributes,
return FALSE;
}
ACCESS_DENIED_ACE *ace;
- if (GetAce(acl, offset, (PVOID *) &ace))
+ if (GetAce (acl, offset, (PVOID *) &ace))
ace->Header.AceFlags |= inherit;
- len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD)
- + GetLengthSid (sid);
+ len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid);
return TRUE;
}
PSECURITY_DESCRIPTOR
-alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
+alloc_sd (__uid32_t uid, __gid32_t gid, int attribute,
PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret)
{
BOOL dummy;
@@ -1295,29 +1531,39 @@ alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
return NULL;
}
- /* Get SID and name of new owner. */
- char owner[UNLEN + 1];
- cygsid owner_sid;
- struct passwd *pw = getpwuid (uid);
- strcpy (owner, pw ? pw->pw_name : getlogin ());
- if ((!pw || !owner_sid.getfrompw (pw))
- && !lookup_name (owner, logsrv, owner_sid))
- return NULL;
- debug_printf ("owner: %s [%d]", owner,
- *GetSidSubAuthority(owner_sid,
- *GetSidSubAuthorityCount(owner_sid) - 1));
-
- /* Get SID and name of new group. */
- cygsid group_sid (NO_SID);
- struct group *grp = getgrgid (gid);
- if (grp)
+ /* Get SID of owner. */
+ cygsid owner_sid (NO_SID);
+ /* Check for current user first */
+ if (uid == myself->uid)
+ owner_sid = cygheap->user.sid ();
+ else if (uid == cygheap->user.orig_uid)
+ owner_sid = cygheap->user.orig_sid ();
+ if (!owner_sid)
{
- if ((!grp || !group_sid.getfromgr (grp))
- && !lookup_name (grp->gr_name, logsrv, group_sid))
- return NULL;
+ /* Otherwise retrieve user data from /etc/passwd */
+ struct passwd *pw = getpwuid32 (uid);
+ if (!pw)
+ {
+ debug_printf ("no /etc/passwd entry for %d", uid);
+ set_errno (EINVAL);
+ return NULL;
+ }
+ else if (!owner_sid.getfrompw (pw))
+ {
+ debug_printf ("no SID for user %d", uid);
+ set_errno (EINVAL);
+ return NULL;
+ }
}
- else
- debug_printf ("no group");
+ owner_sid.debug_print ("alloc_sd: owner SID =");
+
+ /* Get SID of new group. */
+ cygsid group_sid (NO_SID);
+ struct __group32 *grp = getgrgid32 (gid);
+ if (!grp)
+ debug_printf ("no /etc/group entry for %d", gid);
+ else if (!group_sid.getfromgr (grp))
+ debug_printf ("no SID for group %d", gid);
/* Initialize local security descriptor. */
SECURITY_DESCRIPTOR sd;
@@ -1338,14 +1584,14 @@ alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
SetSecurityDescriptorControl (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
/* Create owner for local security descriptor. */
- if (!SetSecurityDescriptorOwner(&sd, owner_sid, FALSE))
+ if (!SetSecurityDescriptorOwner (&sd, owner_sid, FALSE))
{
__seterrno ();
return NULL;
}
/* Create group for local security descriptor. */
- if (group_sid && !SetSecurityDescriptorGroup(&sd, group_sid, FALSE))
+ if (group_sid && !SetSecurityDescriptorGroup (&sd, group_sid, FALSE))
{
__seterrno ();
return NULL;
@@ -1387,8 +1633,7 @@ alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
if (attribute & S_IXGRP)
group_allow |= FILE_GENERIC_EXECUTE;
if ((attribute & (S_IFDIR | S_IWGRP | S_IXGRP))
- == (S_IFDIR | S_IWGRP | S_IXGRP)
- && !(attribute & S_ISVTX))
+ == (S_IFDIR | S_IWGRP | S_IXGRP) && !(attribute & S_ISVTX))
group_allow |= FILE_DELETE_CHILD;
/* Construct allow attribute for everyone. */
@@ -1430,35 +1675,36 @@ alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA);
/* Construct appropriate inherit attribute. */
- DWORD inherit = (attribute & S_IFDIR) ? INHERIT_ALL : DONT_INHERIT;
+ DWORD inherit = (attribute & S_IFDIR) ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
+ : NO_INHERITANCE;
/* Set deny ACE for owner. */
if (owner_deny
&& !add_access_denied_ace (acl, ace_off++, owner_deny,
- owner_sid, acl_len, inherit))
+ owner_sid, acl_len, inherit))
return NULL;
/* Set allow ACE for owner. */
if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
- owner_sid, acl_len, inherit))
+ owner_sid, acl_len, inherit))
return NULL;
/* Set deny ACE for group. */
if (group_deny
&& !add_access_denied_ace (acl, ace_off++, group_deny,
- group_sid, acl_len, inherit))
+ group_sid, acl_len, inherit))
return NULL;
/* Set allow ACE for group. */
if (!add_access_allowed_ace (acl, ace_off++, group_allow,
- group_sid, acl_len, inherit))
+ group_sid, acl_len, inherit))
return NULL;
/* Set allow ACE for everyone. */
if (!add_access_allowed_ace (acl, ace_off++, other_allow,
- well_known_world_sid, acl_len, inherit))
+ well_known_world_sid, acl_len, inherit))
return NULL;
/* Set null ACE for special bits. */
if (null_allow
&& !add_access_allowed_ace (acl, ace_off++, null_allow,
- well_known_null_sid, acl_len, DONT_INHERIT))
+ well_known_null_sid, acl_len, NO_INHERITANCE))
return NULL;
/* Get owner and group from current security descriptor. */
@@ -1491,7 +1737,7 @@ alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
* Add unrelated ACCESS_DENIED_ACE to the beginning but
* behind the owner_deny, ACCESS_ALLOWED_ACE to the end.
*/
- if (!AddAce(acl, ACL_REVISION,
+ if (!AddAce (acl, ACL_REVISION,
ace->Header.AceType == ACCESS_DENIED_ACE_TYPE ?
(owner_deny ? 1 : 0) : MAXDWORD,
(LPVOID) ace, ace->Header.AceSize))
@@ -1536,22 +1782,21 @@ void
set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa,
void *sd_buf, DWORD sd_buf_size)
{
- /* symlinks are anything for everyone!*/
+ /* symlinks are anything for everyone! */
if ((attribute & S_IFLNK) == S_IFLNK)
attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
psa->lpSecurityDescriptor = sd_buf;
- InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR)sd_buf,
+ InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf,
SECURITY_DESCRIPTOR_REVISION);
- psa->lpSecurityDescriptor = alloc_sd (geteuid (), getegid (),
- cygheap->user.logsrv (),
- attribute, (PSECURITY_DESCRIPTOR)sd_buf,
+ psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), attribute,
+ (PSECURITY_DESCRIPTOR) sd_buf,
&sd_buf_size);
}
static int
-set_nt_attribute (const char *file, uid_t uid, gid_t gid,
- const char *logsrv, int attribute)
+set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid,
+ int attribute)
{
if (!wincap.has_security ())
return 0;
@@ -1568,7 +1813,7 @@ set_nt_attribute (const char *file, uid_t uid, gid_t gid,
}
sd_size = 4096;
- if (!(psd = alloc_sd (uid, gid, logsrv, attribute, psd, &sd_size)))
+ if (!(psd = alloc_sd (uid, gid, attribute, psd, &sd_size)))
return -1;
return write_sd (file, psd, sd_size);
@@ -1576,13 +1821,12 @@ set_nt_attribute (const char *file, uid_t uid, gid_t gid,
int
set_file_attribute (int use_ntsec, const char *file,
- uid_t uid, gid_t gid,
- int attribute, const char *logsrv)
+ __uid32_t uid, __gid32_t gid, int attribute)
{
int ret = 0;
if (use_ntsec && allow_ntsec)
- ret = set_nt_attribute (file, uid, gid, logsrv, attribute);
+ ret = set_nt_attribute (file, uid, gid, attribute);
else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute,
sizeof (attribute)))
{
@@ -1598,6 +1842,5 @@ int
set_file_attribute (int use_ntsec, const char *file, int attribute)
{
return set_file_attribute (use_ntsec, file,
- myself->uid, myself->gid,
- attribute, cygheap->user.logsrv ());
+ myself->uid, myself->gid, attribute);
}
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index 8555fe461..d9bd691f3 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -1,6 +1,6 @@
/* security.h: security declarations
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -8,14 +8,14 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
-#define DONT_INHERIT (0)
-#define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE)
-#define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE)
+#include <accctrl.h>
#define DEFAULT_UID DOMAIN_USER_RID_ADMIN
#define DEFAULT_GID DOMAIN_ALIAS_RID_ADMINS
#define MAX_SID_LEN 40
+#define MAX_DACL_LEN(n) (sizeof (ACL) \
+ + (n) * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + MAX_SID_LEN))
#define NO_SID ((PSID)NULL)
@@ -39,6 +39,15 @@ class cygsid {
}
public:
+ inline operator const PSID () { return psid; }
+
+ inline const PSID operator= (cygsid &nsid)
+ { return assign (nsid); }
+ inline const PSID operator= (const PSID nsid)
+ { return assign (nsid); }
+ inline const PSID operator= (const char *nsidstr)
+ { return getfromstr (nsidstr); }
+
inline cygsid () : psid ((PSID) sbuf) {}
inline cygsid (const PSID nsid) { *this = nsid; }
inline cygsid (const char *nstrsid) { *this = nstrsid; }
@@ -46,7 +55,7 @@ public:
inline PSID set () { return psid = (PSID) sbuf; }
BOOL getfrompw (const struct passwd *pw);
- BOOL getfromgr (const struct group *gr);
+ BOOL getfromgr (const struct __group32 *gr);
int get_id (BOOL search_grp, int *type = NULL);
inline int get_uid () { return get_id (FALSE); }
@@ -54,13 +63,6 @@ public:
char *string (char *nsidstr) const;
- inline const PSID operator= (cygsid &nsid)
- { return assign (nsid); }
- inline const PSID operator= (const PSID nsid)
- { return assign (nsid); }
- inline const PSID operator= (const char *nsidstr)
- { return getfromstr (nsidstr); }
-
inline BOOL operator== (const PSID nsid) const
{
if (!psid || !nsid)
@@ -77,8 +79,6 @@ public:
inline BOOL operator!= (const char *nsidstr) const
{ return !(*this == nsidstr); }
- inline operator const PSID () { return psid; }
-
void debug_print (const char *prefix = NULL) const
{
char buf[256];
@@ -86,40 +86,63 @@ public:
}
};
+typedef enum { cygsidlist_empty, cygsidlist_alloc, cygsidlist_auto } cygsidlist_type;
class cygsidlist {
+ int maxcount;
public:
int count;
cygsid *sids;
+ cygsidlist_type type;
- cygsidlist () : count (0), sids (NULL) {}
- ~cygsidlist () { delete [] sids; }
+ cygsidlist (cygsidlist_type t, int m)
+ {
+ type = t;
+ count = 0;
+ maxcount = m;
+ if (t == cygsidlist_alloc)
+ sids = alloc_sids (m);
+ else
+ sids = new cygsid [m];
+ }
+ ~cygsidlist () { if (type == cygsidlist_auto) delete [] sids; }
- BOOL add (cygsid &nsi)
+ BOOL add (const PSID nsi) /* Only with auto for now */
{
- cygsid *tmp = new cygsid [count + 1];
- if (!tmp)
- return FALSE;
- for (int i = 0; i < count; ++i)
- tmp[i] = sids[i];
- delete [] sids;
- sids = tmp;
+ if (count >= maxcount)
+ {
+ cygsid *tmp = new cygsid [ 2 * maxcount];
+ if (!tmp)
+ return FALSE;
+ maxcount *= 2;
+ for (int i = 0; i < count; ++i)
+ tmp[i] = sids[i];
+ delete [] sids;
+ sids = tmp;
+ }
sids[count++] = nsi;
return TRUE;
}
- BOOL add (const PSID nsid) { return add (nsid); }
+ BOOL add (cygsid &nsi) { return add ((PSID) nsi); }
BOOL add (const char *sidstr)
{ cygsid nsi (sidstr); return add (nsi); }
+ BOOL addfromgr (struct __group32 *gr) /* Only with alloc */
+ { return sids[count++].getfromgr (gr); }
BOOL operator+= (cygsid &si) { return add (si); }
BOOL operator+= (const char *sidstr) { return add (sidstr); }
+ BOOL operator+= (const PSID psid) { return add (psid); }
- BOOL contains (cygsid &sid) const
+ int position (const PSID sid) const
{
for (int i = 0; i < count; ++i)
if (sids[i] == sid)
- return TRUE;
- return FALSE;
+ return i;
+ return -1;
}
+
+ BOOL contains (const PSID sid) const { return position (sid) >= 0; }
+ cygsid *alloc_sids (int n);
+ void free_sids ();
void debug_print (const char *prefix = NULL) const
{
debug_printf ("-- begin sidlist ---");
@@ -131,6 +154,31 @@ public:
}
};
+class user_groups {
+public:
+ cygsid pgsid;
+ cygsidlist sgsids;
+ BOOL ischanged;
+
+ BOOL issetgroups () const { return (sgsids.type == cygsidlist_alloc); }
+ void update_supp (const cygsidlist &newsids)
+ {
+ sgsids.free_sids ();
+ sgsids = newsids;
+ ischanged = TRUE;
+ }
+ void clear_supp ()
+ {
+ sgsids.free_sids ();
+ ischanged = TRUE;
+ }
+ void update_pgrp (const PSID sid)
+ {
+ pgsid = sid;
+ ischanged = TRUE;
+ }
+};
+
extern cygsid well_known_null_sid;
extern cygsid well_known_world_sid;
extern cygsid well_known_local_sid;
@@ -159,14 +207,16 @@ extern BOOL allow_smbntsec;
and group lists so they are somehow security related. Besides that
I didn't find a better place to declare them. */
extern struct passwd *internal_getpwent (int);
-extern struct group *internal_getgrent (int);
+extern struct __group32 *internal_getgrent (int);
/* File manipulation */
int __stdcall set_process_privileges ();
int __stdcall get_file_attribute (int, const char *, int *,
- uid_t * = NULL, gid_t * = NULL);
+ __uid32_t * = NULL, __gid32_t * = NULL);
int __stdcall set_file_attribute (int, const char *, int);
-int __stdcall set_file_attribute (int, const char *, uid_t, gid_t, int, const char *);
+int __stdcall set_file_attribute (int, const char *, __uid32_t, __gid32_t, int);
+int __stdcall get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, int *,
+ __uid32_t * = NULL, __gid32_t * = NULL);
LONG __stdcall read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size);
LONG __stdcall write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size);
BOOL __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit);
@@ -178,19 +228,17 @@ void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa,
/* Try a subauthentication. */
HANDLE subauth (struct passwd *pw);
/* Try creating a token directly. */
-HANDLE create_token (cygsid &usersid, cygsid &pgrpsid);
+HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw);
+/* Verify an existing token */
+BOOL verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL * pintern = NULL);
/* Extract U-domain\user field from passwd entry. */
void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user);
-/* Get default logonserver and domain for this box. */
-BOOL get_logon_server_and_user_domain (char *logonserver, char *domain);
+/* Get default logonserver for a domain. */
+BOOL get_logon_server (const char * domain, char * server, WCHAR *wserver = NULL);
/* sec_helper.cc: Security helper functions. */
-BOOL __stdcall is_grp_member (uid_t uid, gid_t gid);
-/* `lookup_name' should be called instead of LookupAccountName.
- * logsrv may be NULL, in this case only the local system is used for lookup.
- * The buffer for ret_sid (40 Bytes) has to be allocated by the caller! */
-BOOL __stdcall lookup_name (const char *, const char *, PSID);
+BOOL __stdcall is_grp_member (__uid32_t uid, __gid32_t gid);
int set_process_privilege (const char *privilege, BOOL enable = TRUE);
/* shared.cc: */
@@ -199,10 +247,23 @@ SECURITY_DESCRIPTOR *__stdcall get_null_sd (void);
/* Various types of security attributes for use in Create* functions. */
extern SECURITY_ATTRIBUTES sec_none, sec_none_nih, sec_all, sec_all_nih;
-extern SECURITY_ATTRIBUTES *__stdcall sec_user (PVOID sa_buf, PSID sid2 = NULL, BOOL inherit = TRUE);
-extern SECURITY_ATTRIBUTES *__stdcall sec_user_nih (PVOID sa_buf, PSID sid2 = NULL);
+extern SECURITY_ATTRIBUTES *__stdcall __sec_user (PVOID sa_buf, PSID sid2, BOOL inherit)
+ __attribute__ ((regparm (3)));
+extern BOOL sec_acl (PACL acl, BOOL admins, PSID sid1 = NO_SID, PSID sid2 = NO_SID);
int __stdcall NTReadEA (const char *file, const char *attrname, char *buf, int len);
BOOL __stdcall NTWriteEA (const char *file, const char *attrname, const char *buf, int len);
-PSECURITY_DESCRIPTOR alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute,
- PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret);
+PSECURITY_DESCRIPTOR alloc_sd (__uid32_t uid, __gid32_t gid, int attribute,
+ PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret);
+
+extern inline SECURITY_ATTRIBUTES *
+sec_user_nih (char sa_buf[], PSID sid = NULL)
+{
+ return allow_ntsec ? __sec_user (sa_buf, sid, FALSE) : &sec_none_nih;
+}
+
+extern inline SECURITY_ATTRIBUTES *
+sec_user (char sa_buf[], PSID sid = NULL)
+{
+ return allow_ntsec ? __sec_user (sa_buf, sid, TRUE) : &sec_none_nih;
+}
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index e66d078c8..c540563fd 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1,6 +1,6 @@
/* select.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Christopher Faylor of Cygnus Solutions
cgf@cygnus.com
@@ -39,10 +39,10 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "sync.h"
#include "sigproc.h"
#include "perthread.h"
#include "tty.h"
+#include "cygthread.h"
/*
* All these defines below should be in sys/types.h
@@ -71,7 +71,7 @@ typedef long fd_mask;
#define NULL_fd_set ((fd_set *) NULL)
#define sizeof_fd_set(n) \
- ((unsigned) (NULL_fd_set->fds_bits + unix_howmany((n), UNIX_NFDBITS)))
+ ((unsigned) (NULL_fd_set->fds_bits + unix_howmany ((n), UNIX_NFDBITS)))
#define UNIX_FD_SET(n, p) \
((p)->fds_bits[(n)/UNIX_NFDBITS] |= (1L << ((n) % UNIX_NFDBITS)))
#define UNIX_FD_CLR(n, p) \
@@ -84,30 +84,12 @@ typedef long fd_mask;
#define allocfd_set(n) ((fd_set *) memset (alloca (sizeof_fd_set (n)), 0, sizeof_fd_set (n)))
#define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n));
-/* Make a fhandler_foo::ready_for_ready method.
- Assumption: The "ready_for_read" methods are called with one level of
- signal blocking. */
-#define MAKEready(what) \
-int \
-fhandler_##what::ready_for_read (int fd, DWORD howlong, int ignra) \
-{ \
- select_record me (this); \
- me.fd = fd; \
- (void) select_read (&me); \
- while (!peek_##what (&me, ignra) && howlong == INFINITE) \
- if (fd >= 0 && cygheap->fdtab.not_open (fd)) \
- break; \
- else if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) \
- break; \
- return me.read_ready; \
-}
-
#define set_handle_or_return_if_not_open(h, s) \
h = (s)->fh->get_handle (); \
if (cygheap->fdtab.not_open ((s)->fd)) \
{ \
- (s)->saw_error = TRUE; \
- set_errno (EBADF); \
+ (s)->saw_error = true; \
+ set_sig_errno (EBADF); \
return -1; \
} \
@@ -228,28 +210,16 @@ select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds,
return 1; /* nothing to do */
if (s->read_ready || s->write_ready || s->except_ready)
- always_ready = TRUE;
+ always_ready = true;
if (s->windows_handle || s->windows_handle || s->windows_handle)
- windows_used = TRUE;
+ windows_used = true;
s->next = start.next;
start.next = s;
return 1;
}
-/* Poll every fd in the select chain. Set appropriate fd in mask. */
-int
-select_stuff::poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
-{
- int n = 0;
- select_record *s = &start;
- while ((s = s->next))
- n += s->poll (s, readfds, writefds, exceptfds);
- select_printf ("returning %d", n);
- return n;
-}
-
/* The heart of select. Waits for an fd to do something interesting. */
int
select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
@@ -268,7 +238,7 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
{
if (m > MAXIMUM_WAIT_OBJECTS)
{
- set_errno (EINVAL);
+ set_sig_errno (EINVAL);
return -1;
}
if (!s->startup (s, this))
@@ -315,12 +285,16 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
select_printf ("woke up. wait_ret %d. verifying", wait_ret);
s = &start;
int gotone = FALSE;
+ /* Some types of object (e.g., consoles) wake up on "inappropriate" events
+ like mouse movements. The verify function will detect these situations.
+ If it returns false, then this wakeup was a false alarm and we should go
+ back to waiting. */
while ((s = s->next))
if (s->saw_error)
return -1; /* Somebody detected an error */
else if ((((wait_ret >= m && s->windows_handle) || s->h == w4[wait_ret])) &&
s->verify (s, readfds, writefds, exceptfds))
- gotone = TRUE;
+ gotone = true;
select_printf ("gotone %d", gotone);
if (gotone)
@@ -351,7 +325,7 @@ out:
static int
set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds)
+ fd_set *exceptfds)
{
int ready = 0;
select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ());
@@ -363,17 +337,39 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
if (me->write_selected && me->write_ready)
{
UNIX_FD_SET (me->fd, writefds);
+ if (me->except_on_write && me->fh->get_device () == FH_SOCKET)
+ ((fhandler_socket *) me->fh)->set_connect_state (CONNECTED);
ready++;
}
- if (me->except_ready && me->except_ready)
+ if ((me->except_selected || me->except_on_write) && me->except_ready)
{
- UNIX_FD_SET (me->fd, exceptfds);
+ if (me->except_on_write) /* Only on sockets */
+ {
+ UNIX_FD_SET (me->fd, writefds);
+ if (me->fh->get_device () == FH_SOCKET)
+ ((fhandler_socket *) me->fh)->set_connect_state (CONNECTED);
+ }
+ if (me->except_selected)
+ UNIX_FD_SET (me->fd, exceptfds);
ready++;
}
select_printf ("ready %d", ready);
return ready;
}
+/* Poll every fd in the select chain. Set appropriate fd in mask. */
+int
+select_stuff::poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+{
+ int n = 0;
+ select_record *s = &start;
+ while ((s = s->next))
+ n += (!s->peek || s->peek (s, true)) ?
+ set_bits (s, readfds, writefds, exceptfds) : 0;
+ select_printf ("returning %d", n);
+ return n;
+}
+
static int
verify_true (select_record *, fd_set *, fd_set *, fd_set *)
{
@@ -400,7 +396,7 @@ no_verify (select_record *, fd_set *, fd_set *, fd_set *)
}
static int
-peek_pipe (select_record *s, int ignra, HANDLE guard_mutex = NULL)
+peek_pipe (select_record *s, bool from_select)
{
int n = 0;
int gotone = 0;
@@ -409,6 +405,15 @@ peek_pipe (select_record *s, int ignra, HANDLE guard_mutex = NULL)
HANDLE h;
set_handle_or_return_if_not_open (h, s);
+ /* pipes require a guard mutex to guard against the situation where multiple
+ readers are attempting to read from the same pipe. In this scenario, it
+ is possible for PeekNamedPipe to report available data to two readers but
+ only one will actually get the data. This will result in the other reader
+ entering fhandler_base::raw_read and blocking indefinitely in an interruptible
+ state. This causes things like "make -j2" to hang. So, for the non-select case
+ we use the pipe mutex, if it is available. */
+ HANDLE guard_mutex = from_select ? NULL : fh->get_guard ();
+
/* Don't perform complicated tests if we don't need to. */
if (!s->read_selected && !s->except_selected)
goto out;
@@ -428,22 +433,22 @@ peek_pipe (select_record *s, int ignra, HANDLE guard_mutex = NULL)
case FH_TTYM:
if (((fhandler_pty_master *)fh)->need_nl)
{
- gotone = s->read_ready = 1;
+ gotone = s->read_ready = true;
goto out;
}
break;
default:
- if (!ignra && fh->get_readahead_valid ())
+ if (fh->get_readahead_valid ())
{
select_printf ("readahead");
- gotone = s->read_ready = 1;
+ gotone = s->read_ready = true;
goto out;
}
}
if (fh->bg_check (SIGTTIN) <= bg_eof)
{
- gotone = s->read_ready = 1;
+ gotone = s->read_ready = true;
goto out;
}
}
@@ -455,34 +460,48 @@ peek_pipe (select_record *s, int ignra, HANDLE guard_mutex = NULL)
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
n = -1;
}
- else if (n && guard_mutex
- && WaitForSingleObject (guard_mutex, 0) != WAIT_OBJECT_0)
+ else if (!n || !guard_mutex)
+ /* no guard mutex or nothing to read from the pipe. */;
+ else if (WaitForSingleObject (guard_mutex, 0) != WAIT_OBJECT_0)
{
select_printf ("%s, couldn't get mutex %p, %E", fh->get_name (),
- guard_mutex);
+ guard_mutex);
n = 0;
}
+ else
+ {
+ /* Now that we have the mutex, make sure that no one else has snuck
+ in and grabbed the data that we originally saw. */
+ if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
+ {
+ select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
+ n = -1;
+ }
+ if (n <= 0)
+ ReleaseMutex (guard_mutex); /* Oops. We lost the race. */
+ }
if (n < 0)
{
+ fh->set_eof (); /* Flag that other end of pipe is gone */
select_printf ("%s, n %d", fh->get_name (), n);
if (s->except_selected)
- gotone += s->except_ready = TRUE;
+ gotone += s->except_ready = true;
if (s->read_selected)
- gotone += s->read_ready = TRUE;
+ gotone += s->read_ready = true;
}
if (n > 0 && s->read_selected)
{
select_printf ("%s, ready for read", fh->get_name ());
- gotone += s->read_ready = TRUE;
+ gotone += s->read_ready = true;
}
if (!gotone && s->fh->hit_eof ())
{
select_printf ("%s, saw EOF", fh->get_name ());
if (s->except_selected)
- gotone = s->except_ready = TRUE;
+ gotone = s->except_ready = true;
if (s->read_selected)
- gotone += s->read_ready = TRUE;
+ gotone += s->read_ready = true;
select_printf ("saw eof on '%s'", fh->get_name ());
}
@@ -490,35 +509,11 @@ out:
return gotone || s->write_ready;
}
-static int
-poll_pipe (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds)
-{
- return peek_pipe (me, 0) ?
- set_bits (me, readfds, writefds, exceptfds) :
- 0;
-}
-
-int
-fhandler_pipe::ready_for_read (int fd, DWORD howlong, int ignra)
-{
- select_record me (this);
- me.fd = fd;
- (void) select_read (&me);
- while (!peek_pipe (&me, ignra, guard) && howlong == INFINITE)
- if (fd >= 0 && cygheap->fdtab.not_open (fd))
- break;
- else if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0)
- break;
- select_printf ("returning %d", me.read_ready);
- return me.read_ready;
-}
-
static int start_thread_pipe (select_record *me, select_stuff *stuff);
struct pipeinf
{
- HANDLE thread;
+ cygthread *thread;
BOOL stop_thread_pipe;
select_record *start;
};
@@ -535,8 +530,8 @@ thread_pipe (void *arg)
while ((s = s->next))
if (s->startup == start_thread_pipe)
{
- if (peek_pipe (s, 0))
- gotone = TRUE;
+ if (peek_pipe (s, true))
+ gotone = true;
if (pi->stop_thread_pipe)
{
select_printf ("stopping");
@@ -562,13 +557,14 @@ start_thread_pipe (select_record *me, select_stuff *stuff)
{
if (stuff->device_specific[FHDEVN(FH_PIPE)])
{
- me->h = ((pipeinf *) stuff->device_specific[FHDEVN(FH_PIPE)])->thread;
+ me->h = *((pipeinf *) stuff->device_specific[FHDEVN(FH_PIPE)])->thread;
return 1;
}
pipeinf *pi = new pipeinf;
pi->start = &stuff->start;
pi->stop_thread_pipe = FALSE;
- pi->thread = me->h = makethread (thread_pipe, (LPVOID)pi, 0, "select_pipe");
+ pi->thread = new cygthread (thread_pipe, (LPVOID)pi, "select_pipe");
+ me->h = *pi->thread;
if (!me->h)
return 0;
stuff->device_specific[FHDEVN(FH_PIPE)] = (void *)pi;
@@ -581,9 +577,8 @@ pipe_cleanup (select_record *, select_stuff *stuff)
pipeinf *pi = (pipeinf *)stuff->device_specific[FHDEVN(FH_PIPE)];
if (pi && pi->thread)
{
- pi->stop_thread_pipe = TRUE;
- WaitForSingleObject (pi->thread, INFINITE);
- CloseHandle (pi->thread);
+ pi->stop_thread_pipe = true;
+ pi->thread->detach ();
delete pi;
stuff->device_specific[FHDEVN(FH_PIPE)] = NULL;
}
@@ -595,9 +590,10 @@ fhandler_pipe::select_read (select_record *s)
if (!s)
s = new select_record;
s->startup = start_thread_pipe;
- s->poll = poll_pipe;
+ s->peek = peek_pipe;
s->verify = verify_ok;
- s->read_selected = TRUE;
+ s->read_selected = true;
+ s->read_ready = false;
s->cleanup = pipe_cleanup;
return s;
}
@@ -609,11 +605,11 @@ fhandler_pipe::select_write (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = poll_pipe;
s->verify = no_verify;
}
- s->write_selected = TRUE;
- s->write_ready = TRUE;
+ s->peek = peek_pipe;
+ s->write_selected = true;
+ s->write_ready = true;
return s;
}
@@ -623,15 +619,16 @@ fhandler_pipe::select_except (select_record *s)
if (!s)
s = new select_record;
s->startup = start_thread_pipe;
- s->poll = poll_pipe;
+ s->peek = peek_pipe;
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
- s->except_selected = TRUE;
+ s->except_selected = true;
+ s->except_ready = false;
return s;
}
static int
-peek_console (select_record *me, int ignra)
+peek_console (select_record *me, bool)
{
extern const char * get_nonascii_key (INPUT_RECORD& input_rec, char *);
fhandler_console *fh = (fhandler_console *)me->fh;
@@ -639,10 +636,10 @@ peek_console (select_record *me, int ignra)
if (!me->read_selected)
return me->write_ready;
- if (!ignra && fh->get_readahead_valid ())
+ if (fh->get_readahead_valid ())
{
select_printf ("readahead");
- return me->read_ready = 1;
+ return me->read_ready = true;
}
if (me->read_ready)
@@ -659,23 +656,27 @@ peek_console (select_record *me, int ignra)
for (;;)
if (fh->bg_check (SIGTTIN) <= bg_eof)
- return me->read_ready = 1;
+ return me->read_ready = true;
else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read)
break;
else
{
- if (irec.EventType == WINDOW_BUFFER_SIZE_EVENT)
- kill_pgrp (fh->tc->getpgid (), SIGWINCH);
- else if (irec.EventType == MOUSE_EVENT &&
- (irec.Event.MouseEvent.dwEventFlags == 0 ||
- irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
+ if (irec.EventType == KEY_EVENT)
{
- if (fh->mouse_aware ())
- return me->read_ready = 1;
+ if (irec.Event.KeyEvent.bKeyDown
+ && (irec.Event.KeyEvent.uChar.AsciiChar
+ || get_nonascii_key (irec, tmpbuf)))
+ return me->read_ready = true;
+ }
+ else
+ {
+ fh->send_winch_maybe ();
+ if (irec.EventType == MOUSE_EVENT
+ && fh->mouse_aware ()
+ && (irec.Event.MouseEvent.dwEventFlags == 0
+ || irec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
+ return me->read_ready = true;
}
- else if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown == TRUE &&
- (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec, tmpbuf)))
- return me->read_ready = 1;
/* Read and discard the event */
ReadConsoleInput (h, &irec, 1, &events_read);
@@ -685,15 +686,12 @@ peek_console (select_record *me, int ignra)
}
static int
-poll_console (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds)
+verify_console (select_record *me, fd_set *rfds, fd_set *wfds,
+ fd_set *efds)
{
- return peek_console (me, 0) ?
- set_bits (me, readfds, writefds, exceptfds) :
- 0;
+ return peek_console (me, true);
}
-MAKEready (console)
select_record *
fhandler_console::select_read (select_record *s)
@@ -702,13 +700,14 @@ fhandler_console::select_read (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = poll_console;
- s->verify = poll_console;
+ s->verify = verify_console;
set_cursor_maybe ();
}
+ s->peek = peek_console;
s->h = get_handle ();
- s->read_selected = TRUE;
+ s->read_selected = true;
+ s->read_ready = false;
return s;
}
@@ -719,13 +718,13 @@ fhandler_console::select_write (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = poll_console;
s->verify = no_verify;
set_cursor_maybe ();
}
- s->write_selected = TRUE;
- s->write_ready = TRUE;
+ s->peek = peek_console;
+ s->write_selected = true;
+ s->write_ready = true;
return s;
}
@@ -736,30 +735,16 @@ fhandler_console::select_except (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = poll_console;
s->verify = no_verify;
set_cursor_maybe ();
}
- s->except_selected = TRUE;
+ s->peek = peek_console;
+ s->except_selected = true;
+ s->except_ready = false;
return s;
}
-int
-fhandler_tty_common::ready_for_read (int fd, DWORD howlong, int ignra)
-{
- select_record me (this);
- me.fd = fd;
- (void) select_read (&me);
- while (!peek_pipe (&me, ignra) && howlong == INFINITE)
- if (fd >= 0 && cygheap->fdtab.not_open (fd))
- break;
- else if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0)
- break;
- select_printf ("returning %d", me.read_ready);
- return me.read_ready;
-}
-
select_record *
fhandler_tty_common::select_read (select_record *s)
{
@@ -783,7 +768,7 @@ verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds)
{
if (WaitForSingleObject (me->h, 0) == WAIT_OBJECT_0)
- me->read_ready = 1;
+ me->read_ready = true;
return set_bits (me, readfds, writefds, exceptfds);
}
@@ -794,37 +779,14 @@ fhandler_tty_slave::select_read (select_record *s)
s = new select_record;
s->h = input_available_event;
s->startup = no_startup;
- s->poll = poll_pipe;
+ s->peek = peek_pipe;
s->verify = verify_tty_slave;
- s->read_selected = TRUE;
+ s->read_selected = true;
+ s->read_ready = false;
s->cleanup = NULL;
return s;
}
-int
-fhandler_tty_slave::ready_for_read (int fd, DWORD howlong, int ignra)
-{
- HANDLE w4[2];
- if (!ignra && get_readahead_valid ())
- {
- select_printf ("readahead");
- return 1;
- }
- w4[0] = signal_arrived;
- w4[1] = input_available_event;
- switch (WaitForMultipleObjects (2, w4, FALSE, howlong))
- {
- case WAIT_OBJECT_0 + 1:
- return 1;
- case WAIT_FAILED:
- select_printf ("wait failed %E");
- case WAIT_OBJECT_0:
- case WAIT_TIMEOUT:
- default:
- return 0;
- }
-}
-
select_record *
fhandler_dev_null::select_read (select_record *s)
{
@@ -832,12 +794,11 @@ fhandler_dev_null::select_read (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = no_verify;
}
s->h = get_handle ();
- s->read_selected = TRUE;
- s->read_ready = TRUE;
+ s->read_selected = true;
+ s->read_ready = true;
return s;
}
@@ -848,12 +809,11 @@ fhandler_dev_null::select_write (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = no_verify;
}
s->h = get_handle ();
- s->write_selected = TRUE;
- s->write_ready = TRUE;
+ s->write_selected = true;
+ s->write_ready = true;
return s;
}
@@ -864,12 +824,11 @@ fhandler_dev_null::select_except (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = no_verify;
}
s->h = get_handle ();
- s->except_selected = TRUE;
- s->except_ready = TRUE;
+ s->except_selected = true;
+ s->except_ready = true;
return s;
}
@@ -877,21 +836,20 @@ static int start_thread_serial (select_record *me, select_stuff *stuff);
struct serialinf
{
- HANDLE thread;
+ cygthread *thread;
BOOL stop_thread_serial;
select_record *start;
};
static int
-peek_serial (select_record *s, int)
+peek_serial (select_record *s, bool)
{
- DWORD ev;
COMSTAT st;
fhandler_serial *fh = (fhandler_serial *)s->fh;
if (fh->get_readahead_valid () || fh->overlapped_armed < 0)
- return s->read_ready = 1;
+ return s->read_ready = true;
select_printf ("fh->overlapped_armed %d", fh->overlapped_armed);
@@ -910,20 +868,19 @@ peek_serial (select_record *s, int)
if (!fh->overlapped_armed)
{
- DWORD ev;
COMSTAT st;
ResetEvent (fh->io_status.hEvent);
- if (!ClearCommError (h, &ev, &st))
+ if (!ClearCommError (h, &fh->ev, &st))
{
debug_printf ("ClearCommError");
goto err;
}
else if (st.cbInQue)
- return s->read_ready = 1;
- else if (WaitCommEvent (h, &ev, &fh->io_status))
- return s->read_ready = 1;
+ return s->read_ready = true;
+ else if (WaitCommEvent (h, &fh->ev, &fh->io_status))
+ return s->read_ready = true;
else if (GetLastError () == ERROR_IO_PENDING)
fh->overlapped_armed = 1;
else
@@ -943,7 +900,7 @@ peek_serial (select_record *s, int)
switch (WaitForMultipleObjects (2, w4, FALSE, to))
{
case WAIT_OBJECT_0:
- if (!ClearCommError (h, &ev, &st))
+ if (!ClearCommError (h, &fh->ev, &st))
{
debug_printf ("ClearCommError");
goto err;
@@ -952,7 +909,7 @@ peek_serial (select_record *s, int)
Sleep (to);
else
{
- return s->read_ready = 1;
+ return s->read_ready = true;
select_printf ("got something");
}
PurgeComm (h, PURGE_TXABORT | PURGE_RXABORT);
@@ -983,7 +940,7 @@ err:
}
__seterrno ();
- s->saw_error = TRUE;
+ s->saw_error = true;
select_printf ("error %E");
return -1;
}
@@ -1000,8 +957,8 @@ thread_serial (void *arg)
while ((s = s->next))
if (s->startup == start_thread_serial)
{
- if (peek_serial (s, 0))
- gotone = TRUE;
+ if (peek_serial (s, true))
+ gotone = true;
}
if (si->stop_thread_serial)
{
@@ -1021,15 +978,14 @@ start_thread_serial (select_record *me, select_stuff *stuff)
{
if (stuff->device_specific[FHDEVN(FH_SERIAL)])
{
- me->h = ((pipeinf *) stuff->device_specific[FHDEVN(FH_SERIAL)])->thread;
+ me->h = *((serialinf *) stuff->device_specific[FHDEVN(FH_SERIAL)])->thread;
return 1;
}
serialinf *si = new serialinf;
si->start = &stuff->start;
si->stop_thread_serial = FALSE;
- si->thread = me->h = makethread (thread_serial, (LPVOID)si, 0, "select_serial");
- if (!me->h)
- return 0;
+ si->thread = new cygthread (thread_serial, (LPVOID)si, "select_serial");
+ me->h = *si->thread;
stuff->device_specific[FHDEVN(FH_SERIAL)] = (void *)si;
return 1;
}
@@ -1040,26 +996,13 @@ serial_cleanup (select_record *, select_stuff *stuff)
serialinf *si = (serialinf *)stuff->device_specific[FHDEVN(FH_SERIAL)];
if (si && si->thread)
{
- si->stop_thread_serial = TRUE;
- WaitForSingleObject (si->thread, INFINITE);
- CloseHandle (si->thread);
+ si->stop_thread_serial = true;
+ si->thread->detach ();
delete si;
stuff->device_specific[FHDEVN(FH_SERIAL)] = NULL;
}
}
-static int
-poll_serial (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds)
-
-{
- return peek_serial (me, 0) ?
- set_bits (me, readfds, writefds, exceptfds) :
- 0;
-}
-
-MAKEready (serial)
-
select_record *
fhandler_serial::select_read (select_record *s)
{
@@ -1067,11 +1010,12 @@ fhandler_serial::select_read (select_record *s)
{
s = new select_record;
s->startup = start_thread_serial;
- s->poll = poll_serial;
s->verify = verify_ok;
s->cleanup = serial_cleanup;
}
- s->read_selected = TRUE;
+ s->peek = peek_serial;
+ s->read_selected = true;
+ s->read_ready = false;
return s;
}
@@ -1082,12 +1026,12 @@ fhandler_serial::select_write (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
+ s->peek = peek_serial;
s->h = get_handle ();
- s->write_selected = TRUE;
- s->write_ready = TRUE;
+ s->write_selected = true;
+ s->write_ready = true;
return s;
}
@@ -1098,18 +1042,53 @@ fhandler_serial::select_except (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
s->h = NULL;
- s->except_selected = FALSE; // Can't do this
+ s->peek = peek_serial;
+ s->except_selected = false; // Can't do this
+ s->except_ready = false;
return s;
}
int
-fhandler_base::ready_for_read (int, DWORD, int)
+fhandler_base::ready_for_read (int fd, DWORD howlong)
{
- return 1;
+ int avail = 0;
+ select_record me (this);
+ me.fd = fd;
+ while (!avail)
+ {
+ (void) select_read (&me);
+ avail = me.read_ready ?: me.peek (&me, false);
+
+ if (fd >= 0 && cygheap->fdtab.not_open (fd))
+ {
+ set_sig_errno (EBADF);
+ avail = 0;
+ break;
+ }
+
+ if (howlong != INFINITE)
+ {
+ if (!avail)
+ set_sig_errno (EAGAIN);
+ break;
+ }
+
+ if (WaitForSingleObject (signal_arrived, avail ? 0 : 10) == WAIT_OBJECT_0)
+ {
+ set_sig_errno (EINTR);
+ avail = 0;
+ break;
+ }
+ }
+
+ if (get_guard () && !avail && me.read_ready)
+ ReleaseMutex (get_guard ());
+
+ select_printf ("read_ready %d, avail %d", me.read_ready, avail);
+ return avail;
}
select_record *
@@ -1119,12 +1098,11 @@ fhandler_base::select_read (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
s->h = get_handle ();
- s->read_selected = TRUE;
- s->read_ready = TRUE;
+ s->read_selected = true;
+ s->read_ready = true;
return s;
}
@@ -1135,12 +1113,11 @@ fhandler_base::select_write (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
s->h = get_handle ();
- s->write_selected = TRUE;
- s->write_ready = TRUE;
+ s->write_selected = true;
+ s->write_ready = true;
return s;
}
@@ -1151,17 +1128,17 @@ fhandler_base::select_except (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
s->h = NULL;
- s->write_selected = TRUE;
+ s->except_selected = true;
+ s->except_ready = false;
return s;
}
struct socketinf
{
- HANDLE thread;
+ cygthread *thread;
winsock_fd_set readfds, writefds, exceptfds;
SOCKET exitsock;
struct sockaddr_in sin;
@@ -1169,65 +1146,59 @@ struct socketinf
};
static int
-peek_socket (select_record *me, int)
+peek_socket (select_record *me, bool)
{
winsock_fd_set ws_readfds, ws_writefds, ws_exceptfds;
struct timeval tv = {0, 0};
WINSOCK_FD_ZERO (&ws_readfds);
WINSOCK_FD_ZERO (&ws_writefds);
WINSOCK_FD_ZERO (&ws_exceptfds);
- int gotone = 0;
HANDLE h;
set_handle_or_return_if_not_open (h, me);
select_printf ("considering handle %p", h);
- if (me->read_selected)
+ if (me->read_selected && !me->read_ready)
{
select_printf ("adding read fd_set %s, fd %d", me->fh->get_name (),
me->fd);
WINSOCK_FD_SET (h, &ws_readfds);
}
- if (me->write_selected)
+ if (me->write_selected && !me->write_ready)
{
select_printf ("adding write fd_set %s, fd %d", me->fh->get_name (),
me->fd);
WINSOCK_FD_SET (h, &ws_writefds);
}
- if (me->except_selected)
+ if ((me->except_selected || me->except_on_write) && !me->except_ready)
{
select_printf ("adding except fd_set %s, fd %d", me->fh->get_name (),
me->fd);
WINSOCK_FD_SET (h, &ws_exceptfds);
}
- int r = WINSOCK_SELECT (0, &ws_readfds, &ws_writefds, &ws_exceptfds, &tv);
- select_printf ("WINSOCK_SELECT returned %d", r);
- if (r == -1)
+ int r;
+ if ((me->read_selected && !me->read_ready)
+ || (me->write_selected && !me->write_ready)
+ || ((me->except_selected || me->except_on_write) && !me->except_ready))
{
- select_printf ("error %d", WSAGetLastError ());
- return 0;
+ r = WINSOCK_SELECT (0, &ws_readfds, &ws_writefds, &ws_exceptfds, &tv);
+ select_printf ("WINSOCK_SELECT returned %d", r);
+ if (r == -1)
+ {
+ select_printf ("error %d", WSAGetLastError ());
+ set_winsock_errno ();
+ return 0;
+ }
+ if (WINSOCK_FD_ISSET (h, &ws_readfds) || (me->read_selected && me->read_ready))
+ me->read_ready = true;
+ if (WINSOCK_FD_ISSET (h, &ws_writefds) || (me->write_selected && me->write_ready))
+ me->write_ready = true;
+ if (WINSOCK_FD_ISSET (h, &ws_exceptfds) || ((me->except_selected || me->except_on_write) && me->except_ready))
+ me->except_ready = true;
}
-
- if (WINSOCK_FD_ISSET (h, &ws_readfds) || (me->read_selected && me->read_ready))
- gotone = me->read_ready = TRUE;
- if (WINSOCK_FD_ISSET (h, &ws_writefds) || (me->write_selected && me->write_ready))
- gotone = me->write_ready = TRUE;
- if (WINSOCK_FD_ISSET (h, &ws_exceptfds) || (me->except_selected && me->except_ready))
- gotone = me->except_ready = TRUE;
- return gotone;
-}
-
-static int
-poll_socket (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds)
-{
- return peek_socket (me, 0) ?
- set_bits (me, readfds, writefds, exceptfds) :
- 0;
+ return me->read_ready || me->write_ready || me->except_ready;
}
-MAKEready (socket)
-
static int start_thread_socket (select_record *, select_stuff *);
static DWORD WINAPI
@@ -1249,17 +1220,17 @@ thread_socket (void *arg)
if (WINSOCK_FD_ISSET (h, &si->readfds))
{
select_printf ("read_ready");
- s->read_ready = TRUE;
+ s->read_ready = true;
}
if (WINSOCK_FD_ISSET (h, &si->writefds))
{
select_printf ("write_ready");
- s->write_ready = TRUE;
+ s->write_ready = true;
}
if (WINSOCK_FD_ISSET (h, &si->exceptfds))
{
select_printf ("except_ready");
- s->except_ready = TRUE;
+ s->except_ready = true;
}
}
@@ -1278,7 +1249,7 @@ start_thread_socket (select_record *me, select_stuff *stuff)
if ((si = (socketinf *)stuff->device_specific[FHDEVN(FH_SOCKET)]))
{
- me->h = si->thread;
+ me->h = *si->thread;
return 1;
}
@@ -1292,17 +1263,17 @@ start_thread_socket (select_record *me, select_stuff *stuff)
{
HANDLE h = s->fh->get_handle ();
select_printf ("Handle %p", h);
- if (s->read_selected)
+ if (s->read_selected && !s->read_ready)
{
WINSOCK_FD_SET (h, &si->readfds);
select_printf ("Added to readfds");
}
- if (s->write_selected)
+ if (s->write_selected && !s->write_ready)
{
WINSOCK_FD_SET (h, &si->writefds);
select_printf ("Added to writefds");
}
- if (s->except_selected)
+ if ((s->except_selected || s->except_on_write) && !s->except_ready)
{
WINSOCK_FD_SET (h, &si->exceptfds);
select_printf ("Added to exceptfds");
@@ -1319,7 +1290,7 @@ start_thread_socket (select_record *me, select_stuff *stuff)
int tmp = 1;
(void) setsockopt (si->exitsock, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp));
- int sin_len = sizeof(si->sin);
+ int sin_len = sizeof (si->sin);
memset (&si->sin, 0, sizeof (si->sin));
si->sin.sin_family = AF_INET;
si->sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
@@ -1347,9 +1318,9 @@ start_thread_socket (select_record *me, select_stuff *stuff)
stuff->device_specific[FHDEVN(FH_SOCKET)] = (void *) si;
si->start = &stuff->start;
select_printf ("stuff_start %p", &stuff->start);
- si->thread = me->h = makethread (thread_socket, (LPVOID)si, 0,
- "select_socket");
- return !!me->h;
+ si->thread = new cygthread (thread_socket, (LPVOID)si, "select_socket");
+ me->h = *si->thread;
+ return 1;
err:
set_winsock_errno ();
@@ -1369,8 +1340,8 @@ socket_cleanup (select_record *, select_stuff *stuff)
/* Set LINGER with 0 timeout for hard close */
struct linger tmp = {1, 0}; /* On, 0 delay */
- (void) setsockopt (s, SOL_SOCKET, SO_LINGER, (char *)&tmp, sizeof(tmp));
- (void) setsockopt (si->exitsock, SOL_SOCKET, SO_LINGER, (char *)&tmp, sizeof(tmp));
+ (void) setsockopt (s, SOL_SOCKET, SO_LINGER, (char *)&tmp, sizeof (tmp));
+ (void) setsockopt (si->exitsock, SOL_SOCKET, SO_LINGER, (char *)&tmp, sizeof (tmp));
/* Connecting to si->exitsock will cause any executing select to wake
up. When this happens then the exitsock condition will cause the
@@ -1385,10 +1356,9 @@ socket_cleanup (select_record *, select_stuff *stuff)
closesocket (s);
/* Wait for thread to go away */
- WaitForSingleObject (si->thread, INFINITE);
+ si->thread->detach ();
shutdown (si->exitsock, SD_BOTH);
closesocket (si->exitsock);
- CloseHandle (si->thread);
stuff->device_specific[FHDEVN(FH_SOCKET)] = NULL;
delete si;
}
@@ -1402,12 +1372,12 @@ fhandler_socket::select_read (select_record *s)
{
s = new select_record;
s->startup = start_thread_socket;
- s->poll = poll_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
+ s->peek = peek_socket;
s->read_ready = saw_shutdown_read ();
- s->read_selected = TRUE;
+ s->read_selected = true;
return s;
}
@@ -1418,12 +1388,17 @@ fhandler_socket::select_write (select_record *s)
{
s = new select_record;
s->startup = start_thread_socket;
- s->poll = poll_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
- s->write_ready = saw_shutdown_write ();
- s->write_selected = TRUE;
+ s->peek = peek_socket;
+ s->write_ready = saw_shutdown_write () || is_unconnected ();
+ s->write_selected = true;
+ if (is_connect_pending ())
+ {
+ s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
+ s->except_on_write = true;
+ }
return s;
}
@@ -1434,18 +1409,18 @@ fhandler_socket::select_except (select_record *s)
{
s = new select_record;
s->startup = start_thread_socket;
- s->poll = poll_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
+ s->peek = peek_socket;
/* FIXME: Is this right? Should these be used as criteria for except? */
s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
- s->except_selected = TRUE;
+ s->except_selected = true;
return s;
}
static int
-peek_windows (select_record *me, int)
+peek_windows (select_record *me, bool)
{
MSG m;
HANDLE h;
@@ -1456,7 +1431,7 @@ peek_windows (select_record *me, int)
if (PeekMessage (&m, (HWND) h, 0, 0, PM_NOREMOVE))
{
- me->read_ready = TRUE;
+ me->read_ready = true;
select_printf ("window %d(%p) ready", me->fd, me->fh->get_handle ());
return 1;
}
@@ -1466,17 +1441,12 @@ peek_windows (select_record *me, int)
}
static int
-poll_windows (select_record *me, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds)
+verify_windows (select_record *me, fd_set *rfds, fd_set *wfds,
+ fd_set *efds)
{
-
- return peek_windows (me, 0) ?
- set_bits (me, readfds, writefds, exceptfds) :
- 0;
+ return peek_windows (me, true);
}
-MAKEready (windows)
-
select_record *
fhandler_windows::select_read (select_record *s)
{
@@ -1484,13 +1454,13 @@ fhandler_windows::select_read (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = poll_windows;
- s->verify = poll_windows;
}
+ s->verify = verify_windows;
+ s->peek = peek_windows;
+ s->read_selected = true;
+ s->read_ready = false;
s->h = get_handle ();
- s->read_selected = TRUE;
- s->h = get_handle ();
- s->windows_handle = TRUE;
+ s->windows_handle = true;
return s;
}
@@ -1501,13 +1471,13 @@ fhandler_windows::select_write (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
+ s->peek = peek_windows;
s->h = get_handle ();
- s->write_selected = TRUE;
- s->write_ready = TRUE;
- s->windows_handle = TRUE;
+ s->write_selected = true;
+ s->write_ready = true;
+ s->windows_handle = true;
return s;
}
@@ -1518,12 +1488,12 @@ fhandler_windows::select_except (select_record *s)
{
s = new select_record;
s->startup = no_startup;
- s->poll = set_bits;
s->verify = verify_ok;
}
+ s->peek = peek_windows;
s->h = get_handle ();
- s->except_selected = TRUE;
- s->except_ready = TRUE;
- s->windows_handle = TRUE;
+ s->except_selected = true;
+ s->except_ready = true;
+ s->windows_handle = true;
return s;
}
diff --git a/winsup/cygwin/sem.cc b/winsup/cygwin/sem.cc
new file mode 100644
index 000000000..63aba8e80
--- /dev/null
+++ b/winsup/cygwin/sem.cc
@@ -0,0 +1,41 @@
+/* sem.cc: Single unix specification IPC interface for Cygwin.
+
+ Copyright 2002 Red Hat, Inc.
+
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+
+#include <sys/types.h>
+#include <cygwin/sem.h>
+
+#include <errno.h>
+
+#include "cygerrno.h"
+
+extern "C" int
+semctl (int semid, int semnum, int cmd, ...)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
+
+extern "C" int
+semget (key_t key, int nsems, int semflg)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
+
+extern "C" int
+semop (int semid, struct sembuf *sops, size_t nsops)
+{
+ set_errno (ENOSYS);
+ return -1;
+}
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index 81d39e3ed..5c3beb999 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -1,6 +1,6 @@
/* shared.cc: shared data area support.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -14,31 +14,22 @@ details. */
#include <stdlib.h>
#include <grp.h>
#include <pwd.h>
-#include "sync.h"
-#include "sigproc.h"
+#include <errno.h>
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
+#include "cygerrno.h"
#include "cygheap.h"
#include "heap.h"
-#include "shared_info.h"
+#include "shared_info_magic.h"
#include "registry.h"
#include "cygwin_version.h"
-#define SHAREDVER (unsigned)(cygwin_version.api_major << 16 | \
- cygwin_version.api_minor)
-
shared_info NO_COPY *cygwin_shared = NULL;
mount_info NO_COPY *mount_table = NULL;
-HANDLE cygwin_mount_h;
-
-/* General purpose security attribute objects for global use. */
-SECURITY_ATTRIBUTES NO_COPY sec_none;
-SECURITY_ATTRIBUTES NO_COPY sec_none_nih;
-SECURITY_ATTRIBUTES NO_COPY sec_all;
-SECURITY_ATTRIBUTES NO_COPY sec_all_nih;
+HANDLE NO_COPY cygwin_mount_h;
char * __stdcall
shared_name (const char *str, int num)
@@ -47,13 +38,13 @@ shared_name (const char *str, int num)
extern bool _cygwin_testing;
__small_sprintf (buf, "%s.%s.%d", cygwin_version.shared_id, str, num);
- if (!_cygwin_testing)
+ if (_cygwin_testing)
strcat (buf, cygwin_version.dll_build_date);
return buf;
}
void * __stdcall
-open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr)
+open_shared (const char *name, int n, HANDLE &shared_h, DWORD size, void *addr)
{
void *shared;
@@ -64,18 +55,14 @@ open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr)
mapname = NULL;
else
{
- mapname = shared_name (name, 0);
+ mapname = shared_name (name, n);
shared_h = OpenFileMappingA (FILE_MAP_READ | FILE_MAP_WRITE,
TRUE, mapname);
}
if (!shared_h &&
- !(shared_h = CreateFileMappingA (INVALID_HANDLE_VALUE,
- &sec_all,
- PAGE_READWRITE,
- 0,
- size,
- mapname)))
- api_fatal ("CreateFileMappingA, %E. Terminating.");
+ !(shared_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_all,
+ PAGE_READWRITE, 0, size, mapname)))
+ api_fatal ("CreateFileMapping, %E. Terminating.");
}
shared = (shared_info *) MapViewOfFileEx (shared_h,
@@ -104,13 +91,12 @@ open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr)
void
shared_info::initialize ()
{
- if (inited)
+ if (version)
{
- if (inited != SHAREDVER)
- api_fatal ("Shared region version mismatch. Version %x != %x.\n"
- "Are you using multiple versions of cygwin1.dll?\n"
- "Run 'cygcheck -r -s -v' to find out.",
- inited, SHAREDVER);
+ if (version != SHARED_VERSION_MAGIC)
+ multiple_cygwin_problem ("shared", version, SHARED_VERSION);
+ else if (cb != SHARED_INFO_CB)
+ multiple_cygwin_problem ("shared size", cb, SHARED_INFO_CB);
return;
}
@@ -119,7 +105,11 @@ shared_info::initialize ()
/* Initialize tty table. */
tty.init ();
- inited = SHAREDVER;
+ version = SHARED_VERSION_MAGIC;
+ cb = sizeof (*this);
+ if (cb != SHARED_INFO_CB)
+ system_printf ("size of shared memory region changed from %u to %u",
+ SHARED_INFO_CB, cb);
}
void __stdcall
@@ -128,6 +118,7 @@ memory_init ()
/* Initialize general shared memory */
HANDLE shared_h = cygheap ? cygheap->shared_h : NULL;
cygwin_shared = (shared_info *) open_shared ("shared",
+ CYGWIN_VERSION_SHARED_DATA,
shared_h,
sizeof (*cygwin_shared),
cygwin_shared_address);
@@ -149,23 +140,34 @@ memory_init ()
}
cygheap->shared_h = shared_h;
- ProtectHandle (cygheap->shared_h);
+ ProtectHandleINH (cygheap->shared_h);
+ getpagesize ();
heap_init ();
- mount_table = (mount_info *) open_shared (user_name, cygwin_mount_h,
+ mount_table = (mount_info *) open_shared (user_name, MOUNT_VERSION,
+ cygwin_mount_h,
sizeof (mount_info), 0);
debug_printf ("opening mount table for '%s' at %p", cygheap->user.name (),
mount_table_address);
- ProtectHandle (cygwin_mount_h);
+ ProtectHandleINH (cygwin_mount_h);
debug_printf ("mount table version %x at %p", mount_table->version, mount_table);
/* Initialize the Cygwin per-user mount table, if necessary */
if (!mount_table->version)
{
- mount_table->version = MOUNT_VERSION;
+ mount_table->version = MOUNT_VERSION_MAGIC;
debug_printf ("initializing mount table");
+ mount_table->cb = sizeof (*mount_table);
+ if (mount_table->cb != MOUNT_INFO_CB)
+ system_printf ("size of mount table region changed from %u to %u",
+ MOUNT_INFO_CB, mount_table->cb);
mount_table->init (); /* Initialize the mount table. */
}
+ else if (mount_table->version != MOUNT_VERSION_MAGIC)
+ multiple_cygwin_problem ("mount", mount_table->version, MOUNT_VERSION);
+ else if (mount_table->cb != MOUNT_INFO_CB)
+ multiple_cygwin_problem ("mount table size", mount_table->cb, MOUNT_INFO_CB);
+
}
void __stdcall
@@ -201,110 +203,3 @@ shared_info::heap_chunk_size ()
return heap_chunk_in_mb << 20;
}
-
-/*
- * Function to return a common SECURITY_DESCRIPTOR * that
- * allows all access.
- */
-
-static NO_COPY SECURITY_DESCRIPTOR *null_sdp = 0;
-
-SECURITY_DESCRIPTOR *__stdcall
-get_null_sd ()
-{
- static NO_COPY SECURITY_DESCRIPTOR sd;
-
- if (null_sdp == 0)
- {
- InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
- SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
- null_sdp = &sd;
- }
- return null_sdp;
-}
-
-PSECURITY_ATTRIBUTES __stdcall
-sec_user (PVOID sa_buf, PSID sid2, BOOL inherit)
-{
- if (! sa_buf)
- return inherit ? &sec_none_nih : &sec_none;
-
- PSECURITY_ATTRIBUTES psa = (PSECURITY_ATTRIBUTES) sa_buf;
- PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)
- ((char *) sa_buf + sizeof (*psa));
- PACL acl = (PACL) ((char *) sa_buf + sizeof (*psa) + sizeof (*psd));
-
- cygsid sid;
-
- if (cygheap->user.sid ())
- sid = cygheap->user.sid ();
- else if (! lookup_name (getlogin (), cygheap->user.logsrv (), sid))
- return inherit ? &sec_none_nih : &sec_none;
-
- size_t acl_len = sizeof (ACL)
- + 4 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD))
- + GetLengthSid (sid)
- + GetLengthSid (well_known_admins_sid)
- + GetLengthSid (well_known_system_sid)
- + GetLengthSid (well_known_creator_owner_sid);
- if (sid2)
- acl_len += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)
- + GetLengthSid (sid2);
-
- if (! InitializeAcl (acl, acl_len, ACL_REVISION))
- debug_printf ("InitializeAcl %E");
-
- if (! AddAccessAllowedAce (acl, ACL_REVISION,
- SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL,
- sid))
- debug_printf ("AddAccessAllowedAce(%s) %E", getlogin ());
-
- if (! AddAccessAllowedAce (acl, ACL_REVISION,
- SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL,
- well_known_admins_sid))
- debug_printf ("AddAccessAllowedAce(admin) %E");
-
- if (! AddAccessAllowedAce (acl, ACL_REVISION,
- SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL,
- well_known_system_sid))
- debug_printf ("AddAccessAllowedAce(system) %E");
-
- if (! AddAccessAllowedAce (acl, ACL_REVISION,
- SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL,
- well_known_creator_owner_sid))
- debug_printf ("AddAccessAllowedAce(creator_owner) %E");
-
- if (sid2)
- if (! AddAccessAllowedAce (acl, ACL_REVISION,
- SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL,
- sid2))
- debug_printf ("AddAccessAllowedAce(sid2) %E");
-
- if (! InitializeSecurityDescriptor (psd,
- SECURITY_DESCRIPTOR_REVISION))
- debug_printf ("InitializeSecurityDescriptor %E");
-
-/*
- * Setting the owner lets the created security attribute not work
- * on NT4 SP3 Server. Don't know why, but the function still does
- * what it should do also if the owner isn't set.
-*/
-#if 0
- if (! SetSecurityDescriptorOwner (psd, sid, FALSE))
- debug_printf ("SetSecurityDescriptorOwner %E");
-#endif
-
- if (! SetSecurityDescriptorDacl (psd, TRUE, acl, FALSE))
- debug_printf ("SetSecurityDescriptorDacl %E");
-
- psa->nLength = sizeof (SECURITY_ATTRIBUTES);
- psa->lpSecurityDescriptor = psd;
- psa->bInheritHandle = inherit;
- return psa;
-}
-
-SECURITY_ATTRIBUTES *__stdcall
-sec_user_nih (PVOID sa_buf, PSID sid2)
-{
- return sec_user (sa_buf, sid2, FALSE);
-}
diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h
index 088b3f908..945bc17a6 100644
--- a/winsup/cygwin/shared_info.h
+++ b/winsup/cygwin/shared_info.h
@@ -17,7 +17,6 @@ class mount_item
public:
/* FIXME: Nasty static allocation. Need to have a heap in the shared
area [with the user being able to configure at runtime the max size]. */
-
/* Win32-style mounted partition source ("C:\foo\bar").
native_path[0] == 0 for unused entries. */
char native_path[MAX_PATH];
@@ -40,13 +39,21 @@ class mount_item
scheme should be satisfactory for a long while yet. */
#define MAX_MOUNTS 30
-#define MOUNT_VERSION 0x01010103
+#define MOUNT_VERSION 27 // increment when mount table changes and
+#define MOUNT_VERSION_MAGIC CYGWIN_VERSION_MAGIC (MOUNT_MAGIC, MOUNT_VERSION)
+#define CURR_MOUNT_MAGIC 0x4fe431cdU
+#define MOUNT_INFO_CB 16488
class reg_key;
+
+/* NOTE: Do not make gratuitous changes to the names or organization of the
+ below class. The layout is checksummed to determine compatibility between
+ different cygwin versions. */
class mount_info
{
public:
DWORD version;
+ unsigned cb;
DWORD sys_mount_table_counter;
int nmounts;
mount_item mount[MAX_MOUNTS];
@@ -87,17 +94,14 @@ class mount_info
int get_cygdrive_info (char *user, char *system, char* user_flags,
char* system_flags);
- void import_v1_mounts ();
-
private:
void sort ();
void read_mounts (reg_key& r);
- void read_v1_mounts (reg_key r, unsigned which);
void mount_slash ();
void to_registry ();
- int cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p);
+ int cygdrive_win32_path (const char *src, char *dst, int& unit);
void cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p);
void read_cygdrive_info_from_registry ();
};
@@ -128,9 +132,21 @@ public:
/******** Shared Info ********/
/* Data accessible to all tasks */
+#define SHARED_VERSION (unsigned)(cygwin_version.api_major << 8 | \
+ cygwin_version.api_minor)
+#define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (SHARED_MAGIC, SHARED_VERSION)
+
+#define SHARED_INFO_CB 47112
+
+#define CURR_SHARED_MAGIC 0x29eb8ccdU
+
+/* NOTE: Do not make gratuitous changes to the names or organization of the
+ below class. The layout is checksummed to determine compatibility between
+ different cygwin versions. */
class shared_info
{
- DWORD inited;
+ DWORD version;
+ DWORD cb;
public:
int heap_chunk_in_mb;
DWORD sys_mount_table_counter;
@@ -158,4 +174,4 @@ void __stdcall shared_terminate (void);
#define cygheap_address shared_align_past ((mount_info *) shared_align_past (cygwin_shared))
char *__stdcall shared_name (const char *, int);
-void *__stdcall open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr);
+void *__stdcall open_shared (const char *name, int n, HANDLE &shared_h, DWORD size, void *addr);
diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc
index dbe9bb0e9..94a86e2a8 100644
--- a/winsup/cygwin/shm.cc
+++ b/winsup/cygwin/shm.cc
@@ -1,499 +1,693 @@
-/* shm.cc: Single unix specification IPC interface for Cygwin
+/* shm.cc: Single unix specification IPC interface for Cygwin.
- Copyright 2001 Red Hat, Inc.
+ Copyright 2002 Red Hat, Inc.
- Originally written by Robert Collins <robert.collins@hotmail.com>
+ Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
+ Based on code by Robert Collins <robert.collins@hotmail.com>.
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
#include "winsup.h"
-#include <sys/stat.h>
+
+#include <sys/types.h>
+
+#include <assert.h>
#include <errno.h>
-#include "cygerrno.h"
-#include <unistd.h>
-#include "security.h"
-#include "fhandler.h"
-#include "path.h"
-#include "dtable.h"
-#include "cygheap.h"
#include <stdio.h>
-#include "thread.h"
-#include <sys/shm.h>
-#include "perprocess.h"
+#include <unistd.h>
+
+#include "cygerrno.h"
+#include "safe_memory.h"
+#include "sigproc.h"
+
+#include "cygserver_ipc.h"
#include "cygserver_shm.h"
-// FIXME IS THIS CORRECT
-/* Implementation notes: We use two shared memory regions per key:
- * One for the control structure, and one for the shared memory.
- * While this has a higher overhead tham a single shared area,
- * It allows more flexability. As the entire code is transparent to the user
- * We can merge these in the future should it be needed.
- */
-extern "C" size_t
-getsystemallocgranularity ()
-{
- SYSTEM_INFO sysinfo;
- static size_t buffer_offset = 0;
- if (buffer_offset)
- return buffer_offset;
- GetSystemInfo (&sysinfo);
- buffer_offset = sysinfo.dwAllocationGranularity;
- return buffer_offset;
-}
+/*---------------------------------------------------------------------------*
+ * class client_shmmgr
+ *
+ * A singleton class.
+ *---------------------------------------------------------------------------*/
-client_request_shm::client_request_shm (int ntype, int nshm_id):
-client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters))
-{
- buffer = (char *) &parameters;
- parameters.in.shm_id = nshm_id;
- parameters.in.type = SHM_REATTACH;
- parameters.in.pid = GetCurrentProcessId ();
-}
+#define shmmgr (client_shmmgr::instance ())
-client_request_shm::client_request_shm (int ntype, int nshm_id, pid_t npid):
-client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters))
+class client_shmmgr
{
- buffer = (char *) &parameters;
- parameters.in.shm_id = nshm_id;
- parameters.in.type = ntype;
- parameters.in.pid = npid;
-}
+private:
+ class segment_t
+ {
+ public:
+ const int shmid;
+ const void *const shmaddr;
+ const int shmflg;
+ HANDLE hFileMap; // Updated by fixup_shms_after_fork ().
-client_request_shm::client_request_shm (key_t nkey, size_t nsize,
- int nshmflg,
- char psdbuf[4096],
- pid_t npid):
-client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters))
-{
- buffer = (char *) &parameters;
- parameters.in.key = nkey;
- parameters.in.size = nsize;
- parameters.in.shmflg = nshmflg;
- parameters.in.type = SHM_CREATE;
- parameters.in.pid = npid;
- memcpy (parameters.in.sd_buf, psdbuf, 4096);
-}
+ segment_t *next;
-static shmnode *shm_head = NULL;
+ segment_t (const int shmid, const void *const shmaddr, const int shmflg,
+ const HANDLE hFileMap)
+ : shmid (shmid), shmaddr (shmaddr), shmflg (shmflg), hFileMap (hFileMap),
+ next (NULL)
+ {}
+ };
-static shmnode *
-build_inprocess_shmds (HANDLE hfilemap, HANDLE hattachmap, key_t key,
- int shm_id)
-{
- HANDLE filemap = hfilemap;
- void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0);
+public:
+ static client_shmmgr & instance ();
- if (!mapptr)
- {
- CloseHandle (hfilemap);
- CloseHandle (hattachmap);
- //FIXME: close filemap and free the mutex
- /* we couldn't access the mapped area with the requested permissions */
- set_errno (EACCES);
- return NULL;
- }
+ void *shmat (int shmid, const void *, int shmflg);
+ int shmctl (int shmid, int cmd, struct shmid_ds *);
+ int shmdt (const void *);
+ int shmget (key_t, size_t, int shmflg);
- /* Now get the user data */
- HANDLE attachmap = hattachmap;
- shmid_ds *shmtemp = new shmid_ds;
- if (!shmtemp)
- {
- system_printf ("failed to malloc shm node\n");
- set_errno (ENOMEM);
- UnmapViewOfFile (mapptr);
- CloseHandle (filemap);
- CloseHandle (attachmap);
- /* exit mutex */
- return NULL;
- }
+ int fixup_shms_after_fork ();
- /* get the system node data */
- *shmtemp = *(shmid_ds *) mapptr;
+private:
+ static NO_COPY client_shmmgr *_instance;
- /* process local data */
- shmnode *tempnode = new shmnode;
+ CRITICAL_SECTION _segments_lock;
+ static segment_t *_segments_head; // List of attached segs by shmaddr.
- tempnode->filemap = filemap;
- tempnode->attachmap = attachmap;
- shmtemp->mapptr = mapptr;
+ static long _shmat_cnt; // No. of attached segs; for info. only.
- /* no need for InterlockedExchange here, we're serialised by the global mutex */
- tempnode->shmds = shmtemp;
- tempnode->shm_id = shm_id;
- tempnode->key = key;
- tempnode->next = shm_head;
- tempnode->attachhead = NULL;
- shm_head = tempnode;
+ client_shmmgr ();
+ ~client_shmmgr ();
- /* FIXME: leave the system wide shm mutex */
+ // Undefined (as this class is a singleton):
+ client_shmmgr (const client_shmmgr &);
+ client_shmmgr & operator= (const client_shmmgr &);
- return tempnode;
-}
+ segment_t *find (const void *, segment_t **previous = NULL);
-int __stdcall
-fixup_shms_after_fork ()
-{
- shmnode *tempnode = shm_head;
- while (tempnode)
- {
- void *newshmds =
- MapViewOfFile (tempnode->filemap, FILE_MAP_WRITE, 0, 0, 0);
- if (!newshmds)
- {
- /* don't worry about handle cleanup, we're dying! */
- system_printf ("failed to reattach to shm control file view %x\n",
- tempnode);
- return 1;
- }
- tempnode->shmds = (class shmid_ds *) newshmds;
- tempnode->shmds->mapptr = newshmds;
- _shmattach *attachnode = tempnode->attachhead;
- while (attachnode)
- {
- void *newdata = MapViewOfFileEx (tempnode->attachmap,
- (attachnode->shmflg & SHM_RDONLY) ?
- FILE_MAP_READ : FILE_MAP_WRITE, 0,
- 0, 0, attachnode->data);
- if (newdata != attachnode->data)
- {
- /* don't worry about handle cleanup, we're dying! */
- system_printf ("failed to reattach to mapped file view %x\n",
- attachnode->data);
- return 1;
- }
- attachnode = attachnode->next;
- }
- tempnode = tempnode->next;
- }
- return 0;
-}
+ void *attach (int shmid, const void *, int shmflg, HANDLE & hFileMap);
-/* this is ugly. Yes, I know that.
- * FIXME: abstract the lookup functionality,
- * So that it can be an array, list, whatever without us being worried
- */
+ segment_t *new_segment (int shmid, const void *, int shmflg, HANDLE);
+};
-/* FIXME: after fork, every memory area needs to have the attach count
- * incremented. This should be done in the server?
- */
+/* static */ NO_COPY client_shmmgr *client_shmmgr::_instance;
-/* FIXME: tell the daemon when we attach, so at process close it can clean up
- * the attach count
+/* The following two variables must be inherited by child processes
+ * since they are used by fixup_shms_after_fork () to re-attach to the
+ * parent's shm segments.
*/
-extern "C" void *
-shmat (int shmid, const void *shmaddr, int shmflg)
+/* static */ client_shmmgr::segment_t *client_shmmgr::_segments_head;
+/* static */ long client_shmmgr::_shmat_cnt;
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::instance ()
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr &
+client_shmmgr::instance ()
{
- shmnode *tempnode = shm_head;
- while (tempnode && tempnode->shm_id != shmid)
- tempnode = tempnode->next;
+ if (!_instance)
+ _instance = safe_new0 (client_shmmgr);
- if (!tempnode)
- {
- /* couldn't find a currently open shm control area for the key - probably because
- * shmget hasn't been called.
- * Allocate a new control block - this has to be handled by the daemon */
- client_request_shm *req =
- new client_request_shm (SHM_REATTACH, shmid, GetCurrentProcessId ());
-
- int rc;
- if ((rc = cygserver_request (req)))
- {
- delete req;
- set_errno (ENOSYS); /* daemon communication failed */
- return (void *) -1;
- }
+ assert (_instance);
- if (req->header.error_code) /* shm_get failed in the daemon */
- {
- set_errno (req->header.error_code);
- delete req;
- return (void *) -1;
- }
+ return *_instance;
+}
- /* we've got the id, now we open the memory area ourselves.
- * This tests security automagically
- * FIXME: make this a method of shmnode ?
- */
- tempnode =
- build_inprocess_shmds (req->parameters.out.filemap,
- req->parameters.out.attachmap,
- req->parameters.out.key,
- req->parameters.out.shm_id);
- delete req;
- if (!tempnode)
- return (void *) -1;
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmat ()
+ *---------------------------------------------------------------------------*/
- }
+void *
+client_shmmgr::shmat (const int shmid,
+ const void *const shmaddr,
+ const int shmflg)
+{
+ syscall_printf ("shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)",
+ shmid, shmaddr, shmflg);
- class shmid_ds *shm = tempnode->shmds;
+ EnterCriticalSection (&_segments_lock);
- if (shmaddr)
- {
- //FIXME: requested base address ?! (Don't forget to fix the fixup_after_fork too)
- set_errno (EINVAL);
- return (void *) -1;
- }
+ HANDLE hFileMap = NULL;
- void *rv = MapViewOfFile (tempnode->attachmap,
- (shmflg & SHM_RDONLY) ? FILE_MAP_READ :
- FILE_MAP_WRITE, 0, 0, 0);
+ void *const ptr = attach (shmid, shmaddr, shmflg, hFileMap);
- if (!rv)
- {
- //FIXME: translate GetLastError()
- set_errno (EACCES);
- return (void *) -1;
- }
- /* tell the daemon we have attached */
- client_request_shm *req =
- new client_request_shm (SHM_ATTACH, shmid);
- int rc;
- if ((rc = cygserver_request (req)))
- {
- debug_printf ("failed to tell deaemon that we have attached\n");
- }
- delete req;
+ if (ptr)
+ new_segment (shmid, ptr, shmflg, hFileMap);
- _shmattach *attachnode = new _shmattach;
- attachnode->data = rv;
- attachnode->shmflg = shmflg;
- attachnode->next =
- (_shmattach *) InterlockedExchangePointer (&tempnode->attachhead,
- attachnode);
+ LeaveCriticalSection (&_segments_lock);
+ if (ptr)
+ syscall_printf ("%p = shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)",
+ ptr, shmid, shmaddr, shmflg);
+ // else
+ // See the syscall_printf in client_shmmgr::attach ().
- return rv;
+ return (ptr ? ptr : (void *) -1);
}
-/* FIXME: tell the daemon when we detach so it doesn't cleanup incorrectly.
- */
-extern "C" int
-shmdt (const void *shmaddr)
-{
- /* this should be "rare" so a hefty search is ok. If this is common, then we
- * should alter the data structs to allow more optimisation
- */
-
-}
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmctl ()
+ *---------------------------------------------------------------------------*/
-//FIXME: who is allowed to perform STAT?
-extern "C" int
-shmctl (int shmid, int cmd, struct shmid_ds *buf)
+int
+client_shmmgr::shmctl (const int shmid,
+ const int cmd,
+ struct shmid_ds *const buf)
{
- shmnode *tempnode = shm_head;
- while (tempnode && tempnode->shm_id != shmid)
- tempnode = tempnode->next;
- if (!tempnode)
+ syscall_printf ("shmctl (shmid = %d, cmd = 0x%x, buf = %p)",
+ shmid, cmd, buf);
+
+ // Check parameters and set up in parameters as required.
+
+ const struct shmid_ds *in_buf = NULL;
+
+ switch (cmd)
{
- /* couldn't find a currently open shm control area for the key - probably because
- * shmget hasn't been called.
- * Allocate a new control block - this has to be handled by the daemon */
- client_request_shm *req =
- new client_request_shm (SHM_REATTACH, shmid, GetCurrentProcessId ());
-
- int rc;
- if ((rc = cygserver_request (req)))
+ case IPC_SET:
+ if (__check_invalid_read_ptr_errno (buf, sizeof (struct shmid_ds)))
+ {
+ syscall_printf (("-1 [EFAULT] = "
+ "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
+ shmid, cmd, buf);
+ set_errno (EFAULT);
+ return -1;
+ }
+ in_buf = buf;
+ break;
+
+ case IPC_STAT:
+ case SHM_STAT:
+ if (__check_null_invalid_struct_errno (buf, sizeof (struct shmid_ds)))
+ {
+ syscall_printf (("-1 [EFAULT] = "
+ "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
+ shmid, cmd, buf);
+ set_errno (EFAULT);
+ return -1;
+ }
+ break;
+
+ case IPC_INFO:
+ if (__check_null_invalid_struct_errno (buf, sizeof (struct shminfo)))
{
- delete req;
- set_errno (ENOSYS); /* daemon communication failed */
+ syscall_printf (("-1 [EFAULT] = "
+ "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
+ shmid, cmd, buf);
+ set_errno (EFAULT);
return -1;
}
+ break;
- if (req->header.error_code) /* shm_get failed in the daemon */
+ case SHM_INFO:
+ if (__check_null_invalid_struct_errno (buf, sizeof (struct shm_info)))
{
- set_errno (req->header.error_code);
- delete req;
+ syscall_printf (("-1 [EFAULT] = "
+ "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
+ shmid, cmd, buf);
+ set_errno (EFAULT);
return -1;
}
+ break;
+ }
- /* we've got the id, now we open the memory area ourselves.
- * This tests security automagically
- * FIXME: make this a method of shmnode ?
- */
- tempnode =
- build_inprocess_shmds (req->parameters.out.filemap,
- req->parameters.out.attachmap,
- req->parameters.out.key,
- req->parameters.out.shm_id);
- delete req;
- if (!tempnode)
- return -1;
+ // Create and issue the command.
+
+ client_request_shm request (shmid, cmd, in_buf);
+
+ if (request.make_request () == -1 || request.error_code ())
+ {
+ syscall_printf (("-1 [%d] = "
+ "shmctl (shmid = %d, cmd = 0x%x, buf = %p)"),
+ request.error_code (), shmid, cmd, buf);
+ set_errno (request.error_code ());
+ return -1;
}
+ // Some commands require special processing for their out parameters.
+
+ int result = 0;
+
switch (cmd)
{
case IPC_STAT:
- buf->shm_perm = tempnode->shmds->shm_perm;
- buf->shm_segsz = tempnode->shmds->shm_segsz;
- buf->shm_lpid = tempnode->shmds->shm_lpid;
- buf->shm_cpid = tempnode->shmds->shm_cpid;
- buf->shm_nattch = tempnode->shmds->shm_nattch;
- buf->shm_atime = tempnode->shmds->shm_atime;
- buf->shm_dtime = tempnode->shmds->shm_dtime;
- buf->shm_ctime = tempnode->shmds->shm_ctime;
+ *buf = request.ds ();
break;
- case IPC_RMID:
- {
- /* TODO: check permissions. Or possibly, the daemon gets to be the only
- * one with write access to the memory area?
- */
- if (tempnode->shmds->shm_nattch)
- system_printf
- ("call to shmctl with cmd= IPC_RMID when memory area still has"
- " attachees\n");
- /* how does this work?
- * we mark the ds area as "deleted", and the at and get calls all fail from now on
- * on, when nattch becomes 0, the mapped data area is destroyed.
- * and each process, as they touch this area detaches. eventually only the
- * daemon has an attach. The daemon gets asked to detach immediately.
- */
-#if 0
-//waiting for the daemon to handle terminating process's
- client_request_shm *req =
- new client_request_shm (SHM_DEL, shmid, GetCurrentProcessId ());
- int rc;
- if ((rc = cygserver_request (req)))
- {
- delete req;
- set_errno (ENOSYS); /* daemon communication failed */
- return -1;
- }
-
- if (req->header.error_code) /* shm_del failed in the daemon */
- {
- set_errno (req->header.error_code);
- delete req;
- return -1;
- }
-
- /* the daemon has deleted it's references */
- /* now for us */
-
-#endif
- }
+ case IPC_INFO:
+ *(struct shminfo *) buf = request.shminfo ();
break;
- case IPC_SET:
- default:
+
+ case SHM_STAT: // ipcs(8) i'face.
+ result = request.shmid ();
+ *buf = request.ds ();
+ break;
+
+ case SHM_INFO: // ipcs(8) i'face.
+ result = request.shmid ();
+ *(struct shm_info *) buf = request.shm_info ();
+ break;
+ }
+
+ syscall_printf ("%d = shmctl (shmid = %d, cmd = 0x%x, buf = %p)",
+ result, shmid, cmd, buf);
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmdt ()
+ *
+ * According to Posix, the only error condition for this system call
+ * is EINVAL if shmaddr is not the address of the start of an attached
+ * shared memory segment. Given that, all other errors just generate
+ * tracing noise.
+ *---------------------------------------------------------------------------*/
+
+int
+client_shmmgr::shmdt (const void *const shmaddr)
+{
+ syscall_printf ("shmdt (shmaddr = %p)", shmaddr);
+
+ EnterCriticalSection (&_segments_lock);
+
+ segment_t *previous = NULL;
+
+ segment_t *const segptr = find (shmaddr, &previous);
+
+ if (!segptr)
+ {
+ LeaveCriticalSection (&_segments_lock);
+ syscall_printf ("-1 [EINVAL] = shmdt (shmaddr = %p)", shmaddr);
set_errno (EINVAL);
return -1;
}
+
+ assert (previous ? previous->next == segptr : _segments_head == segptr);
+
+ if (previous)
+ previous->next = segptr->next;
+ else
+ _segments_head = segptr->next;
+
+ LeaveCriticalSection (&_segments_lock);
+
+ const long cnt = InterlockedDecrement (&_shmat_cnt);
+ assert (cnt >= 0);
+
+ if (!UnmapViewOfFile ((void *) shmaddr))
+ syscall_printf (("failed to unmap view "
+ "[shmid = %d, handle = %p, shmaddr = %p]:"
+ "%E"),
+ segptr->shmid, segptr->hFileMap, shmaddr);
+
+ assert (segptr->hFileMap);
+
+ if (!CloseHandle (segptr->hFileMap))
+ syscall_printf (("failed to close file map handle "
+ "[shmid = %d, handle = %p]: %E"),
+ segptr->shmid, segptr->hFileMap);
+
+ client_request_shm request (segptr->shmid);
+
+ if (request.make_request () == -1 || request.error_code ())
+ syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s",
+ segptr->shmid, segptr->hFileMap,
+ strerror (request.error_code ()));
+
+ safe_delete (segptr);
+
+ syscall_printf ("0 = shmdt (shmaddr = %p)", shmaddr);
+
return 0;
}
-/* FIXME: evaluate getuid() and getgid() against the requested mode. Then
- * choose PAGE_READWRITE | PAGE_READONLY and FILE_MAP_WRITE | FILE_MAP_READ
- * appropriately
- */
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::shmget ()
+ *---------------------------------------------------------------------------*/
-/* FIXME: shmid should be a verifyable object
- */
-
-/* FIXME: on NT we should check everything against the SD. On 95 we just emulate.
- */
-extern "C" int
-shmget (key_t key, size_t size, int shmflg)
+int
+client_shmmgr::shmget (const key_t key, const size_t size, const int shmflg)
{
- DWORD sd_size = 4096;
- char sd_buf[4096];
- PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
- /* create a sd for our open requests based on shmflag & 0x01ff */
- psd = alloc_sd (getuid (), getgid (), cygheap->user.logsrv (),
- shmflg & 0x01ff, psd, &sd_size);
-
- if (key == (key_t) - 1)
+ syscall_printf ("shmget (key = 0x%016X, size = %u, shmflg = 0%o)",
+ key, size, shmflg);
+
+ client_request_shm request (key, size, shmflg);
+
+ if (request.make_request () == -1 || request.error_code ())
{
- set_errno (ENOENT);
+ syscall_printf (("-1 [%d] = "
+ "shmget (key = 0x%016X, size = %u, shmflg = 0%o)"),
+ request.error_code (),
+ key, size, shmflg);
+ set_errno (request.error_code ());
return -1;
}
- /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide
- * to prevent races on shmget.
- */
+ syscall_printf (("%d = shmget (key = 0x%016X, size = %u, shmflg = 0%o)"),
+ request.shmid (),
+ key, size, shmflg);
+
+ return request.shmid ();
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::fixup_shms_after_fork ()
+ *
+ * The hFileMap handles are non-inheritable: so they have to be
+ * re-acquired from cygserver.
+ *
+ * Nb. This routine need not be thread-safe as it is only called at startup.
+ *---------------------------------------------------------------------------*/
+
+int
+client_shmmgr::fixup_shms_after_fork ()
+{
+ debug_printf ("re-attaching to shm segments: %d attached", _shmat_cnt);
+
+ {
+ int length = 0;
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
+ length += 1;
+
+ if (_shmat_cnt != length)
+ {
+ system_printf (("state inconsistent: "
+ "_shmat_cnt = %d, length of segments list = %d"),
+ _shmat_cnt, length);
+ return 1;
+ }
+ }
+
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
+ if (!attach (segptr->shmid,
+ segptr->shmaddr,
+ segptr->shmflg & ~SHM_RND,
+ segptr->hFileMap))
+ {
+ system_printf ("fatal error re-attaching to shm segment %d",
+ segptr->shmid);
+ return 1;
+ }
+
+ if (_shmat_cnt)
+ debug_printf ("re-attached all %d shm segments", _shmat_cnt);
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::client_shmmgr ()
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr::client_shmmgr ()
+{
+ InitializeCriticalSection (&_segments_lock);
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::~client_shmmgr ()
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr::~client_shmmgr ()
+{
+ DeleteCriticalSection (&_segments_lock);
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::find ()
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr::segment_t *
+client_shmmgr::find (const void *const shmaddr, segment_t **previous)
+{
+ if (previous)
+ *previous = NULL;
+
+ for (segment_t *segptr = _segments_head; segptr; segptr = segptr->next)
+ if (segptr->shmaddr == shmaddr)
+ return segptr;
+ else if (segptr->shmaddr > shmaddr) // The list is sorted by shmaddr.
+ return NULL;
+ else if (previous)
+ *previous = segptr;
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::attach ()
+ *
+ * The body of shmat (), also used by fixup_shms_after_fork ().
+ *---------------------------------------------------------------------------*/
+
+void *
+client_shmmgr::attach (const int shmid,
+ const void *shmaddr,
+ const int shmflg,
+ HANDLE & hFileMap)
+{
+ client_request_shm request (shmid, shmflg);
+
+ if (request.make_request () == -1 || request.error_code ())
+ {
+ syscall_printf (("-1 [%d] = "
+ "shmat (shmid = %d, shmaddr = %p, shmflg = 0%o)"),
+ request.error_code (), shmid, shmaddr, shmflg);
+ set_errno (request.error_code ());
+ return NULL;
+ }
+
+ int result = 0;
+
+ const DWORD access = (shmflg & SHM_RDONLY) ? FILE_MAP_READ : FILE_MAP_WRITE;
+
+ if (shmaddr && (shmflg & SHM_RND))
+ shmaddr = (char *) shmaddr - ((ssize_t) shmaddr % SHMLBA);
+
+ void *const ptr =
+ MapViewOfFileEx (request.hFileMap (), access, 0, 0, 0, (void *) shmaddr);
- /* walk the list of currently open keys and return the id if found
- */
- shmnode *tempnode = shm_head;
- while (tempnode)
+ if (!ptr)
{
- if (tempnode->key == key && key != IPC_PRIVATE)
- {
- // FIXME: free the mutex
- if (size && tempnode->shmds->shm_segsz < size)
- {
- set_errno (EINVAL);
- return -1;
- }
- if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
- {
- set_errno (EEXIST);
- // FIXME: free the mutex
- return -1;
- }
- // FIXME: do we need to other tests of the requested mode with the
- // tempnode->shmid mode ? testcase on unix needed.
- // FIXME do we need a security test? We are only examining the keys we already have open.
- // FIXME: what are the sec implications for fork () if we don't check here?
- return tempnode->shm_id;
- }
- tempnode = tempnode->next;
+ syscall_printf (("failed to map view "
+ "[shmid = %d, handle = %p, shmaddr = %p]: %E"),
+ shmid, request.hFileMap (), shmaddr);
+ result = EINVAL; // FIXME
}
- /* couldn't find a currently open shm control area for the key.
- * Allocate a new control block - this has to be handled by the daemon */
- client_request_shm *req =
- new client_request_shm (key, size, shmflg, sd_buf,
- GetCurrentProcessId ());
-
- int rc;
- if ((rc = cygserver_request (req)))
+ else if (shmaddr && ptr != shmaddr)
{
- delete req;
- set_errno (ENOSYS); /* daemon communication failed */
- return -1;
+ syscall_printf (("failed to map view at requested address "
+ "[shmid = %d, handle = %p]: "
+ "requested address = %p, mapped address = %p"),
+ shmid, request.hFileMap (),
+ shmaddr, ptr);
+ result = EINVAL; // FIXME
}
- if (req->header.error_code) /* shm_get failed in the daemon */
+ if (result != 0)
{
- set_errno (req->header.error_code);
- delete req;
- return -1;
+ if (!CloseHandle (request.hFileMap ()))
+ syscall_printf (("failed to close file map handle "
+ "[shmid = %d, handle = %p]: %E"),
+ shmid, request.hFileMap ());
+
+ client_request_shm dt_req (shmid);
+
+ if (dt_req.make_request () == -1 || dt_req.error_code ())
+ syscall_printf ("shmdt request failed [shmid = %d, handle = %p]: %s",
+ shmid, request.hFileMap (),
+ strerror (dt_req.error_code ()));
+
+ set_errno (result);
+ return NULL;
}
- /* we've got the id, now we open the memory area ourselves.
- * This tests security automagically
- * FIXME: make this a method of shmnode ?
- */
- shmnode *shmtemp = build_inprocess_shmds (req->parameters.out.filemap,
- req->parameters.out.attachmap,
- key,
- req->parameters.out.shm_id);
- delete req;
- if (shmtemp)
- return shmtemp->shm_id;
- return -1;
-
-
-#if 0
- /* fill out the node data */
- shmtemp->shm_perm.cuid = getuid ();
- shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid;
- shmtemp->shm_perm.cgid = getgid ();
- shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid;
- shmtemp->shm_perm.mode = shmflg & 0x01ff;
- shmtemp->shm_lpid = 0;
- shmtemp->shm_nattch = 0;
- shmtemp->shm_atime = 0;
- shmtemp->shm_dtime = 0;
- shmtemp->shm_ctime = time (NULL);
- shmtemp->shm_segsz = size;
- *(shmid_ds *) mapptr = *shmtemp;
- shmtemp->filemap = filemap;
- shmtemp->attachmap = attachmap;
- shmtemp->mapptr = mapptr;
-
-#endif
+ hFileMap = request.hFileMap ();
+ return ptr;
+}
+
+/*---------------------------------------------------------------------------*
+ * client_shmmgr::new_segment ()
+ *
+ * Allocate a new segment for the given shmid, file map and address
+ * and insert into the segment map.
+ *---------------------------------------------------------------------------*/
+
+client_shmmgr::segment_t *
+client_shmmgr::new_segment (const int shmid,
+ const void *const shmaddr,
+ const int shmflg,
+ const HANDLE hFileMap)
+{
+ assert (ipc_ext2int_subsys (shmid) == IPC_SHMOP);
+ assert (hFileMap);
+ assert (shmaddr);
+
+ segment_t *previous = NULL; // Insert pointer.
+
+ const segment_t *const tmp = find (shmaddr, &previous);
+
+ assert (!tmp);
+ assert (previous \
+ ? (!previous->next || previous->next->shmaddr > shmaddr) \
+ : (!_segments_head || _segments_head->shmaddr > shmaddr));
+
+ segment_t *const segptr =
+ safe_new (segment_t, shmid, shmaddr, shmflg, hFileMap);
+
+ assert (segptr);
+
+ if (previous)
+ {
+ segptr->next = previous->next;
+ previous->next = segptr;
+ }
+ else
+ {
+ segptr->next = _segments_head;
+ _segments_head = segptr;
+ }
+
+ const long cnt = InterlockedIncrement (&_shmat_cnt);
+ assert (cnt > 0);
+
+ return segptr;
+}
+
+/*---------------------------------------------------------------------------*
+ * shmat ()
+ *---------------------------------------------------------------------------*/
+
+extern "C" void *
+shmat (const int shmid, const void *const shmaddr, const int shmflg)
+{
+ sigframe thisframe (mainthread);
+ return shmmgr.shmat (shmid, shmaddr, shmflg);
+}
+
+/*---------------------------------------------------------------------------*
+ * shmctl ()
+ *---------------------------------------------------------------------------*/
+
+extern "C" int
+shmctl (const int shmid, const int cmd, struct shmid_ds *const buf)
+{
+ sigframe thisframe (mainthread);
+ return shmmgr.shmctl (shmid, cmd, buf);
+}
+
+/*---------------------------------------------------------------------------*
+ * shmdt ()
+ *---------------------------------------------------------------------------*/
+
+extern "C" int
+shmdt (const void *const shmaddr)
+{
+ sigframe thisframe (mainthread);
+ return shmmgr.shmdt (shmaddr);
+}
+
+/*---------------------------------------------------------------------------*
+ * shmget ()
+ *---------------------------------------------------------------------------*/
+
+extern "C" int
+shmget (const key_t key, const size_t size, const int shmflg)
+{
+ sigframe thisframe (mainthread);
+ return shmmgr.shmget (key, size, shmflg);
+}
+
+/*---------------------------------------------------------------------------*
+ * fixup_shms_after_fork ()
+ *---------------------------------------------------------------------------*/
+
+int __stdcall
+fixup_shms_after_fork ()
+{
+ return shmmgr.fixup_shms_after_fork ();
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const int shmid, const int shmflg)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmat;
+
+ _parameters.in.shmid = shmid;
+ _parameters.in.shmflg = shmflg;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+
+ msglen (sizeof (_parameters.in));
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const int shmid,
+ const int cmd,
+ const struct shmid_ds *const buf)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmctl;
+
+ _parameters.in.shmid = shmid;
+ _parameters.in.cmd = cmd;
+ if (buf)
+ _parameters.in.ds = *buf;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+
+ msglen (sizeof (_parameters.in));
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const int shmid)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmdt;
+
+ _parameters.in.shmid = shmid;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+
+ msglen (sizeof (_parameters.in));
+}
+
+/*---------------------------------------------------------------------------*
+ * client_request_shm::client_request_shm ()
+ *---------------------------------------------------------------------------*/
+
+client_request_shm::client_request_shm (const key_t key,
+ const size_t size,
+ const int shmflg)
+ : client_request (CYGSERVER_REQUEST_SHM, &_parameters, sizeof (_parameters))
+{
+ _parameters.in.shmop = SHMOP_shmget;
+
+ _parameters.in.key = key;
+ _parameters.in.size = size;
+ _parameters.in.shmflg = shmflg;
+
+ _parameters.in.cygpid = getpid ();
+ _parameters.in.winpid = GetCurrentProcessId ();
+ _parameters.in.uid = geteuid ();
+ _parameters.in.gid = getegid ();
+
+ msglen (sizeof (_parameters.in));
}
diff --git a/winsup/cygwin/shortcut.c b/winsup/cygwin/shortcut.c
deleted file mode 100644
index d0c511da5..000000000
--- a/winsup/cygwin/shortcut.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* shortcut.c: Read shortcuts. This part of the code must be in C because
- the C++ interface to COM doesn't work without -fvtable-thunk
- which is too dangerous to use.
-
- Copyright 2001 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#define WIN32_LEAN_AND_MEAN
-#include <shlobj.h>
-#include "winsup.h"
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <errno.h>
-#include "shortcut.h"
-
-/* TODO:
- Currently duplicated from path.h. Later rearrangement of path.h
- to allow including from plain C would be better. */
-/* This is needed to avoid including path.h which is a pure C++ header. */
-#define PATH_SYMLINK MOUNT_SYMLINK
-#define PATH_EXEC MOUNT_EXEC
-#define PATH_CYGWIN_EXEC MOUNT_CYGWIN_EXEC
-#define PATH_ALL_EXEC (PATH_CYGWIN_EXEC | PATH_EXEC)
-
-/* TODO: Ditto. */
-static BOOL
-has_exec_chars (const char *buf, int len)
-{
- return len >= 2 &&
- ((buf[0] == '#' && buf[1] == '!') ||
- (buf[0] == ':' && buf[1] == '\n') ||
- (buf[0] == 'M' && buf[1] == 'Z'));
-}
-
-char shortcut_header[SHORTCUT_HDR_SIZE];
-BOOL shortcut_initalized;
-
-void
-create_shortcut_header (void)
-{
- if (!shortcut_initalized)
- {
- shortcut_header[0] = 'L';
- shortcut_header[4] = '\001';
- shortcut_header[5] = '\024';
- shortcut_header[6] = '\002';
- shortcut_header[12] = '\300';
- shortcut_header[19] = 'F';
- shortcut_header[20] = '\f';
- shortcut_header[60] = '\001';
- shortcut_initalized = TRUE;
- }
-}
-
-static BOOL
-cmp_shortcut_header (const char *file_header)
-{
- create_shortcut_header ();
- return memcmp (shortcut_header, file_header, SHORTCUT_HDR_SIZE);
-}
-
-int
-check_shortcut (const char *path, DWORD fileattr, HANDLE h,
- char *contents, int *error, unsigned *pflags)
-{
- HRESULT hres;
- IShellLink *psl = NULL;
- IPersistFile *ppf = NULL;
- WCHAR wc_path[MAX_PATH];
- char file_header[SHORTCUT_HDR_SIZE];
- DWORD len = 0;
- int res = 0;
- DWORD got = 0;
-
- /* Initialize COM library. */
- CoInitialize (NULL);
-
- /* Get a pointer to the IShellLink interface. */
- hres = CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
- &IID_IShellLink, (void **)&psl);
- if (FAILED (hres))
- goto close_it;
- /* Get a pointer to the IPersistFile interface. */
- hres = psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, (void **)&ppf);
- if (FAILED (hres))
- goto close_it;
- /* Load the shortcut. */
- MultiByteToWideChar(CP_ACP, 0, path, -1, wc_path, MAX_PATH);
- hres = ppf->lpVtbl->Load (ppf, wc_path, STGM_READ);
- if (FAILED (hres))
- goto close_it;
- /* Read the files header information. This is used to check for a
- Cygwin or U/WIN shortcut or later to check for executable files. */
- if (!ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0))
- {
- *error = EIO;
- goto close_it;
- }
- /* Try the description (containing a POSIX path) first. */
- if (fileattr & FILE_ATTRIBUTE_READONLY)
- {
- /* Check header if the shortcut is really created by Cygwin or U/WIN. */
- if (got == SHORTCUT_HDR_SIZE && !cmp_shortcut_header (file_header))
- {
- hres = psl->lpVtbl->GetDescription (psl, contents, MAX_PATH);
- if (FAILED (hres))
- goto file_not_symlink;
- len = strlen (contents);
- }
- }
-#if TREAT_NATIVE_SHORTCUTS_AS_SYMLINKS
- /* No description or not R/O: Check the "official" path. */
- if (len == 0)
- {
- char full_path[MAX_PATH];
- WIN32_FIND_DATA wfd;
-
- /* Convert to full path (easy way) */
- if ((path[0] == '\\' && path[1] == '\\')
- || (_toupper (path[0]) >= 'A' && _toupper (path[0]) <= 'Z'
- && path[1] == ':'))
- len = 0;
- else
- {
- len = GetCurrentDirectory (MAX_PATH, full_path);
- if (path[0] == '\\')
- len = 2;
- else if (full_path[len - 1] != '\\')
- strcpy (full_path + len++, "\\");
- }
- strcpy (full_path + len, path);
- /* Set relative path inside of IShellLink interface. */
- hres = psl->lpVtbl->SetRelativePath (psl, full_path, 0);
- if (FAILED (hres))
- goto file_not_symlink;
- /* Get the path to the shortcut target. */
- hres = psl->lpVtbl->GetPath (psl, contents, MAX_PATH, &wfd, 0);
- if (FAILED(hres))
- goto file_not_symlink;
- }
-#endif
- res = strlen (contents);
- if (res) /* It's a symlink. */
- *pflags = PATH_SYMLINK;
- goto close_it;
-
-file_not_symlink:
- /* Not a symlink, see if executable. */
- if (!(*pflags & PATH_ALL_EXEC) && has_exec_chars (file_header, got))
- *pflags |= PATH_EXEC;
-
-close_it:
- /* Release the pointer to IPersistFile. */
- if (ppf)
- ppf->lpVtbl->Release(ppf);
- /* Release the pointer to IShellLink. */
- if (psl)
- psl->lpVtbl->Release(psl);
- /* Uninitialize COM library. */
- CoUninitialize ();
- CloseHandle (h);
-
- return res;
-}
diff --git a/winsup/cygwin/shortcut.h b/winsup/cygwin/shortcut.h
deleted file mode 100644
index 87e7ff156..000000000
--- a/winsup/cygwin/shortcut.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* shortcut.h: Hader file for shortcut.c
-
- Copyright 2001 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The header written to a shortcut by Cygwin or U/WIN. */
-#define SHORTCUT_HDR_SIZE 76
-
-extern char shortcut_header[];
-extern BOOL shortcut_initalized;
-
-extern void create_shortcut_header ();
-
-int check_shortcut (const char *path, DWORD fileattr, HANDLE h,
- char *contents, int *error, unsigned *pflags);
-
-#ifdef __cplusplus
-};
-#endif
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index 70671b884..5b42a1ff1 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -1,6 +1,6 @@
/* signal.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com
Significant changes by Sergey Okhapkin <sos@prospect.com.ru>
@@ -13,9 +13,9 @@ details. */
#include "winsup.h"
#include <errno.h>
+#include <stdlib.h>
#include "cygerrno.h"
#include <sys/cygwin.h>
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
@@ -56,6 +56,9 @@ signal (int sig, _sig_func_ptr func)
prev = myself->getsig (sig).sa_handler;
myself->getsig (sig).sa_handler = func;
myself->getsig (sig).sa_mask = 0;
+ /* SA_RESTART is set to maintain BSD compatible signal behaviour by default.
+ This is also compatible to the behaviour of signal(2) in Linux. */
+ myself->getsig (sig).sa_flags |= SA_RESTART;
set_sigcatchers (prev, func);
syscall_printf ("%p = signal (%d, %p)", prev, sig, func);
@@ -187,6 +190,7 @@ _raise (int sig)
int
_kill (pid_t pid, int sig)
{
+ sigframe thisframe (mainthread);
syscall_printf ("kill (%d, %d)", pid, sig);
/* check that sig is in right range */
if (sig < 0 || sig >= NSIG)
@@ -211,6 +215,7 @@ kill_pgrp (pid_t pid, int sig)
int res = 0;
int found = 0;
int killself = 0;
+ sigframe thisframe (mainthread);
sigproc_printf ("pid %d, signal %d", pid, sig);
@@ -254,6 +259,31 @@ killpg (pid_t pgrp, int sig)
return _kill (-pgrp, sig);
}
+extern "C" void
+abort (void)
+{
+ sigframe thisframe (mainthread);
+ /* Flush all streams as per SUSv2.
+ From my reading of this document, this isn't strictly correct.
+ The streams are supposed to be flushed prior to exit. However,
+ if there is I/O in any signal handler that will not necessarily
+ be flushed.
+ However this is the way FreeBSD does it, and it is much easier to
+ do things this way, so... */
+ if (_reent_clib ()->__cleanup)
+ _reent_clib ()->__cleanup (_reent_clib ());
+
+ /* Ensure that SIGABRT can be caught regardless of blockage. */
+ sigset_t sig_mask;
+ sigfillset (&sig_mask);
+ sigdelset (&sig_mask, SIGABRT);
+ set_process_mask (sig_mask);
+
+ _raise (SIGABRT);
+ (void) thisframe.call_signal_handler (); /* Call any signal handler */
+ do_exit (1); /* signal handler didn't exit. Goodbye. */
+}
+
extern "C" int
sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
{
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 7b55487bb..091065241 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -1,6 +1,6 @@
/* sigproc.cc: inter/intra signal and sub process handler
- Copyright 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Christopher Faylor <cgf@cygnus.com>
@@ -17,6 +17,7 @@ details. */
#include <errno.h>
#include <stdlib.h>
#include <sys/cygwin.h>
+#include <assert.h>
#include "cygerrno.h"
#include "sync.h"
#include "sigproc.h"
@@ -26,11 +27,11 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "child_info.h"
+#include "child_info_magic.h"
#define NEED_VFORK
#include "perthread.h"
-#include <assert.h>
#include "shared_info.h"
+#include "cygthread.h"
/*
* Convenience defines
@@ -79,34 +80,38 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has
Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit
Static DWORD sig_loop_wait = INFINITE; // Wait for signals to arrive
-Static HANDLE sigcatch_nonmain = NULL; // The semaphore signaled when
+Static HANDLE sigcatch_nonmain; // The semaphore signaled when
// signals are available for
// processing from non-main thread
-Static HANDLE sigcatch_main = NULL; // Signalled when main thread sends a
+Static HANDLE sigcatch_main; // Signalled when main thread sends a
// signal
-Static HANDLE sigcatch_nosync = NULL; // Signal wait_sig to scan sigtodo
+Static HANDLE sigcatch_nosync; // Signal wait_sig to scan sigtodo
// but not to bother with any
// synchronization
-Static HANDLE sigcomplete_main = NULL; // Event signaled when a signal has
+Static HANDLE sigcomplete_main; // Event signaled when a signal has
// finished processing for the main
// thread
-Static HANDLE sigcomplete_nonmain = NULL;// Semaphore raised for non-main
+Static HANDLE sigcomplete_nonmain; // Semaphore raised for non-main
// threads when a signal has finished
// processing
-Static HANDLE hwait_sig = NULL; // Handle of wait_sig thread
-Static HANDLE hwait_subproc = NULL; // Handle of sig_subproc thread
+HANDLE NO_COPY sigCONT; // Used to "STOP" a process
+Static cygthread *hwait_sig; // Handle of wait_sig thread
+Static cygthread *hwait_subproc; // Handle of sig_subproc thread
-Static HANDLE wait_sig_inited = NULL; // Control synchronization of
+Static HANDLE wait_sig_inited; // Control synchronization of
// message queue startup
/* Used by WaitForMultipleObjects. These are handles to child processes.
*/
-Static HANDLE events[PSIZE + 1] = {0}; // All my children's handles++
+Static HANDLE events[PSIZE + 1]; // All my children's handles++
#define hchildren (events + 1) // Where the children handles begin
-Static pinfo pchildren[PSIZE]; // All my children info
-Static int nchildren = 0; // Number of active children
-Static pinfo zombies[NZOMBIES]; // All my deceased children info
-Static int nzombies = 0; // Number of deceased children
+Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info
+Static int nchildren; // Number of active children
+Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info
+Static int nzombies; // Number of deceased children
+
+#define pchildren ((pinfo *) cpchildren)
+#define zombies ((pinfo *) czombies)
Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
Static waitq waitq_main; // Storage for main thread
@@ -164,19 +169,36 @@ out:
return res;
}
-__inline static void
-wait_for_me ()
+void __stdcall
+wait_for_sigthread ()
{
- /* See if this is the first signal call after initialization.
- * If so, wait for notification that all initialization has completed.
- * Then set the handle to NULL to avoid checking this again.
- */
- if (wait_sig_inited)
+ assert (wait_sig_inited);
+ (void) WaitForSingleObject (wait_sig_inited, INFINITE);
+ (void) ForceCloseHandle (wait_sig_inited);
+ wait_sig_inited = NULL;
+}
+
+/* Get the sync_proc_subproc muto to control access to
+ * children, zombie arrays.
+ * Attempt to handle case where process is exiting as we try to grab
+ * the mutex.
+ */
+static BOOL
+get_proc_lock (DWORD what, DWORD val)
+{
+ Static int lastwhat = -1;
+ if (!sync_proc_subproc)
+ return FALSE;
+ if (sync_proc_subproc->acquire (WPSP))
{
- (void) WaitForSingleObject (wait_sig_inited, INFINITE);
- (void) ForceCloseHandle (wait_sig_inited);
- wait_sig_inited = NULL;
+ lastwhat = what;
+ return TRUE;
}
+ if (!sync_proc_subproc)
+ return FALSE;
+ system_printf ("Couldn't aquire sync_proc_subproc for(%d,%d), %E, last %d",
+ what, val, lastwhat);
+ return TRUE;
}
static BOOL __stdcall
@@ -184,7 +206,7 @@ proc_can_be_signalled (_pinfo *p)
{
if (p == myself_nowait || p == myself_nowait_nonmain || p == myself)
{
- wait_for_me ();
+ assert (!wait_sig_inited);
return 1;
}
@@ -205,7 +227,7 @@ pid_exists (pid_t pid)
BOOL __stdcall
proc_exists (_pinfo *p)
{
- return p && !(p->process_state & (PID_INITIALIZING | PID_EXITED));
+ return p && !(p->process_state & PID_EXITED);
}
/* Return 1 if this is one of our children, zero otherwise.
@@ -292,12 +314,14 @@ proc_subproc (DWORD what, DWORD val)
if (hchildren[val] != pchildren[val]->hProcess)
{
sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p",
- pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
- ForceCloseHandle1 (hchildren[val], childhProc);
+ pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
+ HANDLE h = hchildren[val];
hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */
+ sync_proc_subproc->release (); // Release the lock ASAP
+ ForceCloseHandle1 (h, childhProc);
ProtectHandle1 (pchildren[val]->hProcess, childhProc);
rc = 0;
- break; // This was an exec()
+ goto out; // This was an exec()
}
sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
@@ -432,22 +456,12 @@ proc_terminate (void)
/* Signal processing is assumed to be blocked in this routine. */
if (hwait_subproc)
{
- int rc;
proc_loop_wait = 0; // Tell wait_subproc thread to exit
wake_wait_subproc (); // Wake wait_subproc loop
-
- /* Wait for wait_subproc thread to exit (but not *too* long) */
- if ((rc = WaitForSingleObject (hwait_subproc, WWSP)) != WAIT_OBJECT_0)
- if (rc == WAIT_TIMEOUT)
- system_printf ("WFSO(hwait_subproc) timed out");
- else
- system_printf ("WFSO(hwait_subproc), rc %d, %E", rc);
-
- HANDLE h = hwait_subproc;
+ hwait_subproc->detach ();
hwait_subproc = NULL;
- ForceCloseHandle1 (h, hwait_subproc);
- sync_proc_subproc->acquire(WPSP);
+ sync_proc_subproc->acquire (WPSP);
(void) proc_subproc (PROC_CLEARWAIT, 1);
/* Clean out zombie processes from the pid list. */
@@ -460,7 +474,7 @@ proc_terminate (void)
ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle);
}
zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
- zombies[i].release(); // FIXME: this breaks older gccs for some reason
+ zombies[i].release (); // FIXME: this breaks older gccs for some reason
}
/* Disassociate my subprocesses */
@@ -517,7 +531,7 @@ sig_dispatch_pending (int justwake)
#endif
else
{
- wait_for_me ();
+ assert (!wait_sig_inited);
if (!justwake)
(void) sig_send (myself, __SIGFLUSH);
else if (ReleaseSemaphore (sigcatch_nosync, 1, NULL))
@@ -550,21 +564,15 @@ sigproc_init ()
/* local event signaled when main thread has been dispatched
to a signal handler function. */
- signal_arrived = CreateEvent(&sec_none_nih, TRUE, FALSE, NULL);
+ signal_arrived = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
ProtectHandle (signal_arrived);
- if (!(hwait_sig = makethread (wait_sig, NULL, 0, "sig")))
- {
- system_printf ("cannot create wait_sig thread, %E");
- api_fatal ("terminating");
- }
-
- ProtectHandle (hwait_sig);
+ hwait_sig = new cygthread (wait_sig, cygself, "sig");
/* sync_proc_subproc is used by proc_subproc. It serialises
* access to the children and zombie arrays.
*/
- sync_proc_subproc = new_muto (FALSE, "sync_proc_subproc");
+ new_muto (sync_proc_subproc);
/* Initialize waitq structure for main thread. A waitq structure is
* allocated for each thread that executes a wait to allow multiple threads
@@ -588,7 +596,6 @@ sigproc_init ()
void __stdcall
sigproc_terminate (void)
{
- HANDLE h = hwait_sig;
hwait_sig = NULL;
if (GetCurrentThreadId () == sigtid)
@@ -610,29 +617,6 @@ sigproc_terminate (void)
sigproc_printf ("entering");
sig_loop_wait = 0; // Tell wait_sig to exit when it is
// finished with anything it is doing
- // sig_dispatch_pending (TRUE); // wake up and die
- /* In case of a sigsuspend */
- SetEvent (signal_arrived);
-
- /* If !hwait_sig, then the process probably hasn't even finished
- * its initialization phase.
- */
- if (0 && hwait_sig)
- {
- if (GetCurrentThreadId () != sigtid)
- WaitForSingleObject (h, 10000);
- ForceCloseHandle1 (h, hwait_sig);
-
-
- if (GetCurrentThreadId () != sigtid)
- {
- ForceCloseHandle (sigcomplete_main);
- ForceCloseHandle (sigcomplete_nonmain);
- ForceCloseHandle (sigcatch_main);
- ForceCloseHandle (sigcatch_nonmain);
- ForceCloseHandle (sigcatch_nosync);
- }
- }
sigproc_printf ("done");
}
@@ -669,7 +653,7 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception)
{
if (no_signals_available ())
goto out; // Either exiting or not yet initializing
- wait_for_me ();
+ assert (!wait_sig_inited);
wait_for_completion = p != myself_nowait;
p = myself;
}
@@ -820,11 +804,9 @@ subproc_init (void)
* the hchildren array.
*/
events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
- if (!(hwait_subproc = makethread (wait_subproc, NULL, 0, "proc")))
- system_printf ("cannot create wait_subproc thread, %E");
+ hwait_subproc = new cygthread (wait_subproc, NULL, "proc");
ProtectHandle (events[0]);
- ProtectHandle (hwait_subproc);
- sigproc_printf ("started wait_subproc thread %p", hwait_subproc);
+ sigproc_printf ("started wait_subproc thread %p", (HANDLE) *hwait_subproc);
}
/* Initialize some of the memory block passed to child processes
@@ -834,11 +816,15 @@ void __stdcall
init_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready)
{
memset (ch, 0, sizeof *ch);
- ch->cb = sizeof *ch;
+ ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info);
+ ch->intro = PROC_MAGIC_GENERIC;
+ ch->magic = CHILD_INFO_MAGIC;
ch->type = chtype;
ch->cygpid = pid;
ch->subproc_ready = subproc_ready;
ch->pppid_handle = myself->ppid_handle;
+ ch->fhandler_union_cb = sizeof (fhandler_union);
+ ch->mount_h = cygwin_mount_h;
}
/* Check the state of all of our children to see if any are stopped or
@@ -899,7 +885,8 @@ getsem (_pinfo *p, const char *str, int init, int max)
set_errno (ESRCH);
return NULL;
}
- int wait = 10000;
+ int wait = 1000;
+ /* Wait for new process to generate its semaphores. */
sigproc_printf ("pid %d, ppid %d, wait %d, initializing %x", p->pid, p->ppid, wait,
ISSTATE (p, PID_INITIALIZING));
for (int i = 0; ISSTATE (p, PID_INITIALIZING) && i < wait; i++)
@@ -912,56 +899,33 @@ getsem (_pinfo *p, const char *str, int init, int max)
char sa_buf[1024];
DWORD winpid = GetCurrentProcessId ();
- h = CreateSemaphore (allow_ntsec ? sec_user_nih (sa_buf) : &sec_none_nih,
- init, max, str = shared_name (str, winpid));
+ h = CreateSemaphore (sec_user_nih (sa_buf), init, max,
+ str = shared_name (str, winpid));
p = myself;
+ if (!h)
+ {
+ system_printf ("can't create semaphore %s, %E", str);
+ __seterrno ();
+ }
}
else
{
h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
- str = shared_name (str, p->dwProcessId));
+ shared_name (str, p->dwProcessId));
- if (h == NULL)
+ if (!h)
{
if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p))
- set_errno (ESRCH);
+ set_errno (ESRCH); /* No such process */
else
- set_errno (EPERM);
- return NULL;
+ set_errno (EPERM); /* Couldn't access the semaphore --
+ different cygwin DLL maybe? */
}
}
- if (!h)
- {
- system_printf ("can't %s %s, %E", p ? "open" : "create", str);
- set_errno (ESRCH);
- }
return h;
}
-/* Get the sync_proc_subproc muto to control access to
- * children, zombie arrays.
- * Attempt to handle case where process is exiting as we try to grab
- * the mutex.
- */
-static BOOL
-get_proc_lock (DWORD what, DWORD val)
-{
- Static int lastwhat = -1;
- if (!sync_proc_subproc)
- return FALSE;
- if (sync_proc_subproc->acquire (WPSP))
- {
- lastwhat = what;
- return TRUE;
- }
- if (!sync_proc_subproc)
- return FALSE;
- system_printf ("Couldn't aquire sync_proc_subproc for(%d,%d), %E, last %d",
- what, val, lastwhat);
- return TRUE;
-}
-
/* Remove a zombie from zombies by swapping it with the last child in the list.
*/
static void __stdcall
@@ -1063,10 +1027,10 @@ stopped_or_terminated (waitq *parent_w, _pinfo *child)
* has been handled, as per POSIX.
*/
static DWORD WINAPI
-wait_sig (VOID *)
+wait_sig (VOID *self)
{
/* Initialization */
- (void) SetThreadPriority (hwait_sig, WAIT_SIG_PRIORITY);
+ (void) SetThreadPriority (*((cygthread *) self), WAIT_SIG_PRIORITY);
/* sigcatch_nosync - semaphore incremented by sig_dispatch_pending and
* by foreign processes to force an examination of
@@ -1085,6 +1049,7 @@ wait_sig (VOID *)
sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main);
+ sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
/* Setting dwProcessId flags that this process is now capable of receiving
* signals. Prior to this, dwProcessId was set to the windows pid of
@@ -1110,7 +1075,7 @@ wait_sig (VOID *)
debug_printf ("subproc_ready %p", child_proc_info->subproc_ready);
if (!SetEvent (child_proc_info->subproc_ready))
system_printf ("SetEvent (subproc_ready) failed, %E");
- ForceCloseHandle (child_proc_info->subproc_ready);
+ ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready);
/* Initialize an "indirect" pid block so that if someone looks up this
process via its Windows PID it will be redirected to the appropriate
Cygwin PID shared memory block. */
@@ -1178,15 +1143,15 @@ wait_sig (VOID *)
/* just forcing the loop */
break;
- /* Internal signal to force a flush of strace data to disk. */
+ /* Internal signal to turn on stracing. */
case __SIGSTRACE:
- // proc_strace (); // Dump cached strace.prntf stuff.
+ strace.hello ();
break;
/* A normal UNIX signal */
default:
sigproc_printf ("Got signal %d", sig);
- int wasdispatched = sig_handle (sig);
+ int wasdispatched = sig_handle (sig, rc != 2);
if (sig == SIGCHLD && wasdispatched)
dispatched_sigchld = 1;
/* Need to decrement again to offset increment below since
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
index 0afb02771..a461efdd6 100644
--- a/winsup/cygwin/sigproc.h
+++ b/winsup/cygwin/sigproc.h
@@ -1,6 +1,6 @@
/* sigproc.h
- Copyright 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -8,6 +8,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#ifndef _SIGPROC_H
+#define _SIGPROC_H
#include <signal.h>
#define EXIT_SIGNAL 0x010000
@@ -50,7 +52,7 @@ class sigframe
{
private:
sigthread *st;
- bool unregister ()
+ inline bool unregister ()
{
if (!st)
return 0;
@@ -64,7 +66,7 @@ private:
}
public:
- void set (sigthread &t, DWORD ebp, bool is_exception = 0)
+ inline void set (sigthread &t, DWORD ebp, bool is_exception = 0)
{
DWORD oframe = t.frame;
st = &t;
@@ -73,16 +75,16 @@ public:
if (!oframe)
t.get_winapi_lock ();
}
-
- sigframe (): st (NULL) {}
- sigframe (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0)) {init (t, ebp);}
- void init (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0))
+ inline void init (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0))
{
if (!t.frame && t.id == GetCurrentThreadId ())
set (t, ebp);
else
st = NULL;
}
+
+ sigframe (): st (NULL) {}
+ sigframe (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0)) {init (t, ebp);}
~sigframe ()
{
unregister ();
@@ -93,12 +95,13 @@ public:
extern sigthread mainthread;
extern HANDLE signal_arrived;
+extern HANDLE sigCONT;
BOOL __stdcall my_parent_is_alive ();
extern "C" int __stdcall sig_dispatch_pending (int force = FALSE);
extern "C" void __stdcall set_process_mask (sigset_t newmask);
extern "C" void __stdcall reset_signal_arrived ();
-int __stdcall sig_handle (int);
+int __stdcall sig_handle (int, bool);
void __stdcall sig_clear (int);
void __stdcall sig_set_pending (int);
int __stdcall handle_sigsuspend (sigset_t);
@@ -116,6 +119,7 @@ int __stdcall sig_send (_pinfo *, int, DWORD ebp = (DWORD) __builtin_frame_addre
bool exception = 0) __attribute__ ((regparm(3)));
void __stdcall signal_fixup_after_fork ();
void __stdcall signal_fixup_after_exec (bool);
+void __stdcall wait_for_sigthread ();
extern char myself_nowait_dummy[];
extern char myself_nowait_nonmain_dummy[];
@@ -124,3 +128,4 @@ extern char myself_nowait_nonmain_dummy[];
#define myself_nowait ((_pinfo *)myself_nowait_dummy)
#define myself_nowait_nonmain ((_pinfo *)myself_nowait_nonmain_dummy)
+#endif /*_SIGPROC_H*/
diff --git a/winsup/cygwin/smallprint.c b/winsup/cygwin/smallprint.c
index d6be72a6c..247fcf942 100644
--- a/winsup/cygwin/smallprint.c
+++ b/winsup/cygwin/smallprint.c
@@ -1,6 +1,6 @@
/* smallprint.c: small print routines for WIN32
- Copyright 1996, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -19,11 +19,11 @@ int __small_sprintf (char *dst, const char *fmt,...);
int __small_vsprintf (char *dst, const char *fmt, va_list ap);
static char *
-rn (char *dst, int base, int dosign, int val, int len, int pad)
+rn (char *dst, int base, int dosign, long long val, int len, int pad)
{
- /* longest number is 4294967295, 10 digits */
+ /* longest number is ULLONG_MAX, 18446744073709551615, 20 digits */
unsigned uval;
- char res[10];
+ char res[20];
static const char str[16] = "0123456789ABCDEF";
int l = 0;
@@ -126,9 +126,18 @@ __small_vsprintf (char *dst, const char *fmt, va_list ap)
case 'd':
dst = rn (dst, 10, addsign, va_arg (ap, int), len, pad);
break;
+ case 'D':
+ dst = rn (dst, 10, addsign, va_arg (ap, long long), len, pad);
+ break;
case 'u':
dst = rn (dst, 10, 0, va_arg (ap, int), len, pad);
break;
+ case 'U':
+ dst = rn (dst, 10, 0, va_arg (ap, long long), len, pad);
+ break;
+ case 'o':
+ dst = rn (dst, 8, 0, va_arg (ap, unsigned), len, pad);
+ break;
case 'p':
*dst++ = '0';
*dst++ = 'x';
@@ -136,6 +145,9 @@ __small_vsprintf (char *dst, const char *fmt, va_list ap)
case 'x':
dst = rn (dst, 16, 0, va_arg (ap, int), len, pad);
break;
+ case 'X':
+ dst = rn (dst, 16, 0, va_arg (ap, long long), len, pad);
+ break;
case 'P':
if (!GetModuleFileName (NULL, tmp, MAX_PATH))
s = "cygwin program";
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 0a0a84deb..193f593bc 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -1,6 +1,6 @@
/* spawn.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -21,12 +21,10 @@ details. */
#include <ctype.h>
#include "cygerrno.h"
#include <sys/cygwin.h>
-#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
#include "sigproc.h"
#include "cygheap.h"
#include "child_info.h"
@@ -48,6 +46,7 @@ static suffix_info std_suffixes[] =
};
HANDLE hExeced;
+DWORD dwExeced;
/* Add .exe to PROG if not already present and see if that exists.
If not, return PROG (converted from posix to win32 rules if necessary).
@@ -56,14 +55,14 @@ HANDLE hExeced;
Returns (possibly NULL) suffix */
static const char *
-perhaps_suffix (const char *prog, path_conv &buf)
+perhaps_suffix (const char *prog, path_conv& buf)
{
char *ext;
debug_printf ("prog '%s'", prog);
buf.check (prog, PC_SYM_FOLLOW | PC_FULL, std_suffixes);
- if (buf.isdir ())
+ if (!buf.exists () || buf.isdir ())
ext = NULL;
else if (buf.known_suffix)
ext = (char *) buf + (buf.known_suffix - buf.get_win32 ());
@@ -84,21 +83,34 @@ perhaps_suffix (const char *prog, path_conv &buf)
const char * __stdcall
find_exec (const char *name, path_conv& buf, const char *mywinenv,
- int null_if_notfound, const char **known_suffix)
+ unsigned opt, const char **known_suffix)
{
const char *suffix = "";
debug_printf ("find_exec (%s)", name);
- char *retval = buf;
+ const char *retval = buf;
+ char tmp[MAX_PATH];
+ const char *posix = (opt & FE_NATIVE) ? NULL : name;
+ bool has_slash = strchr (name, '/');
/* Check to see if file can be opened as is first.
Win32 systems always check . first, but PATH may not be set up to
do this. */
- if ((suffix = perhaps_suffix (name, buf)) != NULL)
- goto out;
+ if ((has_slash || opt & FE_CWD)
+ && (suffix = perhaps_suffix (name, buf)) != NULL)
+ {
+ if (posix && !has_slash)
+ {
+ tmp[0] = '.';
+ tmp[1] = '/';
+ strcpy (tmp + 2, name);
+ posix = tmp;
+ }
+ goto out;
+ }
win_env *winpath;
const char *path;
- char tmp[MAX_PATH];
+ const char *posix_path;
/* Return the error condition if this is an absolute path or if there
is no PATH to search. */
@@ -111,14 +123,17 @@ find_exec (const char *name, path_conv& buf, const char *mywinenv,
debug_printf ("%s%s", mywinenv, path);
+ posix = (opt & FE_NATIVE) ? NULL : tmp;
+ posix_path = winpath->get_posix () - 1;
/* Iterate over the specified path, looking for the file with and
without executable extensions. */
do
{
+ posix_path++;
char *eotmp = strccpy (tmp, &path, ';');
/* An empty path or '.' means the current directory, but we've
already tried that. */
- if (tmp[0] == '\0' || (tmp[0] == '.' && tmp[1] == '\0'))
+ if (opt & FE_CWD && (tmp[0] == '\0' || (tmp[0] == '.' && tmp[1] == '\0')))
continue;
*eotmp++ = '\\';
@@ -127,19 +142,34 @@ find_exec (const char *name, path_conv& buf, const char *mywinenv,
debug_printf ("trying %s", tmp);
if ((suffix = perhaps_suffix (tmp, buf)) != NULL)
- goto out;
+ {
+ if (posix == tmp)
+ {
+ eotmp = strccpy (tmp, &posix_path, ':');
+ if (eotmp == tmp)
+ *eotmp++ = '.';
+ *eotmp++ = '/';
+ strcpy (eotmp, name);
+ }
+ goto out;
+ }
}
- while (*path && *++path);
+ while (*path && *++path && (posix_path = strchr (posix_path, ':')));
errout:
+ posix = NULL;
/* Couldn't find anything in the given path.
Take the appropriate action based on null_if_not_found. */
- if (null_if_notfound)
+ if (opt & FE_NNF)
retval = NULL;
- else
+ else if (opt & FE_NATIVE)
buf.check (name);
+ else
+ retval = name;
out:
+ if (posix)
+ buf.set_path (posix);
debug_printf ("%s = find_exec (%s)", (char *) buf, name);
if (known_suffix)
*known_suffix = suffix ?: strchr (buf, '\0');
@@ -286,7 +316,7 @@ av::unshift (const char *what, int conv)
}
static int __stdcall
-spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
+spawn_guts (const char * prog_arg, const char *const *argv,
const char *const envp[], int mode)
{
BOOL rc;
@@ -322,21 +352,22 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
si.cbReserved2 = sizeof (ciresrv);
DWORD chtype;
- if (mode != _P_OVERLAY && mode != _P_VFORK)
+ if (mode != _P_OVERLAY)
chtype = PROC_SPAWN;
else
chtype = PROC_EXEC;
- HANDLE spr;
- if (mode != _P_OVERLAY)
- spr = NULL;
+ HANDLE subproc_ready;
+ if (chtype != PROC_EXEC)
+ subproc_ready = NULL;
else
{
- spr = CreateEvent (&sec_all, TRUE, FALSE, NULL);
- ProtectHandle (spr);
+ subproc_ready = CreateEvent (&sec_all, TRUE, FALSE, NULL);
+ ProtectHandleINH (subproc_ready);
}
- init_child_info (chtype, &ciresrv, (mode == _P_OVERLAY) ? myself->pid : 1, spr);
+ init_child_info (chtype, &ciresrv, (mode == _P_OVERLAY) ? myself->pid : 1,
+ subproc_ready);
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &ciresrv.parent, 0, 1,
DUPLICATE_SAME_ACCESS))
{
@@ -389,13 +420,10 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
that it is NOT a script file */
while (*ext == '\0')
{
- HANDLE hnd = CreateFileA (real_path,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_none_nih,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- 0);
+ HANDLE hnd = CreateFile (real_path, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sec_none_nih, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
if (hnd == INVALID_HANDLE_VALUE)
{
__seterrno ();
@@ -465,7 +493,9 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
if (arg1)
newargv.unshift (arg1);
- find_exec (pgm, real_path, "PATH=", 0, &ext);
+ /* FIXME: This should not be using FE_NATIVE. It should be putting
+ the posix path on the argv list. */
+ find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext);
newargv.unshift (real_path, 1);
}
@@ -529,18 +559,12 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
MALLOC_CHECK;
}
+ char *envblock;
newargv.all_calloced ();
ciresrv.moreinfo->argc = newargv.argc;
ciresrv.moreinfo->argv = newargv;
-
- ciresrv.moreinfo->envc = envsize (envp, 1);
- ciresrv.moreinfo->envp = (char **) cmalloc (HEAP_1_ARGV, ciresrv.moreinfo->envc);
ciresrv.hexec_proc = hexec_proc;
- char **c;
- const char * const *e;
- for (c = ciresrv.moreinfo->envp, e = envp; *e;)
- *c++ = cstrdup1 (*e++);
- *c = NULL;
+
if (mode != _P_OVERLAY ||
!DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc,
&ciresrv.moreinfo->myself_pinfo, 0,
@@ -572,72 +596,41 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
flags |= CREATE_SUSPENDED;
- /* Build windows style environment list */
- char *envblock;
- if (real_path.iscygexec ())
- envblock = NULL;
- else
- envblock = winenv (envp, 0);
-
- /* Preallocated buffer for `sec_user' call */
- char sa_buf[1024];
-
- if (!hToken && cygheap->user.impersonated
- && cygheap->user.token != INVALID_HANDLE_VALUE)
- hToken = cygheap->user.token;
-
const char *runpath = null_app_name ? NULL : (const char *) real_path;
- syscall_printf ("spawn_guts null_app_name %d (%s, %.132s)", null_app_name, runpath, one_line.buf);
+ syscall_printf ("null_app_name %d (%s, %.132s)", null_app_name, runpath, one_line.buf);
void *newheap;
+ /* Preallocated buffer for `sec_user' call */
+ char sa_buf[1024];
+
cygbench ("spawn-guts");
- if (!hToken)
+
+ if (!cygheap->user.issetuid ())
{
- ciresrv.moreinfo->uid = getuid ();
- /* FIXME: This leaks a handle in the CreateProcessAsUser case since the
- child process doesn't know about cygwin_mount_h. */
- ciresrv.mount_h = cygwin_mount_h;
+ PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf);
+ ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc,
+ real_path.iscygexec ());
newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ());
rc = CreateProcess (runpath, /* image name - with full path */
one_line.buf, /* what was passed to exec */
- /* process security attrs */
- allow_ntsec ? sec_user (sa_buf) : &sec_all_nih,
- /* thread security attrs */
- allow_ntsec ? sec_user (sa_buf) : &sec_all_nih,
- TRUE, /* inherit handles from parent */
+ sec_attribs, /* process security attrs */
+ sec_attribs, /* thread security attrs */
+ TRUE, /* inherit handles from parent */
flags,
- envblock,/* environment */
- 0, /* use current drive/directory */
+ envblock, /* environment */
+ 0, /* use current drive/directory */
&si,
&pi);
}
else
{
- cygsid sid;
- DWORD ret_len;
- if (!GetTokenInformation (hToken, TokenUser, &sid, sizeof sid, &ret_len))
- {
- sid = NO_SID;
- system_printf ("GetTokenInformation: %E");
- }
- /* Retrieve security attributes before setting psid to NULL
- since it's value is needed by `sec_user'. */
- PSECURITY_ATTRIBUTES sec_attribs = allow_ntsec && sid
- ? sec_user (sa_buf, sid)
- : &sec_all_nih;
-
- /* Remove impersonation */
- if (cygheap->user.impersonated
- && cygheap->user.token != INVALID_HANDLE_VALUE)
- RevertToSelf ();
-
- static BOOL first_time = TRUE;
- if (first_time)
- {
- set_process_privilege (SE_RESTORE_NAME);
- first_time = FALSE;
- }
+ PSID sid = cygheap->user.sid ();
+
+ /* Set security attributes with sid */
+ PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, sid);
+
+ RevertToSelf ();
/* Load users registry hive. */
load_registry_hive (sid);
@@ -649,7 +642,7 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
char wstname[1024];
char dskname[1024];
- ciresrv.moreinfo->uid = USHRT_MAX;
+ ciresrv.moreinfo->uid = ILLEGAL_UID;
hwst = GetProcessWindowStation ();
SetUserObjectSecurity (hwst, &dsi, get_null_sd ());
GetUserObjectInformation (hwst, UOI_NAME, wstname, 1024, &n);
@@ -660,23 +653,23 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
strcat (wstname, dskname);
si.lpDesktop = wstname;
+ ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc,
+ real_path.iscygexec ());
newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ());
- rc = CreateProcessAsUser (hToken,
+ rc = CreateProcessAsUser (cygheap->user.token,
runpath, /* image name - with full path */
one_line.buf, /* what was passed to exec */
sec_attribs, /* process security attrs */
sec_attribs, /* thread security attrs */
- TRUE, /* inherit handles from parent */
+ TRUE, /* inherit handles from parent */
flags,
- envblock,/* environment */
- 0, /* use current drive/directory */
+ envblock, /* environment */
+ 0, /* use current drive/directory */
&si,
&pi);
/* Restore impersonation. In case of _P_OVERLAY this isn't
allowed since it would overwrite child data. */
- if (mode != _P_OVERLAY && mode != _P_VFORK
- && cygheap->user.impersonated
- && cygheap->user.token != INVALID_HANDLE_VALUE)
+ if (mode != _P_OVERLAY)
ImpersonateLoggedOnUser (cygheap->user.token);
}
@@ -692,8 +685,8 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
{
__seterrno ();
syscall_printf ("CreateProcess failed, %E");
- if (spr)
- ForceCloseHandle (spr);
+ if (subproc_ready)
+ ForceCloseHandle (subproc_ready);
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
return -1;
}
@@ -728,6 +721,7 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
primarily for strace. */
strace.execing = 1;
hExeced = pi.hProcess;
+ dwExeced = pi.dwProcessId;
strcpy (myself->progname, real_path);
close_all_files ();
}
@@ -746,6 +740,13 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
child->hProcess = pi.hProcess;
child.remember ();
strcpy (child->progname, real_path);
+ /* FIXME: This introduces an unreferenced, open handle into the child.
+ The purpose is to keep the pid shared memory open so that all of
+ the fields filled out by child.remember do not disappear and so there
+ is not a brief period during which the pid is not available.
+ However, we should try to find another way to do this eventually. */
+ (void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
+ NULL, 0, 0, DUPLICATE_SAME_ACCESS);
/* Start the child running */
ResumeThread (pi.hThread);
}
@@ -754,9 +755,6 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
- if (hToken && hToken != cygheap->user.token)
- CloseHandle (hToken);
-
DWORD res;
BOOL exited;
@@ -766,7 +764,7 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
if (mode == _P_OVERLAY)
{
int nwait = 3;
- HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, spr};
+ HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready};
for (int i = 0; i < 100; i++)
{
switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE))
@@ -809,7 +807,7 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
break;
}
- ForceCloseHandle (spr);
+ ForceCloseHandle (subproc_ready);
sigproc_printf ("res = %x", res);
@@ -877,8 +875,8 @@ cwait (int *result, int pid, int)
*/
extern "C" int
-_spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv,
- const char *const *envp)
+spawnve (int mode, const char *path, const char *const *argv,
+ const char *const *envp)
{
int ret;
vfork_save *vf = vfork_storage.val ();
@@ -888,14 +886,14 @@ _spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv,
else
vf = NULL;
- syscall_printf ("_spawnve (%s, %s, %x)", path, argv[0], envp);
+ syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp);
switch (mode)
{
case _P_OVERLAY:
/* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/
/* Just act as an exec if _P_OVERLAY set. */
- spawn_guts (hToken, path, argv, envp, mode);
+ spawn_guts (path, argv, envp, mode);
/* Errno should be set by spawn_guts. */
ret = -1;
break;
@@ -905,12 +903,14 @@ _spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv,
case _P_WAIT:
case _P_DETACH:
subproc_init ();
- ret = spawn_guts (hToken, path, argv, envp, mode);
- if (vf && ret > 0)
+ ret = spawn_guts (path, argv, envp, mode);
+ if (vf)
{
debug_printf ("longjmping due to vfork");
- vf->pid = ret;
- longjmp (vf->j, 1);
+ if (ret < 0)
+ vf->restore_exit (ret);
+ else
+ vf->restore_pid (ret);
}
break;
default:
@@ -943,7 +943,7 @@ spawnl (int mode, const char *path, const char *arg0, ...)
va_end (args);
- return _spawnve (NULL, mode, path, (char * const *) argv, cur_environ ());
+ return spawnve (mode, path, (char * const *) argv, cur_environ ());
}
extern "C" int
@@ -965,8 +965,7 @@ spawnle (int mode, const char *path, const char *arg0, ...)
envp = va_arg (args, const char * const *);
va_end (args);
- return _spawnve (NULL, mode, path, (char * const *) argv,
- (char * const *) envp);
+ return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
}
extern "C" int
@@ -1014,14 +1013,7 @@ spawnlpe (int mode, const char *path, const char *arg0, ...)
extern "C" int
spawnv (int mode, const char *path, const char * const *argv)
{
- return _spawnve (NULL, mode, path, argv, cur_environ ());
-}
-
-extern "C" int
-spawnve (int mode, const char *path, char * const *argv,
- const char * const *envp)
-{
- return _spawnve (NULL, mode, path, argv, envp);
+ return spawnve (mode, path, argv, cur_environ ());
}
extern "C" int
@@ -1035,5 +1027,5 @@ spawnvpe (int mode, const char *file, const char * const *argv,
const char * const *envp)
{
path_conv buf;
- return _spawnve (NULL, mode, find_exec (file, buf), argv, envp);
+ return spawnve (mode, find_exec (file, buf), argv, envp);
}
diff --git a/winsup/cygwin/speclib b/winsup/cygwin/speclib
index f9c467685..6f8e0cd73 100755
--- a/winsup/cygwin/speclib
+++ b/winsup/cygwin/speclib
@@ -1,12 +1,23 @@
#!/bin/sh
+# speclib - Make a special version of the cygwin import library.
+#
+# Copyright 2001, 2002 Red Hat, Inc.
+#
+# This file is part of Cygwin.
+#
+# This software is a copyrighted work licensed under the terms of the
+# Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+# details.
+
case "$1" in
-v) v="-v"; shift
esac
lib=$1; shift
nm=$1; shift
dlltool=$1; shift
+as=$1; shift
def=$1; shift
-trap "rm /tmp/$$.def" 0 1 2 15
+trap "rm -f /tmp/$$.def" 0 1 2 15
(echo "LIBRARY cygwin1.dll
EXPORTS"; $nm --extern-only --defined-only $* | sed -e '/^[ ]*$/d' -e '/:$/d' -e 's/^.* _\(.*\)/\1/' | grep $v -f - -w $def |egrep -vi '^library|exports|^$' | sort) > /tmp/$$.def
-exec $dlltool -d /tmp/$$.def -l "$lib" -D /dev/null
+$dlltool --as=$as -d /tmp/$$.def -l "$lib"
diff --git a/winsup/cygwin/stackdump.sgml b/winsup/cygwin/stackdump.sgml
new file mode 100644
index 000000000..bff76bffd
--- /dev/null
+++ b/winsup/cygwin/stackdump.sgml
@@ -0,0 +1,13 @@
+<sect1 id="func-cygwin-stackdump">
+<title>cygwin_stackdump</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_stackdump</function></funcdef>
+<void>
+</funcsynopsis>
+
+<para> Outputs a stackdump to stderr from the called location.
+</para>
+
+</sect1>
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index 7ffea8501..4a8b48c3c 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -1,6 +1,6 @@
/* strace.cc: system/windows tracing
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -14,52 +14,58 @@ details. */
#include <wingdi.h>
#include <winuser.h>
#include <ctype.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
+#include "perprocess.h"
+#include "cygwin_version.h"
+#include "hires.h"
+#include "cygthread.h"
#define PROTECT(x) x[sizeof(x)-1] = 0
-#define CHECK(x) if (x[sizeof(x)-1] != 0) { small_printf("array bound exceeded %d\n", __LINE__); ExitProcess(1); }
+#define CHECK(x) if (x[sizeof(x)-1] != 0) { small_printf ("array bound exceeded %d\n", __LINE__); ExitProcess (1); }
-class NO_COPY strace strace;
-
-/* 'twould be nice to declare this in winsup.h but winsup.h doesn't require
- stdarg.h, so we declare it here instead. */
+class strace NO_COPY strace;
#ifndef NOSTRACE
-int
-strace::microseconds()
+void
+strace::hello ()
{
- static NO_COPY int first_microsec = 0;
- static NO_COPY long long hires_frequency = 0;
- static NO_COPY int hires_initted = 0;
-
- int microsec;
+ char buf[30];
- if (!hires_initted)
+ if (inited)
{
- hires_initted = 1;
- QueryPerformanceFrequency ((LARGE_INTEGER *) &hires_frequency);
- if (hires_frequency == 0)
- hires_initted = 2;
+ active ^= 1;
+ return;
}
- if (hires_initted == 2)
- {
- int count = GetTickCount ();
- microsec = count * 1000;
- }
- else
+
+ inited = 1;
+ if (!being_debugged ())
+ return;
+
+ __small_sprintf (buf, "cYg%8x %x", _STRACE_INTERFACE_ACTIVATE_ADDR, &active);
+ OutputDebugString (buf);
+
+ if (active)
{
- long long thiscount;
- QueryPerformanceCounter ((LARGE_INTEGER *) &thiscount);
- thiscount = (long long) (((double) thiscount/(double) hires_frequency)
- * 1000000.0);
- microsec = thiscount;
+ prntf (1, NULL, "**********************************************");
+ prntf (1, NULL, "Program name: %s (%d)", myself->progname, myself->pid ?: GetCurrentProcessId ());
+ prntf (1, NULL, "App version: %d.%d, api: %d.%d",
+ user_data->dll_major, user_data->dll_minor,
+ user_data->api_major, user_data->api_minor);
+ prntf (1, NULL, "DLL version: %d.%d, api: %d.%d",
+ cygwin_version.dll_major, cygwin_version.dll_minor,
+ cygwin_version.api_major, cygwin_version.api_minor);
+ prntf (1, NULL, "DLL build: %s", cygwin_version.dll_build_date);
+ prntf (1, NULL, "OS version: Windows %s", wincap.osname ());
+ prntf (1, NULL, "**********************************************");
}
- if (first_microsec == 0)
- first_microsec = microsec;
- return microsec - first_microsec;
+}
+
+int
+strace::microseconds ()
+{
+ static hires_us now;
+ return (int) now.usecs (true);
}
static int __stdcall
@@ -106,8 +112,8 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
char fmt[80];
static NO_COPY int nonewline = FALSE;
DWORD err = GetLastError ();
- const char *tn = threadname (0);
- char *pn = __progname ?: myself->progname;
+ const char *tn = cygthread::name ();
+ char *pn = __progname ?: (myself ? myself->progname : NULL);
int microsec = microseconds ();
lmicrosec = microsec;
@@ -133,7 +139,8 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
if ((p = strrchr (progname, '.')) != NULL && strcasematch (p, ".exe"))
*p = '\000';
p = progname;
- count = __small_sprintf (buf, fmt, p && *p ? p : "?", myself->pid,
+ count = __small_sprintf (buf, fmt, p && *p ? p : "?",
+ myself->pid ?: GetCurrentProcessId (),
execing ? "!" : "");
if (func)
count += getfunc (buf + count, func);
@@ -189,11 +196,11 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
int count;
char buf[10000];
- PROTECT(buf);
+ PROTECT (buf);
SetLastError (err);
count = this->vsprntf (buf, func, fmt, ap);
- CHECK(buf);
+ CHECK (buf);
if (category & _STRACE_SYSTEM)
{
DWORD done;
@@ -229,7 +236,7 @@ strace_printf (unsigned category, const char *func, const char *fmt, ...)
}
}
-static NO_COPY const struct tab
+static NO_COPY struct tab
{
int v;
const char *n;
diff --git a/winsup/cygwin/sync.cc b/winsup/cygwin/sync.cc
index 743ee02e7..b6dec83fa 100644
--- a/winsup/cygwin/sync.cc
+++ b/winsup/cygwin/sync.cc
@@ -4,7 +4,7 @@
which is intended to operate similarly to a mutex but attempts to
avoid making expensive calls to the kernel.
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
Written by Christopher Faylor <cgf@cygnus.com>
@@ -28,18 +28,24 @@ muto NO_COPY muto_start;
#undef WaitForSingleObject
/* Constructor */
-muto::muto (int inh, const char *s) : sync (0), visits(0), waiters(-1), tid (0), next (NULL)
+muto *
+muto::init (const char *s)
{
+ waiters = -1;
/* Create event which is used in the fallback case when blocking is necessary */
- if (!(bruteforce = CreateEvent (inh ? &sec_all_nih : &sec_none_nih, FALSE, FALSE, name)))
+ if (!(bruteforce = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL)))
{
DWORD oerr = GetLastError ();
SetLastError (oerr);
- return;
+ return NULL;
}
name = s;
+ next = muto_start.next;
+ muto_start.next = this;
+ return this;
}
+#if 0 /* FIXME: Do we need this? mutos aren't destroyed until process exit */
/* Destructor (racy?) */
muto::~muto ()
{
@@ -52,6 +58,7 @@ muto::~muto ()
if (h)
CloseHandle (h);
}
+#endif
/* Acquire the lock. Argument is the number of milliseconds to wait for
the lock. Multiple visits from the same thread are allowed and should
diff --git a/winsup/cygwin/sync.h b/winsup/cygwin/sync.h
index 9552801b3..9cd50c3ac 100644
--- a/winsup/cygwin/sync.h
+++ b/winsup/cygwin/sync.h
@@ -1,6 +1,6 @@
/* sync.h: Header file for cygwin synchronization primitives.
- Copyright 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Christopher Faylor <cgf@cygnus.com>
@@ -22,33 +22,28 @@ class muto
public:
class muto *next;
const char *name;
- void *operator new (size_t, void *p) {return p;}
- void *operator new (size_t) {return ::new muto; }
- void operator delete (void *) {;} /* can't handle allocated mutos
- currently */
- muto() {}
/* The real constructor. */
- muto(int inh, const char *name);
- ~muto ();
- int acquire (DWORD ms = INFINITE) __attribute__ ((regparm(1))); /* Acquire the lock. */
- int release (); /* Release the lock. */
+ muto *init(const char *name) __attribute__ ((regparm (3)));
+
+#if 0 /* FIXME: See comment in sync.cc */
+ ~muto ()
+#endif
+ int acquire (DWORD ms = INFINITE) __attribute__ ((regparm (2))); /* Acquire the lock. */
+ int release () __attribute__ ((regparm (1))); /* Release the lock. */
/* Return true if caller thread owns the lock. */
int ismine () {return tid == GetCurrentThreadId ();}
DWORD owner () {return tid;}
int unstable () {return !tid && (sync || waiters >= 0);}
- void reset ();
+ void reset () __attribute__ ((regparm (1)));
};
extern muto muto_start;
/* Use a statically allocated buffer as the storage for a muto */
-#define new_muto(__inh, __name) \
+#define new_muto(__name) \
({ \
- static __attribute__((section(".data_cygwin_nocopy"))) muto __mbuf; \
- (void) new ((char *) &__mbuf) muto (__inh, __name); \
- __mbuf.next = muto_start.next; \
- muto_start.next = &__mbuf; \
- &__mbuf; \
+ static muto __name##_storage __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy"))); \
+ __name = __name##_storage.init (#__name); \
})
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index f4e53db50..167e9c0f9 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1,6 +1,6 @@
/* syscalls.cc: syscalls
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,7 +11,6 @@ details. */
#include "winsup.h"
#include <sys/stat.h>
#include <sys/vfs.h> /* needed for statfs */
-#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
@@ -32,14 +31,14 @@ details. */
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include <unistd.h>
#include "shared_info.h"
#include "cygheap.h"
-
-extern int normalize_posix_path (const char *, char *);
+#define NEED_VFORK
+#include <setjmp.h>
+#include "perthread.h"
SYSTEM_INFO system_info;
@@ -65,33 +64,27 @@ close_all_files (void)
cygwin_shared->delqueue.process_queue ();
}
-static BOOL __stdcall
-check_ttys_fds (void)
+BOOL __stdcall
+check_pty_fds (void)
{
int res = FALSE;
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "close_all_files");
+ SetResourceLock (LOCK_FD_LIST, WRITE_LOCK, "check_pty_fds");
fhandler_base *fh;
for (int i = 0; i < (int) cygheap->fdtab.size; i++)
- if ((fh = cygheap->fdtab[i]) != NULL && fh->get_device() == FH_TTYS)
+ if ((fh = cygheap->fdtab[i]) != NULL &&
+ (fh->get_device () == FH_TTYS || fh->get_device () == FH_PTYM))
{
res = TRUE;
break;
}
- ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "close_all_files");
+ ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK, "check_pty_fds");
return res;
}
int
dup (int fd)
{
- int res;
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
-
- res = dup2 (fd, cygheap->fdtab.find_unused_handle ());
-
- ReleaseResourceLock(LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
-
- return res;
+ return cygheap->fdtab.dup2 (fd, cygheap_fdnew ());
}
int
@@ -104,6 +97,7 @@ extern "C" int
_unlink (const char *ourname)
{
int res = -1;
+ DWORD devn;
sigframe thisframe (mainthread);
path_conv win32_name (ourname, PC_SYM_NOFOLLOW | PC_FULL);
@@ -114,6 +108,13 @@ _unlink (const char *ourname)
goto done;
}
+ if ((devn = win32_name.get_devn ()) == FH_PROC || devn == FH_REGISTRY
+ || devn == FH_PROCESS)
+ {
+ set_errno (EROFS);
+ goto done;
+ }
+
syscall_printf ("_unlink (%s)", win32_name.get_win32 ());
if (!win32_name.exists ())
@@ -185,7 +186,7 @@ _unlink (const char *ourname)
bool delete_on_close_ok;
delete_on_close_ok = !win32_name.isremote ()
- && wincap.has_delete_on_close ();
+ && wincap.has_delete_on_close ();
/* Attempt to use "delete on close" semantics to handle removing
a file which may be open. */
@@ -203,7 +204,8 @@ _unlink (const char *ourname)
syscall_printf ("CreateFile/CloseHandle succeeded");
/* Everything is fine if the file has disappeared or if we know that the
FILE_FLAG_DELETE_ON_CLOSE will eventually work. */
- if (GetFileAttributes (win32_name) == (DWORD) -1 || delete_on_close_ok)
+ if (GetFileAttributes (win32_name) == INVALID_FILE_ATTRIBUTES
+ || delete_on_close_ok)
goto ok; /* The file is either gone already or will eventually be
deleted by the OS. */
}
@@ -266,11 +268,24 @@ getppid ()
extern "C" pid_t
setsid (void)
{
- if (myself->pgid != _getpid ())
+ vfork_save *vf = vfork_storage.val ();
+ /* This is a horrible, horrible kludge */
+ if (vf && vf->pid < 0)
{
- if (myself->ctty == TTY_CONSOLE &&
- !cygheap->fdtab.has_console_fds () &&
- !check_ttys_fds ())
+ pid_t pid = fork ();
+ if (pid > 0)
+ {
+ syscall_printf ("longjmping due to vfork");
+ vf->restore_pid (pid);
+ }
+ /* assuming that fork was successful */
+ }
+
+ if (myself->pgid != myself->pid)
+ {
+ if (myself->ctty == TTY_CONSOLE
+ && !cygheap->fdtab.has_console_fds ()
+ && !check_pty_fds ())
FreeConsole ();
myself->ctty = -1;
myself->sid = _getpid ();
@@ -278,54 +293,124 @@ setsid (void)
syscall_printf ("sid %d, pgid %d, ctty %d", myself->sid, myself->pgid, myself->ctty);
return myself->sid;
}
+
set_errno (EPERM);
return -1;
}
+extern "C" pid_t
+getsid (pid_t pid)
+{
+ pid_t res;
+ if (!pid)
+ res = myself->sid;
+ else
+ {
+ pinfo p (pid);
+ if (p)
+ res = p->sid;
+ else
+ {
+ set_errno (ESRCH);
+ res = -1;
+ }
+ }
+ return res;
+}
+
extern "C" ssize_t
_read (int fd, void *ptr, size_t len)
{
- int res;
- fhandler_base *fh;
+ const struct iovec iov =
+ {
+ iov_base: ptr,
+ iov_len: len
+ };
+
+ return readv (fd, &iov, 1);
+}
+
+extern "C" ssize_t
+_write (int fd, const void *ptr, size_t len)
+{
+ const struct iovec iov =
+ {
+ iov_base: (void *) ptr, // const_cast
+ iov_len: len
+ };
+
+ return writev (fd, &iov, 1);
+}
+
+extern "C" ssize_t
+readv (int fd, const struct iovec *const iov, const int iovcnt)
+{
extern int sigcatchers;
- int e = get_errno ();
+ const int e = get_errno ();
+
+ int res = -1;
+
+ const ssize_t tot = check_iovec_for_read (iov, iovcnt);
+
+ if (tot <= 0)
+ {
+ res = tot;
+ goto done;
+ }
while (1)
{
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ break;
+
+ if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
{
set_errno (EBADF);
- return -1;
+ break;
}
- // set_sig_errno (0);
- fh = cygheap->fdtab[fd];
- DWORD wait = fh->is_nonblocking () ? 0 : INFINITE;
+ DWORD wait = cfd->is_nonblocking () ? 0 : INFINITE;
/* Could block, so let user know we at least got here. */
- syscall_printf ("read (%d, %p, %d) %sblocking, sigcatchers %d", fd, ptr, len, wait ? "" : "non", sigcatchers);
+ syscall_printf ("readv (%d, %p, %d) %sblocking, sigcatchers %d",
+ fd, iov, iovcnt, wait ? "" : "non", sigcatchers);
- if (wait && (/*!sigcatchers || */!fh->is_slow () || fh->get_r_no_interrupt ()))
- debug_printf ("non-interruptible read\n");
- else if (!fh->ready_for_read (fd, wait, 0))
+ if (wait && (!cfd->is_slow () || cfd->get_r_no_interrupt ()))
+ debug_printf ("no need to call ready_for_read\n");
+ else if (!cfd->ready_for_read (fd, wait))
{
- if (!wait)
- set_sig_errno (EAGAIN); /* Don't really need 'set_sig_errno' here, but... */
- else
- set_sig_errno (EINTR);
res = -1;
goto out;
}
+ /* FIXME: This is not thread safe. We need some method to
+ ensure that an fd, closed in another thread, aborts I/O
+ operations. */
+ if (!cfd.isopen ())
+ break;
+
/* Check to see if this is a background read from a "tty",
sending a SIGTTIN, if appropriate */
- res = fh->bg_check (SIGTTIN);
+ res = cfd->bg_check (SIGTTIN);
+
+ if (!cfd.isopen ())
+ {
+ res = -1;
+ break;
+ }
+
if (res > bg_eof)
{
myself->process_state |= PID_TTYIN;
- res = fh->read (ptr, len);
+ if (!cfd.isopen ())
+ {
+ res = -1;
+ break;
+ }
+ res = cfd->readv (iov, iovcnt, tot);
myself->process_state &= ~PID_TTYIN;
}
@@ -335,19 +420,31 @@ _read (int fd, void *ptr, size_t len)
set_errno (e);
}
- syscall_printf ("%d = read (%d<%s>, %p, %d), bin %d, errno %d", res, fd, fh->get_name (),
- ptr, len, fh->get_r_binary (), get_errno ());
+done:
+ syscall_printf ("%d = readv (%d, %p, %d), errno %d", res, fd, iov, iovcnt,
+ get_errno ());
MALLOC_CHECK;
return res;
}
extern "C" ssize_t
-_write (int fd, const void *ptr, size_t len)
+writev (const int fd, const struct iovec *const iov, const int iovcnt)
{
int res = -1;
+ const ssize_t tot = check_iovec_for_write (iov, iovcnt);
+
sigframe thisframe (mainthread);
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ goto done;
- if (cygheap->fdtab.not_open (fd))
+ if (tot <= 0)
+ {
+ res = tot;
+ goto done;
+ }
+
+ if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
{
set_errno (EBADF);
goto done;
@@ -355,118 +452,29 @@ _write (int fd, const void *ptr, size_t len)
/* Could block, so let user know we at least got here. */
if (fd == 1 || fd == 2)
- paranoid_printf ("write (%d, %p, %d)", fd, ptr, len);
+ paranoid_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
else
- syscall_printf ("write (%d, %p, %d)", fd, ptr, len);
-
- fhandler_base *fh;
- fh = cygheap->fdtab[fd];
+ syscall_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
- res = fh->bg_check (SIGTTOU);
+ res = cfd->bg_check (SIGTTOU);
if (res > bg_eof)
{
myself->process_state |= PID_TTYOU;
- res = fh->write (ptr, len);
+ res = cfd->writev (iov, iovcnt, tot);
myself->process_state &= ~PID_TTYOU;
}
done:
if (fd == 1 || fd == 2)
- paranoid_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len);
+ paranoid_printf ("%d = write (%d, %p, %d), errno %d",
+ res, fd, iov, iovcnt, get_errno ());
else
- syscall_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len);
+ syscall_printf ("%d = write (%d, %p, %d), errno %d",
+ res, fd, iov, iovcnt, get_errno ());
MALLOC_CHECK;
- return (ssize_t)res;
-}
-
-/*
- * FIXME - should really move this interface into fhandler, and implement
- * write in terms of it. There are devices in Win32 that could do this with
- * overlapped I/O much more efficiently - we should eventually use
- * these.
- */
-
-extern "C" ssize_t
-writev (int fd, const struct iovec *iov, int iovcnt)
-{
- int i;
- ssize_t len, total;
- char *base;
-
- if (iovcnt < 1 || iovcnt > IOV_MAX)
- {
- set_errno (EINVAL);
- return -1;
- }
-
- /* Ensure that the sum of the iov_len values is less than
- SSIZE_MAX (per spec), if so, we must fail with no output (per spec).
- */
- total = 0;
- for (i = 0; i < iovcnt; ++i)
- {
- total += iov[i].iov_len;
- if (total > SSIZE_MAX)
- {
- set_errno (EINVAL);
- return -1;
- }
- }
- /* Now write the data */
- for (i = 0, total = 0; i < iovcnt; i++, iov++)
- {
- len = iov->iov_len;
- base = iov->iov_base;
- while (len > 0)
- {
- register int nbytes;
- nbytes = write (fd, base, len);
- if (nbytes < 0 && total == 0)
- return -1;
- if (nbytes <= 0)
- return total;
- len -= nbytes;
- total += nbytes;
- base += nbytes;
- }
- }
- return total;
-}
-
-/*
- * FIXME - should really move this interface into fhandler, and implement
- * read in terms of it. There are devices in Win32 that could do this with
- * overlapped I/O much more efficiently - we should eventually use
- * these.
- */
-
-extern "C" ssize_t
-readv (int fd, const struct iovec *iov, int iovcnt)
-{
- int i;
- ssize_t len, total;
- char *base;
-
- for (i = 0, total = 0; i < iovcnt; i++, iov++)
- {
- len = iov->iov_len;
- base = iov->iov_base;
- while (len > 0)
- {
- register int nbytes;
- nbytes = read (fd, base, len);
- if (nbytes < 0 && total == 0)
- return -1;
- if (nbytes <= 0)
- return total;
- len -= nbytes;
- total += nbytes;
- base += nbytes;
- }
- }
- return total;
+ return res;
}
/* _open */
@@ -475,51 +483,46 @@ readv (int fd, const struct iovec *iov, int iovcnt)
extern "C" int
_open (const char *unix_path, int flags, ...)
{
- int fd;
int res = -1;
va_list ap;
mode_t mode = 0;
- fhandler_base *fh;
sigframe thisframe (mainthread);
syscall_printf ("open (%s, %p)", unix_path, flags);
if (!check_null_empty_str_errno (unix_path))
{
- SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, " open ");
-
/* check for optional mode argument */
va_start (ap, flags);
mode = va_arg (ap, mode_t);
va_end (ap);
- fd = cygheap->fdtab.find_unused_handle ();
+ fhandler_base *fh;
+ cygheap_fdnew fd;
- if (fd < 0)
- set_errno (ENMFILE);
- else
+ if (fd >= 0)
{
path_conv pc;
- if (!(fh = cygheap->fdtab.build_fhandler (fd, unix_path, NULL, pc)))
+ if (!(fh = cygheap->fdtab.build_fhandler_from_name (fd, unix_path,
+ NULL, pc)))
res = -1; // errno already set
- else if (!fh->open (pc, flags, (mode & 07777) & ~cygheap->umask))
+ else if (!fh->open (&pc, flags, (mode & 07777) & ~cygheap->umask))
{
- cygheap->fdtab.release (fd);
+ fd.release ();
res = -1;
}
else if ((res = fd) <= 2)
set_std_handle (res);
}
- ReleaseResourceLock (LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," open");
}
syscall_printf ("%d = open (%s, %p)", res, unix_path, flags);
return res;
}
-extern "C" off_t
-_lseek (int fd, off_t pos, int dir)
+extern "C" __off64_t
+lseek64 (int fd, __off64_t pos, int dir)
{
- off_t res;
+ __off64_t res;
sigframe thisframe (mainthread);
if (dir != SEEK_SET && dir != SEEK_CUR && dir != SEEK_END)
@@ -527,20 +530,25 @@ _lseek (int fd, off_t pos, int dir)
set_errno (EINVAL);
res = -1;
}
- else if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- res = -1;
- }
else
{
- res = cygheap->fdtab[fd]->lseek (pos, dir);
+ cygheap_fdget cfd (fd);
+ if (cfd >= 0)
+ res = cfd->lseek (pos, dir);
+ else
+ res = -1;
}
- syscall_printf ("%d = lseek (%d, %d, %d)", res, fd, pos, dir);
+ syscall_printf ("%d = lseek (%d, %D, %d)", res, fd, pos, dir);
return res;
}
+extern "C" __off32_t
+_lseek (int fd, __off32_t pos, int dir)
+{
+ return lseek64 (fd, (__off64_t) pos, dir);
+}
+
extern "C" int
_close (int fd)
{
@@ -550,18 +558,13 @@ _close (int fd)
syscall_printf ("close (%d)", fd);
MALLOC_CHECK;
- if (cygheap->fdtab.not_open (fd))
- {
- debug_printf ("handle %d not open", fd);
- set_errno (EBADF);
- res = -1;
- }
+ cygheap_fdget cfd (fd, true);
+ if (cfd < 0)
+ res = -1;
else
{
- SetResourceLock (LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," close");
- res = cygheap->fdtab[fd]->close ();
- cygheap->fdtab.release (fd);
- ReleaseResourceLock (LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," close");
+ res = cfd->close ();
+ cfd.release ();
}
syscall_printf ("%d = close (%d)", res, fd);
@@ -575,13 +578,11 @@ isatty (int fd)
int res;
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
- {
- syscall_printf ("0 = isatty (%d)", fd);
- return 0;
- }
-
- res = cygheap->fdtab[fd]->is_tty ();
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ res = 0;
+ else
+ res = cfd->is_tty ();
syscall_printf ("%d = isatty (%d)", res, fd);
return res;
}
@@ -598,7 +599,7 @@ _link (const char *a, const char *b)
{
int res = -1;
sigframe thisframe (mainthread);
- path_conv real_a (a, PC_SYM_NOFOLLOW | PC_FULL);
+ path_conv real_a (a, PC_SYM_FOLLOW | PC_FULL);
path_conv real_b (b, PC_SYM_NOFOLLOW | PC_FULL);
if (real_a.error)
@@ -606,6 +607,7 @@ _link (const char *a, const char *b)
set_errno (real_a.error);
goto done;
}
+
if (real_b.error)
{
set_errno (real_b.case_clash ? ECASECLASH : real_b.error);
@@ -614,11 +616,12 @@ _link (const char *a, const char *b)
if (real_b.exists ())
{
- syscall_printf ("file '%s' exists?", (char *)real_b);
+ syscall_printf ("file '%s' exists?", (char *) real_b);
set_errno (EEXIST);
goto done;
}
- if (real_b.get_win32 ()[strlen (real_b.get_win32 ()) - 1] == '.')
+
+ if (real_b[strlen (real_b) - 1] == '.')
{
syscall_printf ("trailing dot, bailing out");
set_errno (EINVAL);
@@ -628,7 +631,7 @@ _link (const char *a, const char *b)
/* Try to make hard link first on Windows NT */
if (wincap.has_hard_links ())
{
- if (CreateHardLinkA (real_b.get_win32 (), real_a.get_win32 (), NULL))
+ if (CreateHardLinkA (real_b, real_a, NULL))
{
res = 0;
goto done;
@@ -645,15 +648,10 @@ _link (const char *a, const char *b)
BOOL bSuccess;
- hFileSource = CreateFile (
- real_a.get_win32 (),
- FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE /*| FILE_SHARE_DELETE*/,
- &sec_none_nih, // sa
- OPEN_EXISTING,
- 0,
- NULL
- );
+ hFileSource = CreateFile (real_a, FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE /*| FILE_SHARE_DELETE*/,
+ &sec_none_nih, // sa
+ OPEN_EXISTING, 0, NULL);
if (hFileSource == INVALID_HANDLE_VALUE)
{
@@ -661,8 +659,7 @@ _link (const char *a, const char *b)
goto docopy;
}
- lpContext = NULL;
- cbPathLen = sys_mbstowcs (wbuf, real_b.get_win32 (), MAX_PATH) * sizeof (WCHAR);
+ cbPathLen = sys_mbstowcs (wbuf, real_b, MAX_PATH) * sizeof (WCHAR);
StreamId.dwStreamId = BACKUP_LINK;
StreamId.dwStreamAttributes = 0;
@@ -671,8 +668,9 @@ _link (const char *a, const char *b)
StreamId.Size.LowPart = cbPathLen;
StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**) +
- StreamId.dwStreamNameSize;
+ StreamId.dwStreamNameSize;
+ lpContext = NULL;
/* Write the WIN32_STREAM_ID */
bSuccess = BackupWrite (
hFileSource,
@@ -724,7 +722,7 @@ _link (const char *a, const char *b)
}
docopy:
/* do this with a copy */
- if (CopyFileA (real_a.get_win32 (), real_b.get_win32 (), 1))
+ if (CopyFileA (real_a, real_b, 1))
res = 0;
else
__seterrno ();
@@ -740,11 +738,11 @@ done:
* systems, it is only a stub that always returns zero.
*/
static int
-chown_worker (const char *name, unsigned fmode, uid_t uid, gid_t gid)
+chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid)
{
int res;
- uid_t old_uid;
- gid_t old_gid;
+ __uid32_t old_uid;
+ __gid32_t old_gid;
if (check_null_empty_str_errno (name))
return -1;
@@ -781,14 +779,14 @@ chown_worker (const char *name, unsigned fmode, uid_t uid, gid_t gid)
&old_gid);
if (!res)
{
- if (uid == (uid_t) -1)
+ if (uid == ILLEGAL_UID)
uid = old_uid;
- if (gid == (gid_t) -1)
+ if (gid == ILLEGAL_GID)
gid = old_gid;
- if (win32_path.isdir())
+ if (win32_path.isdir ())
attrib |= S_IFDIR;
res = set_file_attribute (win32_path.has_acls (), win32_path, uid,
- gid, attrib, cygheap->user.logsrv ());
+ gid, attrib);
}
if (res != 0 && (!win32_path.has_acls () || !allow_ntsec))
{
@@ -805,31 +803,47 @@ done:
}
extern "C" int
-chown (const char * name, uid_t uid, gid_t gid)
+chown32 (const char * name, __uid32_t uid, __gid32_t gid)
{
sigframe thisframe (mainthread);
return chown_worker (name, PC_SYM_FOLLOW, uid, gid);
}
extern "C" int
-lchown (const char * name, uid_t uid, gid_t gid)
+chown (const char * name, __uid16_t uid, __gid16_t gid)
+{
+ sigframe thisframe (mainthread);
+ return chown_worker (name, PC_SYM_FOLLOW,
+ uid16touid32 (uid), gid16togid32 (gid));
+}
+
+extern "C" int
+lchown32 (const char * name, __uid32_t uid, __gid32_t gid)
{
sigframe thisframe (mainthread);
return chown_worker (name, PC_SYM_NOFOLLOW, uid, gid);
}
extern "C" int
-fchown (int fd, uid_t uid, gid_t gid)
+lchown (const char * name, __uid16_t uid, __gid16_t gid)
+{
+ sigframe thisframe (mainthread);
+ return chown_worker (name, PC_SYM_NOFOLLOW,
+ uid16touid32 (uid), gid16togid32 (gid));
+}
+
+extern "C" int
+fchown32 (int fd, __uid32_t uid, __gid32_t gid)
{
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
{
syscall_printf ("-1 = fchown (%d,...)", fd);
- set_errno (EBADF);
return -1;
}
- const char *path = cygheap->fdtab[fd]->get_name ();
+ const char *path = cfd->get_name ();
if (path == NULL)
{
@@ -843,6 +857,12 @@ fchown (int fd, uid_t uid, gid_t gid)
return chown_worker (path, PC_SYM_FOLLOW, uid, gid);
}
+extern "C" int
+fchown (int fd, __uid16_t uid, __gid16_t gid)
+{
+ return fchown32 (fd, uid16touid32 (uid), gid16togid32 (gid));
+}
+
/* umask: POSIX 5.3.3.1 */
extern "C" mode_t
umask (mode_t mask)
@@ -884,8 +904,8 @@ chmod (const char *path, mode_t mode)
/* temporary erase read only bit, to be able to set file security */
SetFileAttributes (win32_path, (DWORD) win32_path & ~FILE_ATTRIBUTE_READONLY);
- uid_t uid;
- gid_t gid;
+ __uid32_t uid;
+ __gid32_t gid;
if (win32_path.isdir ())
mode |= S_IFDIR;
@@ -896,7 +916,7 @@ chmod (const char *path, mode_t mode)
if (win32_path.isdir ())
mode |= S_IFDIR;
if (!set_file_attribute (win32_path.has_acls (), win32_path, uid, gid,
- mode, cygheap->user.logsrv ())
+ mode)
&& allow_ntsec)
res = 0;
@@ -931,14 +951,14 @@ extern "C" int
fchmod (int fd, mode_t mode)
{
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
{
syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode);
- set_errno (EBADF);
return -1;
}
- const char *path = cygheap->fdtab[fd]->get_name ();
+ const char *path = cfd->get_name ();
if (path == NULL)
{
@@ -952,56 +972,61 @@ fchmod (int fd, mode_t mode)
return chmod (path, mode);
}
-/* Cygwin internal */
-static int
-num_entries (const char *win32_name)
+static void
+stat64_to_stat32 (struct __stat64 *src, struct __stat32 *dst)
{
- WIN32_FIND_DATA buf;
- HANDLE handle;
- char buf1[MAX_PATH];
- int count = 0;
-
- strcpy (buf1, win32_name);
- int len = strlen (buf1);
- if (len == 0 || isdirsep (buf1[len - 1]))
- strcat (buf1, "*");
- else
- strcat (buf1, "/*"); /* */
-
- handle = FindFirstFileA (buf1, &buf);
-
- if (handle == INVALID_HANDLE_VALUE)
- return 0;
- count ++;
- while (FindNextFileA (handle, &buf))
- {
- if ((buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
- count ++;
- }
- FindClose (handle);
- return count;
+ dst->st_dev = ((src->st_dev >> 8) & 0xff00) | (src->st_dev & 0xff);
+ dst->st_ino = src->st_ino;
+ dst->st_mode = src->st_mode;
+ dst->st_nlink = src->st_nlink;
+ dst->st_uid = src->st_uid;
+ dst->st_gid = src->st_gid;
+ dst->st_rdev = ((src->st_rdev >> 8) & 0xff00) | (src->st_rdev & 0xff);
+ dst->st_size = src->st_size;
+ dst->st_atim = src->st_atim;
+ dst->st_mtim = src->st_mtim;
+ dst->st_ctim = src->st_ctim;
+ dst->st_blksize = src->st_blksize;
+ dst->st_blocks = src->st_blocks;
}
extern "C" int
-_fstat (int fd, struct stat *buf)
+fstat64 (int fd, struct __stat64 *buf)
{
- int r;
+ int res;
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
- {
- syscall_printf ("-1 = fstat (%d, %p)", fd, buf);
- set_errno (EBADF);
- r = -1;
- }
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ res = -1;
else
{
- memset (buf, 0, sizeof (struct stat));
- r = cygheap->fdtab[fd]->fstat (buf);
- syscall_printf ("%d = fstat (%d, %x)", r, fd, buf);
+ path_conv pc (cfd->get_win32_name (), PC_SYM_NOFOLLOW);
+ memset (buf, 0, sizeof (struct __stat64));
+ res = cfd->fstat (buf, &pc);
+ if (!res)
+ {
+ if (!buf->st_ino)
+ buf->st_ino = hash_path_name (0, cfd->get_win32_name ());
+ if (!buf->st_dev)
+ buf->st_dev = (cfd->get_device () << 16) | cfd->get_unit ();
+ if (!buf->st_rdev)
+ buf->st_rdev = buf->st_dev;
+ }
}
- return r;
+ syscall_printf ("%d = fstat (%d, %p)", res, fd, buf);
+ return res;
+}
+
+extern "C" int
+_fstat (int fd, struct __stat32 *buf)
+{
+ struct __stat64 buf64;
+ int ret = fstat64 (fd, &buf64);
+ if (!ret)
+ stat64_to_stat32 (&buf64, buf);
+ return ret;
}
/* fsync: P96 6.6.1.1 */
@@ -1009,16 +1034,14 @@ extern "C" int
fsync (int fd)
{
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
{
syscall_printf ("-1 = fsync (%d)", fd);
- set_errno (EBADF);
return -1;
}
- HANDLE h = cygheap->fdtab[fd]->get_handle ();
-
- if (FlushFileBuffers (h) == 0)
+ if (FlushFileBuffers (cfd->get_handle ()) == 0)
{
__seterrno ();
return -1;
@@ -1033,32 +1056,6 @@ sync ()
return 0;
}
-int __stdcall
-stat_dev (DWORD devn, int unit, unsigned long ino, struct stat *buf)
-{
- sigframe thisframe (mainthread);
- switch (devn)
- {
- case FH_PIPEW:
- buf->st_mode = STD_WBITS | S_IWGRP | S_IWOTH;
- break;
- case FH_PIPER:
- buf->st_mode = STD_RBITS;
- break;
- default:
- buf->st_mode = STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH;
- break;
- }
-
- buf->st_mode |= devn == FH_FLOPPY ? S_IFBLK : S_IFCHR;
- buf->st_blksize = S_BLKSIZE;
- buf->st_nlink = 1;
- buf->st_dev = buf->st_rdev = FHDEVN (devn) << 8 | (unit & 0xff);
- buf->st_ino = ino;
- buf->st_atime = buf->st_mtime = buf->st_ctime = time (NULL);
- return 0;
-}
-
suffix_info stat_suffixes[] =
{
suffix_info ("", 1),
@@ -1067,152 +1064,91 @@ suffix_info stat_suffixes[] =
};
/* Cygwin internal */
-static int
-stat_worker (const char *caller, const char *name, struct stat *buf,
- int nofollow)
+int __stdcall
+stat_worker (const char *name, struct __stat64 *buf, int nofollow,
+ path_conv *pc)
{
int res = -1;
- int oret;
- uid_t uid;
- gid_t gid;
path_conv real_path;
fhandler_base *fh = NULL;
- MALLOC_CHECK;
- int open_flags = O_RDONLY | O_BINARY | O_DIROPEN
- | (nofollow ? O_NOSYMLINK : 0);
-
- debug_printf ("%s (%s, %p)", caller, name, buf);
-
if (check_null_invalid_struct_errno (buf))
goto done;
- fh = cygheap->fdtab.build_fhandler (-1, name, NULL, real_path,
- (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
- | PC_FULL, stat_suffixes);
+ if (!pc)
+ pc = &real_path;
+
+ fh = cygheap->fdtab.build_fhandler_from_name (-1, name, NULL, *pc,
+ (nofollow ? PC_SYM_NOFOLLOW
+ : PC_SYM_FOLLOW)
+ | PC_FULL, stat_suffixes);
- if (real_path.error)
+ if (pc->error)
{
- set_errno (real_path.error);
- goto done;
+ debug_printf ("got %d error from build_fhandler_from_name", pc->error);
+ set_errno (pc->error);
}
-
- memset (buf, 0, sizeof (struct stat));
-
- if (real_path.is_device ())
- return stat_dev (real_path.get_devn (), real_path.get_unitn (),
- hash_path_name (0, real_path.get_win32 ()), buf);
-
- debug_printf ("%d = file_attributes for '%s'", (DWORD) real_path,
- (char *) real_path);
-
- if ((oret = fh->open (real_path, open_flags, 0)))
- /* ok */;
else
{
- int ntsec_atts = 0;
- /* If we couldn't open the file, try a "query open" with no permissions.
- This will allow us to determine *some* things about the file, at least. */
- fh->set_query_open (TRUE);
- if ((oret = fh->open (real_path, open_flags, 0)))
- /* ok */;
- else if (allow_ntsec && real_path.has_acls () && get_errno () == EACCES
- && !get_file_attribute (TRUE, real_path, &ntsec_atts, &uid, &gid)
- && !ntsec_atts && uid == myself->uid && gid == myself->gid)
- {
- /* Check a special case here. If ntsec is ON it happens
- that a process creates a file using mode 000 to disallow
- other processes access. In contrast to UNIX, this results
- in a failing open call in the same process. Check that
- case. */
- set_file_attribute (TRUE, real_path, 0400);
- oret = fh->open (real_path, open_flags, 0);
- set_file_attribute (TRUE, real_path, ntsec_atts);
- }
- }
- if (oret)
- {
- res = fh->fstat (buf);
- /* The number of links to a directory includes the
- number of subdirectories in the directory, since all
- those subdirectories point to it.
- This is too slow on remote drives, so we do without it and
- set the number of links to 2. */
- /* Unfortunately the count of 2 confuses `find (1)' command. So
- let's try it with `1' as link count. */
- if (real_path.isdir ())
- buf->st_nlink = (real_path.isremote ()
- ? 1 : num_entries (real_path.get_win32 ()));
- fh->close ();
- }
- else if (real_path.exists ())
- {
- /* Unfortunately, the above open may fail if the file exists, though.
- So we have to care for this case here, too. */
- WIN32_FIND_DATA wfd;
- HANDLE handle;
- buf->st_nlink = 1;
- if (real_path.isdir () && real_path.isremote ())
- buf->st_nlink = num_entries (real_path.get_win32 ());
- buf->st_dev = FHDEVN (FH_DISK) << 8;
- buf->st_ino = hash_path_name (0, real_path.get_win32 ());
- if (real_path.isdir ())
- buf->st_mode = S_IFDIR;
- else if (real_path.issymlink ())
- buf->st_mode = S_IFLNK;
- else if (real_path.issocket ())
- buf->st_mode = S_IFSOCK;
- else
- buf->st_mode = S_IFREG;
- if (!real_path.has_acls ()
- || get_file_attribute (TRUE, real_path.get_win32 (),
- &buf->st_mode,
- &buf->st_uid, &buf->st_gid))
- {
- buf->st_mode |= STD_RBITS | STD_XBITS;
- if (!(real_path.has_attribute (FILE_ATTRIBUTE_READONLY)))
- buf->st_mode |= STD_WBITS;
- if (real_path.issymlink ())
- buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO;
- get_file_attribute (FALSE, real_path.get_win32 (),
- NULL, &buf->st_uid, &buf->st_gid);
- }
- if ((handle = FindFirstFile (real_path.get_win32 (), &wfd))
- != INVALID_HANDLE_VALUE)
+ debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow,
+ pc, (DWORD) real_path);
+ memset (buf, 0, sizeof (*buf));
+ res = fh->fstat (buf, pc);
+ if (!res)
{
- buf->st_atime = to_time_t (&wfd.ftLastAccessTime);
- buf->st_mtime = to_time_t (&wfd.ftLastWriteTime);
- buf->st_ctime = to_time_t (&wfd.ftCreationTime);
- buf->st_size = wfd.nFileSizeLow;
- buf->st_blksize = S_BLKSIZE;
- buf->st_blocks = ((unsigned long) buf->st_size +
- S_BLKSIZE-1) / S_BLKSIZE;
- FindClose (handle);
+ if (!buf->st_ino)
+ buf->st_ino = hash_path_name (0, fh->get_win32_name ());
+ if (!buf->st_dev)
+ buf->st_dev = (fh->get_device () << 16) | fh->get_unit ();
+ if (!buf->st_rdev)
+ buf->st_rdev = buf->st_dev;
}
- res = 0;
}
done:
if (fh)
delete fh;
MALLOC_CHECK;
- syscall_printf ("%d = %s (%s, %p)", res, caller, name, buf);
+ syscall_printf ("%d = (%s, %p)", res, name, buf);
return res;
}
extern "C" int
-_stat (const char *name, struct stat *buf)
+stat64 (const char *name, struct __stat64 *buf)
{
sigframe thisframe (mainthread);
- return stat_worker ("stat", name, buf, 0);
+ syscall_printf ("entering");
+ return stat_worker (name, buf, 0);
+}
+
+extern "C" int
+_stat (const char *name, struct __stat32 *buf)
+{
+ struct __stat64 buf64;
+ int ret = stat64 (name, &buf64);
+ if (!ret)
+ stat64_to_stat32 (&buf64, buf);
+ return ret;
}
/* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
extern "C" int
-lstat (const char *name, struct stat *buf)
+lstat64 (const char *name, struct __stat64 *buf)
{
sigframe thisframe (mainthread);
- return stat_worker ("lstat", name, buf, 1);
+ syscall_printf ("entering");
+ return stat_worker (name, buf, 1);
+}
+
+/* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
+extern "C" int
+cygwin_lstat (const char *name, struct __stat32 *buf)
+{
+ struct __stat64 buf64;
+ int ret = lstat64 (name, &buf64);
+ if (!ret)
+ stat64_to_stat32 (&buf64, buf);
+ return ret;
}
extern int acl_access (const char *, int);
@@ -1222,7 +1158,7 @@ access (const char *fn, int flags)
{
sigframe thisframe (mainthread);
// flags were incorrectly specified
- if (flags & ~ (F_OK|R_OK|W_OK|X_OK))
+ if (flags & ~(F_OK|R_OK|W_OK|X_OK))
{
set_errno (EINVAL);
return -1;
@@ -1231,8 +1167,8 @@ access (const char *fn, int flags)
if (allow_ntsec)
return acl_access (fn, flags);
- struct stat st;
- int r = stat (fn, &st);
+ struct __stat64 st;
+ int r = stat_worker (fn, &st, 0);
if (r)
return -1;
r = -1;
@@ -1240,45 +1176,45 @@ access (const char *fn, int flags)
{
if (st.st_uid == myself->uid)
{
- if (! (st.st_mode & S_IRUSR))
+ if (!(st.st_mode & S_IRUSR))
goto done;
}
else if (st.st_gid == myself->gid)
{
- if (! (st.st_mode & S_IRGRP))
+ if (!(st.st_mode & S_IRGRP))
goto done;
}
- else if (! (st.st_mode & S_IROTH))
+ else if (!(st.st_mode & S_IROTH))
goto done;
}
if (flags & W_OK)
{
if (st.st_uid == myself->uid)
{
- if (! (st.st_mode & S_IWUSR))
+ if (!(st.st_mode & S_IWUSR))
goto done;
}
else if (st.st_gid == myself->gid)
{
- if (! (st.st_mode & S_IWGRP))
+ if (!(st.st_mode & S_IWGRP))
goto done;
}
- else if (! (st.st_mode & S_IWOTH))
+ else if (!(st.st_mode & S_IWOTH))
goto done;
}
if (flags & X_OK)
{
if (st.st_uid == myself->uid)
{
- if (! (st.st_mode & S_IXUSR))
+ if (!(st.st_mode & S_IXUSR))
goto done;
}
else if (st.st_gid == myself->gid)
{
- if (! (st.st_mode & S_IXGRP))
+ if (!(st.st_mode & S_IXGRP))
goto done;
}
- else if (! (st.st_mode & S_IXOTH))
+ else if (!(st.st_mode & S_IXOTH))
goto done;
}
r = 0;
@@ -1396,7 +1332,16 @@ done:
else
{
/* make the new file have the permissions of the old one */
- SetFileAttributes (real_new, real_old);
+ DWORD attr = real_old;
+#ifdef HIDDEN_DOT_FILES
+ char *c = strrchr (real_old.get_win32 (), '\\');
+ if ((c && c[1] == '.') || *real_old.get_win32 () == '.')
+ attr &= ~FILE_ATTRIBUTE_HIDDEN;
+ c = strrchr (real_new.get_win32 (), '\\');
+ if ((c && c[1] == '.') || *real_new.get_win32 () == '.')
+ attr |= FILE_ATTRIBUTE_HIDDEN;
+#endif
+ SetFileAttributes (real_new, attr);
/* Shortcut hack, No. 2, part 2 */
/* if the new filename was an existing shortcut, remove it now if the
@@ -1417,6 +1362,9 @@ done:
extern "C" int
system (const char *cmdstring)
{
+ if (check_null_empty_str_errno (cmdstring))
+ return -1;
+
sigframe thisframe (mainthread);
int res;
const char* command[4];
@@ -1511,11 +1459,9 @@ check_posix_perm (const char *fname, int v)
extern "C" long int
fpathconf (int fd, int v)
{
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- return -1;
- }
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
switch (v)
{
case _PC_LINK_MAX:
@@ -1538,7 +1484,7 @@ fpathconf (int fd, int v)
case _PC_NO_TRUNC:
return -1;
case _PC_VDISABLE:
- if (isatty (fd))
+ if (cfd->is_tty ())
return -1;
else
{
@@ -1547,13 +1493,10 @@ fpathconf (int fd, int v)
}
case _PC_POSIX_PERMISSIONS:
case _PC_POSIX_SECURITY:
- {
- fhandler_base *fh = cygheap->fdtab[fd];
- if (fh->get_device () == FH_DISK)
- return check_posix_perm (fh->get_win32_name (), v);
- set_errno (EINVAL);
- return -1;
- }
+ if (cfd->get_device () == FH_DISK)
+ return check_posix_perm (cfd->get_win32_name (), v);
+ set_errno (EINVAL);
+ return -1;
default:
set_errno (EINVAL);
return -1;
@@ -1566,6 +1509,8 @@ pathconf (const char *file, int v)
switch (v)
{
case _PC_PATH_MAX:
+ if (check_null_empty_str_errno (file))
+ return -1;
return PATH_MAX - strlen (file);
case _PC_NAME_MAX:
return PATH_MAX;
@@ -1606,11 +1551,12 @@ pathconf (const char *file, int v)
extern "C" char *
ttyname (int fd)
{
- if (cygheap->fdtab.not_open (fd) || !cygheap->fdtab[fd]->is_tty ())
+ cygheap_fdget cfd (fd);
+ if (cfd < 0 || !cfd->is_tty ())
{
return 0;
}
- return (char *) (cygheap->fdtab[fd]->ttyname ());
+ return (char *) (cfd->ttyname ());
}
extern "C" char *
@@ -1637,21 +1583,20 @@ _cygwin_istext_for_stdio (int fd)
return 0; /* we do it for old apps, due to getc/putc macros */
}
- if (cygheap->fdtab.not_open (fd))
+ cygheap_fdget cfd (fd, false, false);
+ if (cfd < 0)
{
syscall_printf (" _cifs: fd not open\n");
return 0;
}
- fhandler_base *p = cygheap->fdtab[fd];
-
- if (p->get_device () != FH_DISK)
+ if (cfd->get_device () != FH_DISK)
{
syscall_printf (" _cifs: fd not disk file\n");
return 0;
}
- if (p->get_w_binary () || p->get_r_binary ())
+ if (cfd->get_w_binary () || cfd->get_r_binary ())
{
syscall_printf (" _cifs: get_*_binary\n");
return 0;
@@ -1673,8 +1618,8 @@ setmode_helper (FILE *f)
if (fileno (f) != setmode_file)
return 0;
syscall_printf ("setmode: file was %s now %s\n",
- f->_flags & __SCLE ? "cle" : "raw",
- setmode_mode & O_TEXT ? "cle" : "raw");
+ f->_flags & __SCLE ? "text" : "raw",
+ setmode_mode & O_TEXT ? "text" : "raw");
if (setmode_mode & O_TEXT)
f->_flags |= __SCLE;
else
@@ -1685,13 +1630,11 @@ setmode_helper (FILE *f)
extern "C" int
getmode (int fd)
{
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- return -1;
- }
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
- return cygheap->fdtab[fd]->get_flags () & (O_BINARY | O_TEXT);
+ return cfd->get_flags () & (O_BINARY | O_TEXT);
}
/* Set a file descriptor into text or binary mode, returning the
@@ -1700,44 +1643,32 @@ getmode (int fd)
extern "C" int
setmode (int fd, int mode)
{
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- return -1;
- }
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
if (mode != O_BINARY && mode != O_TEXT && mode != 0)
{
set_errno (EINVAL);
return -1;
}
- fhandler_base *p = cygheap->fdtab[fd];
-
/* Note that we have no way to indicate the case that writes are
binary but not reads, or vice-versa. These cases can arise when
using the tty or console interface. People using those
interfaces should not use setmode. */
int res;
- if (p->get_w_binary () && p->get_r_binary ())
+ if (cfd->get_w_binary () && cfd->get_r_binary ())
res = O_BINARY;
- else if (p->get_w_binset () && p->get_r_binset ())
+ else if (cfd->get_w_binset () && cfd->get_r_binset ())
res = O_TEXT; /* Specifically set O_TEXT */
else
res = 0;
if (!mode)
- p->reset_to_open_binmode ();
- else if (mode & O_BINARY)
- {
- p->set_w_binary (1);
- p->set_r_binary (1);
- }
+ cfd->reset_to_open_binmode ();
else
- {
- p->set_w_binary (0);
- p->set_r_binary (0);
- }
+ cfd->set_flags ((cfd->get_flags () & ~(O_TEXT | O_BINARY)) | mode);
if (_cygwin_istext_for_stdio (fd))
setmode_mode = O_TEXT;
@@ -1746,57 +1677,57 @@ setmode (int fd, int mode)
setmode_file = fd;
_fwalk (_REENT, setmode_helper);
- syscall_printf ("setmode (%d<%s>, %s) returns %s\n", fd, p->get_name (),
- mode & O_TEXT ? "text" : "binary",
- res & O_TEXT ? "text" : "binary");
+ syscall_printf ("setmode (%d<%s>, %p) returns %s\n", fd, cfd->get_name (),
+ mode, res & O_TEXT ? "text" : "binary");
return res;
}
-/* ftruncate: P96 5.6.7.1 */
extern "C" int
-ftruncate (int fd, off_t length)
+ftruncate64 (int fd, __off64_t length)
{
sigframe thisframe (mainthread);
int res = -1;
if (length < 0)
- {
- set_errno (EINVAL);
- }
- else if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- }
+ set_errno (EINVAL);
else
{
- HANDLE h = cygheap->fdtab[fd]->get_handle ();
- off_t prev_loc;
-
- if (h)
+ cygheap_fdget cfd (fd);
+ if (cfd >= 0)
{
- /* remember curr file pointer location */
- prev_loc = cygheap->fdtab[fd]->lseek (0, SEEK_CUR);
+ HANDLE h = cygheap->fdtab[fd]->get_handle ();
- cygheap->fdtab[fd]->lseek (length, SEEK_SET);
- if (!SetEndOfFile (h))
+ if (cfd->get_handle ())
{
- __seterrno ();
- }
- else
- res = 0;
+ /* remember curr file pointer location */
+ __off64_t prev_loc = cfd->lseek (0, SEEK_CUR);
- /* restore original file pointer location */
- cygheap->fdtab[fd]->lseek (prev_loc, 0);
+ cfd->lseek (length, SEEK_SET);
+ if (!SetEndOfFile (h))
+ __seterrno ();
+ else
+ res = 0;
+
+ /* restore original file pointer location */
+ cfd->lseek (prev_loc, SEEK_SET);
+ }
}
}
- syscall_printf ("%d = ftruncate (%d, %d)", res, fd, length);
+ syscall_printf ("%d = ftruncate (%d, %d)", res, fd, length);
return res;
}
+/* ftruncate: P96 5.6.7.1 */
+extern "C" int
+ftruncate (int fd, __off32_t length)
+{
+ return ftruncate64 (fd, (__off64_t)length);
+}
+
/* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
extern "C" int
-truncate (const char *pathname, off_t length)
+truncate64 (const char *pathname, __off64_t length)
{
sigframe thisframe (mainthread);
int fd;
@@ -1808,7 +1739,7 @@ truncate (const char *pathname, off_t length)
set_errno (EBADF);
else
{
- res = ftruncate (fd, length);
+ res = ftruncate64 (fd, length);
close (fd);
}
syscall_printf ("%d = truncate (%s, %d)", res, pathname, length);
@@ -1816,15 +1747,23 @@ truncate (const char *pathname, off_t length)
return res;
}
+/* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */
+extern "C" int
+truncate (const char *pathname, __off32_t length)
+{
+ return truncate64 (pathname, (__off64_t)length);
+}
+
extern "C" long
get_osfhandle (int fd)
{
- long res = -1;
+ long res;
- if (cygheap->fdtab.not_open (fd))
- set_errno (EBADF);
+ cygheap_fdget cfd (fd);
+ if (cfd >= 0)
+ res = (long) cfd->get_handle ();
else
- res = (long) cygheap->fdtab[fd]->get_handle ();
+ res = -1;
syscall_printf ("%d = get_osfhandle (%d)", res, fd);
return res;
@@ -1875,13 +1814,10 @@ extern "C" int
fstatfs (int fd, struct statfs *sfs)
{
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- return -1;
- }
- fhandler_disk_file *f = (fhandler_disk_file *) cygheap->fdtab[fd];
- return statfs (f->get_name (), sfs);
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
+ return statfs (cfd->get_name (), sfs);
}
/* setpgid: POSIX 4.3.3.1 */
@@ -1961,16 +1897,14 @@ extern "C" char *
ptsname (int fd)
{
sigframe thisframe (mainthread);
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- return 0;
- }
- return (char *) (cygheap->fdtab[fd]->ptsname ());
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return 0;
+ return (char *) (cfd->ptsname ());
}
/* FIXME: what is this? */
-extern "C" int
+extern "C" int __declspec(dllexport)
regfree ()
{
return 0;
@@ -1996,296 +1930,278 @@ mkfifo (const char *_path, mode_t mode)
return -1;
}
-/* setgid: POSIX 4.2.2.1 */
+/* seteuid: standards? */
extern "C" int
-setgid (gid_t gid)
+seteuid32 (__uid32_t uid)
{
- int ret = setegid (gid);
- if (!ret)
- cygheap->user.real_gid = myself->gid;
- return ret;
-}
-/* setuid: POSIX 4.2.2.1 */
-extern "C" int
-setuid (uid_t uid)
-{
- int ret = seteuid (uid);
- if (!ret)
- cygheap->user.real_uid = myself->uid;
- debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
- return ret;
-}
+ debug_printf ("uid: %d myself->gid: %d", uid, myself->gid);
-extern struct passwd *internal_getlogin (cygheap_user &user);
+ if (!wincap.has_security ()
+ || (uid == myself->uid && !cygheap->user.groups.ischanged))
+ {
+ debug_printf ("Nothing happens");
+ return 0;
+ }
-/* seteuid: standards? */
-extern "C" int
-seteuid (uid_t uid)
-{
- sigframe thisframe (mainthread);
- if (wincap.has_security ())
+ if (uid == ILLEGAL_UID)
{
- char orig_username[UNLEN + 1];
- char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- char username[UNLEN + 1];
- DWORD ulen = UNLEN + 1;
- char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
- SID_NAME_USE use;
+ set_errno (EINVAL);
+ return -1;
+ }
- if (uid == (uid_t) -1 || uid == myself->uid)
- {
- debug_printf ("new euid == current euid, nothing happens");
- return 0;
- }
- struct passwd *pw_new = getpwuid (uid);
- if (!pw_new)
- {
- set_errno (EINVAL);
- return -1;
- }
+ sigframe thisframe (mainthread);
+ cygsid usersid;
+ user_groups &groups = cygheap->user.groups;
+ HANDLE ptok, sav_token;
+ BOOL sav_impersonated, sav_token_is_internal_token;
+ BOOL process_ok, explicitly_created_token = FALSE;
+ struct passwd * pw_new;
+ PSID origpsid, psid2 = NO_SID;
- cygsid tok_usersid;
- DWORD siz;
+ pw_new = getpwuid32 (uid);
+ if (!usersid.getfrompw (pw_new))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ /* Save current information */
+ sav_token = cygheap->user.token;
+ sav_impersonated = cygheap->user.impersonated;
- char *env;
- orig_username[0] = orig_domain[0] = '\0';
- if ((env = getenv ("USERNAME")))
- strncat (orig_username, env, UNLEN + 1);
- if ((env = getenv ("USERDOMAIN")))
- strncat (orig_domain, env, INTERNET_MAX_HOST_NAME_LENGTH + 1);
- if (uid == cygheap->user.orig_uid)
+ RevertToSelf ();
+ if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok))
+ {
+ __seterrno ();
+ goto failed;
+ }
+ /* Verify if the process token is suitable.
+ Currently we do not try to differentiate between
+ internal tokens and others */
+ process_ok = verify_token (ptok, usersid, groups);
+ debug_printf ("Process token %sverified", process_ok ? "" : "not ");
+ if (process_ok)
+ {
+ if (cygheap->user.issetuid ())
+ cygheap->user.impersonated = FALSE;
+ else
{
-
- debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)",
- cygheap->user.token);
- RevertToSelf ();
- if (cygheap->user.token != INVALID_HANDLE_VALUE)
- cygheap->user.impersonated = FALSE;
-
- HANDLE ptok = INVALID_HANDLE_VALUE;
- if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok))
- debug_printf ("OpenProcessToken(): %E\n");
- else if (!GetTokenInformation (ptok, TokenUser, &tok_usersid,
- sizeof tok_usersid, &siz))
- debug_printf ("GetTokenInformation(): %E");
- else if (!LookupAccountSid (NULL, tok_usersid, username, &ulen,
- domain, &dlen, &use))
- debug_printf ("LookupAccountSid(): %E");
- else
- {
- setenv ("USERNAME", username, 1);
- setenv ("USERDOMAIN", domain, 1);
- }
- if (ptok != INVALID_HANDLE_VALUE)
- CloseHandle (ptok);
+ CloseHandle (ptok);
+ goto success; /* No change */
}
+ }
+
+ if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE)
+ {
+ /* Verify if the current tokem is suitable */
+ BOOL token_ok = verify_token (cygheap->user.token, usersid, groups,
+ &sav_token_is_internal_token);
+ debug_printf ("Thread token %d %sverified",
+ cygheap->user.token, token_ok?"":"not ");
+ if (!token_ok)
+ cygheap->user.token = INVALID_HANDLE_VALUE;
else
{
- cygsid usersid, pgrpsid, tok_pgrpsid;
- HANDLE sav_token = INVALID_HANDLE_VALUE;
- BOOL sav_impersonation;
- BOOL current_token_is_internal_token = FALSE;
- BOOL explicitely_created_token = FALSE;
-
- struct group *gr = getgrgid (myself->gid);
- debug_printf ("myself->gid: %d, gr: %d", myself->gid, gr);
-
- usersid.getfrompw (pw_new);
- pgrpsid.getfromgr (gr);
-
- /* Only when ntsec is ON! */
- /* Check if new user == user of impersonation token and
- - if reasonable - new pgrp == pgrp of impersonation token. */
- if (allow_ntsec && cygheap->user.token != INVALID_HANDLE_VALUE)
+ /* Return if current token is valid */
+ if (cygheap->user.impersonated)
{
- if (!GetTokenInformation (cygheap->user.token, TokenUser,
- &tok_usersid, sizeof tok_usersid, &siz))
- {
- debug_printf ("GetTokenInformation(): %E");
- tok_usersid = NO_SID;
- }
- if (!GetTokenInformation (cygheap->user.token, TokenPrimaryGroup,
- &tok_pgrpsid, sizeof tok_pgrpsid, &siz))
- {
- debug_printf ("GetTokenInformation(): %E");
- tok_pgrpsid = NO_SID;
- }
- /* Check if the current user token was internally created. */
- TOKEN_SOURCE ts;
- if (!GetTokenInformation (cygheap->user.token, TokenSource,
- &ts, sizeof ts, &siz))
- debug_printf ("GetTokenInformation(): %E");
- else if (!memcmp (ts.SourceName, "Cygwin.1", 8))
- current_token_is_internal_token = TRUE;
- if ((usersid && tok_usersid && usersid != tok_usersid) ||
- /* Check for pgrp only if current token is an internal
- token. Otherwise the external provided token is
- very likely overwritten here. */
- (current_token_is_internal_token &&
- pgrpsid && tok_pgrpsid && pgrpsid != tok_pgrpsid))
- {
- /* If not, RevertToSelf and close old token. */
- debug_printf ("tsid != usersid");
- RevertToSelf ();
- sav_token = cygheap->user.token;
- sav_impersonation = cygheap->user.impersonated;
- cygheap->user.token = INVALID_HANDLE_VALUE;
- cygheap->user.impersonated = FALSE;
- }
+ CloseHandle (ptok);
+ if (!ImpersonateLoggedOnUser (cygheap->user.token))
+ system_printf ("Impersonating in seteuid failed: %E");
+ goto success; /* No change */
}
+ }
+ }
- /* Only when ntsec is ON! */
- /* If no impersonation token is available, try to
- authenticate using NtCreateToken() or subauthentication. */
- if (allow_ntsec && cygheap->user.token == INVALID_HANDLE_VALUE)
- {
- HANDLE ptok = INVALID_HANDLE_VALUE;
+ /* Set process def dacl to allow access to impersonated token */
+ char dacl_buf[MAX_DACL_LEN (5)];
+ if (usersid != (origpsid = cygheap->user.orig_sid ())) psid2 = usersid;
+ if (sec_acl ((PACL) dacl_buf, FALSE, origpsid, psid2))
+ {
+ TOKEN_DEFAULT_DACL tdacl;
+ tdacl.DefaultDacl = (PACL) dacl_buf;
+ if (!SetTokenInformation (ptok, TokenDefaultDacl,
+ &tdacl, sizeof dacl_buf))
+ debug_printf ("SetTokenInformation"
+ "(TokenDefaultDacl): %E");
+ }
+ CloseHandle (ptok);
- ptok = create_token (usersid, pgrpsid);
- if (ptok != INVALID_HANDLE_VALUE)
- explicitely_created_token = TRUE;
- else
- {
- /* create_token failed. Try subauthentication. */
- debug_printf ("create token failed, try subauthentication.");
- ptok = subauth (pw_new);
- }
- if (ptok != INVALID_HANDLE_VALUE)
- {
- cygwin_set_impersonation_token (ptok);
- /* If sav_token was internally created, destroy it. */
- if (sav_token != INVALID_HANDLE_VALUE &&
- current_token_is_internal_token)
- CloseHandle (sav_token);
- }
- else if (sav_token != INVALID_HANDLE_VALUE)
- cygheap->user.token = sav_token;
- }
- /* If no impersonation is active but an impersonation
- token is available, try to impersonate. */
- if (cygheap->user.token != INVALID_HANDLE_VALUE &&
- !cygheap->user.impersonated)
- {
- debug_printf ("Impersonate (uid == %d)", uid);
- RevertToSelf ();
-
- /* If the token was explicitely created, all information has
- already been set correctly. */
- if (!explicitely_created_token)
- {
- /* Try setting owner to same value as user. */
- if (usersid &&
- !SetTokenInformation (cygheap->user.token, TokenOwner,
- &usersid, sizeof usersid))
- debug_printf ("SetTokenInformation(user.token, "
- "TokenOwner): %E");
- /* Try setting primary group in token to current group
- if token not explicitely created. */
- if (pgrpsid &&
- !SetTokenInformation (cygheap->user.token,
- TokenPrimaryGroup,
- &pgrpsid, sizeof pgrpsid))
- debug_printf ("SetTokenInformation(user.token, "
- "TokenPrimaryGroup): %E");
-
- }
-
- /* Now try to impersonate. */
- if (!LookupAccountSid (NULL, usersid, username, &ulen,
- domain, &dlen, &use))
- debug_printf ("LookupAccountSid (): %E");
- else if (!ImpersonateLoggedOnUser (cygheap->user.token))
- system_printf ("Impersonating (%d) in set(e)uid failed: %E",
- cygheap->user.token);
- else
- {
- cygheap->user.impersonated = TRUE;
- setenv ("USERNAME", username, 1);
- setenv ("USERDOMAIN", domain, 1);
- }
- }
+ if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE)
+ {
+ /* If no impersonation token is available, try to
+ authenticate using NtCreateToken () or subauthentication. */
+ cygheap->user.token = create_token (usersid, groups, pw_new);
+ if (cygheap->user.token != INVALID_HANDLE_VALUE)
+ explicitly_created_token = TRUE;
+ else
+ {
+ /* create_token failed. Try subauthentication. */
+ debug_printf ("create token failed, try subauthentication.");
+ cygheap->user.token = subauth (pw_new);
+ if (cygheap->user.token == INVALID_HANDLE_VALUE)
+ goto failed;
}
+ }
- cygheap_user user;
- /* user.token is used in internal_getlogin () to determine if
- impersonation is active. If so, the token is used for
- retrieving user's SID. */
- user.token = cygheap->user.impersonated ? cygheap->user.token
- : INVALID_HANDLE_VALUE;
- struct passwd *pw_cur = internal_getlogin (user);
- if (pw_cur != pw_new)
+ /* If using the token, set info and impersonate */
+ if (!process_ok)
+ {
+ /* If the token was explicitly created, all information has
+ already been set correctly. */
+ if (!explicitly_created_token)
{
- debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
- cygheap->user.token, pw_cur->pw_uid,
- pw_new->pw_uid, cygheap->user.orig_uid);
- setenv ("USERNAME", orig_username, 1);
- setenv ("USERDOMAIN", orig_domain, 1);
- set_errno (EPERM);
- return -1;
+ /* Try setting owner to same value as user. */
+ if (!SetTokenInformation (cygheap->user.token, TokenOwner,
+ &usersid, sizeof usersid))
+ debug_printf ("SetTokenInformation(user.token, "
+ "TokenOwner): %E");
+ /* Try setting primary group in token to current group */
+ if (!SetTokenInformation (cygheap->user.token,
+ TokenPrimaryGroup,
+ &groups.pgsid, sizeof (cygsid)))
+ debug_printf ("SetTokenInformation(user.token, "
+ "TokenPrimaryGroup): %E");
}
- myself->uid = uid;
- cygheap->user = user;
- }
- else
- set_errno (ENOSYS);
- debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
+ /* Now try to impersonate. */
+ if (!ImpersonateLoggedOnUser (cygheap->user.token))
+ {
+ debug_printf ("ImpersonateLoggedOnUser %E");
+ __seterrno ();
+ goto failed;
+ }
+ cygheap->user.impersonated = TRUE;
+ }
+
+ /* If sav_token was internally created and is replaced, destroy it. */
+ if (sav_token != INVALID_HANDLE_VALUE &&
+ sav_token != cygheap->user.token &&
+ sav_token_is_internal_token)
+ CloseHandle (sav_token);
+ cygheap->user.set_name (pw_new->pw_name);
+ cygheap->user.set_sid (usersid);
+success:
+ myself->uid = uid;
+ groups.ischanged = FALSE;
return 0;
+
+ failed:
+ cygheap->user.token = sav_token;
+ cygheap->user.impersonated = sav_impersonated;
+ if (cygheap->user.issetuid ()
+ && !ImpersonateLoggedOnUser (cygheap->user.token))
+ system_printf ("Impersonating in seteuid failed: %E");
+ return -1;
+}
+
+extern "C" int
+seteuid (__uid16_t uid)
+{
+ return seteuid32 (uid16touid32 (uid));
+}
+
+/* setuid: POSIX 4.2.2.1 */
+extern "C" int
+setuid32 (__uid32_t uid)
+{
+ int ret = seteuid32 (uid);
+ if (!ret)
+ cygheap->user.real_uid = myself->uid;
+ debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
+ return ret;
+}
+
+extern "C" int
+setuid (__uid16_t uid)
+{
+ return setuid32 (uid16touid32 (uid));
}
/* setegid: from System V. */
extern "C" int
-setegid (gid_t gid)
+setegid32 (__gid32_t gid)
{
+ if (!wincap.has_security () || gid == myself->gid)
+ return 0;
+
+ if (gid == ILLEGAL_GID)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
sigframe thisframe (mainthread);
- if (wincap.has_security ())
+ user_groups * groups = &cygheap->user.groups;
+ cygsid gsid;
+ HANDLE ptok;
+
+ struct __group32 * gr = getgrgid32 (gid);
+ if (!gr || gr->gr_gid != gid || !gsid.getfromgr (gr))
{
- if (gid != (gid_t) -1)
- {
- struct group *gr;
+ set_errno (EINVAL);
+ return -1;
+ }
+ myself->gid = gid;
- if (!(gr = getgrgid (gid)))
- {
- set_errno (EINVAL);
- return -1;
- }
- myself->gid = gid;
- if (allow_ntsec)
- {
- cygsid gsid;
- HANDLE ptok;
-
- if (gsid.getfromgr (gr))
- {
- if (!OpenProcessToken (GetCurrentProcess (),
- TOKEN_ADJUST_DEFAULT,
- &ptok))
- debug_printf ("OpenProcessToken(): %E\n");
- else
- {
- if (!SetTokenInformation (ptok, TokenPrimaryGroup,
- &gsid, sizeof gsid))
- debug_printf ("SetTokenInformation(myself, "
- "TokenPrimaryGroup): %E");
- CloseHandle (ptok);
- }
- }
- }
- }
+ groups->update_pgrp (gsid);
+ /* If impersonated, update primary group and revert */
+ if (cygheap->user.issetuid ())
+ {
+ if (!SetTokenInformation (cygheap->user.token,
+ TokenPrimaryGroup,
+ &gsid, sizeof gsid))
+ debug_printf ("SetTokenInformation(thread, "
+ "TokenPrimaryGroup): %E");
+ RevertToSelf ();
}
+ if (!OpenProcessToken (hMainProc, TOKEN_ADJUST_DEFAULT, &ptok))
+ debug_printf ("OpenProcessToken(): %E\n");
else
- set_errno (ENOSYS);
+ {
+ if (!SetTokenInformation (ptok, TokenPrimaryGroup,
+ &gsid, sizeof gsid))
+ debug_printf ("SetTokenInformation(process, "
+ "TokenPrimaryGroup): %E");
+ CloseHandle (ptok);
+ }
+ if (cygheap->user.issetuid ()
+ && !ImpersonateLoggedOnUser (cygheap->user.token))
+ system_printf ("Impersonating in setegid failed: %E");
return 0;
}
+extern "C" int
+setegid (__gid16_t gid)
+{
+ return setegid32 (gid16togid32 (gid));
+}
+
+/* setgid: POSIX 4.2.2.1 */
+extern "C" int
+setgid32 (__gid32_t gid)
+{
+ int ret = setegid32 (gid);
+ if (!ret)
+ cygheap->user.real_gid = myself->gid;
+ return ret;
+}
+
+extern "C" int
+setgid (__gid16_t gid)
+{
+ int ret = setegid32 (gid16togid32 (gid));
+ if (!ret)
+ cygheap->user.real_gid = myself->gid;
+ return ret;
+}
+
/* chroot: privileged Unix system call. */
/* FIXME: Not privileged here. How should this be done? */
extern "C" int
chroot (const char *newroot)
{
sigframe thisframe (mainthread);
- path_conv path (newroot, PC_SYM_FOLLOW | PC_FULL);
+ path_conv path (newroot, PC_SYM_FOLLOW | PC_FULL | PC_POSIX);
int ret;
if (path.error)
@@ -2302,9 +2218,7 @@ chroot (const char *newroot)
}
else
{
- char buf[MAX_PATH];
- normalize_posix_path (newroot, buf);
- cygheap->root.set (buf, path);
+ cygheap->root.set (path.normalized_path, path);
ret = 0;
}
@@ -2514,17 +2428,16 @@ logout (char *line)
return 0;
ut_fd = CreateFile (win32_path.get_win32 (),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_none_nih,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sec_none_nih, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
if (ut_fd != INVALID_HANDLE_VALUE)
{
struct utmp *ut;
struct utmp ut_buf[100];
- off_t pos = 0; /* Position in file */
+ /* FIXME: utmp file access is not 64 bit clean for now. */
+ __off32_t pos = 0; /* Position in file */
DWORD rd;
while (!res && ReadFile (ut_fd, ut_buf, sizeof ut_buf, &rd, NULL)
@@ -2559,3 +2472,101 @@ logout (char *line)
return res;
}
+
+static int utmp_fd = -2;
+static char *utmp_file = (char *) _PATH_UTMP;
+
+static struct utmp utmp_data;
+
+extern "C" void
+setutent ()
+{
+ sigframe thisframe (mainthread);
+ if (utmp_fd == -2)
+ {
+ utmp_fd = _open (utmp_file, O_RDONLY);
+ }
+ _lseek (utmp_fd, 0, SEEK_SET);
+}
+
+extern "C" void
+endutent ()
+{
+ sigframe thisframe (mainthread);
+ _close (utmp_fd);
+ utmp_fd = -2;
+}
+
+extern "C" void
+utmpname (_CONST char *file)
+{
+ sigframe thisframe (mainthread);
+ if (check_null_empty_str (file))
+ {
+ debug_printf ("Invalid file");
+ return;
+ }
+ utmp_file = strdup (file);
+ debug_printf ("New UTMP file: %s", utmp_file);
+}
+
+extern "C" struct utmp *
+getutent ()
+{
+ sigframe thisframe (mainthread);
+ if (utmp_fd == -2)
+ setutent ();
+ if (_read (utmp_fd, &utmp_data, sizeof (utmp_data)) != sizeof (utmp_data))
+ return NULL;
+ return &utmp_data;
+}
+
+extern "C" struct utmp *
+getutid (struct utmp *id)
+{
+ sigframe thisframe (mainthread);
+ if (check_null_invalid_struct_errno (id))
+ return NULL;
+ while (_read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data))
+ {
+ switch (id->ut_type)
+ {
+#if 0 /* Not available in Cygwin. */
+ case RUN_LVL:
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ if (id->ut_type == utmp_data.ut_type)
+ return &utmp_data;
+ break;
+#endif
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case USER_PROCESS:
+ case DEAD_PROCESS:
+ if (id->ut_id == utmp_data.ut_id)
+ return &utmp_data;
+ break;
+ default:
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+extern "C" struct utmp *
+getutline (struct utmp *line)
+{
+ sigframe thisframe (mainthread);
+ if (check_null_invalid_struct_errno (line))
+ return NULL;
+ while (_read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data))
+ {
+ if ((utmp_data.ut_type == LOGIN_PROCESS ||
+ utmp_data.ut_type == USER_PROCESS) &&
+ !strncmp (utmp_data.ut_line, line->ut_line,
+ sizeof (utmp_data.ut_line)))
+ return &utmp_data;
+ }
+ return NULL;
+}
diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc
index 5e1d91ba6..0232faf39 100644
--- a/winsup/cygwin/sysconf.cc
+++ b/winsup/cygwin/sysconf.cc
@@ -1,6 +1,6 @@
/* sysconf.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -18,8 +18,8 @@ details. */
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
-#include "cygheap.h"
#include "cygerrno.h"
+#include "cygheap.h"
#include "ntdll.h"
/* sysconf: POSIX 4.8.1.1 */
@@ -62,7 +62,7 @@ sysconf (int in)
/*FALLTHRU*/
case _SC_PHYS_PAGES:
case _SC_AVPHYS_PAGES:
- if (!wincap.supports_smp ())
+ if (wincap.supports_smp ())
{
NTSTATUS ret;
SYSTEM_BASIC_INFORMATION sbi;
@@ -72,9 +72,9 @@ sysconf (int in)
!= STATUS_SUCCESS)
{
__seterrno_from_win_error (RtlNtStatusToDosError (ret));
- debug_printf("NtQuerySystemInformation: ret = %d, "
- "Dos(ret) = %d",
- ret, RtlNtStatusToDosError (ret));
+ debug_printf ("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
return -1;
}
switch (in)
@@ -89,7 +89,7 @@ sysconf (int in)
return sbi.HighestPhysicalPage - sbi.LowestPhysicalPage + 1;
}
}
- break;
+ break;
}
/* Invalid input or unimplemented sysconf name */
diff --git a/winsup/cygwin/syslog.cc b/winsup/cygwin/syslog.cc
index 66e9ed1cc..f424a4f4e 100644
--- a/winsup/cygwin/syslog.cc
+++ b/winsup/cygwin/syslog.cc
@@ -14,6 +14,7 @@ details. */
#include <syslog.h>
#include <stdarg.h>
#include <unistd.h>
+#include <errno.h>
#include "security.h"
#include "fhandler.h"
#include "path.h"
@@ -41,11 +42,11 @@ get_win95_event_log_path ()
/* FIXME: For MT safe code these will need to be replaced */
#ifdef _MT_SAFE
-#define process_ident _reent_winsup()->_process_ident
-#define process_logopt _reent_winsup()->_process_logopt
-#define process_facility _reent_winsup()->_process_facility
+#define process_ident _reent_winsup ()->_process_ident
+#define process_logopt _reent_winsup ()->_process_logopt
+#define process_facility _reent_winsup ()->_process_facility
/* Default priority logmask */
-#define process_logmask _reent_winsup()->_process_logmask
+#define process_logmask _reent_winsup ()->_process_logmask
#else
static char *process_ident = 0;
static int process_logopt = 0;
@@ -257,13 +258,18 @@ syslog (int priority, const char *message, ...)
WORD eventType;
switch (LOG_PRI (priority))
{
+ case LOG_EMERG:
+ case LOG_ALERT:
+ case LOG_CRIT:
case LOG_ERR:
eventType = EVENTLOG_ERROR_TYPE;
break;
case LOG_WARNING:
eventType = EVENTLOG_WARNING_TYPE;
break;
+ case LOG_NOTICE:
case LOG_INFO:
+ case LOG_DEBUG:
eventType = EVENTLOG_INFORMATION_TYPE;
break;
default:
@@ -297,7 +303,7 @@ syslog (int priority, const char *message, ...)
if (process_logopt & LOG_PID)
{
if (pass.print ("Win32 Process Id = 0x%X : Cygwin Process Id = 0x%X : ",
- GetCurrentProcessId(), getpid ()) == -1)
+ GetCurrentProcessId (), getpid ()) == -1)
return;
}
@@ -307,14 +313,29 @@ syslog (int priority, const char *message, ...)
eventlog capability. */
switch (LOG_PRI (priority))
{
+ case LOG_EMERG:
+ pass.print ("%s : ", "LOG_EMERG");
+ break;
+ case LOG_ALERT:
+ pass.print ("%s : ", "LOG_ALERT");
+ break;
+ case LOG_CRIT:
+ pass.print ("%s : ", "LOG_CRIT");
+ break;
case LOG_ERR:
pass.print ("%s : ", "LOG_ERR");
break;
case LOG_WARNING:
pass.print ("%s : ", "LOG_WARNING");
break;
+ case LOG_NOTICE:
+ pass.print ("%s : ", "LOG_NOTICE");
+ break;
case LOG_INFO:
pass.print ("%s : ", "LOG_INFO");
+ break;
+ case LOG_DEBUG:
+ pass.print ("%s : ", "LOG_DEBUG");
break;
default:
pass.print ("%s : ", "LOG_ERR");
@@ -368,7 +389,7 @@ syslog (int priority, const char *message, ...)
HANDLE fHandle = cygheap->fdtab[fileno (fp)]->get_handle ();
if (LockFile (fHandle, 0, 0, 1, 0) == FALSE)
{
- debug_printf ("failed to lock file %s", get_win95_event_log_path());
+ debug_printf ("failed to lock file %s", get_win95_event_log_path ());
fclose (fp);
return;
}
diff --git a/winsup/cygwin/termios.cc b/winsup/cygwin/termios.cc
index 5488185c4..13b5e5251 100644
--- a/winsup/cygwin/termios.cc
+++ b/winsup/cygwin/termios.cc
@@ -1,6 +1,6 @@
/* termios.cc: termios for WIN32.
- Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
Written by Doug Evans and Steve Chamberlain of Cygnus Support
dje@cygnus.com, sac@cygnus.com
@@ -14,6 +14,7 @@ details. */
#include "winsup.h"
#include <errno.h>
#include <signal.h>
+#include <stdlib.h>
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
@@ -22,6 +23,7 @@ details. */
#include "cygheap.h"
#include "cygwin/version.h"
#include "perprocess.h"
+#include "sigproc.h"
#include <sys/termios.h>
/* tcsendbreak: POSIX 7.2.2.1 */
@@ -30,22 +32,14 @@ tcsendbreak (int fd, int duration)
{
int res = -1;
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- goto out;
- }
-
- fhandler_base *fh;
- fh = cygheap->fdtab[fd];
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ goto out;
- if (!fh->is_tty ())
+ if (!cfd->is_tty ())
set_errno (ENOTTY);
- else
- {
- if ((res = fh->bg_check (-SIGTTOU)) > bg_eof)
- res = fh->tcsendbreak (duration);
- }
+ else if ((res = cfd->bg_check (-SIGTTOU)) > bg_eof)
+ res = cfd->tcsendbreak (duration);
out:
syscall_printf ("%d = tcsendbreak (%d, %d)", res, fd, duration);
@@ -60,22 +54,14 @@ tcdrain (int fd)
termios_printf ("tcdrain");
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- goto out;
- }
-
- fhandler_base *fh;
- fh = cygheap->fdtab[fd];
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ goto out;
- if (!fh->is_tty ())
+ if (!cfd->is_tty ())
set_errno (ENOTTY);
- else
- {
- if ((res = fh->bg_check (-SIGTTOU)) > bg_eof)
- res = fh->tcdrain ();
- }
+ else if ((res = cfd->bg_check (-SIGTTOU)) > bg_eof)
+ res = cfd->tcdrain ();
out:
syscall_printf ("%d = tcdrain (%d)", res, fd);
@@ -88,22 +74,14 @@ tcflush (int fd, int queue)
{
int res = -1;
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- goto out;
- }
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ goto out;
- fhandler_base *fh;
- fh = cygheap->fdtab[fd];
-
- if (!fh->is_tty ())
+ if (!cfd->is_tty ())
set_errno (ENOTTY);
- else
- {
- if ((res = fh->bg_check (-SIGTTOU)) > bg_eof)
- res = fh->tcflush (queue);
- }
+ else if ((res = cfd->bg_check (-SIGTTOU)) > bg_eof)
+ res = cfd->tcflush (queue);
out:
termios_printf ("%d = tcflush (%d, %d)", res, fd, queue);
@@ -116,22 +94,14 @@ tcflow (int fd, int action)
{
int res = -1;
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- goto out;
- }
-
- fhandler_base *fh;
- fh = cygheap->fdtab[fd];
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ goto out;
- if (!fh->is_tty ())
+ if (!cfd->is_tty ())
set_errno (ENOTTY);
- else
- {
- if ((res = fh->bg_check (-SIGTTOU)) > bg_eof)
- res = fh->tcflow (action);
- }
+ else if ((res = cfd->bg_check (-SIGTTOU)) > bg_eof)
+ res = cfd->tcflow (action);
out:
syscall_printf ("%d = tcflow (%d, %d)", res, fd, action);
@@ -142,29 +112,55 @@ out:
extern "C" int
tcsetattr (int fd, int a, const struct termios *t)
{
- int res = -1;
-
- if (cygheap->fdtab.not_open (fd))
- {
- set_errno (EBADF);
- goto out;
- }
-
+ int res;
t = __tonew_termios (t);
+ int e = get_errno ();
- fhandler_base *fh;
- fh = cygheap->fdtab[fd];
-
- if (!fh->is_tty ())
- set_errno (ENOTTY);
- else
+ while (1)
{
- if ((res = fh->bg_check (-SIGTTOU)) > bg_eof)
- res = fh->tcsetattr (a, t);
+ sigframe thisframe (mainthread);
+
+ res = -1;
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ {
+ e = get_errno ();
+ break;
+ }
+
+ if (!cfd->is_tty ())
+ {
+ e = ENOTTY;
+ break;
+ }
+
+ res = cfd->bg_check (-SIGTTOU);
+
+ switch (res)
+ {
+ case bg_eof:
+ e = get_errno ();
+ break;
+ case bg_ok:
+ if (cfd.isopen ())
+ res = cfd->tcsetattr (a, t);
+ else
+ e = get_errno ();
+ break;
+ case bg_signalled:
+ if (thisframe.call_signal_handler ())
+ continue;
+ res = -1;
+ /* fall through intentionally */
+ default:
+ e = get_errno ();
+ break;
+ }
+ break;
}
-out:
- termios_printf ("iflag %x, oflag %x, cflag %x, lflag %x, VMIN %d, VTIME %d",
+ set_errno (e);
+ termios_printf ("iflag %p, oflag %p, cflag %p, lflag %p, VMIN %d, VTIME %d",
t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag, t->c_cc[VMIN],
t->c_cc[VTIME]);
termios_printf ("%d = tcsetattr (%d, %d, %x)", res, fd, a, t);
@@ -178,15 +174,13 @@ tcgetattr (int fd, struct termios *in_t)
int res = -1;
struct termios *t = __makenew_termios (in_t);
- if (cygheap->fdtab.not_open (fd))
- set_errno (EBADF);
- else if (!cygheap->fdtab[fd]->is_tty ())
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ /* saw an error */;
+ else if (!cfd->is_tty ())
set_errno (ENOTTY);
- else
- {
- if ((res = cygheap->fdtab[fd]->tcgetattr (t)) == 0)
- (void) __toapp_termios (in_t, t);
- }
+ else if ((res = cfd->tcgetattr (t)) == 0)
+ (void) __toapp_termios (in_t, t);
if (res)
termios_printf ("%d = tcgetattr (%d, %p)", res, fd, in_t);
@@ -204,12 +198,13 @@ tcgetpgrp (int fd)
{
int res = -1;
- if (cygheap->fdtab.not_open (fd))
- set_errno (EBADF);
- else if (!cygheap->fdtab[fd]->is_tty ())
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ /* saw an error */;
+ else if (!cfd->is_tty ())
set_errno (ENOTTY);
else
- res = cygheap->fdtab[fd]->tcgetpgrp ();
+ res = cfd->tcgetpgrp ();
termios_printf ("%d = tcgetpgrp (%d)", res, fd);
return res;
@@ -221,12 +216,13 @@ tcsetpgrp (int fd, pid_t pgid)
{
int res = -1;
- if (cygheap->fdtab.not_open (fd))
- set_errno (EBADF);
- else if (!cygheap->fdtab[fd]->is_tty ())
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ /* saw an error */;
+ else if (!cfd->is_tty ())
set_errno (ENOTTY);
else
- res = cygheap->fdtab[fd]->tcsetpgrp (pgid);
+ res = cfd->tcsetpgrp (pgid);
termios_printf ("%d = tcsetpgrp (%d, %x)", res, fd, pgid);
return res;
@@ -242,14 +238,14 @@ tcsetpgrp (int fd, pid_t pgid)
extern "C" speed_t
cfgetospeed (struct termios *tp)
{
- return __tonew_termios(tp)->c_ospeed;
+ return __tonew_termios (tp)->c_ospeed;
}
/* cfgetispeed: POSIX96 7.1.3.1 */
extern "C" speed_t
cfgetispeed (struct termios *tp)
{
- return __tonew_termios(tp)->c_ispeed;
+ return __tonew_termios (tp)->c_ispeed;
}
/* cfsetospeed: POSIX96 7.1.3.1 */
diff --git a/winsup/cygwin/test.c b/winsup/cygwin/test.c
deleted file mode 100644
index a7c61665a..000000000
--- a/winsup/cygwin/test.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/* test.c: misc Cygwin testing code
-
- Copyright 1996, 1998, 1999, 2000, 2001 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#include <stdio.h>
-#include <windows.h>
-
-char a[] ="This is static data";
-
-void
-test1()
-{
- int depth = 0;
- while (depth < 5)
- {
- int r;
- printf ("about to fork %d\n", depth);
-
- r = fork ();
-
- if (r == 0)
- {
- int res;
- depth++;
- printf ("************Depth is %d\n", depth);
- sleep (1);
- }
- else
- {
- printf ("This is the parent, quitting %d\n", depth);
- sleep (1);
- exit (1);
- }
- printf ("done loop, depth %d\n", depth);
- }
-}
-
-#define N 10
-int v[N];
-startup ()
-{
- int i;
- for (i = 0; i < N; i++)
- {
- int r;
- fflush (stdout);
- r = fork ();
- if (r)
- {
- v[i] = r;
- printf ("started %d, were'id %d\n", v[i], GetCurrentProcessId ());
- fflush (stdout);
- }
- else
- {
- /* running the child, sleep a bit and exit. */
- printf ("the fork said 0, were %d\n", GetCurrentProcessId ());
- fflush (stdout);
- sleep (2);
- printf ("Running, and exiting %d\n", i);
- fflush (stdout);
- _exit (i + 0x30);
- }
- }
-}
-
-test2()
-{
- int i;
- startup ();
- sleep (1);
- /* Wait for them one by one */
- for (i = 0; i < N; i++)
- {
- int res;
-
- waitpid (v[i], &res, 0);
- printf ("Process %d gave res %x\n", v[i], res);
- if (res != (0x30 + i) << 8)
- printf ("***** BAD *** Process %d gave res %x\n", v[i], res);
- }
-}
-
-test3()
-{
- int i;
- startup ();
- /* Wait for them all at the same time */
- for (i = 0; i < N; i++)
- {
- int res;
- wait (&res);
- printf ("Got res %x\n", res);
- }
-}
-
-test5()
-{
- char *c = strdup ("HI STEVE");
- printf ("c is %s\n", c);
- free (c);
-}
-
-int count;
-
-main (int ac, char **av)
-{
- int r;
- int done;
- int test;
- fprintf (stderr,"TO STDERR\n");
- if (ac < 2) {
- printf ("usage: test <n>\n");
- exit (2);
- }
- test = atoi (av[1]);
-
- printf ("%d %d Hi steve, about to start fork test %d %d.\n",getpid (), count++, test,
- GetCurrentProcessId ());
-fflush (stdout);
- switch (test)
- {
- case 1:
- test1();
- break;
- case 2:
- test2();
- break;
- case 3:
- test3();
- break;
- case 4:
-SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE), FOREGROUND_RED);
-break;
- case 5:
- test5();
-break;
- }
-
-}
-
-free ()
-{
- printf ("MY FREE!\n");
-}
-
-char b[100000];
-int i;
-
-malloc (x)
-{
-char *r = b + i;
-i += x;
-return r;
-}
-
-realloc ()
-{
-}
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index 8b6f1b6d6..84add47c5 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -1,9 +1,9 @@
-/*thread.cc: Locking and threading module functions
+/* thread.cc: Locking and threading module functions
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Originally written by Marco Fuykschot <marco@ddi.nl>
- Substantialy enhanced by Robert Collins <<rbtcollins@hotmail.com>
+ Substantialy enhanced by Robert Collins <rbtcollins@hotmail.com>
This file is part of Cygwin.
@@ -37,8 +37,6 @@ details. */
#include <assert.h>
#include <stdlib.h>
#include <syslog.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "perprocess.h"
#include "security.h"
@@ -48,92 +46,6 @@ details. */
extern int threadsafe;
-/*pthread_key_destructor_list class: to-be threadsafe single linked list
- *FIXME: Put me in a dedicated file, or a least a tools area !
- */
-
-pthread_key_destructor *
-pthread_key_destructor::InsertAfter (pthread_key_destructor *node)
-{
- pthread_key_destructor *temp = next;
- next = node;
- return temp;
-}
-
-pthread_key_destructor *
-pthread_key_destructor::UnlinkNext ()
-{
- pthread_key_destructor *temp = next;
- if (next)
- next = next->Next ();
- return temp;
-}
-
-pthread_key_destructor *
-pthread_key_destructor::Next ()
-{
- return next;
-}
-
-void
-pthread_key_destructor_list::Insert (pthread_key_destructor *node)
-{
- if (!node)
- return;
- head = node->InsertAfter (head);
- if (!head)
- head = node; /*first node special case */
-}
-
- /*remove a given dataitem, wherever in the list it is */
-pthread_key_destructor *
-pthread_key_destructor_list::Remove (pthread_key *key)
-{
- if (!key)
- return NULL;
- if (!head)
- return NULL;
- if (key == head->key)
- return Pop ();
- pthread_key_destructor *temp = head;
- while (temp && temp->Next () && !(key == temp->Next ()->key))
- {
- temp = temp->Next ();
- }
- if (temp)
- return temp->UnlinkNext ();
- return NULL;
-}
-
- /*get the first item and remove at the same time */
-pthread_key_destructor *
-pthread_key_destructor_list::Pop ()
-{
- pthread_key_destructor *temp = head;
- head = head->Next ();
- return temp;
-}
-
-pthread_key_destructor::
-pthread_key_destructor (void (*thedestructor) (void *), pthread_key *key)
-{
- destructor = thedestructor;
- next = NULL;
- this->key = key;
-}
-
-void
-pthread_key_destructor_list::IterateNull ()
-{
- pthread_key_destructor *temp = head;
- while (temp)
- {
- temp->destructor ((temp->key)->get ());
- temp = temp->Next ();
- }
-}
-
-
#define MT_INTERFACE user_data->threadinterface
struct _reent *
@@ -254,51 +166,30 @@ ResourceLocks::Delete ()
void
MTinterface::Init (int forked)
{
-#if 0
- for (int i = 0; i < MT_MAX_ITEMS; i++)
- {
- threadlist.items[i] = NULL;
- mutexlist.items[i] = NULL;
- semalist.items[i] = NULL;
- }
-
- threadlist.index = 0;
- mutexlist.index = 0;
- semalist.index = 0;
-#endif
reent_index = TlsAlloc ();
reents._clib = _impure_ptr;
reents._winsup = &winsup_reent;
winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG);
-#if 0
- winsup_reent._grp_pos = 0;
- winsup_reent._process_ident = 0;
- winsup_reent._process_logopt = 0;
- winsup_reent._process_facility = 0;
-#endif
TlsSetValue (reent_index, &reents);
// the static reent_data will be used in the main thread
-
if (!indexallocated)
{
- indexallocated = (-1);
thread_self_dwTlsIndex = TlsAlloc ();
if (thread_self_dwTlsIndex == TLS_OUT_OF_INDEXES)
system_printf
- ("local storage for thread couldn't be set\nThis means that we are not thread safe!\n");
+ ("local storage for thread couldn't be set\nThis means that we are not thread safe!");
+ else
+ indexallocated = (-1);
}
concurrency = 0;
threadcount = 1; /*1 current thread when Init occurs.*/
- mainthread.win32_obj_id = myself->hProcess;
- mainthread.setThreadIdtoCurrent ();
- /*store the main thread's self pointer */
- TlsSetValue (thread_self_dwTlsIndex, &mainthread);
+ pthread::initMainThread (&mainthread, myself->hProcess);
if (forked)
return;
@@ -307,37 +198,35 @@ MTinterface::Init (int forked)
conds = NULL;
semaphores = NULL;
- /*possible the atfork lists should be inited here as well */
-
-#if 0
- item->function = NULL;
+}
- item->sigs = NULL;
- item->sigmask = NULL;
- item->sigtodo = NULL;
-#endif
+void
+MTinterface::fixup_before_fork (void)
+{
+ pthread_key::fixup_before_fork ();
}
/* This function is called from a single threaded process */
void
MTinterface::fixup_after_fork (void)
{
+ pthread_key::fixup_after_fork ();
pthread_mutex *mutex = mutexs;
- debug_printf("mutexs is %x\n",mutexs);
+ debug_printf ("mutexs is %x",mutexs);
while (mutex)
{
mutex->fixup_after_fork ();
mutex = mutex->next;
}
pthread_cond *cond = conds;
- debug_printf("conds is %x\n",conds);
+ debug_printf ("conds is %x",conds);
while (cond)
{
cond->fixup_after_fork ();
cond = cond->next;
}
semaphore *sem = semaphores;
- debug_printf("semaphores is %x\n",semaphores);
+ debug_printf ("semaphores is %x",semaphores);
while (sem)
{
sem->fixup_after_fork ();
@@ -345,8 +234,46 @@ MTinterface::fixup_after_fork (void)
}
}
+/* pthread calls */
+
+/* static methods */
+void
+pthread::initMainThread (pthread *mainThread, HANDLE win32_obj_id)
+{
+ mainThread->win32_obj_id = win32_obj_id;
+ mainThread->setThreadIdtoCurrent ();
+ setTlsSelfPointer (mainThread);
+}
+
+pthread *
+pthread::self ()
+{
+ pthread *temp = (pthread *) TlsGetValue (MT_INTERFACE->thread_self_dwTlsIndex);
+ if (temp)
+ return temp;
+ temp = new pthread ();
+ temp->precreate (NULL);
+ if (!temp->magic) {
+ delete temp;
+ return pthreadNull::getNullpthread ();
+ }
+ temp->postcreate ();
+ return temp;
+}
+
+void
+pthread::setTlsSelfPointer (pthread *thisThread)
+{
+ /*the OS doesn't check this for <= 64 Tls entries (pre win2k) */
+ TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thisThread);
+}
+
+
+
+/* member methods */
pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0),
-cancelstate (0), canceltype (0)
+ cancelstate (0), canceltype (0), cancel_event (0),
+ joiner (NULL), cleanup_stack (NULL)
{
}
@@ -354,13 +281,21 @@ pthread::~pthread ()
{
if (win32_obj_id)
CloseHandle (win32_obj_id);
+ if (cancel_event)
+ CloseHandle (cancel_event);
}
+void
+pthread::setThreadIdtoCurrent ()
+{
+ thread_id = GetCurrentThreadId ();
+}
void
-pthread::create (void *(*func) (void *), pthread_attr *newattr,
- void *threadarg)
+pthread::precreate (pthread_attr *newattr)
{
+ pthread_mutex *verifyable_mutex_obj = &mutex;
+
/*already running ? */
if (win32_obj_id)
return;
@@ -372,27 +307,424 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr,
attr.inheritsched = newattr->inheritsched;
attr.stacksize = newattr->stacksize;
}
- function = func;
- arg = threadarg;
- win32_obj_id =::CreateThread (&sec_none_nih, attr.stacksize,
+ if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj))
+ {
+ thread_printf ("New thread object access mutex is not valid. this %p",
+ this);
+ magic = 0;
+ return;
+ }
+
+ cancel_event = ::CreateEvent (NULL,TRUE,FALSE,NULL);
+ if (!cancel_event)
+ {
+ system_printf ("couldn't create cancel event, this %p LastError %d", this, GetLastError () );
+ /*we need the event for correct behaviour */
+ magic = 0;
+ return;
+ }
+}
+
+void
+pthread::create (void *(*func) (void *), pthread_attr *newattr,
+ void *threadarg)
+{
+ precreate (newattr);
+ if (!magic)
+ return;
+ function = func;
+ arg = threadarg;
+
+ win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize,
(LPTHREAD_START_ROUTINE) thread_init_wrapper,
this, CREATE_SUSPENDED, &thread_id);
if (!win32_obj_id)
- magic = 0;
- else
{
- /*FIXME: set the priority appropriately for system contention scope */
- if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED)
- {
- /*FIXME: set the scheduling settings for the new thread */
- /*sched_thread_setparam (win32_obj_id, attr.schedparam); */
- }
+ thread_printf ("CreateThread failed: this %p LastError %E", this);
+ magic = 0;
+ }
+ else {
+ postcreate ();
ResumeThread (win32_obj_id);
+ }
+}
+
+void
+pthread::postcreate ()
+{
+ InterlockedIncrement (&MT_INTERFACE->threadcount);
+ /*FIXME: set the priority appropriately for system contention scope */
+ if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED)
+ {
+ /*FIXME: set the scheduling settings for the new thread */
+ /*sched_thread_setparam (win32_obj_id, attr.schedparam); */
+ }
+}
+
+void
+pthread::exit (void *value_ptr)
+{
+ class pthread *thread = this;
+
+ // run cleanup handlers
+ pop_all_cleanup_handlers ();
+
+ pthread_key::runAllDestructors ();
+
+ mutex.Lock ();
+ // cleanup if thread is in detached state and not joined
+ if (__pthread_equal (&joiner, &thread ) )
+ delete this;
+ else
+ {
+ return_ptr = value_ptr;
+ mutex.UnLock ();
+ }
+
+ /* Prevent DLL_THREAD_DETACH Attempting to clean us up */
+ setTlsSelfPointer (0);
+
+ if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0)
+ ::exit (0);
+ else
+ ExitThread (0);
+}
+
+int
+pthread::cancel (void)
+{
+ class pthread *thread = this;
+ class pthread *self = pthread::self ();
+
+ mutex.Lock ();
+
+ if (canceltype == PTHREAD_CANCEL_DEFERRED ||
+ cancelstate == PTHREAD_CANCEL_DISABLE)
+ {
+ // cancel deferred
+ mutex.UnLock ();
+ SetEvent (cancel_event);
+ return 0;
+ }
+
+ else if (__pthread_equal (&thread, &self))
+ {
+ mutex.UnLock ();
+ cancel_self ();
+ return 0; // Never reached
+ }
+
+ // cancel asynchronous
+ SuspendThread (win32_obj_id);
+ if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
+ {
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_CONTROL;
+ GetThreadContext (win32_obj_id, &context);
+ context.Eip = (DWORD) pthread::static_cancel_self;
+ SetThreadContext (win32_obj_id, &context);
+ }
+ mutex.UnLock ();
+ ResumeThread (win32_obj_id);
+
+ return 0;
+/*
+ TODO: insert pthread_testcancel into the required functions
+ the required function list is: *indicates done, X indicates not present in cygwin.
+aio_suspend ()
+*close ()
+*creat ()
+fcntl ()
+fsync ()
+getmsg ()
+getpmsg ()
+lockf ()
+mq_receive ()
+mq_send ()
+msgrcv ()
+msgsnd ()
+msync ()
+nanosleep ()
+open ()
+pause ()
+poll ()
+pread ()
+pthread_cond_timedwait ()
+pthread_cond_wait ()
+*pthread_join ()
+pthread_testcancel ()
+putmsg ()
+putpmsg ()
+pwrite ()
+read ()
+readv ()
+select ()
+sem_wait ()
+sigpause ()
+sigsuspend ()
+sigtimedwait ()
+sigwait ()
+sigwaitinfo ()
+*sleep ()
+system ()
+tcdrain ()
+*usleep ()
+wait ()
+wait3()
+waitid ()
+waitpid ()
+write ()
+writev ()
+
+the optional list is:
+catclose ()
+catgets ()
+catopen ()
+closedir ()
+closelog ()
+ctermid ()
+dbm_close ()
+dbm_delete ()
+dbm_fetch ()
+dbm_nextkey ()
+dbm_open ()
+dbm_store ()
+dlclose ()
+dlopen ()
+endgrent ()
+endpwent ()
+endutxent ()
+fclose ()
+fcntl ()
+fflush ()
+fgetc ()
+fgetpos ()
+fgets ()
+fgetwc ()
+fgetws ()
+fopen ()
+fprintf ()
+fputc ()
+fputs ()
+fputwc ()
+fputws ()
+fread ()
+freopen ()
+fscanf ()
+fseek ()
+fseeko ()
+fsetpos ()
+ftell ()
+ftello ()
+ftw ()
+fwprintf ()
+fwrite ()
+fwscanf ()
+getc ()
+getc_unlocked ()
+getchar ()
+getchar_unlocked ()
+getcwd ()
+getdate ()
+getgrent ()
+getgrgid ()
+getgrgid_r ()
+getgrnam ()
+getgrnam_r ()
+getlogin ()
+getlogin_r ()
+getpwent ()
+*getpwnam ()
+*getpwnam_r ()
+*getpwuid ()
+*getpwuid_r ()
+gets ()
+getutxent ()
+getutxid ()
+getutxline ()
+getw ()
+getwc ()
+getwchar ()
+getwd ()
+glob ()
+iconv_close ()
+iconv_open ()
+ioctl ()
+lseek ()
+mkstemp ()
+nftw ()
+opendir ()
+openlog ()
+pclose ()
+perror ()
+popen ()
+printf ()
+putc ()
+putc_unlocked ()
+putchar ()
+putchar_unlocked ()
+puts ()
+pututxline ()
+putw ()
+putwc ()
+putwchar ()
+readdir ()
+readdir_r ()
+remove ()
+rename ()
+rewind ()
+rewinddir ()
+scanf ()
+seekdir ()
+semop ()
+setgrent ()
+setpwent ()
+setutxent ()
+strerror ()
+syslog ()
+tmpfile ()
+tmpnam ()
+ttyname ()
+ttyname_r ()
+ungetc ()
+ungetwc ()
+unlink ()
+vfprintf ()
+vfwprintf ()
+vprintf ()
+vwprintf ()
+wprintf ()
+wscanf ()
+
+Note, that for fcntl (), for any value of the cmd argument.
+
+And we must not introduce cancellation points anywhere else that's part of the posix or
+opengroup specs.
+ */
+}
+
+void
+pthread::testcancel (void)
+{
+ if (cancelstate == PTHREAD_CANCEL_DISABLE)
+ return;
+
+ if (WAIT_OBJECT_0 == WaitForSingleObject (cancel_event, 0 ) )
+ cancel_self ();
+}
+
+void
+pthread::static_cancel_self (void)
+{
+ pthread::self ()->cancel_self ();
+}
+
+
+int
+pthread::setcancelstate (int state, int *oldstate)
+{
+ int result = 0;
+
+ mutex.Lock ();
+
+ if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)
+ result = EINVAL;
+ else
+ {
+ if (oldstate)
+ *oldstate = cancelstate;
+ cancelstate = state;
+ }
+
+ mutex.UnLock ();
+
+ return result;
+}
+
+int
+pthread::setcanceltype (int type, int *oldtype)
+{
+ int result = 0;
+
+ mutex.Lock ();
+
+ if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)
+ result = EINVAL;
+ else
+ {
+ if (oldtype)
+ *oldtype = canceltype;
+ canceltype = type;
+ }
+
+ mutex.UnLock ();
+
+ return result;
+}
+
+void
+pthread::push_cleanup_handler (__pthread_cleanup_handler *handler)
+{
+ if (this != self ())
+ // TODO: do it?
+ api_fatal ("Attempt to push a cleanup handler across threads");
+ handler->next = cleanup_stack;
+ InterlockedExchangePointer (&cleanup_stack, handler );
+}
+
+void
+pthread::pop_cleanup_handler (int const execute)
+{
+ if (this != self ())
+ // TODO: send a signal or something to the thread ?
+ api_fatal ("Attempt to execute a cleanup handler across threads");
+
+ mutex.Lock ();
+
+ if (cleanup_stack != NULL)
+ {
+ __pthread_cleanup_handler *handler = cleanup_stack;
+
+ if (execute)
+ (*handler->function) (handler->arg);
+ cleanup_stack = handler->next;
}
+
+ mutex.UnLock ();
}
+void
+pthread::pop_all_cleanup_handlers ()
+{
+ while (cleanup_stack != NULL)
+ pop_cleanup_handler (1);
+}
+
+void
+pthread::cancel_self ()
+{
+ exit (PTHREAD_CANCELED);
+}
+
+DWORD
+pthread::getThreadId ()
+{
+ return thread_id;
+}
+
+/* static members */
+bool
+pthread_attr::isGoodObject (pthread_attr_t const *attr)
+{
+ if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+/* instance members */
+
pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC),
joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS),
inheritsched (PTHREAD_INHERIT_SCHED), stacksize (0)
@@ -404,6 +736,14 @@ pthread_attr::~pthread_attr ()
{
}
+bool
+pthread_condattr::isGoodObject (pthread_condattr_t const *attr)
+{
+ if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
pthread_condattr::pthread_condattr ():verifyable_object
(PTHREAD_CONDATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE)
{
@@ -420,14 +760,14 @@ pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_C
this->mutex = NULL;
this->waiting = 0;
- this->win32_obj_id =::CreateEvent (&sec_none_nih, false, /*auto signal reset - which I think is pthreads like ? */
+ this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, /*auto signal reset - which I think is pthreads like ? */
false, /*start non signaled */
NULL /*no name */);
/*TODO: make a shared mem mutex if out attributes request shared mem cond */
- cond_access=NULL;
+ cond_access = NULL;
if ((temperr = pthread_mutex_init (&this->cond_access, NULL)))
{
- system_printf ("couldn't init mutex, this %0p errno=%d\n", this, temperr);
+ system_printf ("couldn't init mutex, this %p errno %d", this, temperr);
/*we need the mutex for correct behaviour */
magic = 0;
}
@@ -435,7 +775,7 @@ pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_C
if (!this->win32_obj_id)
magic = 0;
/* threadsafe addition is easy */
- next = (pthread_cond *)InterlockedExchangePointer (&MT_INTERFACE->conds, this);
+ next = (pthread_cond *) InterlockedExchangePointer (&MT_INTERFACE->conds, this);
}
pthread_cond::~pthread_cond ()
@@ -461,33 +801,33 @@ pthread_cond::BroadCast ()
{
/* TODO: implement the same race fix as Signal has */
if (pthread_mutex_lock (&cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %0p\n", this);
+ system_printf ("Failed to lock condition variable access mutex, this %p", this);
int count = waiting;
- if (verifyable_object_isvalid (&mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (&mutex))
{
if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", this);
/*This isn't and API error - users are allowed to call this when no threads
are waiting
- system_printf ("Broadcast called with invalid mutex\n");
+ system_printf ("Broadcast called with invalid mutex");
*/
return;
}
while (count--)
PulseEvent (win32_obj_id);
if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", this);
}
void
pthread_cond::Signal ()
{
if (pthread_mutex_lock (&cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %0p\n", this);
- if (verifyable_object_isvalid (&mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ system_printf ("Failed to lock condition variable access mutex, this %p", this);
+ if (!pthread_mutex::isGoodObject (&mutex))
{
if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n",
+ system_printf ("Failed to unlock condition variable access mutex, this %p",
this);
return;
}
@@ -496,29 +836,42 @@ pthread_cond::Signal ()
/* nothing to signal */
{
if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", this);
return;
}
+ /* Prime the detection flag */
+ ExitingWait = 1;
+ /* Signal any waiting thread */
PulseEvent (win32_obj_id);
/* No one can start waiting until we release the condition access mutex */
/* The released thread will decrement waiting when it gets a time slice...
without waiting for the access mutex
+ * InterLockedIncrement on 98 +, NT4 + returns the incremented value.
+ * On 95, nt 3.51 < it returns a sign correct number - 0=0, + for greater than 0, -
+ * for less than 0.
+ * Because of this we cannot spin on the waiting count, but rather we need a
+ * dedicated flag for a thread exiting the Wait function.
+ * Also not that Interlocked* sync CPU caches with memory.
*/
int spins = 10;
- while (InterlockedIncrement (&waiting) != (temp - 1) && spins)
+ /* When ExitingWait is nonzero after a decrement, the leaving thread has
+ * done it's thing
+ */
+ while (InterlockedDecrement (&ExitingWait) == 0 && spins)
{
- InterlockedDecrement (&waiting);
+ InterlockedIncrement (&ExitingWait);
/* give up the cpu to force a context switch. */
Sleep (0);
if (spins == 5)
- /* we've had 5 timeslices, and the woekn thread still hasn't done it's
+ /* we've had 5 timeslices, and the woken thread still hasn't done it's
* thing - maybe we raced it with the event? */
PulseEvent (win32_obj_id);
spins--;
}
- InterlockedDecrement (&waiting);
+ if (waiting + 1 != temp)
+ system_printf ("Released too many threads - %d now %d originally", waiting, temp);
if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", this);
}
int
@@ -563,40 +916,90 @@ pthread_cond::TimedWait (DWORD dwMilliseconds)
void
pthread_cond::fixup_after_fork ()
{
- debug_printf("cond %x in fixup_after_fork\n", this);
+ debug_printf ("cond %x in fixup_after_fork", this);
if (shared != PTHREAD_PROCESS_PRIVATE)
- api_fatal("doesn't understand PROCESS_SHARED condition variables\n");
+ api_fatal ("doesn't understand PROCESS_SHARED condition variables");
/* FIXME: duplicate code here and in the constructor. */
- this->win32_obj_id =::CreateEvent (&sec_none_nih, false, false, NULL);
+ this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL);
if (!win32_obj_id)
- api_fatal("failed to create new win32 mutex\n");
+ api_fatal ("failed to create new win32 mutex");
#if DETECT_BAD_APPS
if (waiting)
- api_fatal("Forked() while a condition variable has waiting threads.\nReport to cygwin@cygwin.com\n");
+ api_fatal ("Forked () while a condition variable has waiting threads.\nReport to cygwin@cygwin.com");
#else
waiting = 0;
mutex = NULL;
#endif
}
+/* pthread_key */
+/* static members */
+List<pthread_key> pthread_key::keys;
+
+void
+pthread_key::saveAKey (pthread_key *key)
+{
+ key->saveKeyToBuffer ();
+}
-pthread_key::pthread_key (void (*destructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC)
+void
+pthread_key::fixup_before_fork ()
+{
+ keys.forEach (saveAKey);
+}
+
+void
+pthread_key::restoreAKey (pthread_key *key)
+{
+ key->recreateKeyFromBuffer ();
+}
+
+void
+pthread_key::fixup_after_fork ()
+{
+ keys.forEach (restoreAKey);
+}
+
+void
+pthread_key::destroyAKey (pthread_key *key)
+{
+ key->run_destructor ();
+}
+
+void
+pthread_key::runAllDestructors ()
+{
+ keys.forEach (destroyAKey);
+}
+
+bool
+pthread_key::isGoodObject (pthread_key_t const *key)
+{
+ if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+/* non-static members */
+
+pthread_key::pthread_key (void (*aDestructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC), destructor (aDestructor)
{
dwTlsIndex = TlsAlloc ();
if (dwTlsIndex == TLS_OUT_OF_INDEXES)
magic = 0;
- else if (destructor)
- {
- MT_INTERFACE->destructors.
- Insert (new pthread_key_destructor (destructor, this));
- }
+ else
+ keys.Insert (this);
}
pthread_key::~pthread_key ()
{
- if (pthread_key_destructor *dest = MT_INTERFACE->destructors.Remove (this))
- delete dest;
- TlsFree (dwTlsIndex);
+ /* We may need to make the list code lock the list during operations
+ */
+ if (magic != 0)
+ {
+ keys.Remove (this);
+ TlsFree (dwTlsIndex);
+ }
}
int
@@ -608,10 +1011,34 @@ pthread_key::set (const void *value)
}
void *
-pthread_key::get ()
+pthread_key::get () const
+{
+ int savedError = ::GetLastError ();
+ void *result = TlsGetValue (dwTlsIndex);
+ ::SetLastError (savedError);
+ return result;
+}
+
+void
+pthread_key::saveKeyToBuffer ()
+{
+ fork_buf = get ();
+}
+
+void
+pthread_key::recreateKeyFromBuffer ()
{
- set_errno (0);
- return TlsGetValue (dwTlsIndex);
+ dwTlsIndex = TlsAlloc ();
+ if (dwTlsIndex == TLS_OUT_OF_INDEXES)
+ api_fatal ("pthread_key::recreateKeyFromBuffer () failed to reallocate Tls storage");
+ set (fork_buf);
+}
+
+void
+pthread_key::run_destructor () const
+{
+ if (destructor)
+ destructor (get ());
}
/*pshared mutexs:
@@ -638,10 +1065,35 @@ pthread_key::get ()
*Isn't duplicated, it's reopened.
*/
+/* static members */
+bool
+pthread_mutex::isGoodObject (pthread_mutex_t const *mutex)
+{
+ if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_mutex::isGoodInitializer (pthread_mutex_t const *mutex)
+{
+ if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != VALID_STATIC_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_mutex::isGoodInitializerOrObject (pthread_mutex_t const *mutex)
+{
+ if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) == INVALID_OBJECT)
+ return false;
+ return true;
+}
+
pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC)
{
/*attr checked in the C call */
- if (attr && attr->pshared==PTHREAD_PROCESS_SHARED)
+ if (attr && attr->pshared == PTHREAD_PROCESS_SHARED)
{
// fail
magic = 0;
@@ -651,14 +1103,14 @@ pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREA
InitializeCriticalSection (&criticalsection);
else
{
- this->win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL);
+ this->win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL);
if (!win32_obj_id)
magic = 0;
}
condwaits = 0;
pshared = PTHREAD_PROCESS_PRIVATE;
/* threadsafe addition is easy */
- next = (pthread_mutex *)InterlockedExchangePointer (&MT_INTERFACE->mutexs, this);
+ next = (pthread_mutex *) InterlockedExchangePointer (&MT_INTERFACE->mutexs, this);
}
pthread_mutex::~pthread_mutex ()
@@ -721,26 +1173,34 @@ pthread_mutex::UnLock ()
void
pthread_mutex::fixup_after_fork ()
{
- debug_printf("mutex %x in fixup_after_fork\n", this);
+ debug_printf ("mutex %x in fixup_after_fork", this);
if (pshared != PTHREAD_PROCESS_PRIVATE)
- api_fatal("pthread_mutex::fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's\n");
+ api_fatal ("pthread_mutex::fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's");
/* FIXME: duplicate code here and in the constructor. */
if (wincap.has_try_enter_critical_section ())
- InitializeCriticalSection(&criticalsection);
+ InitializeCriticalSection (&criticalsection);
else
{
- win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL);
+ win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL);
if (!win32_obj_id)
- api_fatal("pthread_mutex::fixup_after_fork() failed to create new win32 mutex\n");
+ api_fatal ("pthread_mutex::fixup_after_fork () failed to create new win32 mutex");
}
#if DETECT_BAD_APPS
if (condwaits)
- api_fatal("Forked() while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com\n");
+ api_fatal ("Forked () while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com");
#else
condwaits = 0;
#endif
}
+bool
+pthread_mutexattr::isGoodObject (pthread_mutexattr_t const * attr)
+{
+ if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC),
pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT)
{
@@ -752,14 +1212,14 @@ pthread_mutexattr::~pthread_mutexattr ()
semaphore::semaphore (int pshared, unsigned int value):verifyable_object (SEM_MAGIC)
{
- this->win32_obj_id =::CreateSemaphore (&sec_none_nih, value, LONG_MAX,
+ this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, value, LONG_MAX,
NULL);
if (!this->win32_obj_id)
magic = 0;
this->shared = pshared;
currentvalue = value;
/* threadsafe addition is easy */
- next = (semaphore *)InterlockedExchangePointer (&MT_INTERFACE->semaphores, this);
+ next = (semaphore *) InterlockedExchangePointer (&MT_INTERFACE->semaphores, this);
}
semaphore::~semaphore ()
@@ -794,7 +1254,10 @@ semaphore::TryWait ()
*We probably need WaitForMultipleObjects here.
*/
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
- return EAGAIN;
+ {
+ set_errno (EAGAIN);
+ return -1;
+ }
currentvalue--;
return 0;
}
@@ -809,13 +1272,13 @@ semaphore::Wait ()
void
semaphore::fixup_after_fork ()
{
- debug_printf("sem %x in fixup_after_fork\n", this);
+ debug_printf ("sem %x in fixup_after_fork", this);
if (shared != PTHREAD_PROCESS_PRIVATE)
- api_fatal("doesn't understand PROCESS_SHARED semaphores variables\n");
+ api_fatal ("doesn't understand PROCESS_SHARED semaphores variables");
/* FIXME: duplicate code here and in the constructor. */
- this->win32_obj_id =::CreateSemaphore (&sec_none_nih, currentvalue, LONG_MAX, NULL);
+ this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue, LONG_MAX, NULL);
if (!win32_obj_id)
- api_fatal("failed to create new win32 semaphore\n");
+ api_fatal ("failed to create new win32 semaphore");
}
verifyable_object::verifyable_object (long verifyer):
@@ -862,14 +1325,14 @@ verifyable_object_isvalid (void const * objectptr, long magic)
/* Pthreads */
void *
-thread_init_wrapper (void *_arg)
+pthread::thread_init_wrapper (void *_arg)
{
// Setup the local/global storage of this thread
pthread *thread = (pthread *) _arg;
struct __reent_t local_reent;
struct _winsup_t local_winsup;
- struct _reent local_clib = _REENT_INIT(local_clib);
+ struct _reent local_clib = _REENT_INIT (local_clib);
struct sigaction _sigs[NSIG];
sigset_t _sig_mask; /*one set for everything to ignore. */
@@ -891,8 +1354,13 @@ thread_init_wrapper (void *_arg)
if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent))
system_printf ("local storage for thread couldn't be set");
- /*the OS doesn't check this for <=64 Tls entries (pre win2k) */
- TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thread);
+ setTlsSelfPointer (thread);
+
+ thread->mutex.Lock ();
+ // if thread is detached force cleanup on exit
+ if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL)
+ thread->joiner = pthread::self ();
+ thread->mutex.UnLock ();
#ifdef _CYG_THREAD_FAILSAFE
if (_REENT == _impure_ptr)
@@ -905,7 +1373,7 @@ thread_init_wrapper (void *_arg)
// call the user's thread
void *ret = thread->function (thread->arg);
- __pthread_exit (ret);
+ thread->exit (ret);
#if 0
// ??? This code only runs if the thread exits by returning.
@@ -915,29 +1383,47 @@ thread_init_wrapper (void *_arg)
return 0;
}
+bool
+pthread::isGoodObject (pthread_t const *thread)
+{
+ if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+unsigned long
+pthread::getsequence_np ()
+{
+ return getThreadId ();
+}
+
int
-__pthread_create (pthread_t *thread, const pthread_attr_t *attr,
+pthread::create (pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
{
- if (attr && verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ DECLARE_TLS_STORAGE;
+ if (attr && !pthread_attr::isGoodObject (attr))
return EINVAL;
*thread = new pthread ();
(*thread)->create (start_routine, attr ? *attr : NULL, arg);
- if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (thread))
{
delete (*thread);
*thread = NULL;
return EAGAIN;
}
- InterlockedIncrement (&MT_INTERFACE->threadcount);
return 0;
}
int
-__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+pthread::once (pthread_once_t *once_control, void (*init_routine) (void))
{
+ // already done ?
+ if (once_control->state)
+ return 0;
+
pthread_mutex_lock (&once_control->mutex);
/*Here we must set a cancellation handler to unlock the mutex if needed */
/*but a cancellation handler is not the right thing. We need this in the thread
@@ -945,7 +1431,7 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
*at a time. Stote a mutex_t *in the pthread_structure. if that's non null unlock
*on pthread_exit ();
*/
- if (once_control->state == 0)
+ if (!once_control->state)
{
init_routine ();
once_control->state = 1;
@@ -955,251 +1441,13 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
return 0;
}
-/*Cancelability states */
-
-
-/*Perform the actual cancel */
-void
-__pthread_cleanup (pthread_t thread)
-{
-}
-
-
int
-__pthread_cancel (pthread_t thread)
+pthread::cancel (pthread_t thread)
{
- if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (&thread))
return ESRCH;
- if (thread->cancelstate == PTHREAD_CANCEL_ENABLE)
- {
-#if 0
- /*once all the functions call testcancel (), we will do this */
- if (thread->canceltype == PTHREAD_CANCEL_DEFERRED)
- {
- }
- else
- {
- /*possible FIXME: this function is meant to return asynchronously
- *from the cancellation routine actually firing. So we may need some sort
- *of signal to be sent that is immediately recieved and acted on.
- */
- __pthread_cleanup (thread);
- }
-#endif
- }
-/* return 0;
-*/
-
- return ESRCH;
-/*
- we return ESRCH until all the required functions call testcancel ();
- this will give applications predictable behaviour.
-
- the required function list is: *indicates done, X indicates not present in cygwin.
-aio_suspend ()
-*close ()
-*creat ()
-fcntl ()
-fsync ()
-getmsg ()
-getpmsg ()
-lockf ()
-mq_receive ()
-mq_send ()
-msgrcv ()
-msgsnd ()
-msync ()
-nanosleep ()
-open ()
-pause ()
-poll ()
-pread ()
-pthread_cond_timedwait ()
-pthread_cond_wait ()
-*pthread_join ()
-pthread_testcancel ()
-putmsg ()
-putpmsg ()
-pwrite ()
-read ()
-readv ()
-select ()
-sem_wait ()
-sigpause ()
-sigsuspend ()
-sigtimedwait ()
-sigwait ()
-sigwaitinfo ()
-*sleep ()
-system ()
-tcdrain ()
-*usleep ()
-wait ()
-wait3()
-waitid ()
-waitpid ()
-write ()
-writev ()
-the optional list is:
-catclose ()
-catgets ()
-catopen ()
-closedir ()
-closelog ()
-ctermid ()
-dbm_close ()
-dbm_delete ()
-dbm_fetch ()
-dbm_nextkey ()
-dbm_open ()
-dbm_store ()
-dlclose ()
-dlopen ()
-endgrent ()
-endpwent ()
-endutxent ()
-fclose ()
-fcntl ()
-fflush ()
-fgetc ()
-fgetpos ()
-fgets ()
-fgetwc ()
-fgetws ()
-fopen ()
-fprintf ()
-fputc ()
-fputs ()
-fputwc ()
-fputws ()
-fread ()
-freopen ()
-fscanf ()
-fseek ()
-fseeko ()
-fsetpos ()
-ftell ()
-ftello ()
-ftw ()
-fwprintf ()
-fwrite ()
-fwscanf ()
-getc ()
-getc_unlocked ()
-getchar ()
-getchar_unlocked ()
-getcwd ()
-getdate ()
-getgrent ()
-getgrgid ()
-getgrgid_r ()
-getgrnam ()
-getgrnam_r ()
-getlogin ()
-getlogin_r ()
-getpwent ()
-*getpwnam ()
-*getpwnam_r ()
-*getpwuid ()
-*getpwuid_r ()
-gets ()
-getutxent ()
-getutxid ()
-getutxline ()
-getw ()
-getwc ()
-getwchar ()
-getwd ()
-glob ()
-iconv_close ()
-iconv_open ()
-ioctl ()
-lseek ()
-mkstemp ()
-nftw ()
-opendir ()
-openlog ()
-pclose ()
-perror ()
-popen ()
-printf ()
-putc ()
-putc_unlocked ()
-putchar ()
-putchar_unlocked ()
-puts ()
-pututxline ()
-putw ()
-putwc ()
-putwchar ()
-readdir ()
-readdir_r ()
-remove ()
-rename ()
-rewind ()
-rewinddir ()
-scanf ()
-seekdir ()
-semop ()
-setgrent ()
-setpwent ()
-setutxent ()
-strerror ()
-syslog ()
-tmpfile ()
-tmpnam ()
-ttyname ()
-ttyname_r ()
-ungetc ()
-ungetwc ()
-unlink ()
-vfprintf ()
-vfwprintf ()
-vprintf ()
-vwprintf ()
-wprintf ()
-wscanf ()
-
-Note, that for fcntl (), for any value of the cmd argument.
-
-And we must not introduce cancellation points anywhere else that's part of the posix or
-opengroup specs.
- */
-}
-
-/*no races in these three functions: they are all current-thread-only */
-int
-__pthread_setcancelstate (int state, int *oldstate)
-{
- class pthread *thread = __pthread_self ();
- if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)
- return EINVAL;
- *oldstate = thread->cancelstate;
- thread->cancelstate = state;
- return 0;
-}
-
-int
-__pthread_setcanceltype (int type, int *oldtype)
-{
- class pthread *thread = __pthread_self ();
- if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)
- return EINVAL;
- *oldtype = thread->canceltype;
- thread->canceltype = type;
- return 0;
-}
-
-/*deferred cancellation request handler */
-void
-__pthread_testcancel (void)
-{
- class pthread *thread = __pthread_self ();
- if (thread->cancelstate == PTHREAD_CANCEL_DISABLE)
- return;
- /*check the cancellation event object here - not neededuntil pthread_cancel actually
- *does something*/
+ return thread->cancel ();
}
/*
@@ -1221,8 +1469,10 @@ __pthread_testcancel (void)
*If yes, we're safe, if no, we're not.
*/
void
-__pthread_atforkprepare (void)
+pthread::atforkprepare (void)
{
+ MT_INTERFACE->fixup_before_fork ();
+
callback *cb = MT_INTERFACE->pthread_prepare;
while (cb)
{
@@ -1232,7 +1482,7 @@ __pthread_atforkprepare (void)
}
void
-__pthread_atforkparent (void)
+pthread::atforkparent (void)
{
callback *cb = MT_INTERFACE->pthread_parent;
while (cb)
@@ -1243,8 +1493,10 @@ __pthread_atforkparent (void)
}
void
-__pthread_atforkchild (void)
+pthread::atforkchild (void)
{
+ MT_INTERFACE->fixup_after_fork ();
+
callback *cb = MT_INTERFACE->pthread_child;
while (cb)
{
@@ -1258,7 +1510,7 @@ __pthread_atforkchild (void)
*parent and child calls are called in FI-FC order.
*/
int
-__pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void))
+pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void))
{
callback *prepcb = NULL, *parentcb = NULL, *childcb = NULL;
if (prepare)
@@ -1293,7 +1545,7 @@ __pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(voi
if (prepcb)
{
prepcb->cb = prepare;
- prepcb->next=(callback *)InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb);
+ prepcb->next = (callback *) InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb);
}
if (parentcb)
{
@@ -1302,7 +1554,7 @@ __pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(voi
while (*t)
t = &(*t)->next;
/*t = pointer to last next in the list */
- parentcb->next=(callback *)InterlockedExchangePointer ((LONG *) t, (long int) parentcb);
+ parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb);
}
if (childcb)
{
@@ -1311,7 +1563,7 @@ __pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(voi
while (*t)
t = &(*t)->next;
/*t = pointer to last next in the list */
- childcb->next=(callback *)InterlockedExchangePointer ((LONG *) t, (long int) childcb);
+ childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb);
}
return 0;
}
@@ -1322,7 +1574,7 @@ __pthread_attr_init (pthread_attr_t *attr)
if (check_valid_pointer (attr))
return EINVAL;
*attr = new pthread_attr;
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
{
delete (*attr);
*attr = NULL;
@@ -1335,7 +1587,7 @@ int
__pthread_attr_getinheritsched (const pthread_attr_t *attr,
int *inheritsched)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
*inheritsched = (*attr)->inheritsched;
return 0;
@@ -1345,7 +1597,7 @@ int
__pthread_attr_getschedparam (const pthread_attr_t *attr,
struct sched_param *param)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
*param = (*attr)->schedparam;
return 0;
@@ -1358,7 +1610,7 @@ __pthread_attr_getschedparam (const pthread_attr_t *attr,
int
__pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
*policy = SCHED_FIFO;
return 0;
@@ -1368,7 +1620,7 @@ __pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy)
int
__pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
*contentionscope = (*attr)->contentionscope;
return 0;
@@ -1377,7 +1629,7 @@ __pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope)
int
__pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
if (detachstate < 0 || detachstate > 1)
return EINVAL;
@@ -1388,7 +1640,7 @@ __pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
int
__pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
*detachstate = (*attr)->joinable;
return 0;
@@ -1397,7 +1649,7 @@ __pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate)
int
__pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
if (inheritsched != PTHREAD_INHERIT_SCHED
&& inheritsched != PTHREAD_EXPLICIT_SCHED)
@@ -1410,7 +1662,7 @@ int
__pthread_attr_setschedparam (pthread_attr_t *attr,
const struct sched_param *param)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
if (!valid_sched_parameters (param))
return ENOTSUP;
@@ -1422,7 +1674,7 @@ __pthread_attr_setschedparam (pthread_attr_t *attr,
int
__pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
if (policy != SCHED_FIFO)
return ENOTSUP;
@@ -1432,7 +1684,7 @@ __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
int
__pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
if (contentionscope != PTHREAD_SCOPE_SYSTEM
&& contentionscope != PTHREAD_SCOPE_PROCESS)
@@ -1448,7 +1700,7 @@ __pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
int
__pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
(*attr)->stacksize = size;
return 0;
@@ -1457,7 +1709,7 @@ __pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
int
__pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
*size = (*attr)->stacksize;
return 0;
@@ -1466,46 +1718,46 @@ __pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
int
__pthread_attr_destroy (pthread_attr_t *attr)
{
- if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_attr::isGoodObject (attr))
return EINVAL;
delete (*attr);
*attr = NULL;
return 0;
}
-void
-__pthread_exit (void *value_ptr)
+int
+pthread::join (pthread_t *thread, void **return_val)
{
- class pthread *thread = __pthread_self ();
+ pthread_t joiner = self ();
- MT_INTERFACE->destructors.IterateNull ();
+ // Initialize return val with NULL
+ if (return_val)
+ *return_val = NULL;
- thread->return_ptr = value_ptr;
- if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0)
- exit (0);
- else
- ExitThread (0);
-}
-
-int
-__pthread_join (pthread_t *thread, void **return_val)
-{
/*FIXME: wait on the thread cancellation event as well - we are a cancellation point*/
- if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (thread))
return ESRCH;
+ if (__pthread_equal (thread,&joiner))
+ return EDEADLK;
+
+ (*thread)->mutex.Lock ();
+
if ((*thread)->attr.joinable == PTHREAD_CREATE_DETACHED)
{
- if (return_val)
- *return_val = NULL;
+ (*thread)->mutex.UnLock ();
return EINVAL;
}
else
{
+ (*thread)->joiner = joiner;
(*thread)->attr.joinable = PTHREAD_CREATE_DETACHED;
+ (*thread)->mutex.UnLock ();
WaitForSingleObject ((*thread)->win32_obj_id, INFINITE);
if (return_val)
- *return_val = (*thread)->return_ptr;
+ *return_val = (*thread)->return_ptr;
+ // cleanup
+ delete (*thread);
} /*End if */
pthread_testcancel ();
@@ -1514,25 +1766,40 @@ __pthread_join (pthread_t *thread, void **return_val)
}
int
-__pthread_detach (pthread_t *thread)
+pthread::detach (pthread_t *thread)
{
- if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (thread))
return ESRCH;
+ (*thread)->mutex.Lock ();
if ((*thread)->attr.joinable == PTHREAD_CREATE_DETACHED)
{
- (*thread)->return_ptr = NULL;
+ (*thread)->mutex.UnLock ();
return EINVAL;
}
- (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED;
+ // check if thread is still alive
+ if (WAIT_TIMEOUT == WaitForSingleObject ((*thread)->win32_obj_id, 0) )
+ {
+ // force cleanup on exit
+ (*thread)->joiner = *thread;
+ (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED;
+ (*thread)->mutex.UnLock ();
+ }
+ else
+ {
+ // thread has already terminated.
+ (*thread)->mutex.UnLock ();
+ delete (*thread);
+ }
+
return 0;
}
int
-__pthread_suspend (pthread_t *thread)
+pthread::suspend (pthread_t *thread)
{
- if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (thread))
return ESRCH;
if ((*thread)->suspended == false)
@@ -1546,9 +1813,9 @@ __pthread_suspend (pthread_t *thread)
int
-__pthread_continue (pthread_t *thread)
+pthread::resume (pthread_t *thread)
{
- if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (thread))
return ESRCH;
if ((*thread)->suspended == true)
@@ -1572,7 +1839,7 @@ int
__pthread_getschedparam (pthread_t thread, int *policy,
struct sched_param *param)
{
- if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!pthread::isGoodObject (&thread))
return ESRCH;
*policy = SCHED_FIFO;
/*we don't return the current effective priority, we return the current requested
@@ -1581,15 +1848,6 @@ __pthread_getschedparam (pthread_t thread, int *policy,
return 0;
}
-
-unsigned long
-__pthread_getsequence_np (pthread_t *thread)
-{
- if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
- return EINVAL;
- return (*thread)->GetThreadId ();
-}
-
/*Thread SpecificData */
int
__pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
@@ -1597,12 +1855,12 @@ __pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
/*The opengroup docs don't define if we should check this or not,
*but creation is relatively rare..
*/
- if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) == VALID_OBJECT)
+ if (pthread_key::isGoodObject (key))
return EBUSY;
*key = new pthread_key (destructor);
- if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
+ if (!pthread_key::isGoodObject (key))
{
delete (*key);
*key = NULL;
@@ -1614,7 +1872,7 @@ __pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
int
__pthread_key_delete (pthread_key_t key)
{
- if (verifyable_object_isvalid (&key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
+ if (!pthread_key::isGoodObject (&key))
return EINVAL;
delete (key);
@@ -1638,7 +1896,7 @@ int
__pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param)
{
- if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!pthread::isGoodObject (&thread))
return ESRCH;
if (policy != SCHED_FIFO)
return ENOTSUP;
@@ -1655,7 +1913,7 @@ __pthread_setschedparam (pthread_t thread, int policy,
int
__pthread_setspecific (pthread_key_t key, const void *value)
{
- if (verifyable_object_isvalid (&key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
+ if (!pthread_key::isGoodObject (&key))
return EINVAL;
(key)->set (value);
return 0;
@@ -1664,7 +1922,7 @@ __pthread_setspecific (pthread_key_t key, const void *value)
void *
__pthread_getspecific (pthread_key_t key)
{
- if (verifyable_object_isvalid (&key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
+ if (!pthread_key::isGoodObject (&key))
return NULL;
return (key)->get ();
@@ -1672,11 +1930,36 @@ __pthread_getspecific (pthread_key_t key)
}
/*Thread synchronisation */
+bool
+pthread_cond::isGoodObject (pthread_cond_t const *cond)
+{
+ if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_cond::isGoodInitializer (pthread_cond_t const *cond)
+{
+ if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_cond::isGoodInitializerOrObject (pthread_cond_t const *cond)
+{
+ if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT)
+ return false;
+ return true;
+}
int
__pthread_cond_destroy (pthread_cond_t *cond)
{
- if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+ if (pthread_cond::isGoodInitializer (cond))
+ return 0;
+ if (!pthread_cond::isGoodObject (cond))
return EINVAL;
/*reads are atomic */
@@ -1692,15 +1975,15 @@ __pthread_cond_destroy (pthread_cond_t *cond)
int
__pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr)
{
- if (attr && verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+ if (attr && !pthread_condattr::isGoodObject (attr))
return EINVAL;
- if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != INVALID_OBJECT)
+ if (pthread_cond::isGoodObject (cond))
return EBUSY;
*cond = new pthread_cond (attr ? (*attr) : NULL);
- if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+ if (!pthread_cond::isGoodObject (cond))
{
delete (*cond);
*cond = NULL;
@@ -1713,7 +1996,9 @@ __pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr)
int
__pthread_cond_broadcast (pthread_cond_t *cond)
{
- if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+ if (pthread_cond::isGoodInitializer (cond))
+ __pthread_cond_init (cond, NULL);
+ if (!pthread_cond::isGoodObject (cond))
return EINVAL;
(*cond)->BroadCast ();
@@ -1724,7 +2009,9 @@ __pthread_cond_broadcast (pthread_cond_t *cond)
int
__pthread_cond_signal (pthread_cond_t *cond)
{
- if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+ if (pthread_cond::isGoodInitializer (cond))
+ __pthread_cond_init (cond, NULL);
+ if (!pthread_cond::isGoodObject (cond))
return EINVAL;
(*cond)->Signal ();
@@ -1743,21 +2030,23 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
if (*mutex == PTHREAD_MUTEX_INITIALIZER)
__pthread_mutex_init (mutex, NULL);
themutex = mutex;
+ if (pthread_cond::isGoodInitializer (cond))
+ __pthread_cond_init (cond, NULL);
- if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (themutex))
return EINVAL;
- if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+ if (!pthread_cond::isGoodObject (cond))
return EINVAL;
/*if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/
if (pthread_mutex_lock (&(*cond)->cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond);
+ system_printf ("Failed to lock condition variable access mutex, this %p", *cond);
if ((*cond)->waiting)
if ((*cond)->mutex && ((*cond)->mutex != (*themutex)))
{
if (pthread_mutex_unlock (&(*cond)->cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
return EINVAL;
}
InterlockedIncrement (&((*cond)->waiting));
@@ -1765,22 +2054,26 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
(*cond)->mutex = (*themutex);
InterlockedIncrement (&((*themutex)->condwaits));
if (pthread_mutex_unlock (&(*cond)->cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
+ /* At this point calls to Signal will progress evebn if we aren' yet waiting
+ * However, the loop there should allow us to get scheduled and call wait,
+ * and have them call PulseEvent again if we dont' respond.
+ */
rv = (*cond)->TimedWait (waitlength);
- /* this may allow a race on the mutex acquisition and waits..
+ /* this may allow a race on the mutex acquisition and waits..
* But doing this within the cond access mutex creates a different race
*/
- bool last = false;
- if (InterlockedDecrement (&((*cond)->waiting)) == 0)
- last = true;
+ InterlockedDecrement (&((*cond)->waiting));
+ /* Tell Signal that we have been released */
+ InterlockedDecrement (&((*cond)->ExitingWait));
(*themutex)->Lock ();
- if (last == true)
- (*cond)->mutex = NULL;
if (pthread_mutex_lock (&(*cond)->cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond);
+ system_printf ("Failed to lock condition variable access mutex, this %p", *cond);
+ if ((*cond)->waiting == 0)
+ (*cond)->mutex = NULL;
InterlockedDecrement (&((*themutex)->condwaits));
if (pthread_mutex_unlock (&(*cond)->cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond);
+ system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
return rv;
}
@@ -1789,11 +2082,11 @@ extern "C" int
pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime)
{
- if (check_valid_pointer(abstime))
+ if (check_valid_pointer (abstime))
return EINVAL;
struct timeb currSysTime;
long waitlength;
- ftime(&currSysTime);
+ ftime (&currSysTime);
waitlength = (abstime->tv_sec - currSysTime.time) *1000;
if (waitlength < 0)
return ETIMEDOUT;
@@ -1809,8 +2102,9 @@ pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
int
__pthread_condattr_init (pthread_condattr_t *condattr)
{
+ /* FIXME: we dereference blindly! */
*condattr = new pthread_condattr;
- if (verifyable_object_isvalid (condattr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_condattr::isGoodObject (condattr))
{
delete (*condattr);
*condattr = NULL;
@@ -1822,7 +2116,7 @@ __pthread_condattr_init (pthread_condattr_t *condattr)
int
__pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
{
- if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_condattr::isGoodObject (attr))
return EINVAL;
*pshared = (*attr)->shared;
return 0;
@@ -1831,7 +2125,7 @@ __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
int
__pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
{
- if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_condattr::isGoodObject (attr))
return EINVAL;
if ((pshared < 0) || (pshared > 1))
return EINVAL;
@@ -1845,7 +2139,7 @@ __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
int
__pthread_condattr_destroy (pthread_condattr_t *condattr)
{
- if (verifyable_object_isvalid (condattr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_condattr::isGoodObject (condattr))
return EINVAL;
delete (*condattr);
*condattr = NULL;
@@ -1859,7 +2153,7 @@ __pthread_kill (pthread_t thread, int sig)
// lock myself, for the use of thread2signal
// two different kills might clash: FIXME
- if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT)
+ if (!pthread::isGoodObject (&thread))
return EINVAL;
if (thread->sigs)
@@ -1874,7 +2168,7 @@ __pthread_kill (pthread_t thread, int sig)
int
__pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
{
- pthread *thread = __pthread_self ();
+ pthread *thread = pthread::self ();
// lock this myself, for the use of thread2signal
// two differt kills might clash: FIXME
@@ -1890,11 +2184,6 @@ __pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
}
/* ID */
-pthread_t
-__pthread_self ()
-{
- return (pthread *) TlsGetValue (MT_INTERFACE->thread_self_dwTlsIndex);
-}
int
__pthread_equal (pthread_t *t1, pthread_t *t2)
@@ -1917,14 +2206,15 @@ int
__pthread_mutex_init (pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr)
{
- if (attr && verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT || check_valid_pointer (mutex))
+ if (attr && !pthread_mutexattr::isGoodObject (attr) || check_valid_pointer (mutex))
return EINVAL;
- if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != INVALID_OBJECT)
+ /* FIXME: bugfix: we should check *mutex being a valid address */
+ if (pthread_mutex::isGoodObject (mutex))
return EBUSY;
*mutex = new pthread_mutex (attr ? (*attr) : NULL);
- if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (mutex))
{
delete (*mutex);
*mutex = NULL;
@@ -1937,10 +2227,10 @@ int
__pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
int *prioceiling)
{
- pthread_mutex_t *themutex=(pthread_mutex_t *) mutex;
- if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ pthread_mutex_t *themutex = (pthread_mutex_t *) mutex;
+ if (pthread_mutex::isGoodInitializer (mutex))
__pthread_mutex_init ((pthread_mutex_t *) mutex, NULL);
- if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (themutex))
return EINVAL;
/*We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support
*mutex priorities.
@@ -1957,18 +2247,22 @@ int
__pthread_mutex_lock (pthread_mutex_t *mutex)
{
pthread_mutex_t *themutex = mutex;
+ /* This could be simplified via isGoodInitializerOrObject
+ and isGoodInitializer, but in a performance critical call like this....
+ no.
+ */
switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER))
{
case INVALID_OBJECT:
return EINVAL;
break;
case VALID_STATIC_OBJECT:
- if (*mutex == PTHREAD_MUTEX_INITIALIZER)
- {
- int rv = __pthread_mutex_init (mutex, NULL);
- if (rv)
+ if (pthread_mutex::isGoodInitializer (mutex))
+ {
+ int rv = __pthread_mutex_init (mutex, NULL);
+ if (rv)
return rv;
- }
+ }
break;
case VALID_OBJECT:
break;
@@ -1981,9 +2275,9 @@ int
__pthread_mutex_trylock (pthread_mutex_t *mutex)
{
pthread_mutex_t *themutex = mutex;
- if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ if (pthread_mutex::isGoodInitializer (mutex))
__pthread_mutex_init (mutex, NULL);
- if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (themutex))
return EINVAL;
if ((*themutex)->TryLock ())
return EBUSY;
@@ -1993,9 +2287,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
int
__pthread_mutex_unlock (pthread_mutex_t *mutex)
{
- if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ if (pthread_mutex::isGoodInitializer (mutex))
__pthread_mutex_init (mutex, NULL);
- if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (mutex))
return EINVAL;
(*mutex)->UnLock ();
return 0;
@@ -2004,9 +2298,9 @@ __pthread_mutex_unlock (pthread_mutex_t *mutex)
int
__pthread_mutex_destroy (pthread_mutex_t *mutex)
{
- if (check_valid_pointer (mutex) && (*mutex == PTHREAD_MUTEX_INITIALIZER))
+ if (pthread_mutex::isGoodInitializer (mutex))
return 0;
- if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (mutex))
return EINVAL;
/*reading a word is atomic */
@@ -2023,9 +2317,9 @@ __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
int *old_ceiling)
{
pthread_mutex_t *themutex = mutex;
- if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ if (pthread_mutex::isGoodInitializer (mutex))
__pthread_mutex_init (mutex, NULL);
- if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutex::isGoodObject (themutex))
return EINVAL;
return ENOSYS;
}
@@ -2036,7 +2330,7 @@ int
__pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr,
int *protocol)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
return ENOSYS;
}
@@ -2045,7 +2339,7 @@ int
__pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
int *pshared)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
*pshared = (*attr)->pshared;
return 0;
@@ -2058,7 +2352,7 @@ __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
int
__pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
*type = (*attr)->mutextype;
return 0;
@@ -2072,11 +2366,11 @@ __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
int
__pthread_mutexattr_init (pthread_mutexattr_t *attr)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != INVALID_OBJECT)
+ if (pthread_mutexattr::isGoodObject (attr))
return EBUSY;
*attr = new pthread_mutexattr ();
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
{
delete (*attr);
*attr = NULL;
@@ -2088,7 +2382,7 @@ __pthread_mutexattr_init (pthread_mutexattr_t *attr)
int
__pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
delete (*attr);
*attr = NULL;
@@ -2100,7 +2394,7 @@ __pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
int
__pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
return ENOSYS;
}
@@ -2110,7 +2404,7 @@ int
__pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
int prioceiling)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
return ENOSYS;
}
@@ -2119,7 +2413,7 @@ int
__pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr,
int *prioceiling)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
return ENOSYS;
}
@@ -2127,7 +2421,7 @@ __pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr,
int
__pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
/*we don't use pshared for anything as yet. We need to test PROCESS_SHARED
*functionality
@@ -2142,7 +2436,7 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
int
__pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
{
- if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+ if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
if (type != PTHREAD_MUTEX_RECURSIVE)
return EINVAL;
@@ -2151,11 +2445,21 @@ __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
}
/*Semaphores */
+
+/* static members */
+bool
+semaphore::isGoodObject (sem_t const * sem)
+{
+ if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
int
-__sem_init (sem_t *sem, int pshared, unsigned int value)
+semaphore::init (sem_t *sem, int pshared, unsigned int value)
{
/*opengroup calls this undefined */
- if (verifyable_object_isvalid (sem, SEM_MAGIC) != INVALID_OBJECT)
+ if (isGoodObject (sem))
return EBUSY;
if (value > SEM_VALUE_MAX)
@@ -2163,7 +2467,7 @@ __sem_init (sem_t *sem, int pshared, unsigned int value)
*sem = new semaphore (pshared, value);
- if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (sem))
{
delete (*sem);
*sem = NULL;
@@ -2173,9 +2477,9 @@ __sem_init (sem_t *sem, int pshared, unsigned int value)
}
int
-__sem_destroy (sem_t *sem)
+semaphore::destroy (sem_t *sem)
{
- if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (sem))
return EINVAL;
/*FIXME - new feature - test for busy against threads... */
@@ -2186,32 +2490,107 @@ __sem_destroy (sem_t *sem)
}
int
-__sem_wait (sem_t *sem)
+semaphore::wait (sem_t *sem)
{
- if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
- return EINVAL;
+ if (!isGoodObject (sem))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
(*sem)->Wait ();
return 0;
}
int
-__sem_trywait (sem_t *sem)
+semaphore::trywait (sem_t *sem)
{
- if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
- return EINVAL;
+ if (!isGoodObject (sem))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
return (*sem)->TryWait ();
}
int
-__sem_post (sem_t *sem)
+semaphore::post (sem_t *sem)
{
- if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
+ if (!isGoodObject (sem))
return EINVAL;
(*sem)->Post ();
return 0;
}
+/* pthreadNull */
+pthread *
+pthreadNull::getNullpthread ()
+{
+ /* because of weird entry points */
+ _instance.magic = 0;
+ return &_instance;
+}
+
+pthreadNull::pthreadNull ()
+{
+ /* Mark ourselves as invalid */
+ magic = 0;
+}
+
+pthreadNull::~pthreadNull ()
+{
+}
+
+void
+pthreadNull::create (void *(*)(void *), pthread_attr *, void *)
+{
+}
+
+void
+pthreadNull::exit (void *value_ptr)
+{
+}
+
+int
+pthreadNull::cancel ()
+{
+ return 0;
+}
+
+void
+pthreadNull::testcancel ()
+{
+}
+
+int
+pthreadNull::setcancelstate (int state, int *oldstate)
+{
+ return EINVAL;
+}
+
+int
+pthreadNull::setcanceltype (int type, int *oldtype)
+{
+ return EINVAL;
+}
+
+void
+pthreadNull::push_cleanup_handler (__pthread_cleanup_handler *handler)
+{
+}
+
+void
+pthreadNull::pop_cleanup_handler (int const execute)
+{
+}
+unsigned long
+pthreadNull::getsequence_np ()
+{
+ return 0;
+}
+
+pthreadNull pthreadNull::_instance = pthreadNull ();
+
#endif // MT_SAFE
diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h
index c724bea14..c36466020 100644
--- a/winsup/cygwin/thread.h
+++ b/winsup/cygwin/thread.h
@@ -1,7 +1,6 @@
/* thread.h: Locking and threading module definitions
- Copyright 1998, 1999, 2000, 2001 Red Hat, Inc.
- Copyright 2001 Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Marco Fuykschot <marco@ddi.nl>
Major update 2001 Robert Collins <rbtcollins@hotmail.com>
@@ -54,7 +53,7 @@ struct _winsup_t
/*
Needed for the group functions
*/
- struct group _grp;
+ struct __group16 _grp;
char *_namearray[2];
int _grp_pos;
@@ -164,7 +163,7 @@ public:
~verifyable_object ();
};
-typedef enum
+typedef enum
{
VALID_OBJECT,
INVALID_OBJECT,
@@ -174,51 +173,98 @@ typedef enum
verifyable_object_state verifyable_object_isvalid (void const *, long);
verifyable_object_state verifyable_object_isvalid (void const *, long, void *);
+/* interface */
+template <class ListNode> class List {
+public:
+ List();
+ void Insert (ListNode *aNode);
+ ListNode *Remove ( ListNode *aNode);
+ ListNode *Pop ();
+ void forEach (void (*)(ListNode *aNode));
+protected:
+ ListNode *head;
+};
+
class pthread_key:public verifyable_object
{
public:
+ static bool isGoodObject (pthread_key_t const *);
+ static void runAllDestructors ();
DWORD dwTlsIndex;
+
int set (const void *);
- void *get ();
+ void *get () const;
- pthread_key (void (*)(void *));
+ pthread_key (void (*)(void *));
~pthread_key ();
-};
+ static void fixup_before_fork();
+ static void fixup_after_fork();
-/* FIXME: test using multiple inheritance and merging key_destructor into pthread_key
- * for efficiency */
-class pthread_key_destructor
-{
-public:
+ /* List support calls */
+ class pthread_key *next;
+private:
+ // lists of objects. USE THREADSAFE INSERTS AND DELETES.
+ static List<pthread_key> keys;
+ static void saveAKey (pthread_key *);
+ static void restoreAKey (pthread_key *);
+ static void destroyAKey (pthread_key *);
+ void saveKeyToBuffer ();
+ void recreateKeyFromBuffer ();
void (*destructor) (void *);
- pthread_key_destructor *InsertAfter (pthread_key_destructor * node);
- pthread_key_destructor *UnlinkNext ();
- pthread_key_destructor *Next ();
-
- pthread_key_destructor (void (*thedestructor) (void *), pthread_key * key);
- pthread_key_destructor *next;
- pthread_key *key;
+ void run_destructor () const;
+ void *fork_buf;
};
-class pthread_key_destructor_list
+/* implementation */
+template <class ListNode>
+List<ListNode>::List<ListNode> () : head(NULL)
{
-public:
- void Insert (pthread_key_destructor * node);
-/* remove a given dataitem, wherever in the list it is */
- pthread_key_destructor *Remove (pthread_key_destructor * item);
-/* get the first item and remove at the same time */
- pthread_key_destructor *Pop ();
- pthread_key_destructor *Remove (pthread_key * key);
- void IterateNull ();
-private:
- pthread_key_destructor * head;
-};
-
+}
+template <class ListNode> void
+List<ListNode>::Insert (ListNode *aNode)
+{
+ if (!aNode)
+ return;
+ aNode->next = (ListNode *) InterlockedExchangePointer (&head, aNode);
+}
+template <class ListNode> ListNode *
+List<ListNode>::Remove ( ListNode *aNode)
+{
+ if (!aNode)
+ return NULL;
+ if (!head)
+ return NULL;
+ if (aNode == head)
+ return Pop ();
+ ListNode *resultPrev = head;
+ while (resultPrev && resultPrev->next && !(aNode == resultPrev->next))
+ resultPrev = resultPrev->next;
+ if (resultPrev)
+ return (ListNode *)InterlockedExchangePointer (&resultPrev->next, resultPrev->next->next);
+ return NULL;
+}
+template <class ListNode> ListNode *
+List<ListNode>::Pop ()
+{
+ return (ListNode *) InterlockedExchangePointer (&head, head->next);
+}
+/* poor mans generic programming. */
+template <class ListNode> void
+List<ListNode>::forEach (void (*callback)(ListNode *))
+{
+ ListNode *aNode = head;
+ while (aNode)
+ {
+ callback (aNode);
+ aNode = aNode->next;
+ }
+}
class pthread_attr:public verifyable_object
{
public:
+ static bool isGoodObject(pthread_attr_t const *);
int joinable;
int contentionscope;
int inheritsched;
@@ -229,43 +275,10 @@ public:
~pthread_attr ();
};
-class pthread:public verifyable_object
-{
-public:
- HANDLE win32_obj_id;
- class pthread_attr attr;
- void *(*function) (void *);
- void *arg;
- void *return_ptr;
- bool suspended;
- int cancelstate, canceltype;
- // int joinable;
-
- DWORD GetThreadId ()
- {
- return thread_id;
- }
- void setThreadIdtoCurrent ()
- {
- thread_id = GetCurrentThreadId ();
- }
-
- /* signal handling */
- struct sigaction *sigs;
- sigset_t *sigmask;
- LONG *sigtodo;
- void create (void *(*)(void *), pthread_attr *, void *);
-
- pthread ();
- ~pthread ();
-
-private:
- DWORD thread_id;
-};
-
class pthread_mutexattr:public verifyable_object
{
public:
+ static bool isGoodObject(pthread_mutexattr_t const *);
int pshared;
int mutextype;
pthread_mutexattr ();
@@ -275,6 +288,9 @@ public:
class pthread_mutex:public verifyable_object
{
public:
+ static bool isGoodObject(pthread_mutex_t const *);
+ static bool isGoodInitializer(pthread_mutex_t const *);
+ static bool isGoodInitializerOrObject(pthread_mutex_t const *);
CRITICAL_SECTION criticalsection;
HANDLE win32_obj_id;
LONG condwaits;
@@ -286,15 +302,111 @@ public:
int UnLock ();
void fixup_after_fork ();
- pthread_mutex (unsigned short);
- pthread_mutex (pthread_mutexattr *);
+ pthread_mutex (pthread_mutexattr * = NULL);
pthread_mutex (pthread_mutex_t *, pthread_mutexattr *);
~pthread_mutex ();
};
+class pthread:public verifyable_object
+{
+public:
+ HANDLE win32_obj_id;
+ class pthread_attr attr;
+ void *(*function) (void *);
+ void *arg;
+ void *return_ptr;
+ bool suspended;
+ int cancelstate, canceltype;
+ HANDLE cancel_event;
+ pthread_t joiner;
+ // int joinable;
+
+ /* signal handling */
+ struct sigaction *sigs;
+ sigset_t *sigmask;
+ LONG *sigtodo;
+ virtual void create (void *(*)(void *), pthread_attr *, void *);
+
+ pthread ();
+ virtual ~pthread ();
+
+ static void initMainThread(pthread *, HANDLE);
+ static bool isGoodObject(pthread_t const *);
+ static void atforkprepare();
+ static void atforkparent();
+ static void atforkchild();
+
+ /* API calls */
+ static int cancel (pthread_t);
+ static int join (pthread_t * thread, void **return_val);
+ static int detach (pthread_t * thread);
+ static int create (pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg);
+ static int once (pthread_once_t *, void (*)(void));
+ static int atfork(void (*)(void), void (*)(void), void (*)(void));
+ static int suspend (pthread_t * thread);
+ static int resume (pthread_t * thread);
+
+ virtual void exit (void *value_ptr);
+
+ virtual int cancel ();
+
+ virtual void testcancel ();
+ static void static_cancel_self ();
+
+ virtual int setcancelstate (int state, int *oldstate);
+ virtual int setcanceltype (int type, int *oldtype);
+
+ virtual void push_cleanup_handler (__pthread_cleanup_handler *handler);
+ virtual void pop_cleanup_handler (int const execute);
+
+ static pthread* self ();
+ static void *thread_init_wrapper (void *);
+
+ virtual unsigned long getsequence_np();
+
+private:
+ DWORD thread_id;
+ __pthread_cleanup_handler *cleanup_stack;
+ pthread_mutex mutex;
+
+ void pop_all_cleanup_handlers (void);
+ void precreate (pthread_attr *);
+ void postcreate ();
+ void setThreadIdtoCurrent();
+ static void setTlsSelfPointer(pthread *);
+ void cancel_self ();
+ DWORD getThreadId ();
+};
+
+class pthreadNull : public pthread
+{
+ public:
+ static pthread *getNullpthread();
+ ~pthreadNull();
+
+ /* From pthread These should never get called
+ * as the ojbect is not verifyable
+ */
+ void create (void *(*)(void *), pthread_attr *, void *);
+ void exit (void *value_ptr);
+ int cancel ();
+ void testcancel ();
+ int setcancelstate (int state, int *oldstate);
+ int setcanceltype (int type, int *oldtype);
+ void push_cleanup_handler (__pthread_cleanup_handler *handler);
+ void pop_cleanup_handler (int const execute);
+ unsigned long getsequence_np();
+
+ private:
+ pthreadNull ();
+ static pthreadNull _instance;
+};
+
class pthread_condattr:public verifyable_object
{
public:
+ static bool isGoodObject(pthread_condattr_t const *);
int shared;
pthread_condattr ();
@@ -304,8 +416,12 @@ public:
class pthread_cond:public verifyable_object
{
public:
+ static bool isGoodObject(pthread_cond_t const *);
+ static bool isGoodInitializer(pthread_cond_t const *);
+ static bool isGoodInitializerOrObject(pthread_cond_t const *);
int shared;
LONG waiting;
+ LONG ExitingWait;
pthread_mutex *mutex;
/* to allow atomic behaviour for cond_broadcast */
pthread_mutex_t cond_access;
@@ -331,6 +447,14 @@ public:
class semaphore:public verifyable_object
{
public:
+ static bool isGoodObject(sem_t const *);
+ /* API calls */
+ static int init (sem_t * sem, int pshared, unsigned int value);
+ static int destroy (sem_t * sem);
+ static int wait (sem_t * sem);
+ static int trywait (sem_t * sem);
+ static int post (sem_t * sem);
+
HANDLE win32_obj_id;
class semaphore * next;
int shared;
@@ -367,41 +491,29 @@ public:
struct _winsup_t winsup_reent;
pthread mainthread;
- pthread_key_destructor_list destructors;
callback *pthread_prepare;
callback *pthread_child;
callback *pthread_parent;
- // list of mutex's. USE THREADSAFE INSERTS AND DELETES.
+ // lists of pthread objects. USE THREADSAFE INSERTS AND DELETES.
class pthread_mutex * mutexs;
class pthread_cond * conds;
class semaphore * semaphores;
void Init (int);
+ void fixup_before_fork (void);
void fixup_after_fork (void);
- MTinterface ():reent_index (0), indexallocated (0), threadcount (1)
- {
- pthread_prepare = NULL;
- pthread_child = NULL;
- pthread_parent = NULL;
- }
+ MTinterface ():reent_index (0), indexallocated (0), threadcount (1)
+ {
+ pthread_prepare = NULL;
+ pthread_child = NULL;
+ pthread_parent = NULL;
+ }
};
-void __pthread_atforkprepare(void);
-void __pthread_atforkparent(void);
-void __pthread_atforkchild(void);
-
extern "C"
{
-void *thread_init_wrapper (void *);
-
-/* ThreadCreation */
-int __pthread_create (pthread_t * thread, const pthread_attr_t * attr,
- void *(*start_routine) (void *), void *arg);
-int __pthread_once (pthread_once_t *, void (*)(void));
-int __pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
-
int __pthread_attr_init (pthread_attr_t * attr);
int __pthread_attr_destroy (pthread_attr_t * attr);
int __pthread_attr_setdetachstate (pthread_attr_t *, int);
@@ -422,20 +534,6 @@ int __pthread_attr_setschedpolicy (pthread_attr_t *, int);
int __pthread_attr_setscope (pthread_attr_t *, int);
int __pthread_attr_setstackaddr (pthread_attr_t *, void *);
-
-
-/* Thread Exit */
-void __pthread_exit (void *value_ptr);
-int __pthread_join (pthread_t * thread, void **return_val);
-int __pthread_detach (pthread_t * thread);
-
-/* Thread suspend */
-
-int __pthread_suspend (pthread_t * thread);
-int __pthread_continue (pthread_t * thread);
-
-unsigned long __pthread_getsequence_np (pthread_t * thread);
-
/* Thread SpecificData */
int __pthread_key_create (pthread_key_t * key, void (*destructor) (void *));
int __pthread_key_delete (pthread_key_t key);
@@ -460,10 +558,8 @@ int __pthread_sigmask (int operation, const sigset_t * set,
sigset_t * old_set);
/* ID */
-pthread_t __pthread_self ();
int __pthread_equal (pthread_t * t1, pthread_t * t2);
-
/* Mutexes */
int __pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *);
int __pthread_mutex_lock (pthread_mutex_t *);
@@ -496,21 +592,7 @@ int __pthread_getschedparam (pthread_t thread, int *policy,
int __pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param);
-/* cancelability states */
-int __pthread_cancel (pthread_t thread);
-int __pthread_setcancelstate (int state, int *oldstate);
-int __pthread_setcanceltype (int type, int *oldtype);
-void __pthread_testcancel (void);
-
-
-/* Semaphores */
-int __sem_init (sem_t * sem, int pshared, unsigned int value);
-int __sem_destroy (sem_t * sem);
-int __sem_wait (sem_t * sem);
-int __sem_trywait (sem_t * sem);
-int __sem_post (sem_t * sem);
};
-
#endif // MT_SAFE
#endif // _CYGNUS_THREADS_
diff --git a/winsup/cygwin/threaded_queue.cc b/winsup/cygwin/threaded_queue.cc
index 5fb22b191..ba0fe4178 100755
--- a/winsup/cygwin/threaded_queue.cc
+++ b/winsup/cygwin/threaded_queue.cc
@@ -1,249 +1,408 @@
/* threaded_queue.cc
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+#include "woutsup.h"
+
+#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
-#include <windows.h>
#include <sys/types.h>
-#include "wincap.h"
+#include <stdlib.h>
#include "threaded_queue.h"
-#define DEBUG 1
-#define debug_printf if (DEBUG) printf
+
+/*****************************************************************************/
+
+/* queue_request */
+
+queue_request::~queue_request ()
+{}
+
+/*****************************************************************************/
/* threaded_queue */
-DWORD WINAPI
-worker_function (LPVOID LpParam)
+threaded_queue::threaded_queue (const size_t initial_workers)
+ : _workers_count (0),
+ _running (false),
+ _submitters_head (NULL),
+ _requests_count (0),
+ _requests_head (NULL),
+ _requests_sem (NULL)
{
- class threaded_queue *queue = (class threaded_queue *) LpParam;
- class queue_request *request;
- /* FIXME use a threadsafe pop instead for speed? */
- while (queue->active)
+ InitializeCriticalSection (&_queue_lock);
+
+ // This semaphore's count is the number of requests on the queue.
+ // The maximum count (129792) is calculated as MAXIMUM_WAIT_OBJECTS
+ // multiplied by max. threads per process (2028?), which is (a few)
+ // more requests than could ever be pending with the current design.
+
+ _requests_sem = CreateSemaphore (NULL, // SECURITY_ATTRIBUTES
+ 0, // Initial count
+ 129792, // Maximum count
+ NULL); // Anonymous
+
+ if (!_requests_sem)
{
- EnterCriticalSection (&queue->queuelock);
- while (!queue->request && queue->active)
- {
- LeaveCriticalSection (&queue->queuelock);
- DWORD rc = WaitForSingleObject (queue->event, INFINITE);
- if (rc == WAIT_FAILED)
- {
- printf ("Wait for event failed\n");
- queue->running--;
- ExitThread (0);
- }
- EnterCriticalSection (&queue->queuelock);
- }
- if (!queue->active)
- {
- queue->running--;
- LeaveCriticalSection (&queue->queuelock);
- ExitThread (0);
- }
- /* not needed, but it is efficient */
- request =
- (class queue_request *) InterlockedExchangePointer (&queue->request,
- queue->request->
- next);
- LeaveCriticalSection (&queue->queuelock);
- request->process ();
- delete request;
+ system_printf (("failed to create the request queue semaphore, "
+ "error = %lu"),
+ GetLastError ());
+ abort ();
}
- queue->running--;
- ExitThread (0);
+
+ create_workers (initial_workers);
}
-void
-threaded_queue::create_workers ()
+threaded_queue::~threaded_queue ()
{
- InitializeCriticalSection (&queuelock);
- if ((event = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL)
+ if (_running)
+ stop ();
+
+ debug_printf ("deleting all pending queue requests");
+ queue_request *reqptr = _requests_head;
+ while (reqptr)
{
- printf ("Failed to create event queue (%lu), terminating\n",
- GetLastError ());
- exit (1);
+ queue_request *const ptr = reqptr;
+ reqptr = reqptr->_next;
+ safe_delete (ptr);
}
- active = true;
- /* FIXME: Use a stack pair and create threads on the fly whenever
- * we have to to service a request.
- */
- for (unsigned int i = 0; i < initial_workers; i++)
+ DeleteCriticalSection (&_queue_lock);
+ if (_requests_sem)
+ (void) CloseHandle (_requests_sem);
+}
+
+/* FIXME: return success or failure rather than quitting */
+void
+threaded_queue::add_submission_loop (queue_submission_loop *const submitter)
+{
+ assert (this);
+ assert (submitter);
+ assert (submitter->_queue == this);
+ assert (!submitter->_next);
+
+ submitter->_next =
+ TInterlockedExchangePointer (&_submitters_head, submitter);
+
+ if (_running)
+ submitter->start ();
+}
+
+bool
+threaded_queue::start ()
+{
+ EnterCriticalSection (&_queue_lock);
+ const bool was_running = _running;
+ _running = true;
+ queue_submission_loop *loopptr = _submitters_head;
+ LeaveCriticalSection (&_queue_lock);
+
+ if (!was_running)
{
- HANDLE hThread;
- DWORD tid;
- hThread = CreateThread (NULL, 0, worker_function, this, 0, &tid);
- if (hThread == NULL)
+ debug_printf ("starting all queue submission loops");
+
+ while (loopptr)
{
- printf ("Failed to create thread (%lu), terminating\n",
- GetLastError ());
- exit (1);
+ queue_submission_loop *const ptr = loopptr;
+ loopptr = loopptr->_next;
+ ptr->start ();
}
- CloseHandle (hThread);
- running++;
}
+
+ return was_running;
}
-void
-threaded_queue::cleanup ()
+bool
+threaded_queue::stop ()
{
- /* harvest the threads */
- active = false;
- /* kill the request processing loops */
- queue_process_param *reqloop;
- /* make sure we don't race with a incoming request creation */
- EnterCriticalSection (&queuelock);
- reqloop =
- (queue_process_param *) InterlockedExchangePointer (&process_head, NULL);
- while (reqloop)
+ EnterCriticalSection (&_queue_lock);
+ const bool was_running = _running;
+ _running = false;
+ queue_submission_loop *loopptr = _submitters_head;
+ LeaveCriticalSection (&_queue_lock);
+
+ if (was_running)
{
- queue_process_param *t = reqloop;
- reqloop = reqloop->next;
- delete t;
+ debug_printf ("stopping all queue submission loops");
+ while (loopptr)
+ {
+ queue_submission_loop *const ptr = loopptr;
+ loopptr = loopptr->_next;
+ ptr->stop ();
+ }
+
+ ReleaseSemaphore (_requests_sem, _workers_count, NULL);
+ while (_workers_count)
+ {
+ debug_printf (("waiting for worker threads to terminate: "
+ "%lu still running"),
+ _workers_count);
+ Sleep (1000);
+ }
+ debug_printf ("all worker threads have terminated");
}
- LeaveCriticalSection (&queuelock);
- if (!running)
- return;
- printf ("Waiting for current queue threads to terminate\n");
- for (int n = running; n; n--)
- PulseEvent (event);
- while (running)
- sleep (1);
- DeleteCriticalSection (&queuelock);
- CloseHandle (event);
+
+ return was_running;
}
/* FIXME: return success or failure */
void
-threaded_queue::add (queue_request * therequest)
+threaded_queue::add (queue_request *const therequest)
{
- /* safe to not "Try" because workers don't hog this, they wait on the event
- */
- EnterCriticalSection (&queuelock);
- if (!running)
+ assert (this);
+ assert (therequest);
+ assert (!therequest->_next);
+
+ if (!_workers_count)
{
- printf ("No worker threads to handle request!\n");
+ system_printf ("warning: no worker threads to handle request!");
+ // FIXME: And then what?
}
- if (!request)
- request = therequest;
+
+ EnterCriticalSection (&_queue_lock);
+ if (!_requests_head)
+ _requests_head = therequest;
else
{
- /* add to the queue end. */
- queue_request *listrequest = request;
- while (listrequest->next)
- listrequest = listrequest->next;
- listrequest->next = therequest;
+ /* Add to the queue end. */
+ queue_request *reqptr = _requests_head;
+ for (; reqptr->_next; reqptr = reqptr->_next)
+ {}
+ assert (reqptr);
+ assert (!reqptr->_next);
+ reqptr->_next = therequest;
}
- PulseEvent (event);
- LeaveCriticalSection (&queuelock);
+
+ _requests_count += 1;
+ assert (_requests_count > 0);
+ LeaveCriticalSection (&_queue_lock);
+
+ (void) ReleaseSemaphore (_requests_sem, 1, NULL);
}
-/* FIXME: return success or failure rather than quitting */
+/*static*/ DWORD WINAPI
+threaded_queue::start_routine (const LPVOID lpParam)
+{
+ class threaded_queue *const queue = (class threaded_queue *) lpParam;
+ assert (queue);
+
+ queue->worker_loop ();
+
+ const long count = InterlockedDecrement (&queue->_workers_count);
+ assert (count >= 0);
+
+ if (queue->_running)
+ debug_printf ("worker loop has exited; thread about to terminate");
+
+ return 0;
+}
+
+/* Called from the constructor: so no need to be thread-safe until the
+ * worker threads start to be created; thus the interlocked increment
+ * of the `_workers_count' field.
+ */
+
void
-threaded_queue::process_requests (queue_process_param * params,
- threaded_queue_thread_function *
- request_loop)
+threaded_queue::create_workers (const size_t initial_workers)
{
- if (params->start (request_loop, this) == false)
- exit (1);
- params->next =
- (queue_process_param *) InterlockedExchangePointer (&process_head,
- params);
+ assert (initial_workers > 0);
+
+ for (unsigned int i = 0; i != initial_workers; i++)
+ {
+ const long count = InterlockedIncrement (&_workers_count);
+ assert (count > 0);
+
+ DWORD tid;
+ const HANDLE hThread =
+ CreateThread (NULL, 0, start_routine, this, 0, &tid);
+
+ if (!hThread)
+ {
+ system_printf ("failed to create thread, error = %lu",
+ GetLastError ());
+ abort ();
+ }
+
+ (void) CloseHandle (hThread);
+ }
}
-/* queue_process_param */
-/* How does a constructor return an error? */
-queue_process_param::queue_process_param (bool ninterruptible):running (false), shutdown (false),
-interruptible
-(ninterruptible)
+void
+threaded_queue::worker_loop ()
{
- if (!interruptible)
- return;
- debug_printf ("creating an interruptible processing thread\n");
- if ((interrupt = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL)
+ while (true)
{
- printf ("Failed to create interrupt event (%lu), terminating\n",
- GetLastError ());
- exit (1);
+ const DWORD rc = WaitForSingleObject (_requests_sem, INFINITE);
+ if (rc == WAIT_FAILED)
+ {
+ system_printf ("wait for request semaphore failed, error = %lu",
+ GetLastError ());
+ return;
+ }
+ assert (rc == WAIT_OBJECT_0);
+
+ EnterCriticalSection (&_queue_lock);
+ if (!_running)
+ {
+ LeaveCriticalSection (&_queue_lock);
+ return;
+ }
+
+ assert (_requests_head);
+ queue_request *const reqptr = _requests_head;
+ _requests_head = reqptr->_next;
+
+ _requests_count -= 1;
+ assert (_requests_count >= 0);
+ LeaveCriticalSection (&_queue_lock);
+
+ assert (reqptr);
+ reqptr->process ();
+ safe_delete (reqptr);
+ }
+}
+
+/*****************************************************************************/
+
+/* queue_submission_loop */
+
+queue_submission_loop::queue_submission_loop (threaded_queue *const queue,
+ const bool ninterruptible)
+ : _running (false),
+ _interrupt_event (NULL),
+ _queue (queue),
+ _interruptible (ninterruptible),
+ _hThread (NULL),
+ _tid (0),
+ _next (NULL)
+{
+ if (_interruptible)
+ {
+ // verbose: debug_printf ("creating an interruptible processing thread");
+
+ _interrupt_event = CreateEvent (NULL, // SECURITY_ATTRIBUTES
+ FALSE, // Auto-reset
+ FALSE, // Initially non-signalled
+ NULL); // Anonymous
+
+ if (!_interrupt_event)
+ {
+ system_printf ("failed to create interrupt event, error = %lu",
+ GetLastError ());
+ abort ();
+ }
}
}
-queue_process_param::~queue_process_param ()
+queue_submission_loop::~queue_submission_loop ()
{
- if (running)
+ if (_running)
stop ();
- if (!interruptible)
- return;
- CloseHandle (interrupt);
+ if (_interrupt_event)
+ (void) CloseHandle (_interrupt_event);
+ if (_hThread)
+ (void) CloseHandle (_hThread);
}
bool
- queue_process_param::start (threaded_queue_thread_function * request_loop,
- threaded_queue * thequeue)
+queue_submission_loop::start ()
{
- queue = thequeue;
- hThread = CreateThread (NULL, 0, request_loop, this, 0, &tid);
- if (hThread)
+ assert (this);
+ assert (!_hThread);
+
+ const bool was_running = _running;
+
+ if (!was_running)
{
- running = true;
- return true;
+ _running = true;
+
+ _hThread = CreateThread (NULL, 0, start_routine, this, 0, &_tid);
+ if (!_hThread)
+ {
+ system_printf ("failed to create thread, error = %lu",
+ GetLastError ());
+ abort ();
+ }
}
- printf ("Failed to create thread (%lu), terminating\n", GetLastError ());
- return false;
+
+ return was_running;
}
-void
-queue_process_param::stop ()
+bool
+queue_submission_loop::stop ()
{
- if (interruptible)
+ assert (this);
+ assert (_hThread && _hThread != INVALID_HANDLE_VALUE);
+
+ const bool was_running = _running;
+
+ if (_running)
{
- InterlockedExchange (&shutdown, true);
- PulseEvent (interrupt);
- /* Wait up to 50 ms for the thread to exit. If it doesn't _and_ we get
- * scheduled again, we print an error and exit. We _should_ loop or
- * try resignalling. We don't want to hand here though...
- */
- int n = 5;
- while (n-- && WaitForSingleObject (hThread, 1000) == WAIT_TIMEOUT);
- if (!n)
+ _running = false;
+
+ if (_interruptible)
{
- printf ("Process thread didn't shutdown cleanly after 200ms!\n");
- exit (1);
+ assert (_interrupt_event
+ && _interrupt_event != INVALID_HANDLE_VALUE);
+
+ SetEvent (_interrupt_event);
+
+ if (WaitForSingleObject (_hThread, 1000) == WAIT_TIMEOUT)
+ {
+ system_printf (("request loop thread %lu failed to shutdown "
+ "when asked politely: about to get heavy"),
+ _tid);
+
+ if (!TerminateThread (_hThread, 0))
+ {
+ system_printf (("failed to kill request loop thread %lu"
+ ", error = %lu"),
+ _tid, GetLastError ());
+ abort ();
+ }
+ }
}
else
- running = false;
- }
- else
- {
- printf ("killing request loop thread %ld\n", tid);
- int rc;
- if (!(rc = TerminateThread (hThread, 0)))
{
- printf ("error shutting down request loop worker thread\n");
+ // FIXME: could wait to see if the request loop notices that
+ // the submission loop is no longer running and shuts down
+ // voluntarily.
+
+ debug_printf ("killing request loop thread %lu", _tid);
+
+ if (!TerminateThread (_hThread, 0))
+ system_printf (("failed to kill request loop thread %lu"
+ ", error = %lu"),
+ _tid, GetLastError ());
}
- running = false;
}
- CloseHandle (hThread);
-}
-/* queue_request */
-queue_request::queue_request ():next (NULL)
-{
+ return was_running;
}
-void
-queue_request::process (void)
+/*static*/ DWORD WINAPI
+queue_submission_loop::start_routine (const LPVOID lpParam)
{
- printf ("\n**********************************************\n"
- "Oh no! we've hit the base queue_request process() function, and this indicates a coding\n"
- "fault !!!\n" "***********************************************\n");
+ class queue_submission_loop *const submission_loop =
+ (class queue_submission_loop *) lpParam;
+ assert (submission_loop);
+
+ submission_loop->request_loop ();
+
+ debug_printf ("submission loop has exited; thread about to terminate");
+
+ submission_loop->stop ();
+
+ return 0;
}
+
+/*****************************************************************************/
diff --git a/winsup/cygwin/threaded_queue.h b/winsup/cygwin/threaded_queue.h
index b330d96ac..5b6fddc42 100755
--- a/winsup/cygwin/threaded_queue.h
+++ b/winsup/cygwin/threaded_queue.h
@@ -1,67 +1,127 @@
/* threaded_queue.h
- Copyright 2001 Red Hat Inc.
+ Copyright 2001, 2002 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com>
- This file is part of Cygwin.
+This file is part of Cygwin.
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
#ifndef _THREADED_QUEUE_
#define _THREADED_QUEUE_
+/*****************************************************************************/
+
/* a specific request */
class queue_request
{
- public:
- class queue_request *next;
- virtual void process ();
- queue_request();
+public:
+ queue_request *_next;
+
+ queue_request () : _next (NULL) {}
+ virtual ~queue_request ();
+
+ virtual void process () = 0;
};
+/*****************************************************************************/
-typedef DWORD WINAPI threaded_queue_thread_function (LPVOID);
-/* parameters for a request finding and submitting loop */
+/* a queue to allocate requests from n submission loops to x worker threads */
-class queue_process_param
+class queue_submission_loop;
+
+class threaded_queue
{
- public:
- bool start (threaded_queue_thread_function *, class threaded_queue *);
- void stop ();
- bool running;
- long int shutdown;
- class queue_process_param * next;
- class threaded_queue *queue;
- queue_process_param (bool ninterruptible);
- ~queue_process_param ();
- bool interruptible;
- HANDLE interrupt;
- HANDLE hThread;
- DWORD tid;
+public:
+ threaded_queue (size_t initial_workers = 1);
+ ~threaded_queue ();
+
+ void add_submission_loop (queue_submission_loop *);
+
+ bool running () const { return _running; }
+
+ bool start ();
+ bool stop ();
+
+ void add (queue_request *);
+
+private:
+ long _workers_count;
+ bool _running;
+
+ queue_submission_loop *_submitters_head;
+
+ long _requests_count; // Informational only.
+ queue_request *_requests_head;
+
+ CRITICAL_SECTION _queue_lock;
+ HANDLE _requests_sem; // == _requests_count
+
+ static DWORD WINAPI start_routine (LPVOID /* this */);
+
+ void create_workers (size_t initial_workers);
+ void worker_loop ();
};
-/* a queue to allocate requests from n submission loops to x worker threads */
+/*****************************************************************************/
-class threaded_queue
+/* parameters for a request finding and submitting loop */
+
+class queue_submission_loop
{
- public:
- CRITICAL_SECTION queuelock;
- HANDLE event;
- bool active;
- queue_request * request;
- unsigned int initial_workers;
- unsigned int running;
- void create_workers ();
- void cleanup ();
- void add (queue_request *);
- void process_requests (queue_process_param *, threaded_queue_thread_function *);
- threaded_queue () : active (false), request (NULL), initial_workers (1), running (0), process_head (NULL) {};
- private:
- queue_request *process_head;
+ friend class threaded_queue;
+
+public:
+ queue_submission_loop (threaded_queue *, bool ninterruptible);
+ virtual ~queue_submission_loop ();
+
+ bool start ();
+ bool stop ();
+
+ threaded_queue *queue () { return _queue; };
+
+protected:
+ bool _running;
+ HANDLE _interrupt_event;
+ threaded_queue *const _queue;
+
+private:
+ bool _interruptible;
+ HANDLE _hThread;
+ DWORD _tid;
+ queue_submission_loop *_next;
+
+ static DWORD WINAPI start_routine (LPVOID /* this */);
+ virtual void request_loop () = 0;
};
+#ifdef __cplusplus
+
+/*---------------------------------------------------------------------------*
+ * Some type-safe versions of the various interlocked functions.
+ *---------------------------------------------------------------------------*/
+
+template <typename T> T *
+TInterlockedExchangePointer (T **lvalue, T *rvalue)
+{
+ return reinterpret_cast<T *>
+ (InterlockedExchangePointer (reinterpret_cast<void **> (lvalue),
+ reinterpret_cast<void *> (rvalue)));
+}
+
+template <typename T> T *
+TInterlockedCompareExchangePointer (T **lvalue, T *rvalue1, T *rvalue2)
+{
+ return reinterpret_cast<T *>
+ (InterlockedCompareExchangePointer (reinterpret_cast<void **> (lvalue),
+ reinterpret_cast<void *> (rvalue1),
+ reinterpret_cast<void *> (rvalue2)));
+}
+
+#endif /* __cplusplus */
+
#endif /* _THREADED_QUEUE_ */
diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc
index e5635ddff..6bb981d1a 100644
--- a/winsup/cygwin/times.cc
+++ b/winsup/cygwin/times.cc
@@ -1,6 +1,6 @@
/* times.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -17,13 +17,11 @@ details. */
#include <stdlib.h>
#include <errno.h>
#include "cygerrno.h"
-#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
+#include "hires.h"
#define FACTOR (0x19db1ded53e8000LL)
#define NSPERSEC 10000000LL
@@ -48,7 +46,7 @@ __to_clock_t (FILETIME * src, int flag)
/* times: POSIX 4.5.2.1 */
extern "C" clock_t
-times (struct tms * buf)
+_times (struct tms * buf)
{
FILETIME creation_time, exit_time, kernel_time, user_time;
@@ -88,12 +86,6 @@ times (struct tms * buf)
return tc;
}
-extern "C" clock_t
-_times (struct tms * buf)
-{
- return times (buf);
-}
-
/* settimeofday: BSD */
extern "C" int
settimeofday (const struct timeval *tv, const struct timezone *tz)
@@ -104,7 +96,7 @@ settimeofday (const struct timeval *tv, const struct timezone *tz)
tz = tz; /* silence warning about unused variable */
- ptm = gmtime(&tv->tv_sec);
+ ptm = gmtime (&tv->tv_sec);
st.wYear = ptm->tm_year + 1900;
st.wMonth = ptm->tm_mon + 1;
st.wDayOfWeek = ptm->tm_wday;
@@ -114,7 +106,7 @@ settimeofday (const struct timeval *tv, const struct timezone *tz)
st.wSecond = ptm->tm_sec;
st.wMilliseconds = tv->tv_usec / 1000;
- res = !SetSystemTime(&st);
+ res = !SetSystemTime (&st);
syscall_printf ("%d = settimeofday (%x, %x)", res, tv, tz);
@@ -126,13 +118,13 @@ extern "C" char *
timezone ()
{
#ifdef _MT_SAFE
- char *b=_reent_winsup()->timezone_buf;
+ char *b=_reent_winsup ()->timezone_buf;
#else
static NO_COPY char b[20] = {0};
#endif
- tzset();
- __small_sprintf (b,"GMT%+d:%02d", (int) (-_timezone / 3600), (int) (abs(_timezone / 60) % 60));
+ tzset ();
+ __small_sprintf (b,"GMT%+d:%02d", (int) (-_timezone / 3600), (int) (abs (_timezone / 60) % 60));
return b;
}
@@ -149,61 +141,39 @@ totimeval (struct timeval *dst, FILETIME *src, int sub, int flag)
dst->tv_sec = x / (long long) (1e6);
}
-/* gettimeofday: BSD */
+/* FIXME: Make thread safe */
extern "C" int
-gettimeofday (struct timeval *p, struct timezone *z)
+gettimeofday (struct timeval *tv, struct timezone *tz)
{
- int res = 0;
-
- if (p != NULL)
- {
- FILETIME f;
+ static hires_ms gtod;
+ static bool tzflag;
+ LONGLONG now = gtod.usecs (false);
+ if (now == (LONGLONG) -1)
+ return -1;
- GetSystemTimeAsFileTime (&f);
- totimeval (p, &f, 0, 1);
- }
+ tv->tv_sec = now / 1000000;
+ tv->tv_usec = now % 1000000;
- if (z != NULL)
+ if (tz != NULL)
{
- tzset();
- z->tz_minuteswest = _timezone / 60;
- z->tz_dsttime = _daylight;
+ if (!tzflag)
+ {
+ tzset ();
+ tzflag = true;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
}
- syscall_printf ("%d = gettimeofday (%x, %x)", res, p, z);
-
- return res;
+ return 0;
}
-extern "C"
-int
+extern "C" int
_gettimeofday (struct timeval *p, struct timezone *z)
{
return gettimeofday (p, z);
}
-#if 0
-/* Work out magic constant below */
-genf ()
-{
- SYSTEMTIME s;
- FILETIME f;
- s.wYear = 1970;
- s.wMonth = 1;
- s.wDayOfWeek = 4;
- s.wDay = 1;
- s.wHour = 0;
- s.wMinute = 0;
- s.wSecond = 0;
- s.wMilliseconds = 0;
- SystemTimeToFileTime (&s, &f);
-
- small_printf ("FILE TIME is %08x%08x\n",
- f.dwHighDateTime,
- f.dwLowDateTime);
-}
-#endif
-
/* Cygwin internal */
void
time_t_to_filetime (time_t time_in, FILETIME *out)
@@ -242,7 +212,6 @@ to_time_t (FILETIME *ptr)
stuffed into two long words.
A time_t is the number of seconds since jan 1 1970. */
- long rem;
long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
/* pass "no time" as epoch */
@@ -250,13 +219,51 @@ to_time_t (FILETIME *ptr)
return 0;
x -= FACTOR; /* number of 100ns between 1601 and 1970 */
- rem = x % ((long long)NSPERSEC);
- rem += (NSPERSEC / 2);
x /= (long long) NSPERSEC; /* number of 100ns in a second */
- x += (long long) (rem / NSPERSEC);
return x;
}
+/* Cygwin internal */
+/* Convert a Win32 time to "UNIX" timestruc_t format. */
+void __stdcall
+to_timestruc_t (FILETIME *ptr, timestruc_t *out)
+{
+ /* A file time is the number of 100ns since jan 1 1601
+ stuffed into two long words.
+ A timestruc_t is the number of seconds and microseconds since jan 1 1970
+ stuffed into a time_t and a long. */
+
+ long rem;
+ long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
+
+ /* pass "no time" as epoch */
+ if (x == 0)
+ {
+ out->tv_sec = 0;
+ out->tv_nsec = 0;
+ return;
+ }
+
+ x -= FACTOR; /* number of 100ns between 1601 and 1970 */
+ rem = x % ((long long)NSPERSEC);
+ x /= (long long) NSPERSEC; /* number of 100ns in a second */
+ out->tv_nsec = rem * 100; /* as tv_nsec is in nanoseconds */
+ out->tv_sec = x;
+}
+
+/* Cygwin internal */
+/* Get the current time as a "UNIX" timestruc_t format. */
+void __stdcall
+time_as_timestruc_t (timestruc_t * out)
+{
+ SYSTEMTIME systemtime;
+ FILETIME filetime;
+
+ GetSystemTime (&systemtime);
+ SystemTimeToFileTime (&systemtime, &filetime);
+ to_timestruc_t (&filetime, out);
+}
+
/* time: POSIX 4.5.1.1, C 4.12.2.4 */
/* Return number of seconds since 00:00 UTC on jan 1, 1970 */
extern "C"
@@ -461,22 +468,18 @@ utimes (const char *path, struct timeval *tvp)
}
/* MSDN suggests using FILE_FLAG_BACKUP_SEMANTICS for accessing
- the times of directories. FIXME: what about Win95??? */
+ the times of directories. */
/* Note: It's not documented in MSDN that FILE_WRITE_ATTRIBUTES is
sufficient to change the timestamps... */
- HANDLE h = CreateFileA (win32.get_win32 (),
- wincap.has_specific_access_rights () ?
- FILE_WRITE_ATTRIBUTES : GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sec_none_nih,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
- 0);
+ HANDLE h = CreateFile (win32, FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sec_none_nih, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ 0);
if (h == INVALID_HANDLE_VALUE)
{
- if ((res = GetFileAttributes (win32.get_win32 ())) != -1 &&
- (res & FILE_ATTRIBUTE_DIRECTORY))
+ if (win32.isdir ())
{
/* What we can do with directories more? */
res = 0;
@@ -565,8 +568,105 @@ ftime (struct timeb *tp)
}
/* obsolete, changed to cygwin_tzset when localtime.c was added - dj */
-extern "C"
-void
+extern "C" void
cygwin_tzset ()
{
}
+
+void
+hires_us::prime ()
+{
+ LARGE_INTEGER ifreq;
+ if (!QueryPerformanceFrequency (&ifreq))
+ {
+ inited = -1;
+ return;
+ }
+
+ FILETIME f;
+ int priority = GetThreadPriority (GetCurrentThread ());
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+ if (!QueryPerformanceCounter (&primed_pc))
+ {
+ SetThreadPriority (GetCurrentThread (), priority);
+ inited = -1;
+ return;
+ }
+
+ GetSystemTimeAsFileTime (&f);
+ SetThreadPriority (GetCurrentThread (), priority);
+
+ inited = 1;
+ primed_ft.HighPart = f.dwHighDateTime;
+ primed_ft.LowPart = f.dwLowDateTime;
+ primed_ft.QuadPart -= FACTOR;
+ primed_ft.QuadPart /= 10;
+ freq = (double) ((double) 1000000. / (double) ifreq.QuadPart);
+ return;
+}
+
+LONGLONG
+hires_us::usecs (bool justdelta)
+{
+ if (!inited)
+ prime ();
+ if (inited < 0)
+ {
+ set_errno (ENOSYS);
+ return (long long) -1;
+ }
+
+ LARGE_INTEGER now;
+ if (!QueryPerformanceCounter (&now))
+ {
+ set_errno (ENOSYS);
+ return -1;
+ }
+
+ // FIXME: Use round() here?
+ now.QuadPart = (LONGLONG) (freq * (double) (now.QuadPart - primed_pc.QuadPart));
+ return justdelta ? now.QuadPart : primed_ft.QuadPart + now.QuadPart;
+}
+
+void
+hires_ms::prime ()
+{
+ TIMECAPS tc;
+ FILETIME f;
+ int priority = GetThreadPriority (GetCurrentThread ());
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+
+ if (timeGetDevCaps (&tc, sizeof (tc)) != TIMERR_NOERROR)
+ minperiod = 0;
+ else
+ {
+ minperiod = min (max (tc.wPeriodMin, 1), tc.wPeriodMax);
+ timeBeginPeriod (minperiod);
+ }
+
+ initime_ms = timeGetTime ();
+ GetSystemTimeAsFileTime (&f);
+ SetThreadPriority (GetCurrentThread (), priority);
+
+ inited = 1;
+ initime_us.HighPart = f.dwHighDateTime;
+ initime_us.LowPart = f.dwLowDateTime;
+ initime_us.QuadPart -= FACTOR;
+ initime_us.QuadPart /= 10;
+}
+
+LONGLONG
+hires_ms::usecs (bool justdelta)
+{
+ if (!inited)
+ prime ();
+ DWORD now = timeGetTime ();
+ // FIXME: Not sure how this will handle the 49.71 day wrap around
+ LONGLONG res = initime_us.QuadPart + ((LONGLONG) (now - initime_ms) * 1000);
+ return res;
+}
+
+hires_ms::~hires_ms ()
+{
+ timeEndPeriod (minperiod);
+}
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 3e3a3c3b1..982bfab57 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -1,6 +1,6 @@
/* tty.cc
- Copyright 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -21,12 +21,10 @@ details. */
#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
-#include "cygwin/cygserver_transport.h"
#include "cygwin/cygserver.h"
#include "shared_info.h"
+#include "cygthread.h"
extern fhandler_tty_master *tty_master;
@@ -56,6 +54,9 @@ ttyslot (void)
void __stdcall
tty_init (void)
{
+ if (!myself->ppid_handle && NOTSTATE (myself, PID_CYGPARENT))
+ cygheap->fdtab.get_debugger_info ();
+
if (NOTSTATE (myself, PID_USETTY))
return;
if (myself->ctty == -1)
@@ -72,8 +73,8 @@ tty_init (void)
void __stdcall
create_tty_master (int ttynum)
{
- tty_master = (fhandler_tty_master *) cygheap->fdtab.build_fhandler (-1, FH_TTYM,
- "/dev/ttym", ttynum);
+ tty_master = (fhandler_tty_master *)
+ cygheap->fdtab.build_fhandler (-1, FH_TTYM, "/dev/ttym", NULL, ttynum);
if (tty_master->init (ttynum))
api_fatal ("Can't create master tty");
else
@@ -143,7 +144,8 @@ tty_list::terminate (void)
ForceCloseHandle1 (t->to_slave, to_pty);
ForceCloseHandle1 (t->from_slave, from_pty);
CloseHandle (tty_master->inuse);
- WaitForSingleObject (tty_master->hThread, INFINITE);
+ if (tty_master->output_thread)
+ tty_master->output_thread->detach ();
t->init ();
char buf[20];
@@ -193,7 +195,7 @@ tty_list::allocate_tty (int with_console)
if (!with_console)
console = NULL;
- else
+ else if (!(console = GetConsoleWindow ()))
{
char *oldtitle = new char [TITLESIZE];
@@ -215,8 +217,12 @@ tty_list::allocate_tty (int with_console)
__small_sprintf (buf, "cygwin.find.console.%d", myself->pid);
SetConsoleTitle (buf);
- Sleep (40);
- console = FindWindow (NULL, buf);
+ for (int times = 0; times < 25; times++)
+ {
+ Sleep (10);
+ if ((console = FindWindow (NULL, buf)))
+ break;
+ }
SetConsoleTitle (oldtitle);
Sleep (40);
ReleaseMutex (title_mutex);
@@ -360,14 +366,14 @@ tty::make_pipes (fhandler_pty_master *ptym)
return FALSE;
}
- ProtectHandle1 (to_slave, to_pty);
+ // ProtectHandle1INH (to_slave, to_pty);
if (CreatePipe (&from_slave, &to_master, &sec_all, 0) == FALSE)
{
termios_printf ("can't create output pipe");
set_errno (ENOENT);
return FALSE;
}
- ProtectHandle1 (from_slave, from_pty);
+ // ProtectHandle1INH (from_slave, from_pty);
termios_printf ("tty%d from_slave %p, to_slave %p", ntty, from_slave,
to_slave);
@@ -395,10 +401,20 @@ tty::common_init (fhandler_pty_master *ptym)
/* Allow the others to open us (for handle duplication) */
- if (wincap.has_security () && cygserver_running==CYGSERVER_OK &&
- (SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION,
- get_null_sd ()) == FALSE))
- small_printf ("Can't set process security, %E");
+ /* FIXME: we shold NOT set the security wide open when the
+ daemon is running
+ */
+ if (wincap.has_security ())
+ {
+ if (cygserver_running == CYGSERVER_UNKNOWN)
+ cygserver_init ();
+
+ if (cygserver_running != CYGSERVER_OK
+ && !SetKernelObjectSecurity (hMainProc,
+ DACL_SECURITY_INFORMATION,
+ get_null_sd ()))
+ system_printf ("Can't set process security, %E");
+ }
/* Create synchronisation events */
@@ -437,8 +453,8 @@ tty::common_init (fhandler_pty_master *ptym)
return FALSE;
}
- ProtectHandle1 (ptym->output_mutex, output_mutex);
- ProtectHandle1 (ptym->input_mutex, input_mutex);
+ ProtectHandle1INH (ptym->output_mutex, output_mutex);
+ ProtectHandle1INH (ptym->input_mutex, input_mutex);
winsize.ws_col = 80;
winsize.ws_row = 25;
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 4aa6363ae..30d8bb03b 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -1,6 +1,6 @@
/* tty.h: shared tty info for cygwin
- Copyright 2000, 2001 Red Hat, Inc.
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -62,6 +62,7 @@ public:
int getsid () {return sid;}
void setsid (pid_t tsid) {sid = tsid;}
void set_ctty (int ttynum, int flags);
+ void kill_pgrp (int sig);
struct termios ti;
struct winsize winsize;
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index 9bbbe9e9c..fc8b73cc6 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -1,6 +1,6 @@
/* uinfo.cc: user info (uid, gid, etc...)
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -17,226 +17,110 @@ details. */
#include <limits.h>
#include <stdlib.h>
#include <lm.h>
+#include <errno.h>
#include <sys/cygwin.h>
-#include "sync.h"
-#include "sigproc.h"
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
+#include "cygerrno.h"
#include "cygheap.h"
#include "registry.h"
+#include "child_info.h"
+#include "environ.h"
-struct passwd *
+void
internal_getlogin (cygheap_user &user)
{
- char username[UNLEN + 1];
- DWORD username_len = UNLEN + 1;
struct passwd *pw = NULL;
- if (!GetUserName (username, &username_len))
- user.set_name ("unknown");
- else
- user.set_name (username);
- debug_printf ("GetUserName() = %s", user.name ());
-
if (wincap.has_security ())
{
- LPWKSTA_USER_INFO_1 wui;
- NET_API_STATUS ret;
- char buf[512];
- char *env;
-
- user.set_logsrv (NULL);
- /* First trying to get logon info from environment */
- if ((env = getenv ("USERNAME")) != NULL)
- user.set_name (env);
- if ((env = getenv ("USERDOMAIN")) != NULL)
- user.set_domain (env);
- if ((env = getenv ("LOGONSERVER")) != NULL)
- user.set_logsrv (env + 2); /* filter leading double backslashes */
- if (user.name () && user.domain ())
- debug_printf ("User: %s, Domain: %s, Logon Server: %s",
- user.name (), user.domain (), user.logsrv ());
- else if (!(ret = NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui)))
- {
- sys_wcstombs (buf, wui->wkui1_username, UNLEN + 1);
- user.set_name (buf);
- sys_wcstombs (buf, wui->wkui1_logon_server,
- INTERNET_MAX_HOST_NAME_LENGTH + 1);
- user.set_logsrv (buf);
- sys_wcstombs (buf, wui->wkui1_logon_domain,
- INTERNET_MAX_HOST_NAME_LENGTH + 1);
- user.set_domain (buf);
- NetApiBufferFree (wui);
- }
- if (!user.logsrv () && get_logon_server_and_user_domain (buf, NULL))
- {
- user.set_logsrv (buf + 2);
- setenv ("LOGONSERVER", buf, 1);
- }
- LPUSER_INFO_3 ui = NULL;
- WCHAR wuser[UNLEN + 1];
- WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
-
- /* HOMEDRIVE and HOMEPATH are wrong most of the time, too,
- after changing user context! */
- sys_mbstowcs (wuser, user.name (), UNLEN + 1);
- wlogsrv[0] = '\0';
- if (user.logsrv ())
- {
- strcat (strcpy (buf, "\\\\"), user.logsrv ());
- sys_mbstowcs (wlogsrv, buf, INTERNET_MAX_HOST_NAME_LENGTH + 3);
- }
- if (!NetUserGetInfo (NULL, wuser, 3, (LPBYTE *)&ui)
- || (wlogsrv[0] && !NetUserGetInfo (wlogsrv, wuser, 3,(LPBYTE *)&ui)))
- {
- sys_wcstombs (buf, ui->usri3_home_dir, MAX_PATH);
- if (!buf[0])
- {
- sys_wcstombs (buf, ui->usri3_home_dir_drive, MAX_PATH);
- if (buf[0])
- strcat (buf, "\\");
- else
- {
- env = getenv ("SYSTEMDRIVE");
- if (env && *env)
- strcat (strcpy (buf, env), "\\");
- else
- GetSystemDirectoryA (buf, MAX_PATH);
- }
- }
- setenv ("HOMEPATH", buf + 2, 1);
- buf[2] = '\0';
- setenv ("HOMEDRIVE", buf, 1);
- NetApiBufferFree (ui);
- }
- debug_printf ("Domain: %s, Logon Server: %s, Windows Username: %s",
- user.domain (), user.logsrv (), user.name ());
+ HANDLE ptok = INVALID_HANDLE_VALUE;
+ DWORD siz;
+ cygsid tu;
+ DWORD ret = 0;
- if (allow_ntsec)
- {
- HANDLE ptok = user.token; /* Which is INVALID_HANDLE_VALUE if no
- impersonation took place. */
- DWORD siz;
- cygsid tu;
- int ret = 0;
-
- /* Try to get the SID either from already impersonated token
- or from current process first. To differ that two cases is
- important, because you can't rely on the user information
- in a process token of a currently impersonated process. */
- if (ptok == INVALID_HANDLE_VALUE
- && !OpenProcessToken (GetCurrentProcess (),
- TOKEN_ADJUST_DEFAULT | TOKEN_QUERY,
- &ptok))
- debug_printf ("OpenProcessToken(): %E\n");
- else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
- debug_printf ("GetTokenInformation(): %E");
- else if (!(ret = user.set_sid (tu)))
- debug_printf ("Couldn't retrieve SID from access token!");
- /* If that failes, try to get the SID from localhost. This can only
- be done if a domain is given because there's a chance that a local
- and a domain user may have the same name. */
- if (!ret && user.domain ())
- {
- /* Concat DOMAIN\USERNAME for the next lookup */
- strcat (strcat (strcpy (buf, user.domain ()), "\\"), user.name ());
- if (!(ret = lookup_name (buf, NULL, user.sid ())))
- debug_printf ("Couldn't retrieve SID locally!");
- }
-
- /* If that fails, too, as a last resort try to get the SID from
- the logon server. */
- if (!ret && !(ret = lookup_name (user.name (), user.logsrv (),
- user.sid ())))
- debug_printf ("Couldn't retrieve SID from '%s'!", user.logsrv ());
-
- /* If we have a SID, try to get the corresponding Cygwin user name
- which can be different from the Windows user name. */
+ /* Try to get the SID either from current process and
+ store it in user.psid */
+ if (!OpenProcessToken (hMainProc, TOKEN_ADJUST_DEFAULT | TOKEN_QUERY,
+ &ptok))
+ system_printf ("OpenProcessToken(): %E\n");
+ else if (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &siz))
+ system_printf ("GetTokenInformation (TokenUser): %E");
+ else if (!(ret = user.set_sid (tu)))
+ system_printf ("Couldn't retrieve SID from access token!");
+ else if (!GetTokenInformation (ptok, TokenPrimaryGroup,
+ &user.groups.pgsid, sizeof tu, &siz))
+ system_printf ("GetTokenInformation (TokenPrimaryGroup): %E");
+ /* We must set the user name, uid and gid.
+ If we have a SID, try to get the corresponding Cygwin
+ password entry. Set user name which can be different
+ from the Windows user name */
+ if (ret)
+ {
cygsid gsid (NO_SID);
- if (ret)
- {
- cygsid psid;
-
- for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
- if (psid.getfrompw (pw) && EqualSid (user.sid (), psid))
- {
- user.set_name (pw->pw_name);
- struct group *gr = getgrgid (pw->pw_gid);
- if (gr)
- if (!gsid.getfromgr (gr))
- gsid = NO_SID;
- break;
- }
- if (!strcasematch (user.name (), "SYSTEM")
- && user.domain () && user.logsrv ())
- {
- if (get_registry_hive_path (user.sid (), buf))
- setenv ("USERPROFILE", buf, 1);
- else
- unsetenv ("USERPROFILE");
- }
- }
+ cygsid psid;
+
+ for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
+ if (psid.getfrompw (pw) && EqualSid (user.sid (), psid))
+ {
+ user.set_name (pw->pw_name);
+ struct __group32 *gr = getgrgid32 (pw->pw_gid);
+ if (gr)
+ if (!gsid.getfromgr (gr))
+ gsid = NO_SID;
+ break;
+ }
- /* If this process is started from a non Cygwin process,
- set token owner to the same value as token user and
- primary group to the group which is set as primary group
- in /etc/passwd. */
- if (ptok != INVALID_HANDLE_VALUE && myself->ppid == 1)
+ /* Set token owner to the same value as token user and
+ primary group to the group in /etc/passwd. */
+ if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
+ debug_printf ("SetTokenInformation(TokenOwner): %E");
+ if (gsid)
{
- if (!SetTokenInformation (ptok, TokenOwner, &tu, sizeof tu))
- debug_printf ("SetTokenInformation(TokenOwner): %E");
- if (gsid && !SetTokenInformation (ptok, TokenPrimaryGroup,
- &gsid, sizeof gsid))
+ user.groups.pgsid = gsid;
+ if (!SetTokenInformation (ptok, TokenPrimaryGroup,
+ &gsid, sizeof gsid))
debug_printf ("SetTokenInformation(TokenPrimaryGroup): %E");
}
+ }
+ if (ptok != INVALID_HANDLE_VALUE)
+ CloseHandle (ptok);
+ }
- /* Close token only if it's a result from OpenProcessToken(). */
- if (ptok != INVALID_HANDLE_VALUE
- && user.token == INVALID_HANDLE_VALUE)
- CloseHandle (ptok);
- }
+ if (!pw)
+ pw = getpwnam (user.name ());
+
+ if (pw)
+ {
+ myself->uid = pw->pw_uid;
+ myself->gid = pw->pw_gid;
+ }
+ else
+ {
+ myself->uid = DEFAULT_UID;
+ myself->gid = DEFAULT_GID;
}
- debug_printf ("Cygwins Username: %s", user.name ());
- return pw ?: getpwnam(user.name ());
+
+ (void) cygheap->user.ontherange (CH_HOME, pw);
+
+ return;
}
void
uinfo_init ()
{
- struct passwd *p;
-
- /* Initialize to non impersonated values.
- Setting `impersonated' to TRUE seems to be wrong but it
- isn't. Impersonated is thought as "Current User and `token'
- are coincident". See seteuid() for the mechanism behind that. */
- if (cygheap->user.token != INVALID_HANDLE_VALUE)
- CloseHandle (cygheap->user.token);
- cygheap->user.token = INVALID_HANDLE_VALUE;
- cygheap->user.impersonated = TRUE;
-
- /* If uid is USHRT_MAX, the process is started from a non cygwin
- process or the user context was changed in spawn.cc */
- if (myself->uid == USHRT_MAX)
- if ((p = internal_getlogin (cygheap->user)) != NULL)
- {
- myself->uid = p->pw_uid;
- /* Set primary group only if ntsec is off or the process has been
- started from a non cygwin process. */
- if (!allow_ntsec || myself->ppid == 1)
- myself->gid = p->pw_gid;
- }
- else
- {
- myself->uid = DEFAULT_UID;
- myself->gid = DEFAULT_GID;
- }
- /* Real and effective uid/gid are always identical on process start up.
- This is at least true for NT/W2K. */
+ if (!child_proc_info)
+ internal_getlogin (cygheap->user); /* Set the cygheap->user. */
+
+ /* Real and effective uid/gid are identical on process start up. */
cygheap->user.orig_uid = cygheap->user.real_uid = myself->uid;
cygheap->user.orig_gid = cygheap->user.real_gid = myself->gid;
+ cygheap->user.set_orig_sid (); /* Update the original sid */
+
+ cygheap->user.token = INVALID_HANDLE_VALUE; /* No token present */
}
extern "C" char *
@@ -245,31 +129,55 @@ getlogin (void)
#ifdef _MT_SAFE
char *this_username=_reent_winsup ()->_username;
#else
- static NO_COPY char this_username[UNLEN + 1];
+ static char this_username[UNLEN + 1] NO_COPY;
#endif
return strcpy (this_username, cygheap->user.name ());
}
-extern "C" uid_t
+extern "C" __uid32_t
+getuid32 (void)
+{
+ return cygheap->user.real_uid;
+}
+
+extern "C" __uid16_t
getuid (void)
{
return cygheap->user.real_uid;
}
-extern "C" gid_t
+extern "C" __gid32_t
+getgid32 (void)
+{
+ return cygheap->user.real_gid;
+}
+
+extern "C" __gid16_t
getgid (void)
{
return cygheap->user.real_gid;
}
-extern "C" uid_t
+extern "C" __uid32_t
+geteuid32 (void)
+{
+ return myself->uid;
+}
+
+extern "C" __uid16_t
geteuid (void)
{
return myself->uid;
}
-extern "C" gid_t
+extern "C" __gid32_t
+getegid32 (void)
+{
+ return myself->gid;
+}
+
+extern "C" __gid16_t
getegid (void)
{
return myself->gid;
@@ -279,13 +187,215 @@ getegid (void)
extern "C" char *
cuserid (char *src)
{
- if (src)
+ if (!src)
+ return getlogin ();
+
+ strcpy (src, getlogin ());
+ return src;
+}
+
+const char *
+cygheap_user::ontherange (homebodies what, struct passwd *pw)
+{
+ LPUSER_INFO_3 ui = NULL;
+ WCHAR wuser[UNLEN + 1];
+ NET_API_STATUS ret;
+ char homepath_env_buf[MAX_PATH + 1];
+ char homedrive_env_buf[3];
+ char *newhomedrive = NULL;
+ char *newhomepath = NULL;
+
+
+ debug_printf ("what %d, pw %p", what, pw);
+ if (what == CH_HOME)
+ {
+ char *p;
+ if (homedrive)
+ newhomedrive = homedrive;
+ else if ((p = getenv ("HOMEDRIVE")))
+ newhomedrive = p;
+
+ if (homepath)
+ newhomepath = homepath;
+ else if ((p = getenv ("HOMEPATH")))
+ newhomepath = p;
+
+ if ((p = getenv ("HOME")))
+ debug_printf ("HOME is already in the environment %s", p);
+ else
+ {
+ if (!pw)
+ pw = getpwnam (name ());
+ if (pw && pw->pw_dir && *pw->pw_dir)
+ {
+ debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
+ setenv ("HOME", pw->pw_dir, 1);
+ }
+ else if (!newhomedrive || !newhomepath)
+ setenv ("HOME", "/", 1);
+ else
+ {
+ char home[MAX_PATH];
+ char buf[MAX_PATH + 1];
+ strcpy (buf, newhomedrive);
+ strcat (buf, newhomepath);
+ cygwin_conv_to_full_posix_path (buf, home);
+ debug_printf ("Set HOME (from HOMEDRIVE/HOMEPATH) to %s", home);
+ setenv ("HOME", home, 1);
+ }
+ }
+ }
+
+ if (what != CH_HOME && homepath == NULL && newhomepath == NULL)
+ {
+ if (!pw)
+ pw = getpwnam (name ());
+ if (pw && pw->pw_dir && *pw->pw_dir)
+ cygwin_conv_to_full_win32_path (pw->pw_dir, homepath_env_buf);
+ else
+ {
+ homepath_env_buf[0] = homepath_env_buf[1] = '\0';
+ if (logsrv ())
+ {
+ WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+ sys_mbstowcs (wlogsrv, logsrv (),
+ sizeof (wlogsrv) / sizeof (*wlogsrv));
+ sys_mbstowcs (wuser, winname (), sizeof (wuser) / sizeof (*wuser));
+ if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3,(LPBYTE *)&ui)))
+ {
+ sys_wcstombs (homepath_env_buf, ui->usri3_home_dir, MAX_PATH);
+ if (!homepath_env_buf[0])
+ {
+ sys_wcstombs (homepath_env_buf, ui->usri3_home_dir_drive,
+ MAX_PATH);
+ if (homepath_env_buf[0])
+ strcat (homepath_env_buf, "\\");
+ else
+ cygwin_conv_to_full_win32_path ("/", homepath_env_buf);
+ }
+ }
+ }
+ if (ui)
+ NetApiBufferFree (ui);
+ }
+
+ if (homepath_env_buf[1] != ':')
+ {
+ newhomedrive = almost_null;
+ newhomepath = homepath_env_buf;
+ }
+ else
+ {
+ homedrive_env_buf[0] = homepath_env_buf[0];
+ homedrive_env_buf[1] = homepath_env_buf[1];
+ homedrive_env_buf[2] = '\0';
+ newhomedrive = homedrive_env_buf;
+ newhomepath = homepath_env_buf + 2;
+ }
+ }
+
+ if (newhomedrive && newhomedrive != homedrive)
+ cfree_and_set (homedrive, (newhomedrive == almost_null)
+ ? almost_null : cstrdup (newhomedrive));
+
+ if (newhomepath && newhomepath != homepath)
+ cfree_and_set (homepath, cstrdup (newhomepath));
+
+ switch (what)
{
- strcpy (src, getlogin ());
- return src;
+ case CH_HOMEDRIVE:
+ return homedrive;
+ case CH_HOMEPATH:
+ return homepath;
+ default:
+ return homepath;
}
+}
+
+const char *
+cygheap_user::test_uid (char *&what, const char *name, size_t namelen)
+{
+ if (!what && !issetuid ())
+ what = getwinenveq (name, namelen, HEAP_STR);
+ return what;
+}
+
+const char *
+cygheap_user::env_logsrv (const char *name, size_t namelen)
+{
+ if (test_uid (plogsrv, name, namelen))
+ return plogsrv;
+
+ const char *mydomain = domain ();
+ const char *myname = winname ();
+ if (!mydomain || strcasematch (myname, "SYSTEM"))
+ return almost_null;
+
+ char logsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+ cfree_and_set (plogsrv, almost_null);
+ if (get_logon_server (mydomain, logsrv, NULL))
+ plogsrv = cstrdup (logsrv);
+ return plogsrv;
+}
+
+const char *
+cygheap_user::env_domain (const char *name, size_t namelen)
+{
+ if (pwinname && test_uid (pdomain, name, namelen))
+ return pdomain;
+
+ char username[UNLEN + 1];
+ DWORD ulen = sizeof (username);
+ char userdomain[DNLEN + 1];
+ DWORD dlen = sizeof (userdomain);
+ SID_NAME_USE use;
+
+ cfree_and_set (pwinname, almost_null);
+ cfree_and_set (pdomain, almost_null);
+ if (!LookupAccountSid (NULL, sid (), username, &ulen,
+ userdomain, &dlen, &use))
+ __seterrno ();
else
{
- return getlogin ();
+ pwinname = cstrdup (username);
+ pdomain = cstrdup (userdomain);
}
+ return pdomain;
+}
+
+const char *
+cygheap_user::env_userprofile (const char *name, size_t namelen)
+{
+ if (test_uid (puserprof, name, namelen))
+ return puserprof;
+
+ char userprofile_env_buf[MAX_PATH + 1];
+ cfree_and_set (puserprof, almost_null);
+ /* FIXME: Should this just be setting a puserprofile like everything else? */
+ const char *myname = winname ();
+ if (myname && strcasematch (myname, "SYSTEM")
+ && get_registry_hive_path (sid (), userprofile_env_buf))
+ puserprof = cstrdup (userprofile_env_buf);
+
+ return puserprof;
+}
+
+const char *
+cygheap_user::env_homepath (const char *name, size_t namelen)
+{
+ return ontherange (CH_HOMEPATH);
+}
+
+const char *
+cygheap_user::env_homedrive (const char *name, size_t namelen)
+{
+ return ontherange (CH_HOMEDRIVE);
+}
+
+const char *
+cygheap_user::env_name (const char *name, size_t namelen)
+{
+ if (!test_uid (pwinname, name, namelen))
+ (void) domain ();
+ return pwinname;
}
diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc
index b73dc970f..de7b9000c 100644
--- a/winsup/cygwin/uname.cc
+++ b/winsup/cygwin/uname.cc
@@ -1,6 +1,6 @@
/* uname.cc
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com
Rewritten by Geoffrey Noer of Cygnus Solutions, noer@cygnus.com
@@ -24,7 +24,7 @@ uname (struct utsname *name)
if (check_null_invalid_struct_errno (name))
return -1;
-
+
char *snp = strstr (cygwin_version.dll_build_date, "SNP");
memset (name, 0, sizeof (*name));
@@ -57,13 +57,23 @@ uname (struct utsname *name)
{
case PROCESSOR_ARCHITECTURE_INTEL:
unsigned int ptype;
- if (sysinfo.dwProcessorType < 3) /* Shouldn't happen. */
- ptype = 3;
- else if (sysinfo.dwProcessorType > 9) /* P4 */
- ptype = 6;
+ if (wincap.has_valid_processorlevel ())
+ {
+ if (sysinfo.wProcessorLevel < 3) /* Shouldn't happen. */
+ ptype = 3;
+ else if (sysinfo.wProcessorLevel > 9) /* P4 */
+ ptype = 6;
+ else
+ ptype = sysinfo.wProcessorLevel;
+ }
else
- ptype = sysinfo.dwProcessorType;
-
+ {
+ if (sysinfo.dwProcessorType == PROCESSOR_INTEL_386 ||
+ sysinfo.dwProcessorType == PROCESSOR_INTEL_486)
+ ptype = sysinfo.dwProcessorType / 100;
+ else
+ ptype = PROCESSOR_INTEL_PENTIUM / 100;
+ }
__small_sprintf (name->machine, "i%d86", ptype);
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
diff --git a/winsup/cygwin/wait.cc b/winsup/cygwin/wait.cc
index 0fa3005cf..d9588e87a 100644
--- a/winsup/cygwin/wait.cc
+++ b/winsup/cygwin/wait.cc
@@ -1,6 +1,6 @@
/* wait.cc: Posix wait routines.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -13,7 +13,6 @@ details. */
#include <stdlib.h>
#include <errno.h>
#include "cygerrno.h"
-#include "sync.h"
#include "sigproc.h"
#include "perthread.h"
diff --git a/winsup/cygwin/winbase.h b/winsup/cygwin/winbase.h
index d72bb0893..15d16a429 100644
--- a/winsup/cygwin/winbase.h
+++ b/winsup/cygwin/winbase.h
@@ -1,5 +1,12 @@
#include_next "winbase.h"
+#ifdef EXPCGF
+#define DECLARE_TLS_STORAGE char **tls[4096] __attribute__ ((unused))
+#else
+#define DECLARE_TLS_STORAGE do {} while (0)
+#define _WINBASE2_H
+#endif
+
#ifndef _WINBASE2_H
#define _WINBASE2_H
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index 4026167ad..01b6660b3 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -1,7 +1,7 @@
/* wincap.cc -- figure out on which OS we're running. Set the
capability class to the appropriate values.
- Copyright 2001 Red Hat, Inc.
+ Copyright 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -22,7 +22,6 @@ static NO_COPY wincaps wincap_unknown = {
has_security:false,
has_security_descriptor_control:false,
has_get_process_times:false,
- has_specific_access_rights:false,
has_lseek_bug:false,
has_lock_file_ex:false,
has_signal_object_and_wait:false,
@@ -43,6 +42,11 @@ static NO_COPY wincaps wincap_unknown = {
has_negative_pids:false,
has_unreliable_pipes:false,
has_try_enter_critical_section:false,
+ has_raw_devices:false,
+ has_valid_processorlevel:false,
+ has_64bit_file_access:false,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:false,
};
static NO_COPY wincaps wincap_95 = {
@@ -56,7 +60,6 @@ static NO_COPY wincaps wincap_95 = {
has_security:false,
has_security_descriptor_control:false,
has_get_process_times:false,
- has_specific_access_rights:false,
has_lseek_bug:true,
has_lock_file_ex:false,
has_signal_object_and_wait:false,
@@ -77,6 +80,11 @@ static NO_COPY wincaps wincap_95 = {
has_negative_pids:true,
has_unreliable_pipes:true,
has_try_enter_critical_section:false,
+ has_raw_devices:false,
+ has_valid_processorlevel:false,
+ has_64bit_file_access:false,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:false,
};
static NO_COPY wincaps wincap_95osr2 = {
@@ -90,7 +98,6 @@ static NO_COPY wincaps wincap_95osr2 = {
has_security:false,
has_security_descriptor_control:false,
has_get_process_times:false,
- has_specific_access_rights:false,
has_lseek_bug:true,
has_lock_file_ex:false,
has_signal_object_and_wait:false,
@@ -111,6 +118,11 @@ static NO_COPY wincaps wincap_95osr2 = {
has_negative_pids:true,
has_unreliable_pipes:true,
has_try_enter_critical_section:false,
+ has_raw_devices:false,
+ has_valid_processorlevel:false,
+ has_64bit_file_access:false,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:false,
};
static NO_COPY wincaps wincap_98 = {
@@ -124,7 +136,6 @@ static NO_COPY wincaps wincap_98 = {
has_security:false,
has_security_descriptor_control:false,
has_get_process_times:false,
- has_specific_access_rights:false,
has_lseek_bug:true,
has_lock_file_ex:false,
has_signal_object_and_wait:false,
@@ -145,6 +156,11 @@ static NO_COPY wincaps wincap_98 = {
has_negative_pids:true,
has_unreliable_pipes:true,
has_try_enter_critical_section:false,
+ has_raw_devices:false,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:false,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:false,
};
static NO_COPY wincaps wincap_98se = {
@@ -158,7 +174,6 @@ static NO_COPY wincaps wincap_98se = {
has_security:false,
has_security_descriptor_control:false,
has_get_process_times:false,
- has_specific_access_rights:false,
has_lseek_bug:true,
has_lock_file_ex:false,
has_signal_object_and_wait:false,
@@ -179,6 +194,11 @@ static NO_COPY wincaps wincap_98se = {
has_negative_pids:true,
has_unreliable_pipes:true,
has_try_enter_critical_section:false,
+ has_raw_devices:false,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:false,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:false,
};
static NO_COPY wincaps wincap_me = {
@@ -192,7 +212,6 @@ static NO_COPY wincaps wincap_me = {
has_security:false,
has_security_descriptor_control:false,
has_get_process_times:false,
- has_specific_access_rights:false,
has_lseek_bug:true,
has_lock_file_ex:false,
has_signal_object_and_wait:false,
@@ -213,6 +232,11 @@ static NO_COPY wincaps wincap_me = {
has_negative_pids:true,
has_unreliable_pipes:true,
has_try_enter_critical_section:false,
+ has_raw_devices:false,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:false,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:false,
};
static NO_COPY wincaps wincap_nt3 = {
@@ -226,7 +250,6 @@ static NO_COPY wincaps wincap_nt3 = {
has_security:true,
has_security_descriptor_control:false,
has_get_process_times:true,
- has_specific_access_rights:true,
has_lseek_bug:false,
has_lock_file_ex:true,
has_signal_object_and_wait:false,
@@ -247,6 +270,11 @@ static NO_COPY wincaps wincap_nt3 = {
has_negative_pids:false,
has_unreliable_pipes:false,
has_try_enter_critical_section:false,
+ has_raw_devices:true,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:true,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:true,
};
static NO_COPY wincaps wincap_nt4 = {
@@ -260,7 +288,6 @@ static NO_COPY wincaps wincap_nt4 = {
has_security:true,
has_security_descriptor_control:false,
has_get_process_times:true,
- has_specific_access_rights:true,
has_lseek_bug:false,
has_lock_file_ex:true,
has_signal_object_and_wait:true,
@@ -281,6 +308,11 @@ static NO_COPY wincaps wincap_nt4 = {
has_negative_pids:false,
has_unreliable_pipes:false,
has_try_enter_critical_section:true,
+ has_raw_devices:true,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:true,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:true,
};
static NO_COPY wincaps wincap_nt4sp4 = {
@@ -294,7 +326,6 @@ static NO_COPY wincaps wincap_nt4sp4 = {
has_security:true,
has_security_descriptor_control:false,
has_get_process_times:true,
- has_specific_access_rights:true,
has_lseek_bug:false,
has_lock_file_ex:true,
has_signal_object_and_wait:true,
@@ -315,6 +346,11 @@ static NO_COPY wincaps wincap_nt4sp4 = {
has_negative_pids:false,
has_unreliable_pipes:false,
has_try_enter_critical_section:true,
+ has_raw_devices:true,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:true,
+ has_process_io_counters:false,
+ supports_reading_modem_output_lines:true,
};
static NO_COPY wincaps wincap_2000 = {
@@ -328,7 +364,6 @@ static NO_COPY wincaps wincap_2000 = {
has_security:true,
has_security_descriptor_control:true,
has_get_process_times:true,
- has_specific_access_rights:true,
has_lseek_bug:false,
has_lock_file_ex:true,
has_signal_object_and_wait:true,
@@ -349,6 +384,11 @@ static NO_COPY wincaps wincap_2000 = {
has_negative_pids:false,
has_unreliable_pipes:false,
has_try_enter_critical_section:true,
+ has_raw_devices:true,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:true,
+ has_process_io_counters:true,
+ supports_reading_modem_output_lines:true,
};
static NO_COPY wincaps wincap_xp = {
@@ -362,7 +402,6 @@ static NO_COPY wincaps wincap_xp = {
has_security:true,
has_security_descriptor_control:true,
has_get_process_times:true,
- has_specific_access_rights:true,
has_lseek_bug:false,
has_lock_file_ex:true,
has_signal_object_and_wait:true,
@@ -383,15 +422,23 @@ static NO_COPY wincaps wincap_xp = {
has_negative_pids:false,
has_unreliable_pipes:false,
has_try_enter_critical_section:true,
+ has_raw_devices:true,
+ has_valid_processorlevel:true,
+ has_64bit_file_access:true,
+ has_process_io_counters:true,
+ supports_reading_modem_output_lines:true,
};
-wincapc NO_COPY wincap;
+wincapc wincap;
void
wincapc::init ()
{
const char *os;
+ if (caps)
+ return; // already initialized
+
memset (&version, 0, sizeof version);
version.dwOSVersionInfoSize = sizeof version;
GetVersionEx (&version);
@@ -408,9 +455,9 @@ wincapc::init ()
case 4:
os = "NT";
if (strcmp (version.szCSDVersion, "Service Pack 4") < 0)
- caps = &wincap_nt4;
+ caps = &wincap_nt4;
else
- caps = &wincap_nt4sp4;
+ caps = &wincap_nt4sp4;
break;
case 5:
os = "NT";
@@ -424,23 +471,23 @@ wincapc::init ()
caps = &wincap_unknown;
break;
}
- break;
+ break;
case VER_PLATFORM_WIN32_WINDOWS:
switch (version.dwMinorVersion)
{
case 0:
os = "95";
- if (strchr(version.szCSDVersion, 'C'))
+ if (strchr (version.szCSDVersion, 'C'))
caps = &wincap_95osr2;
else
caps = &wincap_95;
break;
case 10:
os = "98";
- if (strchr(version.szCSDVersion, 'A'))
- caps = &wincap_98se;
+ if (strchr (version.szCSDVersion, 'A'))
+ caps = &wincap_98se;
else
- caps = &wincap_98;
+ caps = &wincap_98;
break;
case 90:
os = "ME";
@@ -451,9 +498,9 @@ wincapc::init ()
caps = &wincap_unknown;
break;
}
- break;
+ break;
default:
- os = "??";
+ os = "??";
caps = &wincap_unknown;
break;
}
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 038947636..c24b36ae5 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -1,6 +1,6 @@
/* wincap.h: Header for OS capability class.
- Copyright 2001 Red Hat, Inc.
+ Copyright 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -12,7 +12,7 @@ details. */
#define _WINCAP_H
struct wincaps
-{
+{
DWORD lock_file_highword;
DWORD chunksize;
int shared;
@@ -23,7 +23,6 @@ struct wincaps
unsigned has_security : 1;
unsigned has_security_descriptor_control : 1;
unsigned has_get_process_times : 1;
- unsigned has_specific_access_rights : 1;
unsigned has_lseek_bug : 1;
unsigned has_lock_file_ex : 1;
unsigned has_signal_object_and_wait : 1;
@@ -44,6 +43,11 @@ struct wincaps
unsigned has_negative_pids : 1;
unsigned has_unreliable_pipes : 1;
unsigned has_try_enter_critical_section : 1;
+ unsigned has_raw_devices : 1;
+ unsigned has_valid_processorlevel : 1;
+ unsigned has_64bit_file_access : 1;
+ unsigned has_process_io_counters : 1;
+ unsigned supports_reading_modem_output_lines : 1;
};
class wincapc
@@ -56,7 +60,7 @@ public:
void init ();
void set_chunksize (DWORD nchunksize);
-
+
const char *osname () const { return osnam; }
#define IMPLEMENT(cap) cap() const { return ((wincaps *)this->caps)->cap; }
@@ -71,7 +75,6 @@ public:
bool IMPLEMENT (has_security)
bool IMPLEMENT (has_security_descriptor_control)
bool IMPLEMENT (has_get_process_times)
- bool IMPLEMENT (has_specific_access_rights)
bool IMPLEMENT (has_lseek_bug)
bool IMPLEMENT (has_lock_file_ex)
bool IMPLEMENT (has_signal_object_and_wait)
@@ -92,6 +95,11 @@ public:
bool IMPLEMENT (has_negative_pids)
bool IMPLEMENT (has_unreliable_pipes)
bool IMPLEMENT (has_try_enter_critical_section)
+ bool IMPLEMENT (has_raw_devices)
+ bool IMPLEMENT (has_valid_processorlevel)
+ bool IMPLEMENT (has_64bit_file_access)
+ bool IMPLEMENT (has_process_io_counters)
+ bool IMPLEMENT (supports_reading_modem_output_lines)
#undef IMPLEMENT
};
diff --git a/winsup/cygwin/window.cc b/winsup/cygwin/window.cc
index 4567da6a7..7919ab17e 100644
--- a/winsup/cygwin/window.cc
+++ b/winsup/cygwin/window.cc
@@ -1,6 +1,6 @@
/* window.cc: hidden windows for signals/itimer support
- Copyright 1997, 1998, 2000, 2001 Red Hat, Inc.
+ Copyright 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
Written by Sergey Okhapkin <sos@prospect.com.ru>
@@ -18,9 +18,13 @@ details. */
#include <limits.h>
#include <wingdi.h>
#include <winuser.h>
+#define USE_SYS_TYPES_FD_SET
+#include <winsock2.h>
+#include <unistd.h>
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
+#include "cygthread.h"
static NO_COPY UINT timer_active = 0;
static NO_COPY struct itimerval itv;
@@ -60,7 +64,10 @@ WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
return 0;
case WM_ASYNCIO:
- raise (SIGIO);
+ if (WSAGETSELECTEVENT(lParam) == FD_OOB)
+ raise (SIGURG);
+ else
+ raise (SIGIO);
return 0;
default:
return DefWindowProc (hwnd, uMsg, wParam, lParam);
@@ -74,7 +81,7 @@ Winmain (VOID *)
{
MSG msg;
WNDCLASS wc;
- static const NO_COPY char classname[] = "CygwinWndClass";
+ static NO_COPY char classname[] = "CygwinWndClass";
/* Register the window class for the main window. */
@@ -125,19 +132,11 @@ gethwnd ()
if (ourhwnd != NULL)
return ourhwnd;
- HANDLE hThread;
+ cygthread *h;
window_started = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
- hThread = makethread (Winmain, NULL, 0, "win");
- if (!hThread)
- {
- system_printf ("Cannot start window thread");
- }
- else
- {
- SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
- CloseHandle (hThread);
- }
+ h = new cygthread (Winmain, NULL, "win");
+ SetThreadPriority (*h, THREAD_PRIORITY_HIGHEST);
WaitForSingleObject (window_started, INFINITE);
CloseHandle (window_started);
return ourhwnd;
@@ -150,8 +149,7 @@ window_terminate ()
SendMessage (ourhwnd, WM_DESTROY, 0, 0);
}
-extern "C"
-int
+extern "C" int
setitimer (int which, const struct itimerval *value, struct itimerval *oldvalue)
{
UINT elapse;
@@ -195,8 +193,7 @@ setitimer (int which, const struct itimerval *value, struct itimerval *oldvalue)
return 0;
}
-extern "C"
-int
+extern "C" int
getitimer (int which, struct itimerval *value)
{
UINT elapse, val;
@@ -221,27 +218,41 @@ getitimer (int which, struct itimerval *value)
elapse = GetTickCount () - start_time;
val = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000;
val -= elapse;
- value->it_value.tv_sec = val/1000;
- value->it_value.tv_usec = val%1000;
+ value->it_value.tv_sec = val / 1000;
+ value->it_value.tv_usec = val % 1000;
return 0;
}
-extern "C"
-unsigned int
+extern "C" unsigned int
alarm (unsigned int seconds)
{
int ret;
struct itimerval newt, oldt;
- getitimer (ITIMER_REAL, &oldt);
-
newt.it_value.tv_sec = seconds;
newt.it_value.tv_usec = 0;
newt.it_interval.tv_sec = 0;
newt.it_interval.tv_usec = 0;
- setitimer (ITIMER_REAL, &newt, NULL);
+ setitimer (ITIMER_REAL, &newt, &oldt);
ret = oldt.it_value.tv_sec;
if (ret == 0 && oldt.it_value.tv_usec)
ret = 1;
return ret;
}
+
+extern "C" useconds_t
+ualarm (useconds_t value, useconds_t interval)
+{
+ struct itimerval timer, otimer;
+
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = value;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = interval;
+
+ if (setitimer (ITIMER_REAL, &timer, &otimer) < 0)
+ return (u_int)-1;
+
+ return (otimer.it_value.tv_sec * 1000000) + otimer.it_value.tv_usec;
+}
+
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index e40dfb68a..18aaf8a9e 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -1,6 +1,6 @@
/* winsup.h: main Cygwin header file.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
This file is part of Cygwin.
@@ -14,7 +14,6 @@ details. */
#define __INSIDE_CYGWIN__
-#define alloca __builtin_alloca
#define strlen __builtin_strlen
#define strcmp __builtin_strcmp
#define strcpy __builtin_strcpy
@@ -24,7 +23,7 @@ details. */
# define memset __builtin_memset
#endif
-#define NO_COPY __attribute__((section(".data_cygwin_nocopy")))
+#define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy")))
#ifdef __cplusplus
@@ -32,6 +31,10 @@ details. */
#define NEW_MACRO_VARARGS
#endif
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
#include <sys/types.h>
#include <sys/strace.h>
@@ -69,15 +72,18 @@ extern "C" DWORD WINAPI GetLastError (void);
enum codepage_type {ansi_cp, oem_cp};
extern codepage_type current_codepage;
-extern int cygserver_running;
+UINT get_cp ();
+
+int __stdcall sys_wcstombs(char *, const WCHAR *, int)
+ __attribute__ ((regparm(3)));
+
+int __stdcall sys_mbstowcs(WCHAR *, const char *, int)
+ __attribute__ ((regparm(3)));
/* Used to check if Cygwin DLL is dynamically loaded. */
extern int dynamically_loaded;
-#define sys_wcstombs(tgt,src,len) \
- WideCharToMultiByte((current_codepage==ansi_cp?CP_ACP:CP_OEMCP),0,(src),-1,(tgt),(len),NULL,NULL)
-#define sys_mbstowcs(tgt,src,len) \
- MultiByteToWideChar((current_codepage==ansi_cp?CP_ACP:CP_OEMCP),0,(src),-1,(tgt),(len))
+extern int cygserver_running;
#define TITLESIZE 1024
@@ -141,11 +147,25 @@ extern "C" void __stdcall do_exit (int) __attribute__ ((noreturn));
/* UID/GID */
void uinfo_init (void);
+#define ILLEGAL_UID16 ((__uid16_t)-1)
+#define ILLEGAL_UID ((__uid32_t)-1)
+#define ILLEGAL_GID16 ((__gid16_t)-1)
+#define ILLEGAL_GID ((__gid32_t)-1)
+#define ILLEGAL_SEEK ((__off64_t)-1)
+
+#define uid16touid32(u16) ((u16)==ILLEGAL_UID16?ILLEGAL_UID:(__uid32_t)(u16))
+#define gid16togid32(g16) ((g16)==ILLEGAL_GID16?ILLEGAL_GID:(__gid32_t)(g16))
+
+extern "C" __uid32_t getuid32 (void);
+extern "C" __uid32_t geteuid32 (void);
+extern "C" struct passwd *getpwuid32 (__uid32_t);
+
/* various events */
void events_init (void);
void events_terminate (void);
void __stdcall close_all_files (void);
+BOOL __stdcall check_pty_fds (void);
/* Invisible window initialization/termination. */
HWND __stdcall gethwnd (void);
@@ -170,7 +190,7 @@ extern int cygwin_finished_initializing;
void __stdcall set_std_handle (int);
int __stdcall writable_directory (const char *file);
-int __stdcall stat_dev (DWORD, int, unsigned long, struct stat *);
+int __stdcall stat_dev (DWORD, int, unsigned long, struct __stat64 *);
extern BOOL allow_ntsec;
unsigned long __stdcall hash_path_name (unsigned long hash, const char *name) __attribute__ ((regparm(2)));
@@ -186,20 +206,29 @@ extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor
/* Time related */
void __stdcall totimeval (struct timeval *dst, FILETIME * src, int sub, int flag);
long __stdcall to_time_t (FILETIME * ptr);
+void __stdcall to_timestruc_t (FILETIME * ptr, timestruc_t * out);
+void __stdcall time_as_timestruc_t (timestruc_t * out);
void __stdcall set_console_title (char *);
-void set_console_handler ();
+void early_stuff_init ();
+int __stdcall check_null_str (const char *name) __attribute__ ((regparm(1)));
int __stdcall check_null_empty_str (const char *name) __attribute__ ((regparm(1)));
int __stdcall check_null_empty_str_errno (const char *name) __attribute__ ((regparm(1)));
-int __stdcall __check_null_invalid_struct (const void *s, unsigned sz) __attribute__ ((regparm(1)));
-int __stdcall __check_null_invalid_struct_errno (const void *s, unsigned sz) __attribute__ ((regparm(1)));
+int __stdcall check_null_str_errno (const char *name) __attribute__ ((regparm(1)));
+int __stdcall __check_null_invalid_struct (void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_null_invalid_struct_errno (void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_invalid_read_ptr_errno (const void *s, unsigned sz) __attribute__ ((regparm(2)));
#define check_null_invalid_struct(s) \
- __check_null_invalid ((s), sizeof (*(s)))
+ __check_null_invalid_struct ((s), sizeof (*(s)))
#define check_null_invalid_struct_errno(s) \
__check_null_invalid_struct_errno ((s), sizeof (*(s)))
+struct iovec;
+ssize_t check_iovec_for_read (const struct iovec *, int) __attribute__ ((regparm(2)));
+ssize_t check_iovec_for_write (const struct iovec *, int) __attribute__ ((regparm(2)));
+
#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
void __set_winsock_errno (const char *fn, int ln) __attribute__ ((regparm(2)));
@@ -209,12 +238,11 @@ extern bool wsock_started;
extern "C" void __api_fatal (const char *, ...) __attribute__ ((noreturn));
extern "C" int __small_sprintf (char *dst, const char *fmt, ...) /*__attribute__ ((regparm (2)))*/;
extern "C" int __small_vsprintf (char *dst, const char *fmt, va_list ap) /*__attribute__ ((regparm (3)))*/;
+extern void multiple_cygwin_problem (const char *, unsigned, unsigned);
-extern "C" void __malloc_lock (struct _reent *);
-extern "C" void __malloc_unlock (struct _reent *);
-
-extern "C" void __malloc_lock (struct _reent *);
-extern "C" void __malloc_unlock (struct _reent *);
+class path_conv;
+int __stdcall stat_worker (const char *name, struct __stat64 *buf, int nofollow,
+ path_conv *pc = NULL) __attribute__ ((regparm (3)));
/**************************** Exports ******************************/
@@ -250,6 +278,9 @@ extern SYSTEM_INFO system_info;
#define STD_RBITS (S_IRUSR | S_IRGRP | S_IROTH)
#define STD_WBITS (S_IWUSR)
#define STD_XBITS (S_IXUSR | S_IXGRP | S_IXOTH)
+#define NO_W ~(S_IWUSR | S_IWGRP | S_IWOTH)
+#define NO_R ~(S_IRUSR | S_IRGRP | S_IROTH)
+#define NO_X ~(S_IXUSR | S_IXGRP | S_IXOTH)
/* The title on program start. */
extern char *old_title;
@@ -258,4 +289,14 @@ extern BOOL display_title;
extern HANDLE hMainThread;
extern HANDLE hMainProc;
+extern bool cygwin_testing;
+extern unsigned _cygwin_testing_magic;
+extern HMODULE cygwin_hmodule;
+
+extern char almost_null[];
+
+#define winsock2_active (wsadata.wVersion >= 512)
+#define winsock_active (wsadata.wVersion < 512)
+extern struct WSAData wsadata;
+
#endif /* defined __cplusplus */
diff --git a/winsup/cygwin/winver.rc b/winsup/cygwin/winver.rc
index 02eb45a3c..6a265cbd7 100644
--- a/winsup/cygwin/winver.rc
+++ b/winsup/cygwin/winver.rc
@@ -36,7 +36,7 @@ BEGIN
VALUE "FileDescription", "Cygwin\256 POSIX Emulation DLL"
VALUE "FileVersion", STRINGIFY(CYGWIN_VERSION)
VALUE "InternalName", CYGWIN_DLL_NAME
- VALUE "LegalCopyright", "Copyright \251 Red Hat. 1996-2001"
+ VALUE "LegalCopyright", "Copyright \251 Red Hat, Inc. 1996-2002"
VALUE "OriginalFilename", CYGWIN_DLL_NAME
VALUE "ProductName", "Cygwin"
VALUE "ProductVersion", STRINGIFY(CYGWIN_VERSION)
diff --git a/winsup/cygwin/woutsup.h b/winsup/cygwin/woutsup.h
new file mode 100644
index 000000000..c048f1c19
--- /dev/null
+++ b/winsup/cygwin/woutsup.h
@@ -0,0 +1,110 @@
+/* woutsup.h: for Cygwin code compiled outside the DLL (i.e. cygserver).
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef __INSIDE_CYGWIN__
+#error "woutsup.h is not for code being compiled inside the dll"
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#if _WIN32_WINNT < 0x0500
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#define _WINGDI_H
+#define _WINUSER_H
+#define _WINNLS_H
+#define _WINVER_H
+#define _WINNETWK_H
+#define _WINSVC_H
+#include <windows.h>
+#include <wincrypt.h>
+#include <lmcons.h>
+#undef _WINGDI_H
+#undef _WINUSER_H
+#undef _WINNLS_H
+#undef _WINVER_H
+#undef _WINNETWK_H
+#undef _WINSVC_H
+
+#include "wincap.h"
+
+/* The one function we use from winuser.h most of the time */
+extern "C" DWORD WINAPI GetLastError (void);
+
+extern int cygserver_running;
+
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
+#define NEW_MACRO_VARARGS
+#endif
+
+/*
+ * A reproduction of the <sys/strace.h> macros. This allows code that
+ * runs both inside and outside the Cygwin DLL to use the same macros
+ * for logging messages.
+ */
+
+extern "C" void __cygserver__printf (const char *, const char *, ...);
+
+#ifdef NEW_MACRO_VARARGS
+
+#define system_printf(...) \
+ do \
+ { \
+ __cygserver__printf (__PRETTY_FUNCTION__, __VA_ARGS__); \
+ } while (false)
+
+#define __noop_printf(...) do {;} while (false)
+
+#else /* !NEW_MACRO_VARARGS */
+
+#define system_printf(args...) \
+ do \
+ { \
+ __cygserver__printf (__PRETTY_FUNCTION__, ## args); \
+ } while (false)
+
+#define __noop_printf(args...) do {;} while (false)
+
+#endif /* !NEW_MACRO_VARARGS */
+
+#ifdef DEBUGGING
+#define debug_printf system_printf
+#define paranoid_printf system_printf
+#define select_printf system_printf
+#define sigproc_printf system_printf
+#define syscall_printf system_printf
+#define termios_printf system_printf
+#define wm_printf system_printf
+#define minimal_printf system_printf
+#define malloc_printf system_printf
+#define thread_printf system_printf
+#else
+#define debug_printf __noop_printf
+#define paranoid_printf __noop_printf
+#define select_printf __noop_printf
+#define sigproc_printf __noop_printf
+#define syscall_printf __noop_printf
+#define termios_printf __noop_printf
+#define wm_printf __noop_printf
+#define minimal_printf __noop_printf
+#define malloc_printf __noop_printf
+#define thread_printf __noop_printf
+#endif
+
+#include "safe_memory.h"
diff --git a/winsup/cygwin/wsock_event.h b/winsup/cygwin/wsock_event.h
new file mode 100644
index 000000000..3f8638134
--- /dev/null
+++ b/winsup/cygwin/wsock_event.h
@@ -0,0 +1,32 @@
+/* wsock_event.h: Defining the wsock_event class
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef __WSOCK_EVENT_H__
+#define __WSOCK_EVENT_H__
+
+class wsock_event
+{
+ WSAEVENT event;
+ WSAOVERLAPPED ovr;
+public:
+ wsock_event () : event (NULL) {};
+ ~wsock_event ()
+ {
+ if (event)
+ WSACloseEvent (event);
+ event = NULL;
+ };
+
+ /* The methods are implemented in net.cc */
+ LPWSAOVERLAPPED prepare ();
+ int wait (int socket, LPDWORD flags);
+};
+
+#endif /* __WSOCK_EVENT_H__ */