Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2021-05-25 17:49:04 +0300
committerCorinna Vinschen <corinna@vinschen.de>2021-05-25 17:49:04 +0300
commitb62450cf172971c7805143a39c6c491a7a3c9785 (patch)
tree73b1054bd5ee9ec6ccd2ccf644dc3cee5f372879 /winsup/cygwin/fhandler_mqueue.cc
parenta4e074672aa61bd8b8a3b9493b9bdc85683e7604 (diff)
Cygwin: POSIX msg queues: implement open/mq_open entirely in fhandler
The mq_open call is just a framework now. This patch moves the entire functionality into fhandler_mqueue. To support standard OS calls (as on Linux), make fhandler_mqueue a derived class from fhandler_disk_file and keep the base handle the handle to the default stream, to allow implementing O_PATH functionlaity as well as reading from the file and NOT reading binary message queue data. Implement a standard fhandler_mqueue::open method, allowing, for instance, to touch a file under /dev/mqueue and if it doesn't exist, to create a message queue file. FIXME: This introduces a BAD HACK into path_conv::check, which needs reviewing. Keep the posix path intact in the fhandler, and change get_proc_fd_name accordingly to return only the basename plus leading slash for /proc/<PID>/fd. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup/cygwin/fhandler_mqueue.cc')
-rw-r--r--winsup/cygwin/fhandler_mqueue.cc271
1 files changed, 252 insertions, 19 deletions
diff --git a/winsup/cygwin/fhandler_mqueue.cc b/winsup/cygwin/fhandler_mqueue.cc
index 5f97264cd..6b0d98d75 100644
--- a/winsup/cygwin/fhandler_mqueue.cc
+++ b/winsup/cygwin/fhandler_mqueue.cc
@@ -11,21 +11,124 @@ details. */
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
+#include <mqueue.h>
+#include <sys/param.h>
+
+#define MSGSIZE(i) roundup((i), sizeof(long))
+
+struct mq_attr defattr = { 0, 10, 8192, 0 }; /* Linux defaults. */
fhandler_mqueue::fhandler_mqueue () :
- fhandler_base ()
+ fhandler_disk_file ()
{
- nohandle (true);
close_on_exec (true);
}
+int
+fhandler_mqueue::open (int flags, mode_t mode)
+{
+ /* FIXME: reopen by handle semantics missing yet */
+ flags &= ~(O_NOCTTY | O_PATH | O_BINARY | O_TEXT);
+ return mq_open (flags, mode, NULL);
+}
+
+int
+fhandler_mqueue::mq_open (int oflags, mode_t mode, struct mq_attr *attr)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ PUNICODE_STRING mqstream;
+ OBJECT_ATTRIBUTES oa;
+ struct mq_info *mqinfo = NULL;
+ bool created = false;
+
+ if ((oflags & ~(O_ACCMODE | O_CLOEXEC | O_CREAT | O_EXCL | O_NONBLOCK))
+ || (oflags & O_ACCMODE) == O_ACCMODE)
+ {
+ set_errno (EINVAL);
+ return 0;
+ }
+
+ /* attach a stream suffix to the NT filename, thus creating a stream. */
+ mqstream = pc.get_nt_native_path (&ro_u_mq_suffix);
+ pc.get_object_attr (oa, sec_none_nih);
+
+again:
+ if (oflags & O_CREAT)
+ {
+ /* Create and disallow sharing */
+ status = NtCreateFile (&get_handle (),
+ GENERIC_READ | GENERIC_WRITE | DELETE
+ | SYNCHRONIZE, &oa, &io, NULL,
+ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE,
+ FILE_CREATE,
+ FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL, 0);
+ if (!NT_SUCCESS (status))
+ {
+ if (status == STATUS_OBJECT_NAME_COLLISION && (oflags & O_EXCL) == 0)
+ goto exists;
+ __seterrno_from_nt_status (status);
+ return 0;
+ }
+ if (pc.has_acls ())
+ set_created_file_access (get_handle (), pc, mode);
+ created = true;
+ goto out;
+ }
+exists:
+ /* Open the file, and loop while detecting a sharing violation. */
+ while (true)
+ {
+ status = NtOpenFile (&get_handle (),
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+ &oa, &io, FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_SYNCHRONOUS_IO_NONALERT);
+ if (NT_SUCCESS (status))
+ break;
+ if (status == STATUS_OBJECT_NAME_NOT_FOUND && (oflags & O_CREAT))
+ goto again;
+ if (status != STATUS_SHARING_VIOLATION)
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ Sleep (100L);
+ }
+out:
+ /* We need the filename without STREAM_SUFFIX later on */
+ mqstream->Length -= ro_u_mq_suffix.Length;
+ mqstream->Buffer[mqstream->Length / sizeof (WCHAR)] = L'\0';
+
+ if (created)
+ {
+ if (attr == NULL)
+ attr = &defattr;
+ /* Check minimum and maximum values. The max values are pretty much
+ arbitrary, taken from the linux mq_overview man page, up to Linux
+ 3.4. These max values make sure that the internal mq_fattr
+ structure can use 32 bit types. */
+ if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768
+ || attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576)
+ set_errno (EINVAL);
+ else
+ mqinfo = mqinfo_create (attr, mode, oflags & O_NONBLOCK);
+ }
+ else
+ mqinfo = mqinfo_open (oflags & O_NONBLOCK);
+ mq_open_finish (mqinfo != NULL, created);
+ return mqinfo ? 1 : 0;
+}
+
struct mq_info *
-fhandler_mqueue::_mqinfo (HANDLE fh, SIZE_T filesize, mode_t mode, int flags,
+fhandler_mqueue::_mqinfo (SIZE_T filesize, mode_t mode, int flags,
bool just_open)
{
WCHAR buf[NAME_MAX + sizeof ("mqueue/XXX")];
UNICODE_STRING uname;
- OBJECT_ATTRIBUTES attr;
+ OBJECT_ATTRIBUTES oa;
NTSTATUS status;
LARGE_INTEGER fsiz = { QuadPart: (LONGLONG) filesize };
PVOID mptr = NULL;
@@ -38,33 +141,33 @@ fhandler_mqueue::_mqinfo (HANDLE fh, SIZE_T filesize, mode_t mode, int flags,
__small_swprintf (buf, L"mqueue/mtx%s", get_name ());
RtlInitUnicodeString (&uname, buf);
- InitializeObjectAttributes (&attr, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ InitializeObjectAttributes (&oa, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
get_shared_parent_dir (),
everyone_sd (CYG_MUTANT_ACCESS));
- status = NtCreateMutant (&mqinfo ()->mqi_lock, CYG_MUTANT_ACCESS, &attr,
+ status = NtCreateMutant (&mqinfo ()->mqi_lock, CYG_MUTANT_ACCESS, &oa,
FALSE);
if (!NT_SUCCESS (status))
goto err;
wcsncpy (buf + 7, L"snd", 3);
/* same length, no RtlInitUnicodeString required */
- InitializeObjectAttributes (&attr, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ InitializeObjectAttributes (&oa, &uname, OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
get_shared_parent_dir (),
everyone_sd (CYG_EVENT_ACCESS));
- status = NtCreateEvent (&mqinfo ()->mqi_waitsend, CYG_EVENT_ACCESS, &attr,
+ status = NtCreateEvent (&mqinfo ()->mqi_waitsend, CYG_EVENT_ACCESS, &oa,
NotificationEvent, FALSE);
if (!NT_SUCCESS (status))
goto err;
wcsncpy (buf + 7, L"rcv", 3);
/* same length, same attributes, no more init required */
- status = NtCreateEvent (&mqinfo ()->mqi_waitrecv, CYG_EVENT_ACCESS, &attr,
+ status = NtCreateEvent (&mqinfo ()->mqi_waitrecv, CYG_EVENT_ACCESS, &oa,
NotificationEvent, FALSE);
if (!NT_SUCCESS (status))
goto err;
- InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
- status = NtCreateSection (&mqinfo ()->mqi_sect, SECTION_ALL_ACCESS, &attr,
- &fsiz, PAGE_READWRITE, SEC_COMMIT, fh);
+ InitializeObjectAttributes (&oa, NULL, 0, NULL, NULL);
+ status = NtCreateSection (&mqinfo ()->mqi_sect, SECTION_ALL_ACCESS, &oa,
+ &fsiz, PAGE_READWRITE, SEC_COMMIT, get_handle ());
if (!NT_SUCCESS (status))
goto err;
@@ -100,22 +203,152 @@ err:
return NULL;
}
+struct mq_info *
+fhandler_mqueue::mqinfo_open (int flags)
+{
+ FILE_STANDARD_INFORMATION fsi;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ mode_t mode;
+
+ fsi.EndOfFile.QuadPart = 0;
+ status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
+ FileStandardInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return NULL;
+ }
+ if (get_file_attribute (get_handle (), pc, &mode, NULL, NULL))
+ mode = STD_RBITS | STD_WBITS;
+
+ return _mqinfo (fsi.EndOfFile.QuadPart, mode, flags, true);
+}
+
+struct mq_info *
+fhandler_mqueue::mqinfo_create (struct mq_attr *attr, mode_t mode, int flags)
+{
+ long msgsize;
+ off_t filesize = 0;
+ FILE_END_OF_FILE_INFORMATION feofi;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ struct mq_info *mqinfo = NULL;
+
+ msgsize = MSGSIZE (attr->mq_msgsize);
+ filesize = sizeof (struct mq_hdr)
+ + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
+ feofi.EndOfFile.QuadPart = filesize;
+ status = NtSetInformationFile (get_handle (), &io, &feofi, sizeof feofi,
+ FileEndOfFileInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return NULL;
+ }
+
+ mqinfo = _mqinfo (filesize, mode, flags, false);
+
+ if (mqinfo)
+ {
+ /* Initialize header at beginning of file */
+ /* Create free list with all messages on it */
+ int8_t *mptr;
+ struct mq_hdr *mqhdr;
+ struct msg_hdr *msghdr;
+
+ mptr = (int8_t *) mqinfo->mqi_hdr;
+ mqhdr = mqinfo->mqi_hdr;
+ mqhdr->mqh_attr.mq_flags = 0;
+ mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
+ mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
+ mqhdr->mqh_attr.mq_curmsgs = 0;
+ mqhdr->mqh_nwait = 0;
+ mqhdr->mqh_pid = 0;
+ mqhdr->mqh_head = 0;
+ mqhdr->mqh_magic = MQI_MAGIC;
+ long index = sizeof (struct mq_hdr);
+ mqhdr->mqh_free = index;
+ for (int i = 0; i < attr->mq_maxmsg - 1; i++)
+ {
+ msghdr = (struct msg_hdr *) &mptr[index];
+ index += sizeof (struct msg_hdr) + msgsize;
+ msghdr->msg_next = index;
+ }
+ msghdr = (struct msg_hdr *) &mptr[index];
+ msghdr->msg_next = 0; /* end of free list */
+ }
+
+ return mqinfo;
+}
+
+void
+fhandler_mqueue::mq_open_finish (bool success, bool created)
+{
+ NTSTATUS status;
+ HANDLE def_stream;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK io;
+
+ if (get_handle ())
+ {
+ /* If we have an open queue stream handle, close it and set it to NULL */
+ HANDLE queue_stream = get_handle ();
+ set_handle (NULL);
+ if (success)
+ {
+ /* In case of success, open the default stream for reading. This
+ can be used to implement various IO functions without exposing
+ the actual message queue. */
+ pc.get_object_attr (oa, sec_none_nih);
+ status = NtOpenFile (&def_stream, GENERIC_READ | SYNCHRONIZE,
+ &oa, &io, FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_SYNCHRONOUS_IO_NONALERT);
+ if (NT_SUCCESS (status))
+ set_handle (def_stream);
+ else /* Note that we don't treat this as an error! */
+ {
+ debug_printf ("Opening default stream failed: status %y", status);
+ nohandle (true);
+ }
+ }
+ else if (created)
+ {
+ /* In case of error at creation time, delete the file */
+ FILE_DISPOSITION_INFORMATION disp = { TRUE };
+
+ NtSetInformationFile (queue_stream, &io, &disp, sizeof disp,
+ FileDispositionInformation);
+ /* We also have to set the delete disposition on the default stream,
+ otherwise only the queue stream will get deleted */
+ pc.get_object_attr (oa, sec_none_nih);
+ status = NtOpenFile (&def_stream, DELETE, &oa, &io,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_FOR_BACKUP_INTENT);
+ if (NT_SUCCESS (status))
+ {
+ NtSetInformationFile (def_stream, &io, &disp, sizeof disp,
+ FileDispositionInformation);
+ NtClose (def_stream);
+ }
+ }
+ NtClose (queue_stream);
+ }
+}
+
char *
fhandler_mqueue::get_proc_fd_name (char *buf)
{
- return strcpy (buf, get_name ());
+ return strcpy (buf, strrchr (get_name (), '/'));
}
int __reg2
fhandler_mqueue::fstat (struct stat *buf)
{
- int ret = fhandler_base::fstat (buf);
+ int ret = fhandler_disk_file::fstat (buf);
if (!ret)
- {
- buf->st_mode = S_IFREG | mqinfo ()->mqi_mode;
- buf->st_dev = FH_MQUEUE;
- buf->st_ino = hash_path_name (0, get_name ());
- }
+ buf->st_dev = FH_MQUEUE;
return ret;
}