Skip to content

Commit

Permalink
Implement native_misc library for macOS and Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Nov 23, 2019
1 parent 4047629 commit d935dda
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
*/
public class NativeConsole implements Console {

private static final Console backend =
Platform.isCurrentPlatform(Platform.WINDOWS) ? new WindowsNativeConsole() : new UnixNativeConsole();
private static final Console backend = Platform.isCurrentPlatform(Platform.WINDOWS)
? new WindowsNativeConsole()
: new UnixNativeConsole(
Platform.isCurrentPlatform(Platform.MAC_OS_X)
? com.microsoft.tfs.jni.internal.unix.macos.LibC.INSTANCE
: com.microsoft.tfs.jni.internal.unix.linux.LibC.INSTANCE);

public NativeConsole() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.microsoft.tfs.jni.internal.console;

import com.microsoft.tfs.jni.Console;
import com.microsoft.tfs.jni.internal.console.unix.LibC;
import com.microsoft.tfs.jni.internal.console.unix.termios;
import com.microsoft.tfs.jni.internal.console.unix.winsize;
import com.microsoft.tfs.jni.internal.unix.LibC;
import com.microsoft.tfs.jni.internal.unix.termios;
import com.microsoft.tfs.jni.internal.unix.winsize;

class UnixNativeConsole implements Console {

private final LibC libC;

public UnixNativeConsole(LibC libC) {
this.libC = libC;
}

private winsize getTtySize() {
LibC libC = LibC.INSTANCE;
int tty = libC.open("/dev/tty", LibC.O_RDONLY);
if (tty >= 0) {
try {
Expand All @@ -24,19 +29,20 @@ private winsize getTtySize() {
return null;
}

@Override public int getConsoleColumns() {
@Override
public int getConsoleColumns() {
winsize size = getTtySize();
return size == null ? 0 : size.ws_col;
}

@Override public int getConsoleRows() {
@Override
public int getConsoleRows() {
winsize size = getTtySize();
return size == null ? 0 : size.ws_row;
}

@Override public boolean disableEcho() {
LibC libC = LibC.INSTANCE;

@Override
public boolean disableEcho() {
termios settings = new termios();
if (libC.tcgetattr(LibC.STDIN_FILENO, settings) != 0)
return false;
Expand All @@ -46,9 +52,8 @@ private winsize getTtySize() {
return libC.tcsetattr(LibC.STDIN_FILENO, LibC.TCSANOW, settings) == 0;
}

@Override public boolean enableEcho() {
LibC libC = LibC.INSTANCE;

@Override
public boolean enableEcho() {
termios settings = new termios();
if (libC.tcgetattr(LibC.STDIN_FILENO, settings) != 0)
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.microsoft.tfs.jni.internal.platformmisc;

import com.microsoft.tfs.jni.internal.unix.linux.LibC;
import com.microsoft.tfs.jni.internal.unix.linux.passwd;
import com.sun.jna.platform.linux.XAttr;
import com.sun.jna.ptr.PointerByReference;

public class LinuxNativePlatformMisc extends UnixNativePlatformMisc {

private static final LibC libC = LibC.INSTANCE;

protected LinuxNativePlatformMisc() {
super(libC);
}

@Override
public String getHomeDirectory(String username) {
passwd pwd = new passwd();
byte[] pwdBuffer = new byte[1024];
PointerByReference tempPwdPtr = new PointerByReference();
if (libC.getpwnam_r(username, pwd, pwdBuffer, new XAttr.size_t(pwdBuffer.length), tempPwdPtr) != 0
|| tempPwdPtr.getValue() == null)
return null;

passwd tempPwd = new passwd(tempPwdPtr.getValue());
return tempPwd.pw_dir;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.microsoft.tfs.jni.internal.platformmisc;

import com.microsoft.tfs.jni.internal.unix.macos.*;
import com.sun.jna.platform.linux.XAttr;
import com.sun.jna.platform.mac.CoreFoundation;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

public class MacOsNativePlatformMisc extends UnixNativePlatformMisc {

private static final LibC libC = LibC.INSTANCE;
private static final CoreFoundation coreFoundation = CoreFoundation.INSTANCE;
private static final CoreServices coreServices = CoreServices.INSTANCE;
private static final SystemConfiguration systemConfiguration = SystemConfiguration.INSTANCE;

protected MacOsNativePlatformMisc() {
super(libC);
}

@Override
public String getHomeDirectory(String username) {
passwd pwd = new passwd();
byte[] pwdBuffer = new byte[1024];
PointerByReference tempPwdPtr = new PointerByReference();
if (libC.getpwnam_r(username, pwd, pwdBuffer, new XAttr.size_t(pwdBuffer.length), tempPwdPtr) != 0
|| tempPwdPtr.getValue() == null)
return null;

passwd tempPwd = new passwd(tempPwdPtr.getValue());
return tempPwd.pw_dir;
}

/**
* This will attempt to return the HostName system preference (10.4+). If that fails, this will attempt to return
* the LocalHostName system preference (aka, the Bonjour name as configured in Sharing preferences; 10.3+). This is
* to work around MacOS's dynamic hostname. If both of those fail this uses the Unix hostname.
*/
@Override
public String getComputerName() {
IntByReference osVersion = new IntByReference();
if (coreServices.Gestalt(CoreServices.gestaltSystemVersion, osVersion) != 0)
osVersion.setValue(0);

if (osVersion.getValue() >= 0x1040) {
CoreFoundation.CFStringRef microsoft = CoreFoundation.CFStringRef.createCFString("Microsoft");
try {
SCPreferencesRef configuration = systemConfiguration.SCPreferencesCreate(null, microsoft, null);
if (configuration != null) {
try {
CoreFoundation.CFStringRef hostName =
systemConfiguration.SCPreferencesGetHostName(configuration);
if (hostName != null) {
return hostName.stringValue();
}
} finally {
coreFoundation.CFRelease(configuration);
}
}
} finally {
CoreFoundation.INSTANCE.CFRelease(microsoft);
}
}

if (osVersion.getValue() >= 0x1030) {
CoreFoundation.CFStringRef hostName = systemConfiguration.SCDynamicStoreCopyLocalHostName(null);
if (hostName != null) {
try {
return hostName.stringValue();
} finally {
coreFoundation.CFRelease(hostName);
}
}
}

return super.getComputerName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
*/
public class NativePlatformMisc implements PlatformMisc {

private final PlatformMisc backend = Platform.isCurrentPlatform(Platform.WINDOWS)
? new WindowsNativePlatformMisc()
: null;
private final PlatformMisc backend;

/**
* This static initializer is a "best-effort" native code loader (no
Expand All @@ -39,6 +37,12 @@ public class NativePlatformMisc implements PlatformMisc {
}

public NativePlatformMisc() {
if (Platform.isCurrentPlatform(Platform.WINDOWS))
backend = new WindowsNativePlatformMisc();
else if (Platform.isCurrentPlatform(Platform.MAC_OS_X))
backend = new MacOsNativePlatformMisc();
else
backend = new LinuxNativePlatformMisc();
}

@Override
Expand All @@ -49,20 +53,14 @@ public String getHomeDirectory(final String username) {
return null;
}

return nativeGetHomeDirectory(username);
return backend.getHomeDirectory(username);
}

@Override
public boolean changeCurrentDirectory(final String directory) {
Check.notNull(directory, "directory"); //$NON-NLS-1$

boolean success;
if (backend != null)
success = backend.changeCurrentDirectory(directory);
else
success = nativeChangeCurrentDirectory(directory) == 0;

if (success) {
if (backend.changeCurrentDirectory(directory)) {
/*
* We must set this variable for Java classes to have any idea that
* the paths have changed. Canonical path is much nicer to
Expand All @@ -73,9 +71,11 @@ public boolean changeCurrentDirectory(final String directory) {
} catch (final IOException e) {
System.setProperty("user.dir", new File(directory).getAbsolutePath()); //$NON-NLS-1$
}

return true;
}

return success;
return false;
}

@Override
Expand All @@ -89,7 +89,7 @@ public int getDefaultCodePage() {

@Override
public String getComputerName() {
final String name = backend == null ? nativeGetComputerName() : backend.getComputerName();
final String name = backend.getComputerName();

if (name == null || name.length() == 0) {
return null;
Expand Down Expand Up @@ -129,23 +129,9 @@ public String getWellKnownSID(final int wellKnownSIDType, final String domainSID
: backend.getWellKnownSID(wellKnownSIDType, domainSIDString);
}

private static native int nativeChangeCurrentDirectory(String directory);

private static native String nativeGetComputerName();

private static native String nativeGetEnvironmentVariable(String name);

// WARNING: Following only available on Windows.

private static native int nativeGetDefaultCodePage();

private static native String nativeGetCurrentIdentityUser();

private static native String nativeExpandEnvironmentString(String value);

private static native String nativeGetWellKnownSID(int wellKnownSIDType, String domainSIDString);

// WARNING: Following only available on Unix.

private static native String nativeGetHomeDirectory(String username);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.microsoft.tfs.jni.internal.platformmisc;

import com.microsoft.tfs.jni.PlatformMisc;
import com.microsoft.tfs.jni.internal.unix.LibC;
import com.microsoft.tfs.jni.internal.unix.linux.passwd;
import com.sun.jna.platform.linux.XAttr;
import com.sun.jna.platform.unix.LibCAPI;
import com.sun.jna.ptr.PointerByReference;

import java.nio.charset.Charset;

public abstract class UnixNativePlatformMisc implements PlatformMisc {

private final LibC libC;

protected UnixNativePlatformMisc(LibC libC) {
this.libC = libC;
}

@Override
public boolean changeCurrentDirectory(String directory) {
return libC.chdir(directory) == 0;
}

@Override
public int getDefaultCodePage() {
throw new RuntimeException("Platform not supported");
}

@Override
public String getComputerName() {
byte[] buffer = new byte[LibCAPI.HOST_NAME_MAX];
if (libC.gethostname(buffer, buffer.length) != 0) {
return null;
}

return new String(buffer, Charset.defaultCharset());
}

@Override
public String getEnvironmentVariable(String name) {
return null;
}

@Override
public String expandEnvironmentString(String value) {
return null;
}

@Override
public String getCurrentIdentityUser() {
return null;
}

@Override
public String getWellKnownSID(int wellKnownSIDType, String domainSIDString) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
package com.microsoft.tfs.jni.internal.console.unix;
package com.microsoft.tfs.jni.internal.unix;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.linux.XAttr;
import com.sun.jna.ptr.PointerByReference;

public interface LibC extends Library {

LibC INSTANCE = (LibC) Native.loadLibrary("c", LibC.class);

public interface LibC extends com.sun.jna.platform.unix.LibC {
int O_RDONLY = 0;
long TIOCGWINSZ = Platform.isLinux() ? 0x5413L : 0x40087468L;
int STDIN_FILENO = 0;
int ECHO = 8;
int TCSANOW = 0;

int open(String pathname, int flags);

int close(int fd);

int ioctl(int fd, long cmd, winsize p);

int tcgetattr(int fd, termios termios_p);

int tcsetattr(int fd, int optional_actions, termios termios_p);

int chdir(String path);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.microsoft.tfs.jni.internal.unix.linux;

import com.sun.jna.Native;
import com.sun.jna.platform.linux.XAttr;
import com.sun.jna.ptr.PointerByReference;

public interface LibC extends com.microsoft.tfs.jni.internal.unix.LibC {
LibC INSTANCE = Native.load("c", LibC.class);

int getpwnam_r(String name, passwd pwd, byte[] buf, XAttr.size_t buflen, PointerByReference result);
}
Loading

0 comments on commit d935dda

Please sign in to comment.