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