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