1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2014-2018 Paul Sokolovsky
7 * Copyright (c) 2014-2018 Damien P. George
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <dirent.h>
36 #include <fcntl.h>
37
38 #include "py/mpconfig.h"
39 #include "py/runtime.h"
40 #include "py/objtuple.h"
41 #include "py/objstr.h"
42 #include "py/mperrno.h"
43 #include "py/mphal.h"
44 #include "py/mpthread.h"
45 #include "extmod/vfs.h"
46 #include "extmod/misc.h"
47 #include "ulog/ulog.h"
48 #include "genhdr/mpversion.h"
49 #include "aos/kernel.h"
50 #include "dirent.h"
51
52 #if MICROPY_VFS_POSIX
53 #include "vfs_posix.h"
54 #endif
55
56 #define LOG_TAG "MOD_OS"
57
58 extern const mp_obj_type_t mp_fat_vfs_type;
59
60 STATIC const qstr os_uname_info_fields[] = {
61 MP_QSTR_sysname, MP_QSTR_nodename,
62 MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
63 };
64 STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
65 STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
66 STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING);
67 STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
68 STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
69
70 STATIC MP_DEFINE_ATTRTUPLE(
71 os_uname_info_obj,
72 os_uname_info_fields,
73 5,
74 (mp_obj_t)&os_uname_info_sysname_obj,
75 (mp_obj_t)&os_uname_info_nodename_obj,
76 (mp_obj_t)&os_uname_info_release_obj,
77 (mp_obj_t)&os_uname_info_version_obj,
78 (mp_obj_t)&os_uname_info_machine_obj
79 );
80
os_uname(void)81 STATIC mp_obj_t os_uname(void) {
82 return (mp_obj_t)&os_uname_info_obj;
83 }
84 STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
85
os_urandom(mp_obj_t num)86 STATIC mp_obj_t os_urandom(mp_obj_t num) {
87 mp_int_t n = mp_obj_get_int(num);
88 vstr_t vstr;
89 vstr_init_len(&vstr, n);
90 uint32_t r = 0;
91 for (int i = 0; i < n; i++) {
92 if ((i & 3) == 0) {
93 r = aos_rand(); // returns 32-bit random number
94 }
95 vstr.buf[i] = r;
96 r >>= 8;
97 }
98 vstr.buf[n] = '\0';
99 return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
100 }
101 STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
102
up_one_level(char * s)103 static int up_one_level(char *s)
104 {
105 char *tail;
106
107 if (!s)
108 return -1;
109
110 tail = s + strlen(s) - 1;
111 if (*tail == '/')
112 tail--;
113
114 while (*tail != '\0' && *tail != '/')
115 tail--;
116
117 if (*tail == '\0') {
118 return -1;
119 } else {
120 *(tail + 1) = '\0';
121 return 0;
122 }
123 }
124
py_get_realpath(const char * path,char * resolved_path,unsigned int len)125 char *py_get_realpath(const char *path, char *resolved_path, unsigned int len)
126 {
127 char *ret, *p = (char *)path, *r = resolved_path;
128
129 if (!path || !r || len < 1)
130 return NULL;
131
132 memset(r, 0, len);
133
134 // deal with heading char
135 if (p[0] != '/') {
136 // relative path
137 ret = getcwd(r, len);
138 if (!ret)
139 return NULL;
140
141 // add tailing '/' if no
142 if (r[strlen(r) - 1] != '/') {
143 r[strlen(r)] = '/';
144 }
145
146 r += strlen(r);
147 } else {
148 // absolute path
149 r[0] = '/';
150 r++;
151 }
152
153 // iterate to exclude '.', '..'. '/'
154 while (*p != '\0') {
155 while (*p == '/')
156 p++;
157 if (*p == '\0')
158 break;
159
160 if (*p == '.') {
161 p++;
162 // end with '.'
163 if (*p == '\0')
164 break;
165
166 if (*p == '.') {
167 // '..' or '../'
168 if ((*(p + 1) != '/') && (*(p + 1) != '\0')) {
169 printf("Invalid path %s\r\n", path);
170 return NULL;
171 } else {
172 // '..' case
173 p++;
174 // if (*p == '/') {
175 if (up_one_level(resolved_path) != 0) {
176 printf("Failed to go up now. Invalid path %s\r\n", path);
177 return NULL;
178 }
179
180 r = resolved_path + strlen(resolved_path);
181 // }
182
183 // end with '.'
184 if (*p == '\0') {
185 break;
186 }
187 }
188 } else {
189 if ((*p != '/') && (*p != '\0')) {
190 printf("Invalid path %s\r\n", path);
191 return NULL;
192 } else {
193 // '.' case
194 p++;
195 }
196 }
197 }
198
199 while (*p == '/')
200 p++;
201 if (*p == '\0')
202 break;
203
204 // if another round of ./.., just continue
205 if (*p == '.')
206 continue;
207
208 // path string may be found now, save to r
209 while ((*p != '/') && (*p != '\0'))
210 *r++ = *p++;
211
212 // add taling '/' if necessary
213 if (*(r - 1) != '/') {
214 *r++ = '/';
215 }
216 }
217
218 // exclude the tailing '/', just in case it is a file
219 if ((resolved_path[strlen(resolved_path) - 1] == '/') &&
220 (strlen(resolved_path) != 1)) {
221 resolved_path[strlen(resolved_path) - 1] = '\0';
222 }
223
224 return resolved_path;
225 }
226
mod_os_stat(mp_obj_t path_in)227 STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) {
228 struct stat sb;
229 const char *path = mp_obj_str_get_str(path_in);
230 int res = stat(path, &sb);
231
232 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
233 t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
234 t->items[1] = mp_obj_new_int_from_uint(sb.st_ino);
235 t->items[2] = mp_obj_new_int_from_uint(sb.st_dev);
236 t->items[3] = mp_obj_new_int_from_uint(sb.st_nlink);
237 t->items[4] = mp_obj_new_int_from_uint(sb.st_uid);
238 t->items[5] = mp_obj_new_int_from_uint(sb.st_gid);
239 t->items[6] = mp_obj_new_int_from_uint(sb.st_size);
240 t->items[7] = mp_obj_new_int_from_uint(sb.st_atime);
241 t->items[8] = mp_obj_new_int_from_uint(sb.st_mtime);
242 t->items[9] = mp_obj_new_int_from_uint(sb.st_ctime);
243 return MP_OBJ_FROM_PTR(t);
244 }
245 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_stat_obj, mod_os_stat);
246
mod_os_statvfs(mp_obj_t path_in)247 STATIC mp_obj_t mod_os_statvfs(mp_obj_t path_in) {
248 struct statfs sb;
249 const char *path = mp_obj_str_get_str(path_in);
250 int res = statfs(path, &sb);
251
252 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(9, NULL));
253 t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_type);
254 t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
255 t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks);
256 t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree);
257 t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail);
258 t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files);
259 t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree);
260 t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.f_fsid);
261 t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.f_namelen);
262 return MP_OBJ_FROM_PTR(t);
263 }
264 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_statvfs_obj, mod_os_statvfs);
265
266
mod_os_remove(mp_obj_t path_in)267 STATIC mp_obj_t mod_os_remove(mp_obj_t path_in) {
268 const char *path = mp_obj_str_get_str(path_in);
269
270 char abspath[256] = {0};
271 path = py_get_realpath(path, abspath, sizeof(abspath));
272
273 MP_THREAD_GIL_EXIT();
274 int r = unlink(path);
275 MP_THREAD_GIL_ENTER();
276
277 return MP_OBJ_NEW_SMALL_INT(r);
278 }
279 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_remove_obj, mod_os_remove);
280
281
py_mv(char * from,char * to)282 static int py_mv(char *from, char *to)
283 {
284 int fd_from = 0, fd_to = 0;
285 char buf[128] = {0};
286 int rlen = 0, wlen = 0, ret = -1, isdir = false;
287 struct stat s;
288
289 char abspath_from[256] = {0}, abspath_to[256] = {0};
290
291 from = py_get_realpath(from, abspath_from, sizeof(abspath_from));
292 to = py_get_realpath(to, abspath_to, sizeof(abspath_to));
293 if (!from || !to) {
294 LOGE(LOG_TAG, "Failed to get real path!\r\n");
295 return -1;
296 }
297
298 if (!stat(to, &s)) {
299 if (S_ISDIR(s.st_mode)) {
300 char *p = strrchr(from, '/');
301
302 if (!p)
303 ret = asprintf(&to, "%s/%s", to, from);
304 else
305 ret = asprintf(&to, "%s%s", to, p);
306 if (ret < 0) {
307 LOGE(LOG_TAG, "asprintf failed\n");
308 return -1;
309 }
310 isdir = true;
311 }
312 }
313
314 ret = rename(from, to);
315 if (ret < 0 && errno != EXDEV) {
316 LOGE(LOG_TAG, "rename %s to %s failed - %s\n", from, to, strerror(errno));
317 return -1;
318 } else if (ret == 0) {
319 return 0;
320 }
321
322 fd_from = open(from, O_RDONLY);
323 if (fd_from < 0) {
324 LOGE(LOG_TAG, "open %s failed - %s\n", from, strerror(errno));
325 return -1;
326 }
327
328 fd_to = open(to, O_WRONLY | O_CREAT | O_TRUNC);
329 if (fd_to < 0) {
330 LOGE(LOG_TAG, "open %s failed - %s\n", to, strerror(errno));
331 goto close_from;
332 }
333
334 while ((rlen = read(fd_from, buf, 128))) {
335 if (rlen < 0) {
336 LOGE(LOG_TAG, "read %s failed - %s\n", from, strerror(errno));
337 goto close_to;
338 }
339
340 wlen = write(fd_to, buf, rlen);
341 if (wlen != rlen) {
342 LOGE(LOG_TAG, "write %s failed - %s\n", to, strerror(errno));
343 goto close_to;
344 }
345 }
346
347 ret = unlink(from);
348 if (ret) {
349 LOGE(LOG_TAG, "unlink %s failed - %s\n", from, strerror(errno));
350 goto close_to;
351 }
352
353 ret = 0;
354 close_to:
355 close(fd_to);
356 close_from:
357 close(fd_from);
358 if (isdir)
359 free(to);
360 return ret;
361 }
362
mod_os_rename(mp_obj_t old_path_in,mp_obj_t new_path_in)363 STATIC mp_obj_t mod_os_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) {
364 const char *old_path = mp_obj_str_get_str(old_path_in);
365 const char *new_path = mp_obj_str_get_str(new_path_in);
366
367 MP_THREAD_GIL_EXIT();
368 int r = rename(old_path, new_path);
369 MP_THREAD_GIL_ENTER();
370
371 return MP_OBJ_NEW_SMALL_INT(r);
372 }
373 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_os_rename_obj, mod_os_rename);
374
py_rrmdir(const char * path)375 int py_rrmdir(const char *path)
376 {
377 struct stat s;
378 DIR *pdir = NULL;
379 struct dirent *entry = NULL;
380 int ret = -1;
381 char *dir, *p;
382
383 if (!path)
384 return -EINVAL;
385
386 dir = strdup(path);
387 p = dir + strlen(dir) - 1;
388 while ((*p == '/') && (p > dir)) {
389 *p = '\0';
390 p--;
391 }
392
393 if (stat(dir, &s) || !S_ISDIR(s.st_mode)) {
394 // LOGE(LOG_TAG, "%s is neither existed nor a directory\n", dir);
395 goto out;
396 }
397
398 pdir = opendir(dir);
399 if (!pdir) {
400 LOGE(LOG_TAG, "opendir %s failed - %s\n", dir, strerror(errno));
401 goto out;
402 }
403
404 ret = 0;
405 while ((ret == 0) && (entry = readdir(pdir))) {
406 char fpath[128];
407
408 snprintf(fpath, 128, "%s/%s", dir, entry->d_name);
409
410 ret = stat(fpath, &s);
411 if (ret) {
412 LOGE(LOG_TAG, "stat %s failed\n", fpath);
413 break;
414 }
415
416 if (!strcmp(entry->d_name, "."))
417 continue;
418 if (!strcmp(entry->d_name, ".."))
419 continue;
420
421 if (S_ISDIR(s.st_mode))
422 ret = py_rrmdir(fpath);
423 else
424 ret = unlink(fpath);
425 }
426
427 closedir(pdir);
428 if (ret == 0) {
429 ret = rmdir(dir);
430 if (ret)
431 LOGE(LOG_TAG, "rmdir %s failed\n", dir);
432 }
433 out:
434 free(dir);
435 return ret;
436 }
437
438
mod_os_rmdir(mp_obj_t path_in)439 STATIC mp_obj_t mod_os_rmdir(mp_obj_t path_in) {
440 const char *path = mp_obj_str_get_str(path_in);
441 char abspath[256] = {0};
442
443 path = py_get_realpath(path, abspath, sizeof(abspath));
444
445 MP_THREAD_GIL_EXIT();
446 int r = rrmdir(path);
447 MP_THREAD_GIL_ENTER();
448
449 return MP_OBJ_NEW_SMALL_INT(r);
450 }
451 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_rmdir_obj, mod_os_rmdir);
452
mod_os_system(mp_obj_t cmd_in)453 STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) {
454 const char *cmd = mp_obj_str_get_str(cmd_in);
455
456 MP_THREAD_GIL_EXIT();
457 int r = system(cmd);
458 MP_THREAD_GIL_ENTER();
459
460 return MP_OBJ_NEW_SMALL_INT(r);
461 }
462 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system);
463
mod_os_getenv(mp_obj_t var_in)464 STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) {
465 const char *s = getenv(mp_obj_str_get_str(var_in));
466 if (s == NULL) {
467 return mp_const_none;
468 }
469 return mp_obj_new_str(s, strlen(s));
470 }
471 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv);
472
mod_os_putenv(mp_obj_t key_in,mp_obj_t value_in)473 STATIC mp_obj_t mod_os_putenv(mp_obj_t key_in, mp_obj_t value_in) {
474 const char *key = mp_obj_str_get_str(key_in);
475 const char *value = mp_obj_str_get_str(value_in);
476
477 int ret = setenv(key, value, 1);
478 if (ret == -1) {
479 mp_raise_OSError(errno);
480 }
481
482 return MP_OBJ_NEW_SMALL_INT(ret);
483 }
484 MP_DEFINE_CONST_FUN_OBJ_2(mod_os_putenv_obj, mod_os_putenv);
485
mod_os_unsetenv(mp_obj_t key_in)486 STATIC mp_obj_t mod_os_unsetenv(mp_obj_t key_in) {
487 const char *key = mp_obj_str_get_str(key_in);
488 int ret = unsetenv(key);
489 if (ret == -1) {
490 mp_raise_OSError(errno);
491 }
492 return MP_OBJ_NEW_SMALL_INT(ret);
493 }
494 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_unsetenv_obj, mod_os_unsetenv);
495
py_mkdir_do(char * path,int flags)496 static int py_mkdir_do(char *path, int flags)
497 {
498 char *s = NULL;
499 char abspath[256] = {0};
500 #define MKDIR_FLAGS_PARENTS (1 << 0)
501 path = py_get_realpath(path, abspath, sizeof(abspath));
502 if (!path) {
503 LOGE(LOG_TAG, "Failed to get real path!\r\n");
504 return -1;
505 }
506
507 /*
508 * All of operations must base on root directory
509 * As alios has not root dierctory, we can operate '/data' but not '/'
510 */
511 #define MOUNT_BASE_DIR "/"
512 if (strncmp(path, MOUNT_BASE_DIR, strlen(MOUNT_BASE_DIR))) {
513 LOGE(LOG_TAG, "make directory must base on %s\n", MOUNT_BASE_DIR);
514 return -1;
515 }
516
517 if (path[0] == '.') {
518 if (path[1] == '\0')
519 return 0;
520 if (path[1] == '.' && path[2] == '\0')
521 return 0;
522 }
523
524 if (flags & MKDIR_FLAGS_PARENTS)
525 s = path + strlen(MOUNT_BASE_DIR);
526 while (1) {
527 struct stat st;
528
529 if (flags & MKDIR_FLAGS_PARENTS) {
530 /* in case of tailing '/', such as '/data/a/' */
531 if (*(s++) == '\0')
532 break;
533 s = strchr(s, '/');
534 if (s)
535 *s = '\0';
536 }
537
538 if (!stat(path, &st)) {
539 if (S_ISDIR(st.st_mode))
540 goto next;
541 LOGE(LOG_TAG, "make failed - %s already existed and not direcotry\n", path);
542 return -1;
543 }
544
545 if (mkdir(path, 0777) < 0) {
546 LOGE(LOG_TAG, "mkdir %s failed\n", path);
547 return -1;
548 }
549
550 next:
551 if (!s)
552 break;
553 *s = '/';
554 }
555 return 0;
556 }
557
mod_os_mkdir(mp_obj_t path_in)558 STATIC mp_obj_t mod_os_mkdir(mp_obj_t path_in) {
559 // TODO: Accept mode param
560 const char *path = mp_obj_str_get_str(path_in);
561
562 MP_THREAD_GIL_EXIT();
563 int r = py_mkdir_do(path, 0777);
564 MP_THREAD_GIL_ENTER();
565
566 return mp_obj_new_int(r);
567 }
568 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_mkdir_obj, mod_os_mkdir);
569
570 typedef struct _mp_obj_listdir_t {
571 mp_obj_base_t base;
572 mp_fun_1_t iternext;
573 DIR *dir;
574 } mp_obj_listdir_t;
575
listdir_next(mp_obj_t self_in)576 STATIC mp_obj_t listdir_next(mp_obj_t self_in) {
577 mp_obj_listdir_t *self = MP_OBJ_TO_PTR(self_in);
578
579 if (self->dir == NULL) {
580 goto done;
581 }
582 MP_THREAD_GIL_EXIT();
583 struct dirent *dirent = readdir(self->dir);
584 if (dirent == NULL) {
585 closedir(self->dir);
586 MP_THREAD_GIL_ENTER();
587 self->dir = NULL;
588 done:
589 return MP_OBJ_STOP_ITERATION;
590 }
591 MP_THREAD_GIL_ENTER();
592
593 mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
594 t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name));
595
596 #ifdef _DIRENT_HAVE_D_TYPE
597 #ifdef DTTOIF
598 t->items[1] = MP_OBJ_NEW_SMALL_INT(DTTOIF(dirent->d_type));
599 #else
600 if (dirent->d_type == DT_DIR) {
601 t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
602 } else if (dirent->d_type == DT_REG) {
603 t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
604 } else {
605 t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type);
606 }
607 #endif
608 #else
609 // DT_UNKNOWN should have 0 value on any reasonable system
610 t->items[1] = MP_OBJ_NEW_SMALL_INT(0);
611 #endif
612
613 #ifdef _DIRENT_HAVE_D_INO
614 t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino);
615 #else
616 t->items[2] = MP_OBJ_NEW_SMALL_INT(0);
617 #endif
618 return MP_OBJ_FROM_PTR(t);
619 }
620
mod_os_ilistdir(size_t n_args,const mp_obj_t * args)621 STATIC mp_obj_t mod_os_ilistdir(size_t n_args, const mp_obj_t *args) {
622 const char *path = ".";
623 if (n_args > 0) {
624 path = mp_obj_str_get_str(args[0]);
625 }
626
627 char abspath[256] = {0};
628 path = py_get_realpath(path, abspath, sizeof(abspath));
629
630 mp_obj_listdir_t *o = m_new_obj(mp_obj_listdir_t);
631 o->base.type = &mp_type_polymorph_iter;
632 MP_THREAD_GIL_EXIT();
633 o->dir = opendir(path);
634 MP_THREAD_GIL_ENTER();
635 o->iternext = listdir_next;
636 return MP_OBJ_FROM_PTR(o);
637 }
638 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_ilistdir_obj, 0, 1, mod_os_ilistdir);
639
mod_os_listdir(size_t n_args,const mp_obj_t * args)640 STATIC mp_obj_t mod_os_listdir(size_t n_args, const mp_obj_t *args) {
641 const char *path = ".";
642 if (n_args > 0) {
643 path = mp_obj_str_get_str(args[0]);
644 }
645
646 mp_raise_OSError(EPERM);
647 return mp_const_none;
648
649 mp_obj_listdir_t *o = m_new_obj(mp_obj_listdir_t);
650
651 MP_THREAD_GIL_EXIT();
652 MP_THREAD_GIL_ENTER();
653
654 return MP_OBJ_FROM_PTR(o);
655 }
656 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_listdir_obj, 0, 1, mod_os_listdir);
657
mod_os_errno(size_t n_args,const mp_obj_t * args)658 STATIC mp_obj_t mod_os_errno(size_t n_args, const mp_obj_t *args) {
659 if (n_args == 0) {
660 return MP_OBJ_NEW_SMALL_INT(errno);
661 }
662
663 errno = mp_obj_get_int(args[0]);
664 return mp_const_none;
665 }
666 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno);
667
mod_os_chdir(mp_obj_t path_in)668 STATIC mp_obj_t mod_os_chdir(mp_obj_t path_in) {
669 // TODO: Accept mode param
670 char *path = mp_obj_str_get_str(path_in);
671 char abspath[256] = {0};
672 path = py_get_realpath(path, abspath, sizeof(abspath));
673
674 MP_THREAD_GIL_EXIT();
675 int r = chdir(path);
676 MP_THREAD_GIL_ENTER();
677
678 return MP_OBJ_NEW_SMALL_INT(r);
679 }
680 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_chdir_obj, mod_os_chdir);
681
682
mod_os_getcwd()683 STATIC mp_obj_t mod_os_getcwd() {
684 // TODO: Accept mode param
685
686 char buf[MICROPY_ALLOC_PATH_MAX + 1];
687 const char *ret = getcwd(buf, sizeof(buf));
688 if (ret == NULL) {
689 mp_raise_OSError(errno);
690 }
691 return mp_obj_new_str(ret, strlen(ret));
692 }
693
694 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_os_getcwd_obj, mod_os_getcwd);
695
mod_os_file_open(mp_obj_t path_in,mp_obj_t mode_in)696 STATIC mp_obj_t mod_os_file_open(mp_obj_t path_in, mp_obj_t mode_in)
697 {
698 const char *path = mp_obj_str_get_str(path_in);
699 const char *mode = mp_obj_str_get_str(mode_in);
700
701 if(path == NULL || mode == NULL) {
702 mp_raise_OSError(EINVAL);
703 return mp_const_none;
704 }
705
706 FILE *stream = fopen(path, mode);
707 if (stream == NULL) {
708 mp_raise_OSError(ENOENT);
709 return mp_const_none;
710 }
711 return MP_OBJ_FROM_PTR(stream);
712 }
713 MP_DEFINE_CONST_FUN_OBJ_2(mod_os_file_open_obj, mod_os_file_open);
714
mod_os_file_close(mp_obj_t stream_in)715 STATIC mp_obj_t mod_os_file_close(mp_obj_t stream_in)
716 {
717 FILE *stream = (FILE *)MP_OBJ_TO_PTR(stream_in);
718
719 int ret = -1;
720 if (stream != NULL) {
721 ret = fclose(stream);
722 }
723 else {
724 ret = 0;
725 }
726 return mp_obj_new_int(ret);
727 }
728 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_file_close_obj, mod_os_file_close);
729
mod_os_file_read(size_t n_args,const mp_obj_t * args)730 STATIC mp_obj_t mod_os_file_read(size_t n_args, const mp_obj_t *args)
731 {
732 if (n_args < 4) {
733 mp_raise_OSError(EINVAL);
734 return mp_const_false;
735 }
736
737 mp_int_t size = mp_obj_get_int(args[1]);
738 mp_int_t nmemb = mp_obj_get_int(args[2]);
739 FILE *stream = (FILE *)MP_OBJ_TO_PTR(args[3]);
740
741 mp_buffer_info_t bufinfo;
742 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);
743
744 int ret = -1;
745 if (stream != NULL) {
746 ret = fread(bufinfo.buf, size, nmemb, stream);
747 }
748 return mp_obj_new_int(ret);
749 }
750 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mod_os_file_read_obj, 4, mod_os_file_read);
751
mod_os_file_write(size_t n_args,const mp_obj_t * args)752 STATIC mp_obj_t mod_os_file_write(size_t n_args, const mp_obj_t *args)
753 {
754 if (n_args < 4) {
755 mp_raise_OSError(EINVAL);
756 return mp_const_false;
757 }
758 mp_int_t size = mp_obj_get_int(args[1]);
759 mp_int_t nmemb = mp_obj_get_int(args[2]);
760 FILE *stream = (FILE *)MP_OBJ_TO_PTR(args[3]);
761
762 mp_buffer_info_t bufinfo;
763 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
764
765 int ret = -1;
766 if (stream != NULL) {
767 ret = fwrite(bufinfo.buf, size, nmemb, stream);
768 }
769 return mp_obj_new_int(ret);
770 }
771 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(mod_os_file_write_obj, 4, mod_os_file_write);
772
mod_os_file_seek(mp_obj_t stream_in,mp_obj_t offset_in,mp_obj_t whence_in)773 STATIC mp_obj_t mod_os_file_seek(mp_obj_t stream_in, mp_obj_t offset_in, mp_obj_t whence_in)
774 {
775 FILE *stream = (FILE *)MP_OBJ_TO_PTR(stream_in);
776 if (stream == NULL) {
777 mp_raise_OSError(EINVAL);
778 return mp_const_false;
779 }
780
781 mp_int_t offset = mp_obj_get_int(offset_in);
782 mp_int_t whence = mp_obj_get_int(whence_in);
783
784 int ret = fseek(stream, offset, whence);
785 return mp_obj_new_int(ret);
786 }
787 MP_DEFINE_CONST_FUN_OBJ_3(mod_os_file_seek_obj, mod_os_file_seek);
788
mod_os_file_tell(mp_obj_t stream_in)789 STATIC mp_obj_t mod_os_file_tell(mp_obj_t stream_in)
790 {
791 FILE *stream = (FILE *)MP_OBJ_TO_PTR(stream_in);
792 if (stream == NULL) {
793 mp_raise_OSError(EINVAL);
794 return mp_const_false;
795 }
796
797 int ret = ftell(stream);
798 return mp_obj_new_int(ret);
799 }
800 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_file_tell_obj, mod_os_file_tell);
801
mod_os_file_rewind(mp_obj_t stream_in)802 STATIC mp_obj_t mod_os_file_rewind(mp_obj_t stream_in)
803 {
804 FILE *stream = (FILE *)MP_OBJ_TO_PTR(stream_in);
805 if (stream == NULL) {
806 mp_raise_OSError(EINVAL);
807 return mp_const_false;
808 }
809
810 rewind(stream);
811 return mp_const_none;
812 }
813 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_file_rewind_obj, mod_os_file_rewind);
814
mod_os_file_getpos(mp_obj_t stream_in)815 STATIC mp_obj_t mod_os_file_getpos(mp_obj_t stream_in)
816 {
817 FILE *stream = (FILE *)MP_OBJ_TO_PTR(stream_in);
818 if (stream == NULL) {
819 mp_raise_OSError(EINVAL);
820 return mp_const_false;
821 } else {
822 fpos_t pos = 0;
823 int ret = fgetpos(stream, &pos);
824 if (ret == 0) {
825 return mp_obj_new_int(pos);
826 } else {
827 return mp_obj_new_int(-1);
828 }
829 }
830 }
831 MP_DEFINE_CONST_FUN_OBJ_1(mod_os_file_getpos_obj, mod_os_file_getpos);
832
mod_os_file_setpos(mp_obj_t stream_in,mp_obj_t pos_in)833 STATIC mp_obj_t mod_os_file_setpos(mp_obj_t stream_in, mp_obj_t pos_in)
834 {
835 FILE *stream = (FILE *)MP_OBJ_TO_PTR(stream_in);
836 if (stream == NULL) {
837 mp_raise_OSError(EINVAL);
838 return mp_const_false;
839 }
840
841 mp_int_t pos = mp_obj_get_int(pos_in);
842 int ret = fsetpos(stream, &pos);
843 return mp_obj_new_int(ret);
844 }
845 MP_DEFINE_CONST_FUN_OBJ_2(mod_os_file_setpos_obj, mod_os_file_setpos);
846
847 /// \function sync()
848 /// Sync all filesystems.
os_sync(void)849 STATIC mp_obj_t os_sync(void) {
850 #if MICROPY_VFS_FAT
851 for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
852 // this assumes that vfs->obj is fs_user_mount_t with block device functions
853 disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL);
854 }
855 #endif
856 return mp_const_none;
857 }
858 MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);
859
860 #if MICROPY_PY_OS_DUPTERM
mp_uos_dupterm_notify(mp_obj_t obj_in)861 STATIC mp_obj_t mp_uos_dupterm_notify(mp_obj_t obj_in) {
862 (void)obj_in;
863 for (;;) {
864 int c = mp_uos_dupterm_rx_chr();
865 if (c < 0) {
866 break;
867 }
868 ringbuf_put(&stdin_ringbuf, c);
869 }
870 return mp_const_none;
871 }
872 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_dupterm_notify_obj, mp_uos_dupterm_notify);
873 #endif
874
875 STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = {
876 { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
877 { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
878 { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
879
880 #if MICROPY_PY_OS_DUPTERM
881 { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
882 { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&mp_uos_dupterm_notify_obj) },
883 #endif
884
885 { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mod_os_ilistdir_obj) },
886 { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mod_os_listdir_obj) },
887 { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mod_os_mkdir_obj) },
888 { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mod_os_rmdir_obj) },
889 { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mod_os_chdir_obj) },
890 { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mod_os_getcwd_obj) },
891 { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mod_os_remove_obj) },
892 { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mod_os_rename_obj) },
893 { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_os_stat_obj) },
894 { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mod_os_statvfs_obj) },
895 // { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mod_os_mount_obj) },
896 // { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mod_os_umount_obj) },
897 { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mod_os_remove_obj) },
898
899 #if MICROPY_VFS_FAT
900 { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
901 #endif
902 #if MICROPY_VFS_LFS1
903 { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) },
904 #endif
905 #if MICROPY_VFS_LFS2
906 { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
907 #endif
908
909 { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) },
910 { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
911 { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) },
912 { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) },
913 { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) },
914 { MP_ROM_QSTR(MP_QSTR_putenv), MP_ROM_PTR(&mod_os_putenv_obj) },
915 { MP_ROM_QSTR(MP_QSTR_unsetenv), MP_ROM_PTR(&mod_os_unsetenv_obj) },
916
917 // file operation
918 { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_os_file_open_obj) },
919 { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_os_file_read_obj) },
920 { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_os_file_write_obj) },
921 { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mod_os_file_close_obj) },
922 { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mod_os_file_seek_obj) },
923 { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mod_os_file_tell_obj) },
924 { MP_ROM_QSTR(MP_QSTR_rewind), MP_ROM_PTR(&mod_os_file_rewind_obj) },
925 { MP_ROM_QSTR(MP_QSTR_getpos), MP_ROM_PTR(&mod_os_file_getpos_obj) },
926 { MP_ROM_QSTR(MP_QSTR_setpos), MP_ROM_PTR(&mod_os_file_setpos_obj) },
927 };
928
929 STATIC MP_DEFINE_CONST_DICT(mp_module_os_globals, mp_module_os_globals_table);
930
931 const mp_obj_module_t mp_module_uos = {
932 .base = { &mp_type_module },
933 .globals = (mp_obj_dict_t *)&mp_module_os_globals,
934 };
935