📄 posixmodule.c
字号:
/* Portions Copyright (c) 2005 Nokia Corporation */
/* POSIX module implementation */
/* This file is also used for Windows NT and MS-Win. In that case the module
actually calls itself 'nt', not 'posix', and a few functions are
either unimplemented or implemented differently. The source
assumes that for Windows NT, the macro 'MS_WIN32' is defined independent
of the compiler used. Different compilers define their own feature
test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */
/* See also ../Dos/dosmodule.c */
static const char posix__doc__ [] =
#ifndef SYMBIAN
"This module provides access to operating system functionality that is\n\
standardized by the C Standard and the POSIX standard (a thinly\n\
disguised Unix interface). Refer to the library manual and\n\
corresponding Unix manual entries for more information on calls.";
#else
"";
#endif
#include "Python.h"
#include "structseq.h"
#if defined(PYOS_OS2)
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_NOPMAPI
#include <os2.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h> /* For WNOHANG */
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
/* Various compilers have only certain posix functions */
/* XXX Gosh I wish these were all moved into pyconfig.h */
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
#include <process.h>
#else
#if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */
#define HAVE_GETCWD 1
#define HAVE_OPENDIR 1
#define HAVE_SYSTEM 1
#if defined(__OS2__)
#define HAVE_EXECV 1
#define HAVE_WAIT 1
#endif
#include <process.h>
#else
#ifdef __BORLANDC__ /* Borland compiler */
#define HAVE_EXECV 1
#define HAVE_GETCWD 1
#define HAVE_OPENDIR 1
#define HAVE_PIPE 1
#define HAVE_POPEN 1
#define HAVE_SYSTEM 1
#define HAVE_WAIT 1
#else
#ifdef SYMBIAN /* Compilers in Symbian OS environment */
#define HAVE_GETCWD 1
#define HAVE_FSYNC 1
#else
#ifdef _MSC_VER /* Microsoft compiler */
#define HAVE_GETCWD 1
#ifdef MS_WIN32
#define HAVE_SPAWNV 1
#define HAVE_EXECV 1
#define HAVE_PIPE 1
#define HAVE_POPEN 1
#define HAVE_SYSTEM 1
#else /* 16-bit Windows */
#endif /* !MS_WIN32 */
#else /* all other compilers */
/* Unix functions that the configure script doesn't check for */
#define HAVE_EXECV 1
#define HAVE_FORK 1
#if defined(__USLC__) && defined(__SCO_VERSION__) /* SCO UDK Compiler */
#define HAVE_FORK1 1
#endif
#define HAVE_GETCWD 1
#define HAVE_GETEGID 1
#define HAVE_GETEUID 1
#define HAVE_GETGID 1
#define HAVE_GETPPID 1
#define HAVE_GETUID 1
#define HAVE_KILL 1
#define HAVE_OPENDIR 1
#define HAVE_PIPE 1
#define HAVE_POPEN 1
#define HAVE_SYSTEM 1
#define HAVE_WAIT 1
#define HAVE_TTYNAME 1
#endif /* _MSC_VER */
#endif /* SYMBIAN */
#endif /* __BORLANDC__ */
#endif /* ! __WATCOMC__ || __QNX__ */
#endif /* ! __IBMC__ */
#ifndef _MSC_VER
#if defined(sun) && !defined(__SVR4)
/* SunOS 4.1.4 doesn't have prototypes for these: */
extern int rename(const char *, const char *);
extern int pclose(FILE *);
extern int fclose(FILE *);
extern int fsync(int);
extern int lstat(const char *, struct stat *);
extern int symlink(const char *, const char *);
#endif
#ifdef NeXT
/* NeXT's <unistd.h> and <utime.h> aren't worth much */
#undef HAVE_UNISTD_H
#undef HAVE_UTIME_H
#define HAVE_WAITPID
/* #undef HAVE_GETCWD */
#define UNION_WAIT /* This should really be checked for by autoconf */
#endif
#ifndef HAVE_UNISTD_H
#if defined(PYCC_VACPP)
extern int mkdir(char *);
#else
#if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__)
extern int mkdir(const char *);
#else
extern int mkdir(const char *, mode_t);
#endif
#endif
#if defined(__IBMC__) || defined(__IBMCPP__)
extern int chdir(char *);
extern int rmdir(char *);
#else
extern int chdir(const char *);
extern int rmdir(const char *);
#endif
#ifdef __BORLANDC__
extern int chmod(const char *, int);
#else
extern int chmod(const char *, mode_t);
#endif
extern int chown(const char *, uid_t, gid_t);
extern char *getcwd(char *, int);
extern char *strerror(int);
extern int link(const char *, const char *);
extern int rename(const char *, const char *);
extern int stat(const char *, struct stat *);
extern int unlink(const char *);
extern int pclose(FILE *);
#ifdef HAVE_SYMLINK
extern int symlink(const char *, const char *);
#endif /* HAVE_SYMLINK */
#ifdef HAVE_LSTAT
extern int lstat(const char *, struct stat *);
#endif /* HAVE_LSTAT */
#endif /* !HAVE_UNISTD_H */
#endif /* !_MSC_VER */
#ifdef HAVE_UTIME_H
#include <utime.h>
#endif /* HAVE_UTIME_H */
#ifdef HAVE_SYS_UTIME_H
#include <sys/utime.h>
#define HAVE_UTIME_H /* pretend we do for the rest of this file */
#endif /* HAVE_SYS_UTIME_H */
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
#endif /* HAVE_SYS_TIMES_H */
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif /* HAVE_SYS_PARAM_H */
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif /* HAVE_SYS_UTSNAME_H */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif /* MAXPATHLEN */
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#if defined(__WATCOMC__) && !defined(__QNX__)
#include <direct.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) (dirent)->d_namlen
#endif
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#endif
#ifdef _MSC_VER
#include <direct.h>
#include <io.h>
#include <process.h>
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#ifdef MS_WIN32
#define popen _popen
#define pclose _pclose
#else /* 16-bit Windows */
#include <dos.h>
#include <ctype.h>
#endif /* MS_WIN32 */
#endif /* _MSC_VER */
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
#include <io.h>
#endif /* OS2 */
#ifdef UNION_WAIT
/* Emulate some macros on systems that have a union instead of macros */
#ifndef WIFEXITED
#define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump)
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1)
#endif
#ifndef WTERMSIG
#define WTERMSIG(u_wait) ((u_wait).w_termsig)
#endif
#endif /* UNION_WAIT */
/* Don't use the "_r" form if we don't need it (also, won't have a
prototype for it, at least on Solaris -- maybe others as well?). */
#if defined(HAVE_CTERMID_R) && defined(WITH_THREAD)
#define USE_CTERMID_R
#endif
#if defined(HAVE_TMPNAM_R) && defined(WITH_THREAD)
#define USE_TMPNAM_R
#endif
/* choose the appropriate stat and fstat functions and return structs */
#undef STAT
#if defined(MS_WIN64) || defined(MS_WIN32)
# define STAT _stati64
# define FSTAT _fstati64
# define STRUCT_STAT struct _stati64
#else
# define STAT stat
# define FSTAT fstat
# define STRUCT_STAT struct stat
#endif
/* Return a dictionary corresponding to the POSIX environment table */
#ifndef SYMBIAN
#if !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) )
extern char **environ;
#endif /* !_MSC_VER */
static PyObject *
convertenviron(void)
{
PyObject *d;
char **e;
d = PyDict_New();
if (d == NULL)
return NULL;
if (environ == NULL)
return d;
/* This part ignores errors */
for (e = environ; *e != NULL; e++) {
PyObject *k;
PyObject *v;
char *p = strchr(*e, '=');
if (p == NULL)
continue;
k = PyString_FromStringAndSize(*e, (int)(p-*e));
if (k == NULL) {
PyErr_Clear();
continue;
}
v = PyString_FromString(p+1);
if (v == NULL) {
PyErr_Clear();
Py_DECREF(k);
continue;
}
if (PyDict_GetItem(d, k) == NULL) {
if (PyDict_SetItem(d, k, v) != 0)
PyErr_Clear();
}
Py_DECREF(k);
Py_DECREF(v);
}
#if defined(PYOS_OS2)
{
APIRET rc;
char buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */
rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH);
if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */
PyObject *v = PyString_FromString(buffer);
PyDict_SetItemString(d, "BEGINLIBPATH", v);
Py_DECREF(v);
}
rc = DosQueryExtLIBPATH(buffer, END_LIBPATH);
if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */
PyObject *v = PyString_FromString(buffer);
PyDict_SetItemString(d, "ENDLIBPATH", v);
Py_DECREF(v);
}
}
#endif
return d;
}
#endif /* not SYMBIAN */
/* Set a POSIX-specific error from errno, and return NULL */
static PyObject *
posix_error(void)
{
return PyErr_SetFromErrno(PyExc_OSError);
}
static PyObject *
posix_error_with_filename(char* name)
{
return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
}
static PyObject *
posix_error_with_allocated_filename(char* name)
{
PyObject *rc = PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
PyMem_Free(name);
return rc;
}
#ifdef MS_WIN32
static PyObject *
win32_error(char* function, char* filename)
{
/* XXX We should pass the function name along in the future.
(_winreg.c also wants to pass the function name.)
This would however require an additional param to the
Windows error object, which is non-trivial.
*/
errno = GetLastError();
if (filename)
return PyErr_SetFromWindowsErrWithFilename(errno, filename);
else
return PyErr_SetFromWindowsErr(errno);
}
#endif
#if defined(PYOS_OS2)
/**********************************************************************
* Helper Function to Trim and Format OS/2 Messages
**********************************************************************/
static void
os2_formatmsg(char *msgbuf, int msglen, char *reason)
{
msgbuf[msglen] = '\0'; /* OS/2 Doesn't Guarantee a Terminator */
if (strlen(msgbuf) > 0) { /* If Non-Empty Msg, Trim CRLF */
char *lastc = &msgbuf[ strlen(msgbuf)-1 ];
while (lastc > msgbuf && isspace(*lastc))
*lastc-- = '\0'; /* Trim Trailing Whitespace (CRLF) */
}
/* Add Optional Reason Text */
if (reason) {
strcat(msgbuf, " : ");
strcat(msgbuf, reason);
}
}
/**********************************************************************
* Decode an OS/2 Operating System Error Code
*
* A convenience function to lookup an OS/2 error code and return a
* text message we can use to raise a Python exception.
*
* Notes:
* The messages for errors returned from the OS/2 kernel reside in
* the file OSO001.MSG in the \OS2 directory hierarchy.
*
**********************************************************************/
static char *
os2_strerror(char *msgbuf, int msgbuflen, int errorcode, char *reason)
{
APIRET rc;
ULONG msglen;
/* Retrieve Kernel-Related Error Message from OSO001.MSG File */
Py_BEGIN_ALLOW_THREADS
rc = DosGetMessage(NULL, 0, msgbuf, msgbuflen,
errorcode, "oso001.msg", &msglen);
Py_END_ALLOW_THREADS
if (rc == NO_ERROR)
os2_formatmsg(msgbuf, msglen, reason);
else
PyOS_snprintf(msgbuf, msgbuflen,
"unknown OS error #%d", errorcode);
return msgbuf;
}
/* Set an OS/2-specific error and return NULL. OS/2 kernel
errors are not in a global variable e.g. 'errno' nor are
they congruent with posix error numbers. */
static PyObject * os2_error(int code)
{
char text[1024];
PyObject *v;
os2_strerror(text, sizeof(text), code, "");
v = Py_BuildValue("(is)", code, text);
if (v != NULL) {
PyErr_SetObject(PyExc_OSError, v);
Py_DECREF(v);
}
return NULL; /* Signal to Python that an Exception is Pending */
}
#endif /* OS2 */
/* POSIX generic methods */
static PyObject *
posix_int(PyObject *args, char *format, int (*func)(int))
{
int fd;
int res;
if (!PyArg_ParseTuple(args, format, &fd))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = (*func)(fd);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error();
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
posix_1str(PyObject *args, char *format, int (*func)(const char*))
{
char *path1 = NULL;
int res;
if (!PyArg_ParseTuple(args, format,
Py_FileSystemDefaultEncoding, &path1))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = (*func)(path1);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(path1);
PyMem_Free(path1);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
posix_2str(PyObject *args, char *format,
int (*func)(const char *, const char *))
{
char *path1 = NULL, *path2 = NULL;
int res;
if (!PyArg_ParseTuple(args, format,
Py_FileSystemDefaultEncoding, &path1,
Py_FileSystemDefaultEncoding, &path2))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = (*func)(path1, path2);
Py_END_ALLOW_THREADS
PyMem_Free(path1);
PyMem_Free(path2);
if (res != 0)
/* XXX how to report both path1 and path2??? */
return posix_error();
Py_INCREF(Py_None);
return Py_None;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -