@@ -1101,8 +1101,8 @@ abstract static class UtimeNode extends PythonBuiltinNode {
11011101 @ Specialization
11021102 Object utime (String path , PNone times , PNone ns , PNone dir_fd , PNone follow_symlinks ) {
11031103 long time = ((Double ) TimeModuleBuiltins .timeSeconds ()).longValue ();
1104- setMtime (path , time );
1105- setAtime (path , time );
1104+ setMtime (getFile ( path , true ) , time );
1105+ setAtime (getFile ( path , true ) , time );
11061106 return PNone .NONE ;
11071107 }
11081108
@@ -1111,8 +1111,8 @@ Object utime(String path, PNone times, PNone ns, PNone dir_fd, PNone follow_syml
11111111 Object utime (String path , PTuple times , PNone ns , PNone dir_fd , PNone follow_symlinks ) {
11121112 long atime = getTime (times , 0 , "times" );
11131113 long mtime = getTime (times , 1 , "times" );
1114- setMtime (path , mtime );
1115- setAtime (path , atime );
1114+ setMtime (getFile ( path , true ) , mtime );
1115+ setAtime (getFile ( path , true ) , atime );
11161116 return PNone .NONE ;
11171117 }
11181118
@@ -1121,8 +1121,18 @@ Object utime(String path, PTuple times, PNone ns, PNone dir_fd, PNone follow_sym
11211121 Object utime (String path , PNone times , PTuple ns , PNone dir_fd , PNone follow_symlinks ) {
11221122 long atime = getTime (ns , 0 , "ns" ) / 1000 ;
11231123 long mtime = getTime (ns , 1 , "ns" ) / 1000 ;
1124- setMtime (path , mtime );
1125- setAtime (path , atime );
1124+ setMtime (getFile (path , true ), mtime );
1125+ setAtime (getFile (path , true ), atime );
1126+ return PNone .NONE ;
1127+ }
1128+
1129+ @ SuppressWarnings ("unused" )
1130+ @ Specialization
1131+ Object utime (String path , PNone times , PTuple ns , PNone dir_fd , boolean follow_symlinks ) {
1132+ long atime = getTime (ns , 0 , "ns" ) / 1000 ;
1133+ long mtime = getTime (ns , 1 , "ns" ) / 1000 ;
1134+ setMtime (getFile (path , true ), mtime );
1135+ setAtime (getFile (path , true ), atime );
11261136 return PNone .NONE ;
11271137 }
11281138
@@ -1183,18 +1193,36 @@ private PException tupleError(String argname) {
11831193 return raise (TypeError , "utime: '%s' must be either a tuple of two ints or None" , argname );
11841194 }
11851195
1186- private void setMtime (String path , long mtime ) {
1196+ private void setMtime (TruffleFile truffleFile , long mtime ) {
11871197 try {
1188- getContext ().getEnv ().getTruffleFile (path ).setLastModifiedTime (FileTime .from (mtime , TimeUnit .SECONDS ));
1189- } catch (IOException e ) {
1198+ truffleFile .setLastModifiedTime (FileTime .from (mtime , TimeUnit .SECONDS ));
1199+ } catch (IOException | SecurityException e ) {
1200+ throw raise ();
11901201 }
11911202 }
11921203
1193- private void setAtime (String path , long mtime ) {
1204+ private void setAtime (TruffleFile truffleFile , long mtime ) {
11941205 try {
1195- getContext ().getEnv ().getTruffleFile (path ).setLastAccessTime (FileTime .from (mtime , TimeUnit .SECONDS ));
1196- } catch (IOException e ) {
1206+ truffleFile .setLastAccessTime (FileTime .from (mtime , TimeUnit .SECONDS ));
1207+ } catch (IOException | SecurityException e ) {
1208+ throw raise ();
1209+ }
1210+ }
1211+
1212+ private TruffleFile getFile (String path , boolean followSymlinks ) {
1213+ TruffleFile truffleFile = getContext ().getEnv ().getTruffleFile (path );
1214+ if (!followSymlinks ) {
1215+ try {
1216+ truffleFile = truffleFile .getCanonicalFile (LinkOption .NOFOLLOW_LINKS );
1217+ } catch (IOException | SecurityException e ) {
1218+ throw raise ();
1219+ }
11971220 }
1221+ return truffleFile ;
1222+ }
1223+
1224+ private PException raise () {
1225+ throw raise (ValueError , "Operation not allowed" );
11981226 }
11991227
12001228 private int getLength (PTuple times ) {
0 commit comments