⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ulockmgr.c

📁 Linux下fuse用户文件系统的的源代码
💻 C
字号:
/*    libulockmgr: Userspace Lock Manager Library    Copyright (C) 2006  Miklos Szeredi <miklos@szeredi.hu>    This program can be distributed under the terms of the GNU LGPL.    See the file COPYING.LIB*//* #define DEBUG 1 */#include "ulockmgr.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <errno.h>#include <assert.h>#include <signal.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/wait.h>struct message {    unsigned intr : 1;    unsigned nofd : 1;    pthread_t thr;    int cmd;    int fd;    struct flock lock;    int error;};struct fd_store {    struct fd_store *next;    int fd;    int inuse;};struct owner {    struct owner *next;    struct owner *prev;    struct fd_store *fds;    void *id;    size_t id_len;    int cfd;};static pthread_mutex_t ulockmgr_lock;static int ulockmgr_cfd = -1;static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };#define MAX_SEND_FDS 2static void list_del_owner(struct owner *owner){    struct owner *prev = owner->prev;    struct owner *next = owner->next;    prev->next = next;    next->prev = prev;}static void list_add_owner(struct owner *owner, struct owner *next){    struct owner *prev = next->prev;    owner->next = next;    owner->prev = prev;    prev->next = owner;    next->prev = owner;}static int ulockmgr_send_message(int sock, void *buf, size_t buflen,                                 int *fdp, int numfds){    struct msghdr msg;    struct cmsghdr *p_cmsg;    struct iovec vec;    size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];    int res;    assert(numfds <= MAX_SEND_FDS);    msg.msg_control = cmsgbuf;    msg.msg_controllen = sizeof(cmsgbuf);    p_cmsg = CMSG_FIRSTHDR(&msg);    p_cmsg->cmsg_level = SOL_SOCKET;    p_cmsg->cmsg_type = SCM_RIGHTS;    p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);    memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);    msg.msg_controllen = p_cmsg->cmsg_len;    msg.msg_name = NULL;    msg.msg_namelen = 0;    msg.msg_iov = &vec;    msg.msg_iovlen = 1;    msg.msg_flags = 0;    vec.iov_base = buf;    vec.iov_len = buflen;    res = sendmsg(sock, &msg, MSG_NOSIGNAL);    if (res == -1) {        perror("libulockmgr: sendmsg");        return -1;    }    if ((size_t) res != buflen) {        fprintf(stderr, "libulockmgr: sendmsg short\n");        return -1;    }    return 0;}static int ulockmgr_start_daemon(void){    int sv[2];    int res;    char tmp[64];    res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);    if (res == -1) {        perror("libulockmgr: socketpair");        return -1;    }    snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);    res = system(tmp);    close(sv[0]);    if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {        close(sv[1]);        return -1;    }    ulockmgr_cfd = sv[1];    return 0;}static struct owner *ulockmgr_new_owner(const void *id, size_t id_len){    int sv[2];    int res;    char c = 'm';    struct owner *o;    if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)        return NULL;    o = calloc(1, sizeof(struct owner) + id_len);    if (!o) {        fprintf(stderr, "libulockmgr: failed to allocate memory\n");        return NULL;    }    o->id = o + 1;    o->id_len = id_len;    res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);    if (res == -1) {        perror("libulockmgr: socketpair");        goto out_free;    }    res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);    close(sv[0]);    if (res == -1) {        close(ulockmgr_cfd);        ulockmgr_cfd = -1;        goto out_close;    }    o->cfd = sv[1];    memcpy(o->id, id, id_len);    list_add_owner(o, &owner_list);    return o; out_close:    close(sv[1]); out_free:    free(o);    return NULL;}static int ulockmgr_send_request(struct message *msg, const void *id,                                 size_t id_len){    int sv[2];    int cfd;    struct owner *o;    struct fd_store *f = NULL;    struct fd_store *newf = NULL;    struct fd_store **fp;    int fd = msg->fd;    int cmd = msg->cmd;    int res;    int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&                     msg->lock.l_start == 0 && msg->lock.l_len == 0);    for (o = owner_list.next; o != &owner_list; o = o->next)        if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)            break;    if (o == &owner_list)        o = NULL;    if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)        o = ulockmgr_new_owner(id, id_len);    if (!o) {        if (cmd == F_GETLK) {            res = fcntl(msg->fd, F_GETLK, &msg->lock);            return (res == -1) ? -errno : 0;        } else if (msg->lock.l_type == F_UNLCK)            return 0;        else            return -ENOLCK;    }    if (unlockall)        msg->nofd = 1;    else {        for (fp = &o->fds; *fp; fp = &(*fp)->next) {            f = *fp;            if (f->fd == fd) {                msg->nofd = 1;                break;            }        }    }    if (!msg->nofd) {        newf = f = calloc(1, sizeof(struct fd_store));        if (!f) {            fprintf(stderr, "libulockmgr: failed to allocate memory\n");            return -ENOLCK;        }    }    res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);    if (res == -1) {        perror("libulockmgr: socketpair");        free(newf);        return -ENOLCK;    }    cfd = sv[1];    sv[1] = msg->fd;    res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,                                msg->nofd ? 1 : 2);    close(sv[0]);    if (res == -1) {        free(newf);        close(cfd);        return -EIO;    }    if (newf) {        newf->fd = msg->fd;        newf->next = o->fds;        o->fds = newf;    }    if (f)        f->inuse++;    res = recv(cfd, msg, sizeof(struct message), MSG_WAITALL);    if (res == -1) {        perror("libulockmgr: recv");        msg->error = EIO;    } else if (res != sizeof(struct message)) {        fprintf(stderr, "libulockmgr: recv short\n");        msg->error = EIO;    } else if (cmd == F_SETLKW && msg->error == EAGAIN) {        pthread_mutex_unlock(&ulockmgr_lock);        while (1) {            sigset_t old;            sigset_t unblock;            int errno_save;            sigemptyset(&unblock);            sigaddset(&unblock, SIGUSR1);            pthread_sigmask(SIG_UNBLOCK, &unblock, &old);            res = recv(cfd, msg, sizeof(struct message), MSG_WAITALL);            errno_save = errno;            pthread_sigmask(SIG_SETMASK, &old, NULL);            if (res == sizeof(struct message))                break;            else if (res >= 0) {                fprintf(stderr, "libulockmgr: recv short\n");                msg->error = EIO;                break;            } else if (errno_save != EINTR) {                errno = errno_save;                perror("libulockmgr: recv");                msg->error = EIO;                break;            }            msg->intr = 1;            res = send(o->cfd, msg, sizeof(struct message), MSG_NOSIGNAL);            if (res == -1) {                perror("libulockmgr: send");                msg->error = EIO;                break;            }            if (res != sizeof(struct message)) {                fprintf(stderr, "libulockmgr: send short\n");                msg->error = EIO;                break;            }        }        pthread_mutex_lock(&ulockmgr_lock);    }    if (f)        f->inuse--;    close(cfd);    if (unlockall) {        for (fp = &o->fds; *fp;) {            f = *fp;            if (f->fd == fd && !f->inuse) {                *fp = f->next;                free(f);            } else                fp = &f->next;        }        if (!o->fds) {            list_del_owner(o);            close(o->cfd);            free(o);        }        /* Force OK on unlock-all, since it _will_ succeed once the           owner is deleted */        msg->error = 0;    }    return -msg->error;}#ifdef DEBUGstatic uint32_t owner_hash(const unsigned char *id, size_t id_len){    uint32_t h = 0;    size_t i;    for (i = 0; i < id_len; i++)        h = ((h << 8) | (h >> 24)) ^ id[i];    return h;}#endifstatic int ulockmgr_canonicalize(int fd, struct flock *lock){    off_t offset;    if (lock->l_whence == SEEK_CUR) {        offset = lseek(fd, 0, SEEK_CUR);        if (offset == (off_t) -1)            return -errno;    } else if (lock->l_whence == SEEK_END) {        struct stat stbuf;        int res = fstat(fd, &stbuf);        if (res == -1)            return -errno;        offset = stbuf.st_size;    } else        offset = 0;    lock->l_whence = SEEK_SET;    lock->l_start += offset;    if (lock->l_start < 0)        return -EINVAL;    if (lock->l_len < 0) {        lock->l_start += lock->l_len;        if (lock->l_start < 0)            return -EINVAL;        lock->l_len = -lock->l_len;    }    if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)        return -EINVAL;    return 0;}int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,                size_t owner_len){    int err;    struct message msg;    sigset_t old;    sigset_t block;    if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)        return -EINVAL;    if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&        lock->l_whence != SEEK_END)        return -EINVAL;#ifdef DEBUG    fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",            cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,            owner_hash(owner, owner_len));#endif    /* Unlock should never block anyway */    if (cmd == F_SETLKW && lock->l_type == F_UNLCK)        cmd = F_SETLK;    memset(&msg, 0, sizeof(struct message));    msg.cmd = cmd;    msg.fd = fd;    msg.lock = *lock;    err = ulockmgr_canonicalize(fd, &msg.lock);    if (err)        return err;    sigemptyset(&block);    sigaddset(&block, SIGUSR1);    pthread_sigmask(SIG_BLOCK, &block, &old);    pthread_mutex_lock(&ulockmgr_lock);    err = ulockmgr_send_request(&msg, owner, owner_len);    pthread_mutex_unlock(&ulockmgr_lock);    pthread_sigmask(SIG_SETMASK, &old, NULL);    if (!err && cmd == F_GETLK) {        if (msg.lock.l_type == F_UNLCK)            lock->l_type = F_UNLCK;        else            *lock = msg.lock;    }    return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -