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