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