2 Unix SMB/Netbios implementation.
4 change notify handling - hash based implementation
5 Copyright (C) Jeremy Allison 1994-1998
6 Copyright (C) Andrew Tridgell 2000
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 time_t last_check_time; /* time we last checked this entry */
27 time_t modify_time; /* Info from the directory we're monitoring. */
28 time_t status_time; /* Info from the directory we're monitoring. */
29 time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
30 unsigned int num_entries; /* Zero or the number of files in the directory. */
34 /****************************************************************************
35 Create the hash we will use to determine if the contents changed.
36 *****************************************************************************/
37 static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
38 struct change_data *data, struct change_data *old_data)
50 if(vfs_stat(conn,path, &st) == -1) return False;
52 data->modify_time = st.st_mtime;
53 data->status_time = st.st_ctime;
57 * Shortcut to avoid directory scan if the time
58 * has changed - we always must return true then.
60 if (old_data->modify_time != data->modify_time ||
61 old_data->status_time != data->status_time ) {
67 * If we are to watch for changes that are only stored
68 * in inodes of files, not in the directory inode, we must
69 * scan the directory and produce a unique identifier with
70 * which we can determine if anything changed. We use the
71 * modify and change times from all the files in the
72 * directory, added together (ignoring wrapping if it's
73 * larger than the max time_t value).
76 if (!(flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE))) return True;
78 dp = OpenDir(conn, path, True);
79 if (dp == NULL) return False;
81 data->num_entries = 0;
83 pstrcpy(full_name, path);
84 pstrcat(full_name, "/");
86 fullname_len = strlen(full_name);
87 remaining_len = sizeof(full_name) - fullname_len - 1;
88 p = &full_name[fullname_len];
90 while ((fname = ReadDirName(dp))) {
91 if(strequal(fname, ".") || strequal(fname, "..")) continue;
94 safe_strcpy(p, fname, remaining_len);
99 * Do the stat - but ignore errors.
101 vfs_stat(conn,full_name, &st);
102 data->total_time += (st.st_mtime + st.st_ctime);
111 /****************************************************************************
112 register a change notify request
113 *****************************************************************************/
114 static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags)
116 struct change_data data;
118 if (!notify_hash(conn, path, flags, &data, NULL)) return NULL;
120 data.last_check_time = time(NULL);
122 return (void *)memdup(&data, sizeof(data));
125 /****************************************************************************
126 Check if a change notify should be issued.
127 A time of zero means instantaneous check - don't modify the last check time.
128 *****************************************************************************/
129 static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
131 struct change_data *data = (struct change_data *)datap;
132 struct change_data data2;
134 if (t && t < data->last_check_time + lp_change_notify_timeout()) return False;
136 if (!become_user(conn,vuid)) return True;
137 if (!become_service(conn,True)) {
142 if (!notify_hash(conn, path, flags, &data2, data) ||
143 data2.modify_time != data->modify_time ||
144 data2.status_time != data->status_time ||
145 data2.total_time != data->total_time ||
146 data2.num_entries != data->num_entries) {
152 data->last_check_time = t;
159 /****************************************************************************
160 remove a change notify data structure
161 *****************************************************************************/
162 static void hash_remove_notify(void *datap)
168 /****************************************************************************
169 setup hash based change notify
170 ****************************************************************************/
171 struct cnotify_fns *hash_notify_init(void)
173 static struct cnotify_fns cnotify;
175 cnotify.register_notify = hash_register_notify;
176 cnotify.check_notify = hash_check_notify;
177 cnotify.remove_notify = hash_remove_notify;
178 cnotify.select_time = lp_change_notify_timeout();
185 change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
186 change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
191 uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
192 SVAL(cnbp->request_buf,smb_uid);