mirokuratczyk 6 лет назад
Родитель
Сommit
13d46e09e2
4 измененных файлов с 112 добавлено и 84 удалено
  1. 18 12
      MobileLibrary/psi/psi.go
  2. 33 16
      psiphon/config.go
  3. 60 55
      psiphon/config_test.go
  4. 1 1
      psiphon/dataStoreRecovery_test.go

+ 18 - 12
MobileLibrary/psi/psi.go

@@ -54,40 +54,46 @@ func NoticeUserLog(message string) {
 	psiphon.NoticeUserLog(message)
 	psiphon.NoticeUserLog(message)
 }
 }
 
 
-// HomepageFilePath returns the path, relative to the configured data root
-// directory, where homepage files will be paved.
+// HomepageFilePath returns the path where homepage files will be paved.
+//
+// rootDataDirectoryPath is the configured data root directory.
 //
 //
 // Note: homepage files will only be paved if UseNoticeFiles is set in the
 // Note: homepage files will only be paved if UseNoticeFiles is set in the
 // config passed to Start().
 // config passed to Start().
 func HomepageFilePath(rootDataDirectoryPath string) string {
 func HomepageFilePath(rootDataDirectoryPath string) string {
-	return filepath.Join(rootDataDirectoryPath, psiphon.HomepageFilename)
+	return filepath.Join(rootDataDirectoryPath, psiphon.PsiphonDataDirectoryName, psiphon.HomepageFilename)
 }
 }
 
 
-// NoticesFilePath returns the path, relative to the configured data root
-// directory, where the notices file will be paved.
+// NoticesFilePath returns the path where the notices file will be paved.
+//
+// rootDataDirectoryPath is the configured data root directory.
 //
 //
 // Note: notices will only be paved if UseNoticeFiles is set in the config
 // Note: notices will only be paved if UseNoticeFiles is set in the config
 // passed to Start().
 // passed to Start().
 func NoticesFilePath(rootDataDirectoryPath string) string {
 func NoticesFilePath(rootDataDirectoryPath string) string {
-	return filepath.Join(rootDataDirectoryPath, psiphon.NoticesFilename)
+	return filepath.Join(rootDataDirectoryPath, psiphon.PsiphonDataDirectoryName, psiphon.NoticesFilename)
 }
 }
 
 
-// OldNoticesFilePath returns the path, relative to the configured data root
-// directory, where the notices file is moved to when file rotation occurs.
+// OldNoticesFilePath returns the path where the notices file is moved to when
+// file rotation occurs.
+//
+// rootDataDirectoryPath is the configured data root directory.
 //
 //
 // Note: notices will only be paved if UseNoticeFiles is set in the config
 // Note: notices will only be paved if UseNoticeFiles is set in the config
 // passed to Start().
 // passed to Start().
 func OldNoticesFilePath(rootDataDirectoryPath string) string {
 func OldNoticesFilePath(rootDataDirectoryPath string) string {
-	return filepath.Join(rootDataDirectoryPath, psiphon.OldNoticesFilename)
+	return filepath.Join(rootDataDirectoryPath, psiphon.PsiphonDataDirectoryName, psiphon.OldNoticesFilename)
 }
 }
 
 
-// UpgradeDownloadFilePath returns the path, relative to the configured data
-// root directory, where the downloaded upgrade file will be paved.
+// UpgradeDownloadFilePath returns the path where the downloaded upgrade file
+// will be paved.
+//
+// rootDataDirectoryPath is the configured data root directory.
 //
 //
 // Note: upgrades will only be paved if UpgradeDownloadURLs is set in the config
 // Note: upgrades will only be paved if UpgradeDownloadURLs is set in the config
 // passed to Start() and there are upgrades available.
 // passed to Start() and there are upgrades available.
 func UpgradeDownloadFilePath(rootDataDirectoryPath string) string {
 func UpgradeDownloadFilePath(rootDataDirectoryPath string) string {
-	return filepath.Join(rootDataDirectoryPath, psiphon.UpgradeDownloadFilename)
+	return filepath.Join(rootDataDirectoryPath, psiphon.PsiphonDataDirectoryName, psiphon.UpgradeDownloadFilename)
 }
 }
 
 
 var controllerMutex sync.Mutex
 var controllerMutex sync.Mutex

+ 33 - 16
psiphon/config.go

@@ -44,8 +44,11 @@ import (
 const (
 const (
 	TUNNEL_POOL_SIZE = 1
 	TUNNEL_POOL_SIZE = 1
 
 
-	// Filename constants.
-	// All relative to the configured DataRootDirectory.
+	// Psiphon data directory name, relative to config.DataRootDirectory.
+	// See config.GetPsiphonDataDirectory().
+	PsiphonDataDirectoryName = "ca.psiphon.PsiphonTunnel.tunnel-core"
+
+	// Filename constants, all relative to config.GetPsiphonDataDirectory().
 	HomepageFilename        = "homepage"
 	HomepageFilename        = "homepage"
 	NoticesFilename         = "notices"
 	NoticesFilename         = "notices"
 	OldNoticesFilename      = "notices.1"
 	OldNoticesFilename      = "notices.1"
@@ -66,11 +69,6 @@ type Config struct {
 	//
 	//
 	// Psiphon will assume full control of files under this directory. They may
 	// Psiphon will assume full control of files under this directory. They may
 	// be deleted, moved or overwritten.
 	// be deleted, moved or overwritten.
-	//
-	// Warning: If the datastore file,
-	// DataRootDirectory/datastore/DATA_STORE_FILENAME, exists but fails to open
-	// for any reason (checksum error, unexpected file format, etc.) it will be
-	// deleted in order to pave a new datastore and continue running.
 	DataRootDirectory string
 	DataRootDirectory string
 
 
 	// UseNoticeFiles configures notice files for writing. If set, homepages
 	// UseNoticeFiles configures notice files for writing. If set, homepages
@@ -801,6 +799,15 @@ func (config *Config) Commit() error {
 		config.DataRootDirectory = wd
 		config.DataRootDirectory = wd
 	}
 	}
 
 
+	// Create root directory
+	rootDirectoryPath := config.GetPsiphonDataDirectory()
+	if !common.FileExists(rootDirectoryPath) {
+		err := os.Mkdir(rootDirectoryPath, os.ModePerm)
+		if err != nil {
+			return errors.Tracef("failed to create datastore directory %s with error: %s", rootDirectoryPath, err.Error())
+		}
+	}
+
 	// Create datastore directory.
 	// Create datastore directory.
 	dataStoreDirectoryPath := config.GetDataStoreDirectory()
 	dataStoreDirectoryPath := config.GetDataStoreDirectory()
 	if !common.FileExists(dataStoreDirectoryPath) {
 	if !common.FileExists(dataStoreDirectoryPath) {
@@ -838,7 +845,7 @@ func (config *Config) Commit() error {
 
 
 	// Check if the migration from legacy config fields has already been
 	// Check if the migration from legacy config fields has already been
 	// completed. See the Migrate* config fields for more details.
 	// completed. See the Migrate* config fields for more details.
-	migrationCompleteFilePath := filepath.Join(config.DataRootDirectory, "ca.psiphon.PsiphonTunnel.tunnel-core_migration_complete")
+	migrationCompleteFilePath := filepath.Join(config.GetPsiphonDataDirectory(), "migration_complete")
 	needMigration := !common.FileExists(migrationCompleteFilePath)
 	needMigration := !common.FileExists(migrationCompleteFilePath)
 
 
 	// Collect notices to emit them after notice files are set
 	// Collect notices to emit them after notice files are set
@@ -1265,42 +1272,52 @@ func (config *Config) GetAuthorizations() []string {
 	return config.authorizations
 	return config.authorizations
 }
 }
 
 
+// GetPsiphonDataDirectory returns the directory under which all persistent
+// files should be stored. This directory is created under
+// config.DataRootDirectory. The motivation for an additional directory is that
+// config.DataRootDirectory defaults to the current working directory, which may
+// include non-tunnel-core files that should be excluded from directory-spanning
+// operations (e.g. excluding all tunnel-core files from backup).
+func (config *Config) GetPsiphonDataDirectory() string {
+	return filepath.Join(config.DataRootDirectory, PsiphonDataDirectoryName)
+}
+
 // GetHomePageFilename the path where the homepage notices file will be created.
 // GetHomePageFilename the path where the homepage notices file will be created.
 func (config *Config) GetHomePageFilename() string {
 func (config *Config) GetHomePageFilename() string {
-	return filepath.Join(config.DataRootDirectory, HomepageFilename)
+	return filepath.Join(config.GetPsiphonDataDirectory(), HomepageFilename)
 }
 }
 
 
 // GetNoticesFilename returns the path where the notices file will be created.
 // GetNoticesFilename returns the path where the notices file will be created.
 // When the file is rotated it will be moved to config.GetOldNoticesFilename().
 // When the file is rotated it will be moved to config.GetOldNoticesFilename().
 func (config *Config) GetNoticesFilename() string {
 func (config *Config) GetNoticesFilename() string {
-	return filepath.Join(config.DataRootDirectory, NoticesFilename)
+	return filepath.Join(config.GetPsiphonDataDirectory(), NoticesFilename)
 }
 }
 
 
 // GetOldNoticeFilename returns the path where the rotated notices file will be
 // GetOldNoticeFilename returns the path where the rotated notices file will be
 // created.
 // created.
 func (config *Config) GetOldNoticesFilename() string {
 func (config *Config) GetOldNoticesFilename() string {
-	return filepath.Join(config.DataRootDirectory, OldNoticesFilename)
+	return filepath.Join(config.GetPsiphonDataDirectory(), OldNoticesFilename)
 }
 }
 
 
 // GetDataStoreDirectory returns the directory in which the persistent database
 // GetDataStoreDirectory returns the directory in which the persistent database
 // will be stored. Created in Config.Commit(). The persistent database contains
 // will be stored. Created in Config.Commit(). The persistent database contains
 // information such as server entries.
 // information such as server entries.
 func (config *Config) GetDataStoreDirectory() string {
 func (config *Config) GetDataStoreDirectory() string {
-	return filepath.Join(config.DataRootDirectory, "datastore")
+	return filepath.Join(config.GetPsiphonDataDirectory(), "datastore")
 }
 }
 
 
 // GetObfuscatedServerListDownloadDirectory returns the directory in which
 // GetObfuscatedServerListDownloadDirectory returns the directory in which
 // obfuscated remote server list downloads will be stored. Created in
 // obfuscated remote server list downloads will be stored. Created in
 // Config.Commit().
 // Config.Commit().
 func (config *Config) GetObfuscatedServerListDownloadDirectory() string {
 func (config *Config) GetObfuscatedServerListDownloadDirectory() string {
-	return filepath.Join(config.DataRootDirectory, "osl")
+	return filepath.Join(config.GetPsiphonDataDirectory(), "osl")
 }
 }
 
 
 // GetRemoteServerListDownloadFilename returns the filename where the remote
 // GetRemoteServerListDownloadFilename returns the filename where the remote
 // server list download will be stored. Data is stored in co-located files
 // server list download will be stored. Data is stored in co-located files
 // (RemoteServerListDownloadFilename.part*) to allow for resumable downloading.
 // (RemoteServerListDownloadFilename.part*) to allow for resumable downloading.
 func (config *Config) GetRemoteServerListDownloadFilename() string {
 func (config *Config) GetRemoteServerListDownloadFilename() string {
-	return filepath.Join(config.DataRootDirectory, "remote_server_list")
+	return filepath.Join(config.GetPsiphonDataDirectory(), "remote_server_list")
 }
 }
 
 
 // GetUpgradeDownloadFilename specifies the filename where upgrade downloads
 // GetUpgradeDownloadFilename specifies the filename where upgrade downloads
@@ -1308,13 +1325,13 @@ func (config *Config) GetRemoteServerListDownloadFilename() string {
 // (or UpgradeDownloadUrl) is specified. Data is stored in co-located files
 // (or UpgradeDownloadUrl) is specified. Data is stored in co-located files
 // (UpgradeDownloadFilename.part*) to allow for resumable downloading.
 // (UpgradeDownloadFilename.part*) to allow for resumable downloading.
 func (config *Config) GetUpgradeDownloadFilename() string {
 func (config *Config) GetUpgradeDownloadFilename() string {
-	return filepath.Join(config.DataRootDirectory, UpgradeDownloadFilename)
+	return filepath.Join(config.GetPsiphonDataDirectory(), UpgradeDownloadFilename)
 }
 }
 
 
 // GetTapdanceDirectory returns the directory under which tapdance will create
 // GetTapdanceDirectory returns the directory under which tapdance will create
 // and manage files.
 // and manage files.
 func (config *Config) GetTapdanceDirectory() string {
 func (config *Config) GetTapdanceDirectory() string {
-	return filepath.Join(config.DataRootDirectory, "tapdance")
+	return filepath.Join(config.GetPsiphonDataDirectory(), "tapdance")
 }
 }
 
 
 // UseUpstreamProxy indicates if an upstream proxy has been
 // UseUpstreamProxy indicates if an upstream proxy has been

+ 60 - 55
psiphon/config_test.go

@@ -389,85 +389,90 @@ func (suite *ConfigTestSuite) Test_LoadConfig_Migrate() {
 				Name: "data_root_directory",
 				Name: "data_root_directory",
 				Children: []FileTree{
 				Children: []FileTree{
 					{
 					{
-						Name: "ca.psiphon.PsiphonTunnel.tunnel-core_migration_complete",
-					},
-					{
-						Name: "remote_server_list",
-					},
-					{
-						Name: "remote_server_list.part",
-					},
-					{
-						Name: "remote_server_list.part.etag",
+						Name: "non_tunnel_core_file_should_not_be_clobbered",
 					},
 					},
 					{
 					{
-						Name: "datastore",
+						Name: "ca.psiphon.PsiphonTunnel.tunnel-core",
 						Children: []FileTree{
 						Children: []FileTree{
 							{
 							{
-								Name: "psiphon.boltdb",
+								Name: "migration_complete",
 							},
 							},
 							{
 							{
-								Name: "psiphon.boltdb.lock",
+								Name: "remote_server_list",
 							},
 							},
-						},
-					},
-					{
-						Name: "osl",
-						Children: []FileTree{
 							{
 							{
-								Name: "osl-registry",
+								Name: "remote_server_list.part",
 							},
 							},
 							{
 							{
-								Name: "osl-registry.cached",
+								Name: "remote_server_list.part.etag",
 							},
 							},
 							{
 							{
-								Name: "osl-1",
+								Name: "datastore",
+								Children: []FileTree{
+									{
+										Name: "psiphon.boltdb",
+									},
+									{
+										Name: "psiphon.boltdb.lock",
+									},
+								},
 							},
 							},
 							{
 							{
-								Name: "osl-1.part",
+								Name: "osl",
+								Children: []FileTree{
+									{
+										Name: "osl-registry",
+									},
+									{
+										Name: "osl-registry.cached",
+									},
+									{
+										Name: "osl-1",
+									},
+									{
+										Name: "osl-1.part",
+									},
+								},
 							},
 							},
-						},
-					},
-					{
-						Name: "tapdance",
-						Children: []FileTree{
 							{
 							{
 								Name: "tapdance",
 								Name: "tapdance",
 								Children: []FileTree{
 								Children: []FileTree{
 									{
 									{
-										Name: "file1",
-									},
-									{
-										Name: "file2",
+										Name: "tapdance",
+										Children: []FileTree{
+											{
+												Name: "file1",
+											},
+											{
+												Name: "file2",
+											},
+										},
 									},
 									},
 								},
 								},
 							},
 							},
+							{
+								Name: "upgrade",
+							},
+							{
+								Name: "upgrade.1234",
+							},
+							{
+								Name: "upgrade.1234.part",
+							},
+							{
+								Name: "upgrade.1234.part.etag",
+							},
+							{
+								Name: "notices",
+							},
+							{
+								Name: "notices.1",
+							},
+							{
+								Name: "homepage",
+							},
 						},
 						},
 					},
 					},
-					{
-						Name: "upgrade",
-					},
-					{
-						Name: "upgrade.1234",
-					},
-					{
-						Name: "upgrade.1234.part",
-					},
-					{
-						Name: "upgrade.1234.part.etag",
-					},
-					{
-						Name: "notices",
-					},
-					{
-						Name: "notices.1",
-					},
-					{
-						Name: "homepage",
-					},
-					{
-						Name: "non_tunnel_core_file_should_not_be_clobbered",
-					},
 				},
 				},
 			},
 			},
 			{
 			{

+ 1 - 1
psiphon/dataStoreRecovery_test.go

@@ -190,7 +190,7 @@ func TestBoltResiliency(t *testing.T) {
 	}
 	}
 
 
 	truncateDataStore := func() {
 	truncateDataStore := func() {
-		filename := filepath.Join(testDataDirName, "datastore", "psiphon.boltdb")
+		filename := filepath.Join(testDataDirName, "ca.psiphon.PsiphonTunnel.tunnel-core", "datastore", "psiphon.boltdb")
 		configFile, err := os.OpenFile(filename, os.O_RDWR, 0666)
 		configFile, err := os.OpenFile(filename, os.O_RDWR, 0666)
 		if err != nil {
 		if err != nil {
 			t.Fatalf("OpenFile failed: %s", err)
 			t.Fatalf("OpenFile failed: %s", err)