@@ -455,6 +455,77 @@ static mp_obj_t vfs_fat_umount(mp_obj_t self_in) {
455455}
456456static MP_DEFINE_CONST_FUN_OBJ_1 (fat_vfs_umount_obj , vfs_fat_umount ) ;
457457
458+ // CIRCUITPY-CHANGE
459+ static mp_obj_t vfs_fat_utime (mp_obj_t vfs_in , mp_obj_t path_in , mp_obj_t times_in ) {
460+ mp_obj_fat_vfs_t * self = MP_OBJ_TO_PTR (vfs_in );
461+ const char * path = mp_obj_str_get_str (path_in );
462+ if (!mp_obj_is_tuple_compatible (times_in )) {
463+ mp_raise_type_arg (& mp_type_TypeError , times_in );
464+ }
465+
466+ mp_obj_t * otimes ;
467+ mp_obj_get_array_fixed_n (times_in , 2 , & otimes );
468+
469+ // Validate that both elements of the tuple are int and discard the second one
470+ int time [2 ];
471+ time [0 ] = mp_obj_get_int (otimes [0 ]);
472+ time [1 ] = mp_obj_get_int (otimes [1 ]);
473+ timeutils_struct_time_t tm ;
474+ timeutils_seconds_since_epoch_to_struct_time (time [0 ], & tm );
475+
476+ FILINFO fno ;
477+ fno .fdate = (WORD )(((tm .tm_year - 1980 ) * 512U ) | tm .tm_mon * 32U | tm .tm_mday );
478+ fno .ftime = (WORD )(tm .tm_hour * 2048U | tm .tm_min * 32U | tm .tm_sec / 2U );
479+ FRESULT res = f_utime (& self -> fatfs , path , & fno );
480+ if (res != FR_OK ) {
481+ mp_raise_OSError_fresult (res );
482+ }
483+
484+ return mp_const_none ;
485+ }
486+ static MP_DEFINE_CONST_FUN_OBJ_3 (fat_vfs_utime_obj , vfs_fat_utime ) ;
487+
488+ static mp_obj_t vfs_fat_getreadonly (mp_obj_t self_in ) {
489+ fs_user_mount_t * self = MP_OBJ_TO_PTR (self_in );
490+ return mp_obj_new_bool (!filesystem_is_writable_by_python (self ));
491+ }
492+ static MP_DEFINE_CONST_FUN_OBJ_1 (fat_vfs_getreadonly_obj , vfs_fat_getreadonly ) ;
493+
494+ static MP_PROPERTY_GETTER (fat_vfs_readonly_obj ,
495+ (mp_obj_t )& fat_vfs_getreadonly_obj );
496+
497+ #if MICROPY_FATFS_USE_LABEL
498+ static mp_obj_t vfs_fat_getlabel (mp_obj_t self_in ) {
499+ fs_user_mount_t * self = MP_OBJ_TO_PTR (self_in );
500+ char working_buf [12 ];
501+ FRESULT res = f_getlabel (& self -> fatfs , working_buf , NULL );
502+ if (res != FR_OK ) {
503+ mp_raise_OSError_fresult (res );
504+ }
505+ return mp_obj_new_str (working_buf , strlen (working_buf ));
506+ }
507+ static MP_DEFINE_CONST_FUN_OBJ_1 (fat_vfs_getlabel_obj , vfs_fat_getlabel ) ;
508+
509+ static mp_obj_t vfs_fat_setlabel (mp_obj_t self_in , mp_obj_t label_in ) {
510+ fs_user_mount_t * self = MP_OBJ_TO_PTR (self_in );
511+ verify_fs_writable (self );
512+ const char * label_str = mp_obj_str_get_str (label_in );
513+ FRESULT res = f_setlabel (& self -> fatfs , label_str );
514+ if (res != FR_OK ) {
515+ if (res == FR_WRITE_PROTECTED ) {
516+ mp_raise_msg (& mp_type_OSError , MP_ERROR_TEXT ("Read-only filesystem" ));
517+ }
518+ mp_raise_OSError_fresult (res );
519+ }
520+ return mp_const_none ;
521+ }
522+ static MP_DEFINE_CONST_FUN_OBJ_2 (fat_vfs_setlabel_obj , vfs_fat_setlabel ) ;
523+
524+ static MP_PROPERTY_GETSET (fat_vfs_label_obj ,
525+ (mp_obj_t )& fat_vfs_getlabel_obj ,
526+ (mp_obj_t )& fat_vfs_setlabel_obj );
527+ #endif
528+
458529static const mp_rom_map_elem_t fat_vfs_locals_dict_table [] = {
459530 // CIRCUITPY-CHANGE: correct name
460531 #if FF_FS_REENTRANT
0 commit comments