Branch: Tag:

2011-01-25

2011-01-25 09:56:44 by Arne Goedeke <el@laramies.com>

System.Inotify: initial version merged from Public.System.Inotify

1: + /* vim:syntax=c +  */ + /* -*- c -*- + || This file is part of Pike. For copyright information see COPYRIGHT. + || Pike is distributed under GPL, LGPL and MPL. See the file COPYING + || for more information. + || $Id$ + */    -  + /* Module for the linux inotify api. +  * +  * Ref: inotify(7) +  * +  */ +  + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif +  + #ifdef HAVE_SYS_INOTIFY_H +  + #include <sys/inotify.h> + #include <errno.h> +  + #include "global.h" + #include "interpret.h" + #include "module.h" + #include "program.h" + #include "stralloc.h" + #include "svalue.h" + #include "object.h" + #include "pike_types.h" + #include "builtin_functions.h" +  + DECLARATIONS +  + /*! @module System */ +  + /*! @module Inotify +  *! This module implements an API to linux inotify. It is available on all +  *! kernels from version 2.6.13 onwards. Inotify offers fast and scalable file +  *! notifications. +  */ +  + /*! @decl constant IN_ALL_EVENTS +  *! This is a derived constant that is not part of the standard inotify API. It +  *! is the union of all other constants. +  *! +  *! @decl constant IN_ACCESS +  *! @decl constant IN_ATTRIB +  *! @decl constant IN_CLOSE +  *! @decl constant IN_CLOSE_WRITE +  *! @decl constant IN_CLOSE_NOWRITE +  *! @decl constant IN_CREATE +  *! @decl constant IN_DELETE +  *! @decl constant IN_DELETE_SELF +  *! @decl constant IN_MODIFY +  *! @decl constant IN_MOVE_SELF +  *! @decl constant IN_MOVED_FROM +  *! @decl constant IN_MOVED_TO +  *! @decl constant IN_OPEN +  *! @decl constant IN_MOVE +  *! @decl constant IN_CLOSE +  *! @decl constant IN_DONT_FOLLOW +  *! @decl constant IN_MASK_ADD +  *! @decl constant IN_ONESHOT +  *! @decl constant IN_ONLYDIR +  *! @decl constant IN_IGNORED +  *! @decl constant IN_ISDIR +  *! @decl constant IN_Q_OVERFLOW +  *! @decl constant IN_UNMOUNT +  *! Please have a look at the inotify(7) manpage for information about +  *! these constants. +  *! @note +  *! Some constants may not be available when the module has been +  *! compiled on a machine with linux kernel before 2.6.15. See the +  *! manpage for more details. +  */ +  + /*! @decl array parse_event(string data) +  *! Parses one inotify_event struct from @expr{data@}. +  *! @returns +  *! Returns an array consisting of +  *! @ul +  *! @item +  *! The watch descriptor returned by @[add_watch()] when +  *! the wathc for this file was added. +  *! @item +  *! An integer that describes the event that occured. See +  *! the inotify manpage for a list of possible events and +  *! their numerical identifiers. +  *! @item +  *! An integer cookie that can be used to group together +  *! different events that were triggered by moving a file +  *! from one location to another. +  *! @item +  *! The name of the file. This will only be present if the +  *! event happened to a file in a directory that was +  *! watched, e.g. with @[System.Inotify.IN_CREATE]. +  *! Otherwise this will be 0. +  *! @item +  *! The length of the data that has been parsed. In case a +  *! string contains more than one inotify event, this +  *! parse function has to be called again with the rest as +  *! an argument. +  *! @endul +  */ + PIKEFUN array parse_event(string data) { +  struct inotify_event * event; +  size_t len; +  +  if (data->size_shift) +  Pike_error("Inotify events should not be wide.\n"); +  +  if ((size_t)data->len < sizeof(struct inotify_event)) +  Pike_error("Malformed data.\n"); +  +  event = (struct inotify_event *)data->str; +  pop_n_elems(args); +  +  if (event->len > data->len - sizeof(struct inotify_event)) +  Pike_error("Data missing.\n"); +  +  push_int((int)event->wd); +  push_int((int)event->mask); +  push_int((int)event->cookie); +  +  if (event->len && (len = strlen(event->name))) +  push_string(make_shared_binary_string(event->name, len)); +  else +  push_int(0); +  +  push_int((int)(event->len + sizeof(struct inotify_event))); +  +  f_aggregate(5); + } +  + /*! @class _Instance +  *! Simple wrapper class that gives direct access to the inotify(7) +  *! interface. On create an inotify instance is initiated by calling +  *! inotify_init(2). Every object of this class has its own inotify +  *! file descriptor. Use this class only if you want direct access to +  *! the file descriptor to read from it manually. For a more user +  *! friendly inferface use @[System.Inotify.Instance]. +  */ + PIKECLASS _Instance { +  CVAR int fd; +  +  /*! @decl int add_watch(string file, int mask) +  *! Add a watch for a certain file or directory and specific events. +  *! Adding more than one watch for one file will overwrite the +  *! previous watch unless @[System.Inotify.IN_MASK_ADD] is contained +  *! in the mask. +  *! @param path +  *! Path of the file or directory. +  *! @param mask +  *! Integer mask specifying the event type. This can be a +  *! combination of different event types using bitwise OR. +  *! See the inotify manpage for possible values and their +  *! description. The values defined by the inotify header +  *! file are exported by @[System.Inotify] as constants +  *! using the same names (e.g. @[System.Inotify.IN_CREATE]). +  *! @note +  *! Subdirectories are not watched. If you want to watch +  *! subdirectories aswell, its necessary to add watches +  *! for them individually. +  */ +  PIKEFUN int add_watch(string file, int mask) { +  INT32 err; +  +  if (file->size_shift) +  Pike_error("Widestring filenames are not allowed.\n"); +  +  err = inotify_add_watch(THIS->fd, file->str, (INT32)mask); +  +  if (err == -1) +  Pike_error("inotify_add_watch failed: %s\n", +  strerror(errno)); +  else +  RETURN err; +  } +  +  /*! @decl int get_fd() +  *! @returns +  *! Returns the file descriptor that is associated to the inotify +  *! instance. +  */ +  PIKEFUN int get_fd() { +  RETURN THIS->fd; +  } +  +  /*! @decl int rm_watch(int wd) +  *! Remove a watch. +  *! @param wd +  *! The watch descriptor that was returned by @[add_watch()]. +  */ +  PIKEFUN void rm_watch(int wd) { +  INT32 err; +  +  err = inotify_rm_watch(THIS->fd, wd); +  +  if (err == 0) { +  return; +  } +  +  if (errno == EINVAL) { +  Pike_error("Wrong argument to rm_watch().\n"); +  } else if (errno == EBADF) { +  Pike_error("Oups. I feel funny inside.\n"); +  } +  } +  +  INIT { +  THIS->fd = inotify_init(); +  +  if (THIS->fd == -1) switch (errno) { +  case EMFILE: +  Pike_error("User limit on inotify instances reached.\n"); +  case ENFILE: +  Pike_error("User limit on file descriptors reached.\n"); +  case ENOMEM: Pike_error("No free kernel memory available.\n"); +  } +  } +  +  EXIT { +  close(THIS->fd); +  } + } +  + /*! @endclass +  */ +  + #define ADD_ICONST(name) do { \ +  add_integer_constant(#name, name, 0); \ + } while(0); +  +  + PIKE_MODULE_INIT { +  ADD_ICONST(IN_ACCESS); +  ADD_ICONST(IN_ALL_EVENTS); +  ADD_ICONST(IN_ATTRIB); +  ADD_ICONST(IN_CLOSE_WRITE); +  ADD_ICONST(IN_CLOSE_NOWRITE); +  ADD_ICONST(IN_CREATE); +  ADD_ICONST(IN_DELETE); +  ADD_ICONST(IN_DELETE_SELF); +  ADD_ICONST(IN_MODIFY); +  ADD_ICONST(IN_MOVE_SELF); +  ADD_ICONST(IN_MOVED_FROM); +  ADD_ICONST(IN_MOVED_TO); +  ADD_ICONST(IN_OPEN); +  +  ADD_ICONST(IN_MOVE); +  ADD_ICONST(IN_CLOSE); +  + /* some of these came with 2.6.15 linux and 2.5 glibc */ + #ifdef IN_DONT_FOLLOW +  ADD_ICONST(IN_DONT_FOLLOW); + #endif + #ifdef IN_MASK_ADD +  ADD_ICONST(IN_MASK_ADD); + #endif +  ADD_ICONST(IN_ONESHOT); + #ifdef IN_ONLYDIR +  ADD_ICONST(IN_ONLYDIR); + #endif +  +  ADD_ICONST(IN_IGNORED); +  ADD_ICONST(IN_ISDIR); +  ADD_ICONST(IN_Q_OVERFLOW); +  ADD_ICONST(IN_UNMOUNT); +  +  INIT + } +  + PIKE_MODULE_EXIT { +  EXIT + } +  + /*! @endmodule +  */ + /*! @endmodule +  */ + /*! @endmodule +  */ + #endif /* HAVE_SYS_INOTIFY_H */   Newline at end of file added.