}
#endif
-#ifdef HAVE_DEVICE_MACROS
-PyDoc_STRVAR(posix_major__doc__,
-"major(device) -> major number\n\
-Extracts a device major number from a raw device number.");
+
+PyDoc_STRVAR(posix_lstat__doc__,
+"lstat(path) -> stat result\n\n\
+Like stat(path), but do not follow symbolic links.");
static PyObject *
-posix_major(PyObject *self, PyObject *args)
+posix_lstat(PyObject *self, PyObject *args)
{
- int device;
- if (!PyArg_ParseTuple(args, "i:major", &device))
- return NULL;
- return PyLong_FromLong((long)major(device));
+#ifdef HAVE_LSTAT
+ return posix_do_stat(self, args, "O&:lstat", lstat, NULL, NULL);
+#else /* !HAVE_LSTAT */
+#ifdef MS_WINDOWS
+ return posix_do_stat(self, args, "O&:lstat", win32_lstat, "U:lstat",
+ win32_lstat_w);
+#else
+ return posix_do_stat(self, args, "O&:lstat", STAT, NULL, NULL);
+#endif
+#endif /* !HAVE_LSTAT */
}
-PyDoc_STRVAR(posix_minor__doc__,
-"minor(device) -> minor number\n\
-Extracts a device minor number from a raw device number.");
+
+#ifdef HAVE_READLINK
+PyDoc_STRVAR(posix_readlink__doc__,
+"readlink(path) -> path\n\n\
+Return a string representing the path to which the symbolic link points.");
static PyObject *
-posix_minor(PyObject *self, PyObject *args)
+posix_readlink(PyObject *self, PyObject *args)
{
- int device;
- if (!PyArg_ParseTuple(args, "i:minor", &device))
+ PyObject* v;
+ char buf[MAXPATHLEN];
+ PyObject *opath;
+ char *path;
+ int n;
+ int arg_is_unicode = 0;
+
+ if (!PyArg_ParseTuple(args, "O&:readlink",
+ PyUnicode_FSConverter, &opath))
return NULL;
- return PyLong_FromLong((long)minor(device));
+ path = PyBytes_AsString(opath);
+ v = PySequence_GetItem(args, 0);
+ if (v == NULL) {
+ Py_DECREF(opath);
+ return NULL;
+ }
+
+ if (PyUnicode_Check(v)) {
+ arg_is_unicode = 1;
+ }
+ Py_DECREF(v);
+
+ Py_BEGIN_ALLOW_THREADS
+ n = readlink(path, buf, (int) sizeof buf);
+ Py_END_ALLOW_THREADS
+ if (n < 0)
+ return posix_error_with_allocated_filename(opath);
+
+ Py_DECREF(opath);
+ if (arg_is_unicode)
+ return PyUnicode_DecodeFSDefaultAndSize(buf, n);
+ else
+ return PyBytes_FromStringAndSize(buf, n);
}
+#endif /* HAVE_READLINK */
-PyDoc_STRVAR(posix_makedev__doc__,
-"makedev(major, minor) -> device number\n\
-Composes a raw device number from the major and minor device numbers.");
+
+#if defined(HAVE_SYMLINK) && !defined(MS_WINDOWS)
+PyDoc_STRVAR(posix_symlink__doc__,
+"symlink(src, dst)\n\n\
+Create a symbolic link pointing to src named dst.");
static PyObject *
-posix_makedev(PyObject *self, PyObject *args)
+posix_symlink(PyObject *self, PyObject *args)
{
- int major, minor;
- if (!PyArg_ParseTuple(args, "ii:makedev", &major, &minor))
- return NULL;
- return PyLong_FromLong((long)makedev(major, minor));
+ return posix_2str(args, "O&O&:symlink", symlink);
}
-#endif /* device macros */
+#endif /* HAVE_SYMLINK */
+#if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
-#ifdef HAVE_FTRUNCATE
-PyDoc_STRVAR(posix_ftruncate__doc__,
-"ftruncate(fd, length)\n\n\
-Truncate a file to a specified length.");
+PyDoc_STRVAR(win_readlink__doc__,
+"readlink(path) -> path\n\n\
+Return a string representing the path to which the symbolic link points.");
+/* Windows readlink implementation */
static PyObject *
-posix_ftruncate(PyObject *self, PyObject *args)
+win_readlink(PyObject *self, PyObject *args)
{
- int fd;
- off_t length;
- int res;
- PyObject *lenobj;
+ wchar_t *path;
+ DWORD n_bytes_returned;
+ DWORD io_result;
+ PyObject *po, *result;
+ HANDLE reparse_point_handle;
- if (!PyArg_ParseTuple(args, "iO:ftruncate", &fd, &lenobj))
- return NULL;
+ char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
+ wchar_t *print_name;
-#if !defined(HAVE_LARGEFILE_SUPPORT)
- length = PyLong_AsLong(lenobj);
-#else
- length = PyLong_Check(lenobj) ?
- PyLong_AsLongLong(lenobj) : PyLong_AsLong(lenobj);
-#endif
- if (PyErr_Occurred())
+ if (!PyArg_ParseTuple(args,
+ "U:readlink",
+ &po))
+ return NULL;
+ path = PyUnicode_AsUnicode(po);
+ if (path == NULL)
return NULL;
+ /* First get a handle to the reparse point */
Py_BEGIN_ALLOW_THREADS
- res = ftruncate(fd, length);
+ reparse_point_handle = CreateFileW(
+ path,
+ 0,
+ 0,
+ 0,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
+ 0);
Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error();
- Py_INCREF(Py_None);
- return Py_None;
-}
-#endif
-#ifdef HAVE_PUTENV
-PyDoc_STRVAR(posix_putenv__doc__,
-"putenv(key, value)\n\n\
-Change or add an environment variable.");
+ if (reparse_point_handle==INVALID_HANDLE_VALUE)
+ return win32_error_object("readlink", po);
-/* Save putenv() parameters as values here, so we can collect them when they
- * get re-set with another call for the same key. */
-static PyObject *posix_putenv_garbage;
+ Py_BEGIN_ALLOW_THREADS
+ /* New call DeviceIoControl to read the reparse point */
+ io_result = DeviceIoControl(
+ reparse_point_handle,
+ FSCTL_GET_REPARSE_POINT,
+ 0, 0, /* in buffer */
+ target_buffer, sizeof(target_buffer),
+ &n_bytes_returned,
+ 0 /* we're not using OVERLAPPED_IO */
+ );
+ CloseHandle(reparse_point_handle);
+ Py_END_ALLOW_THREADS
-static PyObject *
-posix_putenv(PyObject *self, PyObject *args)
-{
-#ifdef MS_WINDOWS
- wchar_t *s1, *s2;
- wchar_t *newenv;
-#else
- PyObject *os1, *os2;
- char *s1, *s2;
- char *newenv;
-#endif
- PyObject *newstr = NULL;
- size_t len;
+ if (io_result==0)
+ return win32_error_object("readlink", po);
-#ifdef MS_WINDOWS
- if (!PyArg_ParseTuple(args,
- "uu:putenv",
- &s1, &s2))
- return NULL;
-#else
- if (!PyArg_ParseTuple(args,
- "O&O&:putenv",
- PyUnicode_FSConverter, &os1,
- PyUnicode_FSConverter, &os2))
+ if (rdb->ReparseTag != IO_REPARSE_TAG_SYMLINK)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "not a symbolic link");
return NULL;
- s1 = PyBytes_AsString(os1);
- s2 = PyBytes_AsString(os2);
-#endif
+ }
+ print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer +
+ rdb->SymbolicLinkReparseBuffer.PrintNameOffset;
-#if defined(PYOS_OS2)
- if (stricmp(s1, "BEGINLIBPATH") == 0) {
- APIRET rc;
+ result = PyUnicode_FromWideChar(print_name,
+ rdb->SymbolicLinkReparseBuffer.PrintNameLength/2);
+ return result;
+}
- rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH);
- if (rc != NO_ERROR) {
- os2_error(rc);
- goto error;
- }
+#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
- } else if (stricmp(s1, "ENDLIBPATH") == 0) {
- APIRET rc;
+#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
- rc = DosSetExtLIBPATH(s2, END_LIBPATH);
- if (rc != NO_ERROR) {
- os2_error(rc);
- goto error;
- }
- } else {
-#endif
- /* XXX This can leak memory -- not easy to fix :-( */
- /* len includes space for a trailing \0; the size arg to
- PyBytes_FromStringAndSize does not count that */
-#ifdef MS_WINDOWS
- len = wcslen(s1) + wcslen(s2) + 2;
- if (_MAX_ENV < (len - 1)) {
- PyErr_Format(PyExc_ValueError,
- "the environment variable is longer than %u characters",
- _MAX_ENV);
- goto error;
+/* Grab CreateSymbolicLinkW dynamically from kernel32 */
+static int has_CreateSymbolicLinkW = 0;
+static DWORD (CALLBACK *Py_CreateSymbolicLinkW)(LPWSTR, LPWSTR, DWORD);
+static int
+check_CreateSymbolicLinkW()
+{
+ HINSTANCE hKernel32;
+ /* only recheck */
+ if (has_CreateSymbolicLinkW)
+ return has_CreateSymbolicLinkW;
+ hKernel32 = GetModuleHandleW(L"KERNEL32");
+ *(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32,
+ "CreateSymbolicLinkW");
+ if (Py_CreateSymbolicLinkW)
+ has_CreateSymbolicLinkW = 1;
+ return has_CreateSymbolicLinkW;
+}
+
+PyDoc_STRVAR(win_symlink__doc__,
+"symlink(src, dst, target_is_directory=False)\n\n\
+Create a symbolic link pointing to src named dst.\n\
+target_is_directory is required if the target is to be interpreted as\n\
+a directory.\n\
+This function requires Windows 6.0 or greater, and raises a\n\
+NotImplementedError otherwise.");
+
+static PyObject *
+win_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"src", "dest", "target_is_directory", NULL};
+ PyObject *osrc, *odest;
+ PyObject *usrc = NULL, *udest = NULL;
+ wchar_t *wsrc, *wdest;
+ int target_is_directory = 0;
+ DWORD res;
- WIN32_FILE_ATTRIBUTE_DATA src_info;
+
+ if (!check_CreateSymbolicLinkW())
+ {
+ /* raise NotImplementedError */
+ return PyErr_Format(PyExc_NotImplementedError,
+ "CreateSymbolicLinkW not found");
}
- newstr = PyUnicode_FromUnicode(NULL, (int)len - 1);
-#else
- len = PyBytes_GET_SIZE(os1) + PyBytes_GET_SIZE(os2) + 2;
- newstr = PyBytes_FromStringAndSize(NULL, (int)len - 1);
-#endif
- if (newstr == NULL) {
- PyErr_NoMemory();
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, "OO|i:symlink", kwlist,
+ &osrc, &odest, &target_is_directory))
+ return NULL;
+
+ usrc = win32_decode_filename(osrc);
+ if (!usrc)
+ return NULL;
+ udest = win32_decode_filename(odest);
+ if (!udest)
goto error;
- }
-#ifdef MS_WINDOWS
- newenv = PyUnicode_AsUnicode(newstr);
- _snwprintf(newenv, len, L"%s=%s", s1, s2);
- if (_wputenv(newenv)) {
- posix_error();
+
+ if (win32_can_symlink == 0)
+ return PyErr_Format(PyExc_OSError, "symbolic link privilege not held");
+
+ wsrc = PyUnicode_AsUnicode(usrc);
+ if (wsrc == NULL)
goto error;
- }
-#else
- newenv = PyBytes_AS_STRING(newstr);
- PyOS_snprintf(newenv, len, "%s=%s", s1, s2);
- if (putenv(newenv)) {
- posix_error();
+ wdest = PyUnicode_AsUnicode(udest);
+ if (wsrc == NULL)
goto error;
- }
-#endif
- /* if src is a directory, ensure target_is_directory==1 */
- if(
- GetFileAttributesExW(
- wsrc, GetFileExInfoStandard, &src_info
- ))
- {
- target_is_directory = target_is_directory ||
- (src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
- /* Install the first arg and newstr in posix_putenv_garbage;
- * this will cause previous value to be collected. This has to
- * happen after the real putenv() call because the old value
- * was still accessible until then. */
- if (PyDict_SetItem(posix_putenv_garbage,
-#ifdef MS_WINDOWS
- PyTuple_GET_ITEM(args, 0),
-#else
- os1,
-#endif
- newstr)) {
- /* really not much we can do; just leak */
- PyErr_Clear();
-- }
-
- else {
- Py_DECREF(newstr);
- }
+ Py_BEGIN_ALLOW_THREADS
+ res = Py_CreateSymbolicLinkW(wdest, wsrc, target_is_directory);
+ Py_END_ALLOW_THREADS
-#if defined(PYOS_OS2)
- }
-#endif
+ Py_DECREF(usrc);
+ Py_DECREF(udest);
+ if (!res)
+ return win32_error_object("symlink", osrc);
-#ifndef MS_WINDOWS
- Py_DECREF(os1);
- Py_DECREF(os2);
-#endif
- Py_RETURN_NONE;
+ Py_INCREF(Py_None);
+ return Py_None;
error:
-#ifndef MS_WINDOWS
- Py_DECREF(os1);
- Py_DECREF(os2);
-#endif
- Py_XDECREF(newstr);
+ Py_XDECREF(usrc);
+ Py_XDECREF(udest);
return NULL;
}
-#endif /* putenv */
-
-#ifdef HAVE_UNSETENV
-PyDoc_STRVAR(posix_unsetenv__doc__,
-"unsetenv(key)\n\n\
-Delete an environment variable.");
+#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
-static PyObject *
-posix_unsetenv(PyObject *self, PyObject *args)
+#ifdef HAVE_TIMES
+#if defined(PYCC_VACPP) && defined(PYOS_OS2)
+static long
+system_uptime(void)
{
- PyObject *os1;
- char *s1;
-#ifndef HAVE_BROKEN_UNSETENV
- int err;
-#endif
-
- if (!PyArg_ParseTuple(args, "O&:unsetenv",
- PyUnicode_FSConverter, &os1))
- return NULL;
- s1 = PyBytes_AsString(os1);
-
-#ifdef HAVE_BROKEN_UNSETENV
- unsetenv(s1);
-#else
- err = unsetenv(s1);
- if (err) {
- Py_DECREF(os1);
- return posix_error();
- }
-#endif
+ ULONG value = 0;
- /* Remove the key from posix_putenv_garbage;
- * this will cause it to be collected. This has to
- * happen after the real unsetenv() call because the
- * old value was still accessible until then.
- */
- if (PyDict_DelItem(posix_putenv_garbage, os1)) {
- /* really not much we can do; just leak */
- PyErr_Clear();
- }
+ Py_BEGIN_ALLOW_THREADS
+ DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &value, sizeof(value));
+ Py_END_ALLOW_THREADS
- Py_DECREF(os1);
- Py_RETURN_NONE;
+ return value;
}
-#endif /* unsetenv */
-
-PyDoc_STRVAR(posix_strerror__doc__,
-"strerror(code) -> string\n\n\
-Translate an error code to a message string.");
static PyObject *
-posix_strerror(PyObject *self, PyObject *args)
+posix_times(PyObject *self, PyObject *noargs)
{
- int code;
- char *message;
- if (!PyArg_ParseTuple(args, "i:strerror", &code))
- return NULL;
- message = strerror(code);
- if (message == NULL) {
- PyErr_SetString(PyExc_ValueError,
- "strerror() argument out of range");
- return NULL;
- }
- return PyUnicode_FromString(message);
+ /* Currently Only Uptime is Provided -- Others Later */
+ return Py_BuildValue("ddddd",
+ (double)0 /* t.tms_utime / HZ */,
+ (double)0 /* t.tms_stime / HZ */,
+ (double)0 /* t.tms_cutime / HZ */,
+ (double)0 /* t.tms_cstime / HZ */,
+ (double)system_uptime() / 1000);
}
-
-
-#ifdef HAVE_SYS_WAIT_H
-
-#ifdef WCOREDUMP
-PyDoc_STRVAR(posix_WCOREDUMP__doc__,
-"WCOREDUMP(status) -> bool\n\n\
-Return True if the process returning 'status' was dumped to a core file.");
-
+#else /* not OS2 */
+#define NEED_TICKS_PER_SECOND
+static long ticks_per_second = -1;
static PyObject *
-posix_WCOREDUMP(PyObject *self, PyObject *args)
+posix_times(PyObject *self, PyObject *noargs)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
-
- if (!PyArg_ParseTuple(args, "i:WCOREDUMP", &WAIT_STATUS_INT(status)))
- return NULL;
-
- return PyBool_FromLong(WCOREDUMP(status));
+ struct tms t;
+ clock_t c;
+ errno = 0;
+ c = times(&t);
+ if (c == (clock_t) -1)
+ return posix_error();
+ return Py_BuildValue("ddddd",
+ (double)t.tms_utime / ticks_per_second,
+ (double)t.tms_stime / ticks_per_second,
+ (double)t.tms_cutime / ticks_per_second,
+ (double)t.tms_cstime / ticks_per_second,
+ (double)c / ticks_per_second);
}
-#endif /* WCOREDUMP */
+#endif /* not OS2 */
+#endif /* HAVE_TIMES */
-#ifdef WIFCONTINUED
-PyDoc_STRVAR(posix_WIFCONTINUED__doc__,
-"WIFCONTINUED(status) -> bool\n\n\
-Return True if the process returning 'status' was continued from a\n\
-job control stop.");
+#ifdef MS_WINDOWS
+#define HAVE_TIMES /* so the method table will pick it up */
static PyObject *
-posix_WIFCONTINUED(PyObject *self, PyObject *args)
+posix_times(PyObject *self, PyObject *noargs)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
-
- if (!PyArg_ParseTuple(args, "i:WCONTINUED", &WAIT_STATUS_INT(status)))
- return NULL;
-
- return PyBool_FromLong(WIFCONTINUED(status));
-}
-#endif /* WIFCONTINUED */
+ FILETIME create, exit, kernel, user;
+ HANDLE hProc;
+ hProc = GetCurrentProcess();
+ GetProcessTimes(hProc, &create, &exit, &kernel, &user);
+ /* The fields of a FILETIME structure are the hi and lo part
+ of a 64-bit value expressed in 100 nanosecond units.
+ 1e7 is one second in such units; 1e-7 the inverse.
+ 429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
+ */
+ return Py_BuildValue(
+ "ddddd",
+ (double)(user.dwHighDateTime*429.4967296 +
+ user.dwLowDateTime*1e-7),
+ (double)(kernel.dwHighDateTime*429.4967296 +
+ kernel.dwLowDateTime*1e-7),
+ (double)0,
+ (double)0,
+ (double)0);
+}
+#endif /* MS_WINDOWS */
-#ifdef WIFSTOPPED
-PyDoc_STRVAR(posix_WIFSTOPPED__doc__,
-"WIFSTOPPED(status) -> bool\n\n\
-Return True if the process returning 'status' was stopped.");
+#ifdef HAVE_TIMES
+PyDoc_STRVAR(posix_times__doc__,
+"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n\
+Return a tuple of floating point numbers indicating process times.");
+#endif
+
+
+#ifdef HAVE_GETSID
+PyDoc_STRVAR(posix_getsid__doc__,
+"getsid(pid) -> sid\n\n\
+Call the system call getsid().");
static PyObject *
-posix_WIFSTOPPED(PyObject *self, PyObject *args)
+posix_getsid(PyObject *self, PyObject *args)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
-
- if (!PyArg_ParseTuple(args, "i:WIFSTOPPED", &WAIT_STATUS_INT(status)))
+ pid_t pid;
+ int sid;
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getsid", &pid))
return NULL;
-
- return PyBool_FromLong(WIFSTOPPED(status));
+ sid = getsid(pid);
+ if (sid < 0)
+ return posix_error();
+ return PyLong_FromLong((long)sid);
}
-#endif /* WIFSTOPPED */
+#endif /* HAVE_GETSID */
-#ifdef WIFSIGNALED
-PyDoc_STRVAR(posix_WIFSIGNALED__doc__,
-"WIFSIGNALED(status) -> bool\n\n\
-Return True if the process returning 'status' was terminated by a signal.");
+
+#ifdef HAVE_SETSID
+PyDoc_STRVAR(posix_setsid__doc__,
+"setsid()\n\n\
+Call the system call setsid().");
static PyObject *
-posix_WIFSIGNALED(PyObject *self, PyObject *args)
+posix_setsid(PyObject *self, PyObject *noargs)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
+ if (setsid() < 0)
+ return posix_error();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif /* HAVE_SETSID */
- if (!PyArg_ParseTuple(args, "i:WIFSIGNALED", &WAIT_STATUS_INT(status)))
- return NULL;
+#ifdef HAVE_SETPGID
+PyDoc_STRVAR(posix_setpgid__doc__,
+"setpgid(pid, pgrp)\n\n\
+Call the system call setpgid().");
- return PyBool_FromLong(WIFSIGNALED(status));
+static PyObject *
+posix_setpgid(PyObject *self, PyObject *args)
+{
+ pid_t pid;
+ int pgrp;
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:setpgid", &pid, &pgrp))
+ return NULL;
+ if (setpgid(pid, pgrp) < 0)
+ return posix_error();
+ Py_INCREF(Py_None);
+ return Py_None;
}
-#endif /* WIFSIGNALED */
+#endif /* HAVE_SETPGID */
-#ifdef WIFEXITED
-PyDoc_STRVAR(posix_WIFEXITED__doc__,
-"WIFEXITED(status) -> bool\n\n\
-Return true if the process returning 'status' exited using the exit()\n\
-system call.");
+
+#ifdef HAVE_TCGETPGRP
+PyDoc_STRVAR(posix_tcgetpgrp__doc__,
+"tcgetpgrp(fd) -> pgid\n\n\
+Return the process group associated with the terminal given by a fd.");
static PyObject *
-posix_WIFEXITED(PyObject *self, PyObject *args)
+posix_tcgetpgrp(PyObject *self, PyObject *args)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
-
- if (!PyArg_ParseTuple(args, "i:WIFEXITED", &WAIT_STATUS_INT(status)))
+ int fd;
+ pid_t pgid;
+ if (!PyArg_ParseTuple(args, "i:tcgetpgrp", &fd))
return NULL;
-
- return PyBool_FromLong(WIFEXITED(status));
+ pgid = tcgetpgrp(fd);
+ if (pgid < 0)
+ return posix_error();
+ return PyLong_FromPid(pgid);
}
-#endif /* WIFEXITED */
+#endif /* HAVE_TCGETPGRP */
-#ifdef WEXITSTATUS
-PyDoc_STRVAR(posix_WEXITSTATUS__doc__,
-"WEXITSTATUS(status) -> integer\n\n\
-Return the process return code from 'status'.");
+
+#ifdef HAVE_TCSETPGRP
+PyDoc_STRVAR(posix_tcsetpgrp__doc__,
+"tcsetpgrp(fd, pgid)\n\n\
+Set the process group associated with the terminal given by a fd.");
static PyObject *
-posix_WEXITSTATUS(PyObject *self, PyObject *args)
+posix_tcsetpgrp(PyObject *self, PyObject *args)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
-
- if (!PyArg_ParseTuple(args, "i:WEXITSTATUS", &WAIT_STATUS_INT(status)))
+ int fd;
+ pid_t pgid;
+ if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID ":tcsetpgrp", &fd, &pgid))
return NULL;
-
- return Py_BuildValue("i", WEXITSTATUS(status));
+ if (tcsetpgrp(fd, pgid) < 0)
+ return posix_error();
+ Py_INCREF(Py_None);
+ return Py_None;
}
-#endif /* WEXITSTATUS */
+#endif /* HAVE_TCSETPGRP */
-#ifdef WTERMSIG
-PyDoc_STRVAR(posix_WTERMSIG__doc__,
-"WTERMSIG(status) -> integer\n\n\
-Return the signal that terminated the process that provided the 'status'\n\
-value.");
+/* Functions acting on file descriptors */
+
+PyDoc_STRVAR(posix_open__doc__,
+"open(filename, flag [, mode=0777]) -> fd\n\n\
+Open a file (for low level IO).");
static PyObject *
-posix_WTERMSIG(PyObject *self, PyObject *args)
+posix_open(PyObject *self, PyObject *args)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
+ PyObject *ofile;
+ char *file;
+ int flag;
+ int mode = 0777;
+ int fd;
- if (!PyArg_ParseTuple(args, "i:WTERMSIG", &WAIT_STATUS_INT(status)))
- return NULL;
+#ifdef MS_WINDOWS
+ PyObject *po;
+ if (PyArg_ParseTuple(args, "Ui|i:open", &po, &flag, &mode)) {
+ wchar_t *wpath = PyUnicode_AsUnicode(po);
+ if (wpath == NULL)
+ return NULL;
- return Py_BuildValue("i", WTERMSIG(status));
+ Py_BEGIN_ALLOW_THREADS
+ fd = _wopen(wpath, flag, mode);
+ Py_END_ALLOW_THREADS
+ if (fd < 0)
+ return posix_error();
+ return PyLong_FromLong((long)fd);
+ }
+ /* Drop the argument parsing error as narrow strings
+ are also valid. */
+ PyErr_Clear();
+#endif
+
+ if (!PyArg_ParseTuple(args, "O&i|i:open",
+ PyUnicode_FSConverter, &ofile,
+ &flag, &mode))
+ return NULL;
+#ifdef MS_WINDOWS
+ if (win32_warn_bytes_api()) {
+ Py_DECREF(ofile);
+ return NULL;
+ }
+#endif
+ file = PyBytes_AsString(ofile);
+ Py_BEGIN_ALLOW_THREADS
+ fd = open(file, flag, mode);
+ Py_END_ALLOW_THREADS
+ if (fd < 0)
+ return posix_error_with_allocated_filename(ofile);
+ Py_DECREF(ofile);
+ return PyLong_FromLong((long)fd);
}
-#endif /* WTERMSIG */
-#ifdef WSTOPSIG
-PyDoc_STRVAR(posix_WSTOPSIG__doc__,
-"WSTOPSIG(status) -> integer\n\n\
-Return the signal that stopped the process that provided\n\
-the 'status' value.");
+
+PyDoc_STRVAR(posix_close__doc__,
+"close(fd)\n\n\
+Close a file descriptor (for low level IO).");
static PyObject *
-posix_WSTOPSIG(PyObject *self, PyObject *args)
+posix_close(PyObject *self, PyObject *args)
{
- WAIT_TYPE status;
- WAIT_STATUS_INT(status) = 0;
-
- if (!PyArg_ParseTuple(args, "i:WSTOPSIG", &WAIT_STATUS_INT(status)))
+ int fd, res;
+ if (!PyArg_ParseTuple(args, "i:close", &fd))
return NULL;
-
- return Py_BuildValue("i", WSTOPSIG(status));
+ if (!_PyVerify_fd(fd))
+ return posix_error();
+ Py_BEGIN_ALLOW_THREADS
+ res = close(fd);
+ Py_END_ALLOW_THREADS
+ if (res < 0)
+ return posix_error();
+ Py_INCREF(Py_None);
+ return Py_None;
}
-#endif /* WSTOPSIG */
-
-#endif /* HAVE_SYS_WAIT_H */
-#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H)
-#ifdef _SCO_DS
-/* SCO OpenServer 5.0 and later requires _SVID3 before it reveals the
- needed definitions in sys/statvfs.h */
-#define _SVID3
-#endif
-#include <sys/statvfs.h>
+PyDoc_STRVAR(posix_closerange__doc__,
+"closerange(fd_low, fd_high)\n\n\
+Closes all file descriptors in [fd_low, fd_high), ignoring errors.");
-static PyObject*
-_pystatvfs_fromstructstatvfs(struct statvfs st) {
- PyObject *v = PyStructSequence_New(&StatVFSResultType);
- if (v == NULL)
+static PyObject *
+posix_closerange(PyObject *self, PyObject *args)
+{
+ int fd_from, fd_to, i;
+ if (!PyArg_ParseTuple(args, "ii:closerange", &fd_from, &fd_to))
return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ for (i = fd_from; i < fd_to; i++)
+ if (_PyVerify_fd(i))
+ close(i);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
-#if !defined(HAVE_LARGEFILE_SUPPORT)
- PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
- PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
- PyStructSequence_SET_ITEM(v, 2, PyLong_FromLong((long) st.f_blocks));
- PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long) st.f_bfree));
- PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong((long) st.f_bavail));
- PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong((long) st.f_files));
- PyStructSequence_SET_ITEM(v, 6, PyLong_FromLong((long) st.f_ffree));
- PyStructSequence_SET_ITEM(v, 7, PyLong_FromLong((long) st.f_favail));
- PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
- PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
-#else
- PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
- PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
- PyStructSequence_SET_ITEM(v, 2,
- PyLong_FromLongLong((PY_LONG_LONG) st.f_blocks));
- PyStructSequence_SET_ITEM(v, 3,
- PyLong_FromLongLong((PY_LONG_LONG) st.f_bfree));
- PyStructSequence_SET_ITEM(v, 4,
- PyLong_FromLongLong((PY_LONG_LONG) st.f_bavail));
- PyStructSequence_SET_ITEM(v, 5,
- PyLong_FromLongLong((PY_LONG_LONG) st.f_files));
- PyStructSequence_SET_ITEM(v, 6,
- PyLong_FromLongLong((PY_LONG_LONG) st.f_ffree));
- PyStructSequence_SET_ITEM(v, 7,
- PyLong_FromLongLong((PY_LONG_LONG) st.f_favail));
- PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
- PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
-#endif
- return v;
+PyDoc_STRVAR(posix_dup__doc__,
+"dup(fd) -> fd2\n\n\
+Return a duplicate of a file descriptor.");
+
+static PyObject *
+posix_dup(PyObject *self, PyObject *args)
+{
+ int fd;
+ if (!PyArg_ParseTuple(args, "i:dup", &fd))
+ return NULL;
+ if (!_PyVerify_fd(fd))
+ return posix_error();
+ fd = dup(fd);
+ if (fd < 0)
+ return posix_error();
+ return PyLong_FromLong((long)fd);
}
-PyDoc_STRVAR(posix_fstatvfs__doc__,
-"fstatvfs(fd) -> statvfs result\n\n\
-Perform an fstatvfs system call on the given fd.");
+
+PyDoc_STRVAR(posix_dup2__doc__,
+"dup2(old_fd, new_fd)\n\n\
+Duplicate file descriptor.");
static PyObject *
-posix_fstatvfs(PyObject *self, PyObject *args)
+posix_dup2(PyObject *self, PyObject *args)
{
- int fd, res;
- struct statvfs st;
+ int fd, fd2, res;
+ if (!PyArg_ParseTuple(args, "ii:dup2", &fd, &fd2))
+ return NULL;
+ if (!_PyVerify_fd_dup2(fd, fd2))
+ return posix_error();
+ res = dup2(fd, fd2);
+ if (res < 0)
+ return posix_error();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
- if (!PyArg_ParseTuple(args, "i:fstatvfs", &fd))
+#ifdef HAVE_LOCKF
+PyDoc_STRVAR(posix_lockf__doc__,
+"lockf(fd, cmd, len)\n\n\
+Apply, test or remove a POSIX lock on an open file descriptor.\n\n\
+fd is an open file descriptor.\n\
+cmd specifies the command to use - one of F_LOCK, F_TLOCK, F_ULOCK or\n\
+F_TEST.\n\
+len specifies the section of the file to lock.");
+
+static PyObject *
+posix_lockf(PyObject *self, PyObject *args)
+{
+ int fd, cmd, res;
+ off_t len;
+ if (!PyArg_ParseTuple(args, "iiO&:lockf",
+ &fd, &cmd, _parse_off_t, &len))
return NULL;
+
Py_BEGIN_ALLOW_THREADS
- res = fstatvfs(fd, &st);
+ res = lockf(fd, cmd, len);
Py_END_ALLOW_THREADS
- if (res != 0)
+
+ if (res < 0)
return posix_error();
- return _pystatvfs_fromstructstatvfs(st);
+ Py_RETURN_NONE;
}
-#endif /* HAVE_FSTATVFS && HAVE_SYS_STATVFS_H */
-
+#endif
-#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
-#include <sys/statvfs.h>
-PyDoc_STRVAR(posix_statvfs__doc__,
-"statvfs(path) -> statvfs result\n\n\
-Perform a statvfs system call on the given path.");
+PyDoc_STRVAR(posix_lseek__doc__,
+"lseek(fd, pos, how) -> newpos\n\n\
+Set the current position of a file descriptor.\n\
+Return the new cursor position in bytes, starting from the beginning.");
static PyObject *
-posix_statvfs(PyObject *self, PyObject *args)
+posix_lseek(PyObject *self, PyObject *args)
{
- char *path;
- int res;
- struct statvfs st;
- if (!PyArg_ParseTuple(args, "s:statvfs", &path))
+ int fd, how;
+#if defined(MS_WIN64) || defined(MS_WINDOWS)
+ PY_LONG_LONG pos, res;
+#else
+ off_t pos, res;
+#endif
+ PyObject *posobj;
+ if (!PyArg_ParseTuple(args, "iOi:lseek", &fd, &posobj, &how))
+ return NULL;
+#ifdef SEEK_SET
+ /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
+ switch (how) {
+ case 0: how = SEEK_SET; break;
+ case 1: how = SEEK_CUR; break;
+ case 2: how = SEEK_END; break;
+ }
+#endif /* SEEK_END */
+
+#if !defined(HAVE_LARGEFILE_SUPPORT)
+ pos = PyLong_AsLong(posobj);
+#else
+ pos = PyLong_AsLongLong(posobj);
+#endif
+ if (PyErr_Occurred())
return NULL;
+
+ if (!_PyVerify_fd(fd))
+ return posix_error();
Py_BEGIN_ALLOW_THREADS
- res = statvfs(path, &st);
+#if defined(MS_WIN64) || defined(MS_WINDOWS)
+ res = _lseeki64(fd, pos, how);
+#else
+ res = lseek(fd, pos, how);
+#endif
Py_END_ALLOW_THREADS
- if (res != 0)
- return posix_error_with_filename(path);
+ if (res < 0)
+ return posix_error();
- return _pystatvfs_fromstructstatvfs(st);
+#if !defined(HAVE_LARGEFILE_SUPPORT)
+ return PyLong_FromLong(res);
+#else
+ return PyLong_FromLongLong(res);
+#endif
}
-#endif /* HAVE_STATVFS */
-/* This is used for fpathconf(), pathconf(), confstr() and sysconf().
- * It maps strings representing configuration variable names to
- * integer values, allowing those functions to be called with the
- * magic names instead of polluting the module's namespace with tons of
- * rarely-used constants. There are three separate tables that use
- * these definitions.
- *
- * This code is always included, even if none of the interfaces that
- * need it are included. The #if hackery needed to avoid it would be
- * sufficiently pervasive that it's not worth the loss of readability.
- */
-struct constdef {
- char *name;
- long value;
-};
-static int
-conv_confname(PyObject *arg, int *valuep, struct constdef *table,
- size_t tablesize)
+PyDoc_STRVAR(posix_read__doc__,
+"read(fd, buffersize) -> string\n\n\
+Read a file descriptor.");
+
+static PyObject *
+posix_read(PyObject *self, PyObject *args)
{
- if (PyLong_Check(arg)) {
- *valuep = PyLong_AS_LONG(arg);
- return 1;
+ int fd, size;
+ Py_ssize_t n;
+ PyObject *buffer;
+ if (!PyArg_ParseTuple(args, "ii:read", &fd, &size))
+ return NULL;
+ if (size < 0) {
+ errno = EINVAL;
+ return posix_error();
}
- else {
- /* look up the value in the table using a binary search */
- size_t lo = 0;
- size_t mid;
- size_t hi = tablesize;
- int cmp;
- const char *confname;
- if (!PyUnicode_Check(arg)) {
- PyErr_SetString(PyExc_TypeError,
- "configuration names must be strings or integers");
- return 0;
- }
- confname = _PyUnicode_AsString(arg);
- if (confname == NULL)
- return 0;
- while (lo < hi) {
- mid = (lo + hi) / 2;
- cmp = strcmp(confname, table[mid].name);
- if (cmp < 0)
- hi = mid;
- else if (cmp > 0)
- lo = mid + 1;
- else {
- *valuep = table[mid].value;
- return 1;
- }
+ buffer = PyBytes_FromStringAndSize((char *)NULL, size);
+ if (buffer == NULL)
+ return NULL;
+ if (!_PyVerify_fd(fd)) {
+ Py_DECREF(buffer);
+ return posix_error();
+ }
+ Py_BEGIN_ALLOW_THREADS
+ n = read(fd, PyBytes_AS_STRING(buffer), size);
+ Py_END_ALLOW_THREADS
+ if (n < 0) {
+ Py_DECREF(buffer);
+ return posix_error();
+ }
+ if (n != size)
+ _PyBytes_Resize(&buffer, n);
+ return buffer;
+}
+
+#if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
+ || defined(__APPLE__))) || defined(HAVE_READV) || defined(HAVE_WRITEV)
+static Py_ssize_t
+iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, int cnt, int type)
+{
+ int i, j;
+ Py_ssize_t blen, total = 0;
+
+ *iov = PyMem_New(struct iovec, cnt);
+ if (*iov == NULL) {
+ PyErr_NoMemory();
+ return total;
+ }
+
+ *buf = PyMem_New(Py_buffer, cnt);
+ if (*buf == NULL) {
+ PyMem_Del(*iov);
+ PyErr_NoMemory();
+ return total;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ PyObject *item = PySequence_GetItem(seq, i);
+ if (item == NULL)
+ goto fail;
+ if (PyObject_GetBuffer(item, &(*buf)[i], type) == -1) {
+ Py_DECREF(item);
+ goto fail;
}
- PyErr_SetString(PyExc_ValueError, "unrecognized configuration name");
- return 0;
+ Py_DECREF(item);
+ (*iov)[i].iov_base = (*buf)[i].buf;
+ blen = (*buf)[i].len;
+ (*iov)[i].iov_len = blen;
+ total += blen;
+ }
+ return total;
+
+fail:
+ PyMem_Del(*iov);
+ for (j = 0; j < i; j++) {
+ PyBuffer_Release(&(*buf)[j]);
+ }
+ PyMem_Del(*buf);
+ return 0;
+}
+
+static void
+iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt)
+{
+ int i;
+ PyMem_Del(iov);
+ for (i = 0; i < cnt; i++) {
+ PyBuffer_Release(&buf[i]);
}
+ PyMem_Del(buf);
}
+#endif
+#ifdef HAVE_READV
+PyDoc_STRVAR(posix_readv__doc__,
+"readv(fd, buffers) -> bytesread\n\n\
+Read from a file descriptor into a number of writable buffers. buffers\n\
+is an arbitrary sequence of writable buffers.\n\
+Returns the total number of bytes read.");
-#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
-static struct constdef posix_constants_pathconf[] = {
-#ifdef _PC_ABI_AIO_XFER_MAX
- {"PC_ABI_AIO_XFER_MAX", _PC_ABI_AIO_XFER_MAX},
+static PyObject *
+posix_readv(PyObject *self, PyObject *args)
+{
+ int fd, cnt;
+ Py_ssize_t n;
+ PyObject *seq;
+ struct iovec *iov;
+ Py_buffer *buf;
+
+ if (!PyArg_ParseTuple(args, "iO:readv", &fd, &seq))
+ return NULL;
+ if (!PySequence_Check(seq)) {
+ PyErr_SetString(PyExc_TypeError,
+ "readv() arg 2 must be a sequence");
+ return NULL;
+ }
+ cnt = PySequence_Size(seq);
+
+ if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ n = readv(fd, iov, cnt);
+ Py_END_ALLOW_THREADS
+
+ iov_cleanup(iov, buf, cnt);
+ return PyLong_FromSsize_t(n);
+}
#endif
-#ifdef _PC_ABI_ASYNC_IO
- {"PC_ABI_ASYNC_IO", _PC_ABI_ASYNC_IO},
-#endif
-#ifdef _PC_ASYNC_IO
- {"PC_ASYNC_IO", _PC_ASYNC_IO},
-#endif
-#ifdef _PC_CHOWN_RESTRICTED
- {"PC_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED},
-#endif
-#ifdef _PC_FILESIZEBITS
- {"PC_FILESIZEBITS", _PC_FILESIZEBITS},
-#endif
-#ifdef _PC_LAST
- {"PC_LAST", _PC_LAST},
-#endif
-#ifdef _PC_LINK_MAX
- {"PC_LINK_MAX", _PC_LINK_MAX},
-#endif
-#ifdef _PC_MAX_CANON
- {"PC_MAX_CANON", _PC_MAX_CANON},
-#endif
-#ifdef _PC_MAX_INPUT
- {"PC_MAX_INPUT", _PC_MAX_INPUT},
-#endif
-#ifdef _PC_NAME_MAX
- {"PC_NAME_MAX", _PC_NAME_MAX},
-#endif
-#ifdef _PC_NO_TRUNC
- {"PC_NO_TRUNC", _PC_NO_TRUNC},
-#endif
-#ifdef _PC_PATH_MAX
- {"PC_PATH_MAX", _PC_PATH_MAX},
-#endif
-#ifdef _PC_PIPE_BUF
- {"PC_PIPE_BUF", _PC_PIPE_BUF},
-#endif
-#ifdef _PC_PRIO_IO
- {"PC_PRIO_IO", _PC_PRIO_IO},
-#endif
-#ifdef _PC_SOCK_MAXBUF
- {"PC_SOCK_MAXBUF", _PC_SOCK_MAXBUF},
-#endif
-#ifdef _PC_SYNC_IO
- {"PC_SYNC_IO", _PC_SYNC_IO},
-#endif
-#ifdef _PC_VDISABLE
- {"PC_VDISABLE", _PC_VDISABLE},
-#endif
-#ifdef _PC_ACL_ENABLED
- {"PC_ACL_ENABLED", _PC_ACL_ENABLED},
-#endif
-#ifdef _PC_MIN_HOLE_SIZE
- {"PC_MIN_HOLE_SIZE", _PC_MIN_HOLE_SIZE},
-#endif
-#ifdef _PC_ALLOC_SIZE_MIN
- {"PC_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN},
-#endif
-#ifdef _PC_REC_INCR_XFER_SIZE
- {"PC_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE},
-#endif
-#ifdef _PC_REC_MAX_XFER_SIZE
- {"PC_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE},
-#endif
-#ifdef _PC_REC_MIN_XFER_SIZE
- {"PC_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE},
-#endif
-#ifdef _PC_REC_XFER_ALIGN
- {"PC_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN},
-#endif
-#ifdef _PC_SYMLINK_MAX
- {"PC_SYMLINK_MAX", _PC_SYMLINK_MAX},
-#endif
-#ifdef _PC_XATTR_ENABLED
- {"PC_XATTR_ENABLED", _PC_XATTR_ENABLED},
-#endif
-#ifdef _PC_XATTR_EXISTS
- {"PC_XATTR_EXISTS", _PC_XATTR_EXISTS},
-#endif
-#ifdef _PC_TIMESTAMP_RESOLUTION
- {"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
-#endif
-};
-static int
-conv_path_confname(PyObject *arg, int *valuep)
+#ifdef HAVE_PREAD
+PyDoc_STRVAR(posix_pread__doc__,
+"pread(fd, buffersize, offset) -> string\n\n\
+Read from a file descriptor, fd, at a position of offset. It will read up\n\
+to buffersize number of bytes. The file offset remains unchanged.");
+
+static PyObject *
+posix_pread(PyObject *self, PyObject *args)
{
- return conv_confname(arg, valuep, posix_constants_pathconf,
- sizeof(posix_constants_pathconf)
- / sizeof(struct constdef));
+ int fd, size;
+ off_t offset;
+ Py_ssize_t n;
+ PyObject *buffer;
+ if (!PyArg_ParseTuple(args, "iiO&:pread", &fd, &size, _parse_off_t, &offset))
+ return NULL;
+
+ if (size < 0) {
+ errno = EINVAL;
+ return posix_error();
+ }
+ buffer = PyBytes_FromStringAndSize((char *)NULL, size);
+ if (buffer == NULL)
+ return NULL;
+ if (!_PyVerify_fd(fd)) {
+ Py_DECREF(buffer);
+ return posix_error();
+ }
+ Py_BEGIN_ALLOW_THREADS
+ n = pread(fd, PyBytes_AS_STRING(buffer), size, offset);
+ Py_END_ALLOW_THREADS
+ if (n < 0) {
+ Py_DECREF(buffer);
+ return posix_error();
+ }
+ if (n != size)
+ _PyBytes_Resize(&buffer, n);
+ return buffer;
}
#endif