X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/32e93c9e89c603462c230e10f46c525eb392e668..6d81466ac65eb84cb77eaa73e589628b5afcb963:/src/w32.c diff --git a/src/w32.c b/src/w32.c index e548864211..aba0b5a81f 100644 --- a/src/w32.c +++ b/src/w32.c @@ -1,5 +1,6 @@ /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API. - Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc. + +Copyright (C) 1994-1995, 2000-2014 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -140,6 +141,7 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { #include #include +#include /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we define them by hand if not already defined. */ @@ -301,6 +303,8 @@ static BOOL g_b_init_convert_sddl_to_sd; static BOOL g_b_init_is_valid_security_descriptor; static BOOL g_b_init_set_file_security_w; static BOOL g_b_init_set_file_security_a; +static BOOL g_b_init_set_named_security_info_w; +static BOOL g_b_init_set_named_security_info_a; static BOOL g_b_init_get_adapters_info; /* @@ -375,6 +379,22 @@ typedef BOOL (WINAPI *SetFileSecurityA_Proc) ( LPCSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor); +typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) ( + LPCWSTR lpObjectName, + SE_OBJECT_TYPE ObjectType, + SECURITY_INFORMATION SecurityInformation, + PSID psidOwner, + PSID psidGroup, + PACL pDacl, + PACL pSacl); +typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) ( + LPCSTR lpObjectName, + SE_OBJECT_TYPE ObjectType, + SECURITY_INFORMATION SecurityInformation, + PSID psidOwner, + PSID psidGroup, + PACL pDacl, + PACL pSacl); typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) ( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pOwner, @@ -458,6 +478,9 @@ typedef DWORD (WINAPI *GetAdaptersInfo_Proc) ( PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); +int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int); +int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); + /* ** A utility function ** */ static BOOL is_windows_9x (void) @@ -809,6 +832,69 @@ set_file_security (const char *lpFileName, } } +static DWORD WINAPI +set_named_security_info (LPCTSTR lpObjectName, + SE_OBJECT_TYPE ObjectType, + SECURITY_INFORMATION SecurityInformation, + PSID psidOwner, + PSID psidGroup, + PACL pDacl, + PACL pSacl) +{ + static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL; + static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + errno = ENOTSUP; + return ENOTSUP; + } + if (w32_unicode_filenames) + { + wchar_t filename_w[MAX_PATH]; + + if (g_b_init_set_named_security_info_w == 0) + { + g_b_init_set_named_security_info_w = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Set_Named_Security_InfoW = + (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32, + "SetNamedSecurityInfoW"); + } + if (s_pfn_Set_Named_Security_InfoW == NULL) + { + errno = ENOTSUP; + return ENOTSUP; + } + filename_to_utf16 (lpObjectName, filename_w); + return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType, + SecurityInformation, psidOwner, + psidGroup, pDacl, pSacl)); + } + else + { + char filename_a[MAX_PATH]; + + if (g_b_init_set_named_security_info_a == 0) + { + g_b_init_set_named_security_info_a = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Set_Named_Security_InfoA = + (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32, + "SetNamedSecurityInfoA"); + } + if (s_pfn_Set_Named_Security_InfoA == NULL) + { + errno = ENOTSUP; + return ENOTSUP; + } + filename_to_ansi (lpObjectName, filename_a); + return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType, + SecurityInformation, psidOwner, + psidGroup, pDacl, pSacl)); + } +} + static BOOL WINAPI get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pOwner, @@ -1322,7 +1408,7 @@ w32_valid_pointer_p (void *p, int size) conversion back and forth from UTF-8 to UTF-16, then don't: first, it was measured to take only a few microseconds on a not-so-fast machine, and second, that's exactly what the ANSI APIs we used - before do anyway, because they are just thin wrappers around the + before did anyway, because they are just thin wrappers around the Unicode APIs.) The variables file-name-coding-system and default-file-name-coding-system @@ -1349,8 +1435,8 @@ w32_valid_pointer_p (void *p, int size) For the same reasons, no CRT function or Win32 API can be called directly in Emacs sources, without either converting the file - name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going - through some shadowing function defined here. + names from UTF-8 to UTF-16 or ANSI codepage, or going through + some shadowing function defined here. . Environment variables stored in Vprocess_environment are encoded in the ANSI codepage, so if getenv/egetenv is used for a variable @@ -1371,7 +1457,7 @@ w32_valid_pointer_p (void *p, int size) . Running subprocesses in non-ASCII directories and with non-ASCII file arguments is limited to the current codepage (even though Emacs is perfectly capable of finding an executable program file - even in a directory whose name cannot be encoded in the current + in a directory whose name cannot be encoded in the current codepage). This is because the command-line arguments are encoded _before_ they get to the w32-specific level, and the encoding is not known in advance (it doesn't have to be the @@ -1389,8 +1475,8 @@ w32_valid_pointer_p (void *p, int size) the current codepage. . Turning on w32-unicode-filename on Windows 9X (if it at all - works) requires UNICOWS.DLL, which is currently loaded only in a - GUI session. */ + works) requires UNICOWS.DLL, which is thus a requirement even in + non-GUI sessions, something the we previously avoided. */ @@ -1460,8 +1546,8 @@ codepage_for_filenames (CPINFO *cp_info) int filename_to_utf16 (const char *fn_in, wchar_t *fn_out) { - int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1, - fn_out, MAX_PATH); + int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1, + fn_out, MAX_PATH); if (!result) { @@ -1487,8 +1573,8 @@ filename_to_utf16 (const char *fn_in, wchar_t *fn_out) int filename_from_utf16 (const wchar_t *fn_in, char *fn_out) { - int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1, - fn_out, MAX_UTF8_PATH, NULL, NULL); + int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1, + fn_out, MAX_UTF8_PATH, NULL, NULL); if (!result) { @@ -1521,8 +1607,8 @@ filename_to_ansi (const char *fn_in, char *fn_out) int result; int codepage = codepage_for_filenames (NULL); - result = WideCharToMultiByte (codepage, 0, fn_utf16, -1, - fn_out, MAX_PATH, NULL, NULL); + result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1, + fn_out, MAX_PATH, NULL, NULL); if (!result) { DWORD err = GetLastError (); @@ -1551,8 +1637,8 @@ filename_from_ansi (const char *fn_in, char *fn_out) { wchar_t fn_utf16[MAX_PATH]; int codepage = codepage_for_filenames (NULL); - int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1, - fn_utf16, MAX_PATH); + int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1, + fn_utf16, MAX_PATH); if (!result) { @@ -1731,9 +1817,28 @@ getloadavg (double loadavg[], int nelem) ULONGLONG idle, kernel, user; time_t now = time (NULL); + /* If system time jumped back for some reason, delete all samples + whose time is later than the current wall-clock time. This + prevents load average figures from becoming frozen for prolonged + periods of time, when system time is reset backwards. */ + if (last_idx >= 0) + { + while (difftime (now, samples[last_idx].sample_time) < -1.0) + { + if (last_idx == first_idx) + { + first_idx = last_idx = -1; + break; + } + last_idx = buf_prev (last_idx); + } + } + /* Store another sample. We ignore samples that are less than 1 sec apart. */ - if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now) + if (last_idx < 0 + || (difftime (now, samples[last_idx].sample_time) + >= 1.0 - 2*DBL_EPSILON*now)) { sample_system_load (&idle, &kernel, &user); last_idx = buf_next (last_idx); @@ -2282,6 +2387,8 @@ ansi_encode_filename (Lisp_Object filename) dostounix_filename (shortname); encoded_filename = build_string (shortname); } + else + encoded_filename = build_unibyte_string (fname); } else encoded_filename = build_unibyte_string (fname); @@ -3931,8 +4038,8 @@ sys_link (const char * old, const char * new) /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN indicates that flag is unsupported for CP_UTF8, and OTOH says it is the default anyway. */ - wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1, - data.wid.cStreamName, MAX_PATH); + wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1, + data.wid.cStreamName, MAX_PATH); if (wlen > 0) { LPVOID context = NULL; @@ -4640,10 +4747,9 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) return -1; } - /* Remove trailing directory separator, unless name is the root - directory of a drive or UNC volume in which case ensure there - is a trailing separator. */ len = strlen (name); + /* Allocate 1 extra byte so that we could append a slash to a root + directory, down below. */ name = strcpy (alloca (len + 2), name); /* Avoid a somewhat costly call to is_symlink if the filesystem @@ -4858,6 +4964,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) } else if (rootdir) { + /* Make sure root directories end in a slash. */ if (!IS_DIRECTORY_SEP (name[len-1])) strcat (name, "\\"); if (GetDriveType (name) < 2) @@ -4873,6 +4980,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) { int have_wfd = -1; + /* Make sure non-root directories do NOT end in a slash, + otherwise FindFirstFile might fail. */ if (IS_DIRECTORY_SEP (name[len-1])) name[len - 1] = 0; @@ -5033,7 +5142,10 @@ fstatat (int fd, char const *name, struct stat *st, int flags) if (fd != AT_FDCWD) { - if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) + char lastc = dir_pathname[strlen (dir_pathname) - 1]; + + if (_snprintf (fullname, sizeof fullname, "%s%s%s", + dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name) < 0) { errno = ENAMETOOLONG; @@ -5244,6 +5356,30 @@ utime (const char *name, struct utimbuf *times) return 0; } +int +sys_umask (int mode) +{ + static int current_mask; + int retval, arg = 0; + + /* The only bit we really support is the write bit. Files are + always readable on MS-Windows, and the execute bit does not exist + at all. */ + /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs + to prevent access by other users on NTFS. */ + if ((mode & S_IWRITE) != 0) + arg |= S_IWRITE; + + retval = _umask (arg); + /* Merge into the return value the bits they've set the last time, + which msvcrt.dll ignores and never returns. Emacs insists on its + notion of mask being identical to what we return. */ + retval |= (current_mask & ~S_IWRITE); + current_mask = mode; + + return retval; +} + /* Symlink-related functions. */ #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY @@ -5853,7 +5989,7 @@ acl_set_file (const char *fname, acl_type_t type, acl_t acl) DWORD err; int st = 0, retval = -1; SECURITY_INFORMATION flags = 0; - PSID psid; + PSID psidOwner, psidGroup; PACL pacl; BOOL dflt; BOOL dacl_present; @@ -5879,11 +6015,13 @@ acl_set_file (const char *fname, acl_type_t type, acl_t acl) else fname = filename; - if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt) - && psid) + if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner, + &dflt) + && psidOwner) flags |= OWNER_SECURITY_INFORMATION; - if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt) - && psid) + if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup, + &dflt) + && psidGroup) flags |= GROUP_SECURITY_INFORMATION; if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present, &pacl, &dflt) @@ -5910,10 +6048,22 @@ acl_set_file (const char *fname, acl_type_t type, acl_t acl) e = errno; errno = 0; + /* SetFileSecurity is deprecated by MS, and sometimes fails when + DACL inheritance is involved, but it seems to preserve ownership + better than SetNamedSecurityInfo, which is important e.g., in + copy-file. */ if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl)) { err = GetLastError (); + if (errno != ENOTSUP) + err = set_named_security_info (fname, SE_FILE_OBJECT, flags, + psidOwner, psidGroup, pacl, NULL); + } + else + err = ERROR_SUCCESS; + if (err != ERROR_SUCCESS) + { if (errno == ENOTSUP) ; else if (err == ERROR_INVALID_OWNER @@ -6001,6 +6151,116 @@ careadlinkat (int fd, char const *filename, return NULL; } +int +w32_copy_file (const char *from, const char *to, + int keep_time, int preserve_ownership, int copy_acls) +{ + acl_t acl = NULL; + BOOL copy_result; + wchar_t from_w[MAX_PATH], to_w[MAX_PATH]; + char from_a[MAX_PATH], to_a[MAX_PATH]; + + /* We ignore preserve_ownership for now. */ + preserve_ownership = preserve_ownership; + + if (copy_acls) + { + acl = acl_get_file (from, ACL_TYPE_ACCESS); + if (acl == NULL && acl_errno_valid (errno)) + return -2; + } + if (w32_unicode_filenames) + { + filename_to_utf16 (from, from_w); + filename_to_utf16 (to, to_w); + copy_result = CopyFileW (from_w, to_w, FALSE); + } + else + { + filename_to_ansi (from, from_a); + filename_to_ansi (to, to_a); + copy_result = CopyFileA (from_a, to_a, FALSE); + } + if (!copy_result) + { + /* CopyFile doesn't set errno when it fails. By far the most + "popular" reason is that the target is read-only. */ + DWORD err = GetLastError (); + + switch (err) + { + case ERROR_FILE_NOT_FOUND: + errno = ENOENT; + break; + case ERROR_ACCESS_DENIED: + errno = EACCES; + break; + case ERROR_ENCRYPTION_FAILED: + errno = EIO; + break; + default: + errno = EPERM; + break; + } + + if (acl) + acl_free (acl); + return -1; + } + /* CopyFile retains the timestamp by default. However, see + "Community Additions" for CopyFile: it sounds like that is not + entirely true. Testing on Windows XP confirms that modified time + is copied, but creation and last-access times are not. + FIXME? */ + else if (!keep_time) + { + struct timespec now; + DWORD attributes; + + if (w32_unicode_filenames) + { + /* Ensure file is writable while its times are set. */ + attributes = GetFileAttributesW (to_w); + SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY); + now = current_timespec (); + if (set_file_times (-1, to, now, now)) + { + /* Restore original attributes. */ + SetFileAttributesW (to_w, attributes); + if (acl) + acl_free (acl); + return -3; + } + /* Restore original attributes. */ + SetFileAttributesW (to_w, attributes); + } + else + { + attributes = GetFileAttributesA (to_a); + SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY); + now = current_timespec (); + if (set_file_times (-1, to, now, now)) + { + SetFileAttributesA (to_a, attributes); + if (acl) + acl_free (acl); + return -3; + } + SetFileAttributesA (to_a, attributes); + } + } + if (acl != NULL) + { + bool fail = + acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0; + acl_free (acl); + if (fail && acl_errno_valid (errno)) + return -4; + } + + return 0; +} + /* Support for browsing other processes and their attributes. See process.c for the Lisp bindings. */ @@ -7430,15 +7690,15 @@ fcntl (int s, int cmd, int options) if (cmd == F_DUPFD_CLOEXEC) return sys_dup (s); - if (winsock_lib == NULL) - { - errno = ENETDOWN; - return -1; - } - check_errno (); if (fd_info[s].flags & FILE_SOCKET) { + if (winsock_lib == NULL) + { + errno = ENETDOWN; + return -1; + } + if (cmd == F_SETFL && options == O_NONBLOCK) { unsigned long nblock = 1; @@ -7455,13 +7715,36 @@ fcntl (int s, int cmd, int options) return SOCKET_ERROR; } } + else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE)) + == (FILE_PIPE | FILE_WRITE)) + { + /* Force our writes to pipes be non-blocking. */ + if (cmd == F_SETFL && options == O_NONBLOCK) + { + HANDLE h = (HANDLE)_get_osfhandle (s); + DWORD pipe_mode = PIPE_NOWAIT; + + if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL)) + { + DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ())); + return SOCKET_ERROR; + } + fd_info[s].flags |= FILE_NDELAY; + return 0; + } + else + { + errno = EINVAL; + return SOCKET_ERROR; + } + } errno = ENOTSOCK; return SOCKET_ERROR; } /* Shadow main io functions: we need to handle pipes and sockets more - intelligently, and implement non-blocking mode as well. */ + intelligently. */ int sys_close (int fd) @@ -7946,7 +8229,6 @@ sys_read (int fd, char * buffer, unsigned int count) /* From w32xfns.c */ extern HANDLE interrupt_handle; -/* For now, don't bother with a non-blocking mode */ int sys_write (int fd, const void * buffer, unsigned int count) { @@ -8081,6 +8363,22 @@ sys_write (int fd, const void * buffer, unsigned int count) nchars += n; if (n < 0) { + /* When there's no buffer space in a pipe that is in the + non-blocking mode, _write returns ENOSPC. We return + EAGAIN instead, which should trigger the logic in + send_process that enters waiting loop and calls + wait_reading_process_output to allow process input to + be accepted during the wait. Those calls to + wait_reading_process_output allow sys_select to + notice when process input becomes available, thus + avoiding deadlock whereby each side of the pipe is + blocked on write, waiting for the other party to read + its end of the pipe. */ + if (errno == ENOSPC + && fd < MAXDESC + && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY)) + == (FILE_PIPE | FILE_NDELAY))) + errno = EAGAIN; nchars = n; break; } @@ -8353,6 +8651,7 @@ network_interface_list (void) Lisp_Object network_interface_info (Lisp_Object ifname) { + CHECK_STRING (ifname); return network_interface_get_info (ifname); } @@ -8472,7 +8771,7 @@ check_windows_init_file (void) need to ENCODE_FILE here, but we do need to convert the file names from UTF-8 to ANSI. */ init_file = build_string ("term/w32-win"); - fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil); + fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0); if (fd < 0) { Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil); @@ -8494,22 +8793,22 @@ check_windows_init_file (void) "not unpacked properly.\nSee the README.W32 file in the " "top-level Emacs directory for more information.", init_file_name, load_path); - needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, - -1, NULL, 0); + needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, + -1, NULL, 0); if (needed > 0) { wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t)); - MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1, - msg_w, needed); - needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1, - NULL, 0, NULL, NULL); + pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1, + msg_w, needed); + needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, + NULL, 0, NULL, NULL); if (needed > 0) { char *msg_a = alloca (needed + 1); - WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed, - NULL, NULL); + pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed, + NULL, NULL); msg = msg_a; } } @@ -8668,6 +8967,57 @@ shutdown_handler (DWORD type) return FALSE; } +/* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On + NT, return a handle to GDI32.DLL. */ +HANDLE +maybe_load_unicows_dll (void) +{ + if (os_subtype == OS_9X) + { + HANDLE ret = LoadLibrary ("Unicows.dll"); + if (ret) + { + /* These two functions are present on Windows 9X as stubs + that always fail. We need the real implementations from + UNICOWS.DLL, so we must call these functions through + pointers, and assign the correct addresses to these + pointers at program startup (see emacs.c, which calls + this function early on). */ + pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar"); + pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte"); + return ret; + } + else + { + int button; + + button = MessageBox (NULL, + "Emacs cannot load the UNICOWS.DLL library.\n" + "This library is essential for using Emacs\n" + "on this system. You need to install it.\n\n" + "Emacs will exit when you click OK.", + "Emacs cannot load UNICOWS.DLL", + MB_ICONERROR | MB_TASKMODAL + | MB_SETFOREGROUND | MB_OK); + switch (button) + { + case IDOK: + default: + exit (1); + } + } + } + else + { + /* On NT family of Windows, these two functions are always + linked in, so we just assign their addresses to the 2 + pointers; no need for the LoadLibrary dance. */ + pMultiByteToWideChar = MultiByteToWideChar; + pWideCharToMultiByte = WideCharToMultiByte; + return LoadLibrary ("Gdi32.dll"); + } +} + /* globals_of_w32 is used to initialize those global variables that must always be initialized on startup even when the global variable @@ -8718,6 +9068,8 @@ globals_of_w32 (void) g_b_init_is_valid_security_descriptor = 0; g_b_init_set_file_security_w = 0; g_b_init_set_file_security_a = 0; + g_b_init_set_named_security_info_w = 0; + g_b_init_set_named_security_info_a = 0; g_b_init_get_adapters_info = 0; num_of_processors = 0; /* The following sets a handler for shutdown notifications for