Add synchronization after file operations
[platform/core/test/security-tests.git] / src / cynara-tests / common / cynara_test_file_operations.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include <cstdlib>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <ftw.h>
22 #include <pwd.h>
23 #include <sys/sendfile.h>
24 #include <sys/smack.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include <cynara_test_commons.h>
30 #include <dpl/test/test_runner.h>
31 #include <memory.h>
32
33 #include <cynara_test_file_operations.h>
34
35 namespace FileOperations
36 {
37
38 static int removeFile(const char *fpath, const struct stat * /*sb*/,
39                           int tflag, struct FTW * /*ftwbuf*/)
40 {
41     if (tflag == FTW_F)
42         RUNNER_ASSERT_ERRNO_MSG(!unlink(fpath), "Unable to unlink " << fpath << " file");
43     else
44         RUNNER_ASSERT_MSG(tflag == FTW_DP, "Visited file should not exist. Path: " << fpath);
45     return 0;
46 }
47
48 bool dirExists(const std::string &directory)
49 {
50     struct stat st;
51     int ret = stat(directory.c_str(), &st);
52     if (ret == -1 && errno == ENOENT) {
53         return false;
54     } else if (ret == -1) {
55         RUNNER_ASSERT_ERRNO_MSG(false, "Cannot stat " << directory
56                                           << " not due to its nonexistence");
57     }
58     RUNNER_ASSERT_MSG(st.st_mode & S_IFDIR, directory << " is not a directory");
59     return true;
60 }
61
62 void copyCynaraFile(const std::string &src, const std::string &dst)
63 {
64     using PwBufPtr = CStringPtr;
65     int inFd = TEMP_FAILURE_RETRY(open(src.c_str(), O_RDONLY));
66     RUNNER_ASSERT_ERRNO_MSG(inFd > 0, "Opening " << src << " file failed");
67     FdUniquePtr inFdPtr(&inFd);
68
69     int outFd = TEMP_FAILURE_RETRY(creat(dst.c_str(), 0700));
70     RUNNER_ASSERT_ERRNO_MSG(outFd > 0, "Creating " << dst << " file failed");
71     FdUniquePtr outFdPtr(&outFd);
72
73     long int len = sysconf(_SC_GETPW_R_SIZE_MAX);
74     RUNNER_ASSERT_MSG(len != -1, "No suggested buflen");
75     size_t buflen = len;
76     char *buf = static_cast<char*>(malloc(buflen));
77
78     PwBufPtr pwBufPtr(buf);
79
80     struct passwd pwbuf, *pwbufp = nullptr;
81     int ret = TEMP_FAILURE_RETRY(getpwnam_r(CynaraTestConsts::USER.c_str(),
82                                             &pwbuf, buf, buflen, &pwbufp));
83     RUNNER_ASSERT_ERRNO_MSG(ret == 0, "getpwnam_r failed on " << CynaraTestConsts::USER << " user");
84     RUNNER_ASSERT_MSG(pwbufp, "User " << CynaraTestConsts::USER << " does not exist");
85
86     ret = fchown(outFd, pwbufp->pw_uid, pwbufp->pw_gid);
87     RUNNER_ASSERT_ERRNO_MSG(ret != -1, "fchown failed");
88
89     ret = smack_fsetlabel(outFd, CynaraTestConsts::LABEL.c_str(), SMACK_LABEL_ACCESS);
90     RUNNER_ASSERT_MSG(ret == 0, "Setting smack label failed");
91
92     struct stat statSrc;
93     ret = fstat(inFd, &statSrc);
94     RUNNER_ASSERT_ERRNO_MSG(ret != -1, "fstat failed");
95
96     ret = sendfile(outFd, inFd, 0, statSrc.st_size);
97     RUNNER_ASSERT_ERRNO_MSG(ret != -1, "sendfile failed");
98
99     ret = fsync(outFd);
100     RUNNER_ASSERT_ERRNO_MSG(ret != -1, "fsync failed");
101 }
102
103 void copyCynaraFiles(const std::string &source, const std::string &destination)
104 {
105     DIR *dirPtr = nullptr;
106     struct dirent *direntPtr;
107
108     RUNNER_ASSERT_ERRNO_MSG(dirPtr = opendir(source.c_str()),
109                                "opening " << source << " dir failed");
110     DirPtr dirScopedPtr(dirPtr);
111
112     while((direntPtr = readdir(dirPtr)) != nullptr) {
113         if (!strcmp(direntPtr->d_name, ".")
114          || !strcmp(direntPtr->d_name, ".."))
115             continue;
116         std::string tempDest = destination + "/" + direntPtr->d_name;
117         std::string tempSrc = source + "/" + direntPtr->d_name;
118         copyCynaraFile(tempSrc, tempDest);
119     }
120
121     syncDir(destination);
122 }
123
124 void syncElem(const std::string &filename, int flags, mode_t mode)
125 {
126     int fileFd = TEMP_FAILURE_RETRY(open(filename.c_str(), flags, mode));
127     RUNNER_ASSERT_ERRNO_MSG(fileFd != -1, "open failed name=" << filename);
128     FdUniquePtr fdPtr(&fileFd);
129
130     int ret = fsync(fileFd);
131     RUNNER_ASSERT_ERRNO_MSG(ret != -1, "fsync failed name=" << filename);
132 }
133
134 void syncDir(const std::string &dirname, mode_t mode) {
135     syncElem(dirname, O_DIRECTORY, mode);
136 }
137
138 void makeDir(const std::string &directory)
139 {
140     RUNNER_ASSERT_ERRNO_MSG(!mkdir(directory.c_str(), S_IRWXU | S_IRWXG | S_IRWXO),
141                                "Unable to make " << directory << " test directory");
142
143     syncDir(directory);
144 }
145
146 void removeDirFiles(const std::string &dir)
147 {
148     int ret = nftw(dir.c_str(), removeFile, 2, FTW_DEPTH | FTW_PHYS);
149     if (ret == -1)
150         RUNNER_ASSERT_ERRNO_MSG(errno == ENOENT, "nftw failed");
151     else
152         syncDir(dir);
153 }
154
155 void removeDirIfExists(const std::string &dir)
156 {
157     RUNNER_ASSERT_ERRNO_MSG(!rmdir(dir.c_str()) || errno == ENOENT,
158                                "Removing " << dir << " dir failed");
159 }
160
161 } // namespace FileOperations