xref: /haiku/src/kits/storage/NodeMonitor.cpp (revision 51978af14a173e7fae0563b562be5603bc652aeb)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 
6 #include <AppMisc.h>
7 #include <Looper.h>
8 #include <Messenger.h>
9 #include <NodeMonitor.h>
10 
11 // TODO: Tests!
12 
13 // private libroot.so functions
14 
15 /*!	\brief Subscribes a target to node and/or mount watching.
16 
17 	Depending on \a flags, different actions are performed. If flags is \c 0,
18 	mount watching is requested. \a device and \a node must be \c -1 in this
19 	case. Otherwise node watching is requested. \a device and \a node must
20 	refer to a valid node, and \a flags must note contain the flag
21 	\c B_WATCH_MOUNT, but at least one of the other valid flags.
22 
23 	\param device The device the node resides on (node_ref::device). \c -1, if
24 		   only mount watching is requested.
25 	\param node The node ID of the node (node_ref::device). \c -1, if
26 		   only mount watching is requested.
27 	\param flags A bit mask composed of the values specified in
28 		   <NodeMonitor.h>.
29 	\param port The port of the target (a looper port).
30 	\param handlerToken The token of the target handler. \c -2, if the
31 		   preferred handler of the looper is the target.
32 	\return \c B_OK, if everything went fine, another error code otherwise.
33 */
34 extern "C" status_t _kstart_watching_vnode_(dev_t device, ino_t node,
35 											uint32 flags, port_id port,
36 											int32 handlerToken);
37 
38 /*!	\brief Unsubscribes a target from watching a node.
39 	\param device The device the node resides on (node_ref::device).
40 	\param node The node ID of the node (node_ref::device).
41 	\param port The port of the target (a looper port).
42 	\param handlerToken The token of the target handler. \c -2, if the
43 		   preferred handler of the looper is the target.
44 	\return \c B_OK, if everything went fine, another error code otherwise.
45 */
46 extern "C" status_t _kstop_watching_vnode_(dev_t device, ino_t node,
47 										   port_id port, int32 handlerToken);
48 
49 
50 /*!	\brief Unsubscribes a target from node and mount monitoring.
51 	\param port The port of the target (a looper port).
52 	\param handlerToken The token of the target handler. \c -2, if the
53 		   preferred handler of the looper is the target.
54 	\return \c B_OK, if everything went fine, another error code otherwise.
55 */
56 extern "C" status_t _kstop_notifying_(port_id port, int32 handlerToken);
57 
58 
59 // actual implementation
60 
61 // watch_node
62 /*!	\brief Subscribes a target to node and/or mount watching, or unsubscribes
63 		   it from node watching.
64 
65 	Depending of \a flags the action performed by this function varies:
66 	- \a flags is \c 0: The target is unsubscribed from watching the node.
67 	  \a node must not be \c NULL in this case.
68 	- \a flags contains \c B_WATCH_MOUNT: The target is subscribed to mount
69 	  watching.
70 	- \a flags contains at least one of \c B_WATCH_NAME, \c B_WATCH_STAT,
71 	  \c B_WATCH_ATTR, or \c B_WATCH_DIRECTORY: The target is subscribed to
72 	  watching the specified aspects of the node. \a node must not be \c NULL
73 	  in this case.
74 
75 	Note, that the latter two cases are not mutual exlusive, i.e. mount and
76 	node watching can be requested with a single call.
77 
78 	\param node node_ref referring to the node to be watched. May be \c NULL,
79 		   if only mount watching is requested.
80 	\param flags Flags indicating the actions to be performed.
81 	\param target Messenger referring to the target. Must be valid.
82 	\return \c B_OK, if everything went fine, another error code otherwise.
83 */
84 status_t
85 watch_node(const node_ref *node, uint32 flags, BMessenger target)
86 {
87 	status_t error = (target.IsValid() ? B_OK : B_BAD_VALUE);
88 	if (error == B_OK) {
89 		BLooper *looper = NULL;
90 		BHandler *handler = target.Target(&looper);
91 		error = watch_node(node, flags, handler, looper);
92 	}
93 	return error;
94 }
95 
96 // watch_node
97 /*!	\brief Subscribes a target to node and/or mount watching, or unsubscribes
98 		   it from node watching.
99 
100 	Depending of \a flags the action performed by this function varies:
101 	- \a flags is \c 0: The target is unsubscribed from watching the node.
102 	  \a node must not be \c NULL in this case.
103 	- \a flags contains \c B_WATCH_MOUNT: The target is subscribed to mount
104 	  watching.
105 	- \a flags contains at least one of \c B_WATCH_NAME, \c B_WATCH_STAT,
106 	  \c B_WATCH_ATTR, or \c B_WATCH_DIRECTORY: The target is subscribed to
107 	  watching the specified aspects of the node. \a node must not be \c NULL
108 	  in this case.
109 
110 	Note, that the latter two cases are not mutual exlusive, i.e. mount and
111 	node watching can be requested with a single call.
112 
113 	\param node node_ref referring to the node to be watched. May be \c NULL,
114 		   if only mount watching is requested.
115 	\param flags Flags indicating the actions to be performed.
116 	\param handler The target handler. May be \c NULL, if \a looper is not
117 		   \c NULL. Then the preferred handler of the looper is targeted.
118 	\param looper The target looper. May be \c NULL, if \a handler is not
119 		   \c NULL. Then the handler's looper is the target looper.
120 	\return \c B_OK, if everything went fine, another error code otherwise.
121 */
122 status_t
123 watch_node(const node_ref *node, uint32 flags, const BHandler *handler,
124 		   const BLooper *looper)
125 {
126 	status_t error = B_OK;
127 	// check looper and handler and get the handler token
128 	int32 handlerToken = -2;
129 	if (handler) {
130 		handlerToken = _get_object_token_(handler);
131 		if (looper) {
132 			if (looper != handler->Looper())
133 				error = B_BAD_VALUE;
134 		} else {
135 			looper = handler->Looper();
136 			if (!looper)
137 				error = B_BAD_VALUE;
138 		}
139 	} else if (!looper)
140 		error = B_BAD_VALUE;
141 	if (error == B_OK) {
142 		port_id port = _get_looper_port_(looper);
143 		if (flags == B_STOP_WATCHING) {
144 			// unsubscribe from node node watching
145 			if (node) {
146 				error = _kstop_watching_vnode_(node->device, node->node, port,
147 											   handlerToken);
148 			} else
149 				error = B_BAD_VALUE;
150 		} else {
151 			// subscribe to...
152 			// mount watching
153 			if (flags & B_WATCH_MOUNT) {
154 				error = _kstart_watching_vnode_((dev_t)-1, (ino_t)-1, 0, port, handlerToken);
155 				flags &= ~B_WATCH_MOUNT;
156 			}
157 			// node watching
158 			if (error == B_OK && flags) {
159 				error = _kstart_watching_vnode_(node->device, node->node,
160 												flags, port, handlerToken);
161 			}
162 		}
163 	}
164 	return error;
165 }
166 
167 // stop_watching
168 /*!	\brief Unsubscribes a target from node and mount monitoring.
169 	\param target Messenger referring to the target. Must be valid.
170 	\return \c B_OK, if everything went fine, another error code otherwise.
171 */
172 status_t
173 stop_watching(BMessenger target)
174 {
175 	status_t error = (target.IsValid() ? B_OK : B_BAD_VALUE);
176 	if (error == B_OK) {
177 		BLooper *looper = NULL;
178 		BHandler *handler = target.Target(&looper);
179 		error = stop_watching(handler, looper);
180 	}
181 	return error;
182 }
183 
184 // stop_watching
185 /*!	\brief Unsubscribes a target from node and mount monitoring.
186 	\param handler The target handler. May be \c NULL, if \a looper is not
187 		   \c NULL. Then the preferred handler of the looper is targeted.
188 	\param looper The target looper. May be \c NULL, if \a handler is not
189 		   \c NULL. Then the handler's looper is the target looper.
190 	\return \c B_OK, if everything went fine, another error code otherwise.
191 */
192 status_t
193 stop_watching(const BHandler *handler, const BLooper *looper)
194 {
195 	status_t error = B_OK;
196 	// check looper and handler and get the handler token
197 	int32 handlerToken = -2;
198 	if (handler) {
199 		handlerToken = _get_object_token_(handler);
200 		if (looper) {
201 			if (looper != handler->Looper())
202 				error = B_BAD_VALUE;
203 		} else {
204 			looper = handler->Looper();
205 			if (!looper)
206 				error = B_BAD_VALUE;
207 		}
208 	} else if (!looper)
209 		error = B_BAD_VALUE;
210 	// unsubscribe
211 	if (error == B_OK) {
212 		port_id port = _get_looper_port_(looper);
213 		error = _kstop_notifying_(port, handlerToken);
214 	}
215 	return error;
216 }
217 
218