1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package libcore.io;
18 
19 import android.system.ErrnoException;
20 import android.system.NetlinkSocketAddress;
21 import android.system.OsConstants;
22 import android.system.PacketSocketAddress;
23 import android.system.StructTimeval;
24 import android.system.StructUcred;
25 import android.system.UnixSocketAddress;
26 
27 import java.io.File;
28 import java.io.FileDescriptor;
29 import java.io.FileInputStream;
30 import java.io.FileOutputStream;
31 import java.net.Inet4Address;
32 import java.net.Inet6Address;
33 import java.net.InetAddress;
34 import java.net.InetSocketAddress;
35 import java.net.NetworkInterface;
36 import java.net.ServerSocket;
37 import java.net.SocketOptions;
38 import java.nio.ByteBuffer;
39 import java.nio.charset.StandardCharsets;
40 import java.util.Arrays;
41 import java.util.Locale;
42 import java.util.concurrent.atomic.AtomicReference;
43 import junit.framework.TestCase;
44 import static android.system.OsConstants.*;
45 
46 public class OsTest extends TestCase {
testIsSocket()47   public void testIsSocket() throws Exception {
48     File f = new File("/dev/null");
49     FileInputStream fis = new FileInputStream(f);
50     assertFalse(S_ISSOCK(Libcore.os.fstat(fis.getFD()).st_mode));
51     fis.close();
52 
53     ServerSocket s = new ServerSocket();
54     assertTrue(S_ISSOCK(Libcore.os.fstat(s.getImpl().getFD$()).st_mode));
55     s.close();
56   }
57 
testFcntlInt()58   public void testFcntlInt() throws Exception {
59     File f = File.createTempFile("OsTest", "tst");
60     FileInputStream fis = null;
61     try {
62       fis = new FileInputStream(f);
63       Libcore.os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
64       int flags = Libcore.os.fcntlVoid(fis.getFD(), F_GETFD);
65       assertTrue((flags & FD_CLOEXEC) != 0);
66     } finally {
67       IoUtils.closeQuietly(fis);
68       f.delete();
69     }
70   }
71 
testUnixDomainSockets_in_file_system()72   public void testUnixDomainSockets_in_file_system() throws Exception {
73     String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
74     new File(path).delete();
75     checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false);
76   }
77 
testUnixDomainSocket_abstract_name()78   public void testUnixDomainSocket_abstract_name() throws Exception {
79     // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7).
80     checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true);
81   }
82 
testUnixDomainSocket_unnamed()83   public void testUnixDomainSocket_unnamed() throws Exception {
84     final FileDescriptor fd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
85     // unix(7) says an unbound socket is unnamed.
86     checkNoSockName(fd);
87     Libcore.os.close(fd);
88   }
89 
checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)90   private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)
91       throws Exception {
92     final FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
93     Libcore.os.bind(serverFd, address);
94     Libcore.os.listen(serverFd, 5);
95 
96     checkSockName(serverFd, isAbstract, address);
97 
98     Thread server = new Thread(new Runnable() {
99       public void run() {
100         try {
101           UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed();
102           FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
103           checkSockName(clientFd, isAbstract, address);
104           checkNoName(peerAddress);
105 
106           checkNoPeerName(clientFd);
107 
108           StructUcred credentials = Libcore.os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED);
109           assertEquals(Libcore.os.getpid(), credentials.pid);
110           assertEquals(Libcore.os.getuid(), credentials.uid);
111           assertEquals(Libcore.os.getgid(), credentials.gid);
112 
113           byte[] request = new byte[256];
114           Libcore.os.read(clientFd, request, 0, request.length);
115 
116           String s = new String(request, "UTF-8");
117           byte[] response = s.toUpperCase(Locale.ROOT).getBytes("UTF-8");
118           Libcore.os.write(clientFd, response, 0, response.length);
119 
120           Libcore.os.close(clientFd);
121         } catch (Exception ex) {
122           throw new RuntimeException(ex);
123         }
124       }
125     });
126     server.start();
127 
128     FileDescriptor clientFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
129 
130     Libcore.os.connect(clientFd, address);
131     checkNoSockName(clientFd);
132 
133     String string = "hello, world!";
134 
135     byte[] request = string.getBytes("UTF-8");
136     assertEquals(request.length, Libcore.os.write(clientFd, request, 0, request.length));
137 
138     byte[] response = new byte[request.length];
139     assertEquals(response.length, Libcore.os.read(clientFd, response, 0, response.length));
140 
141     assertEquals(string.toUpperCase(Locale.ROOT), new String(response, "UTF-8"));
142 
143     Libcore.os.close(clientFd);
144   }
145 
checkSockName(FileDescriptor fd, boolean isAbstract, UnixSocketAddress address)146   private static void checkSockName(FileDescriptor fd, boolean isAbstract,
147       UnixSocketAddress address) throws Exception {
148     UnixSocketAddress isa = (UnixSocketAddress) Libcore.os.getsockname(fd);
149     assertEquals(address, isa);
150     if (isAbstract) {
151       assertEquals(0, isa.getSunPath()[0]);
152     }
153   }
154 
checkNoName(UnixSocketAddress usa)155   private void checkNoName(UnixSocketAddress usa) {
156     assertEquals(0, usa.getSunPath().length);
157   }
158 
checkNoPeerName(FileDescriptor fd)159   private void checkNoPeerName(FileDescriptor fd) throws Exception {
160     checkNoName((UnixSocketAddress) Libcore.os.getpeername(fd));
161   }
162 
checkNoSockName(FileDescriptor fd)163   private void checkNoSockName(FileDescriptor fd) throws Exception {
164     checkNoName((UnixSocketAddress) Libcore.os.getsockname(fd));
165   }
166 
test_strsignal()167   public void test_strsignal() throws Exception {
168     assertEquals("Killed", Libcore.os.strsignal(9));
169     assertEquals("Unknown signal -1", Libcore.os.strsignal(-1));
170   }
171 
test_byteBufferPositions_write_pwrite()172   public void test_byteBufferPositions_write_pwrite() throws Exception {
173     FileOutputStream fos = new FileOutputStream(new File("/dev/null"));
174     FileDescriptor fd = fos.getFD();
175     final byte[] contents = new String("goodbye, cruel world").getBytes(StandardCharsets.US_ASCII);
176     ByteBuffer byteBuffer = ByteBuffer.wrap(contents);
177 
178     byteBuffer.position(0);
179     int written = Libcore.os.write(fd, byteBuffer);
180     assertTrue(written > 0);
181     assertEquals(written, byteBuffer.position());
182 
183     byteBuffer.position(4);
184     written = Libcore.os.write(fd, byteBuffer);
185     assertTrue(written > 0);
186     assertEquals(written + 4, byteBuffer.position());
187 
188     byteBuffer.position(0);
189     written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */);
190     assertTrue(written > 0);
191     assertEquals(written, byteBuffer.position());
192 
193     byteBuffer.position(4);
194     written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */);
195     assertTrue(written > 0);
196     assertEquals(written + 4, byteBuffer.position());
197 
198     fos.close();
199   }
200 
test_byteBufferPositions_read_pread()201   public void test_byteBufferPositions_read_pread() throws Exception {
202     FileInputStream fis = new FileInputStream(new File("/dev/zero"));
203     FileDescriptor fd = fis.getFD();
204     ByteBuffer byteBuffer = ByteBuffer.allocate(64);
205 
206     byteBuffer.position(0);
207     int read = Libcore.os.read(fd, byteBuffer);
208     assertTrue(read > 0);
209     assertEquals(read, byteBuffer.position());
210 
211     byteBuffer.position(4);
212     read = Libcore.os.read(fd, byteBuffer);
213     assertTrue(read > 0);
214     assertEquals(read + 4, byteBuffer.position());
215 
216     byteBuffer.position(0);
217     read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */);
218     assertTrue(read > 0);
219     assertEquals(read, byteBuffer.position());
220 
221     byteBuffer.position(4);
222     read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */);
223     assertTrue(read > 0);
224     assertEquals(read + 4, byteBuffer.position());
225 
226     fis.close();
227   }
228 
checkByteBufferPositions_sendto_recvfrom( int family, InetAddress loopback)229   static void checkByteBufferPositions_sendto_recvfrom(
230       int family, InetAddress loopback) throws Exception {
231     final FileDescriptor serverFd = Libcore.os.socket(family, SOCK_STREAM, 0);
232     Libcore.os.bind(serverFd, loopback, 0);
233     Libcore.os.listen(serverFd, 5);
234 
235     InetSocketAddress address = (InetSocketAddress) Libcore.os.getsockname(serverFd);
236 
237     final Thread server = new Thread(new Runnable() {
238       public void run() {
239         try {
240           InetSocketAddress peerAddress = new InetSocketAddress();
241           FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
242 
243           // Attempt to receive a maximum of 24 bytes from the client, and then
244           // close the connection.
245           ByteBuffer buffer = ByteBuffer.allocate(16);
246           int received = Libcore.os.recvfrom(clientFd, buffer, 0, null);
247           assertTrue(received > 0);
248           assertEquals(received, buffer.position());
249 
250           ByteBuffer buffer2 = ByteBuffer.allocate(16);
251           buffer2.position(8);
252           received = Libcore.os.recvfrom(clientFd, buffer2, 0, null);
253           assertTrue(received > 0);
254           assertEquals(received + 8, buffer.position());
255 
256           Libcore.os.close(clientFd);
257         } catch (Exception ex) {
258           throw new RuntimeException(ex);
259         }
260       }
261     });
262 
263     server.start();
264 
265     FileDescriptor clientFd = Libcore.os.socket(family, SOCK_STREAM, 0);
266     Libcore.os.connect(clientFd, address.getAddress(), address.getPort());
267 
268     final byte[] bytes = "good bye, cruel black hole with fancy distortion"
269         .getBytes(StandardCharsets.US_ASCII);
270     assertTrue(bytes.length > 24);
271 
272     ByteBuffer input = ByteBuffer.wrap(bytes);
273     input.position(0);
274     input.limit(16);
275 
276     int sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
277     assertTrue(sent > 0);
278     assertEquals(sent, input.position());
279 
280     input.position(16);
281     input.limit(24);
282     sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
283     assertTrue(sent > 0);
284     assertEquals(sent + 16, input.position());
285 
286     Libcore.os.close(clientFd);
287   }
288 
test_NetlinkSocket()289   public void test_NetlinkSocket() throws Exception {
290     FileDescriptor nlSocket = Libcore.os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
291     Libcore.os.bind(nlSocket, new NetlinkSocketAddress());
292     NetlinkSocketAddress address = (NetlinkSocketAddress) Libcore.os.getsockname(nlSocket);
293     assertTrue(address.getPortId() > 0);
294     assertEquals(0, address.getGroupsMask());
295 
296     NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
297     Libcore.os.connect(nlSocket, nlKernel);
298     NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Libcore.os.getpeername(nlSocket);
299     assertEquals(0, nlPeer.getPortId());
300     assertEquals(0, nlPeer.getGroupsMask());
301     Libcore.os.close(nlSocket);
302   }
303 
test_PacketSocketAddress()304   public void test_PacketSocketAddress() throws Exception {
305     NetworkInterface lo = NetworkInterface.getByName("lo");
306     FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
307     PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex());
308     Libcore.os.bind(fd, addr);
309 
310     PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd);
311     assertEquals((short) ETH_P_IPV6, bound.sll_protocol);  // ETH_P_IPV6 is an int.
312     assertEquals(lo.getIndex(), bound.sll_ifindex);
313     assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
314     assertEquals(0, bound.sll_pkttype);
315 
316     // The loopback address is ETH_ALEN bytes long and is all zeros.
317     // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
318     assertEquals(6, bound.sll_addr.length);
319     for (int i = 0; i < 6; i++) {
320       assertEquals(0, bound.sll_addr[i]);
321     }
322   }
323 
test_byteBufferPositions_sendto_recvfrom_af_inet()324   public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
325     checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
326   }
327 
test_byteBufferPositions_sendto_recvfrom_af_inet6()328   public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
329     checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
330   }
331 
checkSendToSocketAddress(int family, InetAddress loopback)332   private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
333     FileDescriptor recvFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
334     Libcore.os.bind(recvFd, loopback, 0);
335     StructTimeval tv = StructTimeval.fromMillis(20);
336     Libcore.os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
337 
338     InetSocketAddress to = ((InetSocketAddress) Libcore.os.getsockname(recvFd));
339     FileDescriptor sendFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
340     byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8");
341     int len = msg.length;
342 
343     assertEquals(len, Libcore.os.sendto(sendFd, msg, 0, len, 0, to));
344     byte[] received = new byte[msg.length + 42];
345     InetSocketAddress from = new InetSocketAddress();
346     assertEquals(len, Libcore.os.recvfrom(recvFd, received, 0, received.length, 0, from));
347     assertEquals(loopback, from.getAddress());
348   }
349 
test_sendtoSocketAddress_af_inet()350   public void test_sendtoSocketAddress_af_inet() throws Exception {
351     checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
352   }
353 
test_sendtoSocketAddress_af_inet6()354   public void test_sendtoSocketAddress_af_inet6() throws Exception {
355     checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
356   }
357 
test_socketFamilies()358   public void test_socketFamilies() throws Exception {
359     FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
360     Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
361     InetSocketAddress localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
362     assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
363 
364     fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
365     Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
366     localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
367     assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
368 
369     fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
370     Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
371     localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
372     assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
373     try {
374       Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
375       fail("Expected ErrnoException binding IPv4 socket to ::");
376     } catch (ErrnoException expected) {
377       assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, expected.errno);
378     }
379   }
380 
assertArrayEquals(byte[] expected, byte[] actual)381   private static void assertArrayEquals(byte[] expected, byte[] actual) {
382     assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
383         Arrays.equals(expected, actual));
384   }
385 
checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet, byte type, byte responseType, boolean useSendto)386   private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
387       byte type, byte responseType, boolean useSendto) throws Exception {
388     int len = packet.length;
389     packet[0] = type;
390     if (useSendto) {
391       assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, to, 0));
392     } else {
393       Libcore.os.connect(fd, to, 0);
394       assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, null, 0));
395     }
396 
397     int icmpId = ((InetSocketAddress) Libcore.os.getsockname(fd)).getPort();
398     byte[] received = new byte[4096];
399     InetSocketAddress srcAddress = new InetSocketAddress();
400     assertEquals(len, Libcore.os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
401     assertEquals(to, srcAddress.getAddress());
402     assertEquals(responseType, received[0]);
403     assertEquals(received[4], (byte) (icmpId >> 8));
404     assertEquals(received[5], (byte) (icmpId & 0xff));
405 
406     received = Arrays.copyOf(received, len);
407     received[0] = (byte) type;
408     received[2] = received[3] = 0;  // Checksum.
409     received[4] = received[5] = 0;  // ICMP ID.
410     assertArrayEquals(packet, received);
411   }
412 
test_socketPing()413   public void test_socketPing() throws Exception {
414     final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
415     final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
416     final byte[] packet = ("\000\000\000\000" +  // ICMP type, code.
417         "\000\000\000\003" +  // ICMP ID (== port), sequence number.
418         "Hello myself").getBytes(StandardCharsets.US_ASCII);
419 
420     FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
421     InetAddress ipv6Loopback = InetAddress.getByName("::1");
422     checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
423     checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
424 
425     fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
426     InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
427     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
428     checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
429   }
430 
test_Ipv4Fallback()431   public void test_Ipv4Fallback() throws Exception {
432     // This number of iterations gives a ~60% chance of creating the conditions that caused
433     // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C using
434     // vogar, this test takes about 4s.
435     final int ITERATIONS = 10000;
436     for (int i = 0; i < ITERATIONS; i++) {
437       FileDescriptor mUdpSock = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
438       try {
439           Libcore.os.bind(mUdpSock, Inet4Address.ANY, 0);
440       } catch(ErrnoException e) {
441           fail("ErrnoException after " + i + " iterations: " + e);
442       } finally {
443           Libcore.os.close(mUdpSock);
444       }
445     }
446   }
447 
test_unlink()448   public void test_unlink() throws Exception {
449     File f = File.createTempFile("OsTest", "tst");
450     assertTrue(f.exists());
451     Libcore.os.unlink(f.getAbsolutePath());
452     assertFalse(f.exists());
453 
454     try {
455       Libcore.os.unlink(f.getAbsolutePath());
456       fail();
457     } catch (ErrnoException e) {
458       assertEquals(OsConstants.ENOENT, e.errno);
459     }
460   }
461 
462   // b/27294715
test_recvfrom_concurrentShutdown()463   public void test_recvfrom_concurrentShutdown() throws Exception {
464       final FileDescriptor serverFd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
465       Libcore.os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0);
466       // Set 4s timeout
467       IoBridge.setSocketOption(serverFd, SocketOptions.SO_TIMEOUT, new Integer(4000));
468 
469       final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>(null);
470       final Thread killer = new Thread(new Runnable() {
471           public void run() {
472               try {
473                   Thread.sleep(2000);
474                   try {
475                       Libcore.os.shutdown(serverFd, SHUT_RDWR);
476                   } catch (ErrnoException expected) {
477                       if (OsConstants.ENOTCONN != expected.errno) {
478                           killerThreadException.set(expected);
479                       }
480                   }
481               } catch (Exception ex) {
482                   killerThreadException.set(ex);
483               }
484           }
485       });
486       killer.start();
487 
488       ByteBuffer buffer = ByteBuffer.allocate(16);
489       InetSocketAddress srcAddress = new InetSocketAddress();
490       int received = Libcore.os.recvfrom(serverFd, buffer, 0, srcAddress);
491       assertTrue(received == 0);
492       Libcore.os.close(serverFd);
493 
494       killer.join();
495       assertNull(killerThreadException.get());
496   }
497 
test_xattr()498   public void test_xattr() throws Exception {
499     final String NAME_TEST = "user.meow";
500 
501     final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
502     final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8);
503 
504     File file = File.createTempFile("xattr", "test");
505     String path = file.getAbsolutePath();
506 
507     byte[] tmp = new byte[1024];
508     try {
509       try {
510         Libcore.os.getxattr(path, NAME_TEST, tmp);
511         fail("Expected ENODATA");
512       } catch (ErrnoException e) {
513         assertEquals(OsConstants.ENODATA, e.errno);
514       }
515 
516       Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
517       assertEquals(VALUE_CAKE.length, Libcore.os.getxattr(path, NAME_TEST, tmp));
518       assertStartsWith(VALUE_CAKE, tmp);
519 
520       try {
521         Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE);
522         fail("Expected EEXIST");
523       } catch (ErrnoException e) {
524         assertEquals(OsConstants.EEXIST, e.errno);
525       }
526 
527       Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE);
528       assertEquals(VALUE_PIE.length, Libcore.os.getxattr(path, NAME_TEST, tmp));
529       assertStartsWith(VALUE_PIE, tmp);
530 
531       Libcore.os.removexattr(path, NAME_TEST);
532       try {
533         Libcore.os.getxattr(path, NAME_TEST, tmp);
534         fail("Expected ENODATA");
535       } catch (ErrnoException e) {
536         assertEquals(OsConstants.ENODATA, e.errno);
537       }
538 
539     } finally {
540       file.delete();
541     }
542   }
543 
test_realpath()544   public void test_realpath() throws Exception {
545       File tmpDir = new File(System.getProperty("java.io.tmpdir"));
546       // This is a chicken and egg problem. We have no way of knowing whether
547       // the temporary directory or one of its path elements were symlinked, so
548       // we'll need this call to realpath.
549       String canonicalTmpDir = Libcore.os.realpath(tmpDir.getAbsolutePath());
550 
551       // Test that "." and ".." are resolved correctly.
552       assertEquals(canonicalTmpDir,
553           Libcore.os.realpath(canonicalTmpDir + "/./../" + tmpDir.getName()));
554 
555       // Test that symlinks are resolved correctly.
556       File target = new File(tmpDir, "target");
557       File link = new File(tmpDir, "link");
558       try {
559           assertTrue(target.createNewFile());
560           Libcore.os.symlink(target.getAbsolutePath(), link.getAbsolutePath());
561 
562           assertEquals(canonicalTmpDir + "/target",
563               Libcore.os.realpath(canonicalTmpDir + "/link"));
564       } finally {
565           boolean deletedTarget = target.delete();
566           boolean deletedLink = link.delete();
567           // Asserting this here to provide a definitive reason for
568           // a subsequent failure on the same run.
569           assertTrue("deletedTarget = " + deletedTarget + ", deletedLink =" + deletedLink,
570               deletedTarget && deletedLink);
571       }
572   }
573 
assertStartsWith(byte[] expectedContents, byte[] container)574   private static void assertStartsWith(byte[] expectedContents, byte[] container) {
575     for (int i = 0; i < expectedContents.length; i++) {
576       if (expectedContents[i] != container[i]) {
577         fail("Expected " + Arrays.toString(expectedContents) + " but found "
578             + Arrays.toString(expectedContents));
579       }
580     }
581   }
582 }
583