1 /*
2 * SessionPerFilePathStorage.cpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #include <shared_core/Error.hpp>
17 #include <shared_core/FilePath.hpp>
18
19 #include <core/FileSerializer.hpp>
20 #include <core/FileUtils.hpp>
21
22 #include <session/SessionModuleContext.hpp>
23
24 using namespace rstudio::core;
25
26 namespace rstudio {
27 namespace session {
28 namespace module_context {
29
perFilePathStorage(const std::string & scope,const FilePath & filePath,bool directory,FilePath * pStorage)30 Error perFilePathStorage(const std::string& scope, const FilePath& filePath, bool directory, FilePath* pStorage)
31 {
32 // url escape path (so we can use key=value persistence)
33 std::string escapedPath = http::util::urlEncode(filePath.getAbsolutePath());
34
35 // read index
36 FilePath dbPath = module_context::scopedScratchPath().completePath(scope);
37 Error error = dbPath.ensureDirectory();
38 if (error)
39 return error;
40 std::map<std::string,std::string> index;
41 FilePath indexFile = dbPath.completePath("INDEX");
42 if (indexFile.exists())
43 {
44 error = readStringMapFromFile(indexFile, &index);
45 if (error)
46 return error;
47 }
48
49 // use existing storage if it exists, otherwise create new
50 std::string storage = index[escapedPath];
51 if (storage.empty())
52 {
53 // create storage
54 FilePath storageFile = file_utils::uniqueFilePath(dbPath);
55 if (directory)
56 {
57 error = storageFile.ensureDirectory();
58 if (error)
59 return error;
60 }
61 else
62 {
63 error = core::writeStringToFile(storageFile, "");
64 if (error)
65 return error;
66 }
67
68 // update storage
69 storage = storageFile.getFilename();
70
71 // update index
72 index[escapedPath] = storage;
73 Error error = writeStringMapToFile(indexFile, index);
74 if (error)
75 return error;
76 }
77
78 // return the path
79 *pStorage = dbPath.completeChildPath(storage);
80 return Success();
81 }
82
83
84 } // namespace module_context
85 } // namespace session
86 } // namespace rstudio
87