int inode_stat(FAR struct inode *inode, FAR struct stat *buf) { DEBUGASSERT(inode != NULL && buf != NULL); memset(buf, 0, sizeof(*buf)); if (INODE_IS_SPECIAL(inode)) { #if defined(CONFIG_FS_NAMED_SEMAPHORES) if (INODE_IS_NAMEDSEM(inode)) { buf->st_mode = S_IFSEM; } else #endif #if !defined(CONFIG_DISABLE_MQUEUE) if (INODE_IS_MQUEUE(inode)) { buf->st_mode = S_IFMQ; } else #endif { } } else if (inode->u.i_ops != NULL) { /* Determine read/write privileges based on the existence of read * and write methods. */ if (inode->u.i_ops->read) { buf->st_mode = S_IROTH | S_IRGRP | S_IRUSR; } if (inode->u.i_ops->write) { buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; } /* Determine the type of the inode */ if (INODE_IS_MOUNTPT(inode)) { buf->st_mode |= S_IFDIR; } else if (INODE_IS_BLOCK(inode)) { /* What is if also has child inodes? */ buf->st_mode |= S_IFBLK; } else /* if (INODE_IS_DRIVER(inode)) */ { /* What is it if it also has child inodes? */ buf->st_mode |= S_IFCHR; } } else { /* If it has no operations, then it must just be a intermediate * node in the inode tree. It is something like a directory. * We'll say that all pseudo-directories are read-able but not * write-able. */ buf->st_mode |= S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; } return OK; }
mqd_t mq_open(FAR const char *mq_name, int oflags, ...) { FAR struct inode *inode; FAR const char *relpath = NULL; FAR struct mqueue_inode_s *msgq; char fullpath[MAX_MQUEUE_PATH]; va_list ap; struct mq_attr *attr; mqd_t mqdes; mode_t mode; int errcode; int ret; /* Make sure that a non-NULL name is supplied */ if (!mq_name) { errcode = EINVAL; goto errout; } /* Get the full path to the message queue */ snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", mq_name); /* Make sure that the check for the existence of the message queue * and the creation of the message queue are atomic with respect to * other processes executing mq_open(). A simple sched_lock() should * be sufficient. */ sched_lock(); /* Get the inode for this mqueue. This should succeed if the message * queue has already been created. */ inode = inode_find(fullpath, &relpath); if (inode) { /* It exists. Verify that the inode is a message queue */ if (!INODE_IS_MQUEUE(inode)) { errcode = ENXIO; goto errout_with_inode; } /* It exists and is a message queue. Check if the caller wanted to * create a new mqueue with this name. */ if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { errcode = EEXIST; goto errout_with_inode; } /* Create a message queue descriptor for the current thread */ msgq = inode->u.i_mqueue; mqdes = mq_descreate(NULL, msgq, oflags); if (!mqdes) { errcode = ENOMEM; goto errout_with_inode; } } else { /* The mqueue does not exists. Were we asked to create it? */ if ((oflags & O_CREAT) == 0) { /* The mqueue does not exist and O_CREAT is not set */ errcode = ENOENT; goto errout_with_lock; } /* Create the mqueue. First we have to extract the additional * parameters from the variable argument list. */ va_start(ap, oflags); mode = va_arg(ap, mode_t); attr = va_arg(ap, FAR struct mq_attr*); va_end(ap); /* Create an inode in the pseudo-filesystem at this path */ inode_semtake(); ret = inode_reserve(fullpath, &inode); inode_semgive(); if (ret < 0) { errcode = -ret; goto errout_with_lock; } /* Allocate memory for the new message queue. */ msgq = (FAR struct mqueue_inode_s*)mq_msgqalloc(mode, attr); if (!msgq) { errcode = ENOSPC; goto errout_with_inode; } /* Create a message queue descriptor for the TCB */ mqdes = mq_descreate(NULL, msgq, oflags); if (!mqdes) { errcode = ENOMEM; goto errout_with_msgq; } /* Bind the message queue and the inode structure */ INODE_SET_MQUEUE(inode); inode->u.i_mqueue = msgq; msgq->inode = inode; } sched_unlock(); return mqdes; errout_with_msgq: mq_msgqfree(msgq); inode->u.i_mqueue = NULL; errout_with_inode: inode_release(inode); errout_with_lock: sched_unlock(); errout: set_errno(errcode); return (mqd_t)ERROR; }
int mq_unlink(FAR const char *mq_name) { FAR struct inode *inode; FAR const char *relpath = NULL; char fullpath[MAX_MQUEUE_PATH]; int errcode; int ret; /* Get the full path to the message queue */ snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", mq_name); /* Get the inode for this message queue. */ sched_lock(); inode = inode_find(fullpath, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } /* Verify that what we found is, indeed, a message queue */ if (!INODE_IS_MQUEUE(inode)) { errcode = ENXIO; goto errout_with_inode; } /* Refuse to unlink the inode if it has children. I.e., if it is * functioning as a directory and the directory is not empty. */ inode_semtake(); if (inode->i_child != NULL) { errcode = ENOTEMPTY; goto errout_with_semaphore; } /* Remove the old inode from the tree. Because we hold a reference count * on the inode, it will not be deleted now. This will set the * FSNODEFLAG_DELETED bit in the inode flags. */ ret = inode_remove(fullpath); /* inode_remove() should always fail with -EBUSY because we hae a reference * on the inode. -EBUSY means taht the inode was, indeed, unlinked but * thatis could not be freed because there are refrences. */ DEBUGASSERT(ret >= 0 || ret == -EBUSY); UNUSED(ret); /* Now we do not release the reference count in the normal way (by calling * inode release. Rather, we call mq_inode_release(). mq_inode_release * will decrement the reference count on the inode. But it will also free * the message queue if that reference count decrements to zero. Since we * hold one reference, that can only occur if the message queue is not * in-use. */ inode_semgive(); mq_inode_release(inode); sched_unlock(); return OK; errout_with_semaphore: inode_semgive(); errout_with_inode: inode_release(inode); errout: set_errno(errcode); sched_unlock(); return ERROR; }