Skip to content

Commit 35481e2

Browse files
jonsimantova-maurice
authored andcommitted
Add GetAppDataPath() to get application-specific data path for storing files for the user.
Adds shell32 linker requirement for Windows. PiperOrigin-RevId: 313681313
1 parent 5c2073c commit 35481e2

File tree

5 files changed

+190
-1
lines changed

5 files changed

+190
-1
lines changed

database/CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,18 @@ elseif(IOS)
139139
set(database_platform_SRCS
140140
"${ios_SRCS}")
141141
else()
142+
# Add platform-specific util files.
143+
if(MSVC)
144+
set(desktop_extra_SRCS src/desktop/util_desktop_windows.cc)
145+
elseif(APPLE)
146+
set(desktop_extra_SRCS src/desktop/util_desktop_macos.mm)
147+
else()
148+
# Linux
149+
set(desktop_extra_SRCS src/desktop/util_desktop_linux.cc)
150+
endif()
142151
set(database_platform_SRCS
143-
"${desktop_SRCS}")
152+
"${desktop_SRCS}"
153+
"${desktop_extra_SRCS}")
144154
endif()
145155

146156
if(ANDROID OR IOS)

database/src/desktop/util_desktop.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@ std::string WireProtocolPathToString(const Path& path);
347347
// NOTE: Don't change this unless you're changing the wire protocol!
348348
Variant GetWireProtocolParams(const QueryParams& query_params);
349349

350+
// Get a local path that you can use for storing app-specific files.
351+
// This is platform-specific. If it returns an empty string, it was
352+
// unable to find a proper path and you can just use the current directory
353+
// or whatever.
354+
std::string GetAppDataPath(const char* app_name, bool should_create = true);
355+
350356
} // namespace internal
351357
} // namespace database
352358
} // namespace firebase
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2017 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <dirent.h>
16+
#include <pwd.h>
17+
#include <sys/stat.h>
18+
#include <sys/types.h>
19+
#include <unistd.h>
20+
21+
#include "database/src/desktop/util_desktop.h"
22+
23+
namespace firebase {
24+
namespace database {
25+
namespace internal {
26+
27+
std::string GetAppDataPath(const char* app_name, bool should_create) {
28+
// On Linux, use XDG data home, usually $HOME/.local/share/$app_name, or user
29+
// home directory otherwise.
30+
31+
const char* xdg_data_home = getenv("XDG_DATA_HOME");
32+
if (xdg_data_home) {
33+
// Assume that this directory already exists.
34+
return std::string(xdg_data_home);
35+
}
36+
std::string home_directory = "";
37+
38+
const char* home = getenv("HOME");
39+
if (home) {
40+
home_directory = std::string(home);
41+
} else {
42+
// Get home directory from user info.
43+
passwd pwd;
44+
passwd* result;
45+
auto buffer_size = static_cast<size_t>(sysconf(_SC_GETPW_R_SIZE_MAX));
46+
std::string buffer(buffer_size, '\0');
47+
uid_t uid = getuid();
48+
int rc;
49+
do {
50+
rc = getpwuid_r(uid, &pwd, &buffer[0], buffer_size, &result);
51+
} while (rc == EINTR);
52+
if (rc == 0) {
53+
home_directory = std::string(pwd.pw_dir);
54+
}
55+
}
56+
if (home_directory.empty()) return "";
57+
58+
// Make sure home/.local/share exists, ignore "already exists" errors making
59+
// these directories.
60+
if (should_create) {
61+
int retval;
62+
retval = mkdir((home_directory + "/.local").c_str(), 0700);
63+
if (retval != 0 && errno != EEXIST) return "";
64+
retval = mkdir((home_directory + "/.local/share").c_str(), 0700);
65+
if (retval != 0 && errno != EEXIST) return "";
66+
retval = mkdir((home_directory + "/.local/share" + app_name).c_str(), 0700);
67+
if (retval != 0 && errno != EEXIST) return "";
68+
}
69+
return (home_directory + "/.local/share" + app_name);
70+
}
71+
72+
} // namespace internal
73+
} // namespace database
74+
} // namespace firebase
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2017 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#import <Foundation/Foundation.h>
16+
17+
#include <sys/stat.h>
18+
#include <sys/types.h>
19+
#include "database/src/desktop/util_desktop.h"
20+
21+
namespace firebase {
22+
namespace database {
23+
namespace internal {
24+
25+
std::string GetAppDataPath(const char* app_name, bool should_create) {
26+
NSArray<NSString*>* directories =
27+
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
28+
std::string path = directories[0].UTF8String;
29+
if (should_create) {
30+
int retval;
31+
retval = mkdir(path.c_str(), 0700);
32+
if (retval != 0 && errno != EEXIST) return "";
33+
retval = mkdir((path + "/" + app_name).c_str(), 0700);
34+
if (retval != 0 && errno != EEXIST) return "";
35+
}
36+
return path + "/" + app_name;
37+
}
38+
39+
} // namespace internal
40+
} // namespace database
41+
} // namespace firebase
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2017 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <direct.h>
16+
#include <shlobj.h>
17+
#include <stringapiset.h>
18+
19+
#include <iostream>
20+
#include <string>
21+
22+
#include "app/src/log.h"
23+
#include "database/src/desktop/util_desktop.h"
24+
25+
namespace firebase {
26+
namespace database {
27+
namespace internal {
28+
29+
static std::string utf8_encode(const std::wstring& wstr) {
30+
if (wstr.empty()) return std::string();
31+
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(),
32+
NULL, 0, NULL, NULL);
33+
std::string strTo(size_needed, 0);
34+
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0],
35+
size_needed, NULL, NULL);
36+
return strTo;
37+
}
38+
39+
std::string GetAppDataPath(const char* app_name, bool should_create) {
40+
wchar_t* pwstr = nullptr;
41+
HRESULT result = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pwstr);
42+
if (result != S_OK) {
43+
return "";
44+
}
45+
std::wstring wstr(pwstr);
46+
CoTaskMemFree(static_cast<void*>(pwstr));
47+
std::string dir = utf8_encode(wstr);
48+
if (dir == "") return "";
49+
if (should_create) {
50+
int retval = _mkdir((dir + "\\" + app_name).c_str());
51+
if (retval != 0 && errno != EEXIST) return "";
52+
}
53+
return dir + "\\" + app_name;
54+
}
55+
56+
} // namespace internal
57+
} // namespace database
58+
} // namespace firebase

0 commit comments

Comments
 (0)