@@ -1268,13 +1268,64 @@ pub(super) mod _os {
12681268 }
12691269
12701270 #[ pyfunction]
1271- fn link ( src : OsPath , dst : OsPath , vm : & VirtualMachine ) -> PyResult < ( ) > {
1272- fs:: hard_link ( & src. path , & dst. path ) . map_err ( |err| {
1273- let builder = err. to_os_error_builder ( vm) ;
1274- let builder = builder. filename ( src. filename ( vm) ) ;
1275- let builder = builder. filename2 ( dst. filename ( vm) ) ;
1276- builder. build ( vm) . upcast ( )
1277- } )
1271+ fn link (
1272+ src : OsPath ,
1273+ dst : OsPath ,
1274+ follow_symlinks : FollowSymlinks ,
1275+ vm : & VirtualMachine ,
1276+ ) -> PyResult < ( ) > {
1277+ #[ cfg( unix) ]
1278+ {
1279+ use std:: os:: unix:: ffi:: OsStrExt ;
1280+ let src_cstr = std:: ffi:: CString :: new ( src. path . as_os_str ( ) . as_bytes ( ) )
1281+ . map_err ( |_| vm. new_value_error ( "embedded null byte" ) ) ?;
1282+ let dst_cstr = std:: ffi:: CString :: new ( dst. path . as_os_str ( ) . as_bytes ( ) )
1283+ . map_err ( |_| vm. new_value_error ( "embedded null byte" ) ) ?;
1284+
1285+ let flags = if follow_symlinks. 0 {
1286+ libc:: AT_SYMLINK_FOLLOW
1287+ } else {
1288+ 0
1289+ } ;
1290+
1291+ let ret = unsafe {
1292+ libc:: linkat (
1293+ libc:: AT_FDCWD ,
1294+ src_cstr. as_ptr ( ) ,
1295+ libc:: AT_FDCWD ,
1296+ dst_cstr. as_ptr ( ) ,
1297+ flags,
1298+ )
1299+ } ;
1300+
1301+ if ret != 0 {
1302+ let err = std:: io:: Error :: last_os_error ( ) ;
1303+ let builder = err. to_os_error_builder ( vm) ;
1304+ let builder = builder. filename ( src. filename ( vm) ) ;
1305+ let builder = builder. filename2 ( dst. filename ( vm) ) ;
1306+ return Err ( builder. build ( vm) . upcast ( ) ) ;
1307+ }
1308+
1309+ Ok ( ( ) )
1310+ }
1311+
1312+ #[ cfg( not( unix) ) ]
1313+ {
1314+ // On non-Unix platforms, ignore follow_symlinks if it's the default value
1315+ // or raise NotImplementedError if explicitly set to False
1316+ if !follow_symlinks. 0 {
1317+ return Err ( vm. new_not_implemented_error (
1318+ "link: follow_symlinks unavailable on this platform" ,
1319+ ) ) ;
1320+ }
1321+
1322+ fs:: hard_link ( & src. path , & dst. path ) . map_err ( |err| {
1323+ let builder = err. to_os_error_builder ( vm) ;
1324+ let builder = builder. filename ( src. filename ( vm) ) ;
1325+ let builder = builder. filename2 ( dst. filename ( vm) ) ;
1326+ builder. build ( vm) . upcast ( )
1327+ } )
1328+ }
12781329 }
12791330
12801331 #[ cfg( any( unix, windows) ) ]
@@ -1842,6 +1893,7 @@ pub(super) mod _os {
18421893 SupportFunc :: new( "access" , Some ( false ) , Some ( false ) , None ) ,
18431894 SupportFunc :: new( "chdir" , None , Some ( false ) , Some ( false ) ) ,
18441895 // chflags Some, None Some
1896+ SupportFunc :: new( "link" , Some ( false ) , Some ( false ) , Some ( cfg!( unix) ) ) ,
18451897 SupportFunc :: new( "listdir" , Some ( LISTDIR_FD ) , Some ( false ) , Some ( false ) ) ,
18461898 SupportFunc :: new( "mkdir" , Some ( false ) , Some ( MKDIR_DIR_FD ) , Some ( false ) ) ,
18471899 // mkfifo Some Some None
0 commit comments