1/*
2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Node.h"
8
9#include <string.h>
10#include <sys/time.h>
11#include <unistd.h>
12
13#include "Block.h"
14#include "DebugSupport.h"
15#include "Volume.h"
16
17
18static inline uint64
19current_time_nanos()
20{
21	timeval time;
22	gettimeofday(&time, NULL);
23
24	return (uint64)time.tv_sec * 1000000000 + (uint64)time.tv_usec * 1000;
25}
26
27
28Node::Node(Volume* volume, uint64 blockIndex, const checksumfs_node& nodeData)
29	:
30	fVolume(volume),
31	fBlockIndex(blockIndex),
32	fNode(nodeData),
33	fNodeDataDirty(false)
34{
35	_Init();
36
37	fAccessedTime = ModificationTime();
38}
39
40
41Node::Node(Volume* volume, mode_t mode)
42	:
43	fVolume(volume),
44	fBlockIndex(0),
45	fNodeDataDirty(true)
46{
47	_Init();
48
49	memset(&fNode, 0, sizeof(fNode));
50
51	fNode.mode = mode;
52
53	// set user/group
54	fNode.uid = geteuid();
55	fNode.gid = getegid();
56
57	// set the times
58	timeval time;
59	gettimeofday(&time, NULL);
60
61	fAccessedTime = current_time_nanos();
62	fNode.creationTime = fAccessedTime;
63	fNode.modificationTime = fAccessedTime;
64	fNode.changeTime = fAccessedTime;
65}
66
67
68Node::~Node()
69{
70	rw_lock_destroy(&fLock);
71}
72
73
74void
75Node::SetBlockIndex(uint64 blockIndex)
76{
77	fBlockIndex = blockIndex;
78}
79
80
81status_t
82Node::InitForVFS()
83{
84	return B_OK;
85}
86
87
88void
89Node::DeletingNode()
90{
91	// delete the node's attribute directory
92	if (AttributeDirectory() == 0)
93		return;
94
95	Node* attributeDirectory;
96	if (fVolume->GetNode(AttributeDirectory(), attributeDirectory) == B_OK) {
97		fVolume->RemoveNode(attributeDirectory);
98		fVolume->PutNode(attributeDirectory);
99	} else {
100		ERROR("Failed to get attribute directory (at %" B_PRIu64 ") for "
101			"deleted node at %" B_PRIu64 "\n", AttributeDirectory(),
102			BlockIndex());
103	}
104}
105
106
107status_t
108Node::Resize(uint64 newSize, bool fillWithZeroes, Transaction& transaction)
109{
110	RETURN_ERROR(B_BAD_VALUE);
111}
112
113
114status_t
115Node::Read(off_t pos, void* buffer, size_t size, size_t& _bytesRead)
116{
117	RETURN_ERROR(B_BAD_VALUE);
118}
119
120
121status_t
122Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten,
123	bool& _sizeChanged)
124{
125	RETURN_ERROR(B_BAD_VALUE);
126}
127
128
129status_t
130Node::Sync()
131{
132	return B_OK;
133}
134
135
136void
137Node::SetMode(uint32 mode)
138{
139	ASSERT((mode & S_IFMT) == (Mode() & S_IFMT));
140
141	fNode.mode = mode;
142	fNodeDataDirty = true;
143}
144
145
146void
147Node::SetAttributeType(uint32 type)
148{
149	fNode.attributeType = type;
150	fNodeDataDirty = true;
151}
152
153
154void
155Node::SetParentDirectory(uint32 blockIndex)
156{
157	fNode.parentDirectory = blockIndex;
158	fNodeDataDirty = true;
159}
160
161
162void
163Node::SetAttributeDirectory(uint32 blockIndex)
164{
165	fNode.attributeDirectory = blockIndex;
166	fNodeDataDirty = true;
167}
168
169
170void
171Node::SetHardLinks(uint32 value)
172{
173	fNode.hardLinks = value;
174	fNodeDataDirty = true;
175}
176
177
178void
179Node::SetUID(uint32 uid)
180{
181	fNode.uid = uid;
182	fNodeDataDirty = true;
183}
184
185
186void
187Node::SetGID(uint32 gid)
188{
189	fNode.gid = gid;
190	fNodeDataDirty = true;
191}
192
193
194void
195Node::SetSize(uint64 size)
196{
197	fNode.size = size;
198	fNodeDataDirty = true;
199}
200
201
202void
203Node::SetAccessedTime(uint64 time)
204{
205	fAccessedTime = time;
206}
207
208
209void
210Node::SetCreationTime(uint64 time)
211{
212	fNode.creationTime = time;
213	fNodeDataDirty = true;
214}
215
216
217void
218Node::SetModificationTime(uint64 time)
219{
220	fNode.modificationTime = time;
221	fNodeDataDirty = true;
222}
223
224
225void
226Node::SetChangeTime(uint64 time)
227{
228	fNode.changeTime = time;
229	fNodeDataDirty = true;
230}
231
232
233void
234Node::Touched(int32 mode)
235{
236	fAccessedTime = current_time_nanos();
237
238	switch (mode) {
239		default:
240		case NODE_MODIFIED:
241			fNode.modificationTime = fAccessedTime;
242		case NODE_STAT_CHANGED:
243			fNode.changeTime = fAccessedTime;
244		case NODE_ACCESSED:
245			break;
246	}
247}
248
249
250void
251Node::RevertNodeData(const checksumfs_node& nodeData)
252{
253	fNode = nodeData;
254	fNodeDataDirty = false;
255}
256
257
258status_t
259Node::Flush(Transaction& transaction)
260{
261	if (!fNodeDataDirty)
262		return B_OK;
263
264	Block block;
265	if (!block.GetWritable(fVolume, fBlockIndex, transaction))
266		return B_ERROR;
267
268	memcpy(block.Data(), &fNode, sizeof(fNode));
269
270	fNodeDataDirty = false;
271	return B_OK;
272}
273
274
275void
276Node::_Init()
277{
278	rw_lock_init(&fLock, "checkfs node");
279}
280