8000 py/stream.c: Implemented truncate(). by DavidEGrayson · Pull Request #11500 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

py/stream.c: Implemented truncate(). #11500

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion extmod/vfs_fat_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,20 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
s->offset = f_tell(&self->fp);
return 0;

} else if (request == MP_STREAM_TRUNCATE) {
// f_truncate does not take a size argument so we have to do extra work.
uint32_t pos = f_tell(&self->fp);
f_lseek(&self->fp, arg);
FRESULT res = f_truncate(&self->fp);
if (pos < arg) {
f_lseek(&self->fp, pos);
}
if (res != FR_OK) {
*errcode = fresult_to_errno_table[res];
return MP_STREAM_ERROR;
}
return 0;

} else if (request == MP_STREAM_FLUSH) {
FRESULT res = f_sync(&self->fp);
if (res != FR_OK) {
Expand All @@ -144,7 +158,6 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
}
}
return 0;

} else {
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
Expand All @@ -163,6 +176,7 @@ STATIC const mp_rom_map_elem_t vfs_fat_rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR_truncate), MP_ROM_PTR(&mp_stream_truncate_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
Expand Down
8 changes: 8 additions & 0 deletions extmod/vfs_lfsx_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ STATIC mp_uint_t MP_VFS_LFSx(file_ioctl)(mp_obj_t self_in, mp_uint_t request, ui
}
s->offset = res;
return 0;
} else if (request == MP_STREAM_TRUNCATE) {
int res = LFSx_API(file_truncate)(&self->vfs->lfs, &self->file, arg);
if (res < 0) {
*errcode = -res;
return MP_STREAM_ERROR;
}
return 0;
} else if (request == MP_STREAM_FLUSH) {
int res = LFSx_API(file_sync)(&self->vfs->lfs, &self->file);
if (res < 0) {
Expand Down Expand Up @@ -211,6 +218,7 @@ STATIC const mp_rom_map_elem_t MP_VFS_LFSx(file_locals_dict_table)[] = {
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR_truncate), MP_ROM_PTR(&mp_stream_truncate_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&MP_VFS_LFSx(file___exit___obj)) },
Expand Down
11 changes: 11 additions & 0 deletions extmod/vfs_posix_file.c
8000
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
s->offset = off;
return 0;
}
case MP_STREAM_TRUNCATE: {
MP_THREAD_GIL_EXIT();
int res = ftruncate(o->fd, arg);
MP_THREAD_GIL_ENTER();
if (res < 0) {
*errcode = errno;
return MP_STREAM_ERROR;
}
return 0;
}
case MP_STREAM_CLOSE:
if (o->fd >= 0) {
MP_THREAD_GIL_EXIT();
Expand Down Expand Up @@ -235,6 +245,7 @@ STATIC const mp_rom_map_elem_t vfs_posix_rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR_truncate), MP_ROM_PTR(&mp_stream_truncate_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
Expand Down
10 changes: 10 additions & 0 deletions py/objstringio.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
s->offset = o->pos = new_pos;
return 0;
}
case MP_STREAM_TRUNCATE:
// In CPython, StringIO.truncate never expands the string.
if (o->vstr->len > arg) {
o->vstr->len = arg;
if (o->pos > arg) {
o->pos = arg;
}
}
return 0;
case MP_STREAM_FLUSH:
return 0;
case MP_STREAM_CLOSE:
Expand Down Expand Up @@ -228,6 +237,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR_truncate), MP_ROM_PTR(&mp_stream_truncate_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) },
Expand Down
21 changes: 21 additions & 0 deletions py/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,27 @@ STATIC mp_obj_t stream_tell(mp_obj_t self) {
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell);

STATIC mp_obj_t stream_truncate(size_t n_args, const mp_obj_t *args) {
const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
mp_uint_t size;
if (n_args > 1) {
mp_int_t arg = mp_obj_get_int(args[1]);
if (arg < 0) {
mp_raise_OSError(MP_EINVAL);
}
size = arg;
} else {
size = mp_obj_get_int(stream_tell(args[0]));
}
int error;
mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_TRUNCATE, size, &error);
if (res == MP_STREAM_ERROR) {
mp_raise_OSError(error);
}
return mp_obj_new_int(size);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_truncate_obj, 1, 2, stream_truncate);

STATIC mp_obj_t stream_flush(mp_obj_t self) {
const mp_stream_p_t *stream_p = mp_get_stream(self);
int error;
Expand Down
2 changes: 2 additions & 0 deletions py/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define MP_STREAM_GET_DATA_OPTS (8) // Get data/message options
#define MP_STREAM_SET_DATA_OPTS (9) // Set data/message options
#define MP_STREAM_GET_FILENO (10) // Get fileno of underlying file
#define MP_STREAM_TRUNCATE (11)

// These poll ioctl values are compatible with Linux
#define MP_STREAM_POLL_RD (0x0001)
Expand Down Expand Up @@ -85,6 +86,7 @@ MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_truncate_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj);

Expand Down
40 changes: 40 additions & 0 deletions tests/io/file_truncate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import io


def test_truncate(file):
file.write("a" * 64)

# arg < 0
try:
file.truncate(-1)
except Exception as e:
# Usually this is OSError, but it is ValueError for
# a StringIO in CPython.
print("-1 invalid")

# no arg
file.seek(56)
print(file.truncate()) # 56
print(file.seek(0, 2)) # 56

# position < arg < size: file gets shorter
file.seek(40)
print(file.truncate(48)) # 48
print(file.seek(0, 2)) # 48

# arg < position < size: file gets shorter, position decreases
file.seek(40)
print(file.truncate(32)) # 32
print(file.seek(0, 2)) # 32
print(file.tell()) # 32

# position < size < arg: file gets longer, unless it is StringIO
file.seek(24)
print(file.truncate(64)) # 64
print(file.seek(0, 2)) # 64 or 32


with open("f", "w+") as file:
test_truncate(file)

test_truncate(io.StringIO())
0