mirror of https://github.com/python/cpython.git
445 lines
8.1 KiB
C
445 lines
8.1 KiB
C
|
/* POSIX module implementation */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <signal.h>
|
||
|
#include <string.h>
|
||
|
#include <setjmp.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/time.h>
|
||
|
#ifdef SYSV
|
||
|
#include <dirent.h>
|
||
|
#define direct dirent
|
||
|
#else
|
||
|
#include <sys/dir.h>
|
||
|
#endif
|
||
|
|
||
|
#include "PROTO.h"
|
||
|
#include "object.h"
|
||
|
#include "intobject.h"
|
||
|
#include "stringobject.h"
|
||
|
#include "tupleobject.h"
|
||
|
#include "listobject.h"
|
||
|
#include "dictobject.h"
|
||
|
#include "methodobject.h"
|
||
|
#include "moduleobject.h"
|
||
|
#include "objimpl.h"
|
||
|
#include "import.h"
|
||
|
#include "sigtype.h"
|
||
|
#include "modsupport.h"
|
||
|
#include "errors.h"
|
||
|
|
||
|
extern char *strerror();
|
||
|
|
||
|
#ifdef AMOEBA
|
||
|
#define NO_LSTAT
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* Return a dictionary corresponding to the POSIX environment table */
|
||
|
|
||
|
extern char **environ;
|
||
|
|
||
|
static object *
|
||
|
convertenviron()
|
||
|
{
|
||
|
object *d;
|
||
|
char **e;
|
||
|
d = newdictobject();
|
||
|
if (d == NULL)
|
||
|
return NULL;
|
||
|
if (environ == NULL)
|
||
|
return d;
|
||
|
/* XXX This part ignores errors */
|
||
|
for (e = environ; *e != NULL; e++) {
|
||
|
object *v;
|
||
|
char *p = strchr(*e, '=');
|
||
|
if (p == NULL)
|
||
|
continue;
|
||
|
v = newstringobject(p+1);
|
||
|
if (v == NULL)
|
||
|
continue;
|
||
|
*p = '\0';
|
||
|
(void) dictinsert(d, *e, v);
|
||
|
*p = '=';
|
||
|
DECREF(v);
|
||
|
}
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
|
||
|
static object *PosixError; /* Exception posix.error */
|
||
|
|
||
|
/* Set a POSIX-specific error from errno, and return NULL */
|
||
|
|
||
|
static object *
|
||
|
posix_error()
|
||
|
{
|
||
|
object *v = newtupleobject(2);
|
||
|
if (v != NULL) {
|
||
|
settupleitem(v, 0, newintobject((long)errno));
|
||
|
settupleitem(v, 1, newstringobject(strerror(errno)));
|
||
|
}
|
||
|
err_setval(PosixError, v);
|
||
|
if (v != NULL)
|
||
|
DECREF(v);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* POSIX generic methods */
|
||
|
|
||
|
static object *
|
||
|
posix_1str(args, func)
|
||
|
object *args;
|
||
|
int (*func) FPROTO((const char *));
|
||
|
{
|
||
|
object *path1;
|
||
|
if (!getstrarg(args, &path1))
|
||
|
return NULL;
|
||
|
if ((*func)(getstringvalue(path1)) < 0)
|
||
|
return posix_error();
|
||
|
INCREF(None);
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_2str(args, func)
|
||
|
object *args;
|
||
|
int (*func) FPROTO((const char *, const char *));
|
||
|
{
|
||
|
object *path1, *path2;
|
||
|
if (!getstrstrarg(args, &path1, &path2))
|
||
|
return NULL;
|
||
|
if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0)
|
||
|
return posix_error();
|
||
|
INCREF(None);
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_strint(args, func)
|
||
|
object *args;
|
||
|
int (*func) FPROTO((const char *, int));
|
||
|
{
|
||
|
object *path1;
|
||
|
int i;
|
||
|
if (!getstrintarg(args, &path1, &i))
|
||
|
return NULL;
|
||
|
if ((*func)(getstringvalue(path1), i) < 0)
|
||
|
return posix_error();
|
||
|
INCREF(None);
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_do_stat(self, args, statfunc)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
int (*statfunc) FPROTO((const char *, struct stat *));
|
||
|
{
|
||
|
struct stat st;
|
||
|
object *path;
|
||
|
object *v;
|
||
|
if (!getstrarg(args, &path))
|
||
|
return NULL;
|
||
|
if ((*statfunc)(getstringvalue(path), &st) != 0)
|
||
|
return posix_error();
|
||
|
v = newtupleobject(10);
|
||
|
if (v == NULL)
|
||
|
return NULL;
|
||
|
errno = 0;
|
||
|
#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member))
|
||
|
SET(0, st_mode);
|
||
|
SET(1, st_ino);
|
||
|
SET(2, st_dev);
|
||
|
SET(3, st_nlink);
|
||
|
SET(4, st_uid);
|
||
|
SET(5, st_gid);
|
||
|
SET(6, st_size);
|
||
|
SET(7, st_atime);
|
||
|
SET(8, st_mtime);
|
||
|
SET(9, st_ctime);
|
||
|
#undef SET
|
||
|
if (errno != 0) {
|
||
|
DECREF(v);
|
||
|
return err_nomem();
|
||
|
}
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* POSIX methods */
|
||
|
|
||
|
static object *
|
||
|
posix_chdir(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int chdir PROTO((const char *));
|
||
|
return posix_1str(args, chdir);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_chmod(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int chmod PROTO((const char *, mode_t));
|
||
|
return posix_strint(args, chmod);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_getcwd(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
char buf[1026];
|
||
|
extern char *getcwd PROTO((char *, int));
|
||
|
if (!getnoarg(args))
|
||
|
return NULL;
|
||
|
if (getcwd(buf, sizeof buf) == NULL)
|
||
|
return posix_error();
|
||
|
return newstringobject(buf);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_link(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int link PROTO((const char *, const char *));
|
||
|
return posix_2str(args, link);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_listdir(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
object *name, *d, *v;
|
||
|
DIR *dirp;
|
||
|
struct direct *ep;
|
||
|
if (!getstrarg(args, &name))
|
||
|
return NULL;
|
||
|
if ((dirp = opendir(getstringvalue(name))) == NULL)
|
||
|
return posix_error();
|
||
|
if ((d = newlistobject(0)) == NULL) {
|
||
|
closedir(dirp);
|
||
|
return NULL;
|
||
|
}
|
||
|
while ((ep = readdir(dirp)) != NULL) {
|
||
|
v = newstringobject(ep->d_name);
|
||
|
if (v == NULL) {
|
||
|
DECREF(d);
|
||
|
d = NULL;
|
||
|
break;
|
||
|
}
|
||
|
if (addlistitem(d, v) != 0) {
|
||
|
DECREF(v);
|
||
|
DECREF(d);
|
||
|
d = NULL;
|
||
|
break;
|
||
|
}
|
||
|
DECREF(v);
|
||
|
}
|
||
|
closedir(dirp);
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_mkdir(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int mkdir PROTO((const char *, mode_t));
|
||
|
return posix_strint(args, mkdir);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_rename(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int rename PROTO((const char *, const char *));
|
||
|
return posix_2str(args, rename);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_rmdir(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int rmdir PROTO((const char *));
|
||
|
return posix_1str(args, rmdir);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_stat(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int stat PROTO((const char *, struct stat *));
|
||
|
return posix_do_stat(self, args, stat);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_system(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
object *command;
|
||
|
int sts;
|
||
|
if (!getstrarg(args, &command))
|
||
|
return NULL;
|
||
|
sts = system(getstringvalue(command));
|
||
|
return newintobject((long)sts);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_umask(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
int i;
|
||
|
if (!getintarg(args, &i))
|
||
|
return NULL;
|
||
|
i = umask(i);
|
||
|
if (i < 0)
|
||
|
return posix_error();
|
||
|
return newintobject((long)i);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_unlink(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int unlink PROTO((const char *));
|
||
|
return posix_1str(args, unlink);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_utimes(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
object *path;
|
||
|
struct timeval tv[2];
|
||
|
if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
|
||
|
err_badarg();
|
||
|
return NULL;
|
||
|
}
|
||
|
if (!getstrarg(gettupleitem(args, 0), &path) ||
|
||
|
!getlonglongargs(gettupleitem(args, 1),
|
||
|
&tv[0].tv_sec, &tv[1].tv_sec))
|
||
|
return NULL;
|
||
|
tv[0].tv_usec = tv[1].tv_usec = 0;
|
||
|
if (utimes(getstringvalue(path), tv) < 0)
|
||
|
return posix_error();
|
||
|
INCREF(None);
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
#ifdef NO_GETCWD
|
||
|
|
||
|
/* Quick hack to get posix.getcwd() working for pure BSD 4.3 */
|
||
|
/* XXX This assumes MAXPATHLEN = 1024 !!! */
|
||
|
|
||
|
static char *
|
||
|
getcwd(buf, size)
|
||
|
char *buf;
|
||
|
int size;
|
||
|
{
|
||
|
extern char *getwd PROTO((char *));
|
||
|
register char *ret = getwd(buf);
|
||
|
if (ret == NULL)
|
||
|
errno = EACCES; /* Most likely error */
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#endif /* NO_GETCWD */
|
||
|
|
||
|
|
||
|
#ifndef NO_LSTAT
|
||
|
|
||
|
static object *
|
||
|
posix_lstat(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int lstat PROTO((const char *, struct stat *));
|
||
|
return posix_do_stat(self, args, lstat);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_readlink(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
char buf[1024]; /* XXX Should use MAXPATHLEN */
|
||
|
object *path;
|
||
|
int n;
|
||
|
if (!getstrarg(args, &path))
|
||
|
return NULL;
|
||
|
n = readlink(getstringvalue(path), buf, sizeof buf);
|
||
|
if (n < 0)
|
||
|
return posix_error();
|
||
|
return newsizedstringobject(buf, n);
|
||
|
}
|
||
|
|
||
|
static object *
|
||
|
posix_symlink(self, args)
|
||
|
object *self;
|
||
|
object *args;
|
||
|
{
|
||
|
extern int symlink PROTO((const char *, const char *));
|
||
|
return posix_2str(args, symlink);
|
||
|
}
|
||
|
|
||
|
#endif /* NO_LSTAT */
|
||
|
|
||
|
|
||
|
static struct methodlist posix_methods[] = {
|
||
|
{"chdir", posix_chdir},
|
||
|
{"chmod", posix_chmod},
|
||
|
{"getcwd", posix_getcwd},
|
||
|
{"link", posix_link},
|
||
|
{"listdir", posix_listdir},
|
||
|
{"mkdir", posix_mkdir},
|
||
|
{"rename", posix_rename},
|
||
|
{"rmdir", posix_rmdir},
|
||
|
{"stat", posix_stat},
|
||
|
{"system", posix_system},
|
||
|
{"umask", posix_umask},
|
||
|
{"unlink", posix_unlink},
|
||
|
{"utimes", posix_utimes},
|
||
|
#ifndef NO_LSTAT
|
||
|
{"lstat", posix_lstat},
|
||
|
{"readlink", posix_readlink},
|
||
|
{"symlink", posix_symlink},
|
||
|
#endif
|
||
|
{NULL, NULL} /* Sentinel */
|
||
|
};
|
||
|
|
||
|
|
||
|
void
|
||
|
initposix()
|
||
|
{
|
||
|
object *m, *d, *v;
|
||
|
|
||
|
m = initmodule("posix", posix_methods);
|
||
|
d = getmoduledict(m);
|
||
|
|
||
|
/* Initialize posix.environ dictionary */
|
||
|
v = convertenviron();
|
||
|
if (v == NULL || dictinsert(d, "environ", v) != 0)
|
||
|
fatal("can't define posix.environ");
|
||
|
DECREF(v);
|
||
|
|
||
|
/* Initialize posix.error exception */
|
||
|
PosixError = newstringobject("posix.error");
|
||
|
if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
|
||
|
fatal("can't define posix.error");
|
||
|
}
|