2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include <linux/kernel.h>
19 #include <linux/version.h>
20 #include <linux/slab.h>
22 #include <linux/mount.h>
23 #include <linux/hashtable.h>
24 #include <linux/ctype.h>
25 #include <linux/module.h>
28 #define DEFINE_DLOG(_name) extern int fslog_##_name(const char *fmt, ...)
30 DEFINE_DLOG(dlog_efs
);
31 DEFINE_DLOG(dlog_etc
);
32 DEFINE_DLOG(dlog_rmdir
);
35 #define MAX_EXT (1 << 7)
39 struct hlist_node hlist
;
43 struct dlog_keyword_hash_tbl
{
44 DECLARE_HASHTABLE(table
, 7);
48 DLOG_HT_EXTENSION
= 0,
54 DLOG_SUPP_PART_DATA
= 0,
66 static struct dlog_keyword_hash_tbl ht
[DLOG_HT_MAX
];
68 static const char *support_part
[] = {
72 static const char *extensions
[] = {
74 "arw", "bmp", "cr2", "dng", "gif",
75 "jpeg", "jpg", "nef", "nrw", "orf",
76 "pef", "png", "raf", "rw2", "srw",
80 "awb", "dff", "dsf", "flac", "imy",
81 "m4a", "mid", "midi", "mka", "mp3",
82 "mpga", "mxmf", "oga", "ogg", "ota",
83 "rtttl", "rtx", "smf", "wav", "wma",
86 "3g2", "3gp", "3gpp", "3gpp2",
87 "ak3g", "asf", "avi", "divx", "flv",
88 "m2t", "m2ts", "m4v", "mkv", "mp4",
89 "mpeg", "mpg", "mts", "skm", "tp",
90 "trp", "ts", "webm", "wmv",
93 "csv", "doc", "docm", "docx", "dot",
94 "dotx", "htm", "html", "hwdt", "hwp",
95 "hwpx", "hwt", "memo", "pdf", "pot",
96 "potx", "pps", "ppsx", "ppt", "pptm",
97 "pptx", "rtf", "snb", "spd", "xls",
98 "xlsm", "xlsx", "xlt", "xltx", "xml",
102 static const char *exceptions
[] = {
103 /* exception extension */
104 "db-shm", "shm", "bak", "mbak", "gz",
105 "log", "swap", "dcs", "tmp", "temp",
109 static const char **dlog_keyword_tbl
[DLOG_HT_MAX
] = {
110 extensions
, exceptions
113 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
114 static inline unsigned int dlog_full_name_hash(const char *name
, unsigned int len
)
116 return full_name_hash((void *)0x0, name
, len
);
118 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) */
119 static inline unsigned int dlog_full_name_hash(const char *name
, unsigned int len
)
121 return full_name_hash(name
, len
);
125 bool is_ext(const char *name
, const char token
, struct dlog_keyword_hash_tbl
*hash_tbl
)
127 char *ext
= strrchr(name
, token
);
128 struct dlog_keyword
*hash_cur
;
136 ext
= kstrdup(&ext
[1], GFP_KERNEL
);
140 for (i
= 0; ext
[i
]; i
++)
141 ext
[i
] = tolower(ext
[i
]);
142 hash
= dlog_full_name_hash(ext
, strlen(ext
));
144 hash_for_each_possible(hash_tbl
->table
, hash_cur
, hlist
, hash
) {
145 if (!strcmp(ext
, hash_cur
->keyword
)) {
155 int __init
dlog_keyword_hash_init(void)
161 hash_init(ht
[tbl_idx
].table
);
162 for (i
= 0; dlog_keyword_tbl
[tbl_idx
][i
]; i
++) {
163 struct dlog_keyword
*hte
;
165 hte
= kzalloc(sizeof(struct dlog_keyword
), GFP_KERNEL
);
169 INIT_HLIST_NODE(&hte
->hlist
);
170 hte
->keyword
= dlog_keyword_tbl
[tbl_idx
][i
];
171 hash_add(ht
[tbl_idx
].table
, &hte
->hlist
,
172 dlog_full_name_hash(hte
->keyword
, strlen(hte
->keyword
)));
175 } while(tbl_idx
< DLOG_HT_MAX
);
179 module_init(dlog_keyword_hash_init
);
181 void __exit
dlog_keyword_hash_exit(void)
185 struct dlog_keyword
*hash_cur
;
188 hash_for_each(ht
[num_ht
].table
, i
, hash_cur
, hlist
)
190 } while(++num_ht
< DLOG_HT_MAX
);
193 module_exit(dlog_keyword_hash_exit
);
195 static int get_support_part_id(struct vfsmount
*mnt
)
198 struct mount
*mount
= real_mount(mnt
);
200 /* check partition which need register delete log */
202 if (!strcmp(mount
->mnt_mountpoint
->d_name
.name
, support_part
[idx
]))
204 } while(support_part
[++idx
]);
209 static int is_sdcard(struct vfsmount
*mnt
)
211 /* internal storage (external storage till Andorid 8.x) */
212 if (mnt
->mnt_sb
->s_magic
== SDCARDFS_SUPER_MAGIC
)
214 /* external storage from Android 9.x */
215 else if (mnt
->mnt_sb
->s_magic
== SDFAT_SUPER_MAGIC
)
217 else if (mnt
->mnt_sb
->s_magic
== MSDOS_SUPER_MAGIC
)
223 static void make_prefix(int part_id
, char *prefix
)
225 if (part_id
== DLOG_SUPP_PART_DATA
)
231 static void store_log(struct dentry
*dentry
, struct inode
*inode
,
232 struct path
*path
, int type
, int part_id
)
234 kuid_t euid
= current
->cred
->euid
;
235 unsigned long ino
= inode
? inode
->i_ino
: 0;
236 loff_t isize
= inode
? inode
->i_size
: 0;
238 char *buf
, *full_path
;
241 buf
= kzalloc(PATH_MAX
, GFP_KERNEL
);
243 printk(KERN_ERR
"%s memory alloc failed : ENOMEM\n", __func__
);
247 full_path
= dentry_path_raw(dentry
, buf
, PATH_MAX
);
248 make_prefix(part_id
, &prefix
);
254 if (type
== DLOG_MM
) {
255 fslog_dlog_mm("[%c]\"%s\" (%u, %lu, %lu, %lld%c)\n", prefix
, full_path
,
256 euid
, path
->dentry
->d_inode
->i_ino
, ino
, isize
, unit
);
260 if (type
== DLOG_ETC
) {
261 fslog_dlog_etc("[%c]\"%s\" (%u, %lu, %lu, %lld%c)\n", prefix
, full_path
,
262 euid
, path
->dentry
->d_inode
->i_ino
, ino
, isize
, unit
);
266 if (type
== DLOG_EFS
) {
267 fslog_dlog_efs("\"%s\" (%lu, %lu, %lld%c)\n", full_path
,
268 path
->dentry
->d_inode
->i_ino
, ino
, isize
, unit
);
272 if (type
== DLOG_RMDIR
)
273 fslog_dlog_rmdir("[%c]\"%s\" (%u, %lu)\n", prefix
, full_path
,
274 euid
, path
->dentry
->d_inode
->i_ino
);
279 void dlog_hook(struct dentry
*dentry
, struct inode
*inode
, struct path
*path
)
281 int part_id
= get_support_part_id(path
->mnt
);
283 if ((part_id
< 0) && !is_sdcard(path
->mnt
))
286 /* for efs partition */
287 if (part_id
== DLOG_SUPP_PART_EFS
) {
288 store_log(dentry
, inode
, path
, DLOG_EFS
, part_id
);
292 /* for data partition`s only multimedia file */
293 if (is_ext(dentry
->d_name
.name
, '.', &ht
[DLOG_HT_EXTENSION
])) {
294 store_log(dentry
, inode
, path
, DLOG_MM
, part_id
);
298 /* for data partition except multimedia file */
299 if (!is_ext(dentry
->d_name
.name
, '.', &ht
[DLOG_HT_EXCEPTION
])
300 && !is_ext(dentry
->d_name
.name
, '-', &ht
[DLOG_HT_EXCEPTION
]))
301 store_log(dentry
, inode
, path
, DLOG_ETC
, part_id
);
307 static int get_dentry_depth(struct dentry
*dentry
)
310 struct dentry
*tmp_de
= dentry
;
312 while (!IS_ROOT(tmp_de
)) {
313 struct dentry
*parent
= tmp_de
->d_parent
;
316 if (depth
> MAX_DEPTH
)
324 void dlog_hook_rmdir(struct dentry
*dentry
, struct path
*path
)
327 int part_id
= get_support_part_id(path
->mnt
);
329 if (part_id
!= DLOG_SUPP_PART_DATA
)
332 depth
= get_dentry_depth(dentry
);
336 store_log(dentry
, NULL
, path
, DLOG_RMDIR
, part_id
);
341 MODULE_LICENSE("GPL");
342 MODULE_DESCRIPTION("Logging unlink file path");
343 MODULE_AUTHOR("Samsung Electronics Co., Ltd.");