mercurial/osutil.c
changeset 5421 9b5d626be8ba
parent 5416 ca890c0c3f1f
child 5422 a3ba7ef98c94
equal deleted inserted replaced
5420:6d1bd20ae14d 5421:9b5d626be8ba
    16 #include <sys/stat.h>
    16 #include <sys/stat.h>
    17 #include <sys/types.h>
    17 #include <sys/types.h>
    18 #include <unistd.h>
    18 #include <unistd.h>
    19 
    19 
    20 struct listdir_stat {
    20 struct listdir_stat {
    21     PyObject_HEAD
    21 	PyObject_HEAD
    22     struct stat st;
    22 	struct stat st;
    23 };
    23 };
    24 
    24 
    25 #define listdir_slot(name) \
    25 #define listdir_slot(name) \
    26     static PyObject *listdir_stat_##name(PyObject *self, void *x) \
    26     static PyObject *listdir_stat_##name(PyObject *self, void *x) \
    27     { \
    27     { \
    28         return PyInt_FromLong(((struct listdir_stat *) self)->st.name); \
    28         return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
    29     }
    29     }
    30 
    30 
    31 listdir_slot(st_dev);
    31 listdir_slot(st_dev);
    32 listdir_slot(st_mode);
    32 listdir_slot(st_mode);
    33 listdir_slot(st_nlink);
    33 listdir_slot(st_nlink);
    34 listdir_slot(st_size);
    34 listdir_slot(st_size);
    35 listdir_slot(st_mtime);
    35 listdir_slot(st_mtime);
    36 listdir_slot(st_ctime);
    36 listdir_slot(st_ctime);
    37 
    37 
    38 static struct PyGetSetDef listdir_stat_getsets[] = {
    38 static struct PyGetSetDef listdir_stat_getsets[] = {
    39   {"st_dev", listdir_stat_st_dev, 0, 0, 0},
    39 	{"st_dev", listdir_stat_st_dev, 0, 0, 0},
    40   {"st_mode", listdir_stat_st_mode, 0, 0, 0},
    40 	{"st_mode", listdir_stat_st_mode, 0, 0, 0},
    41   {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
    41 	{"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
    42   {"st_size", listdir_stat_st_size, 0, 0, 0},
    42 	{"st_size", listdir_stat_st_size, 0, 0, 0},
    43   {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
    43 	{"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
    44   {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
    44 	{"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
    45   {0, 0, 0, 0, 0}
    45 	{0, 0, 0, 0, 0}
    46 };
    46 };
    47 
    47 
    48 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
    48 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
    49 {
    49 {
    50     return (*t->tp_alloc)(t, 0);
    50 	return t->tp_alloc(t, 0);
    51 }
    51 }
    52 
    52 
    53 static void listdir_stat_dealloc(PyObject *o)
    53 static void listdir_stat_dealloc(PyObject *o)
    54 {
    54 {
    55     (*o->ob_type->tp_free)(o);
    55 	o->ob_type->tp_free(o);
    56 }
    56 }
    57 
    57 
    58 static PyTypeObject listdir_stat_type = {
    58 static PyTypeObject listdir_stat_type = {
    59     PyObject_HEAD_INIT(NULL)
    59 	PyObject_HEAD_INIT(NULL)
    60     0,                         /*ob_size*/
    60 	0,                         /*ob_size*/
    61     "osutil.stat",             /*tp_name*/
    61 	"osutil.stat",             /*tp_name*/
    62     sizeof(struct listdir_stat), /*tp_basicsize*/
    62 	sizeof(struct listdir_stat), /*tp_basicsize*/
    63     0,                         /*tp_itemsize*/
    63 	0,                         /*tp_itemsize*/
    64     (destructor)listdir_stat_dealloc, /*tp_dealloc*/
    64 	(destructor)listdir_stat_dealloc, /*tp_dealloc*/
    65     0,                         /*tp_print*/
    65 	0,                         /*tp_print*/
    66     0,                         /*tp_getattr*/
    66 	0,                         /*tp_getattr*/
    67     0,                         /*tp_setattr*/
    67 	0,                         /*tp_setattr*/
    68     0,                         /*tp_compare*/
    68 	0,                         /*tp_compare*/
    69     0,                         /*tp_repr*/
    69 	0,                         /*tp_repr*/
    70     0,                         /*tp_as_number*/
    70 	0,                         /*tp_as_number*/
    71     0,                         /*tp_as_sequence*/
    71 	0,                         /*tp_as_sequence*/
    72     0,                         /*tp_as_mapping*/
    72 	0,                         /*tp_as_mapping*/
    73     0,                         /*tp_hash */
    73 	0,                         /*tp_hash */
    74     0,                         /*tp_call*/
    74 	0,                         /*tp_call*/
    75     0,                         /*tp_str*/
    75 	0,                         /*tp_str*/
    76     0,                         /*tp_getattro*/
    76 	0,                         /*tp_getattro*/
    77     0,                         /*tp_setattro*/
    77 	0,                         /*tp_setattro*/
    78     0,                         /*tp_as_buffer*/
    78 	0,                         /*tp_as_buffer*/
    79     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    79 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    80     "stat objects",           /* tp_doc */
    80 	"stat objects",            /* tp_doc */
    81     0,                         /* tp_traverse */
    81 	0,                         /* tp_traverse */
    82     0,                         /* tp_clear */
    82 	0,                         /* tp_clear */
    83     0,                         /* tp_richcompare */
    83 	0,                         /* tp_richcompare */
    84     0,                         /* tp_weaklistoffset */
    84 	0,                         /* tp_weaklistoffset */
    85     0,                         /* tp_iter */
    85 	0,                         /* tp_iter */
    86     0,                         /* tp_iternext */
    86 	0,                         /* tp_iternext */
    87     0,                         /* tp_methods */
    87 	0,                         /* tp_methods */
    88     0,                         /* tp_members */
    88 	0,                         /* tp_members */
    89     listdir_stat_getsets,      /* tp_getset */
    89 	listdir_stat_getsets,      /* tp_getset */
    90     0,                         /* tp_base */
    90 	0,                         /* tp_base */
    91     0,                         /* tp_dict */
    91 	0,                         /* tp_dict */
    92     0,                         /* tp_descr_get */
    92 	0,                         /* tp_descr_get */
    93     0,                         /* tp_descr_set */
    93 	0,                         /* tp_descr_set */
    94     0,                         /* tp_dictoffset */
    94 	0,                         /* tp_dictoffset */
    95     0,                         /* tp_init */
    95 	0,                         /* tp_init */
    96     0,                         /* tp_alloc */
    96 	0,                         /* tp_alloc */
    97     listdir_stat_new,          /* tp_new */
    97 	listdir_stat_new,          /* tp_new */
    98 };
    98 };
    99 
    99 
   100 static inline int mode_to_kind(int mode)
   100 static inline int mode_to_kind(int mode)
   101 {
   101 {
   102     if (S_ISREG(mode)) return S_IFREG;
   102 	if (S_ISREG(mode)) return S_IFREG;
   103     if (S_ISDIR(mode)) return S_IFDIR;
   103 	if (S_ISDIR(mode)) return S_IFDIR;
   104     if (S_ISLNK(mode)) return S_IFLNK;
   104 	if (S_ISLNK(mode)) return S_IFLNK;
   105     if (S_ISBLK(mode)) return S_IFBLK;
   105 	if (S_ISBLK(mode)) return S_IFBLK;
   106     if (S_ISCHR(mode)) return S_IFCHR;
   106 	if (S_ISCHR(mode)) return S_IFCHR;
   107     if (S_ISFIFO(mode)) return S_IFIFO;
   107 	if (S_ISFIFO(mode)) return S_IFIFO;
   108     if (S_ISSOCK(mode)) return S_IFSOCK;
   108 	if (S_ISSOCK(mode)) return S_IFSOCK;
   109     return mode;
   109 	return mode;
   110 }
   110 }
   111 
   111 
   112 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
   112 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
   113 {
   113 {
   114     DIR *dir = NULL;
       
   115     struct dirent *ent;
       
   116     PyObject *list = NULL;
       
   117     PyObject *ctor_args = NULL;
       
   118     int all_kinds = 1;
       
   119     char *full_path;
       
   120     int path_len;
       
   121     int do_stat;
       
   122     char *path;
       
   123     int ret;
       
   124 
       
   125     {
       
   126 	static char *kwlist[] = { "path", "stat", NULL };
   114 	static char *kwlist[] = { "path", "stat", NULL };
   127 	PyObject *statobj = NULL;
   115 	PyObject *statobj = NULL;
       
   116 	DIR *dir = NULL;
       
   117 	struct dirent *ent;
       
   118 	PyObject *list = NULL;
       
   119 	PyObject *ctor_args = NULL;
       
   120 	int all_kinds = 1;
       
   121 	char *full_path;
       
   122 	int path_len;
       
   123 	int do_stat;
       
   124 	char *path;
       
   125 	int ret;
       
   126 	ssize_t size;
       
   127 	ssize_t i;
       
   128 	int dfd;
   128 
   129 
   129 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
   130 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
   130 					 &path, &path_len, &statobj))
   131 					 &path, &path_len, &statobj))
   131 	    goto bail;
   132 		goto bail;
   132 
   133 
   133 	do_stat = statobj && PyObject_IsTrue(statobj);
   134 	do_stat = statobj && PyObject_IsTrue(statobj);
   134     }
   135 
   135 
   136 	dir = opendir(path);
   136     if ((dir = opendir(path)) == NULL) {
   137 	if (!dir) {
   137 	list = PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
   138 		list = PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
   138         goto bail;
   139 		goto bail;
   139     }
   140 	}
   140 
   141 
   141     if ((list = PyList_New(0)) == NULL)
   142 	list = PyList_New(0);
   142         goto bail;
   143 	if (!list)
   143 
   144 		goto bail;
   144     full_path = alloca(path_len + PATH_MAX + 2);
   145 
   145     memcpy(full_path, path, path_len);
   146 	full_path = alloca(path_len + PATH_MAX + 2);
   146     full_path[path_len] = '/';
   147 	memcpy(full_path, path, path_len);
   147 
   148 	full_path[path_len] = '/';
   148     while ((ent = readdir(dir))) {
   149 
   149         PyObject *name = NULL;
   150 	for (ent = readdir(dir); ent; ent = readdir(dir)) {
   150         PyObject *py_kind = NULL;
   151 		PyObject *name = NULL;
   151         PyObject *val = NULL;
   152 		PyObject *py_kind = NULL;
   152         unsigned char d_type;
   153 		PyObject *val = NULL;
   153         int kind = -1;
   154 		unsigned char d_type;
   154 
   155 		int kind = -1;
   155         if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
   156 
   156             continue;
   157 		if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
       
   158 			continue;
   157 
   159 
   158 #ifdef DT_REG
   160 #ifdef DT_REG
   159 	if (do_stat)
   161 		if (do_stat)
   160 	    d_type = 0;
   162 			d_type = 0;
   161 	else
   163 		else
   162 	    d_type = ent->d_type;
   164 			d_type = ent->d_type;
   163 #else
   165 #else
   164         d_type = 0;
   166 		d_type = 0;
   165 #endif
   167 #endif
   166 
   168 
   167         switch (d_type) {
   169 		switch (d_type) {
   168 #ifdef DT_REG
   170 #ifdef DT_REG
   169         case DT_REG: kind = S_IFREG; break;
   171 		case DT_REG: kind = S_IFREG; break;
   170         case DT_DIR: kind = S_IFDIR; break;
   172 		case DT_DIR: kind = S_IFDIR; break;
   171         case DT_LNK: kind = S_IFLNK; break;
   173 		case DT_LNK: kind = S_IFLNK; break;
   172         case DT_BLK: kind = S_IFBLK; break;
   174 		case DT_BLK: kind = S_IFBLK; break;
   173         case DT_CHR: kind = S_IFCHR; break;
   175 		case DT_CHR: kind = S_IFCHR; break;
   174         case DT_FIFO: kind = S_IFIFO; break;
   176 		case DT_FIFO: kind = S_IFIFO; break;
   175         case DT_SOCK: kind = S_IFSOCK; break;
   177 		case DT_SOCK: kind = S_IFSOCK; break;
   176 #endif
   178 #endif
   177 	default:
   179 		default:
   178 	    if (all_kinds)
   180 			if (all_kinds)
   179 		all_kinds = 0;
   181 				all_kinds = 0;
   180 	    break;
   182 			break;
       
   183 		}
       
   184 
       
   185 		name = PyString_FromString(ent->d_name);
       
   186 		if (kind != -1)
       
   187 			py_kind = PyInt_FromLong(kind);
       
   188 		else {
       
   189 			py_kind = Py_None;
       
   190 			Py_INCREF(Py_None);
       
   191 		}
       
   192 
       
   193 		val = PyTuple_New(do_stat ? 3 : 2);
       
   194 
       
   195 		if (!name || !py_kind || !val) {
       
   196 			Py_XDECREF(name);
       
   197 			Py_XDECREF(py_kind);
       
   198 			Py_XDECREF(val);
       
   199 			goto bail;
       
   200 		}
       
   201 
       
   202 		PyTuple_SET_ITEM(val, 0, name);
       
   203 		PyTuple_SET_ITEM(val, 1, py_kind);
       
   204 		if (do_stat) {
       
   205 			PyTuple_SET_ITEM(val, 2, Py_None);
       
   206 			Py_INCREF(Py_None);
       
   207 		}
       
   208 
       
   209 		PyList_Append(list, val);
       
   210 		Py_DECREF(val);
   181 	}
   211 	}
   182 
   212 
   183         name = PyString_FromString(ent->d_name);
   213 	PyList_Sort(list);
   184 	if (kind != -1)
   214 	size = PyList_Size(list);
   185 	    py_kind = PyInt_FromLong(kind);
   215 #ifdef AT_SYMLINK_NOFOLLOW
   186 	else {
   216 	dfd = dirfd(dir);
   187 	    py_kind = Py_None;
   217 #endif
   188 	    Py_INCREF(Py_None);
   218 
       
   219 	if (do_stat || !all_kinds) {
       
   220 		for (i = 0; i < size; i++) {
       
   221 			PyObject *elt = PyList_GetItem(list, i);
       
   222 			char *name = PyString_AsString(PyTuple_GET_ITEM(elt, 0));
       
   223 			PyObject *py_st = NULL;
       
   224 			PyObject *py_kind = PyTuple_GET_ITEM(elt, 1);
       
   225 			int kind;
       
   226 
       
   227 			kind = py_kind == Py_None ? -1 : PyInt_AsLong(py_kind);
       
   228 
       
   229 			if (kind != -1 && !do_stat)
       
   230 				continue;
       
   231 
       
   232 			strcpy(full_path + path_len + 1, name);
       
   233 
       
   234 			if (do_stat) {
       
   235 				struct listdir_stat *st;
       
   236 
       
   237 				if (!ctor_args) {
       
   238 					ctor_args = PyTuple_New(0);
       
   239 					if (!ctor_args)
       
   240 						goto bail;
       
   241 				}
       
   242 
       
   243 				st = (struct listdir_stat *)
       
   244 					PyObject_CallObject((PyObject *)&listdir_stat_type,
       
   245 							    ctor_args);
       
   246 
       
   247 				if (!st)
       
   248 					goto bail;
       
   249 #ifdef AT_SYMLINK_NOFOLLOW
       
   250 				ret = fstatat(dfd, name, &st->st, AT_SYMLINK_NOFOLLOW);
       
   251 #else
       
   252 				ret = lstat(full_path, &st->st);
       
   253 #endif
       
   254 				if (ret == -1) {
       
   255 					list = PyErr_SetFromErrnoWithFilename(PyExc_OSError,
       
   256 									      full_path);
       
   257 					goto bail;
       
   258 				}
       
   259 				if (kind == -1)
       
   260 					kind = mode_to_kind(st->st.st_mode);
       
   261 				py_st = (PyObject *)st;
       
   262 			} else {
       
   263 				struct stat buf;
       
   264 #ifdef AT_SYMLINK_NOFOLLOW
       
   265 				ret = fstatat(dfd, ent->d_name, &buf, AT_SYMLINK_NOFOLLOW);
       
   266 #else
       
   267 				ret = lstat(full_path, &buf);
       
   268 #endif
       
   269 				if (ret == -1) {
       
   270 					list = PyErr_SetFromErrnoWithFilename(PyExc_OSError,
       
   271 									      full_path);
       
   272 					goto bail;
       
   273 				}
       
   274 				if (kind == -1)
       
   275 					kind = mode_to_kind(buf.st_mode);
       
   276 			}
       
   277 
       
   278 			if (py_kind == Py_None && kind != -1) {
       
   279 				py_kind = PyInt_FromLong(kind);
       
   280 				if (!py_kind)
       
   281 					goto bail;
       
   282 				Py_XDECREF(Py_None);
       
   283 				PyTuple_SET_ITEM(elt, 1, py_kind);
       
   284 			}
       
   285 
       
   286 			if (do_stat) {
       
   287 				if (!py_st) {
       
   288 					py_st = Py_None;
       
   289 					Py_INCREF(Py_None);
       
   290 				}
       
   291 				PyTuple_SET_ITEM(elt, 2, py_st);
       
   292 			}
       
   293 		}
   189 	}
   294 	}
   190 
   295 
   191         val = PyTuple_New(do_stat ? 3 : 2);
   296 	goto done;
   192 
   297 
   193         if (name == NULL || py_kind == NULL || val == NULL) {
   298 	bail:
   194             Py_XDECREF(name);
   299 		Py_XDECREF(list);
   195             Py_XDECREF(py_kind);
   300 
   196             Py_XDECREF(val);
   301 	done:
   197 
   302 		Py_XDECREF(ctor_args);
   198             goto bail;
   303 		if (dir)
   199 	}
   304 			closedir(dir);
   200 
   305 	return list;
   201         PyTuple_SET_ITEM(val, 0, name);
   306 }
   202         PyTuple_SET_ITEM(val, 1, py_kind);
   307 
   203 	if (do_stat) {
       
   204 	    PyTuple_SET_ITEM(val, 2, Py_None);
       
   205 	    Py_INCREF(Py_None);
       
   206 	}
       
   207 
       
   208         PyList_Append(list, val);
       
   209         Py_DECREF(val);
       
   210     }
       
   211 
       
   212     PyList_Sort(list);
       
   213 
       
   214     if (do_stat || !all_kinds) {
       
   215 	ssize_t size = PyList_Size(list);
       
   216 	ssize_t i;
       
   217 #ifdef AT_SYMLINK_NOFOLLOW
       
   218 	int dfd = dirfd(dir);
       
   219 #endif
       
   220 
       
   221 	for (i = 0; i < size; i++) {
       
   222 	    PyObject *elt = PyList_GetItem(list, i);
       
   223 	    char *name = PyString_AsString(PyTuple_GET_ITEM(elt, 0));
       
   224 	    PyObject *py_st = NULL;
       
   225 	    PyObject *py_kind = PyTuple_GET_ITEM(elt, 1);
       
   226 	    int kind;
       
   227 
       
   228 	    kind = py_kind == Py_None ? -1 : PyInt_AsLong(py_kind);
       
   229 
       
   230 	    if (kind != -1 && !do_stat)
       
   231 		continue;
       
   232 
       
   233             strcpy(full_path + path_len + 1, name);
       
   234 
       
   235 	    if (do_stat) {
       
   236 		struct listdir_stat *st;
       
   237 
       
   238 		if (ctor_args == NULL) {
       
   239 		    ctor_args = PyTuple_New(0);
       
   240 		    if (ctor_args == NULL)
       
   241 			goto bail;
       
   242 		}
       
   243 
       
   244 		st = (struct listdir_stat *)
       
   245 		    PyObject_CallObject((PyObject *) &listdir_stat_type,
       
   246 					ctor_args);
       
   247 		if (st == NULL)
       
   248 		    goto bail;
       
   249 #ifdef AT_SYMLINK_NOFOLLOW
       
   250 		ret = fstatat(dfd, name, &st->st, AT_SYMLINK_NOFOLLOW);
       
   251 #else
       
   252 		ret = lstat(full_path, &st->st);
       
   253 #endif
       
   254 		if (ret == -1) {
       
   255 		    list = PyErr_SetFromErrnoWithFilename(PyExc_OSError,
       
   256 							  full_path);
       
   257 		    goto bail;
       
   258 		}
       
   259 		if (kind == -1)
       
   260 		    kind = mode_to_kind(st->st.st_mode);
       
   261 		py_st = (PyObject *) st;
       
   262 	    } else {
       
   263 		struct stat buf;
       
   264 #ifdef AT_SYMLINK_NOFOLLOW
       
   265 		ret = fstatat(dfd, ent->d_name, &buf, AT_SYMLINK_NOFOLLOW);
       
   266 #else
       
   267 		ret = lstat(full_path, &buf);
       
   268 #endif
       
   269 		if (ret == -1) {
       
   270 		    list = PyErr_SetFromErrnoWithFilename(PyExc_OSError,
       
   271 							  full_path);
       
   272 		    goto bail;
       
   273 		}
       
   274 		if (kind == -1)
       
   275 		    kind = mode_to_kind(buf.st_mode);
       
   276 	    }
       
   277 
       
   278 	    if (py_kind == Py_None && kind != -1) {
       
   279 		py_kind = PyInt_FromLong(kind);
       
   280 		if (py_kind == NULL)
       
   281 		    goto bail;
       
   282 		Py_XDECREF(Py_None);
       
   283 		PyTuple_SET_ITEM(elt, 1, py_kind);
       
   284 	    }
       
   285 
       
   286 	    if (do_stat) {
       
   287 		if (py_st == NULL) {
       
   288 		    py_st = Py_None;
       
   289 		    Py_INCREF(Py_None);
       
   290 		}
       
   291 		PyTuple_SET_ITEM(elt, 2, py_st);
       
   292 	    }
       
   293         }
       
   294     }
       
   295 
       
   296     goto done;
       
   297 
       
   298 bail:
       
   299     Py_XDECREF(list);
       
   300 
       
   301 done:
       
   302     Py_XDECREF(ctor_args);
       
   303     if (dir)
       
   304         closedir(dir);
       
   305 
       
   306     return list;
       
   307 }
       
   308 
   308 
   309 static char osutil_doc[] = "Native operating system services.";
   309 static char osutil_doc[] = "Native operating system services.";
   310 
   310 
   311 static PyMethodDef methods[] = {
   311 static PyMethodDef methods[] = {
   312     {"listdir", (PyCFunction) listdir, METH_VARARGS | METH_KEYWORDS,
   312 	{"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
   313      "list a directory\n"},
   313 	 "list a directory\n"},
   314     {NULL, NULL}
   314 	{NULL, NULL}
   315 };
   315 };
   316 
   316 
   317 PyMODINIT_FUNC initosutil(void)
   317 PyMODINIT_FUNC initosutil(void)
   318 {
   318 {
   319     if (PyType_Ready(&listdir_stat_type) == -1)
   319 	if (PyType_Ready(&listdir_stat_type) == -1)
   320         return;
   320 		return;
   321 
   321 
   322     Py_InitModule3("osutil", methods, osutil_doc);
   322 	Py_InitModule3("osutil", methods, osutil_doc);
   323 }
   323 }