embox

Форк
0
/
krename.c 
219 строк · 4.9 Кб
1
/*
2
 * @file
3
 *
4
 * @date Nov 29, 2012
5
 * @author: Anton Bondarev
6
 */
7

8
#include <unistd.h>
9
#include <fcntl.h>
10
#include <stdio.h>
11
#include <stddef.h>
12
#include <string.h>
13
#include <stdlib.h>
14
#include <errno.h>
15

16
#include <lib/libds/tree.h>
17

18
#include <fs/inode.h>
19
#include <fs/inode_operation.h>
20
#include <fs/kfsop.h>
21
#include <fs/perm.h>
22

23
#include <fs/path.h>
24

25
/**
26
 * Simple util function to copy file in oldpath to newpath
27
 * @param Should be regular file to copy
28
 * @param Name of new copy
29
 * @return ENOERR if file successfully copied -1 and set errno in other way
30
 */
31
static int copy_file(const char *oldpath, const char *newpath) {
32
	int oldfd, newfd, rc;
33
	char buf[BUFSIZ];
34
	struct stat old_st;
35

36
	oldfd = open(oldpath, O_RDONLY);
37
	if (-1 == oldfd) {
38
		return -1;
39
	}
40

41
	if (-1 == fstat(oldfd, &old_st)) {
42
		return -1;
43
	}
44

45
	newfd = open(newpath, O_CREAT|O_WRONLY|O_TRUNC, old_st.st_mode & 0777);
46
	if (-1 == newfd) {
47
		return -1;
48
	}
49

50
	/* Copy bytes */
51
	while ((rc = read(oldfd, buf, sizeof(buf))) > 0) {
52
		if (write(newfd, buf, rc) <= 0) {
53
			SET_ERRNO(EIO);
54
			return -1;
55
		}
56
	}
57

58
	/* Close files and free memory*/
59
	rc = close(oldfd);
60
	if (0 != rc) {
61
		return -1;
62
	}
63
	rc = close(newfd);
64
	if (0 != rc) {
65
		return -1;
66
	}
67

68
	return ENOERR;
69
}
70

71
/**
72
 * Rename oldpath to newpath
73
 * @param Path to file or directory to rename
74
 * @param Destination path, could not be existent file
75
 * @return ENOERR if file successfully copied -1 and set errno in other way
76
 */
77
int krename(const char *oldpath, const char *newpath) {
78
	int rc, newpathlen, diritemlen;
79
	char *oldpathcopy, *newpathcopy;
80
	char *opc_free, *npc_free;
81
	char *name, *newpathbuf = NULL;
82
	char *newpatharg, *oldpatharg;
83
	struct path oldnode, newnode;
84
	struct inode *diritem;
85
	/* We use custom tree traversal while I can't
86
	 * get success with tree_foreach_children */
87
	struct tree_link *link, *end_link;
88

89
	if (PATH_MAX < strlen(oldpath) ||
90
			PATH_MAX < strlen(newpath)) {
91
		SET_ERRNO(ENAMETOOLONG);
92
		return -1;
93
	}
94

95
	/* Check if source file exists */
96
	oldpathcopy = strdup(oldpath);
97
	opc_free = oldpathcopy;
98
	rc = fs_perm_lookup((const char *) oldpathcopy,
99
			(const char **) &oldpathcopy, &oldnode);
100
	free(opc_free);
101
	if (0 != rc) {
102
		SET_ERRNO(-rc);
103
		return -1;
104
	}
105

106
	/* Check if destination file already exists or if directory were
107
	 * provided as destination path */
108
	newpathcopy = strdup(newpath);
109
	npc_free = newpathcopy;
110
	rc = fs_perm_lookup((const char *) newpathcopy,
111
			(const char **) &newpathcopy, &newnode);
112
	free(npc_free);
113
	if (0 == rc) {
114
		if (S_ISDIR(newnode.node->i_mode)) {
115
			/* Directory was passed as destination */
116
			name = strrchr(oldpath, '/') + 1;
117
			newpathlen = strlen(newpath) + strlen(name);
118
			if (newpathlen > PATH_MAX) {
119
				SET_ERRNO(ENAMETOOLONG);
120
				return -1;
121
			}
122
			newpathbuf = calloc(newpathlen + 2, sizeof(char));
123
			if (NULL == newpathbuf) {
124
				SET_ERRNO(ENOMEM);
125
				return -1;
126
			}
127
			strcat(newpathbuf, newpath);
128
			if (newpathbuf[strlen(newpathbuf) - 1] != '/') {
129
				strcat(newpathbuf, "/");
130
			}
131
			strcat(newpathbuf, name);
132
			newpath = newpathbuf;
133
		} else {
134
			SET_ERRNO(EINVAL);
135
			return -1;
136
		}
137
	}
138

139
	/**
140
	 * TODO:
141
	 * Here we should check if we move within one filesystem and don't copy
142
	 * data in such case. Instead of that just make new hardlink
143
	 * and remove old one.
144
	 */
145

146
	/* If oldpath is directory, copy it recursively */
147
	if (S_ISDIR(oldnode.node->i_mode)) {
148
		rc = kmkdir(newpath, oldnode.node->i_mode);
149
		if (-1 == rc) {
150
			return -1;
151
		}
152

153
		/**
154
		 * Following line should be here:
155
		 *  tree_foreach_children(diritem, (&oldnode->tree_link), tree_link) {
156
		 * But it's not working with it.
157
		 */
158
		link = tree_children_begin(&oldnode.node->tree_link);
159
		end_link = tree_children_end(&oldnode.node->tree_link);
160

161
		while (link != end_link) {
162
			char *node_name;
163

164
			diritem = tree_element(link, typeof(*diritem), tree_link);
165
			link = tree_children_next(link);
166

167
			node_name = inode_name(diritem);
168
			if (0 != strcmp(".", node_name) &&
169
					0 != strcmp("..", node_name)) {
170
				diritemlen = strlen(node_name);
171
				oldpatharg =
172
						calloc(strlen(oldpath) + diritemlen + 2, sizeof(char));
173
				newpatharg =
174
						calloc(strlen(newpath) + diritemlen + 2, sizeof(char));
175
				if (NULL == oldpatharg || NULL == newpatharg) {
176
					SET_ERRNO(ENOMEM);
177
					return -1;
178
				}
179

180
				strcat(oldpatharg, oldpath);
181
				if (oldpatharg[strlen(oldpatharg) - 1] != '/') {
182
					strcat(oldpatharg, "/");
183
				}
184
				strcat(oldpatharg, node_name);
185
				strcat(newpatharg, newpath);
186
				if (newpatharg[strlen(newpatharg) - 1] != '/') {
187
					strcat(newpatharg, "/");
188
				}
189
				strcat(newpatharg, node_name);
190

191
				/* Call itself recursively */
192
				if (-1 == krename(oldpatharg, newpatharg)) {
193
					return -1;
194
				}
195

196
				free(newpatharg);
197
				free(oldpatharg);
198
			}
199
		}
200
	/* Or copy file */
201
	} else {
202
		rc = copy_file(oldpath, newpath);
203
		if (-1 == rc) {
204
			return -1;
205
		}
206
	}
207

208
	if (NULL != newpathbuf) {
209
		free(newpathbuf);
210
	}
211

212
	/* Delete file in old path */
213
	rc = kremove(oldpath);
214
	if (0 != rc) {
215
		return -1;
216
	}
217

218
	return ENOERR;
219
}
220

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.