The Pedigree Project 0.1
UnixFilesystem.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "UnixFilesystem.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/process/Mutex.h"
23#include "pedigree/kernel/process/Process.h"
24#include "pedigree/kernel/process/Thread.h"
25#include "pedigree/kernel/processor/Processor.h"
26#include "pedigree/kernel/syscallError.h"
27
28#include <errno.h>
29
30#include "modules/subsys/posix/FileDescriptor.h"
31#include "modules/subsys/posix/logging.h"
32#include "modules/system/vfs/VFS.h"
33
34String UnixFilesystem::m_VolumeLabel("unix");
35Mutex UnixFilesystem::m_NamespaceLock;
36Mutex UnixSocket::m_ConnectionLock;
37Mutex SocketRights::m_InFlightLock;
38size_t SocketRights::m_InFlight = 0;
39
40SocketRights::SocketRights(size_t reservation)
41 : m_Descriptors(reservation), m_Reservation(reservation) {}
42
43SocketRights::~SocketRights() {
44 for (auto descriptor : m_Descriptors) {
45 delete descriptor;
46 }
47 m_Descriptors.clear(true);
48
49 LockGuard<Mutex> guard(m_InFlightLock);
50 assert(m_InFlight >= m_Reservation);
51 m_InFlight -= m_Reservation;
52}
53
54bool SocketRights::create(size_t descriptorCount, SharedPointer<SocketRights>& rights) {
55 rights.reset();
56 if (!descriptorCount || descriptorCount > MaximumDescriptors) {
57 return false;
58 }
59
60 {
61 LockGuard<Mutex> guard(m_InFlightLock);
62 if (descriptorCount > MaximumInFlight - m_InFlight) {
63 return false;
64 }
65 m_InFlight += descriptorCount;
66 }
67
68 rights.reset(new SocketRights(descriptorCount));
69 return true;
70}
71
72void SocketRights::append(FileDescriptor* descriptor) {
73 assert(descriptor);
74 assert(m_Descriptors.count() < m_Reservation);
75 m_Descriptors.pushBack(descriptor);
76}
77
78size_t SocketRights::count() const {
79 return m_Descriptors.count();
80}
81
82FileDescriptor* SocketRights::descriptor(size_t index) const {
83 return m_Descriptors[index];
84}
85
86#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
87size_t SocketRights::inFlightForTest() {
88 LockGuard<Mutex> guard(m_InFlightLock);
89 return m_InFlight;
90}
91#endif
92
93namespace {
94#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
95UnixStreamControlLockHook g_UnixStreamControlLockHook = nullptr;
96
97void invokeUnixStreamControlLockHook() {
98 UnixStreamControlLockHook hook =
99 __atomic_exchange_n(&g_UnixStreamControlLockHook,
100 static_cast<UnixStreamControlLockHook>(nullptr), __ATOMIC_ACQ_REL);
101 if (hook) {
102 hook();
103 }
104}
105#endif
106
107bool currentThreadWasInterrupted() {
108#if defined(PEDIGREE_EXTERNAL_SOURCE)
109 return false;
110#else
111 Thread* thread = Processor::information().getCurrentThread();
112 return thread && thread->getInterruptionReason() == Thread::InterruptedBySignal;
113#endif
114}
115
116void captureStreamInterruption(bool block, bool* interrupted) {
117 if (block && interrupted && currentThreadWasInterrupted()) {
118 *interrupted = true;
119 }
120}
121
122enum class StreamSerializationWait {
123 Nonblocking,
124 Interruptible,
125};
126
127class StreamSerializationGuard {
128 public:
129#if defined(PEDIGREE_EXTERNAL_SOURCE)
130 StreamSerializationGuard(UnixStreamSerializationGate& mutex, StreamSerializationWait)
131 : m_Mutex(mutex), m_Acquired(m_Mutex.acquire()) {}
132#else
133 StreamSerializationGuard(Semaphore& semaphore, StreamSerializationWait wait)
134 : m_TerminationDeferral(true), m_Semaphore(semaphore), m_Acquired(false) {
135 if (wait == StreamSerializationWait::Nonblocking) {
136 m_Acquired = m_Semaphore.tryAcquire();
137 } else {
138 Semaphore::SemaphoreError error = Semaphore::NoError;
139 m_Acquired = m_Semaphore.acquireWithError(1, 0, 0, error);
140 }
141
142 if (!m_Acquired) {
143 m_TerminationDeferral = TerminationDeferral(false);
144 }
145 }
146#endif
147
148 ~StreamSerializationGuard() {
149 if (m_Acquired) {
150#if defined(PEDIGREE_EXTERNAL_SOURCE)
151 m_Mutex.release();
152#else
153 m_Semaphore.release();
154#endif
155 }
156 }
157
158 explicit operator bool() const {
159 return m_Acquired;
160 }
161
162 private:
163#if defined(PEDIGREE_EXTERNAL_SOURCE)
165#else
166 TerminationDeferral m_TerminationDeferral;
167 Semaphore& m_Semaphore;
168#endif
169 bool m_Acquired;
170};
171} // namespace
172
173#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
174void setUnixStreamControlLockHookForTest(UnixStreamControlLockHook hook) {
175 __atomic_store_n(&g_UnixStreamControlLockHook, hook, __ATOMIC_RELEASE);
176}
177#endif
178
179UnixSocketConnection::Stream::ControlGuard::ControlGuard(Stream& stream)
180 : m_Stream(stream), m_Guard(stream.m_ControlLock) {
181#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
182 invokeUnixStreamControlLockHook();
183#endif
184}
185
186UnixSocketConnection::Stream::ControlGuard::~ControlGuard() {
187 m_Stream.discardControlsIfRequested();
188 m_Stream.m_ControlLock.release();
189 m_Guard.disown();
190
191 // A handler can run after the final check above but before the unlock. If
192 // it requested a drain in that window, finish it after releasing the lock;
193 // any later handler observes an unowned mutex and drains synchronously.
194 if (m_Stream.m_DiscardControlsRequested) {
195 ControlGuard cleanupGuard(m_Stream);
196 }
197}
198
199UnixSocketConnection::Stream::Stream(bool packets)
200 : m_Packets(packets),
201 m_Records(MAX_UNIX_PACKET_BACKLOG * sizeof(uintptr_t)),
202 m_PendingPackets(),
203 m_Bytes(MAX_UNIX_STREAM_QUEUE),
204#if defined(PEDIGREE_EXTERNAL_SOURCE)
205 m_SendLock(),
206 m_ReceiveLock(),
207#else
208 m_SendLock(1, true),
209 m_ReceiveLock(1, true),
210#endif
211 m_ControlLock(),
212 m_DiscardControlsRequested(false),
213 m_Controls(),
214 m_BytesWritten(0),
215 m_BytesRead(0) {
216}
217
218UnixSocketConnection::Stream::~Stream() {
219 LockGuard<Mutex> guard(m_ControlLock);
220 discardControls();
221 m_DiscardControlsRequested = false;
222}
223
224size_t UnixSocketConnection::Stream::write(const uint8_t* buffer, size_t count, bool block,
225 const SharedPointer<SocketRights>& rights,
226 bool* interrupted) {
227 struct iovec vector = {const_cast<uint8_t*>(buffer), count};
228 return writeVectors(&vector, 1, block, rights, interrupted);
229}
230
231size_t UnixSocketConnection::Stream::writeVectors(const struct iovec* vectors, size_t vectorCount,
232 bool block,
233 const SharedPointer<SocketRights>& rights,
234 bool* interrupted) {
235 if (interrupted) {
236 *interrupted = false;
237 }
238
239 size_t firstVector = 0;
240 while (firstVector < vectorCount && !vectors[firstVector].iov_len) {
241 ++firstVector;
242 }
243 if (firstVector == vectorCount) {
244 return 0;
245 }
246
247 Control* pendingControl = rights ? new Control(0, rights) : nullptr;
248 StreamSerializationGuard sendGuard(m_SendLock, block ? StreamSerializationWait::Interruptible
249 : StreamSerializationWait::Nonblocking);
250 if (!sendGuard) {
251 captureStreamInterruption(block, interrupted);
252 delete pendingControl;
253 return 0;
254 }
255 size_t written = 0;
256 size_t firstOffset = 0;
257
258 if (pendingControl) {
259 if (!m_Bytes.canWrite(block)) {
260 captureStreamInterruption(block, interrupted);
261 delete pendingControl;
262 return 0;
263 }
264
265 ControlGuard controlGuard(*this);
266 const uint8_t* first = reinterpret_cast<const uint8_t*>(vectors[firstVector].iov_base);
267 if (m_Bytes.write(first, 1, block) != 1) {
268 captureStreamInterruption(block, interrupted);
269 delete pendingControl;
270 return 0;
271 }
272
273 pendingControl->byteOffset = m_BytesWritten;
274 m_Controls.pushBack(pendingControl);
275 ++m_BytesWritten;
276 ++written;
277 firstOffset = 1;
278 }
279
280 for (size_t i = firstVector; i < vectorCount; ++i) {
281 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(vectors[i].iov_base);
282 const size_t count = vectors[i].iov_len;
283 const size_t offset = i == firstVector ? firstOffset : 0;
284 if (offset >= count) {
285 continue;
286 }
287
288 const size_t tail = m_Bytes.write(buffer + offset, count - offset, block);
289 if (tail) {
290 ControlGuard controlGuard(*this);
291 m_BytesWritten += tail;
292 written += tail;
293 }
294 if (tail < count - offset) {
295 captureStreamInterruption(block, interrupted);
296 break;
297 }
298 }
299
300 return written;
301}
302
303size_t UnixSocketConnection::Stream::read(uint8_t* buffer, size_t count, bool block,
304 SharedPointer<SocketRights>* rights, bool* interrupted) {
305 struct iovec vector = {buffer, count};
306 return readVectors(&vector, 1, block, rights, interrupted);
307}
308
309size_t UnixSocketConnection::Stream::readVectors(struct iovec* vectors, size_t vectorCount,
310 bool block, SharedPointer<SocketRights>* rights,
311 bool* interrupted) {
312 if (interrupted) {
313 *interrupted = false;
314 }
315 if (rights) {
316 rights->reset();
317 }
318
319 StreamSerializationGuard receiveGuard(m_ReceiveLock, block
320 ? StreamSerializationWait::Interruptible
321 : StreamSerializationWait::Nonblocking);
322 if (!receiveGuard) {
323 captureStreamInterruption(block, interrupted);
324 return 0;
325 }
326 size_t totalRead = 0;
327 bool canBlock = block;
328 for (size_t i = 0; i < vectorCount; ++i) {
329 uint8_t* buffer = reinterpret_cast<uint8_t*>(vectors[i].iov_base);
330 size_t count = vectors[i].iov_len;
331 if (!count) {
332 continue;
333 }
334
335 if (!m_Bytes.canRead(canBlock)) {
336 captureStreamInterruption(canBlock, interrupted);
337 break;
338 }
339
340 ControlGuard controlGuard(*this);
341 while (m_Controls.count()) {
342 Control* stale = *m_Controls.begin();
343 if (stale->byteOffset >= m_BytesRead) {
344 break;
345 }
346 delete m_Controls.popFront();
347 }
348
349 size_t amount = count;
350 if (rights && m_Controls.count()) {
351 Control* next = *m_Controls.begin();
352 const uint64_t distance = next->byteOffset - m_BytesRead;
353 if (distance < amount) {
354 amount = static_cast<size_t>(distance + 1);
355 }
356 }
357
358 const size_t bytesRead = m_Bytes.read(buffer, amount, canBlock);
359 if (bytesRead < amount) {
360 captureStreamInterruption(canBlock, interrupted);
361 }
362 m_BytesRead += bytesRead;
363 bool consumedControl = false;
364 while (bytesRead && m_Controls.count()) {
365 Control* crossed = *m_Controls.begin();
366 if (crossed->byteOffset >= m_BytesRead) {
367 break;
368 }
369 crossed = m_Controls.popFront();
370 if (rights) {
371 *rights = crossed->rights;
372 consumedControl = true;
373 }
374 delete crossed;
375 if (rights) {
376 break;
377 }
378 }
379
380 totalRead += bytesRead;
381 canBlock = false;
382 if (consumedControl || bytesRead < amount) {
383 break;
384 }
385 }
386
387 return totalRead;
388}
389
390bool UnixSocketConnection::Stream::writePacket(const uint8_t* buffer, size_t count, bool block,
391 const SharedPointer<SocketRights>& rights,
392 bool* interrupted) {
393 if (interrupted) {
394 *interrupted = false;
395 }
396 StreamSerializationGuard sendGuard(m_SendLock, block ? StreamSerializationWait::Interruptible
397 : StreamSerializationWait::Nonblocking);
398 if (!sendGuard || !m_Records.canWrite(block)) {
399 captureStreamInterruption(block, interrupted);
400 return false;
401 }
402
403 Packet* packet = new Packet();
404 packet->length = count;
405 packet->rights = rights;
406 if (count) {
407 packet->bytes = new uint8_t[count];
408 MemoryCopy(packet->bytes, buffer, count);
409 }
410
411 // The send gate reserves the observed free slot. Do not wait for queue
412 // capacity while holding the control lock, which shutdown also uses.
413 // Pointer publication and ownership insertion must remain indivisible
414 // with respect to both receives and shutdown's deferred drain.
415 ControlGuard controlGuard(*this);
416 const uintptr_t record = reinterpret_cast<uintptr_t>(packet);
417 if (m_Records.writeAtomic(reinterpret_cast<const uint8_t*>(&record), sizeof(record), true) !=
418 sizeof(record)) {
419 delete packet;
420 captureStreamInterruption(block, interrupted);
421 return false;
422 }
423 m_PendingPackets.pushBack(packet);
424 return true;
425}
426
427bool UnixSocketConnection::Stream::readPacket(uint8_t* buffer, size_t count, bool block,
429 uint64_t& bytesRead, uint64_t& packetLength,
430 bool* interrupted) {
431 rights.reset();
432 bytesRead = packetLength = 0;
433 if (interrupted) {
434 *interrupted = false;
435 }
436 StreamSerializationGuard receiveGuard(m_ReceiveLock, block
437 ? StreamSerializationWait::Interruptible
438 : StreamSerializationWait::Nonblocking);
439 if (!receiveGuard || !m_Records.canRead(block)) {
440 captureStreamInterruption(block, interrupted);
441 return false;
442 }
443
444 ControlGuard controlGuard(*this);
445 uintptr_t record = 0;
446 if (m_Records.read(reinterpret_cast<uint8_t*>(&record), sizeof(record), false) !=
447 sizeof(record)) {
448 captureStreamInterruption(block, interrupted);
449 return false;
450 }
451 Packet* packet = reinterpret_cast<Packet*>(record);
452 assert(m_PendingPackets.count() && *m_PendingPackets.begin() == packet);
453 m_PendingPackets.popFront();
454 packetLength = packet->length;
455 bytesRead = count < packetLength ? count : packetLength;
456 if (bytesRead) {
457 MemoryCopy(buffer, packet->bytes, bytesRead);
458 }
459 rights = packet->rights;
460 delete packet;
461 return true;
462}
463
464bool UnixSocketConnection::Stream::canWrite(bool block) {
465 return m_Packets ? m_Records.canWrite(block) : m_Bytes.canWrite(block);
466}
467
468bool UnixSocketConnection::Stream::canRead(bool block) {
469 return m_Packets ? m_Records.canRead(block) : m_Bytes.canRead(block);
470}
471
472uint64_t UnixSocketConnection::Stream::readableGeneration() const {
473 return m_Packets ? m_Records.readableGeneration() : m_Bytes.readableGeneration();
474}
475
476uint64_t UnixSocketConnection::Stream::writableGeneration() const {
477 return m_Packets ? m_Records.writableGeneration() : m_Bytes.writableGeneration();
478}
479
480void UnixSocketConnection::Stream::disableWrites() {
481 m_Bytes.disableWrites();
482 m_Records.disableWrites();
483}
484
485void UnixSocketConnection::Stream::disableReads() {
486 // Reject new control-bearing writes first. A marker already being committed
487 // holds m_ControlLock across its byte write and list insertion, so draining
488 // under that lock closes the race without waiting on a gate that a suspended
489 // signal-handler caller may itself own.
490 disableWrites();
491 m_Bytes.disableReads();
492 m_Records.disableReads();
493
494#if !defined(PEDIGREE_EXTERNAL_SOURCE)
495 if (m_ControlLock.isOwnedByCurrentThread()) {
496 m_DiscardControlsRequested = true;
497 return;
498 }
499#endif
500
501 ControlGuard controlGuard(*this);
502 discardControls();
503 m_DiscardControlsRequested = false;
504}
505
506void UnixSocketConnection::Stream::monitor(Semaphore* waiter) {
507 if (m_Packets) {
508 m_Records.monitor(waiter);
509 } else {
510 m_Bytes.monitor(waiter);
511 }
512}
513
514void UnixSocketConnection::Stream::monitor(Thread* thread, Event* event) {
515 if (m_Packets) {
516 m_Records.monitor(thread, event);
517 } else {
518 m_Bytes.monitor(thread, event);
519 }
520}
521
522void UnixSocketConnection::Stream::cullMonitorTargets(Semaphore* waiter) {
523 if (m_Packets) {
524 m_Records.cullMonitorTargets(waiter);
525 } else {
526 m_Bytes.cullMonitorTargets(waiter);
527 }
528}
529
530void UnixSocketConnection::Stream::cullMonitorTargets(Event* event) {
531 if (m_Packets) {
532 m_Records.cullMonitorTargets(event);
533 } else {
534 m_Bytes.cullMonitorTargets(event);
535 }
536}
537
538void UnixSocketConnection::Stream::discardControls() {
539 while (m_PendingPackets.count()) {
540 delete m_PendingPackets.popFront();
541 }
542 while (m_Controls.count()) {
543 delete m_Controls.popFront();
544 }
545}
546
547void UnixSocketConnection::Stream::discardControlsIfRequested() {
548 while (m_DiscardControlsRequested.compareAndSwap(true, false)) {
549 discardControls();
550 }
551}
552
553UnixSocketConnection::UnixSocketConnection(bool packets)
554 : m_FirstStream(packets),
555 m_SecondStream(packets),
556 m_Active(false),
557 m_Failed(false),
558 m_Closed{false, false},
559 m_ReadShutdown{false, false},
560 m_WriteShutdown{false, false},
561 m_Creds() {
562 for (size_t i = 0; i < 2; ++i) {
563 m_Creds[i].uid = -1;
564 m_Creds[i].gid = -1;
565 m_Creds[i].pid = -1;
566 }
567}
568
569UnixSocket::UnixSocket(const String& name, Filesystem* pFs, File* pParent, UnixSocket* other,
570 SocketType type)
571 : File(name, 0, 0, 0, 0, pFs, 0, pParent),
572 m_Type(type),
573 m_State(Inactive),
574 m_Datagrams(MAX_UNIX_DGRAM_BACKLOG),
575 m_Stream(MAX_UNIX_STREAM_QUEUE),
576 m_Connection(),
577 m_ConnectionSide(false),
578 m_PendingSockets(),
579 m_Creds() {
580 (void)other;
581
582 if (m_Type == Datagram) {
583 // Datagram sockets are always active, they don't bind to each other.
584 m_State = Active;
585 }
586
587 m_Creds.uid = -1;
588 m_Creds.gid = -1;
589 m_Creds.pid = -1;
590}
591
592UnixSocket::~UnixSocket() {
593 unbind();
594}
595
596int UnixSocket::select(bool bWriting, int timeout) {
597 if (m_Type != Datagram) {
599 SocketState state;
600 bool shutdown = false;
601 {
602 LockGuard<Mutex> guard(m_ConnectionLock);
603 state = getStateLocked();
604 connection = m_Connection;
605 if (connection) {
606 const bool side = m_ConnectionSide;
607 shutdown =
608 bWriting
609 ? connection->m_WriteShutdown[side] || connection->m_ReadShutdown[side ? 0 : 1]
610 : connection->m_ReadShutdown[side] || connection->m_WriteShutdown[side ? 0 : 1];
611 }
612 }
613
614 if (state == Listening) {
615 return !bWriting && m_Stream.canRead(timeout == 1);
616 }
617
618 if (state == Closed) {
619 return !bWriting;
620 }
621
622 if (state != Active || !connection) {
623 return false;
624 }
625
626 if (shutdown) {
627 return true;
628 }
629
630 if (bWriting) {
631 if (outgoingStream(connection)->canWrite(timeout == 1)) {
632 return true;
633 }
634 } else {
635 if (incomingStream(connection)->canRead(timeout == 1)) {
636 return true;
637 }
638 }
639
640 return false;
641 } else {
642 {
643 LockGuard<Mutex> guard(m_ConnectionLock);
644 if (m_State == Closed) {
645 return !bWriting;
646 }
647 }
648
649 if (timeout) {
650 return m_Datagrams.waitFor(bWriting ? RingBufferWait::Writing : RingBufferWait::Reading);
651 } else if (bWriting) {
652 return m_Datagrams.canWrite();
653 } else {
654 return m_Datagrams.dataReady();
655 }
656 }
657}
658
659uint64_t UnixSocket::readBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
660 bool bCanBlock) {
661 String remote;
662 return recvfrom(size, buffer, bCanBlock, remote);
663}
664
665uint64_t UnixSocket::recvfrom(uint64_t size, uintptr_t buffer, bool bCanBlock, String& from) {
666 if (m_Type == SequencedPacket) {
667 from = String();
669 uint64_t bytesRead = 0, packetLength = 0;
670 receivePacket(size, buffer, bCanBlock, rights, bytesRead, packetLength);
671 return bytesRead;
672 }
673 if (m_Type == Streaming) {
674 from = String();
675 return receiveStream(size, buffer, bCanBlock, nullptr);
676 }
677
679 uint64_t bytesRead = 0;
680 uint64_t datagramLength = 0;
681 receiveDatagram(size, buffer, bCanBlock, from, rights, bytesRead, datagramLength);
682 return bytesRead;
683}
684
685uint64_t UnixSocket::receiveStream(uint64_t size, uintptr_t buffer, bool bCanBlock,
686 SharedPointer<SocketRights>* rights, bool* interrupted) {
687 struct iovec vector = {reinterpret_cast<void*>(buffer),
688 static_cast<size_t>(size > SIZE_MAX ? SIZE_MAX : size)};
689 return receiveStream(&vector, 1, bCanBlock, rights, interrupted);
690}
691
692uint64_t UnixSocket::receiveStream(struct iovec* vectors, size_t vectorCount, bool bCanBlock,
693 SharedPointer<SocketRights>* rights, bool* interrupted) {
694 if (interrupted) {
695 *interrupted = false;
696 }
697 if (rights) {
698 rights->reset();
699 }
700
702 SocketState state;
703 {
704 LockGuard<Mutex> guard(m_ConnectionLock);
705 state = getStateLocked();
706 connection = m_Connection;
707 }
708
709 if (m_Type != Streaming || !connection || (state != Active && state != Closed)) {
710 return 0;
711 }
712
713 return incomingStream(connection)
714 ->readVectors(vectors, vectorCount, state == Active && bCanBlock, rights, interrupted);
715}
716
717bool UnixSocket::receiveDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, String& from,
718 SharedPointer<SocketRights>& rights, uint64_t& bytesRead,
719 uint64_t& datagramLength) {
720 rights.reset();
721 bytesRead = 0;
722 datagramLength = 0;
723
724 {
725 LockGuard<Mutex> guard(m_ConnectionLock);
726 if (m_State == Closed || m_Type != Datagram) {
727 return false;
728 }
729 }
730
731 if (bCanBlock) {
732 if (!select(false, 1)) {
733 return false;
734 }
735 } else if (!select(false, 0)) {
736 return false;
737 }
738
739 struct buf* datagram = nullptr;
740 DatagramBuffer::Error error = DatagramBuffer::NoError;
741 if (!m_Datagrams.read(datagram, error)) {
742 return false;
743 }
744
745 datagramLength = datagram->len;
746 bytesRead = size < datagramLength ? size : datagramLength;
747 if (bytesRead) {
748 MemoryCopy(reinterpret_cast<void*>(buffer), datagram->pBuffer, bytesRead);
749 }
750 if (datagram->remotePath) {
751 from.assign(datagram->remotePath, datagram->remotePathLen);
752 }
753 rights = datagram->rights;
754 destroyDatagram(datagram);
755 return true;
756}
757
758uint64_t UnixSocket::writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
759 bool bCanBlock) {
760 if (m_Type == SequencedPacket) {
762 return sendPacket(size, buffer, bCanBlock, rights) ? size : 0;
763 }
764 if (m_Type == Streaming) {
766 return sendStream(size, buffer, bCanBlock, rights);
767 }
768
770 return sendDatagram(size, buffer, bCanBlock, location, rights) ? size : 0;
771}
772
773uint64_t UnixSocket::sendStream(uint64_t size, uintptr_t buffer, bool bCanBlock,
774 const SharedPointer<SocketRights>& rights, bool* interrupted) {
775 struct iovec vector = {reinterpret_cast<void*>(buffer),
776 static_cast<size_t>(size > SIZE_MAX ? SIZE_MAX : size)};
777 return sendStream(&vector, 1, bCanBlock, rights, interrupted);
778}
779
780uint64_t UnixSocket::sendStream(const struct iovec* vectors, size_t vectorCount, bool bCanBlock,
781 const SharedPointer<SocketRights>& rights, bool* interrupted) {
782 if (interrupted) {
783 *interrupted = false;
784 }
786 SocketState state;
787 {
788 LockGuard<Mutex> guard(m_ConnectionLock);
789 state = getStateLocked();
790 connection = m_Connection;
791 }
792
793 if (m_Type != Streaming || !connection || state != Active) {
794 N_NOTICE("UnixSocket::write => closed or not connected");
795 return 0;
796 }
797
798 return outgoingStream(connection)
799 ->writeVectors(vectors, vectorCount, bCanBlock, rights, interrupted);
800}
801
802bool UnixSocket::sendPacket(uint64_t size, uintptr_t buffer, bool bCanBlock,
803 const SharedPointer<SocketRights>& rights, int* error) {
804 if (error) {
805 *error = 0;
806 }
807 auto fail = [error](int value) {
808 if (error) {
809 *error = value;
810 }
811 return false;
812 };
813 if (m_Type != SequencedPacket) {
814 return fail(EPROTOTYPE);
815 }
816 if (size > MAX_UNIX_STREAM_QUEUE) {
817 return fail(EMSGSIZE);
818 }
820 SocketState state;
821 {
822 LockGuard<Mutex> guard(m_ConnectionLock);
823 state = getStateLocked();
824 connection = m_Connection;
825 }
826 if (!connection || state != Active || writeShutdown()) {
827 return fail(wasConnected() ? EPIPE : ENOTCONN);
828 }
829 bool interrupted = false;
830 if (outgoingStream(connection)
831 ->writePacket(reinterpret_cast<const uint8_t*>(buffer), size, bCanBlock, rights,
832 &interrupted)) {
833 return true;
834 }
835 if (interrupted) {
836 return fail(EINTR);
837 }
838 return fail(getState() == Closed || writeShutdown() ? EPIPE : EAGAIN);
839}
840
841bool UnixSocket::receivePacket(uint64_t size, uintptr_t buffer, bool bCanBlock,
842 SharedPointer<SocketRights>& rights, uint64_t& bytesRead,
843 uint64_t& packetLength, bool* interrupted) {
844 rights.reset();
845 bytesRead = packetLength = 0;
846 if (interrupted) {
847 *interrupted = false;
848 }
850 SocketState state;
851 {
852 LockGuard<Mutex> guard(m_ConnectionLock);
853 state = getStateLocked();
854 connection = m_Connection;
855 }
856 if (m_Type != SequencedPacket || !connection || (state != Active && state != Closed)) {
857 return false;
858 }
859 return incomingStream(connection)
860 ->readPacket(reinterpret_cast<uint8_t*>(buffer), size, state == Active && bCanBlock, rights,
861 bytesRead, packetLength, interrupted);
862}
863
864bool UnixSocket::sendDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, uintptr_t source,
865 const SharedPointer<SocketRights>& rights, int* error) {
866 if (error) {
867 *error = 0;
868 }
869 auto fail = [error](int value) {
870 if (error) {
871 *error = value;
872 }
873 return false;
874 };
875 if (m_Type != Datagram) {
876 return fail(EPROTOTYPE);
877 }
878 if (getState() == Closed) {
879 return fail(ECONNREFUSED);
880 }
881
882 struct buf* b = new buf();
883 if (!b) {
884 return fail(ENOMEM);
885 }
886 if (size) {
887 b->pBuffer = new char[size];
888 if (!b->pBuffer) {
889 destroyDatagram(b);
890 return fail(ENOMEM);
891 }
892 MemoryCopy(b->pBuffer, reinterpret_cast<void*>(buffer), size);
893 }
894 b->len = size;
895 b->rights = rights;
896 if (source) {
897 b->remotePathLen = StringLength(reinterpret_cast<const char*>(source));
898 b->remotePath = new char[b->remotePathLen + 1];
899 if (!b->remotePath) {
900 destroyDatagram(b);
901 return fail(ENOMEM);
902 }
903 MemoryCopy(b->remotePath, reinterpret_cast<const void*>(source), b->remotePathLen + 1);
904 }
905 // Admission and queue capacity must be checked by the same write operation.
906 const DatagramBuffer::Error result = bCanBlock ? m_Datagrams.write(b) : m_Datagrams.tryWrite(b);
907 if (result != DatagramBuffer::NoError) {
908 destroyDatagram(b);
909 if (result == DatagramBuffer::Closed) {
910 return fail(ECONNREFUSED);
911 }
912 if (result == DatagramBuffer::Interrupted || result == DatagramBuffer::ThreadTerminating) {
913 return fail(EINTR);
914 }
915 return fail(EAGAIN);
916 }
917
918 dataChanged();
919 return true;
920}
921
922void UnixSocket::destroyDatagram(struct buf* datagram) {
923 if (!datagram) {
924 return;
925 }
926
927 delete[] datagram->remotePath;
928 delete[] datagram->pBuffer;
929 delete datagram;
930}
931
932bool UnixSocket::bind(UnixSocket* other, bool block) {
933 (void)block;
934
935 if (!other || m_Type == Datagram || other->m_Type != m_Type) {
936 return false;
937 }
938
940 new UnixSocketConnection(m_Type == SequencedPacket));
941 {
942 LockGuard<Mutex> guard(m_ConnectionLock);
943 if (m_State != Inactive || other->m_State != Inactive || m_Connection || other->m_Connection) {
944 N_NOTICE("UnixSocket::bind endpoints are not inactive");
945 return false;
946 }
947
948 m_Connection = connection;
949 m_ConnectionSide = false;
950 other->m_Connection = connection;
951 other->m_ConnectionSide = true;
952 m_State = Connecting;
953 other->m_State = Connecting;
954
955 setCreds();
956 connection->m_Creds[0] = m_Creds;
957 }
958
959 return true;
960}
961
962void UnixSocket::unbind() {
964 bool side = false;
965 List<UnixSocket*> pending;
966 {
967 LockGuard<Mutex> guard(m_ConnectionLock);
968 connection = m_Connection;
969 if (connection) {
970 side = m_ConnectionSide;
971 connection->m_Closed[side] = true;
972 }
973
974 m_State = Closed;
975 while (m_PendingSockets.count()) {
976 pending.pushBack(m_PendingSockets.popFront());
977 }
978 }
979
980 N_NOTICE("UnixSocket::unbind");
981
982 if (m_Type == Datagram) {
983 m_Datagrams.close();
984 struct buf* datagram = nullptr;
985 while (m_Datagrams.takeAfterClose(datagram)) {
986 destroyDatagram(datagram);
987 }
988 }
989
990 if (connection) {
992 side ? &connection->m_SecondStream : &connection->m_FirstStream;
994 side ? &connection->m_FirstStream : &connection->m_SecondStream;
995 incoming->disableReads();
996 outgoing->disableWrites();
997 notifyStream(incoming);
998 notifyStream(outgoing);
999 }
1000
1001 m_Stream.disableWrites();
1002 m_Stream.disableReads();
1003 m_Stream.notifyMonitors();
1004
1005 while (pending.count()) {
1006 UnixSocket* socket = pending.popFront();
1007 socket->failConnection();
1008 delete socket;
1009 }
1010}
1011
1012bool UnixSocket::shutdown(int how) {
1014 bool side = false;
1015 {
1016 LockGuard<Mutex> guard(m_ConnectionLock);
1017 if (m_Type == Datagram || !m_Connection || !m_Connection->m_Active || m_Connection->m_Failed ||
1018 m_Connection->m_Closed[0] || m_Connection->m_Closed[1]) {
1019 SYSCALL_ERROR(NotConnected);
1020 return false;
1021 }
1022
1023 connection = m_Connection;
1024 side = m_ConnectionSide;
1025 if (how == SHUT_RD || how == SHUT_RDWR) {
1026 connection->m_ReadShutdown[side] = true;
1027 }
1028 if (how == SHUT_WR || how == SHUT_RDWR) {
1029 connection->m_WriteShutdown[side] = true;
1030 }
1031 }
1032
1033 auto* incoming = side ? &connection->m_SecondStream : &connection->m_FirstStream;
1034 auto* outgoing = side ? &connection->m_FirstStream : &connection->m_SecondStream;
1035 if (how == SHUT_RD || how == SHUT_RDWR) {
1036 incoming->disableReads();
1037 notifyStream(incoming);
1038 }
1039 if (how == SHUT_WR || how == SHUT_RDWR) {
1040 outgoing->disableWrites();
1041 notifyStream(outgoing);
1042 }
1043 return true;
1044}
1045
1046bool UnixSocket::writeShutdown() const {
1047 LockGuard<Mutex> guard(m_ConnectionLock);
1048 if (!m_Connection) {
1049 return false;
1050 }
1051 const bool side = m_ConnectionSide;
1052 return m_Connection->m_WriteShutdown[side] || m_Connection->m_ReadShutdown[side ? 0 : 1];
1053}
1054
1055bool UnixSocket::readShutdown() const {
1056 LockGuard<Mutex> guard(m_ConnectionLock);
1057 if (!m_Connection) {
1058 return false;
1059 }
1060 const bool side = m_ConnectionSide;
1061 return m_Connection->m_ReadShutdown[side] || m_Connection->m_WriteShutdown[side ? 0 : 1];
1062}
1063
1064void UnixSocket::acknowledgeBind() {
1066 {
1067 LockGuard<Mutex> guard(m_ConnectionLock);
1068 connection = m_Connection;
1069 if (!connection || connection->m_Failed || connection->m_Closed[0] || connection->m_Closed[1] ||
1070 connection->m_Active) {
1071 return;
1072 }
1073
1074 N_NOTICE("acking bind");
1075
1076 connection->m_Active = true;
1077 m_State = Active;
1078
1079 setCreds();
1080 connection->m_Creds[m_ConnectionSide ? 1 : 0] = m_Creds;
1081 }
1082
1083 notifyStream(&connection->m_FirstStream);
1084 notifyStream(&connection->m_SecondStream);
1085}
1086
1087bool UnixSocket::addSocket(UnixSocket* socket) {
1089 LockGuard<Mutex> guard(m_ConnectionLock);
1090 if (m_State != Listening || !socket || !socket->m_Connection || socket->m_Connection->m_Failed ||
1091 socket->m_Connection->m_Closed[0] || socket->m_Connection->m_Closed[1]) {
1092 return false;
1093 }
1094
1095 connection = socket->m_Connection;
1096 socket->m_Creds = m_Creds;
1097 connection->m_Creds[socket->m_ConnectionSide ? 1 : 0] = m_Creds;
1098 connection->m_Active = true;
1099 socket->m_State = Active;
1100 m_PendingSockets.pushBack(socket);
1101
1102 N_NOTICE("adding listening socket");
1103
1104 // No data moving on listen sockets so we use the stream buffer as a
1105 // signaling primitive. Keep queue ownership and its signal atomic with
1106 // listener teardown so a failed enqueue remains caller-owned.
1107 uint8_t c = 0;
1108 if (m_Stream.write(&c, 1, false) == 1) {
1109 notifyStream(&connection->m_FirstStream);
1110 notifyStream(&connection->m_SecondStream);
1111 return true;
1112 }
1113
1114 for (List<UnixSocket*>::Iterator it = m_PendingSockets.begin(); it != m_PendingSockets.end();
1115 ++it) {
1116 if (*it == socket) {
1117 m_PendingSockets.erase(it);
1118 break;
1119 }
1120 }
1121 return false;
1122}
1123
1124UnixSocket* UnixSocket::getSocket(bool block) {
1125 uint8_t c = 0;
1126 if (m_Stream.read(&c, 1, block) != 1) {
1127 return nullptr;
1128 }
1129
1130 N_NOTICE("got a socket");
1131
1132 LockGuard<Mutex> guard(m_ConnectionLock);
1133
1134 if (m_State != Listening || !m_PendingSockets.count()) {
1135 return nullptr;
1136 }
1137
1138 N_NOTICE("popping socket");
1139 return m_PendingSockets.popFront();
1140}
1141
1142void UnixSocket::addWaiter(Semaphore* waiter, bool read, bool write) {
1143 if (m_Type == Datagram) {
1144 m_Datagrams.monitor(waiter);
1145 return;
1146 }
1147
1149 bool side = false;
1150 bool closed = false;
1151 {
1152 LockGuard<Mutex> guard(m_ConnectionLock);
1153 closed = getStateLocked() == Closed;
1154 connection = m_Connection;
1155 side = m_ConnectionSide;
1156 }
1157
1158 if (closed) {
1159 // Closing readiness is persistent. Do not strand a waiter behind
1160 // unbind's one-shot monitor notification.
1161 waiter->release();
1162 return;
1163 }
1164
1165 const bool monitorRead = read || (!read && !write);
1166 if (!connection) {
1167 if (monitorRead || write) {
1168 m_Stream.monitor(waiter);
1169 }
1170 {
1171 LockGuard<Mutex> guard(m_ConnectionLock);
1172 closed = getStateLocked() == Closed;
1173 }
1174 if (closed) {
1175 m_Stream.notifyMonitors();
1176 }
1177 return;
1178 }
1179
1181 side ? &connection->m_SecondStream : &connection->m_FirstStream;
1183 side ? &connection->m_FirstStream : &connection->m_SecondStream;
1184 if (monitorRead) {
1185 incoming->monitor(waiter);
1186 }
1187 if (write && (!monitorRead || outgoing != incoming)) {
1188 outgoing->monitor(waiter);
1189 }
1190
1191 {
1192 LockGuard<Mutex> guard(m_ConnectionLock);
1193 closed = getStateLocked() == Closed;
1194 }
1195 if (closed) {
1196 // Repair close-before-enrollment without nesting buffer operations
1197 // under m_ConnectionLock. A concurrent notifier clears these targets.
1198 if (monitorRead) {
1199 notifyStream(incoming);
1200 }
1201 if (write && (!monitorRead || outgoing != incoming)) {
1202 notifyStream(outgoing);
1203 }
1204 }
1205}
1206
1207void UnixSocket::removeWaiter(Semaphore* waiter) {
1208 if (m_Type == Datagram) {
1209 m_Datagrams.cullMonitorTargets(waiter);
1210 return;
1211 }
1212
1214 {
1215 LockGuard<Mutex> guard(m_ConnectionLock);
1216 connection = m_Connection;
1217 if (!connection) {
1218 m_Stream.cullMonitorTargets(waiter);
1219 return;
1220 }
1221 }
1222
1223 connection->m_FirstStream.cullMonitorTargets(waiter);
1224 connection->m_SecondStream.cullMonitorTargets(waiter);
1225}
1226
1227void UnixSocket::addWaiter(Thread* thread, Event* event) {
1228 if (m_Type == Datagram) {
1229 m_Datagrams.monitor(thread, event);
1230 return;
1231 }
1232
1234 bool closed = false;
1235 {
1236 LockGuard<Mutex> guard(m_ConnectionLock);
1237 closed = getStateLocked() == Closed;
1238 connection = m_Connection;
1239 }
1240
1241 if (closed) {
1242 // Closing readiness is persistent; send without retaining the
1243 // connection lock across event delivery.
1244#if !defined(PEDIGREE_EXTERNAL_SOURCE)
1245 thread->sendEvent(event);
1246#endif
1247 return;
1248 }
1249
1250 if (!connection) {
1251 m_Stream.monitor(thread, event);
1252 {
1253 LockGuard<Mutex> guard(m_ConnectionLock);
1254 closed = getStateLocked() == Closed;
1255 }
1256 if (closed) {
1257 m_Stream.notifyMonitors();
1258 }
1259 return;
1260 }
1261
1262 UnixSocketConnection::Stream* first = &connection->m_FirstStream;
1263 UnixSocketConnection::Stream* second = &connection->m_SecondStream;
1264 first->monitor(thread, event);
1265 if (second != first) {
1266 second->monitor(thread, event);
1267 }
1268
1269 {
1270 LockGuard<Mutex> guard(m_ConnectionLock);
1271 closed = getStateLocked() == Closed;
1272 }
1273 if (closed) {
1274 // Repair close-before-enrollment; notifyMonitors is idempotent with a
1275 // concurrent unbind notifier because it consumes registered targets.
1276 notifyStream(first);
1277 if (second != first) {
1278 notifyStream(second);
1279 }
1280 }
1281}
1282
1283void UnixSocket::removeWaiter(Event* event) {
1284 if (m_Type == Datagram) {
1285 m_Datagrams.cullMonitorTargets(event);
1286 return;
1287 }
1288
1290 {
1291 LockGuard<Mutex> guard(m_ConnectionLock);
1292 connection = m_Connection;
1293 if (!connection) {
1294 m_Stream.cullMonitorTargets(event);
1295 return;
1296 }
1297 }
1298
1299 connection->m_FirstStream.cullMonitorTargets(event);
1300 connection->m_SecondStream.cullMonitorTargets(event);
1301}
1302
1303bool UnixSocket::markListening() {
1304 LockGuard<Mutex> guard(m_ConnectionLock);
1305
1306 if (m_Type == Datagram) {
1307 // Datagram sockets do not accept connections
1308 return false;
1309 }
1310
1311 if (m_State != Inactive) {
1312 // can't listen on a bound socket
1313 return false;
1314 }
1315
1316 setCreds();
1317 m_State = Listening;
1318 return true;
1319}
1320
1321UnixSocket::SocketState UnixSocket::getState() const {
1322 LockGuard<Mutex> guard(m_ConnectionLock);
1323 return getStateLocked();
1324}
1325
1326UnixSocket::SocketState UnixSocket::getStateLocked() const {
1327 if (m_Type == Datagram || !m_Connection) {
1328 return m_State;
1329 }
1330
1331 if (m_Connection->m_Failed || m_Connection->m_Closed[m_ConnectionSide ? 1 : 0] ||
1332 m_Connection->m_Closed[m_ConnectionSide ? 0 : 1]) {
1333 return Closed;
1334 }
1335
1336 return m_Connection->m_Active ? Active : Connecting;
1337}
1338
1339bool UnixSocket::wasConnected() const {
1340 LockGuard<Mutex> guard(m_ConnectionLock);
1341 return m_Connection && m_Connection->m_Active && !m_Connection->m_Failed;
1342}
1343
1345 ReadinessGenerations generations;
1346 if (m_Type == Datagram) {
1347 generations.read = m_Datagrams.readableGeneration();
1348 return generations;
1349 }
1350
1352 SocketState state;
1353 bool side = false;
1354 {
1355 LockGuard<Mutex> guard(m_ConnectionLock);
1356 state = getStateLocked();
1357 connection = m_Connection;
1358 side = m_ConnectionSide;
1359 }
1360
1361 if (state == Listening || !connection) {
1362 generations.read = m_Stream.readableGeneration();
1363 generations.write = m_Stream.writableGeneration();
1364 return generations;
1365 }
1366
1368 side ? &connection->m_SecondStream : &connection->m_FirstStream;
1370 side ? &connection->m_FirstStream : &connection->m_SecondStream;
1371 generations.read = incoming->readableGeneration();
1372 generations.write = outgoing->writableGeneration();
1373 return generations;
1374}
1375
1376void UnixSocket::failConnection() {
1378 {
1379 LockGuard<Mutex> guard(m_ConnectionLock);
1380 connection = m_Connection;
1381 if (!connection) {
1382 m_State = Closed;
1383 return;
1384 }
1385
1386 connection->m_Failed = true;
1387 connection->m_Closed[0] = true;
1388 connection->m_Closed[1] = true;
1389 m_State = Closed;
1390 }
1391
1392 connection->m_FirstStream.disableWrites();
1393 connection->m_FirstStream.disableReads();
1394 connection->m_SecondStream.disableWrites();
1395 connection->m_SecondStream.disableReads();
1396 notifyStream(&connection->m_FirstStream);
1397 notifyStream(&connection->m_SecondStream);
1398}
1399
1400struct ucred UnixSocket::getPeerCredentials() const {
1401 LockGuard<Mutex> guard(m_ConnectionLock);
1402 if (!m_Connection) {
1403 struct ucred empty;
1404 empty.uid = -1;
1405 empty.gid = -1;
1406 empty.pid = -1;
1407 return empty;
1408 }
1409
1410 return m_Connection->m_Creds[m_ConnectionSide ? 0 : 1];
1411}
1412
1413UnixSocketConnection::Stream* UnixSocket::incomingStream(
1414 const SharedPointer<UnixSocketConnection>& connection) const {
1415 return m_ConnectionSide ? &connection->m_SecondStream : &connection->m_FirstStream;
1416}
1417
1418UnixSocketConnection::Stream* UnixSocket::outgoingStream(
1419 const SharedPointer<UnixSocketConnection>& connection) const {
1420 return m_ConnectionSide ? &connection->m_FirstStream : &connection->m_SecondStream;
1421}
1422
1423void UnixSocket::setCreds() {
1424#if THREADS
1425 Process* pCurrentProcess = Processor::information().getCurrentThread()->getParent();
1426 m_Creds.uid = pCurrentProcess->getUserId();
1427 m_Creds.gid = pCurrentProcess->getGroupId();
1428 m_Creds.pid = pCurrentProcess->getUserspaceId();
1429#endif
1430}
1431
1432UnixDirectory::UnixDirectory(const String& name, Filesystem* pFs, File* pParent)
1433 : Directory(name, 0, 0, 0, 0, pFs, 0, pParent), m_Lock() {
1434 cacheDirectoryContents();
1435}
1436
1437UnixDirectory::~UnixDirectory() {}
1438
1439bool UnixDirectory::addEntry(const String& filename, File* pFile) {
1440 return addDirectoryEntry(filename, pFile);
1441}
1442
1443bool UnixDirectory::removeEntry(const String& filename, File* pFile) {
1444 LockGuard<Mutex> guard(m_Lock);
1445 return removeDirectoryEntry(filename.view(), pFile);
1446}
1447
1448bool UnixDirectory::removeFromParent(UnixDirectory* parent, const String& filename) {
1449 if (parent == this) {
1450 SYSCALL_ERROR(InvalidArgument);
1451 return false;
1452 }
1453 LockGuard<Mutex> namespaceGuard(namespaceMutationLock());
1454 LockGuard<Mutex> guard(m_Lock);
1455 bool empty = false;
1456 if (isEmpty(empty) != ReadStatus::Complete) {
1457 SYSCALL_ERROR(IoError);
1458 return false;
1459 }
1460 if (!empty) {
1461 SYSCALL_ERROR(NotEmpty);
1462 return false;
1463 }
1464 if (!parent->removeEntry(filename, this))
1465 return false;
1466 markDetached();
1467 return true;
1468}
1469
1473
1474UnixFilesystem::UnixFilesystem() : Filesystem(), m_pRoot(0) {
1475 UnixDirectory* pRoot = new UnixDirectory(String(""), this, 0);
1476
1477 m_pRoot = pRoot;
1478 VFS::instance().trackFile(m_pRoot);
1479
1480 // allow owner/group rwx but others only r-x on the filesystem root
1481 m_pRoot->setPermissions(FILE_UR | FILE_UW | FILE_UX | FILE_GR | FILE_GW | FILE_GX | FILE_OR |
1482 FILE_OX);
1483}
1484
1485UnixFilesystem::~UnixFilesystem() {
1486 Directory::fromFile(m_pRoot)->emptyCache();
1487 if (!VFS::instance().untrackFile(m_pRoot)) {
1488 ERROR("UnixFilesystem::~UnixFilesystem: root didn't get destroyed");
1489 }
1490}
1491
1492Mutex& UnixFilesystem::namespaceLock() {
1493 return m_NamespaceLock;
1494}
1495
1496bool UnixFilesystem::createFile(File* parent, const String& filename, uint32_t mask) {
1497 UnixDirectory* pParent = static_cast<UnixDirectory*>(Directory::fromFile(parent));
1498
1499 UnixSocket* pSocket = new UnixSocket(filename, this, parent);
1500 if (!pParent->addEntry(filename, pSocket)) {
1501 delete pSocket;
1502 return false;
1503 }
1504
1505 // give owner/group full permission to the socket by default
1506 pSocket->setPermissions(FILE_UR | FILE_UW | FILE_UX | FILE_GR | FILE_GW | FILE_GX | FILE_OR |
1507 FILE_OX);
1508
1509 return true;
1510}
1511
1512bool UnixFilesystem::createDirectory(File* parent, const String& filename, uint32_t mask) {
1513 UnixDirectory* pParent = static_cast<UnixDirectory*>(Directory::fromFile(parent));
1514
1515 UnixDirectory* pChild = new UnixDirectory(filename, this, parent);
1516 if (!pParent->addEntry(filename, pChild)) {
1517 delete pChild;
1518 return false;
1519 }
1520
1521 // give owner/group full permission to the directory by default
1522 pChild->setPermissions(FILE_UR | FILE_UW | FILE_UX | FILE_GR | FILE_GW | FILE_GX | FILE_OR |
1523 FILE_OX);
1524
1525 return true;
1526}
1527
1528bool UnixFilesystem::removeNode(File* parent, const String& filename, File* file) {
1529 UnixDirectory* pParent = static_cast<UnixDirectory*>(Directory::fromFile(parent));
1530 if (file->isDirectory()) {
1531 return static_cast<UnixDirectory*>(file)->removeFromParent(pParent, filename);
1532 }
1533 return pParent->removeEntry(filename, file);
1534}
1535
1536void UnixSocket::notifyStream(UnixSocketConnection::Stream* stream) {
1537 if (m_Type == SequencedPacket) {
1538 stream->records().notifyMonitors();
1539 } else {
1540 stream->buffer().notifyMonitors();
1541 }
1542}
size_t write(const T *buffer, size_t count, bool block=true)
Definition Buffer.cc:103
void monitor(Thread *pThread, Event *pEvent)
Definition Buffer.cc:594
void disableReads()
Definition Buffer.cc:422
void disableWrites()
Definition Buffer.cc:406
void cullMonitorTargets(Thread *pThread)
Definition Buffer.cc:620
void notifyMonitors()
Definition Buffer.cc:659
bool canRead(bool block)
Definition Buffer.cc:525
uint64_t readableGeneration() const
Definition Buffer.cc:559
size_t read(T *buffer, size_t count, bool block=true)
Definition Buffer.cc:296
static Directory * fromFile(File *pF)
Definition Directory.h:151
bool addDirectoryEntry(const String &name, File *pTarget)
Definition Directory.cc:835
void markCachePopulated()
bool empty()
void emptyCache()
Mutex & namespaceMutationLock()
Definition Directory.h:416
bool removeDirectoryEntry(const HashedStringView &name, File *expected)
Definition Directory.cc:894
ReadStatus isEmpty(bool &empty)
Definition Directory.cc:318
Definition Event.h:49
Definition File.h:75
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:239
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:342
virtual bool isDirectory()
Definition File.cc:804
void dataChanged()
Definition File.cc:1452
Definition List.h:61
Iterator begin()
Definition List.h:122
::Iterator< T, node_t > Iterator
Definition List.h:67
Iterator end()
Definition List.h:132
void close()
Definition Mailbox.h:114
MUST_USE_RESULT bool waitFor(MailboxWait::WaitType wait, Time::Timestamp &timeout, Error &error)
waitFor - block until the given condition is true (readable/writeable)
Definition Mailbox.h:350
bool canWrite()
canWrite - is it possible to write to the ring buffer without blocking?
Definition Mailbox.h:340
MUST_USE_RESULT bool takeAfterClose(T &out)
Definition Mailbox.h:142
MUST_USE_RESULT bool read(T &out, Time::Timestamp &timeout, Error &error)
Definition Mailbox.h:276
Error tryWrite(const T &obj)
Definition Mailbox.h:213
Error write(const T &obj, Time::Timestamp &timeout)
Writes one object, waiting for space up to the supplied timeout.
Definition Mailbox.h:154
bool dataReady()
dataReady - is data ready for reading from the ring buffer?
Definition Mailbox.h:330
Definition Mutex.h:56
size_t getUserspaceId() const
Definition Process.h:504
Process * getParent()
Definition Process.h:620
virtual int64_t getUserId() const
Definition Process.cc:2238
static ProcessorInformation & information()
bool monitor(Thread *pThread, Event *pEvent)
monitor - add a new Event to be fired when something happens
Definition RingBuffer.h:80
void cullMonitorTargets(Thread *pThread)
Cull all monitor targets pointing to pThread.
Definition RingBuffer.h:127
void release(size_t n=1)
Definition Semaphore.cc:549
static bool create(size_t descriptorCount, SharedPointer< SocketRights > &rights)
StringView view() const
Definition String.cc:783
bool sendEvent(Event *pEvent)
Definition Thread.cc:1115
virtual void cacheDirectoryContents()
virtual bool createFile(File *parent, const String &filename, uint32_t mask)
virtual bool removeNode(File *parent, const String &filename, File *file)
virtual bool createDirectory(File *parent, const String &filename, uint32_t mask)
uint64_t sendStream(uint64_t size, uintptr_t buffer, bool bCanBlock, const SharedPointer< SocketRights > &rights, bool *interrupted=nullptr)
bool sendDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, uintptr_t source, const SharedPointer< SocketRights > &rights, int *error=nullptr)
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
uint64_t receiveStream(uint64_t size, uintptr_t buffer, bool bCanBlock, SharedPointer< SocketRights > *rights, bool *interrupted=nullptr)
virtual int select(bool bWriting=false, int timeout=0)
bool receiveDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, String &from, SharedPointer< SocketRights > &rights, uint64_t &bytesRead, uint64_t &datagramLength)
ReadinessGenerations readinessGenerations() override
bool sendPacket(uint64_t size, uintptr_t buffer, bool bCanBlock, const SharedPointer< SocketRights > &rights, int *error=nullptr)
static VFS & instance()
Definition VFS.cc:311
void trackFile(File *pFile)
Track a File object that exists. It is necessary to keep track of File objects, or at least those tha...
Definition VFS.cc:1625
Iterator erase(Iterator &Iter)
Definition List.h:352
T popFront()
Definition List.h:330
size_t count() const
Definition List.h:212
void pushBack(const T &value)
Definition List.h:216
void pushBack(const T &value)
Definition Vector.h:275
void clear(bool freeMem=false)
Definition Vector.h:378
size_t count() const
Definition Vector.h:270