Skip to content

Commit 74365d7

Browse files
committed
[GR-53368] Implement os.truncate
PullRequest: graalpython/3336
2 parents fa55a68 + 36a62e3 commit 74365d7

File tree

8 files changed

+119
-4
lines changed

8 files changed

+119
-4
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_posix.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -252,6 +252,19 @@ def test_waitstatus_to_exitcode(self):
252252
self.assertEqual(-12, os.waitstatus_to_exitcode(0x428C))
253253
self.assertRaises(ValueError, os.waitstatus_to_exitcode, 0xFF)
254254

255+
def test_truncate(self):
256+
try:
257+
with open(TEST_FULL_PATH1, os.O_WRONLY | os.O_CREAT) as fd:
258+
os.write(fd, b'hello world')
259+
os.truncate(TEST_FULL_PATH1, 5)
260+
with open(TEST_FULL_PATH1, os.O_RDONLY) as fd:
261+
self.assertEqual(b'hello', os.read(fd, 100))
262+
finally:
263+
try:
264+
os.unlink(TEST_FULL_PATH1)
265+
except Exception:
266+
pass
267+
255268

256269
class WithCurdirFdTests(unittest.TestCase):
257270

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,8 +1192,9 @@ protected ArgumentClinicProvider getArgumentClinic() {
11921192
}
11931193

11941194
@Specialization
1195-
PNone ftruncate(VirtualFrame frame, int fd, long length,
1195+
static PNone ftruncate(VirtualFrame frame, int fd, long length,
11961196
@Bind("this") Node inliningTarget,
1197+
@Bind("getPosixSupport()") PosixSupport posixSupport,
11971198
@CachedLibrary(limit = "1") PosixSupportLibrary posixLib,
11981199
@Cached SysModuleBuiltins.AuditNode auditNode,
11991200
@Cached GilNode gil,
@@ -1204,15 +1205,15 @@ PNone ftruncate(VirtualFrame frame, int fd, long length,
12041205
try {
12051206
gil.release(true);
12061207
try {
1207-
posixLib.ftruncate(getPosixSupport(), fd, length);
1208+
posixLib.ftruncate(posixSupport, fd, length);
12081209
} finally {
12091210
gil.acquire();
12101211
}
12111212
return PNone.NONE;
12121213
} catch (PosixException e) {
12131214
errorProfile.enter(inliningTarget);
12141215
if (e.getErrorCode() == OSErrorEnum.EINTR.getNumber()) {
1215-
PythonContext.triggerAsyncActions(this);
1216+
PythonContext.triggerAsyncActions(inliningTarget);
12161217
} else {
12171218
throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e);
12181219
}
@@ -1221,6 +1222,52 @@ PNone ftruncate(VirtualFrame frame, int fd, long length,
12211222
}
12221223
}
12231224

1225+
@Builtin(name = "truncate", minNumOfPositionalArgs = 2, parameterNames = {"path", "length"})
1226+
@ArgumentClinic(name = "path", conversionClass = PathConversionNode.class, args = {"false", "true"})
1227+
@ArgumentClinic(name = "length", conversionClass = OffsetConversionNode.class)
1228+
@GenerateNodeFactory
1229+
public abstract static class TruncateNode extends PythonBinaryClinicBuiltinNode {
1230+
1231+
@Override
1232+
protected ArgumentClinicProvider getArgumentClinic() {
1233+
return PosixModuleBuiltinsClinicProviders.TruncateNodeClinicProviderGen.INSTANCE;
1234+
}
1235+
1236+
@Specialization
1237+
static PNone truncate(VirtualFrame frame, PosixPath path, long length,
1238+
@Bind("this") Node inliningTarget,
1239+
@Bind("getPosixSupport()") PosixSupport posixSupport,
1240+
@Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib,
1241+
@Shared @Cached SysModuleBuiltins.AuditNode auditNode,
1242+
@Shared @Cached GilNode gil,
1243+
@Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
1244+
auditNode.audit(inliningTarget, "os.truncate", path.originalObject, length);
1245+
try {
1246+
gil.release(true);
1247+
try {
1248+
posixLib.truncate(posixSupport, path.value, length);
1249+
} finally {
1250+
gil.acquire();
1251+
}
1252+
return PNone.NONE;
1253+
} catch (PosixException e) {
1254+
throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject);
1255+
}
1256+
}
1257+
1258+
@Specialization
1259+
static PNone ftruncate(VirtualFrame frame, PosixFd fd, long length,
1260+
@Bind("this") Node inliningTarget,
1261+
@Bind("getPosixSupport()") PosixSupport posixSupport,
1262+
@Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib,
1263+
@Shared @Cached SysModuleBuiltins.AuditNode auditNode,
1264+
@Shared @Cached GilNode gil,
1265+
@Cached InlinedBranchProfile errorProfile,
1266+
@Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
1267+
return FtruncateNode.ftruncate(frame, fd.fd, length, inliningTarget, posixSupport, posixLib, auditNode, gil, errorProfile, constructAndRaiseNode);
1268+
}
1269+
}
1270+
12241271
@Builtin(name = "fsync", minNumOfPositionalArgs = 1, parameterNames = "fd")
12251272
@ArgumentClinic(name = "fd", conversionClass = FileDescriptorConversionNode.class)
12261273
@GenerateNodeFactory

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,27 @@ public void ftruncateMessage(int fd, long length,
800800
}
801801
}
802802

803+
@ExportMessage
804+
public void truncate(Object path, long length,
805+
@Bind("$node") Node inliningTarget,
806+
@Shared("eq") @Cached TruffleString.EqualNode eqNode,
807+
@Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException {
808+
TruffleString pathname = pathToTruffleString(path, fromJavaStringNode);
809+
TruffleFile file = getTruffleFile(pathname, eqNode);
810+
try {
811+
doTruncate(file, length);
812+
} catch (Exception e) {
813+
throw posixException(OSErrorEnum.fromException(e, eqNode));
814+
}
815+
}
816+
817+
@TruffleBoundary
818+
private static void doTruncate(TruffleFile file, long length) throws IOException {
819+
try (SeekableByteChannel channel = file.newByteChannel(Set.of(StandardOpenOption.WRITE))) {
820+
channel.truncate(length);
821+
}
822+
}
823+
803824
@ExportMessage(name = "fsync")
804825
public void fsyncMessage(int fd) throws PosixException {
805826
if (!fsync(fd)) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/ImageBuildtimePosixSupport.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,13 @@ final void ftruncate(int fd, long length,
268268
nativeLib.ftruncate(nativePosixSupport, fd, length);
269269
}
270270

271+
@ExportMessage
272+
final void truncate(Object path, long length,
273+
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException {
274+
checkNotInImageBuildtime();
275+
nativeLib.truncate(nativePosixSupport, path, length);
276+
}
277+
271278
@ExportMessage
272279
final void fsync(int fd,
273280
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,17 @@ final void ftruncate(int fd, long length,
283283
}
284284
}
285285

286+
@ExportMessage
287+
final void truncate(Object path, long length,
288+
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {
289+
logEnter("truncate", "%s, %d", path, length);
290+
try {
291+
lib.truncate(delegate, path, length);
292+
} catch (PosixException e) {
293+
throw logException("truncate", e);
294+
}
295+
}
296+
286297
@ExportMessage
287298
final void fsync(int fd,
288299
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ private enum PosixNativeFunction {
187187
call_select("(sint32, [sint32], sint32, [sint32], sint32, [sint32], sint32, sint64, sint64, [sint8]):sint32"),
188188
call_lseek("(sint32, sint64, sint32):sint64"),
189189
call_ftruncate("(sint32, sint64):sint32"),
190+
call_truncate("([sint8], sint64):sint32"),
190191
call_fsync("(sint32):sint32"),
191192
call_flock("(sint32, sint32):sint32"),
192193
call_fcntl_lock("(sint32, sint32, sint32, sint32, sint64, sint64):sint32"),
@@ -685,6 +686,15 @@ public void ftruncate(int fd, long length,
685686
}
686687
}
687688

689+
@ExportMessage
690+
public void truncate(Object path, long length,
691+
@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException {
692+
int res = invokeNode.callInt(this, PosixNativeFunction.call_truncate, pathToCString(path), length);
693+
if (res != 0) {
694+
throw getErrnoAndThrowPosixException(invokeNode);
695+
}
696+
}
697+
688698
@ExportMessage
689699
public void fsync(int fd,
690700
@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ public abstract class PosixSupportLibrary extends Library {
111111

112112
public abstract void ftruncate(Object receiver, int fd, long length) throws PosixException;
113113

114+
public abstract void truncate(Object receiver, Object path, long length) throws PosixException;
115+
114116
public abstract void fsync(Object receiver, int fd) throws PosixException;
115117

116118
public abstract void flock(Object receiver, int fd, int operation) throws PosixException;

graalpython/python-libposix/src/posix.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ int32_t call_ftruncate(int32_t fd, int64_t length) {
220220
return ftruncate(fd, length);
221221
}
222222

223+
int32_t call_truncate(const char* path, int64_t length) {
224+
return truncate(path, length);
225+
}
226+
223227
int32_t call_fsync(int32_t fd) {
224228
return fsync(fd);
225229
}

0 commit comments

Comments
 (0)