1#ifndef _LINUX_FS_NOTIFY_H 2#define _LINUX_FS_NOTIFY_H 3 4/* 5 * include/linux/fsnotify.h - generic hooks for filesystem notification, to 6 * reduce in-source duplication from both dnotify and inotify. 7 * 8 * We don't compile any of this away in some complicated menagerie of ifdefs. 9 * Instead, we rely on the code inside to optimize away as needed. 10 * 11 * (C) Copyright 2005 Robert Love 12 */ 13 14#ifdef __KERNEL__ 15 16#include <linux/dnotify.h> 17#include <linux/inotify.h> 18#include <linux/audit.h> 19 20/* 21 * fsnotify_d_instantiate - instantiate a dentry for inode 22 * Called with dcache_lock held. 23 */ 24static inline void fsnotify_d_instantiate(struct dentry *entry, 25 struct inode *inode) 26{ 27 inotify_d_instantiate(entry, inode); 28} 29 30/* 31 * fsnotify_d_move - entry has been moved 32 * Called with dcache_lock and entry->d_lock held. 33 */ 34static inline void fsnotify_d_move(struct dentry *entry) 35{ 36 inotify_d_move(entry); 37} 38 39/* 40 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir 41 */ 42static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, 43 const char *old_name, const char *new_name, 44 int isdir, struct inode *target, struct inode *source) 45{ 46 u32 cookie = inotify_get_cookie(); 47 48 if (old_dir == new_dir) 49 inode_dir_notify(old_dir, DN_RENAME); 50 else { 51 inode_dir_notify(old_dir, DN_DELETE); 52 inode_dir_notify(new_dir, DN_CREATE); 53 } 54 55 if (isdir) 56 isdir = IN_ISDIR; 57 inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name, 58 source); 59 inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name, 60 source); 61 62 if (target) { 63 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL); 64 inotify_inode_is_dead(target); 65 } 66 67 if (source) { 68 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); 69 } 70 audit_inode_child(new_name, source, new_dir); 71} 72 73/* 74 * fsnotify_nameremove - a filename was removed from a directory 75 */ 76static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) 77{ 78 if (isdir) 79 isdir = IN_ISDIR; 80 dnotify_parent(dentry, DN_DELETE); 81 inotify_dentry_parent_queue_event(dentry, IN_DELETE|isdir, 0, dentry->d_name.name); 82} 83 84/* 85 * fsnotify_inoderemove - an inode is going away 86 */ 87static inline void fsnotify_inoderemove(struct inode *inode) 88{ 89 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL); 90 inotify_inode_is_dead(inode); 91} 92 93/* 94 * fsnotify_create - 'name' was linked in 95 */ 96static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) 97{ 98 inode_dir_notify(inode, DN_CREATE); 99 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name, 100 dentry->d_inode); 101 audit_inode_child(dentry->d_name.name, dentry->d_inode, inode); 102} 103 104/* 105 * fsnotify_mkdir - directory 'name' was created 106 */ 107static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) 108{ 109 inode_dir_notify(inode, DN_CREATE); 110 inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, 111 dentry->d_name.name, dentry->d_inode); 112 audit_inode_child(dentry->d_name.name, dentry->d_inode, inode); 113} 114 115/* 116 * fsnotify_access - file was read 117 */ 118static inline void fsnotify_access(struct dentry *dentry) 119{ 120 struct inode *inode = dentry->d_inode; 121 u32 mask = IN_ACCESS; 122 123 if (S_ISDIR(inode->i_mode)) 124 mask |= IN_ISDIR; 125 126 dnotify_parent(dentry, DN_ACCESS); 127 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 128 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 129} 130 131/* 132 * fsnotify_modify - file was modified 133 */ 134static inline void fsnotify_modify(struct dentry *dentry) 135{ 136 struct inode *inode = dentry->d_inode; 137 u32 mask = IN_MODIFY; 138 139 if (S_ISDIR(inode->i_mode)) 140 mask |= IN_ISDIR; 141 142 dnotify_parent(dentry, DN_MODIFY); 143 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 144 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 145} 146 147/* 148 * fsnotify_open - file was opened 149 */ 150static inline void fsnotify_open(struct dentry *dentry) 151{ 152 struct inode *inode = dentry->d_inode; 153 u32 mask = IN_OPEN; 154 155 if (S_ISDIR(inode->i_mode)) 156 mask |= IN_ISDIR; 157 158 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 159 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 160} 161 162/* 163 * fsnotify_close - file was closed 164 */ 165static inline void fsnotify_close(struct file *file) 166{ 167 struct dentry *dentry = file->f_path.dentry; 168 struct inode *inode = dentry->d_inode; 169 const char *name = dentry->d_name.name; 170 mode_t mode = file->f_mode; 171 u32 mask = (mode & FMODE_WRITE) ? IN_CLOSE_WRITE : IN_CLOSE_NOWRITE; 172 173 if (S_ISDIR(inode->i_mode)) 174 mask |= IN_ISDIR; 175 176 inotify_dentry_parent_queue_event(dentry, mask, 0, name); 177 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 178} 179 180/* 181 * fsnotify_xattr - extended attributes were changed 182 */ 183static inline void fsnotify_xattr(struct dentry *dentry) 184{ 185 struct inode *inode = dentry->d_inode; 186 u32 mask = IN_ATTRIB; 187 188 if (S_ISDIR(inode->i_mode)) 189 mask |= IN_ISDIR; 190 191 inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name); 192 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 193} 194 195/* 196 * fsnotify_change - notify_change event. file was modified and/or metadata 197 * was changed. 198 */ 199static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) 200{ 201 struct inode *inode = dentry->d_inode; 202 int dn_mask = 0; 203 u32 in_mask = 0; 204 205 if (ia_valid & ATTR_UID) { 206 in_mask |= IN_ATTRIB; 207 dn_mask |= DN_ATTRIB; 208 } 209 if (ia_valid & ATTR_GID) { 210 in_mask |= IN_ATTRIB; 211 dn_mask |= DN_ATTRIB; 212 } 213 if (ia_valid & ATTR_SIZE) { 214 in_mask |= IN_MODIFY; 215 dn_mask |= DN_MODIFY; 216 } 217 /* both times implies a utime(s) call */ 218 if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) 219 { 220 in_mask |= IN_ATTRIB; 221 dn_mask |= DN_ATTRIB; 222 } else if (ia_valid & ATTR_ATIME) { 223 in_mask |= IN_ACCESS; 224 dn_mask |= DN_ACCESS; 225 } else if (ia_valid & ATTR_MTIME) { 226 in_mask |= IN_MODIFY; 227 dn_mask |= DN_MODIFY; 228 } 229 if (ia_valid & ATTR_MODE) { 230 in_mask |= IN_ATTRIB; 231 dn_mask |= DN_ATTRIB; 232 } 233 234 if (dn_mask) 235 dnotify_parent(dentry, dn_mask); 236 if (in_mask) { 237 if (S_ISDIR(inode->i_mode)) 238 in_mask |= IN_ISDIR; 239 inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL); 240 inotify_dentry_parent_queue_event(dentry, in_mask, 0, 241 dentry->d_name.name); 242 } 243} 244 245#ifdef CONFIG_INOTIFY /* inotify helpers */ 246 247/* 248 * fsnotify_oldname_init - save off the old filename before we change it 249 */ 250static inline const char *fsnotify_oldname_init(const char *name) 251{ 252 return kstrdup(name, GFP_KERNEL); 253} 254 255/* 256 * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init 257 */ 258static inline void fsnotify_oldname_free(const char *old_name) 259{ 260 kfree(old_name); 261} 262 263#else /* CONFIG_INOTIFY */ 264 265static inline const char *fsnotify_oldname_init(const char *name) 266{ 267 return NULL; 268} 269 270static inline void fsnotify_oldname_free(const char *old_name) 271{ 272} 273 274#endif /* ! CONFIG_INOTIFY */ 275 276#endif /* __KERNEL__ */ 277 278#endif /* _LINUX_FS_NOTIFY_H */ 279