• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * sload.c
3  *
4  * Copyright (C) 2015 Huawei Ltd.
5  * Witten by:
6  *   Hou Pengyang <houpengyang@huawei.com>
7  *   Liu Shuoran <liushuoran@huawei.com>
8  *   Jaegeuk Kim <jaegeuk@kernel.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14 #define _GNU_SOURCE
15 #include "fsck.h"
16 #include <libgen.h>
17 #include <dirent.h>
18 #include <mntent.h>
19 
20 #ifdef HAVE_LIBSELINUX
21 #include <selinux/selinux.h>
22 #include <selinux/label.h>
23 #endif
24 
25 #ifdef WITH_ANDROID
26 #include <selinux/label.h>
27 #include <private/android_filesystem_config.h>
28 
handle_selabel(struct dentry * de,int dir,char * target_out)29 static void handle_selabel(struct dentry *de, int dir, char *target_out)
30 {
31 	uint64_t capabilities;
32 	unsigned int mode = 0;
33 	unsigned int uid = 0;
34 	unsigned int gid = 0;
35 
36 	fs_config(de->path, dir, target_out, &uid,
37 			&gid, &mode, &capabilities);
38 	de->mode = mode;
39 	de->uid = uid;
40 	de->gid = gid;
41 	de->capabilities = capabilities;
42 }
43 #else
44 #define handle_selabel(...)
45 #endif
46 
filter_dot(const struct dirent * d)47 static int filter_dot(const struct dirent *d)
48 {
49 	return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
50 }
51 
f2fs_make_directory(struct f2fs_sb_info * sbi,int entries,struct dentry * de)52 static void f2fs_make_directory(struct f2fs_sb_info *sbi,
53 				int entries, struct dentry *de)
54 {
55 	int i = 0;
56 
57 	for (i = 0; i < entries; i++) {
58 		if (de[i].file_type == F2FS_FT_DIR)
59 			f2fs_mkdir(sbi, de + i);
60 		else if (de[i].file_type == F2FS_FT_REG_FILE)
61 			f2fs_create(sbi, de + i);
62 		else if (de[i].file_type == F2FS_FT_SYMLINK)
63 			f2fs_symlink(sbi, de + i);
64 	}
65 }
66 
build_directory(struct f2fs_sb_info * sbi,const char * full_path,const char * dir_path,const char * target_out_dir,nid_t dir_ino,struct selabel_handle * sehnd)67 static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
68 			const char *dir_path, const char *target_out_dir,
69 			nid_t dir_ino, struct selabel_handle *sehnd)
70 {
71 	int entries = 0;
72 	struct dentry *dentries;
73 	struct dirent **namelist = NULL;
74 	struct stat stat;
75 	int i, ret = 0;
76 
77 	entries = scandir(full_path, &namelist, filter_dot, (void *)alphasort);
78 	if (entries < 0) {
79 		ERR_MSG("No entries in %s\n", full_path);
80 		return -ENOENT;
81 	}
82 
83 	dentries = calloc(entries, sizeof(struct dentry));
84 	if (dentries == NULL)
85 		return -ENOMEM;
86 
87 	for (i = 0; i < entries; i++) {
88 		dentries[i].name = (unsigned char *)strdup(namelist[i]->d_name);
89 		if (dentries[i].name == NULL) {
90 			ERR_MSG("Skip: ENOMEM\n");
91 			continue;
92 		}
93 		dentries[i].len = strlen((char *)dentries[i].name);
94 
95 		ret = asprintf(&dentries[i].path, "%s/%s",
96 					dir_path, namelist[i]->d_name);
97 		ASSERT(ret > 0);
98 		ret = asprintf(&dentries[i].full_path, "%s/%s",
99 					full_path, namelist[i]->d_name);
100 		ASSERT(ret > 0);
101 		free(namelist[i]);
102 
103 		ret = lstat(dentries[i].full_path, &stat);
104 		if (ret < 0) {
105 			ERR_MSG("Skip: lstat failure\n");
106 			continue;
107 		}
108 		dentries[i].size = stat.st_size;
109 		dentries[i].mode = stat.st_mode &
110 			(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
111 		dentries[i].mtime = stat.st_mtime;
112 
113 		handle_selabel(dentries + i, S_ISDIR(stat.st_mode),
114 							target_out_dir);
115 
116 #ifdef HAVE_LIBSELINUX
117 		if (sehnd && selabel_lookup(sehnd, &dentries[i].secon,
118 					dentries[i].path, stat.st_mode) < 0)
119 			ERR_MSG("Cannot lookup security context for %s\n",
120 						dentries[i].path);
121 #endif
122 
123 		dentries[i].pino = dir_ino;
124 
125 		if (S_ISREG(stat.st_mode)) {
126 			dentries[i].file_type = F2FS_FT_REG_FILE;
127 		} else if (S_ISDIR(stat.st_mode)) {
128 			dentries[i].file_type = F2FS_FT_DIR;
129 		} else if (S_ISCHR(stat.st_mode)) {
130 			dentries[i].file_type = F2FS_FT_CHRDEV;
131 		} else if (S_ISBLK(stat.st_mode)) {
132 			dentries[i].file_type = F2FS_FT_BLKDEV;
133 		} else if (S_ISFIFO(stat.st_mode)) {
134 			dentries[i].file_type = F2FS_FT_FIFO;
135 		} else if (S_ISSOCK(stat.st_mode)) {
136 			dentries[i].file_type = F2FS_FT_SOCK;
137 		} else if (S_ISLNK(stat.st_mode)) {
138 			dentries[i].file_type = F2FS_FT_SYMLINK;
139 			dentries[i].link = calloc(F2FS_BLKSIZE, 1);
140 			ASSERT(dentries[i].link);
141 			ret = readlink(dentries[i].full_path,
142 					dentries[i].link, F2FS_BLKSIZE - 1);
143 			ASSERT(ret >= 0);
144 		} else {
145 			MSG(1, "unknown file type on %s", dentries[i].path);
146 			i--;
147 			entries--;
148 		}
149 	}
150 
151 	free(namelist);
152 
153 	f2fs_make_directory(sbi, entries, dentries);
154 
155 	for (i = 0; i < entries; i++) {
156 		if (dentries[i].file_type == F2FS_FT_REG_FILE) {
157 			f2fs_build_file(sbi, dentries + i);
158 		} else if (dentries[i].file_type == F2FS_FT_DIR) {
159 			char *subdir_full_path = NULL;
160 			char *subdir_dir_path;
161 
162 			ret = asprintf(&subdir_full_path, "%s/",
163 							dentries[i].full_path);
164 			ASSERT(ret > 0);
165 			ret = asprintf(&subdir_dir_path, "%s/",
166 							dentries[i].path);
167 			ASSERT(ret > 0);
168 
169 			build_directory(sbi, subdir_full_path, subdir_dir_path,
170 					target_out_dir, dentries[i].ino, sehnd);
171 			free(subdir_full_path);
172 			free(subdir_dir_path);
173 		} else if (dentries[i].file_type == F2FS_FT_SYMLINK) {
174 			/*
175 			 * It is already done in f2fs_make_directory
176 			 * f2fs_make_symlink(sbi, dir_ino, &dentries[i]);
177 			 */
178 		} else {
179 			MSG(1, "Error unknown file type\n");
180 		}
181 
182 #ifdef HAVE_LIBSELINUX
183 		if (dentries[i].secon) {
184 			inode_set_selinux(sbi, dentries[i].ino, dentries[i].secon);
185 			MSG(1, "File = %s \n----->SELinux context = %s\n",
186 					dentries[i].path, dentries[i].secon);
187 			MSG(1, "----->mode = 0x%x, uid = 0x%x, gid = 0x%x, "
188 					"capabilities = 0x%lx \n",
189 					dentries[i].mode, dentries[i].uid,
190 					dentries[i].gid, dentries[i].capabilities);
191 		}
192 
193 		free(dentries[i].secon);
194 #endif
195 
196 		free(dentries[i].path);
197 		free(dentries[i].full_path);
198 		free((void *)dentries[i].name);
199 	}
200 
201 	free(dentries);
202 	return 0;
203 }
204 
f2fs_sload(struct f2fs_sb_info * sbi,const char * from_dir,const char * mount_point,const char * target_out_dir,struct selabel_handle * sehnd)205 int f2fs_sload(struct f2fs_sb_info *sbi, const char *from_dir,
206 				const char *mount_point,
207 				const char *target_out_dir,
208 				struct selabel_handle *sehnd)
209 {
210 	int ret = 0;
211 	nid_t mnt_ino = F2FS_ROOT_INO(sbi);
212 
213 	/* flush NAT/SIT journal entries */
214 	flush_journal_entries(sbi);
215 
216 	ret = f2fs_find_path(sbi, (char *)mount_point, &mnt_ino);
217 	if (ret) {
218 		ERR_MSG("Failed to get mount point %s\n", mount_point);
219 		return ret;
220 	}
221 
222 	ret = build_directory(sbi, from_dir, mount_point, target_out_dir,
223 						mnt_ino, sehnd);
224 	if (ret) {
225 		ERR_MSG("Failed to build due to %d\n", ret);
226 		return ret;
227 	}
228 
229 #ifdef HAVE_LIBSELINUX
230 	if (sehnd) {
231 		char *secontext = NULL;
232 
233 		/* set root inode selinux context */
234 		if (selabel_lookup(sehnd, &secontext, mount_point, S_IFDIR) < 0)
235 			ERR_MSG("cannot lookup security context for %s\n",
236 								mount_point);
237 		if (secontext) {
238 			MSG(1, "Labeling %s as %s, root_ino = %d\n",
239 					mount_point, secontext, F2FS_ROOT_INO(sbi));
240 			/* xattr_add for root inode */
241 			inode_set_selinux(sbi, F2FS_ROOT_INO(sbi), secontext);
242 		}
243 		free(secontext);
244 	}
245 #endif
246 
247 	/* update curseg info; can update sit->types */
248 	move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
249 	zero_journal_entries(sbi);
250 	write_curseg_info(sbi);
251 
252 	/* flush dirty sit entries */
253 	flush_sit_entries(sbi);
254 
255 	write_checkpoint(sbi);
256 	return 0;
257 }
258