server: Use the tgkill system call on all Linux platforms.
[wine] / server / change.c
1 /*
2  * Server-side change notification management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2006 Mike McCormack
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <signal.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <limits.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #ifdef HAVE_SYS_ERRNO_H
36 #include <sys/errno.h>
37 #endif
38
39 #include "ntstatus.h"
40 #define WIN32_NO_STATUS
41 #include "windef.h"
42
43 #include "file.h"
44 #include "handle.h"
45 #include "thread.h"
46 #include "request.h"
47 #include "process.h"
48 #include "security.h"
49 #include "winternl.h"
50
51 /* dnotify support */
52
53 #ifdef linux
54 #ifndef F_NOTIFY
55 #define F_NOTIFY 1026
56 #define DN_ACCESS       0x00000001      /* File accessed */
57 #define DN_MODIFY       0x00000002      /* File modified */
58 #define DN_CREATE       0x00000004      /* File created */
59 #define DN_DELETE       0x00000008      /* File removed */
60 #define DN_RENAME       0x00000010      /* File renamed */
61 #define DN_ATTRIB       0x00000020      /* File changed attributes */
62 #define DN_MULTISHOT    0x80000000      /* Don't remove notifier */
63 #endif
64 #endif
65
66 /* inotify support */
67
68 #ifdef HAVE_SYS_INOTIFY_H
69 #include <sys/inotify.h>
70 #define USE_INOTIFY
71 #elif defined(__linux__) && defined(__i386__)
72
73 #define SYS_inotify_init        291
74 #define SYS_inotify_add_watch   292
75 #define SYS_inotify_rm_watch    293
76
77 struct inotify_event {
78     int           wd;
79     unsigned int  mask;
80     unsigned int  cookie;
81     unsigned int  len;
82     char          name[1];
83 };
84
85 #define IN_ACCESS        0x00000001
86 #define IN_MODIFY        0x00000002
87 #define IN_ATTRIB        0x00000004
88 #define IN_CLOSE_WRITE   0x00000008
89 #define IN_CLOSE_NOWRITE 0x00000010
90 #define IN_OPEN          0x00000020
91 #define IN_MOVED_FROM    0x00000040
92 #define IN_MOVED_TO      0x00000080
93 #define IN_CREATE        0x00000100
94 #define IN_DELETE        0x00000200
95 #define IN_DELETE_SELF   0x00000400
96
97 #define IN_ISDIR         0x40000000
98
99 static inline int inotify_init( void )
100 {
101     return syscall( SYS_inotify_init );
102 }
103
104 static inline int inotify_add_watch( int fd, const char *name, unsigned int mask )
105 {
106     return syscall( SYS_inotify_add_watch, fd, name, mask );
107 }
108
109 static inline int inotify_rm_watch( int fd, int wd )
110 {
111     return syscall( SYS_inotify_rm_watch, fd, wd );
112 }
113
114 #define USE_INOTIFY
115
116 #endif
117
118 struct inode;
119
120 static void free_inode( struct inode *inode );
121
122 static struct fd *inotify_fd;
123
124 struct change_record {
125     struct list entry;
126     int action;
127     int len;
128     char name[1];
129 };
130
131 struct dir
132 {
133     struct object  obj;      /* object header */
134     struct fd     *fd;       /* file descriptor to the directory */
135     mode_t         mode;     /* file stat.st_mode */
136     uid_t          uid;      /* file stat.st_uid */
137     struct list    entry;    /* entry in global change notifications list */
138     unsigned int   filter;   /* notification filter */
139     int            notified; /* SIGIO counter */
140     int            want_data; /* return change data */
141     int            subtree;  /* do we want to watch subdirectories? */
142     struct list    change_records;   /* data for the change */
143     struct list    in_entry; /* entry in the inode dirs list */
144     struct inode  *inode;    /* inode of the associated directory */
145 };
146
147 static struct fd *dir_get_fd( struct object *obj );
148 static struct security_descriptor *dir_get_sd( struct object *obj );
149 static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
150                        unsigned int set_info );
151 static void dir_dump( struct object *obj, int verbose );
152 static void dir_destroy( struct object *obj );
153
154 static const struct object_ops dir_ops =
155 {
156     sizeof(struct dir),       /* size */
157     dir_dump,                 /* dump */
158     no_get_type,              /* get_type */
159     add_queue,                /* add_queue */
160     remove_queue,             /* remove_queue */
161     default_fd_signaled,      /* signaled */
162     no_satisfied,             /* satisfied */
163     no_signal,                /* signal */
164     dir_get_fd,               /* get_fd */
165     default_fd_map_access,    /* map_access */
166     dir_get_sd,               /* get_sd */
167     dir_set_sd,               /* set_sd */
168     no_lookup_name,           /* lookup_name */
169     no_open_file,             /* open_file */
170     fd_close_handle,          /* close_handle */
171     dir_destroy               /* destroy */
172 };
173
174 static int dir_get_poll_events( struct fd *fd );
175 static enum server_fd_type dir_get_fd_type( struct fd *fd );
176
177 static const struct fd_ops dir_fd_ops =
178 {
179     dir_get_poll_events,         /* get_poll_events */
180     default_poll_event,          /* poll_event */
181     no_flush,                    /* flush */
182     dir_get_fd_type,             /* get_fd_type */
183     default_fd_ioctl,            /* ioctl */
184     default_fd_queue_async,      /* queue_async */
185     default_fd_reselect_async,   /* reselect_async */
186     default_fd_cancel_async      /* cancel_async */
187 };
188
189 static struct list change_list = LIST_INIT(change_list);
190
191 static void dnotify_adjust_changes( struct dir *dir )
192 {
193 #if defined(F_SETSIG) && defined(F_NOTIFY)
194     int fd = get_unix_fd( dir->fd );
195     unsigned int filter = dir->filter;
196     unsigned int val;
197     if ( 0 > fcntl( fd, F_SETSIG, SIGIO) )
198         return;
199
200     val = DN_MULTISHOT;
201     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
202         val |= DN_RENAME | DN_DELETE | DN_CREATE;
203     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
204         val |= DN_RENAME | DN_DELETE | DN_CREATE;
205     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
206         val |= DN_ATTRIB;
207     if (filter & FILE_NOTIFY_CHANGE_SIZE)
208         val |= DN_MODIFY;
209     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
210         val |= DN_MODIFY;
211     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
212         val |= DN_ACCESS;
213     if (filter & FILE_NOTIFY_CHANGE_CREATION)
214         val |= DN_CREATE;
215     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
216         val |= DN_ATTRIB;
217     fcntl( fd, F_NOTIFY, val );
218 #endif
219 }
220
221 /* insert change in the global list */
222 static inline void insert_change( struct dir *dir )
223 {
224     sigset_t sigset;
225
226     sigemptyset( &sigset );
227     sigaddset( &sigset, SIGIO );
228     sigprocmask( SIG_BLOCK, &sigset, NULL );
229     list_add_head( &change_list, &dir->entry );
230     sigprocmask( SIG_UNBLOCK, &sigset, NULL );
231 }
232
233 /* remove change from the global list */
234 static inline void remove_change( struct dir *dir )
235 {
236     sigset_t sigset;
237
238     sigemptyset( &sigset );
239     sigaddset( &sigset, SIGIO );
240     sigprocmask( SIG_BLOCK, &sigset, NULL );
241     list_remove( &dir->entry );
242     sigprocmask( SIG_UNBLOCK, &sigset, NULL );
243 }
244
245 static void dir_dump( struct object *obj, int verbose )
246 {
247     struct dir *dir = (struct dir *)obj;
248     assert( obj->ops == &dir_ops );
249     fprintf( stderr, "Dirfile fd=%p filter=%08x\n", dir->fd, dir->filter );
250 }
251
252 /* enter here directly from SIGIO signal handler */
253 void do_change_notify( int unix_fd )
254 {
255     struct dir *dir;
256
257     /* FIXME: this is O(n) ... probably can be improved */
258     LIST_FOR_EACH_ENTRY( dir, &change_list, struct dir, entry )
259     {
260         if (get_unix_fd( dir->fd ) != unix_fd) continue;
261         interlocked_xchg_add( &dir->notified, 1 );
262         break;
263     }
264 }
265
266 /* SIGIO callback, called synchronously with the poll loop */
267 void sigio_callback(void)
268 {
269     struct dir *dir;
270
271     LIST_FOR_EACH_ENTRY( dir, &change_list, struct dir, entry )
272     {
273         if (interlocked_xchg( &dir->notified, 0 ))
274             fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_NOTIFY_ENUM_DIR );
275     }
276 }
277
278 static struct fd *dir_get_fd( struct object *obj )
279 {
280     struct dir *dir = (struct dir *)obj;
281     assert( obj->ops == &dir_ops );
282     return (struct fd *)grab_object( dir->fd );
283 }
284
285 static int get_dir_unix_fd( struct dir *dir )
286 {
287     return get_unix_fd( dir->fd );
288 }
289
290 static struct security_descriptor *dir_get_sd( struct object *obj )
291 {
292     struct dir *dir = (struct dir *)obj;
293     int unix_fd;
294     struct stat st;
295     struct security_descriptor *sd;
296     assert( obj->ops == &dir_ops );
297
298     unix_fd = get_dir_unix_fd( dir );
299
300     if (unix_fd == -1 || fstat( unix_fd, &st ) == -1)
301         return obj->sd;
302
303     /* mode and uid the same? if so, no need to re-generate security descriptor */
304     if (obj->sd &&
305         (st.st_mode & (S_IRWXU|S_IRWXO)) == (dir->mode & (S_IRWXU|S_IRWXO)) &&
306         (st.st_uid == dir->uid))
307         return obj->sd;
308
309     sd = mode_to_sd( st.st_mode,
310                      security_unix_uid_to_sid( st.st_uid ),
311                      token_get_primary_group( current->process->token ));
312     if (!sd) return obj->sd;
313
314     dir->mode = st.st_mode;
315     dir->uid = st.st_uid;
316     free( obj->sd );
317     obj->sd = sd;
318     return sd;
319 }
320
321 static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
322                        unsigned int set_info )
323 {
324     struct dir *dir = (struct dir *)obj;
325     const SID *owner;
326     struct stat st;
327     mode_t mode;
328     int unix_fd;
329
330     assert( obj->ops == &dir_ops );
331
332     unix_fd = get_dir_unix_fd( dir );
333
334     if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1;
335
336     if (set_info & OWNER_SECURITY_INFORMATION)
337     {
338         owner = sd_get_owner( sd );
339         if (!owner)
340         {
341             set_error( STATUS_INVALID_SECURITY_DESCR );
342             return 0;
343         }
344         if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) ))
345         {
346             /* FIXME: get Unix uid and call fchown */
347         }
348     }
349     else if (obj->sd)
350         owner = sd_get_owner( obj->sd );
351     else
352         owner = token_get_user( current->process->token );
353
354     if (set_info & DACL_SECURITY_INFORMATION)
355     {
356         /* keep the bits that we don't map to access rights in the ACL */
357         mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
358         mode |= sd_to_mode( sd, owner );
359
360         if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
361         {
362             file_set_error();
363             return 0;
364         }
365     }
366     return 1;
367 }
368
369 static struct change_record *get_first_change_record( struct dir *dir )
370 {
371     struct list *ptr = list_head( &dir->change_records );
372     if (!ptr) return NULL;
373     list_remove( ptr );
374     return LIST_ENTRY( ptr, struct change_record, entry );
375 }
376
377 static void dir_destroy( struct object *obj )
378 {
379     struct change_record *record;
380     struct dir *dir = (struct dir *)obj;
381     assert (obj->ops == &dir_ops);
382
383     if (dir->filter)
384         remove_change( dir );
385
386     if (dir->inode)
387     {
388         list_remove( &dir->in_entry );
389         free_inode( dir->inode );
390     }
391
392     while ((record = get_first_change_record( dir ))) free( record );
393
394     release_object( dir->fd );
395
396     if (inotify_fd && list_empty( &change_list ))
397     {
398         release_object( inotify_fd );
399         inotify_fd = NULL;
400     }
401 }
402
403 struct dir *get_dir_obj( struct process *process, obj_handle_t handle, unsigned int access )
404 {
405     return (struct dir *)get_handle_obj( process, handle, access, &dir_ops );
406 }
407
408 static int dir_get_poll_events( struct fd *fd )
409 {
410     return 0;
411 }
412
413 static enum server_fd_type dir_get_fd_type( struct fd *fd )
414 {
415     return FD_TYPE_DIR;
416 }
417
418 #ifdef USE_INOTIFY
419
420 #define HASH_SIZE 31
421
422 struct inode {
423     struct list ch_entry;    /* entry in the children list */
424     struct list children;    /* children of this inode */
425     struct inode *parent;    /* parent of this inode */
426     struct list dirs;        /* directory handles watching this inode */
427     struct list ino_entry;   /* entry in the inode hash */
428     struct list wd_entry;    /* entry in the watch descriptor hash */
429     dev_t dev;               /* device number */
430     ino_t ino;               /* device's inode number */
431     int wd;                  /* inotify's watch descriptor */
432     char *name;              /* basename name of the inode */
433 };
434
435 static struct list inode_hash[ HASH_SIZE ];
436 static struct list wd_hash[ HASH_SIZE ];
437
438 static int inotify_add_dir( char *path, unsigned int filter );
439
440 static struct inode *inode_from_wd( int wd )
441 {
442     struct list *bucket = &wd_hash[ wd % HASH_SIZE ];
443     struct inode *inode;
444
445     LIST_FOR_EACH_ENTRY( inode, bucket, struct inode, wd_entry )
446         if (inode->wd == wd)
447             return inode;
448
449     return NULL;
450 }
451
452 static inline struct list *get_hash_list( dev_t dev, ino_t ino )
453 {
454     return &inode_hash[ (ino ^ dev) % HASH_SIZE ];
455 }
456
457 static struct inode *find_inode( dev_t dev, ino_t ino )
458 {
459     struct list *bucket = get_hash_list( dev, ino );
460     struct inode *inode;
461
462     LIST_FOR_EACH_ENTRY( inode, bucket, struct inode, ino_entry )
463         if (inode->ino == ino && inode->dev == dev)
464              return inode;
465
466     return NULL;
467 }
468
469 static struct inode *create_inode( dev_t dev, ino_t ino )
470 {
471     struct inode *inode;
472
473     inode = malloc( sizeof *inode );
474     if (inode)
475     {
476         list_init( &inode->children );
477         list_init( &inode->dirs );
478         inode->ino = ino;
479         inode->dev = dev;
480         inode->wd = -1;
481         inode->parent = NULL;
482         inode->name = NULL;
483         list_add_tail( get_hash_list( dev, ino ), &inode->ino_entry );
484     }
485     return inode;
486 }
487
488 static struct inode *get_inode( dev_t dev, ino_t ino )
489 {
490     struct inode *inode;
491
492     inode = find_inode( dev, ino );
493     if (inode)
494         return inode;
495     return create_inode( dev, ino );
496 }
497
498 static void inode_set_wd( struct inode *inode, int wd )
499 {
500     if (inode->wd != -1)
501         list_remove( &inode->wd_entry );
502     inode->wd = wd;
503     list_add_tail( &wd_hash[ wd % HASH_SIZE ], &inode->wd_entry );
504 }
505
506 static void inode_set_name( struct inode *inode, const char *name )
507 {
508     free (inode->name);
509     inode->name = name ? strdup( name ) : NULL;
510 }
511
512 static void free_inode( struct inode *inode )
513 {
514     int subtree = 0, watches = 0;
515     struct inode *tmp, *next;
516     struct dir *dir;
517
518     LIST_FOR_EACH_ENTRY( dir, &inode->dirs, struct dir, in_entry )
519     {
520         subtree |= dir->subtree;
521         watches++;
522     }
523
524     if (!subtree && !inode->parent)
525     {
526         LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &inode->children,
527                                   struct inode, ch_entry )
528         {
529             assert( tmp != inode );
530             assert( tmp->parent == inode );
531             free_inode( tmp );
532         }
533     }
534
535     if (watches)
536         return;
537
538     if (inode->parent)
539         list_remove( &inode->ch_entry );
540
541     /* disconnect remaining children from the parent */
542     LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &inode->children, struct inode, ch_entry )
543     {
544         list_remove( &tmp->ch_entry );
545         tmp->parent = NULL;
546     }
547
548     if (inode->wd != -1)
549     {
550         inotify_rm_watch( get_unix_fd( inotify_fd ), inode->wd );
551         list_remove( &inode->wd_entry );
552     }
553     list_remove( &inode->ino_entry );
554
555     free( inode->name );
556     free( inode );
557 }
558
559 static struct inode *inode_add( struct inode *parent,
560                                 dev_t dev, ino_t ino, const char *name )
561 {
562     struct inode *inode;
563  
564     inode = get_inode( dev, ino );
565     if (!inode)
566         return NULL;
567  
568     if (!inode->parent)
569     {
570         list_add_tail( &parent->children, &inode->ch_entry );
571         inode->parent = parent;
572         assert( inode != parent );
573     }
574     inode_set_name( inode, name );
575
576     return inode;
577 }
578
579 static struct inode *inode_from_name( struct inode *inode, const char *name )
580 {
581     struct inode *i;
582
583     LIST_FOR_EACH_ENTRY( i, &inode->children, struct inode, ch_entry )
584         if (i->name && !strcmp( i->name, name ))
585             return i;
586     return NULL;
587 }
588
589 static int inotify_get_poll_events( struct fd *fd );
590 static void inotify_poll_event( struct fd *fd, int event );
591
592 static const struct fd_ops inotify_fd_ops =
593 {
594     inotify_get_poll_events,     /* get_poll_events */
595     inotify_poll_event,          /* poll_event */
596     NULL,                        /* flush */
597     NULL,                        /* get_fd_type */
598     NULL,                        /* ioctl */
599     NULL,                        /* queue_async */
600     NULL,                        /* reselect_async */
601     NULL,                        /* cancel_async */
602 };
603
604 static int inotify_get_poll_events( struct fd *fd )
605 {
606     return POLLIN;
607 }
608
609 static void inotify_do_change_notify( struct dir *dir, unsigned int action,
610                                       const char *relpath )
611 {
612     struct change_record *record;
613
614     assert( dir->obj.ops == &dir_ops );
615
616     if (dir->want_data)
617     {
618         size_t len = strlen(relpath);
619         record = malloc( offsetof(struct change_record, name[len]) );
620         if (!record)
621             return;
622
623         record->action = action;
624         memcpy( record->name, relpath, len );
625         record->len = len;
626
627         list_add_tail( &dir->change_records, &record->entry );
628     }
629
630     fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_ALERTED );
631 }
632
633 static unsigned int filter_from_event( struct inotify_event *ie )
634 {
635     unsigned int filter = 0;
636
637     if (ie->mask & (IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_CREATE))
638         filter |= FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
639     if (ie->mask & IN_MODIFY)
640         filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
641     if (ie->mask & IN_ATTRIB)
642         filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY;
643     if (ie->mask & IN_ACCESS)
644         filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
645     if (ie->mask & IN_CREATE)
646         filter |= FILE_NOTIFY_CHANGE_CREATION;
647
648     if (ie->mask & IN_ISDIR)
649         filter &= ~FILE_NOTIFY_CHANGE_FILE_NAME;
650     else
651         filter &= ~FILE_NOTIFY_CHANGE_DIR_NAME;
652
653     return filter;
654 }
655
656 /* scan up the parent directories for watches */
657 static unsigned int filter_from_inode( struct inode *inode, int is_parent )
658 {
659     unsigned int filter = 0;
660     struct dir *dir;
661
662     /* combine filters from parents watching subtrees */
663     while (inode)
664     {
665         LIST_FOR_EACH_ENTRY( dir, &inode->dirs, struct dir, in_entry )
666             if (dir->subtree || !is_parent)
667                 filter |= dir->filter;
668         is_parent = 1;
669         inode = inode->parent;
670     }
671
672     return filter;
673 }
674
675 static char *inode_get_path( struct inode *inode, int sz )
676 {
677     struct list *head;
678     char *path;
679     int len;
680
681     if (!inode)
682         return NULL;
683
684     head = list_head( &inode->dirs );
685     if (head)
686     {
687         int unix_fd = get_unix_fd( LIST_ENTRY( head, struct dir, in_entry )->fd );
688         path = malloc ( 32 + sz );
689         if (path)
690             sprintf( path, "/proc/self/fd/%u/", unix_fd );
691         return path;
692     }
693
694     if (!inode->name)
695         return NULL;
696
697     len = strlen( inode->name );
698     path = inode_get_path( inode->parent, sz + len + 1 );
699     if (!path)
700         return NULL;
701     
702     strcat( path, inode->name );
703     strcat( path, "/" );
704
705     return path;
706 }
707
708 static void inode_check_dir( struct inode *parent, const char *name )
709 {
710     char *path;
711     unsigned int filter;
712     struct inode *inode;
713     struct stat st;
714     int wd = -1;
715
716     path = inode_get_path( parent, strlen(name) );
717     if (!path)
718         return;
719
720     strcat( path, name );
721
722     if (stat( path, &st ) < 0)
723         goto end;
724
725     filter = filter_from_inode( parent, 1 );
726     if (!filter)
727         goto end;
728
729     inode = inode_add( parent, st.st_dev, st.st_ino, name );
730     if (!inode || inode->wd != -1)
731         goto end;
732
733     wd = inotify_add_dir( path, filter );
734     if (wd != -1)
735         inode_set_wd( inode, wd );
736     else
737         free_inode( inode );
738
739 end:
740     free( path );
741 }
742
743 static int prepend( char **path, const char *segment )
744 {
745     int extra;
746     char *p;
747
748     extra = strlen( segment ) + 1;
749     if (*path)
750     {
751         int len = strlen( *path ) + 1;
752         p = realloc( *path, len + extra );
753         if (!p) return 0;
754         memmove( &p[ extra ], p, len );
755         p[ extra - 1 ] = '/';
756         memcpy( p, segment, extra - 1 );
757     }
758     else
759     {
760         p = malloc( extra );
761         if (!p) return 0;
762         memcpy( p, segment, extra );
763     }
764
765     *path = p;
766
767     return 1;
768 }
769
770 static void inotify_notify_all( struct inotify_event *ie )
771 {
772     unsigned int filter, action;
773     struct inode *inode, *i;
774     char *path = NULL;
775     struct dir *dir;
776
777     inode = inode_from_wd( ie->wd );
778     if (!inode)
779     {
780         fprintf( stderr, "no inode matches %d\n", ie->wd);
781         return;
782     }
783
784     filter = filter_from_event( ie );
785     
786     if (ie->mask & IN_CREATE)
787     {
788         if (ie->mask & IN_ISDIR)
789             inode_check_dir( inode, ie->name );
790
791         action = FILE_ACTION_ADDED;
792     }
793     else if (ie->mask & IN_DELETE)
794         action = FILE_ACTION_REMOVED;
795     else if (ie->mask & IN_MOVED_FROM)
796         action = FILE_ACTION_RENAMED_OLD_NAME;
797     else if (ie->mask & IN_MOVED_TO)
798         action = FILE_ACTION_RENAMED_NEW_NAME;
799     else
800         action = FILE_ACTION_MODIFIED;
801
802     /*
803      * Work our way up the inode hierarchy
804      *  extending the relative path as we go
805      *  and notifying all recursive watches.
806      */
807     if (!prepend( &path, ie->name ))
808         return;
809
810     for (i = inode; i; i = i->parent)
811     {
812         LIST_FOR_EACH_ENTRY( dir, &i->dirs, struct dir, in_entry )
813             if ((filter & dir->filter) && (i==inode || dir->subtree))
814                 inotify_do_change_notify( dir, action, path );
815
816         if (!i->name || !prepend( &path, i->name ))
817             break;
818     }
819
820     free( path );
821
822     if (ie->mask & IN_DELETE)
823     {
824         i = inode_from_name( inode, ie->name );
825         if (i)
826             free_inode( i );
827     }
828 }
829
830 static void inotify_poll_event( struct fd *fd, int event )
831 {
832     int r, ofs, unix_fd;
833     char buffer[0x1000];
834     struct inotify_event *ie;
835
836     unix_fd = get_unix_fd( fd );
837     r = read( unix_fd, buffer, sizeof buffer );
838     if (r < 0)
839     {
840         fprintf(stderr,"inotify_poll_event(): inotify read failed!\n");
841         return;
842     }
843
844     for( ofs = 0; ofs < r - offsetof(struct inotify_event, name); )
845     {
846         ie = (struct inotify_event*) &buffer[ofs];
847         if (!ie->len)
848             break;
849         ofs += offsetof( struct inotify_event, name[ie->len] );
850         if (ofs > r) break;
851         inotify_notify_all( ie );
852     }
853 }
854
855 static inline struct fd *create_inotify_fd( void )
856 {
857     int unix_fd;
858
859     unix_fd = inotify_init();
860     if (unix_fd<0)
861         return NULL;
862     return create_anonymous_fd( &inotify_fd_ops, unix_fd, NULL, 0 );
863 }
864
865 static int map_flags( unsigned int filter )
866 {
867     unsigned int mask;
868
869     /* always watch these so we can track subdirectories in recursive watches */
870     mask = (IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF);
871
872     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
873         mask |= IN_ATTRIB;
874     if (filter & FILE_NOTIFY_CHANGE_SIZE)
875         mask |= IN_MODIFY;
876     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
877         mask |= IN_MODIFY;
878     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
879         mask |= IN_ACCESS;
880     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
881         mask |= IN_ATTRIB;
882
883     return mask;
884 }
885
886 static int inotify_add_dir( char *path, unsigned int filter )
887 {
888     int wd = inotify_add_watch( get_unix_fd( inotify_fd ),
889                                 path, map_flags( filter ) );
890     if (wd != -1)
891         set_fd_events( inotify_fd, POLLIN );
892     return wd;
893 }
894
895 static int init_inotify( void )
896 {
897     int i;
898
899     if (inotify_fd)
900         return 1;
901
902     inotify_fd = create_inotify_fd();
903     if (!inotify_fd)
904         return 0;
905
906     for (i=0; i<HASH_SIZE; i++)
907     {
908         list_init( &inode_hash[i] );
909         list_init( &wd_hash[i] );
910     }
911
912     return 1;
913 }
914
915 static int inotify_adjust_changes( struct dir *dir )
916 {
917     unsigned int filter;
918     struct inode *inode;
919     struct stat st;
920     char path[32];
921     int wd, unix_fd;
922
923     if (!inotify_fd)
924         return 0;
925
926     unix_fd = get_unix_fd( dir->fd );
927
928     inode = dir->inode;
929     if (!inode)
930     {
931         /* check if this fd is already being watched */
932         if (-1 == fstat( unix_fd, &st ))
933             return 0;
934
935         inode = get_inode( st.st_dev, st.st_ino );
936         if (!inode)
937             inode = create_inode( st.st_dev, st.st_ino );
938         if (!inode)
939             return 0;
940         list_add_tail( &inode->dirs, &dir->in_entry );
941         dir->inode = inode;
942     }
943
944     filter = filter_from_inode( inode, 0 );
945
946     sprintf( path, "/proc/self/fd/%u", unix_fd );
947     wd = inotify_add_dir( path, filter );
948     if (wd == -1) return 0;
949
950     inode_set_wd( inode, wd );
951
952     return 1;
953 }
954
955 static char *get_basename( const char *link )
956 {
957     char *buffer, *name = NULL;
958     int r, n = 0x100;
959
960     while (1)
961     {
962         buffer = malloc( n );
963         if (!buffer) return NULL;
964
965         r = readlink( link, buffer, n );
966         if (r < 0)
967             break;
968
969         if (r < n)
970         {
971             name = buffer;
972             break;
973         }
974         free( buffer );
975         n *= 2;
976     }
977
978     if (name)
979     {
980         while (r > 0 && name[ r - 1 ] == '/' )
981             r--;
982         name[ r ] = 0;
983
984         name = strrchr( name, '/' );
985         if (name)
986             name = strdup( &name[1] );
987     }
988
989     free( buffer );
990     return name;
991 }
992
993 static int dir_add_to_existing_notify( struct dir *dir )
994 {
995     struct inode *inode, *parent;
996     unsigned int filter = 0;
997     struct stat st, st_new;
998     char link[35], *name;
999     int wd, unix_fd;
1000
1001     if (!inotify_fd)
1002         return 0;
1003
1004     unix_fd = get_unix_fd( dir->fd );
1005
1006     /* check if it's in the list of inodes we want to watch */
1007     if (-1 == fstat( unix_fd, &st_new ))
1008         return 0;
1009     inode = find_inode( st_new.st_dev, st_new.st_ino );
1010     if (inode)
1011         return 0;
1012
1013     /* lookup the parent */
1014     sprintf( link, "/proc/self/fd/%u/..", unix_fd );
1015     if (-1 == stat( link, &st ))
1016         return 0;
1017
1018     /*
1019      * If there's no parent, stop.  We could keep going adding
1020      *  ../ to the path until we hit the root of the tree or
1021      *  find a recursively watched ancestor.
1022      * Assume it's too expensive to search up the tree for now.
1023      */
1024     parent = find_inode( st.st_dev, st.st_ino );
1025     if (!parent)
1026         return 0;
1027
1028     if (parent->wd == -1)
1029         return 0;
1030
1031     filter = filter_from_inode( parent, 1 );
1032     if (!filter)
1033         return 0;
1034
1035     sprintf( link, "/proc/self/fd/%u", unix_fd );
1036     name = get_basename( link );
1037     if (!name)
1038         return 0;
1039     inode = inode_add( parent, st_new.st_dev, st_new.st_ino, name );
1040     free( name );
1041     if (!inode)
1042         return 0;
1043
1044     /* Couldn't find this inode at the start of the function, must be new */
1045     assert( inode->wd == -1 );
1046
1047     wd = inotify_add_dir( link, filter );
1048     if (wd != -1)
1049         inode_set_wd( inode, wd );
1050
1051     return 1;
1052 }
1053
1054 #else
1055
1056 static int init_inotify( void )
1057 {
1058     return 0;
1059 }
1060
1061 static int inotify_adjust_changes( struct dir *dir )
1062 {
1063     return 0;
1064 }
1065
1066 static void free_inode( struct inode *inode )
1067 {
1068     assert( 0 );
1069 }
1070
1071 static int dir_add_to_existing_notify( struct dir *dir )
1072 {
1073     return 0;
1074 }
1075
1076 #endif  /* USE_INOTIFY */
1077
1078 struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode )
1079 {
1080     struct dir *dir;
1081
1082     dir = alloc_object( &dir_ops );
1083     if (!dir)
1084         return NULL;
1085
1086     list_init( &dir->change_records );
1087     dir->filter = 0;
1088     dir->notified = 0;
1089     dir->want_data = 0;
1090     dir->inode = NULL;
1091     grab_object( fd );
1092     dir->fd = fd;
1093     dir->mode = mode;
1094     dir->uid  = ~(uid_t)0;
1095     set_fd_user( fd, &dir_fd_ops, &dir->obj );
1096
1097     dir_add_to_existing_notify( dir );
1098
1099     return &dir->obj;
1100 }
1101
1102 /* enable change notifications for a directory */
1103 DECL_HANDLER(read_directory_changes)
1104 {
1105     struct dir *dir;
1106     struct async *async;
1107
1108     if (!req->filter)
1109     {
1110         set_error(STATUS_INVALID_PARAMETER);
1111         return;
1112     }
1113
1114     dir = get_dir_obj( current->process, req->async.handle, 0 );
1115     if (!dir)
1116         return;
1117
1118     /* requests don't timeout */
1119     if (!(async = fd_queue_async( dir->fd, &req->async, ASYNC_TYPE_WAIT ))) goto end;
1120
1121     /* assign it once */
1122     if (!dir->filter)
1123     {
1124         init_inotify();
1125         insert_change( dir );
1126         dir->filter = req->filter;
1127         dir->subtree = req->subtree;
1128         dir->want_data = req->want_data;
1129     }
1130
1131     /* if there's already a change in the queue, send it */
1132     if (!list_empty( &dir->change_records ))
1133         fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_ALERTED );
1134
1135     /* setup the real notification */
1136     if (!inotify_adjust_changes( dir ))
1137         dnotify_adjust_changes( dir );
1138
1139     release_object( async );
1140     set_error(STATUS_PENDING);
1141
1142 end:
1143     release_object( dir );
1144 }
1145
1146 DECL_HANDLER(read_change)
1147 {
1148     struct change_record *record;
1149     struct dir *dir;
1150
1151     dir = get_dir_obj( current->process, req->handle, 0 );
1152     if (!dir)
1153         return;
1154
1155     if ((record = get_first_change_record( dir )) != NULL)
1156     {
1157         reply->action = record->action;
1158         set_reply_data( record->name, record->len );
1159         free( record );
1160     }
1161     else
1162         set_error( STATUS_NO_DATA_DETECTED );
1163
1164     release_object( dir );
1165 }