1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
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 <fcntl.h>
17#include <stdio.h>
18#include <string.h>
19#include <sys/stat.h>
20#include <unistd.h>
21#include <errno.h>
22#include "test.h"
23#define BUFFER_SIZE 1024
24#define RENAME_ZERO 0
25
26static int g_error = 0;
27static char g_dirPath[] = "/data/local/tmp";
28static char g_oldPath[] = "/data/local/tmp/renameat2_test.txt";
29static char g_oldName[] = "renameat2_test.txt";
30static char g_oldMsg[] = "renameat2";
31static char g_newPath[] = "/data/local/tmp/newrenameat2_test.txt";
32static char g_newName[] = "newrenameat2_test.txt";
33static char g_newMsg[] = "newrenameat2";
34
35static void WriteFile(char *path, char *msg)
36{
37    FILE *file = fopen(path, "w+");
38    if (file == NULL) {
39        g_error++;
40        return;
41    }
42    size_t len = strlen(msg);
43    size_t n = fwrite(msg, sizeof(char), len, file);
44    if (fclose(file)) {
45        g_error++;
46        return;
47    }
48    if (n != len) {
49        g_error++;
50        return;
51    }
52}
53
54static void ReadFile(char *path, size_t len, char *buf)
55{
56    FILE *file = fopen(path, "r");
57    if (file == NULL) {
58        g_error++;
59        return;
60    }
61    size_t n = fread(buf, sizeof(char), len, file);
62    if (fclose(file)) {
63        g_error++;
64        return;
65    }
66    if (n != len) {
67        g_error++;
68        return;
69    }
70}
71
72static void CompareFileString(char *path, size_t readCount, char *compareString)
73{
74    char buf[BUFFER_SIZE] = {0};
75    ReadFile(path, readCount, buf);
76    if (strcmp(compareString, buf)) {
77        g_error++;
78    }
79}
80
81static void RemoveFile()
82{
83    if (access(g_oldPath, F_OK) == 0) {
84        if (remove(g_oldPath)) {
85            printf("information: file removed fail\n");
86        }
87    }
88    if (access(g_newPath, F_OK) == 0) {
89        if (remove(g_newPath)) {
90            printf("information: file removed fail\n");
91        }
92    }
93}
94
95static void RenameNoReplaceTest(int oldFolder, int newFolder)
96{
97    WriteFile(g_oldPath, g_oldMsg);
98    if (renameat2(oldFolder, g_oldName, newFolder, g_newName, RENAME_NOREPLACE) == -1) {
99        g_error++;
100        return;
101    }
102    if (access(g_oldPath, F_OK) == 0) {
103        g_error++;
104        return;
105    }
106    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
107    RemoveFile();
108
109    WriteFile(g_oldPath, g_oldMsg);
110    WriteFile(g_newPath, g_newMsg);
111    if (renameat2(oldFolder, g_oldName, newFolder, g_newName, RENAME_NOREPLACE) == 0) {
112        g_error++;
113        return;
114    }
115    CompareFileString(g_oldPath, strlen(g_oldMsg), g_oldMsg);
116    CompareFileString(g_newPath, strlen(g_newMsg), g_newMsg);
117    RemoveFile();
118
119    WriteFile(g_oldPath, g_oldMsg);
120    if (renameat2(AT_FDCWD, g_oldPath, AT_FDCWD, g_newPath, RENAME_NOREPLACE) == -1) {
121        g_error++;
122        return;
123    }
124    if (access(g_oldPath, F_OK) == 0) {
125        g_error++;
126        return;
127    }
128    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
129    RemoveFile();
130
131    WriteFile(g_oldPath, g_oldMsg);
132    WriteFile(g_newPath, g_newMsg);
133    if (renameat2(AT_FDCWD, g_oldPath, AT_FDCWD, g_newPath, RENAME_NOREPLACE) == 0) {
134        g_error++;
135        return;
136    }
137    CompareFileString(g_oldPath, strlen(g_oldMsg), g_oldMsg);
138    CompareFileString(g_newPath, strlen(g_newMsg), g_newMsg);
139    RemoveFile();
140}
141
142static void ZeroTest(int oldFolder, int newFolder)
143{
144    WriteFile(g_oldPath, g_oldMsg);
145    if (renameat2(oldFolder, g_oldName, newFolder, g_newName, RENAME_ZERO) == -1) {
146        g_error++;
147        return;
148    }
149    if (access(g_oldPath, F_OK) == 0) {
150        g_error++;
151        return;
152    }
153    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
154    RemoveFile();
155
156    WriteFile(g_oldPath, g_oldMsg);
157    WriteFile(g_newPath, g_newMsg);
158    if (renameat2(oldFolder, g_oldName, newFolder, g_newName, RENAME_ZERO) == -1) {
159        g_error++;
160        return;
161    }
162    if (access(g_oldPath, F_OK) == 0) {
163        g_error++;
164        return;
165    }
166    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
167    RemoveFile();
168
169    WriteFile(g_oldPath, g_oldMsg);
170    if (renameat2(AT_FDCWD, g_oldPath, AT_FDCWD, g_newPath, RENAME_ZERO) == -1) {
171        g_error++;
172        return;
173    }
174    if (access(g_oldPath, F_OK) == 0) {
175        g_error++;
176        return;
177    }
178    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
179    RemoveFile();
180
181    WriteFile(g_oldPath, g_oldMsg);
182    WriteFile(g_newPath, g_newMsg);
183    if (renameat2(AT_FDCWD, g_oldPath, AT_FDCWD, g_newPath, RENAME_ZERO) == -1) {
184        g_error++;
185        return;
186    }
187    if (access(g_oldPath, F_OK) == 0) {
188        g_error++;
189        return;
190    }
191    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
192    RemoveFile();
193}
194
195static void RenameExchangeTest(int oldFolder, int newFolder)
196{
197    WriteFile(g_oldPath, g_oldMsg);
198    WriteFile(g_newPath, g_newMsg);
199    if (renameat2(oldFolder, g_oldName, newFolder, g_newName, RENAME_EXCHANGE) == -1) {
200        g_error++;
201        return;
202    }
203    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
204    CompareFileString(g_oldPath, strlen(g_newMsg), g_newMsg);
205    RemoveFile();
206
207    WriteFile(g_oldPath, g_oldMsg);
208    WriteFile(g_newPath, g_newMsg);
209    if (renameat2(AT_FDCWD, g_oldPath, AT_FDCWD, g_newPath, RENAME_EXCHANGE) == -1) {
210        g_error++;
211        return;
212    }
213    CompareFileString(g_newPath, strlen(g_oldMsg), g_oldMsg);
214    CompareFileString(g_oldPath, strlen(g_newMsg), g_newMsg);
215    RemoveFile();
216}
217
218static void CloseFolder(DIR *dir)
219{
220    if (closedir(dir)) {
221        printf("information: close folder fail\n");
222    }
223}
224
225int main(void)
226{
227    DIR *dir = opendir(g_dirPath);
228    if (dir == NULL) {
229        t_error("%s open dir failed, errno: %d\n", __func__, errno);
230        return 1;
231    }
232    int dirFD = dirfd(dir);
233    if (dirFD == -1) {
234        t_error("%s open dirfd failed, errno: %d\n", __func__, errno);
235        return 1;
236    }
237
238    g_error = 0;
239    RenameNoReplaceTest(dirFD, dirFD);
240    if (g_error) {
241        t_error("%s renameat2 failed,flags: RENAME_NOREPLACE\n", __func__);
242        RemoveFile();
243        CloseFolder(dir);
244        return 1;
245    }
246
247    g_error = 0;
248    ZeroTest(dirFD, dirFD);
249    if (g_error) {
250        t_error("%s renameat2 failed,flags: zero\n", __func__);
251        RemoveFile();
252        CloseFolder(dir);
253        return 1;
254    }
255
256    g_error = 0;
257    RenameExchangeTest(dirFD, dirFD);
258    if (g_error) {
259        t_error("%s renameat2 failed,flags: RENAME_EXCHANGE\n", __func__);
260        RemoveFile();
261        CloseFolder(dir);
262        return 1;
263    }
264    CloseFolder(dir);
265    return 0;
266}