Subversion Repositories public

Rev

Rev 39 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 luk 1
 
2
/// inotify C++ interface implementation
3
/**
4
 * \file inotify-cxx.cpp
5
 *
6
 * inotify C++ interface
7
 *
103 luk 8
 * Copyright (C) 2006, 2007, 2009 Lukas Jelinek <lukas@aiken.cz>
3 luk 9
 *
10
 * This program is free software; you can redistribute it and/or
11
 * modify it under the terms of one of the following licenses:
12
 *
13
 * \li 1. X11-style license (see LICENSE-X11)
14
 * \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL)
15
 * \li 3. GNU General Public License, version 2  (see LICENSE-GPL)
16
 *
17
 * If you want to help with choosing the best license for you,
18
 * please visit http://www.gnu.org/licenses/license-list.html.
103 luk 19
 *
20
 * Credits:
21
 *     Mike Frysinger (cleanup of includes)
3 luk 22
 *
23
 */
24
 
25
 
26
#include <errno.h>
27
#include <unistd.h>
13 luk 28
#include <fcntl.h>
103 luk 29
#include <fstream>
3 luk 30
 
103 luk 31
#include <sys/syscall.h>
32
 
33
// Use this if syscalls not defined
34
#ifndef __NR_inotify_init
35
#include <sys/inotify-syscalls.h>
36
#endif // __NR_inotify_init
37
 
3 luk 38
#include "inotify-cxx.h"
39
 
29 luk 40
/// procfs inotify base path
41
#define PROCFS_INOTIFY_BASE "/proc/sys/fs/inotify/"
42
 
13 luk 43
/// dump separator (between particular entries)
3 luk 44
#define DUMP_SEP \
45
  ({ \
46
    if (!rStr.empty()) { \
11 luk 47
      rStr.append(","); \
3 luk 48
    } \
49
  })
50
 
13 luk 51
 
23 luk 52
 
13 luk 53
int32_t InotifyEvent::GetDescriptor() const
54
{
55
  return  m_pWatch != NULL            // if watch exists
56
      ?   m_pWatch->GetDescriptor()   // return its descriptor
57
      :   -1;                         // else return -1
58
}
59
 
11 luk 60
uint32_t InotifyEvent::GetMaskByName(const std::string& rName)
61
{
62
  if (rName == "IN_ACCESS")
63
    return IN_ACCESS;
64
  else if (rName == "IN_MODIFY")
65
    return IN_MODIFY;
66
  else if (rName == "IN_ATTRIB")
67
    return IN_ATTRIB;
68
  else if (rName == "IN_CLOSE_WRITE")
69
    return IN_CLOSE_WRITE;
70
  else if (rName == "IN_CLOSE_NOWRITE")
71
    return IN_CLOSE_NOWRITE;
25 luk 72
  else if (rName == "IN_OPEN")
73
    return IN_OPEN;
11 luk 74
  else if (rName == "IN_MOVED_FROM")
75
    return IN_MOVED_FROM;
76
  else if (rName == "IN_MOVED_TO")
77
    return IN_MOVED_TO;
78
  else if (rName == "IN_CREATE")
79
    return IN_CREATE;
80
  else if (rName == "IN_DELETE")
81
    return IN_DELETE;
82
  else if (rName == "IN_DELETE_SELF")
83
    return IN_DELETE_SELF;
84
  else if (rName == "IN_UNMOUNT")
85
    return IN_UNMOUNT;
86
  else if (rName == "IN_Q_OVERFLOW")
87
    return IN_Q_OVERFLOW;
88
  else if (rName == "IN_IGNORED")
89
    return IN_IGNORED;
90
  else if (rName == "IN_CLOSE")
91
    return IN_CLOSE;
92
  else if (rName == "IN_MOVE")
93
    return IN_MOVE;
94
  else if (rName == "IN_ISDIR")
95
    return IN_ISDIR;
96
  else if (rName == "IN_ONESHOT")
97
    return IN_ONESHOT;
98
  else if (rName == "IN_ALL_EVENTS")
99
    return IN_ALL_EVENTS;
100
 
17 luk 101
#ifdef IN_DONT_FOLLOW
102
  else if (rName == "IN_DONT_FOLLOW")
103
    return IN_DONT_FOLLOW;
104
#endif // IN_DONT_FOLLOW
105
 
106
#ifdef IN_ONLYDIR
107
  else if (rName == "IN_ONLYDIR")
108
    return IN_ONLYDIR;
109
#endif // IN_ONLYDIR
29 luk 110
 
111
#ifdef IN_MOVE_SELF
112
  else if (rName == "IN_MOVE_SELF")
113
    return IN_MOVE_SELF;
114
#endif // IN_MOVE_SELF
17 luk 115
 
11 luk 116
  return (uint32_t) 0;
117
}
3 luk 118
 
11 luk 119
void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr)
3 luk 120
{
121
  rStr = "";
122
 
11 luk 123
  if (IsType(uValue, IN_ALL_EVENTS)) {
124
    rStr.append("IN_ALL_EVENTS");
3 luk 125
  }
11 luk 126
  else {
127
    if (IsType(uValue, IN_ACCESS)) {
128
      DUMP_SEP;
129
      rStr.append("IN_ACCESS");    
130
    }
131
    if (IsType(uValue, IN_MODIFY)) {
132
      DUMP_SEP;
133
      rStr.append("IN_MODIFY");
134
    }
135
    if (IsType(uValue, IN_ATTRIB)) {
136
      DUMP_SEP;
137
      rStr.append("IN_ATTRIB");
138
    }
139
    if (IsType(uValue, IN_CREATE)) {
140
      DUMP_SEP;
141
      rStr.append("IN_CREATE");
142
    }
143
    if (IsType(uValue, IN_DELETE)) {
144
      DUMP_SEP;
145
      rStr.append("IN_DELETE");
146
    }
147
    if (IsType(uValue, IN_DELETE_SELF)) {
148
      DUMP_SEP;
149
      rStr.append("IN_DELETE_SELF");
150
    }
151
    if (IsType(uValue, IN_OPEN)) {
152
      DUMP_SEP;
153
      rStr.append("IN_OPEN");
154
    }
155
    if (IsType(uValue, IN_CLOSE)) {
156
      DUMP_SEP;
157
      rStr.append("IN_CLOSE");
158
    }
35 luk 159
 
160
#ifdef IN_MOVE_SELF
161
    if (IsType(uValue, IN_MOVE_SELF)) {
162
      DUMP_SEP;
163
      rStr.append("IN_MOVE_SELF");    
164
    }
165
#endif // IN_MOVE_SELF
166
 
11 luk 167
    else {
168
      if (IsType(uValue, IN_CLOSE_WRITE)) {
169
        DUMP_SEP;
170
        rStr.append("IN_CLOSE_WRITE");
171
      }
172
      if (IsType(uValue, IN_CLOSE_NOWRITE)) {
173
        DUMP_SEP;
174
        rStr.append("IN_CLOSE_NOWRITE");
175
      }
176
    }
177
    if (IsType(uValue, IN_MOVE)) {
178
      DUMP_SEP;
179
      rStr.append("IN_MOVE");
180
    }
181
    else {
182
      if (IsType(uValue, IN_MOVED_FROM)) {
183
        DUMP_SEP;
184
        rStr.append("IN_MOVED_FROM");
185
      }
186
      if (IsType(uValue, IN_MOVED_TO)) {
187
        DUMP_SEP;
188
        rStr.append("IN_MOVED_TO");
189
      }
190
    }
3 luk 191
  }
11 luk 192
  if (IsType(uValue, IN_UNMOUNT)) {
3 luk 193
    DUMP_SEP;
194
    rStr.append("IN_UNMOUNT");
195
  }
11 luk 196
  if (IsType(uValue, IN_Q_OVERFLOW)) {
3 luk 197
    DUMP_SEP;
198
    rStr.append("IN_Q_OVERFLOW");
199
  }
11 luk 200
  if (IsType(uValue, IN_IGNORED)) {
3 luk 201
    DUMP_SEP;
202
    rStr.append("IN_IGNORED");
203
  }
11 luk 204
  if (IsType(uValue, IN_ISDIR)) {
3 luk 205
    DUMP_SEP;
206
    rStr.append("IN_ISDIR");
207
  }
11 luk 208
  if (IsType(uValue, IN_ONESHOT)) {
3 luk 209
    DUMP_SEP;
210
    rStr.append("IN_ONESHOT");
211
  }
17 luk 212
 
213
#ifdef IN_DONT_FOLLOW
214
  if (IsType(uValue, IN_DONT_FOLLOW)) {
215
    DUMP_SEP;
216
    rStr.append("IN_DONT_FOLLOW");
217
  }
218
#endif // IN_DONT_FOLLOW
219
 
220
#ifdef IN_ONLYDIR
221
  if (IsType(uValue, IN_ONLYDIR)) {
222
    DUMP_SEP;
223
    rStr.append("IN_ONLYDIR");
224
  }
225
#endif // IN_ONLYDIR
3 luk 226
}
227
 
11 luk 228
void InotifyEvent::DumpTypes(std::string& rStr) const
229
{
13 luk 230
  DumpTypes(m_uMask, rStr);
11 luk 231
}
3 luk 232
 
11 luk 233
 
17 luk 234
void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException)
235
{
21 luk 236
  IN_WRITE_BEGIN
237
 
17 luk 238
  if (m_wd != -1) {
239
    int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask);
21 luk 240
    if (wd != m_wd) {
241
      IN_WRITE_END_NOTHROW
17 luk 242
      throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this);
21 luk 243
    }
17 luk 244
  }
245
 
246
  m_uMask = uMask;
21 luk 247
 
248
  IN_WRITE_END
17 luk 249
}
250
 
251
void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException)
252
{
21 luk 253
  IN_WRITE_BEGIN
254
 
255
  if (fEnabled == m_fEnabled) {
256
    IN_WRITE_END_NOTHROW
17 luk 257
    return;
21 luk 258
  }
17 luk 259
 
260
  if (m_pInotify != NULL) {
261
    if (fEnabled) {
262
      m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask);
21 luk 263
      if (m_wd == -1) {
264
        IN_WRITE_END_NOTHROW
17 luk 265
        throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this);
21 luk 266
      }
17 luk 267
      m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this));
268
    }
269
    else {
21 luk 270
      if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) {
271
        IN_WRITE_END_NOTHROW
17 luk 272
        throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this);
21 luk 273
      }
17 luk 274
      m_pInotify->m_watches.erase(m_wd);
275
      m_wd = -1;
276
    }
277
  }
278
 
279
  m_fEnabled = fEnabled;
21 luk 280
 
281
  IN_WRITE_END
17 luk 282
}
283
 
37 luk 284
void InotifyWatch::__Disable()
33 luk 285
{
286
  IN_WRITE_BEGIN
287
 
288
  if (!m_fEnabled) {
289
    IN_WRITE_END_NOTHROW
290
    throw InotifyException(IN_EXC_MSG("event cannot occur on disabled watch"), EINVAL, this);
291
  }
292
 
293
  if (m_pInotify != NULL) {
294
    m_pInotify->m_watches.erase(m_wd);
295
    m_wd = -1;
296
  }
297
 
298
  m_fEnabled = false;
299
 
300
  IN_WRITE_END
301
}
17 luk 302
 
33 luk 303
 
13 luk 304
Inotify::Inotify() throw (InotifyException)
3 luk 305
{
21 luk 306
  IN_LOCK_INIT
307
 
13 luk 308
  m_fd = inotify_init();
21 luk 309
  if (m_fd == -1) {
310
    IN_LOCK_DONE
17 luk 311
    throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL);
21 luk 312
  }
3 luk 313
}
314
 
315
Inotify::~Inotify()
316
{
317
  Close();
21 luk 318
 
319
  IN_LOCK_DONE
3 luk 320
}
321
 
322
void Inotify::Close()
323
{
21 luk 324
  IN_WRITE_BEGIN
325
 
3 luk 326
  if (m_fd != -1) {
327
    RemoveAll();
328
    close(m_fd);
329
    m_fd = -1;
330
  }
21 luk 331
 
332
  IN_WRITE_END
3 luk 333
}
334
 
13 luk 335
void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException)
3 luk 336
{
21 luk 337
  IN_WRITE_BEGIN
338
 
17 luk 339
  // invalid descriptor - this case shouldn't occur - go away
21 luk 340
  if (m_fd == -1) {
341
    IN_WRITE_END_NOTHROW
13 luk 342
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
21 luk 343
  }
17 luk 344
 
345
  // this path already watched - go away  
21 luk 346
  if (FindWatch(pWatch->GetPath()) != NULL) {
347
    IN_WRITE_END_NOTHROW
17 luk 348
    throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this);
21 luk 349
  }
17 luk 350
 
351
  // for enabled watch
352
  if (pWatch->IsEnabled()) {
3 luk 353
 
17 luk 354
    // try to add watch to kernel
355
    int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask());
356
 
357
    // adding failed - go away
21 luk 358
    if (wd == -1) {
359
      IN_WRITE_END_NOTHROW
17 luk 360
      throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this);
21 luk 361
    }
17 luk 362
 
363
    // this path already watched (but defined another way)
364
    InotifyWatch* pW = FindWatch(wd);
365
    if (pW != NULL) {
366
 
367
      // try to recover old watch because it may be modified - then go away
368
      if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) {
21 luk 369
        IN_WRITE_END_NOTHROW
17 luk 370
        throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this);
371
      }
372
      else {
373
        // recovery failed - go away
21 luk 374
        IN_WRITE_END_NOTHROW
17 luk 375
        throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this);
376
      }
377
    }
378
 
379
    pWatch->m_wd = wd;
380
    m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch));
381
  }
382
 
383
  m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch));
13 luk 384
  pWatch->m_pInotify = this;
21 luk 385
 
386
  IN_WRITE_END
3 luk 387
}
388
 
13 luk 389
void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException)
3 luk 390
{
21 luk 391
  IN_WRITE_BEGIN
392
 
17 luk 393
  // invalid descriptor - this case shouldn't occur - go away
21 luk 394
  if (m_fd == -1) {
395
    IN_WRITE_END_NOTHROW
13 luk 396
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
21 luk 397
  }
17 luk 398
 
399
  // for enabled watch
400
  if (pWatch->m_wd != -1) {  
3 luk 401
 
17 luk 402
    // removing watch failed - go away
21 luk 403
    if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) {
404
      IN_WRITE_END_NOTHROW
17 luk 405
      throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this);
21 luk 406
    }
17 luk 407
    m_watches.erase(pWatch->m_wd);
408
    pWatch->m_wd = -1;
409
  }
410
 
411
  m_paths.erase(pWatch->m_path);
13 luk 412
  pWatch->m_pInotify = NULL;
21 luk 413
 
414
  IN_WRITE_END
3 luk 415
}
416
 
417
void Inotify::RemoveAll()
418
{
21 luk 419
  IN_WRITE_BEGIN
420
 
17 luk 421
  IN_WP_MAP::iterator it = m_paths.begin();
422
  while (it != m_paths.end()) {
11 luk 423
    InotifyWatch* pW = (*it).second;
17 luk 424
    if (pW->m_wd != -1) {
425
      inotify_rm_watch(m_fd, pW->m_wd);
426
      pW->m_wd = -1;
427
    }
11 luk 428
    pW->m_pInotify = NULL;
3 luk 429
    it++;
430
  }
431
 
432
  m_watches.clear();
17 luk 433
  m_paths.clear();
21 luk 434
 
435
  IN_WRITE_END
3 luk 436
}
437
 
13 luk 438
void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException)
3 luk 439
{
440
  ssize_t len = 0;
441
 
442
  do {
443
    len = read(m_fd, m_buf, INOTIFY_BUFLEN);
444
  } while (fNoIntr && len == -1 && errno == EINTR);
445
 
27 luk 446
  if (len == -1 && !(errno == EWOULDBLOCK || errno == EINTR))
447
    throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this);
448
 
449
  if (len == -1)
15 luk 450
    return;
451
 
21 luk 452
  IN_WRITE_BEGIN
453
 
3 luk 454
  ssize_t i = 0;
455
  while (i < len) {
13 luk 456
    struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i];
457
    InotifyWatch* pW = FindWatch(pEvt->wd);
17 luk 458
    if (pW != NULL) {
13 luk 459
      InotifyEvent evt(pEvt, pW);
37 luk 460
      if (    InotifyEvent::IsType(pW->GetMask(), IN_ONESHOT)
461
          ||  InotifyEvent::IsType(evt.GetMask(), IN_IGNORED))
462
        pW->__Disable();
13 luk 463
      m_events.push_back(evt);
464
    }
465
    i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len;
3 luk 466
  }
467
 
21 luk 468
  IN_WRITE_END
3 luk 469
}
470
 
13 luk 471
bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException)
3 luk 472
{
21 luk 473
  if (pEvt == NULL)
474
    throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this);
13 luk 475
 
21 luk 476
  IN_WRITE_BEGIN
477
 
478
  bool b = !m_events.empty();
479
  if (b) {
480
    *pEvt = m_events.front();
3 luk 481
    m_events.pop_front();
21 luk 482
  }
483
 
484
  IN_WRITE_END
13 luk 485
 
3 luk 486
  return b;
487
}
488
 
13 luk 489
bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException)
3 luk 490
{
13 luk 491
  if (pEvt == NULL)
492
    throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this);
3 luk 493
 
21 luk 494
  IN_READ_BEGIN
495
 
496
  bool b = !m_events.empty();
497
  if (b) {
13 luk 498
    *pEvt = m_events.front();
499
  }
500
 
21 luk 501
  IN_READ_END
502
 
503
  return b;
3 luk 504
}
505
 
506
InotifyWatch* Inotify::FindWatch(int iDescriptor)
507
{
21 luk 508
  IN_READ_BEGIN
509
 
3 luk 510
  IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor);
21 luk 511
  InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second;
512
 
513
  IN_READ_END
514
 
515
  return pW;
3 luk 516
}
17 luk 517
 
518
InotifyWatch* Inotify::FindWatch(const std::string& rPath)
519
{
21 luk 520
  IN_READ_BEGIN
521
 
17 luk 522
  IN_WP_MAP::iterator it = m_paths.find(rPath);
21 luk 523
  InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second;
524
 
525
  IN_READ_END
17 luk 526
 
21 luk 527
  return pW;
17 luk 528
}
3 luk 529
 
13 luk 530
void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException)
531
{
21 luk 532
  IN_WRITE_BEGIN
533
 
534
  if (m_fd == -1) {
535
    IN_WRITE_END_NOTHROW
13 luk 536
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
21 luk 537
  }
13 luk 538
 
539
  int res = fcntl(m_fd, F_GETFL);
21 luk 540
  if (res == -1) {
541
    IN_WRITE_END_NOTHROW
13 luk 542
    throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this);
21 luk 543
  }
13 luk 544
 
545
  if (fNonBlock) {
546
    res |= O_NONBLOCK;
547
  }
548
  else {
549
    res &= ~O_NONBLOCK;
550
  }
551
 
21 luk 552
  if (fcntl(m_fd, F_SETFL, res) == -1) {
553
    IN_WRITE_END_NOTHROW
13 luk 554
    throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this);
21 luk 555
  }
556
 
557
  IN_WRITE_END
29 luk 558
}
13 luk 559
 
39 luk 560
void Inotify::SetCloseOnExec(bool fClOnEx) throw (InotifyException)
561
{
562
  IN_WRITE_BEGIN
563
 
564
  if (m_fd == -1) {
565
    IN_WRITE_END_NOTHROW
566
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
567
  }
568
 
569
  int res = fcntl(m_fd, F_GETFD);
570
  if (res == -1) {
571
    IN_WRITE_END_NOTHROW
572
    throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this);
573
  }
574
 
575
  if (fClOnEx) {
576
    res |= FD_CLOEXEC;
577
  }
578
  else {
579
    res &= ~FD_CLOEXEC;
580
  }
581
 
582
  if (fcntl(m_fd, F_SETFD, res) == -1) {
583
    IN_WRITE_END_NOTHROW
584
    throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this);
585
  }
586
 
587
  IN_WRITE_END
588
}
589
 
29 luk 590
uint32_t Inotify::GetCapability(InotifyCapability_t cap) throw (InotifyException)
591
{
592
  FILE* f = fopen(GetCapabilityPath(cap).c_str(), "r");
593
  if (f == NULL)
594
    throw InotifyException(IN_EXC_MSG("cannot get capability"), errno, NULL);
595
 
596
  unsigned int val = 0;
597
  if (fscanf(f, "%u", &val) != 1) {
598
    fclose(f);
599
    throw InotifyException(IN_EXC_MSG("cannot get capability"), EIO, NULL);
600
  }
601
 
602
  fclose(f);
603
 
604
  return (uint32_t) val;
605
}
606
 
607
void Inotify::SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException)
608
{
609
  FILE* f = fopen(GetCapabilityPath(cap).c_str(), "w");
610
  if (f == NULL)
611
    throw InotifyException(IN_EXC_MSG("cannot set capability"), errno, NULL);
612
 
613
  if (fprintf(f, "%u", (unsigned int) val) <= 0) {
614
    fclose(f);
615
    throw InotifyException(IN_EXC_MSG("cannot set capability"), EIO, NULL);
616
  }
617
 
618
  fclose(f);
619
}
620
 
621
std::string Inotify::GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException)
622
{
623
  std::string path(PROCFS_INOTIFY_BASE);
624
 
625
  switch (cap) {
626
    case IN_MAX_EVENTS:
627
      path.append("max_queued_events");
628
      break;
629
    case IN_MAX_INSTANCES:
630
      path.append("max_user_instances");
631
      break;
632
    case IN_MAX_WATCHES:
633
      path.append("max_user_watches");
634
      break;
635
    default:
636
      throw InotifyException(IN_EXC_MSG("unknown capability type"), EINVAL, NULL);
637
  }
638
 
639
  return path;
640
}
641