mercurial/osutil.c
changeset 7031 19e8d034932e
parent 7022 bdc8d00c4ffa
child 7033 892d27fb04a5
equal deleted inserted replaced
7030:20a5dd5d6dd9 7031:19e8d034932e
    94 	0,                         /* tp_init */
    94 	0,                         /* tp_init */
    95 	0,                         /* tp_alloc */
    95 	0,                         /* tp_alloc */
    96 	listdir_stat_new,          /* tp_new */
    96 	listdir_stat_new,          /* tp_new */
    97 };
    97 };
    98 
    98 
    99 static PyObject *listfiles(PyObject *list, DIR *dir,
    99 #ifdef AT_SYMLINK_NOFOLLOW
   100 			   int keep_stat, int *need_stat)
   100 #define USEFDOPEN 1
   101 {
   101 #else
       
   102 #define USEFDOPEN 0
       
   103 #endif
       
   104 
       
   105 int entkind(struct dirent *ent)
       
   106 {
       
   107 #ifdef DT_REG
       
   108 	switch (ent->d_type) {
       
   109 	case DT_REG: return S_IFREG;
       
   110 	case DT_DIR: return S_IFDIR;
       
   111 	case DT_LNK: return S_IFLNK;
       
   112 	case DT_BLK: return S_IFBLK;
       
   113 	case DT_CHR: return S_IFCHR;
       
   114 	case DT_FIFO: return S_IFIFO;
       
   115 	case DT_SOCK: return S_IFSOCK;
       
   116 	}
       
   117 #endif
       
   118 }
       
   119 
       
   120 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
       
   121 {
       
   122 	static char *kwlist[] = { "path", "stat", NULL };
       
   123 	PyObject *statflag = NULL, *list, *elem, *stat, *ret = NULL;
       
   124 	char fullpath[PATH_MAX + 10], *path;
       
   125 	int pathlen, keepstat, kind, dfd, err;
       
   126 	struct stat st;
   102 	struct dirent *ent;
   127 	struct dirent *ent;
   103 	PyObject *name, *py_kind, *val;
   128 	DIR *dir;
   104 
   129 
   105 #ifdef DT_REG
   130 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
   106 	*need_stat = 0;
   131 					 &path, &pathlen, &statflag))
   107 #else
   132 		goto error_parse;
   108 	*need_stat = 1;
   133 
   109 #endif
   134 	strncpy(fullpath, path, PATH_MAX);
   110 
   135 	fullpath[pathlen] = '/';
   111 	for (ent = readdir(dir); ent; ent = readdir(dir)) {
   136 	keepstat = statflag && PyObject_IsTrue(statflag);
   112 		int kind = -1;
   137 
   113 
   138 	if (USEFDOPEN) {
       
   139 		dfd = open(path, O_RDONLY);
       
   140 		if (dfd == -1) {
       
   141 			PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
       
   142 			goto error_parse;
       
   143 		}
       
   144 		dir = fdopendir(dfd);
       
   145 	} else
       
   146 		dir = opendir(path);
       
   147 	if (!dir) {
       
   148 		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
       
   149 		goto error_dir;
       
   150  	}
       
   151 
       
   152 	list = PyList_New(0);
       
   153 	if (!list)
       
   154 		goto error_list;
       
   155 
       
   156 	while ((ent = readdir(dir))) {
   114 		if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
   157 		if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
   115 			continue;
   158 			continue;
   116 
   159 
   117 #ifdef DT_REG
   160 		kind = entkind(ent);
   118 		if (!keep_stat)
   161 		if (kind == -1 || keepstat) {
   119 			switch (ent->d_type) {
   162 			if (USEFDOPEN)
   120 			case DT_REG: kind = S_IFREG; break;
   163 				err = fstatat(dfd, ent->d_name, &st,
   121 			case DT_DIR: kind = S_IFDIR; break;
   164 					      AT_SYMLINK_NOFOLLOW);
   122 			case DT_LNK: kind = S_IFLNK; break;
   165 			else {
   123 			case DT_BLK: kind = S_IFBLK; break;
   166 				strncpy(fullpath + pathlen + 1, ent->d_name,
   124 			case DT_CHR: kind = S_IFCHR; break;
   167 					PATH_MAX - pathlen);
   125 			case DT_FIFO: kind = S_IFIFO; break;
   168 				fullpath[PATH_MAX] = 0;
   126 			case DT_SOCK: kind = S_IFSOCK; break;
   169 				err = lstat(fullpath, &st);
   127 			default:
       
   128 				*need_stat = 0;
       
   129 				break;
       
   130 			}
   170 			}
   131 #endif
   171 			if (err == -1) {
   132 
   172 				strncpy(fullpath + pathlen + 1, ent->d_name,
   133 		if (kind != -1)
   173 					PATH_MAX - pathlen);
   134 			py_kind = PyInt_FromLong(kind);
   174 				fullpath[PATH_MAX] = 0;
   135 		else {
   175 				PyErr_SetFromErrnoWithFilename(PyExc_OSError,
   136 			py_kind = Py_None;
   176 							       fullpath);
   137 			Py_INCREF(Py_None);
   177 				goto error;
       
   178 			}
       
   179 			kind = st.st_mode & S_IFMT;
   138 		}
   180 		}
   139 
   181 
   140 		val = PyTuple_New(keep_stat ? 3 : 2);
   182 		if (keepstat) {
   141 		name = PyString_FromString(ent->d_name);
   183 			stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
   142 
   184 			if (!stat)
   143 		if (!name || !py_kind || !val) {
   185 				goto error;
   144 			Py_XDECREF(name);
   186 			memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
   145 			Py_XDECREF(py_kind);
   187 			elem = Py_BuildValue("siN", ent->d_name, kind, stat);
   146 			Py_XDECREF(val);
   188 		} else
   147 			return PyErr_NoMemory();
   189 			elem = Py_BuildValue("si", ent->d_name, kind);
   148 		}
   190 		if (!elem)
   149 
   191 			goto error;
   150 		PyTuple_SET_ITEM(val, 0, name);
   192 
   151 		PyTuple_SET_ITEM(val, 1, py_kind);
   193 		PyList_Append(list, elem);
   152 		if (keep_stat) {
   194 		Py_DECREF(elem);
   153 			PyTuple_SET_ITEM(val, 2, Py_None);
       
   154 			Py_INCREF(Py_None);
       
   155 		}
       
   156 
       
   157 		PyList_Append(list, val);
       
   158 		Py_DECREF(val);
       
   159 	}
   195 	}
   160 
   196 
   161 	return 0;
       
   162 }
       
   163 
       
   164 static PyObject *statfiles(PyObject *list, PyObject *ctor_args, int keep,
       
   165 			   char *path, int len, int dfd)
       
   166 {
       
   167 	struct stat buf;
       
   168 	struct stat *stp = &buf;
       
   169 	int kind;
       
   170 	int ret;
       
   171 	ssize_t i;
       
   172 	ssize_t size = PyList_Size(list);
       
   173 
       
   174 	for (i = 0; i < size; i++) {
       
   175 		PyObject *elt = PyList_GetItem(list, i);
       
   176 		char *name = PyString_AsString(PyTuple_GET_ITEM(elt, 0));
       
   177 		PyObject *py_st = NULL;
       
   178 		PyObject *py_kind = PyTuple_GET_ITEM(elt, 1);
       
   179 
       
   180 		kind = py_kind == Py_None ? -1 : PyInt_AsLong(py_kind);
       
   181 		if (kind != -1 && !keep)
       
   182 			continue;
       
   183 
       
   184 		strncpy(path + len + 1, name, PATH_MAX - len);
       
   185 		path[PATH_MAX] = 0;
       
   186 
       
   187 		if (keep) {
       
   188 			py_st = PyObject_CallObject(
       
   189 				(PyObject *)&listdir_stat_type, ctor_args);
       
   190 			if (!py_st)
       
   191 				return PyErr_NoMemory();
       
   192 			stp = &((struct listdir_stat *)py_st)->st;
       
   193 			PyTuple_SET_ITEM(elt, 2, py_st);
       
   194 		}
       
   195 
       
   196 #ifdef AT_SYMLINK_NOFOLLOW
       
   197 		ret = fstatat(dfd, name, stp, AT_SYMLINK_NOFOLLOW);
       
   198 #else
       
   199 		ret = lstat(path, stp);
       
   200 #endif
       
   201 		if (ret == -1)
       
   202 			return PyErr_SetFromErrnoWithFilename(PyExc_OSError,
       
   203 							      path);
       
   204 
       
   205 		if (kind == -1) {
       
   206 			if (S_ISREG(stp->st_mode))
       
   207 				kind = S_IFREG;
       
   208 			else if (S_ISDIR(stp->st_mode))
       
   209 				kind = S_IFDIR;
       
   210 			else if (S_ISLNK(stp->st_mode))
       
   211 				kind = S_IFLNK;
       
   212 			else if (S_ISBLK(stp->st_mode))
       
   213 				kind = S_IFBLK;
       
   214 			else if (S_ISCHR(stp->st_mode))
       
   215 				kind = S_IFCHR;
       
   216 			else if (S_ISFIFO(stp->st_mode))
       
   217 				kind = S_IFIFO;
       
   218 			else if (S_ISSOCK(stp->st_mode))
       
   219 				kind = S_IFSOCK;
       
   220 			else
       
   221 				kind = stp->st_mode;
       
   222 		}
       
   223 
       
   224 		if (py_kind == Py_None && kind != -1) {
       
   225 			py_kind = PyInt_FromLong(kind);
       
   226 			if (!py_kind)
       
   227 				return PyErr_NoMemory();
       
   228 			Py_XDECREF(Py_None);
       
   229 			PyTuple_SET_ITEM(elt, 1, py_kind);
       
   230 		}
       
   231 	}
       
   232 
       
   233 	return 0;
       
   234 }
       
   235 
       
   236 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
       
   237 {
       
   238 	static char *kwlist[] = { "path", "stat", NULL };
       
   239 	DIR *dir = NULL;
       
   240 	PyObject *statobj = NULL;
       
   241 	PyObject *list = NULL;
       
   242 	PyObject *err = NULL;
       
   243 	PyObject *ctor_args = NULL;
       
   244 	char *path;
       
   245 	char full_path[PATH_MAX + 10];
       
   246 	int path_len;
       
   247 	int need_stat, keep_stat;
       
   248 	int dfd;
       
   249 
       
   250 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
       
   251 					 &path, &path_len, &statobj))
       
   252 		goto bail;
       
   253 
       
   254 	keep_stat = statobj && PyObject_IsTrue(statobj);
       
   255 
       
   256 #ifdef AT_SYMLINK_NOFOLLOW
       
   257 	dfd = open(path, O_RDONLY);
       
   258 	if (dfd != -1)
       
   259 		dir = fdopendir(dfd);
       
   260 #else
       
   261 	dir = opendir(path);
       
   262 	dfd = -1;
       
   263 #endif
       
   264 	if (!dir) {
       
   265 		err = PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
       
   266 		goto bail;
       
   267 	}
       
   268 
       
   269 	list = PyList_New(0);
       
   270 	ctor_args = PyTuple_New(0);
       
   271 	if (!list || !ctor_args)
       
   272 		goto bail;
       
   273 
       
   274 	strncpy(full_path, path, PATH_MAX);
       
   275 	full_path[path_len] = '/';
       
   276 
       
   277 	err = listfiles(list, dir, keep_stat, &need_stat);
       
   278 	if (err)
       
   279 		goto bail;
       
   280 
       
   281 	PyList_Sort(list);
   197 	PyList_Sort(list);
   282 
   198 	ret = list;
   283 	if (!keep_stat && !need_stat)
   199 	Py_INCREF(ret);
   284 		goto done;
   200 
   285 
   201 error:
   286 	err = statfiles(list, ctor_args, keep_stat, full_path, path_len, dfd);
   202 	Py_DECREF(list);
   287 	if (!err)
   203 error_list:
   288 		goto done;
   204 	closedir(dir);
   289 
   205 error_dir:
   290  bail:
   206 	if (USEFDOPEN)
   291 	Py_XDECREF(list);
   207  		close(dfd);
   292 
   208 error_parse:
   293  done:
   209 	return ret;
   294 	Py_XDECREF(ctor_args);
   210 }
   295 	if (dir)
       
   296 		closedir(dir);
       
   297 	return err ? err : list;
       
   298 }
       
   299 
       
   300 
   211 
   301 static char osutil_doc[] = "Native operating system services.";
   212 static char osutil_doc[] = "Native operating system services.";
   302 
   213 
   303 static PyMethodDef methods[] = {
   214 static PyMethodDef methods[] = {
   304 	{"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
   215 	{"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,