1/*
2 * Copyright 2010, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 */
8
9#include <new>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <errno.h>
15#include <dirent.h>
16
17#include <fs_info.h>
18#include <fs_interface.h>
19
20#include <debug.h>
21#include <KernelExport.h>
22
23#include <io_requests.h>
24
25static const char *kLogFilePrefix = "/var/log/log_overlay";
26
27
28#define DO_LOG(format, args...) \
29	{ \
30		char _printBuffer[256]; \
31		int _printSize = snprintf(_printBuffer, sizeof(_printBuffer), \
32			"%llu %ld %p: " format, system_time(), find_thread(NULL), \
33			((fs_vnode *)vnode->private_node)->private_node, args); \
34		if ((unsigned int)_printSize > sizeof(_printBuffer)) { \
35			_printBuffer[sizeof(_printBuffer) - 1] = '\n'; \
36			_printSize = sizeof(_printBuffer); \
37		} \
38		write((int)volume->private_volume, _printBuffer, _printSize); \
39	}
40
41#define OVERLAY_CALL(op, params...) \
42	status_t result = B_UNSUPPORTED; \
43	fs_vnode *superVnode = (fs_vnode *)vnode->private_node; \
44	if (superVnode->ops->op != NULL) \
45		result = superVnode->ops->op(volume->super_volume, superVnode, params); \
46
47
48static status_t
49overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
50{
51	DO_LOG("put_vnode reenter: %s\n", reenter ? "yes" : "no");
52
53	status_t result = B_UNSUPPORTED;
54	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
55	if (superVnode->ops->put_vnode != NULL) {
56		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
57			reenter);
58	}
59
60	DO_LOG("put_vnode result: 0x%08lx\n", result);
61	delete (fs_vnode *)vnode->private_node;
62	return result;
63}
64
65
66static status_t
67overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
68{
69	DO_LOG("remove_vnode reenter: %s\n", reenter ? "yes" : "no");
70
71	status_t result = B_UNSUPPORTED;
72	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
73	if (superVnode->ops->remove_vnode != NULL) {
74		result = superVnode->ops->remove_vnode(volume->super_volume, superVnode,
75			reenter);
76	}
77
78	DO_LOG("remove_vnode result: 0x%08lx\n", result);
79	delete (fs_vnode *)vnode->private_node;
80	return result;
81}
82
83
84static status_t
85overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
86	fs_volume *superVolume, fs_vnode *_superVnode)
87{
88	if (volume == superVolume) {
89		*_superVnode = *vnode;
90		return B_OK;
91	}
92
93	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
94	if (superVnode->ops->get_super_vnode != NULL) {
95		return superVnode->ops->get_super_vnode(volume->super_volume,
96			superVnode, superVolume, _superVnode);
97	}
98
99	*_superVnode = *superVnode;
100	return B_OK;
101}
102
103
104static status_t
105overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
106{
107	DO_LOG("lookup name: \"%s\"\n", name);
108	OVERLAY_CALL(lookup, name, id)
109	DO_LOG("lookup result: 0x%08lx; id: %llu\n", result, *id);
110	return result;
111}
112
113
114static status_t
115overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
116	size_t bufferSize)
117{
118	DO_LOG("get_vnode_name buffer: %p; buffer_size: %lu\n", buffer, bufferSize);
119	OVERLAY_CALL(get_vnode_name, buffer, bufferSize)
120	DO_LOG("get_vnode_name result: 0x%08lx; buffer: \"%s\"\n", result,
121		result == B_OK ? buffer : "unsafe");
122	return result;
123}
124
125
126static bool
127overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
128{
129	DO_LOG("can_page cookie: %p\n", cookie);
130	bool result = false;
131	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
132	if (superVnode->ops->can_page != NULL) {
133		result = superVnode->ops->can_page(volume->super_volume, superVnode,
134			cookie);
135	}
136
137	DO_LOG("can_page result: %s\n", result ? "yes" : "no");
138	return result;
139}
140
141
142static status_t
143overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
144	const iovec *vecs, size_t count, size_t *numBytes)
145{
146	DO_LOG("read_pages cookie: %p; pos: %lld; vecs: %p; count: %lu;"
147		" num_bytes: %lu\n", cookie, pos, vecs, count, *numBytes);
148	OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes)
149	DO_LOG("read_pages result: 0x%08lx; num_bytes: %lu\n", result, *numBytes);
150	return result;
151}
152
153
154static status_t
155overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
156	const iovec *vecs, size_t count, size_t *numBytes)
157{
158	DO_LOG("write_pages cookie: %p; pos: %lld; vecs: %p; count: %lu;"
159		" num_bytes: %lu\n", cookie, pos, vecs, count, *numBytes);
160	OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes)
161	DO_LOG("write_pages result: 0x%08lx; num_bytes: %lu\n", result, *numBytes);
162	return result;
163}
164
165
166static status_t
167overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
168	io_request *request)
169{
170	DO_LOG("io cookie: %p; request: %p (write: %s; offset: %lld; length: %llu)"
171		"\n", cookie, request, io_request_is_write(request) ? "yes" : "no",
172		io_request_offset(request), io_request_length(request));
173	OVERLAY_CALL(io, cookie, request)
174	DO_LOG("io result: 0x%08lx\n", result);
175	return result;
176}
177
178
179static status_t
180overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
181	io_request *request)
182{
183	DO_LOG("cancel_io cookie: %p; request: %p\n", cookie, request);
184	OVERLAY_CALL(cancel_io, cookie, request)
185	DO_LOG("cancel_io result: 0x%08lx\n", result);
186	return result;
187}
188
189
190static status_t
191overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
192	size_t size, struct file_io_vec *vecs, size_t *count)
193{
194	DO_LOG("get_file_map offset: %lld; size: %lu; vecs: %p; count: %lu\n",
195		offset, size, vecs, *count);
196	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
197	DO_LOG("get_file_map result: 0x%08lx; count: %lu\n", result, *count);
198	return result;
199}
200
201
202static status_t
203overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
204	void *buffer, size_t length)
205{
206	DO_LOG("ioctl cookie: %p; op: %lu; buffer: %p; size: %lu\n", cookie, op,
207		buffer, length);
208	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
209	DO_LOG("ioctl result: 0x%08lx\n", result);
210	return result;
211}
212
213
214static status_t
215overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
216	int flags)
217{
218	DO_LOG("set_flags cookie: %p; flags: %d\n", cookie, flags);
219	OVERLAY_CALL(set_flags, cookie, flags)
220	DO_LOG("set_flags result: 0x%08lx\n", result);
221	return result;
222}
223
224
225static status_t
226overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
227	selectsync *sync)
228{
229	DO_LOG("select cookie: %p; event: %u; selectsync: %p\n", cookie, event,
230		sync);
231	OVERLAY_CALL(select, cookie, event, sync)
232	DO_LOG("select result: 0x%08lx\n", result);
233	return result;
234}
235
236
237static status_t
238overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
239	selectsync *sync)
240{
241	DO_LOG("deselect cookie: %p; event: %u; selectsync: %p\n", cookie, event,
242		sync);
243	OVERLAY_CALL(deselect, cookie, event, sync)
244	DO_LOG("deselect result: 0x%08lx\n", result);
245	return result;
246}
247
248
249static status_t
250overlay_fsync(fs_volume *volume, fs_vnode *vnode)
251{
252	DO_LOG("%s\n", "fsync");
253
254	status_t result = B_UNSUPPORTED;
255	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
256	if (superVnode->ops->fsync != NULL)
257		result = superVnode->ops->fsync(volume->super_volume, superVnode);
258
259	DO_LOG("fsync result: 0x%08lx\n", result);
260	return result;
261}
262
263
264static status_t
265overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
266	size_t *bufferSize)
267{
268	DO_LOG("read_symlink buffer: %p; buffer_size: %lu\n", buffer, *bufferSize);
269	OVERLAY_CALL(read_symlink, buffer, bufferSize)
270	DO_LOG("read_symlink result: 0x%08lx; buffer_size: %lu; \"%.*s\"\n", result,
271		*bufferSize, result == B_OK ? (int)*bufferSize : 6,
272		result == B_OK ? buffer : "unsafe");
273	return result;
274}
275
276
277static status_t
278overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
279	const char *path, int mode)
280{
281	DO_LOG("create_symlink name: \"%s\"; path: \"%s\"; mode: %u\n", name, path,
282		mode);
283	OVERLAY_CALL(create_symlink, name, path, mode)
284	DO_LOG("create_symlink result: 0x%08lx\n", result);
285	return result;
286}
287
288
289static status_t
290overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
291	fs_vnode *target)
292{
293	DO_LOG("link name: \"%s\"; target: %p\n", name,
294		((fs_vnode *)target->private_node)->private_node);
295	OVERLAY_CALL(link, name, (fs_vnode *)target->private_node)
296	DO_LOG("link result: 0x%08lx\n", result);
297	return result;
298}
299
300
301static status_t
302overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
303{
304	DO_LOG("unlink name: \"%s\"\n", name);
305	OVERLAY_CALL(unlink, name)
306	DO_LOG("unlink result: 0x%08lx\n", result);
307	return result;
308}
309
310
311static status_t
312overlay_rename(fs_volume *volume, fs_vnode *vnode,
313	const char *fromName, fs_vnode *toDir, const char *toName)
314{
315	DO_LOG("rename from_name: \"%s\"; to_dir: %p; to_name: \"%s\"\n",
316		fromName, ((fs_vnode *)toDir->private_node)->private_node, toName);
317	OVERLAY_CALL(rename, fromName, (fs_vnode *)toDir->private_node, toName)
318	DO_LOG("rename result: 0x%08lx\n", result);
319	return result;
320}
321
322
323static status_t
324overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
325{
326	DO_LOG("access mode: %u\n", mode);
327	OVERLAY_CALL(access, mode)
328	DO_LOG("access result: 0x%08lx\n", result);
329	return result;
330}
331
332
333static status_t
334overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
335{
336	DO_LOG("read_stat stat: %p\n", stat);
337	OVERLAY_CALL(read_stat, stat)
338	if (result == B_OK) {
339		DO_LOG("read_stat result: 0x%08lx; stat(dev: %lu; ino: %llu; mode: %u;"
340			" uid: %u; gid %u; size: %llu)\n", result, stat->st_dev,
341			stat->st_ino, stat->st_mode, stat->st_uid, stat->st_gid,
342			stat->st_size);
343	} else
344		DO_LOG("read_stat result: 0x%08lx\n", result);
345	return result;
346}
347
348
349static status_t
350overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
351	uint32 statMask)
352{
353	DO_LOG("write_stat stat: %p; mask: %lu\n", stat, statMask);
354	OVERLAY_CALL(write_stat, stat, statMask)
355	DO_LOG("write_stat result: 0x%08lx\n", result);
356	return result;
357}
358
359
360static status_t
361overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
362	int openMode, int perms, void **cookie, ino_t *newVnodeID)
363{
364	DO_LOG("create name: \"%s\"; open_mode: %u; perms: %u\n", name, openMode,
365		perms);
366	OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID)
367	DO_LOG("create result: 0x%08lx; cookie: %p; new_vnode_id: %llu\n", result,
368		*cookie, *newVnodeID);
369	return result;
370}
371
372
373static status_t
374overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
375{
376	DO_LOG("open open_mode: %u\n", openMode);
377	OVERLAY_CALL(open, openMode, cookie)
378	DO_LOG("open result: 0x%08lx; cookie: %p\n", result, *cookie);
379	return result;
380}
381
382
383static status_t
384overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
385{
386	DO_LOG("close cookie %p\n", cookie);
387	OVERLAY_CALL(close, cookie)
388	DO_LOG("close result: 0x%08lx\n", result);
389	return result;
390}
391
392
393static status_t
394overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
395{
396	DO_LOG("free_cookie cookie %p\n", cookie);
397	OVERLAY_CALL(free_cookie, cookie)
398	DO_LOG("free_cookie result: 0x%08lx\n", result);
399	return result;
400}
401
402
403static status_t
404overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
405	void *buffer, size_t *length)
406{
407	DO_LOG("read cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie, pos,
408		buffer, *length);
409	OVERLAY_CALL(read, cookie, pos, buffer, length)
410	DO_LOG("read result: 0x%08lx; length: %lu\n", result, *length);
411	return result;
412}
413
414
415static status_t
416overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
417	const void *buffer, size_t *length)
418{
419	DO_LOG("write cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie,
420		pos, buffer, *length);
421	OVERLAY_CALL(write, cookie, pos, buffer, length)
422	DO_LOG("write result: 0x%08lx; length: %lu\n", result, *length);
423	return result;
424}
425
426
427static status_t
428overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
429	int perms)
430{
431	DO_LOG("create_dir name: \"%s\"; perms: %u\n", name, perms);
432	OVERLAY_CALL(create_dir, name, perms)
433	DO_LOG("create_dir result: 0x%08lx\n", result);
434	return result;
435}
436
437
438static status_t
439overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
440{
441	DO_LOG("remove_dir name: \"%s\"\n", name);
442	OVERLAY_CALL(remove_dir, name)
443	DO_LOG("remove_dir result: 0x%08lx\n", result);
444	return result;
445}
446
447
448static status_t
449overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
450{
451	DO_LOG("%s\n", "open_dir");
452	OVERLAY_CALL(open_dir, cookie)
453	DO_LOG("open_dir result: 0x%08lx; cookie: %p\n", result, *cookie);
454	return result;
455}
456
457
458static status_t
459overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
460{
461	DO_LOG("close_dir cookie: %p\n", cookie);
462	OVERLAY_CALL(close_dir, cookie)
463	DO_LOG("close_dir result: 0x%08lx\n", result);
464	return result;
465}
466
467
468static status_t
469overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
470{
471	DO_LOG("free_dir_cookie cookie: %p\n", cookie);
472	OVERLAY_CALL(free_dir_cookie, cookie)
473	DO_LOG("free_dir_cookie result: 0x%08lx\n", result);
474	return result;
475}
476
477
478static status_t
479overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
480	struct dirent *buffer, size_t bufferSize, uint32 *num)
481{
482	DO_LOG("read_dir cookie: %p; buffer: %p; buffer_size: %lu\n", cookie,
483		buffer, bufferSize);
484	OVERLAY_CALL(read_dir, cookie, buffer, bufferSize, num);
485	DO_LOG("read_dir result: 0x%08lx; num: %lu\n", result, *num);
486	return result;
487}
488
489
490static status_t
491overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
492{
493	DO_LOG("rewind_dir cookie: %p\n", cookie);
494	OVERLAY_CALL(rewind_dir, cookie)
495	DO_LOG("rewind_dir result: 0x%08lx\n", result);
496	return result;
497}
498
499
500static status_t
501overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
502{
503	DO_LOG("%s\n", "open_attr_dir");
504	OVERLAY_CALL(open_attr_dir, cookie)
505	DO_LOG("open_attr_dir result: 0x%08lx; cookie: %p\n", result, *cookie);
506	return result;
507}
508
509
510static status_t
511overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
512{
513	DO_LOG("close_attr_dir cookie: %p\n", cookie);
514	OVERLAY_CALL(close_attr_dir, cookie)
515	DO_LOG("close_attr_dir result: 0x%08lx\n", result);
516	return result;
517}
518
519
520static status_t
521overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
522{
523	DO_LOG("free_attr_dir_cookie cookie: %p\n", cookie);
524	OVERLAY_CALL(free_attr_dir_cookie, cookie)
525	DO_LOG("free_attr_dir_cookie result: 0x%08lx\n", result);
526	return result;
527}
528
529
530static status_t
531overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
532	struct dirent *buffer, size_t bufferSize, uint32 *num)
533{
534	DO_LOG("read_attr_dir cookie: %p; buffer: %p; buffer_size: %lu\n", cookie,
535		buffer, bufferSize);
536	OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num);
537	DO_LOG("read_attr_dir result: 0x%08lx; num: %lu\n", result, *num);
538	return result;
539}
540
541
542static status_t
543overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
544{
545	DO_LOG("rewind_attr_dir cookie: %p\n", cookie);
546	OVERLAY_CALL(rewind_attr_dir, cookie)
547	DO_LOG("rewind_attr_dir result: 0x%08lx\n", result);
548	return result;
549}
550
551
552static status_t
553overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
554	uint32 type, int openMode, void **cookie)
555{
556	DO_LOG("create_attr name: \"%s\"; type: 0x%08lx; open_mode: %u\n", name,
557		type, openMode);
558	OVERLAY_CALL(create_attr, name, type, openMode, cookie)
559	DO_LOG("create_attr result: 0x%08lx; cookie: %p\n", result, *cookie);
560	return result;
561}
562
563
564static status_t
565overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
566	int openMode, void **cookie)
567{
568	DO_LOG("open_attr name: \"%s\"; open_mode: %u\n", name, openMode);
569	OVERLAY_CALL(open_attr, name, openMode, cookie)
570	DO_LOG("open_attr result: 0x%08lx; cookie: %p\n", result, *cookie);
571	return result;
572}
573
574
575static status_t
576overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie)
577{
578	DO_LOG("close_attr cookie: %p\n", cookie);
579	OVERLAY_CALL(close_attr, cookie)
580	DO_LOG("close_attr result: 0x%08lx\n", result);
581	return result;
582}
583
584
585static status_t
586overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
587{
588	DO_LOG("free_attr_cookie cookie: %p\n", cookie);
589	OVERLAY_CALL(free_attr_cookie, cookie)
590	DO_LOG("free_attr_cookie result: 0x%08lx\n", result);
591	return result;
592}
593
594
595static status_t
596overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
597	void *buffer, size_t *length)
598{
599	DO_LOG("read_attr cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie,
600		pos, buffer, *length);
601	OVERLAY_CALL(read_attr, cookie, pos, buffer, length)
602	DO_LOG("read_attr result: 0x%08lx; length: %lu\n", result, *length);
603	return result;
604}
605
606
607static status_t
608overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
609	const void *buffer, size_t *length)
610{
611	DO_LOG("write_attr cookie: %p; pos: %lld; buffer: %p; length: %lu\n",
612		cookie, pos, buffer, *length);
613	OVERLAY_CALL(write_attr, cookie, pos, buffer, length)
614	DO_LOG("write_attr result: 0x%08lx; length: %lu\n", result, *length);
615	return result;
616}
617
618
619static status_t
620overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
621	struct stat *stat)
622{
623	DO_LOG("read_attr_stat cookie: %p; stat: %p\n", cookie, stat);
624	OVERLAY_CALL(read_attr_stat, cookie, stat)
625	if (result == B_OK) {
626		DO_LOG("read_attr_stat result: 0x%08lx; stat(dev: %lu; ino: %llu;"
627			" mode: %u; uid: %u; gid %u; size: %llu; type: 0x%08lx)\n", result,
628			stat->st_dev, stat->st_ino, stat->st_mode, stat->st_uid,
629			stat->st_gid, stat->st_size, stat->st_type);
630	} else
631		DO_LOG("read_attr_stat result: 0x%08lx\n", result);
632	return result;
633}
634
635
636static status_t
637overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
638	const struct stat *stat, int statMask)
639{
640	DO_LOG("write_attr_stat cookie: %p; stat: %p; mask: %u\n", cookie, stat,
641		statMask);
642	OVERLAY_CALL(write_attr_stat, cookie, stat, statMask)
643	DO_LOG("write_attr_stat result: 0x%08lx\n", result);
644	return result;
645}
646
647
648static status_t
649overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
650	const char *fromName, fs_vnode *toVnode, const char *toName)
651{
652	DO_LOG("rename_attr from_name: \"%s\"; to_vnode: %p; to_name: \"%s\"\n",
653		fromName, ((fs_vnode *)toVnode->private_node)->private_node, toName);
654	OVERLAY_CALL(rename_attr, fromName, (fs_vnode *)toVnode->private_node,
655		toName)
656	DO_LOG("rename_attr result: 0x%08lx\n", result);
657	return result;
658}
659
660
661static status_t
662overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
663{
664	DO_LOG("remove_attr name: \"%s\"\n", name);
665	OVERLAY_CALL(remove_attr, name)
666	DO_LOG("remove_attr result: 0x%08lx\n", result);
667	return result;
668}
669
670
671static status_t
672overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
673	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
674	fs_vnode *_superVnode, ino_t *nodeID)
675{
676	DO_LOG("create_special_node name: \"%s\"; sub_vnode: %p; mode: %u;"
677		" flags: %lu\n", name, subVnode->private_node, mode, flags);
678	OVERLAY_CALL(create_special_node, name, (fs_vnode *)subVnode->private_node,
679		mode, flags, _superVnode, nodeID)
680	DO_LOG("create_special_node result: 0x%08lx; super_vnode: %p;"
681		" node_id: %llu\n", result, _superVnode->private_node, *nodeID);
682	return result;
683}
684
685
686static fs_vnode_ops sOverlayVnodeOps = {
687	&overlay_lookup,
688	&overlay_get_vnode_name,
689
690	&overlay_put_vnode,
691	&overlay_remove_vnode,
692
693	&overlay_can_page,
694	&overlay_read_pages,
695	&overlay_write_pages,
696
697	&overlay_io,
698	&overlay_cancel_io,
699
700	&overlay_get_file_map,
701
702	/* common */
703	&overlay_ioctl,
704	&overlay_set_flags,
705	&overlay_select,
706	&overlay_deselect,
707	&overlay_fsync,
708
709	&overlay_read_symlink,
710	&overlay_create_symlink,
711	&overlay_link,
712	&overlay_unlink,
713	&overlay_rename,
714
715	&overlay_access,
716	&overlay_read_stat,
717	&overlay_write_stat,
718	NULL,	// fs_preallocate
719
720	/* file */
721	&overlay_create,
722	&overlay_open,
723	&overlay_close,
724	&overlay_free_cookie,
725	&overlay_read,
726	&overlay_write,
727
728	/* directory */
729	&overlay_create_dir,
730	&overlay_remove_dir,
731	&overlay_open_dir,
732	&overlay_close_dir,
733	&overlay_free_dir_cookie,
734	&overlay_read_dir,
735	&overlay_rewind_dir,
736
737	/* attribute directory operations */
738	&overlay_open_attr_dir,
739	&overlay_close_attr_dir,
740	&overlay_free_attr_dir_cookie,
741	&overlay_read_attr_dir,
742	&overlay_rewind_attr_dir,
743
744	/* attribute operations */
745	&overlay_create_attr,
746	&overlay_open_attr,
747	&overlay_close_attr,
748	&overlay_free_attr_cookie,
749	&overlay_read_attr,
750	&overlay_write_attr,
751
752	&overlay_read_attr_stat,
753	&overlay_write_attr_stat,
754	&overlay_rename_attr,
755	&overlay_remove_attr,
756
757	/* support for node and FS layers */
758	&overlay_create_special_node,
759	&overlay_get_super_vnode
760};
761
762
763//	#pragma mark - volume ops
764
765
766#define DO_VOLUME_LOG(format, args...) \
767	{ \
768		char _printBuffer[256]; \
769		int _printSize = snprintf(_printBuffer, sizeof(_printBuffer), \
770			"%llu %ld %p: " format, system_time(), find_thread(NULL), \
771			volume->super_volume, args); \
772		if ((unsigned int)_printSize > sizeof(_printBuffer)) { \
773			_printBuffer[sizeof(_printBuffer) - 1] = '\n'; \
774			_printSize = sizeof(_printBuffer); \
775		} \
776		write((int)volume->private_volume, _printBuffer, _printSize); \
777	}
778
779#define OVERLAY_VOLUME_CALL(op, params...) \
780	status_t result = B_UNSUPPORTED; \
781	if (volume->super_volume->ops->op != NULL) \
782		result = volume->super_volume->ops->op(volume->super_volume, params); \
783
784
785static status_t
786overlay_unmount(fs_volume *volume)
787{
788	if (volume->super_volume != NULL
789		&& volume->super_volume->ops != NULL
790		&& volume->super_volume->ops->unmount != NULL)
791		volume->super_volume->ops->unmount(volume->super_volume);
792
793	close((int)volume->private_volume);
794	return B_OK;
795}
796
797
798static status_t
799overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
800{
801	DO_VOLUME_LOG("%s\n", "read_fs_info");
802	OVERLAY_VOLUME_CALL(read_fs_info, info)
803	DO_VOLUME_LOG("read_fs_info result: 0x%08lx; info(dev: %lu; root: %llu;"
804		" flags: %lu; block_size: %lld; io_size: %lld; total_blocks: %lld;"
805		" free_blocks: %lld; total_nodes: %lld; free_nodes: %lld;"
806		" device_name: \"%s\"; volume_name: \"%s\"; fsh_name: \"%s\")\n",
807		result, info->dev, info->root, info->flags, info->block_size,
808		info->io_size, info->total_blocks, info->free_blocks,
809		info->total_nodes, info->free_nodes, info->device_name,
810		info->volume_name, info->fsh_name);
811	return result;
812}
813
814
815static status_t
816overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
817	uint32 mask)
818{
819	DO_VOLUME_LOG("write_fs_info info: %p; mask: %lu\n", info, mask);
820	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
821	DO_VOLUME_LOG("write_fs_info result: 0x%08lx\n", result);
822	return result;
823}
824
825
826static status_t
827overlay_sync(fs_volume *volume)
828{
829	DO_VOLUME_LOG("%s\n", "sync");
830	status_t result = B_UNSUPPORTED;
831	if (volume->super_volume->ops->sync != NULL)
832		result = volume->super_volume->ops->sync(volume->super_volume);
833	DO_VOLUME_LOG("sync result: 0x%08lx\n", result);
834	return result;
835}
836
837
838static status_t
839overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *type,
840	uint32 *flags, bool reenter)
841{
842	DO_VOLUME_LOG("get_vnode id: %llu; vnode: %p; type*: %p; flags*: %p;"
843		" reenter: %d\n", id, vnode, type, flags, reenter);
844
845	if (volume->super_volume->ops->get_vnode == NULL) {
846		DO_VOLUME_LOG("get_vnode %s\n", "not supported");
847		return B_UNSUPPORTED;
848	}
849
850	fs_vnode *superVnode = new(std::nothrow) fs_vnode;
851	if (superVnode == NULL) {
852		DO_VOLUME_LOG("get_vnode %s\n", "no memory");
853		return B_NO_MEMORY;
854	}
855
856	status_t result = volume->super_volume->ops->get_vnode(volume->super_volume,
857		id, superVnode, type, flags, reenter);
858	if (result != B_OK) {
859		DO_VOLUME_LOG("get_vnode result: 0x%08lx\n", result);
860		delete superVnode;
861		return result;
862	}
863
864	vnode->private_node = superVnode;
865	vnode->ops = &sOverlayVnodeOps;
866
867	DO_VOLUME_LOG("get_vnode result: 0x%08lx; super_vnode: %p\n", result,
868		superVnode->private_node);
869	return B_OK;
870}
871
872
873static status_t
874overlay_open_index_dir(fs_volume *volume, void **cookie)
875{
876	DO_VOLUME_LOG("%s\n", "open_index_dir");
877	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
878	DO_VOLUME_LOG("open_index_dir result: 0x%08lx; cookie: %p\n", result,
879		*cookie);
880	return result;
881}
882
883
884static status_t
885overlay_close_index_dir(fs_volume *volume, void *cookie)
886{
887	DO_VOLUME_LOG("close_index_dir cookie: %p\n", cookie);
888	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
889	DO_VOLUME_LOG("close_index_dir result: 0x%08lx\n", result);
890	return result;
891}
892
893
894static status_t
895overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
896{
897	DO_VOLUME_LOG("free_index_dir_cookie cookie: %p\n", cookie);
898	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
899	DO_VOLUME_LOG("free_index_dir_cookie result: 0x%08lx\n", result);
900	return result;
901}
902
903
904static status_t
905overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
906	size_t bufferSize, uint32 *num)
907{
908	DO_VOLUME_LOG("read_index_dir cookie: %p; buffer: %p; buffer_size: %lu\n",
909		cookie, buffer, bufferSize);
910	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, num)
911	DO_VOLUME_LOG("read_index_dir result: 0x%08lx; num: %lu\n", result, *num);
912	return result;
913}
914
915
916static status_t
917overlay_rewind_index_dir(fs_volume *volume, void *cookie)
918{
919	DO_VOLUME_LOG("rewind_index_dir cookie: %p\n", cookie);
920	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
921	DO_VOLUME_LOG("rewind_index_dir result: 0x%08lx\n", result);
922	return result;
923}
924
925
926static status_t
927overlay_create_index(fs_volume *volume, const char *name, uint32 type,
928	uint32 flags)
929{
930	DO_VOLUME_LOG("create_index name: \"%s\"; type: %lu; flags: %lu\n", name,
931		type, flags);
932	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
933	DO_VOLUME_LOG("create_index result: 0x%08lx\n", result);
934	return result;
935}
936
937
938static status_t
939overlay_remove_index(fs_volume *volume, const char *name)
940{
941	DO_VOLUME_LOG("remove_index name: \"%s\"\n", name);
942	OVERLAY_VOLUME_CALL(remove_index, name)
943	DO_VOLUME_LOG("remove_index result: 0x%08lx\n", result);
944	return result;
945}
946
947
948static status_t
949overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
950{
951	DO_VOLUME_LOG("read_index_stat name: \"%s\"; stat: %p\n", name, stat);
952	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
953	if (result == B_OK) {
954		DO_VOLUME_LOG("read_index_stat result: 0x%08lx; stat(dev: %lu;"
955			" ino: %llu; mode: %u; uid: %u; gid %u; size: %llu;"
956			" type: 0x%08lx)\n", result, stat->st_dev, stat->st_ino,
957			stat->st_mode, stat->st_uid, stat->st_gid, stat->st_size,
958			stat->st_type);
959	} else
960		DO_VOLUME_LOG("read_index_stat result: 0x%08lx\n", result);
961	return result;
962}
963
964
965static status_t
966overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
967	port_id port, uint32 token, void **cookie)
968{
969	DO_VOLUME_LOG("open_query query: \"%s\"; flags: %lu; port: %ld;"
970		" token: %lu\n", query, flags, port, token);
971	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, cookie)
972	DO_VOLUME_LOG("open_query result: 0x%08lx; cookie: %p\n", result, *cookie);
973	return result;
974}
975
976
977static status_t
978overlay_close_query(fs_volume *volume, void *cookie)
979{
980	DO_VOLUME_LOG("close_query cookie: %p\n", cookie);
981	OVERLAY_VOLUME_CALL(close_query, cookie)
982	DO_VOLUME_LOG("close_query result: 0x%08lx\n", result);
983	return result;
984}
985
986
987static status_t
988overlay_free_query_cookie(fs_volume *volume, void *cookie)
989{
990	DO_VOLUME_LOG("free_query_cookie cookie: %p\n", cookie);
991	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
992	DO_VOLUME_LOG("free_query_cookie result: 0x%08lx\n", result);
993	return result;
994}
995
996
997static status_t
998overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
999	size_t bufferSize, uint32 *num)
1000{
1001	DO_VOLUME_LOG("read_query cookie: %p; buffer: %p; buffer_size: %lu\n",
1002		cookie, buffer, bufferSize);
1003	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, num)
1004	DO_VOLUME_LOG("read_query result: 0x%08lx; num: %lu\n", result, *num);
1005	return result;
1006}
1007
1008
1009static status_t
1010overlay_rewind_query(fs_volume *volume, void *cookie)
1011{
1012	DO_VOLUME_LOG("rewind_query cookie: %p\n", cookie);
1013	OVERLAY_VOLUME_CALL(rewind_query, cookie)
1014	DO_VOLUME_LOG("rewind_query result: 0x%08lx\n", result);
1015	return result;
1016}
1017
1018
1019static status_t
1020overlay_all_layers_mounted(fs_volume *volume)
1021{
1022	return B_OK;
1023}
1024
1025
1026static status_t
1027overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
1028{
1029	fs_vnode *superVnode = new(std::nothrow) fs_vnode;
1030	if (superVnode == NULL)
1031		return B_NO_MEMORY;
1032
1033	*superVnode = *vnode;
1034	vnode->private_node = superVnode;
1035	vnode->ops = &sOverlayVnodeOps;
1036	return B_OK;
1037}
1038
1039
1040static status_t
1041overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
1042{
1043	delete (fs_vnode *)vnode->private_node;
1044	return B_OK;
1045}
1046
1047
1048static fs_volume_ops sOverlayVolumeOps = {
1049	&overlay_unmount,
1050
1051	&overlay_read_fs_info,
1052	&overlay_write_fs_info,
1053	&overlay_sync,
1054
1055	&overlay_get_vnode,
1056	&overlay_open_index_dir,
1057	&overlay_close_index_dir,
1058	&overlay_free_index_dir_cookie,
1059	&overlay_read_index_dir,
1060	&overlay_rewind_index_dir,
1061
1062	&overlay_create_index,
1063	&overlay_remove_index,
1064	&overlay_read_index_stat,
1065
1066	&overlay_open_query,
1067	&overlay_close_query,
1068	&overlay_free_query_cookie,
1069	&overlay_read_query,
1070	&overlay_rewind_query,
1071
1072	&overlay_all_layers_mounted,
1073	&overlay_create_sub_vnode,
1074	&overlay_delete_sub_vnode
1075};
1076
1077
1078//	#pragma mark - filesystem module
1079
1080
1081static status_t
1082overlay_mount(fs_volume *volume, const char *device, uint32 flags,
1083	const char *args, ino_t *rootID)
1084{
1085	char filename[256];
1086	snprintf(filename, sizeof(filename), "%s%s", kLogFilePrefix, device);
1087	filename[sizeof(filename) - 1] = 0;
1088
1089	int filenameLength = strlen(filename);
1090	for (int i = strlen(kLogFilePrefix); i < filenameLength; i++) {
1091		if (filename[i] == '/')
1092			filename[i] = '_';
1093	}
1094
1095	int fd = creat(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1096	if (fd < 0)
1097		return errno;
1098
1099	volume->private_volume = (void *)fd;
1100	volume->ops = &sOverlayVolumeOps;
1101	return B_OK;
1102}
1103
1104
1105static status_t
1106overlay_std_ops(int32 op, ...)
1107{
1108	switch (op) {
1109		case B_MODULE_INIT:
1110		case B_MODULE_UNINIT:
1111			return B_OK;
1112		default:
1113			return B_ERROR;
1114	}
1115}
1116
1117
1118static file_system_module_info sOverlayFileSystem = {
1119	{
1120		"file_systems/log_overlay"B_CURRENT_FS_API_VERSION,
1121		0,
1122		overlay_std_ops,
1123	},
1124
1125	"log_overlay",						// short_name
1126	"Logging Overlay File System",		// pretty_name
1127	0,									// DDM flags
1128
1129	// scanning
1130	NULL, // identify_partition
1131	NULL, // scan_partition
1132	NULL, // free_identify_partition_cookie
1133	NULL, // free_partition_content_cookie
1134
1135	// general operations
1136	&overlay_mount,
1137
1138	// capability querying
1139	NULL, // get_supported_operations
1140
1141	NULL, // validate_resize
1142	NULL, // validate_move
1143	NULL, // validate_set_content_name
1144	NULL, // validate_set_content_parameters
1145	NULL, // validate_initialize
1146
1147	// shadow partition modification
1148	NULL, // shadow_changed
1149
1150	// writing
1151	NULL, // defragment
1152	NULL, // repair
1153	NULL, // resize
1154	NULL, // move
1155	NULL, // set_content_name
1156	NULL, // set_content_parameters
1157	NULL // initialize
1158};
1159
1160module_info *modules[] = {
1161	(module_info *)&sOverlayFileSystem,
1162	NULL,
1163};
1164