Expose smb.conf to external storage. (#21)
* Consolidate ShareManager into the unified init process. * Remove misc.xml * Expose smb.conf to external storage. Some clean-up on initialization code. Fix a bug that doesn't restart SMB client after configuration is updated. * Use the right TAG. * Guard a log behind debug flag.
This commit is contained in:
parent
6b1a97b626
commit
b16d629dc5
2 changed files with 86 additions and 41 deletions
|
@ -45,42 +45,75 @@ class SambaConfiguration implements Iterable<Map.Entry<String, String>> {
|
|||
private static final String CONF_KEY_VALUE_SEPARATOR = " = ";
|
||||
|
||||
private final File mHomeFolder;
|
||||
private final File mShareFolder;
|
||||
private final Map<String, String> mConfigurations = new HashMap<>();
|
||||
|
||||
SambaConfiguration(File homeFolder) {
|
||||
SambaConfiguration(File homeFolder, @Nullable File shareFolder) {
|
||||
mHomeFolder = homeFolder;
|
||||
if (shareFolder != null && (shareFolder.isDirectory() || shareFolder.mkdirs())) {
|
||||
mShareFolder = shareFolder;
|
||||
} else {
|
||||
Log.w(TAG, "Failed to create share folder. Only default value is supported.");
|
||||
|
||||
// Use home folder as the share folder to avoid null checks everywhere.
|
||||
mShareFolder = mHomeFolder;
|
||||
}
|
||||
|
||||
setHomeEnv(homeFolder.getAbsolutePath());
|
||||
}
|
||||
|
||||
public void flushAsDefault() {
|
||||
void flushDefault(OnConfigurationChangedListener listener) {
|
||||
// lmhosts are not used in SambaDocumentsProvider and prioritize bcast because sometimes in home
|
||||
// settings DNS will resolve unknown domain name to a specific IP for advertisement.
|
||||
//
|
||||
// lmhosts -- lmhosts file if existed side by side to smb.conf
|
||||
// wins -- Windows Internet Name Service
|
||||
// hosts -- hosts file and DNS resolution
|
||||
// bcast -- NetBIOS broadcast
|
||||
addConfiguration("name resolve order", "wins bcast hosts");
|
||||
|
||||
// Urge from users to disable SMB1 by default.
|
||||
addConfiguration("client min protocol", "SMB2");
|
||||
addConfiguration("client max protocol", "SMB3");
|
||||
|
||||
File smbFile = getSmbFile(mHomeFolder);
|
||||
if (!smbFile.exists()) {
|
||||
flush(null);
|
||||
flush(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized SambaConfiguration addConfiguration(String key, String value) {
|
||||
synchronized SambaConfiguration addConfiguration(String key, String value) {
|
||||
mConfigurations.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized SambaConfiguration removeConfiguration(String key) {
|
||||
synchronized SambaConfiguration removeConfiguration(String key) {
|
||||
mConfigurations.remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void load(OnConfigurationChangedListener listener) {
|
||||
new LoadTask(listener).execute();
|
||||
boolean syncFromExternal(OnConfigurationChangedListener listener) {
|
||||
final File smbFile = getSmbFile(mHomeFolder);
|
||||
final File extSmbFile = getExtSmbFile(mShareFolder);
|
||||
|
||||
if (extSmbFile.isFile() && extSmbFile.lastModified() > smbFile.lastModified()) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Syncing " + SMB_CONF_FILE +
|
||||
" from external source to internal source.");
|
||||
new SyncTask(listener).execute(extSmbFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void flush(@Nullable OnConfigurationChangedListener listener) {
|
||||
private void flush(OnConfigurationChangedListener listener) {
|
||||
new FlushTask(listener).execute();
|
||||
}
|
||||
|
||||
private synchronized void read() throws IOException {
|
||||
private synchronized void read(File smbFile) throws IOException {
|
||||
mConfigurations.clear();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(getSmbFile(mHomeFolder)))) {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(smbFile))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] conf = line.split(CONF_KEY_VALUE_SEPARATOR);
|
||||
|
@ -113,6 +146,10 @@ class SambaConfiguration implements Iterable<Map.Entry<String, String>> {
|
|||
return new File(smbFolder, SMB_CONF_FILE);
|
||||
}
|
||||
|
||||
private static File getExtSmbFile(File shareFolder) {
|
||||
return new File(shareFolder, SMB_CONF_FILE);
|
||||
}
|
||||
|
||||
private void setHomeEnv(String absoluteFolder) {
|
||||
try {
|
||||
setEnv(HOME_VAR, absoluteFolder);
|
||||
|
@ -128,16 +165,18 @@ class SambaConfiguration implements Iterable<Map.Entry<String, String>> {
|
|||
return mConfigurations.entrySet().iterator();
|
||||
}
|
||||
|
||||
private class LoadTask extends BiResultTask<Void, Void, Void> {
|
||||
private class SyncTask extends BiResultTask<File, Void, Void> {
|
||||
|
||||
private final OnConfigurationChangedListener mListener;
|
||||
|
||||
private LoadTask(OnConfigurationChangedListener listener) {
|
||||
private SyncTask(OnConfigurationChangedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void run(Void... params) throws IOException {
|
||||
read();
|
||||
public Void run(File... params) throws IOException {
|
||||
read(params[0]);
|
||||
write();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -148,9 +187,9 @@ class SambaConfiguration implements Iterable<Map.Entry<String, String>> {
|
|||
}
|
||||
|
||||
private class FlushTask extends BiResultTask<Void, Void, Void> {
|
||||
private final @Nullable OnConfigurationChangedListener mListener;
|
||||
private final OnConfigurationChangedListener mListener;
|
||||
|
||||
private FlushTask(@Nullable OnConfigurationChangedListener listener) {
|
||||
private FlushTask(OnConfigurationChangedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
|
@ -162,9 +201,7 @@ class SambaConfiguration implements Iterable<Map.Entry<String, String>> {
|
|||
|
||||
@Override
|
||||
public void onSucceeded(Void result) {
|
||||
if (mListener != null) {
|
||||
mListener.onConfigurationChanged();
|
||||
}
|
||||
mListener.onConfigurationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,21 +25,22 @@ import android.net.Network;
|
|||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
|
||||
import android.util.Log;
|
||||
import com.google.android.sambadocumentsprovider.SambaConfiguration.OnConfigurationChangedListener;
|
||||
import com.google.android.sambadocumentsprovider.cache.DocumentCache;
|
||||
import com.google.android.sambadocumentsprovider.nativefacade.CredentialCache;
|
||||
import com.google.android.sambadocumentsprovider.nativefacade.SambaMessageLooper;
|
||||
import com.google.android.sambadocumentsprovider.nativefacade.SmbFacade;
|
||||
import java.io.File;
|
||||
|
||||
public class SambaProviderApplication extends Application {
|
||||
|
||||
private static final String TAG = "SambaProviderApplication";
|
||||
|
||||
private final DocumentCache mCache = new DocumentCache();
|
||||
private final TaskManager mTaskManager = new TaskManager();
|
||||
|
||||
private SmbFacade mSambaClient;
|
||||
private CredentialCache mCredentialCache;
|
||||
|
||||
private SambaConfiguration mSambaConf;
|
||||
private ShareManager mShareManager;
|
||||
|
||||
@Override
|
||||
|
@ -49,10 +50,6 @@ public class SambaProviderApplication extends Application {
|
|||
init(this);
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
((SambaProviderApplication) context.getApplicationContext()).initialize(context);
|
||||
}
|
||||
|
||||
private void initialize(Context context) {
|
||||
if (mSambaClient != null) {
|
||||
// Already initialized.
|
||||
|
@ -62,30 +59,38 @@ public class SambaProviderApplication extends Application {
|
|||
initializeSambaConf(context);
|
||||
|
||||
final SambaMessageLooper looper = new SambaMessageLooper();
|
||||
mCredentialCache = looper.getCredentialCache();
|
||||
CredentialCache credentialCache = looper.getCredentialCache();
|
||||
mSambaClient = looper.getClient();
|
||||
|
||||
mShareManager = new ShareManager(context, mCredentialCache);
|
||||
mShareManager = new ShareManager(context, credentialCache);
|
||||
|
||||
registerNetworkCallback(context);
|
||||
}
|
||||
|
||||
private void initializeSambaConf(Context context) {
|
||||
mSambaConf = new SambaConfiguration(context.getDir("home", MODE_PRIVATE));
|
||||
final File home = context.getDir("home", MODE_PRIVATE);
|
||||
final File share = context.getExternalFilesDir(null);
|
||||
final SambaConfiguration sambaConf = new SambaConfiguration(home, share);
|
||||
|
||||
// lmhosts are not used in SambaDocumentsProvider and prioritize bcast because sometimes in home
|
||||
// settings DNS will resolve unknown domain name to a specific IP for advertisement.
|
||||
//
|
||||
// lmhosts -- lmhosts file if existed side by side to smb.conf
|
||||
// wins -- Windows Internet Name Service
|
||||
// hosts -- hosts file and DNS resolution
|
||||
// bcast -- NetBIOS broadcast
|
||||
mSambaConf.addConfiguration("name resolve order", "wins bcast hosts");
|
||||
final OnConfigurationChangedListener listener = new OnConfigurationChangedListener() {
|
||||
@Override
|
||||
public void onConfigurationChanged() {
|
||||
if (mSambaClient != null) {
|
||||
mSambaClient.reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Urge from users to disable SMB1 by default.
|
||||
mSambaConf.addConfiguration("client min protocol", "SMB2");
|
||||
mSambaConf.addConfiguration("client max protocol", "SMB3");
|
||||
mSambaConf.flushAsDefault();
|
||||
// Sync from external folder. The reason why we don't use external folder directly as HOME is
|
||||
// because there are cases where external storage is not ready, and we don't have an external
|
||||
// folder at all.
|
||||
if (sambaConf.syncFromExternal(listener)) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Syncing smb.conf from external folder. No need to try "
|
||||
+ "flushing default config.");
|
||||
return;
|
||||
}
|
||||
|
||||
sambaConf.flushDefault(listener);
|
||||
}
|
||||
|
||||
private void registerNetworkCallback(Context context) {
|
||||
|
@ -102,7 +107,10 @@ public class SambaProviderApplication extends Application {
|
|||
mSambaClient.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
getApplication(context).initialize(context);
|
||||
}
|
||||
|
||||
public static ShareManager getServerManager(Context context) {
|
||||
|
|
Loading…
Reference in a new issue