+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);
+ }
+}
+