* Implemented flock() semantics to the advisory locking backend. Not tested
(must also compare to BSD; I've looked at their sources, but I might have missed something). * Added sys/file.h and the flock() system call. * common_fcntl() could forget to put back the file descriptor on some error conditions (I guess we should introduce and use a DescriptorGetter class). * Cleaned up fcntl.h, moved the BSD extensions S_IREAD and S_IWRITE to sys/stat.h where they belong, and added the missing S_IEXEC to them. * Added some more comments. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23836 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e5bc2a9e7a
commit
a32a4683ff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008, Haiku Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _FCNTL_H
|
||||
@ -74,15 +74,6 @@ struct flock {
|
||||
pid_t l_pid;
|
||||
};
|
||||
|
||||
/* for use with flock() - TODO: this should be moved to sys/file.h *if* we'll support flock() one day */
|
||||
#define LOCK_SH 0x01 /* shared file lock */
|
||||
#define LOCK_EX 0x02 /* exclusive file lock */
|
||||
#define LOCK_NB 0x04 /* don't block when locking */
|
||||
#define LOCK_UN 0x08 /* unlock file */
|
||||
|
||||
#define S_IREAD 0x0100 /* owner may read */
|
||||
#define S_IWRITE 0x0080 /* owner may write */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -99,4 +90,4 @@ extern int fcntl(int fd, int op, ...);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FCNTL_H */
|
||||
#endif /* _FCNTL_H */
|
||||
|
29
headers/posix/sys/file.h
Normal file
29
headers/posix/sys/file.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2008, Haiku Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SYS_FILE_H
|
||||
#define _SYS_FILE_H
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/* for use with flock() */
|
||||
#define LOCK_SH 0x01 /* shared file lock */
|
||||
#define LOCK_EX 0x02 /* exclusive file lock */
|
||||
#define LOCK_NB 0x04 /* don't block when locking */
|
||||
#define LOCK_UN 0x08 /* unlock file */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int flock(int fd, int op);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_FILE_H */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008, Haiku Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SYS_STAT_H_
|
||||
@ -85,6 +85,11 @@ struct stat {
|
||||
#define S_IWOTH 00002 /* write permission: other */
|
||||
#define S_IXOTH 00001 /* execute permission: other */
|
||||
|
||||
/* BSD extensions */
|
||||
#define S_IREAD S_IRUSR
|
||||
#define S_IWRITE S_IWUSR
|
||||
#define S_IEXEC S_IXUSR
|
||||
|
||||
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)
|
||||
#define ALLPERMS (S_ISUID | S_ISGID | S_ISTXT | S_IRWXU | S_IRWXG | S_IRWXO)
|
||||
#define DEFFILEMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007, Haiku Inc. All rights reserved.
|
||||
* Copyright 2004-2008, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_SYSCALLS_H
|
||||
@ -151,6 +151,7 @@ extern int _kern_open_parent_dir(int fd, char *name,
|
||||
size_t nameLength);
|
||||
extern status_t _kern_fcntl(int fd, int op, uint32 argument);
|
||||
extern status_t _kern_fsync(int fd);
|
||||
extern status_t _kern_flock(int fd, int op);
|
||||
extern off_t _kern_seek(int fd, off_t pos, int seekType);
|
||||
extern status_t _kern_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms);
|
||||
extern status_t _kern_create_dir(int fd, const char *path, int perms);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
@ -145,6 +145,7 @@ int _user_open_dir(int fd, const char *path);
|
||||
int _user_open_parent_dir(int fd, char *name, size_t nameLength);
|
||||
status_t _user_fcntl(int fd, int op, uint32 argument);
|
||||
status_t _user_fsync(int fd);
|
||||
status_t _user_flock(int fd, int op);
|
||||
status_t _user_read_stat(int fd, const char *path, bool traverseLink,
|
||||
struct stat *stat, size_t statSize);
|
||||
status_t _user_write_stat(int fd, const char *path, bool traverseLink,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@ -128,6 +129,7 @@ struct advisory_locking {
|
||||
struct advisory_lock {
|
||||
list_link link;
|
||||
team_id team;
|
||||
pid_t session;
|
||||
off_t offset;
|
||||
off_t length;
|
||||
bool shared;
|
||||
@ -1088,7 +1090,6 @@ err1:
|
||||
|
||||
/*! Retrieves the first lock that has been set by the current team.
|
||||
*/
|
||||
|
||||
static status_t
|
||||
get_advisory_lock(struct vnode *vnode, struct flock *flock)
|
||||
{
|
||||
@ -1128,15 +1129,18 @@ release_advisory_lock(struct vnode *vnode, struct flock *flock)
|
||||
return flock != NULL ? B_BAD_VALUE : B_OK;
|
||||
|
||||
team_id team = team_get_current_team_id();
|
||||
pid_t session = thread_get_current_thread()->team->session_id;
|
||||
|
||||
// find matching lock entry
|
||||
|
||||
status_t status = B_BAD_VALUE;
|
||||
struct advisory_lock *lock = NULL;
|
||||
while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) {
|
||||
if (lock->team == team && (flock == NULL || (flock != NULL
|
||||
&& lock->offset == flock->l_start
|
||||
&& lock->length == flock->l_len))) {
|
||||
while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks,
|
||||
lock)) != NULL) {
|
||||
if (lock->team == team && (flock == NULL
|
||||
|| (flock != NULL && lock->offset == flock->l_start
|
||||
&& lock->length == flock->l_len))
|
||||
|| lock->session == session) {
|
||||
// we found our lock, free it
|
||||
list_remove_item(&locking->locks, lock);
|
||||
free(lock);
|
||||
@ -1176,8 +1180,18 @@ release_advisory_lock(struct vnode *vnode, struct flock *flock)
|
||||
}
|
||||
|
||||
|
||||
/*! Acquires an advisory lock for the \a vnode. If \a wait is \c true, it
|
||||
will wait for the lock to become available, if there are any collisions
|
||||
(it will return B_PERMISSION_DENIED in this case if \a wait is \c false).
|
||||
|
||||
If \a session is -1, POSIX semantics are used for this lock. Otherwise,
|
||||
BSD flock() semantics are used, that is, all children can unlock the file
|
||||
in question (we even allow parents to remove the lock, though, but that
|
||||
seems to be in line to what the BSD's are doing).
|
||||
*/
|
||||
static status_t
|
||||
acquire_advisory_lock(struct vnode *vnode, struct flock *flock, bool wait)
|
||||
acquire_advisory_lock(struct vnode *vnode, pid_t session, struct flock *flock,
|
||||
bool wait)
|
||||
{
|
||||
FUNCTION(("acquire_advisory_lock(vnode = %p, flock = %p, wait = %s)\n",
|
||||
vnode, flock, wait ? "yes" : "no"));
|
||||
@ -1185,6 +1199,8 @@ acquire_advisory_lock(struct vnode *vnode, struct flock *flock, bool wait)
|
||||
bool shared = flock->l_type == F_RDLCK;
|
||||
status_t status = B_OK;
|
||||
|
||||
// TODO: do deadlock detection!
|
||||
|
||||
restart:
|
||||
// if this vnode has an advisory_locking structure attached,
|
||||
// lock that one and search for any colliding file lock
|
||||
@ -1194,7 +1210,8 @@ restart:
|
||||
if (locking != NULL) {
|
||||
// test for collisions
|
||||
struct advisory_lock *lock = NULL;
|
||||
while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) {
|
||||
while ((lock = (struct advisory_lock *)list_get_next_item(
|
||||
&locking->locks, lock)) != NULL) {
|
||||
if (lock->offset <= flock->l_start + flock->l_len
|
||||
&& lock->offset + lock->length > flock->l_start) {
|
||||
// locks do overlap
|
||||
@ -1214,9 +1231,10 @@ restart:
|
||||
|
||||
if (waitForLock >= B_OK) {
|
||||
if (!wait)
|
||||
status = B_PERMISSION_DENIED;
|
||||
status = session != -1 ? B_WOULD_BLOCK : B_PERMISSION_DENIED;
|
||||
else {
|
||||
status = switch_sem_etc(locking->lock, waitForLock, 1, B_CAN_INTERRUPT, 0);
|
||||
status = switch_sem_etc(locking->lock, waitForLock, 1,
|
||||
B_CAN_INTERRUPT, 0);
|
||||
if (status == B_OK) {
|
||||
// see if we're still colliding
|
||||
goto restart;
|
||||
@ -1240,7 +1258,8 @@ restart:
|
||||
// we own the locking object, so it can't go away
|
||||
}
|
||||
|
||||
struct advisory_lock *lock = (struct advisory_lock *)malloc(sizeof(struct advisory_lock));
|
||||
struct advisory_lock *lock = (struct advisory_lock *)malloc(
|
||||
sizeof(struct advisory_lock));
|
||||
if (lock == NULL) {
|
||||
if (waitForLock >= B_OK)
|
||||
release_sem_etc(waitForLock, 1, B_RELEASE_ALL);
|
||||
@ -1249,6 +1268,7 @@ restart:
|
||||
}
|
||||
|
||||
lock->team = team_get_current_team_id();
|
||||
lock->session = session;
|
||||
// values must already be normalized when getting here
|
||||
lock->offset = flock->l_start;
|
||||
lock->length = flock->l_len;
|
||||
@ -1261,6 +1281,10 @@ restart:
|
||||
}
|
||||
|
||||
|
||||
/*! Normalizes the \a flock structure to make it easier to compare the
|
||||
structure with others. The l_start and l_len fields are set to absolute
|
||||
values according to the l_whence field.
|
||||
*/
|
||||
static status_t
|
||||
normalize_flock(struct file_descriptor *descriptor, struct flock *flock)
|
||||
{
|
||||
@ -1279,7 +1303,8 @@ normalize_flock(struct file_descriptor *descriptor, struct flock *flock)
|
||||
if (FS_CALL(vnode, read_stat) == NULL)
|
||||
return EOPNOTSUPP;
|
||||
|
||||
status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat);
|
||||
status = FS_CALL(vnode, read_stat)(vnode->mount->cookie,
|
||||
vnode->private_node, &stat);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
@ -4512,7 +4537,6 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel)
|
||||
struct file_descriptor *descriptor;
|
||||
struct vnode *vnode;
|
||||
struct flock flock;
|
||||
status_t status;
|
||||
|
||||
FUNCTION(("common_fcntl(fd = %d, op = %d, argument = %lx, %s)\n",
|
||||
fd, op, argument, kernel ? "kernel" : "user"));
|
||||
@ -4521,11 +4545,19 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel)
|
||||
if (descriptor == NULL)
|
||||
return B_FILE_ERROR;
|
||||
|
||||
status_t status = B_OK;
|
||||
|
||||
if (op == F_SETLK || op == F_SETLKW || op == F_GETLK) {
|
||||
if (descriptor->type != FDTYPE_FILE)
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&flock, (struct flock *)argument, sizeof(struct flock)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
status = B_BAD_VALUE;
|
||||
else if (user_memcpy(&flock, (struct flock *)argument,
|
||||
sizeof(struct flock)) < B_OK)
|
||||
status = B_BAD_ADDRESS;
|
||||
|
||||
if (status != B_OK) {
|
||||
put_fd(descriptor);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
@ -4564,8 +4596,8 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel)
|
||||
vnode->private_node, descriptor->cookie, (int)argument);
|
||||
if (status == B_OK) {
|
||||
// update this descriptor's open_mode field
|
||||
descriptor->open_mode = (descriptor->open_mode & ~(O_APPEND | O_NONBLOCK))
|
||||
| argument;
|
||||
descriptor->open_mode = (descriptor->open_mode
|
||||
& ~(O_APPEND | O_NONBLOCK)) | argument;
|
||||
}
|
||||
} else
|
||||
status = EOPNOTSUPP;
|
||||
@ -4595,7 +4627,8 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel)
|
||||
status = get_advisory_lock(descriptor->u.vnode, &flock);
|
||||
if (status == B_OK) {
|
||||
// copy back flock structure
|
||||
status = user_memcpy((struct flock *)argument, &flock, sizeof(struct flock));
|
||||
status = user_memcpy((struct flock *)argument, &flock,
|
||||
sizeof(struct flock));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -4609,11 +4642,15 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel)
|
||||
status = release_advisory_lock(descriptor->u.vnode, &flock);
|
||||
else {
|
||||
// the open mode must match the lock type
|
||||
if ((descriptor->open_mode & O_RWMASK) == O_RDONLY && flock.l_type == F_WRLCK
|
||||
|| (descriptor->open_mode & O_RWMASK) == O_WRONLY && flock.l_type == F_RDLCK)
|
||||
if ((descriptor->open_mode & O_RWMASK) == O_RDONLY
|
||||
&& flock.l_type == F_WRLCK
|
||||
|| (descriptor->open_mode & O_RWMASK) == O_WRONLY
|
||||
&& flock.l_type == F_RDLCK)
|
||||
status = B_FILE_ERROR;
|
||||
else
|
||||
status = acquire_advisory_lock(descriptor->u.vnode, &flock, op == F_SETLKW);
|
||||
else {
|
||||
status = acquire_advisory_lock(descriptor->u.vnode, -1,
|
||||
&flock, op == F_SETLKW);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -7287,6 +7324,43 @@ _user_fsync(int fd)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_user_flock(int fd, int op)
|
||||
{
|
||||
struct file_descriptor *descriptor;
|
||||
struct vnode *vnode;
|
||||
struct flock flock;
|
||||
status_t status;
|
||||
|
||||
FUNCTION(("_user_fcntl(fd = %d, op = %d)\n", fd, op));
|
||||
|
||||
descriptor = get_fd_and_vnode(fd, &vnode, false);
|
||||
if (descriptor == NULL)
|
||||
return B_FILE_ERROR;
|
||||
|
||||
if (descriptor->type != FDTYPE_FILE) {
|
||||
put_fd(descriptor);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
flock.l_start = 0;
|
||||
flock.l_len = OFF_MAX;
|
||||
flock.l_whence = 0;
|
||||
flock.l_type = (op & LOCK_SH) != 0 ? F_RDLCK : F_WRLCK;
|
||||
|
||||
if ((op & LOCK_UN) != 0)
|
||||
status = release_advisory_lock(descriptor->u.vnode, &flock);
|
||||
else {
|
||||
status = acquire_advisory_lock(descriptor->u.vnode,
|
||||
thread_get_current_thread()->team->session_id, &flock,
|
||||
(op & LOCK_NB) == 0);
|
||||
}
|
||||
|
||||
put_fd(descriptor);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_user_lock_node(int fd)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||
|
||||
MergeObject posix_sys.o :
|
||||
chmod.c
|
||||
flock.c
|
||||
ftime.c
|
||||
getrusage.c
|
||||
gettimeofday.c
|
||||
|
24
src/system/libroot/posix/sys/flock.c
Normal file
24
src/system/libroot/posix/sys/flock.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <syscalls.h>
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int
|
||||
flock(int fd, int op)
|
||||
{
|
||||
status_t status = _kern_flock(fd, op);
|
||||
if (status < B_OK) {
|
||||
errno = status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user