2000-09-03 12:16:35 +08:00
|
|
|
/* cygheap.h: Cygwin heap manager.
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
2005-11-05 04:45:56 +08:00
|
|
|
#include "hires.h"
|
2009-08-02 03:52:46 +08:00
|
|
|
#include "cygheap_malloc.h"
|
2014-02-10 03:44:56 +08:00
|
|
|
#include "pwdgrp.h"
|
2000-09-03 12:16:35 +08:00
|
|
|
|
2000-10-02 10:26:04 +08:00
|
|
|
#define incygheap(s) (cygheap && ((char *) (s) >= (char *) cygheap) && ((char *) (s) <= ((char *) cygheap_max)))
|
2000-09-03 12:16:35 +08:00
|
|
|
|
2000-11-14 13:53:32 +08:00
|
|
|
struct _cmalloc_entry
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
2013-04-23 17:44:36 +08:00
|
|
|
unsigned b;
|
2000-11-14 13:53:32 +08:00
|
|
|
char *ptr;
|
|
|
|
};
|
|
|
|
struct _cmalloc_entry *prev;
|
|
|
|
char data[0];
|
|
|
|
};
|
|
|
|
|
2001-06-03 10:31:16 +08:00
|
|
|
struct cygheap_root_mount_info
|
|
|
|
{
|
2003-11-15 07:40:06 +08:00
|
|
|
char posix_path[CYG_MAX_PATH];
|
2001-06-03 10:31:16 +08:00
|
|
|
unsigned posix_pathlen;
|
2003-11-15 07:40:06 +08:00
|
|
|
char native_path[CYG_MAX_PATH];
|
2001-06-03 10:31:16 +08:00
|
|
|
unsigned native_pathlen;
|
2008-07-17 04:20:45 +08:00
|
|
|
bool caseinsensitive;
|
2001-06-03 10:31:16 +08:00
|
|
|
};
|
|
|
|
|
2001-06-04 09:28:09 +08:00
|
|
|
/* CGF: FIXME This doesn't belong here */
|
|
|
|
|
2000-11-15 08:13:09 +08:00
|
|
|
class cygheap_root
|
|
|
|
{
|
|
|
|
/* Root directory information.
|
|
|
|
This is used after a chroot is called. */
|
2001-06-03 10:31:16 +08:00
|
|
|
struct cygheap_root_mount_info *m;
|
|
|
|
|
2000-11-15 08:13:09 +08:00
|
|
|
public:
|
2001-06-03 10:31:16 +08:00
|
|
|
bool posix_ok (const char *path)
|
|
|
|
{
|
|
|
|
if (!m)
|
|
|
|
return 1;
|
2008-07-17 04:20:45 +08:00
|
|
|
return path_prefix_p (m->posix_path, path, m->posix_pathlen,
|
|
|
|
m->caseinsensitive);
|
2001-06-03 10:31:16 +08:00
|
|
|
}
|
|
|
|
bool ischroot_native (const char *path)
|
|
|
|
{
|
|
|
|
if (!m)
|
|
|
|
return 1;
|
|
|
|
return strncasematch (m->native_path, path, m->native_pathlen)
|
2001-09-08 05:32:07 +08:00
|
|
|
&& (path[m->native_pathlen] == '\\' || !path[m->native_pathlen]);
|
2001-06-03 10:31:16 +08:00
|
|
|
}
|
|
|
|
const char *unchroot (const char *path)
|
|
|
|
{
|
|
|
|
if (!m)
|
|
|
|
return path;
|
|
|
|
const char *p = path + m->posix_pathlen;
|
|
|
|
if (!*p)
|
|
|
|
p = "/";
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
bool exists () {return !!m;}
|
2008-07-17 04:20:45 +08:00
|
|
|
void set (const char *, const char *, bool);
|
2001-06-03 10:31:16 +08:00
|
|
|
size_t posix_length () const { return m->posix_pathlen; }
|
|
|
|
const char *posix_path () const { return m->posix_path; }
|
|
|
|
size_t native_length () const { return m->native_pathlen; }
|
|
|
|
const char *native_path () const { return m->native_path; }
|
2000-11-15 08:13:09 +08:00
|
|
|
};
|
|
|
|
|
2002-06-12 13:13:54 +08:00
|
|
|
enum homebodies
|
|
|
|
{
|
|
|
|
CH_HOMEDRIVE,
|
|
|
|
CH_HOMEPATH,
|
|
|
|
CH_HOME
|
|
|
|
};
|
|
|
|
|
2001-01-17 22:57:09 +08:00
|
|
|
class cygheap_user
|
|
|
|
{
|
2000-11-15 08:13:09 +08:00
|
|
|
/* Extendend user information.
|
|
|
|
The information is derived from the internal_getlogin call
|
|
|
|
when on a NT system. */
|
2009-07-01 05:18:44 +08:00
|
|
|
char *pname; /* user's name */
|
2000-11-16 05:04:02 +08:00
|
|
|
char *plogsrv; /* Logon server, may be FQDN */
|
|
|
|
char *pdomain; /* Logon domain of the user */
|
2002-06-12 13:13:54 +08:00
|
|
|
char *homedrive; /* User's home drive */
|
|
|
|
char *homepath; /* User's home path */
|
2004-10-08 05:28:57 +08:00
|
|
|
char *psystemroot; /* Value of SYSTEMROOT */
|
2002-06-29 10:36:08 +08:00
|
|
|
char *pwinname; /* User's name as far as Windows knows it */
|
2002-06-28 04:44:27 +08:00
|
|
|
char *puserprof; /* User profile */
|
2003-09-27 09:56:36 +08:00
|
|
|
cygsid effec_cygsid; /* buffer for user's SID */
|
|
|
|
cygsid saved_cygsid; /* Remains intact even after impersonation */
|
2000-11-15 08:13:09 +08:00
|
|
|
public:
|
2013-04-23 17:44:36 +08:00
|
|
|
uid_t saved_uid; /* Remains intact even after impersonation */
|
|
|
|
gid_t saved_gid; /* Ditto */
|
|
|
|
uid_t real_uid; /* Remains intact on seteuid, replaced by setuid */
|
|
|
|
gid_t real_gid; /* Ditto */
|
|
|
|
user_groups groups; /* Primary and supp SIDs */
|
2000-11-15 08:13:09 +08:00
|
|
|
|
2000-11-16 05:04:02 +08:00
|
|
|
/* token is needed if set(e)uid should be called. It can be set by a call
|
|
|
|
to `set_impersonation_token()'. */
|
2003-06-30 21:07:36 +08:00
|
|
|
HANDLE external_token;
|
|
|
|
HANDLE internal_token;
|
2005-04-03 21:06:43 +08:00
|
|
|
HANDLE curr_primary_token;
|
2007-07-17 04:01:15 +08:00
|
|
|
HANDLE curr_imp_token;
|
2009-10-13 18:23:31 +08:00
|
|
|
bool ext_token_is_restricted; /* external_token is restricted token */
|
|
|
|
bool curr_token_is_restricted; /* curr_primary_token is restricted token */
|
|
|
|
bool setuid_to_restricted; /* switch to restricted token by setuid () */
|
2000-11-16 05:04:02 +08:00
|
|
|
|
2002-06-28 04:44:27 +08:00
|
|
|
/* 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,
|
2003-12-08 06:37:12 +08:00
|
|
|
I've removed the constructor entirely. Please reinstate this if this
|
2002-06-28 04:44:27 +08:00
|
|
|
situation ever changes.
|
2001-06-04 22:29:54 +08:00
|
|
|
cygheap_user () : pname (NULL), plogsrv (NULL), pdomain (NULL),
|
2003-09-16 17:24:52 +08:00
|
|
|
homedrive (NULL), homepath (NULL),
|
2002-06-28 04:44:27 +08:00
|
|
|
token (INVALID_HANDLE_VALUE) {}
|
|
|
|
*/
|
|
|
|
|
2000-11-15 08:13:09 +08:00
|
|
|
~cygheap_user ();
|
|
|
|
|
2003-09-11 05:01:40 +08:00
|
|
|
void init ();
|
2000-11-15 08:13:09 +08:00
|
|
|
void set_name (const char *new_name);
|
|
|
|
const char *name () const { return pname; }
|
|
|
|
|
2002-06-29 10:36:08 +08:00
|
|
|
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);
|
2004-10-08 05:28:57 +08:00
|
|
|
const char *env_systemroot (const char *, size_t);
|
2000-11-15 08:13:09 +08:00
|
|
|
|
2002-06-29 10:36:08 +08:00
|
|
|
const char *logsrv ()
|
|
|
|
{
|
2002-06-30 06:05:30 +08:00
|
|
|
const char *p = env_logsrv ("LOGONSERVER=", sizeof ("LOGONSERVER=") - 1);
|
|
|
|
return (p == almost_null) ? NULL : p;
|
2002-06-29 10:36:08 +08:00
|
|
|
}
|
|
|
|
const char *winname ()
|
|
|
|
{
|
2002-06-30 06:05:30 +08:00
|
|
|
const char *p = env_name ("USERNAME=", sizeof ("USERNAME=") - 1);
|
|
|
|
return (p == almost_null) ? NULL : p;
|
2002-06-29 10:36:08 +08:00
|
|
|
}
|
|
|
|
const char *domain ()
|
|
|
|
{
|
2002-06-30 06:05:30 +08:00
|
|
|
const char *p = env_domain ("USERDOMAIN=", sizeof ("USERDOMAIN=") - 1);
|
|
|
|
return (p == almost_null) ? NULL : p;
|
2002-06-29 10:36:08 +08:00
|
|
|
}
|
2013-04-23 17:44:36 +08:00
|
|
|
void set_sid (PSID new_sid) { effec_cygsid = new_sid;}
|
|
|
|
void set_saved_sid () { saved_cygsid = effec_cygsid; }
|
2014-02-28 19:37:02 +08:00
|
|
|
cygpsid &sid () { return effec_cygsid; }
|
|
|
|
cygpsid &saved_sid () { return saved_cygsid; }
|
2002-06-12 13:13:54 +08:00
|
|
|
const char *ontherange (homebodies what, struct passwd * = NULL);
|
2004-10-28 09:46:01 +08:00
|
|
|
#define NO_IMPERSONATION NULL
|
2007-07-17 04:01:15 +08:00
|
|
|
bool issetuid () const { return curr_imp_token != NO_IMPERSONATION; }
|
2005-04-03 21:06:43 +08:00
|
|
|
HANDLE primary_token () { return curr_primary_token; }
|
2007-07-17 04:01:15 +08:00
|
|
|
HANDLE imp_token () { return curr_imp_token; }
|
2003-06-30 21:07:36 +08:00
|
|
|
void deimpersonate ()
|
|
|
|
{
|
2007-01-24 18:50:47 +08:00
|
|
|
RevertToSelf ();
|
2003-06-30 21:07:36 +08:00
|
|
|
}
|
2005-04-03 21:06:43 +08:00
|
|
|
bool reimpersonate ()
|
2003-06-30 21:07:36 +08:00
|
|
|
{
|
2006-12-13 00:27:32 +08:00
|
|
|
if (issetuid ())
|
2007-07-17 04:01:15 +08:00
|
|
|
return ImpersonateLoggedOnUser (primary_token ());
|
2006-12-13 00:27:32 +08:00
|
|
|
return true;
|
2003-06-30 21:07:36 +08:00
|
|
|
}
|
2003-07-15 01:04:21 +08:00
|
|
|
bool has_impersonation_tokens ()
|
2004-10-28 09:46:01 +08:00
|
|
|
{ return external_token != NO_IMPERSONATION
|
|
|
|
|| internal_token != NO_IMPERSONATION
|
2005-04-03 21:06:43 +08:00
|
|
|
|| curr_primary_token != NO_IMPERSONATION; }
|
2003-06-30 21:07:36 +08:00
|
|
|
void close_impersonation_tokens ()
|
|
|
|
{
|
2007-07-17 04:01:15 +08:00
|
|
|
if (curr_imp_token != NO_IMPERSONATION)
|
|
|
|
CloseHandle (curr_imp_token);
|
2005-04-03 21:06:43 +08:00
|
|
|
if (curr_primary_token != NO_IMPERSONATION
|
2011-06-06 13:02:13 +08:00
|
|
|
&& curr_primary_token != external_token
|
2005-04-03 21:06:43 +08:00
|
|
|
&& curr_primary_token != internal_token)
|
|
|
|
CloseHandle (curr_primary_token);
|
2004-10-28 09:46:01 +08:00
|
|
|
if (external_token != NO_IMPERSONATION)
|
2005-04-03 21:06:43 +08:00
|
|
|
CloseHandle (external_token);
|
2004-10-28 09:46:01 +08:00
|
|
|
if (internal_token != NO_IMPERSONATION)
|
2005-04-03 21:06:43 +08:00
|
|
|
CloseHandle (internal_token);
|
2002-06-17 07:34:43 +08:00
|
|
|
}
|
2008-02-15 00:47:11 +08:00
|
|
|
PWCHAR get_windows_id (PWCHAR buf)
|
|
|
|
{
|
|
|
|
return effec_cygsid.string (buf);
|
|
|
|
}
|
|
|
|
char *get_windows_id (char *buf)
|
2004-11-21 03:09:19 +08:00
|
|
|
{
|
2007-02-22 18:54:47 +08:00
|
|
|
return effec_cygsid.string (buf);
|
2004-11-21 03:09:19 +08:00
|
|
|
}
|
2005-02-14 02:17:29 +08:00
|
|
|
|
2013-01-21 12:34:52 +08:00
|
|
|
const char __reg3 *test_uid (char *&, const char *, size_t);
|
2000-11-15 08:13:09 +08:00
|
|
|
};
|
2000-11-14 13:53:32 +08:00
|
|
|
|
2001-04-17 11:52:08 +08:00
|
|
|
/* cwd cache stuff. */
|
|
|
|
|
2012-03-05 19:50:25 +08:00
|
|
|
enum fcwd_version_t {
|
|
|
|
FCWD_OLD,
|
|
|
|
FCWD_W7,
|
|
|
|
FCWD_W8
|
|
|
|
};
|
|
|
|
|
2015-12-16 04:43:33 +08:00
|
|
|
/* This class is used to store the CWD. The CWD storage in the
|
|
|
|
RTL_USER_PROCESS_PARAMETERS block is only an afterthought now. The actual
|
|
|
|
CWD storage is a FAST_CWD structure which is allocated on the process heap.
|
|
|
|
The new method only requires minimal locking and it's much more multi-thread
|
|
|
|
friendly. Presumably it minimizes contention when accessing the CWD.
|
2012-03-05 19:50:25 +08:00
|
|
|
The class fcwd_access_t is supposed to encapsulate the gory implementation
|
2013-04-23 17:44:36 +08:00
|
|
|
details depending on OS version from the calling functions.
|
|
|
|
The layout of all structures has been tested on 32 and 64 bit. */
|
2012-03-05 19:50:25 +08:00
|
|
|
class fcwd_access_t {
|
2015-12-16 04:43:33 +08:00
|
|
|
/* This is the layout used in Windows 8 and later. */
|
2012-03-05 19:50:25 +08:00
|
|
|
struct FAST_CWD_8 {
|
|
|
|
LONG ReferenceCount; /* Only release when this is 0. */
|
|
|
|
HANDLE DirectoryHandle;
|
|
|
|
ULONG OldDismountCount; /* Reflects the system DismountCount
|
|
|
|
at the time the CWD has been set. */
|
|
|
|
UNICODE_STRING Path; /* Path's Buffer member always refers
|
|
|
|
to the following Buffer array. */
|
|
|
|
LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
|
2013-04-23 17:44:36 +08:00
|
|
|
WCHAR Buffer[MAX_PATH] __attribute ((aligned (8)));
|
2012-03-05 19:50:25 +08:00
|
|
|
};
|
|
|
|
/* This is the layout used in Windows 7 and Vista. */
|
|
|
|
struct FAST_CWD_7 {
|
|
|
|
UNICODE_STRING Path; /* Path's Buffer member always refers
|
|
|
|
to the following Buffer array. */
|
|
|
|
HANDLE DirectoryHandle;
|
|
|
|
LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
|
|
|
|
LONG ReferenceCount; /* Only release when this is 0. */
|
|
|
|
ULONG OldDismountCount; /* Reflects the system DismountCount
|
|
|
|
at the time the CWD has been set. */
|
2013-04-23 17:44:36 +08:00
|
|
|
WCHAR Buffer[MAX_PATH] __attribute ((aligned (8)));
|
2012-03-05 19:50:25 +08:00
|
|
|
};
|
|
|
|
/* This is the old FAST_CWD structure up to the patch from KB 2393802,
|
|
|
|
release in February 2011. */
|
|
|
|
struct FAST_CWD_OLD {
|
|
|
|
LONG ReferenceCount; /* Only release when this is 0. */
|
|
|
|
HANDLE DirectoryHandle;
|
|
|
|
ULONG OldDismountCount; /* Reflects the system DismountCount
|
|
|
|
at the time the CWD has been set. */
|
|
|
|
UNICODE_STRING Path; /* Path's Buffer member always refers
|
|
|
|
to the following Buffer array. */
|
|
|
|
WCHAR Buffer[MAX_PATH];
|
|
|
|
};
|
|
|
|
union {
|
|
|
|
FAST_CWD_OLD fold;
|
|
|
|
FAST_CWD_7 f7;
|
|
|
|
FAST_CWD_8 f8;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define IMPLEMENT(type, name) \
|
|
|
|
type name () { \
|
|
|
|
switch (fast_cwd_version ()) { \
|
|
|
|
case FCWD_OLD: \
|
|
|
|
default: \
|
|
|
|
return fold.name; \
|
|
|
|
case FCWD_W7: \
|
|
|
|
return f7.name; \
|
|
|
|
case FCWD_W8: \
|
|
|
|
return f8.name; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
IMPLEMENT (LONG &, ReferenceCount)
|
|
|
|
IMPLEMENT (HANDLE &, DirectoryHandle)
|
|
|
|
IMPLEMENT (ULONG &, OldDismountCount)
|
|
|
|
IMPLEMENT (UNICODE_STRING &, Path)
|
|
|
|
IMPLEMENT (WCHAR *, Buffer)
|
|
|
|
void SetFSCharacteristics (LONG val);
|
|
|
|
static fcwd_version_t &fast_cwd_version (void);
|
|
|
|
|
|
|
|
public:
|
|
|
|
void CopyPath (UNICODE_STRING &target);
|
|
|
|
void Free (PVOID heap);
|
|
|
|
void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count);
|
|
|
|
static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir);
|
|
|
|
static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer);
|
|
|
|
};
|
2001-04-17 11:52:08 +08:00
|
|
|
|
2009-05-13 23:00:06 +08:00
|
|
|
class cwdstuff
|
2001-04-17 11:52:08 +08:00
|
|
|
{
|
2009-05-13 23:00:06 +08:00
|
|
|
private:
|
2001-04-17 11:52:08 +08:00
|
|
|
char *posix;
|
2008-01-31 22:18:49 +08:00
|
|
|
HANDLE dir;
|
2010-08-13 19:51:54 +08:00
|
|
|
DWORD drive_length;
|
|
|
|
int error; /* This contains an errno number which corresponds
|
|
|
|
to the problem with this path when trying to start
|
|
|
|
a native Win32 application. See cwdstuff::set for
|
2011-11-14 09:29:49 +08:00
|
|
|
how it gets set. See child_info_spawn::worker for how
|
|
|
|
it's evaluated. */
|
2012-03-05 19:50:25 +08:00
|
|
|
|
|
|
|
friend class fcwd_access_t;
|
|
|
|
/* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in
|
|
|
|
ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD.
|
|
|
|
Unfortunately RtlpCurDirRef is not exported from ntdll.dll. */
|
|
|
|
fcwd_access_t **fast_cwd_ptr;
|
|
|
|
/* Type of FAST_CWD used on this system. Keeping this information
|
|
|
|
available in shared memory avoids to test for the version every time
|
|
|
|
around. Default to new version. */
|
|
|
|
fcwd_version_t fast_cwd_version;
|
2014-10-15 03:14:33 +08:00
|
|
|
void override_win32_cwd (bool init, ULONG old_dismount_count);
|
2010-10-09 18:54:13 +08:00
|
|
|
|
2009-05-13 23:00:06 +08:00
|
|
|
public:
|
|
|
|
UNICODE_STRING win32;
|
2005-04-05 12:31:00 +08:00
|
|
|
static muto cwd_lock;
|
2009-09-22 03:29:16 +08:00
|
|
|
const char *get_posix () const { return posix; };
|
2014-10-15 03:14:33 +08:00
|
|
|
void reset_posix (wchar_t *w_cwd);
|
|
|
|
char *get (char *buf, int need_posix = 1, int with_chroot = 0,
|
|
|
|
unsigned ulen = NT_MAX_PATH);
|
|
|
|
PWCHAR get (PWCHAR buf, unsigned buflen = NT_MAX_PATH)
|
|
|
|
{
|
|
|
|
cwd_lock.acquire ();
|
|
|
|
buf[0] = L'\0';
|
|
|
|
wcsncat (buf, win32.Buffer, buflen - 1);
|
|
|
|
cwd_lock.release ();
|
|
|
|
return buf;
|
|
|
|
}
|
2008-01-31 22:18:49 +08:00
|
|
|
HANDLE get_handle () { return dir; }
|
2005-02-14 02:17:29 +08:00
|
|
|
DWORD get_drive (char * dst)
|
2004-09-08 07:26:28 +08:00
|
|
|
{
|
2007-10-24 00:26:28 +08:00
|
|
|
cwd_lock.acquire ();
|
2008-02-15 00:47:11 +08:00
|
|
|
DWORD ret = sys_wcstombs (dst, NT_MAX_PATH, win32.Buffer, drive_length);
|
2005-04-05 12:31:00 +08:00
|
|
|
cwd_lock.release ();
|
2007-10-24 00:26:28 +08:00
|
|
|
return ret;
|
2004-09-08 07:26:28 +08:00
|
|
|
}
|
2010-08-13 19:51:54 +08:00
|
|
|
int get_error () const { return error; }
|
|
|
|
const char *get_error_desc () const;
|
2001-04-17 11:52:08 +08:00
|
|
|
void init ();
|
2010-08-13 19:51:54 +08:00
|
|
|
int set (path_conv *, const char *);
|
2001-04-17 11:52:08 +08:00
|
|
|
};
|
|
|
|
|
2002-07-14 04:00:27 +08:00
|
|
|
#ifdef DEBUGGING
|
|
|
|
struct cygheap_debug
|
|
|
|
{
|
|
|
|
handle_list starth;
|
|
|
|
handle_list freeh[500];
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2009-05-15 03:49:37 +08:00
|
|
|
struct cygheap_locale
|
|
|
|
{
|
|
|
|
mbtowc_p mbtowc;
|
|
|
|
wctomb_p wctomb;
|
|
|
|
char charset[ENCODING_LEN + 1];
|
|
|
|
};
|
|
|
|
|
2002-10-23 00:18:55 +08:00
|
|
|
struct user_heap_info
|
|
|
|
{
|
|
|
|
void *base;
|
|
|
|
void *ptr;
|
|
|
|
void *top;
|
2003-08-23 03:25:56 +08:00
|
|
|
void *max;
|
2013-04-23 17:44:36 +08:00
|
|
|
SIZE_T chunk;
|
2013-08-31 05:02:02 +08:00
|
|
|
void __reg2 *sbrk (ptrdiff_t);
|
|
|
|
void __reg1 init ();
|
2002-10-23 00:18:55 +08:00
|
|
|
};
|
|
|
|
|
2014-02-10 03:44:56 +08:00
|
|
|
class cygheap_domain_info
|
|
|
|
{
|
|
|
|
PWCHAR pdom_name;
|
|
|
|
PWCHAR pdom_dns_name;
|
|
|
|
cygsid pdom_sid;
|
|
|
|
|
|
|
|
PWCHAR adom_name;
|
|
|
|
cygsid adom_sid;
|
|
|
|
|
|
|
|
PDS_DOMAIN_TRUSTSW tdom;
|
|
|
|
ULONG tdom_count;
|
|
|
|
|
|
|
|
PWCHAR rfc2307_domain_buf;
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool init ();
|
|
|
|
|
|
|
|
inline PCWSTR primary_flat_name () const { return pdom_name; }
|
|
|
|
inline PCWSTR primary_dns_name () const { return pdom_dns_name; }
|
|
|
|
inline cygsid &primary_sid () { return pdom_sid; }
|
|
|
|
|
|
|
|
inline bool member_machine () const { return pdom_sid != NO_SID; }
|
|
|
|
|
|
|
|
inline PCWSTR account_flat_name () const { return adom_name; }
|
|
|
|
inline cygsid &account_sid () { return adom_sid; }
|
|
|
|
|
|
|
|
inline PDS_DOMAIN_TRUSTSW trusted_domain (ULONG idx) const
|
|
|
|
{ return (idx < tdom_count) ? tdom + idx : NULL; }
|
2015-03-31 00:05:06 +08:00
|
|
|
PDS_DOMAIN_TRUSTSW add_domain (PCWSTR, PSID);
|
2014-02-10 03:44:56 +08:00
|
|
|
|
|
|
|
inline PWCHAR get_rfc2307_domain () const
|
|
|
|
{ return rfc2307_domain_buf ?: NULL; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class cygheap_pwdgrp
|
|
|
|
{
|
2014-11-27 03:46:59 +08:00
|
|
|
enum nss_pfx_t {
|
|
|
|
NSS_PFX_AUTO = 0,
|
|
|
|
NSS_PFX_PRIMARY,
|
|
|
|
NSS_PFX_ALWAYS
|
2014-02-10 03:44:56 +08:00
|
|
|
};
|
2014-11-27 03:46:59 +08:00
|
|
|
public:
|
|
|
|
enum nss_scheme_method {
|
|
|
|
NSS_SCHEME_FALLBACK = 0,
|
|
|
|
NSS_SCHEME_WINDOWS,
|
|
|
|
NSS_SCHEME_CYGWIN,
|
|
|
|
NSS_SCHEME_UNIX,
|
|
|
|
NSS_SCHEME_DESC,
|
|
|
|
NSS_SCHEME_PATH,
|
|
|
|
NSS_SCHEME_FREEATTR
|
|
|
|
};
|
|
|
|
struct nss_scheme_t {
|
|
|
|
nss_scheme_method method;
|
|
|
|
PWCHAR attrib;
|
|
|
|
};
|
|
|
|
private:
|
|
|
|
bool nss_inited;
|
|
|
|
uint32_t pwd_src;
|
|
|
|
uint32_t grp_src;
|
|
|
|
nss_pfx_t prefix;
|
|
|
|
WCHAR separator[2];
|
|
|
|
bool caching;
|
|
|
|
|
|
|
|
#define NSS_SCHEME_MAX 4
|
|
|
|
nss_scheme_t home_scheme[NSS_SCHEME_MAX];
|
|
|
|
nss_scheme_t shell_scheme[NSS_SCHEME_MAX];
|
|
|
|
nss_scheme_t gecos_scheme[NSS_SCHEME_MAX];
|
|
|
|
|
|
|
|
uint32_t enums;
|
|
|
|
PWCHAR enum_tdoms;
|
2014-02-10 03:44:56 +08:00
|
|
|
|
|
|
|
void nss_init_line (const char *line);
|
|
|
|
void _nss_init ();
|
|
|
|
|
|
|
|
public:
|
|
|
|
struct {
|
2014-03-13 01:36:56 +08:00
|
|
|
pwdgrp cygserver;
|
2014-02-10 03:44:56 +08:00
|
|
|
pwdgrp file;
|
|
|
|
pwdgrp win;
|
|
|
|
} pwd_cache;
|
|
|
|
struct {
|
2014-03-13 01:36:56 +08:00
|
|
|
pwdgrp cygserver;
|
2014-02-10 03:44:56 +08:00
|
|
|
pwdgrp file;
|
|
|
|
pwdgrp win;
|
|
|
|
} grp_cache;
|
|
|
|
|
|
|
|
void init ();
|
|
|
|
|
2014-11-27 03:46:59 +08:00
|
|
|
/* Implemented in ldap.cc */
|
|
|
|
PWCHAR *ldap_user_attr;
|
|
|
|
void init_ldap_user_attr ();
|
|
|
|
|
2014-02-10 03:44:56 +08:00
|
|
|
inline void nss_init () { if (!nss_inited) _nss_init (); }
|
2014-11-12 19:19:08 +08:00
|
|
|
inline bool nss_pwd_files () const { return !!(pwd_src & NSS_SRC_FILES); }
|
|
|
|
inline bool nss_pwd_db () const { return !!(pwd_src & NSS_SRC_DB); }
|
|
|
|
inline int nss_pwd_src () const { return pwd_src; } /* CW_GETNSS_PWD_SRC */
|
|
|
|
inline bool nss_grp_files () const { return !!(grp_src & NSS_SRC_FILES); }
|
|
|
|
inline bool nss_grp_db () const { return !!(grp_src & NSS_SRC_DB); }
|
|
|
|
inline int nss_grp_src () const { return grp_src; } /* CW_GETNSS_GRP_SRC */
|
2014-11-27 03:46:59 +08:00
|
|
|
inline bool nss_prefix_auto () const { return prefix == NSS_PFX_AUTO; }
|
|
|
|
inline bool nss_prefix_primary () const { return prefix == NSS_PFX_PRIMARY; }
|
|
|
|
inline bool nss_prefix_always () const { return prefix == NSS_PFX_ALWAYS; }
|
2014-02-10 03:44:56 +08:00
|
|
|
inline PCWSTR nss_separator () const { return separator; }
|
2014-03-13 01:36:56 +08:00
|
|
|
inline bool nss_cygserver_caching () const { return caching; }
|
|
|
|
inline void nss_disable_cygserver_caching () { caching = false; }
|
2014-11-27 03:46:59 +08:00
|
|
|
|
2015-02-13 00:55:38 +08:00
|
|
|
char *get_home (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, PCWSTR dnsdomain,
|
|
|
|
PCWSTR name, bool fq);
|
2014-12-02 19:30:04 +08:00
|
|
|
char *get_home (struct _USER_INFO_3 *ui, cygpsid &sid, PCWSTR dom,
|
|
|
|
PCWSTR name, bool fq);
|
2014-11-27 03:46:59 +08:00
|
|
|
|
2015-02-13 00:55:38 +08:00
|
|
|
char *get_shell (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, PCWSTR dnsdomain,
|
|
|
|
PCWSTR name, bool fq);
|
2015-01-09 01:08:47 +08:00
|
|
|
char *get_shell (struct _USER_INFO_3 *ui, cygpsid &sid, PCWSTR dom,
|
|
|
|
PCWSTR name, bool fq);
|
2014-11-27 03:46:59 +08:00
|
|
|
|
2015-02-13 00:55:38 +08:00
|
|
|
char *get_gecos (cyg_ldap *pldap, cygpsid &sid, PCWSTR dom, PCWSTR dnsdomain,
|
|
|
|
PCWSTR name, bool fq);
|
2015-01-09 01:08:47 +08:00
|
|
|
char *get_gecos (struct _USER_INFO_3 *ui, cygpsid &sid, PCWSTR dom,
|
|
|
|
PCWSTR name, bool fq);
|
2014-11-27 03:46:59 +08:00
|
|
|
|
2014-02-17 23:36:33 +08:00
|
|
|
inline int nss_db_enums () const { return enums; }
|
|
|
|
inline PCWSTR nss_db_enum_tdoms () const { return enum_tdoms; }
|
2014-02-10 03:44:56 +08:00
|
|
|
};
|
|
|
|
|
2014-02-11 19:51:29 +08:00
|
|
|
class cygheap_ugid_cache
|
|
|
|
{
|
|
|
|
struct idmap {
|
|
|
|
uint32_t nfs_id;
|
|
|
|
uint32_t cyg_id;
|
|
|
|
};
|
|
|
|
class idmaps {
|
|
|
|
uint32_t _cnt;
|
|
|
|
uint32_t _max;
|
|
|
|
idmap *_map;
|
|
|
|
public:
|
|
|
|
uint32_t get (uint32_t id) const
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < _cnt; ++i)
|
|
|
|
if (_map[i].nfs_id == id)
|
|
|
|
return _map[i].cyg_id;
|
|
|
|
return (uint32_t) -1;
|
|
|
|
}
|
2016-03-13 00:56:21 +08:00
|
|
|
uint32_t reverse_get (uint32_t id) const
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < _cnt; ++i)
|
|
|
|
if (_map[i].cyg_id == id)
|
|
|
|
return _map[i].nfs_id;
|
|
|
|
return (uint32_t) -1;
|
|
|
|
}
|
2014-02-11 19:51:29 +08:00
|
|
|
void add (uint32_t nfs_id, uint32_t cyg_id)
|
|
|
|
{
|
|
|
|
if (_cnt >= _max)
|
|
|
|
_map = (idmap *) crealloc (_map, (_max += 10) * sizeof (*_map));
|
|
|
|
_map[_cnt].nfs_id = nfs_id;
|
|
|
|
_map[_cnt].cyg_id = cyg_id;
|
|
|
|
++_cnt;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
idmaps uids;
|
|
|
|
idmaps gids;
|
|
|
|
|
|
|
|
public:
|
|
|
|
uid_t get_uid (uid_t uid) const { return uids.get (uid); }
|
|
|
|
gid_t get_gid (gid_t gid) const { return gids.get (gid); }
|
2016-03-13 00:56:21 +08:00
|
|
|
uid_t reverse_get_uid (uid_t uid) const { return uids.reverse_get (uid); }
|
|
|
|
gid_t reverse_get_gid (gid_t gid) const { return gids.reverse_get (gid); }
|
2014-02-11 19:51:29 +08:00
|
|
|
void add_uid (uid_t nfs_uid, uid_t cyg_uid) { uids.add (nfs_uid, cyg_uid); }
|
|
|
|
void add_gid (gid_t nfs_gid, gid_t cyg_gid) { gids.add (nfs_gid, cyg_gid); }
|
|
|
|
};
|
|
|
|
|
2005-03-23 03:00:31 +08:00
|
|
|
struct hook_chain
|
|
|
|
{
|
|
|
|
void **loc;
|
|
|
|
const void *func;
|
|
|
|
struct hook_chain *next;
|
|
|
|
};
|
|
|
|
|
2009-06-08 11:53:40 +08:00
|
|
|
struct mini_cygheap
|
|
|
|
{
|
|
|
|
cygheap_locale locale;
|
|
|
|
};
|
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
#define NBUCKETS 40
|
|
|
|
|
2014-11-29 04:46:13 +08:00
|
|
|
struct threadlist_t
|
|
|
|
{
|
|
|
|
struct _cygtls *thread;
|
|
|
|
HANDLE mutex; /* Used to avoid accessing tls area of
|
|
|
|
deleted thread. See comment in
|
|
|
|
cygheap::remove_tls for a description. */
|
|
|
|
};
|
|
|
|
|
2009-06-08 11:53:40 +08:00
|
|
|
struct init_cygheap: public mini_cygheap
|
2000-11-14 13:53:32 +08:00
|
|
|
{
|
|
|
|
_cmalloc_entry *chain;
|
2013-04-23 17:44:36 +08:00
|
|
|
unsigned bucket_val[NBUCKETS];
|
|
|
|
char *buckets[NBUCKETS];
|
2012-02-14 19:27:43 +08:00
|
|
|
WCHAR installation_root[PATH_MAX];
|
2014-10-17 22:36:59 +08:00
|
|
|
WCHAR installation_dir[PATH_MAX];
|
2014-10-27 19:33:53 +08:00
|
|
|
size_t installation_dir_len;
|
2012-02-14 19:27:43 +08:00
|
|
|
UNICODE_STRING installation_key;
|
|
|
|
WCHAR installation_key_buf[18];
|
2000-11-15 08:13:09 +08:00
|
|
|
cygheap_root root;
|
2014-02-10 03:44:56 +08:00
|
|
|
cygheap_domain_info dom;
|
|
|
|
cygheap_pwdgrp pg;
|
2014-02-11 19:51:29 +08:00
|
|
|
cygheap_ugid_cache ugid_cache;
|
2000-11-15 08:13:09 +08:00
|
|
|
cygheap_user user;
|
2002-10-23 00:18:55 +08:00
|
|
|
user_heap_info user_heap;
|
2000-11-14 13:53:32 +08:00
|
|
|
mode_t umask;
|
2010-04-20 18:44:52 +08:00
|
|
|
unsigned long rlim_core;
|
2001-01-28 13:51:15 +08:00
|
|
|
HANDLE console_h;
|
2001-04-17 11:52:08 +08:00
|
|
|
cwdstuff cwd;
|
2001-04-19 05:10:15 +08:00
|
|
|
dtable fdtab;
|
2002-07-14 04:00:27 +08:00
|
|
|
#ifdef DEBUGGING
|
|
|
|
cygheap_debug debug;
|
|
|
|
#endif
|
2003-09-01 10:05:32 +08:00
|
|
|
struct sigaction *sigs;
|
2003-12-08 06:37:12 +08:00
|
|
|
|
2011-04-18 03:56:25 +08:00
|
|
|
fhandler_termios *ctty; /* Current tty */
|
2014-11-29 04:46:13 +08:00
|
|
|
threadlist_t *threadlist;
|
2013-04-23 17:44:36 +08:00
|
|
|
uint32_t sthreads;
|
2004-09-12 11:47:57 +08:00
|
|
|
pid_t pid; /* my pid */
|
2008-03-24 22:48:58 +08:00
|
|
|
struct { /* Equivalent to using LIST_HEAD. */
|
|
|
|
struct inode_t *lh_first;
|
|
|
|
} inode_list; /* Global inode pointer for adv. locking. */
|
2005-03-23 03:00:31 +08:00
|
|
|
hook_chain hooks;
|
2004-01-14 23:45:37 +08:00
|
|
|
void close_ctty ();
|
2012-02-14 19:27:43 +08:00
|
|
|
void init_installation_root ();
|
2013-01-21 12:34:52 +08:00
|
|
|
void __reg1 init_tls_list ();;
|
|
|
|
void __reg2 add_tls (_cygtls *);
|
2014-11-29 04:46:13 +08:00
|
|
|
HANDLE __reg3 remove_tls (_cygtls *);
|
|
|
|
threadlist_t __reg2 *find_tls (_cygtls *);
|
|
|
|
threadlist_t __reg3 *find_tls (int, bool&);
|
|
|
|
void unlock_tls (threadlist_t *t) { if (t) ReleaseMutex (t->mutex); }
|
2000-11-14 13:53:32 +08:00
|
|
|
};
|
|
|
|
|
2005-11-14 12:28:45 +08:00
|
|
|
|
2004-04-11 12:07:18 +08:00
|
|
|
#define _CYGHEAPSIZE_SLOP (128 * 1024)
|
2004-03-19 03:30:51 +08:00
|
|
|
#define CYGHEAPSIZE (sizeof (init_cygheap) + (20000 * sizeof (fhandler_union)) + _CYGHEAPSIZE_SLOP)
|
|
|
|
#define CYGHEAPSIZE_MIN (sizeof (init_cygheap) + (10000 * sizeof (fhandler_union)))
|
2001-04-19 05:10:15 +08:00
|
|
|
|
2000-11-14 13:53:32 +08:00
|
|
|
extern init_cygheap *cygheap;
|
|
|
|
extern void *cygheap_max;
|
|
|
|
|
2001-10-16 07:39:33 +08:00
|
|
|
class cygheap_fdmanip
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
int fd;
|
|
|
|
bool locked;
|
|
|
|
public:
|
2010-08-10 00:53:35 +08:00
|
|
|
cygheap_fdmanip (): fd (-1), locked (false) {}
|
2001-10-16 07:39:33 +08:00
|
|
|
virtual ~cygheap_fdmanip ()
|
|
|
|
{
|
|
|
|
if (locked)
|
2004-01-14 23:45:37 +08:00
|
|
|
cygheap->fdtab.unlock ();
|
2001-10-16 07:39:33 +08:00
|
|
|
}
|
2011-12-17 08:03:31 +08:00
|
|
|
virtual void release () { cygheap->fdtab.release (fd); }
|
2001-10-16 07:39:33 +08:00
|
|
|
operator int &() {return fd;}
|
2010-08-10 00:53:35 +08:00
|
|
|
operator fhandler_base* &() {return cygheap->fdtab[fd];}
|
|
|
|
operator fhandler_socket* () const {return reinterpret_cast<fhandler_socket *> (cygheap->fdtab[fd]);}
|
|
|
|
operator fhandler_pipe* () const {return reinterpret_cast<fhandler_pipe *> (cygheap->fdtab[fd]);}
|
|
|
|
void operator = (fhandler_base *fh) {cygheap->fdtab[fd] = fh;}
|
|
|
|
fhandler_base *operator -> () const {return cygheap->fdtab[fd];}
|
2001-11-02 07:48:34 +08:00
|
|
|
bool isopen () const
|
|
|
|
{
|
2010-08-10 00:53:35 +08:00
|
|
|
if (cygheap->fdtab[fd])
|
2001-11-02 07:48:34 +08:00
|
|
|
return true;
|
|
|
|
set_errno (EBADF);
|
|
|
|
return false;
|
|
|
|
}
|
2001-10-16 07:39:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class cygheap_fdnew : public cygheap_fdmanip
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cygheap_fdnew (int seed_fd = -1, bool lockit = true)
|
|
|
|
{
|
|
|
|
if (lockit)
|
2004-01-14 23:45:37 +08:00
|
|
|
cygheap->fdtab.lock ();
|
2001-10-16 07:39:33 +08:00
|
|
|
if (seed_fd < 0)
|
|
|
|
fd = cygheap->fdtab.find_unused_handle ();
|
|
|
|
else
|
|
|
|
fd = cygheap->fdtab.find_unused_handle (seed_fd + 1);
|
|
|
|
if (fd >= 0)
|
2010-08-10 00:53:35 +08:00
|
|
|
locked = lockit;
|
2001-10-16 07:39:33 +08:00
|
|
|
else
|
|
|
|
{
|
2013-12-06 03:43:34 +08:00
|
|
|
/* errno set by find_unused_handle */
|
2001-10-16 07:39:33 +08:00
|
|
|
if (lockit)
|
2004-01-14 23:45:37 +08:00
|
|
|
cygheap->fdtab.unlock ();
|
2001-10-16 07:39:33 +08:00
|
|
|
locked = false;
|
|
|
|
}
|
|
|
|
}
|
2011-12-17 08:03:31 +08:00
|
|
|
~cygheap_fdnew ()
|
|
|
|
{
|
|
|
|
if (cygheap->fdtab[fd])
|
2012-06-04 02:02:45 +08:00
|
|
|
cygheap->fdtab[fd]->inc_refcnt ();
|
2011-12-17 08:03:31 +08:00
|
|
|
}
|
2010-08-10 00:53:35 +08:00
|
|
|
void operator = (fhandler_base *fh) {cygheap->fdtab[fd] = fh;}
|
2001-10-16 07:39:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class cygheap_fdget : public cygheap_fdmanip
|
|
|
|
{
|
2011-12-17 08:03:31 +08:00
|
|
|
fhandler_base *fh;
|
|
|
|
public:
|
2001-10-16 11:31:50 +08:00
|
|
|
cygheap_fdget (int fd, bool lockit = false, bool do_set_errno = true)
|
2001-10-16 07:39:33 +08:00
|
|
|
{
|
|
|
|
if (lockit)
|
2004-01-14 23:45:37 +08:00
|
|
|
cygheap->fdtab.lock ();
|
2010-08-10 00:53:35 +08:00
|
|
|
if (fd >= 0 && fd < (int) cygheap->fdtab.size && cygheap->fdtab[fd] != NULL)
|
2001-10-16 07:39:33 +08:00
|
|
|
{
|
|
|
|
this->fd = fd;
|
|
|
|
locked = lockit;
|
2011-12-17 08:03:31 +08:00
|
|
|
fh = cygheap->fdtab[fd];
|
2012-06-04 02:02:45 +08:00
|
|
|
fh->inc_refcnt ();
|
2001-10-16 07:39:33 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->fd = -1;
|
2001-10-16 11:31:50 +08:00
|
|
|
if (do_set_errno)
|
2001-10-16 22:43:36 +08:00
|
|
|
set_errno (EBADF);
|
2001-10-16 07:39:33 +08:00
|
|
|
if (lockit)
|
2004-01-14 23:45:37 +08:00
|
|
|
cygheap->fdtab.unlock ();
|
2001-10-16 07:39:33 +08:00
|
|
|
locked = false;
|
2011-12-17 08:03:31 +08:00
|
|
|
fh = NULL;
|
2001-10-16 07:39:33 +08:00
|
|
|
}
|
|
|
|
}
|
2011-12-17 08:03:31 +08:00
|
|
|
~cygheap_fdget ()
|
|
|
|
{
|
2012-06-04 02:02:45 +08:00
|
|
|
if (fh && fh->dec_refcnt () <= 0)
|
2011-12-17 08:03:31 +08:00
|
|
|
{
|
2012-01-22 14:45:08 +08:00
|
|
|
debug_only_printf ("deleting fh %p", fh);
|
2011-12-17 08:03:31 +08:00
|
|
|
delete fh;
|
|
|
|
}
|
|
|
|
}
|
2012-01-22 15:27:57 +08:00
|
|
|
void release () { cygheap->fdtab.release (fd); }
|
2001-10-16 07:39:33 +08:00
|
|
|
};
|
|
|
|
|
2005-01-31 18:28:55 +08:00
|
|
|
class cygheap_fdenum : public cygheap_fdmanip
|
|
|
|
{
|
|
|
|
public:
|
2005-10-24 23:09:07 +08:00
|
|
|
cygheap_fdenum (bool lockit = false)
|
2005-01-31 18:28:55 +08:00
|
|
|
{
|
2005-10-24 07:47:45 +08:00
|
|
|
locked = lockit;
|
2005-01-31 18:28:55 +08:00
|
|
|
if (lockit)
|
|
|
|
cygheap->fdtab.lock ();
|
2005-10-24 23:09:07 +08:00
|
|
|
fd = -1;
|
2005-01-31 18:28:55 +08:00
|
|
|
}
|
|
|
|
int next ()
|
|
|
|
{
|
|
|
|
while (++fd < (int) cygheap->fdtab.size)
|
2010-08-10 00:53:35 +08:00
|
|
|
if (cygheap->fdtab[fd] != NULL)
|
2005-05-02 11:50:11 +08:00
|
|
|
return fd;
|
2005-01-31 18:28:55 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
void rewind ()
|
|
|
|
{
|
2005-10-24 23:09:07 +08:00
|
|
|
fd = -1;
|
2005-01-31 18:28:55 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2002-06-16 05:59:32 +08:00
|
|
|
void __stdcall cygheap_fixup_in_child (bool);
|
2000-10-02 10:26:04 +08:00
|
|
|
void __stdcall cygheap_init ();
|
2014-10-17 22:36:59 +08:00
|
|
|
void setup_cygheap ();
|
2005-06-01 11:46:56 +08:00
|
|
|
extern char _cygheap_start[] __attribute__((section(".idata")));
|