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