shithub: drawcpu

ref: 50d01b2e88713afb5a1276849b1ae75389263986
dir: /kern/devlfd-posix.c/

View raw version
#include "u.h"
#include <errno.h>
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"

#undef read
#undef write

Chan*
lfdchan(void *fd)
{
    Chan *c;
    
    c = newchan();
    c->type = devno('L');
    c->aux = fd;
    c->path = newpath("/fd");
    c->mode = ORDWR;
    c->qid.type = QTFILE;
    c->qid.path = (uintptr)fd;  /* Use fd number as qid.path */
    c->qid.vers = 0;
    c->dev = 0;
    c->offset = 0;
    return c;
}

int
lfdfd(int fd)
{
    Fgrp *fg = up->fgrp;
    Chan *c;

    /* Check if fd is valid */
    if(fd < 0 || fd >= fg->nfd || fg->fd[fd] == nil) {
        c = lfdchan((void*)(uintptr)fd);
        lock(&fg->ref.lk);
        if(fd >= fg->nfd) {
            int newnfd = fd + DELTAFD;
            Chan **newfd = smalloc(newnfd * sizeof(Chan*));
            if(fg->nfd > 0)
                memmove(newfd, fg->fd, fg->nfd * sizeof(Chan*));
            free(fg->fd);
            fg->fd = newfd;
            fg->nfd = newnfd;
        }
        fg->fd[fd] = c;
        if(fd > fg->maxfd)
            fg->maxfd = fd;
        unlock(&fg->ref.lk);
    } else {
        c = fg->fd[fd];
    }
    return newfd(c);
}

static int
fdgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
{
    Fgrp *fg = up->fgrp;
    int fd;

    if(s == DEVDOTDOT) {
        devdir(c, c->qid, "#L", 0, eve, DMDIR|0775, dp);
        return 1;
    }

    lock(&fg->ref.lk);
    if(name) {
        /* Look up by name (e.g., "0", "1", "2", etc.) */
        char *end;
        fd = strtol(name, &end, 10);
        if(*end != '\0' || fd < 0 || fd >= fg->nfd || fg->fd[fd] == nil) {
            unlock(&fg->ref.lk);
            return -1;  /* Invalid or closed fd */
        }
    } else {
        /* Generate by index, starting with 0, 1, 2, then others up to maxfd */
        for(fd = 0; fd <= fg->maxfd && s >= 0; fd++) {
            if(fd >= fg->nfd || fg->fd[fd] == nil)
                continue;
            if(s-- == 0)
                break;
        }
        if(fd > fg->maxfd || fg->fd[fd] == nil) {
            unlock(&fg->ref.lk);
            return -1;
        }
    }

    sprint(up->genbuf, "%d", fd);
    devdir(c, fg->fd[fd]->qid, up->genbuf, 0, eve, 0666, dp);
    unlock(&fg->ref.lk);
    return 1;
}

static Chan*
lfdattach(char *spec)
{
    Chan *c;

    if(spec && *spec)
        error(Ebadarg);
    c = devattach('L', spec);
    c->qid.type = QTDIR;
    c->qid.path = 0;
    return c;
}

static Walkqid*
lfdwalk(Chan *c, Chan *nc, char **name, int nname)
{
    return devwalk(c, nc, name, nname, nil, 0, fdgen);
}

static int
lfdstat(Chan *c, uchar *db, int n)
{
    return devstat(c, db, n, nil, 0, fdgen);
}

static Chan*
lfdopen(Chan *c, int omode)
{
    Fgrp *fg = up->fgrp;
    int fd;

    if(c->qid.type & QTDIR) {
        if(omode != OREAD)
            error(Eperm);
        c->mode = openmode(omode);
        c->flag |= COPEN;
        c->offset = 0;
        return c;
    }

    lock(&fg->ref.lk);
    fd = (int)c->qid.path;  /* qid.path stores the fd number */
    if(fd < 0 || fd >= fg->nfd || fg->fd[fd] == nil) {
        unlock(&fg->ref.lk);
        error(Enonexist);
    }

    c->mode = openmode(omode);
    c->flag |= COPEN;
    c->offset = 0;
    c->aux = (void*)(uintptr)fd;
    unlock(&fg->ref.lk);
    return c;
}

static void
lfdclose(Chan *c)
{
    Fgrp *fg = up->fgrp;
    int fd;

    if(c->qid.type & QTDIR)
        return;

    lock(&fg->ref.lk);
    fd = (int)c->qid.path;
    if(fd >= 0 && fd < fg->nfd && fg->fd[fd] != nil) {
        close(fd);
        fg->fd[fd] = nil;
        if(fd == fg->maxfd) {
            while(fg->maxfd > 0 && fg->fd[fg->maxfd] == nil)
                fg->maxfd--;
        }
    }
    unlock(&fg->ref.lk);
}

static long
lfdread(Chan *c, void *buf, long n, vlong off)
{
    USED(off);  /* Can't pread on pipes */
    if(c->qid.type & QTDIR)
        return devdirread(c, buf, n, nil, 0, fdgen);

    n = read((int)(uintptr)c->aux, buf, n);
    if(n < 0)
        oserror();
    return n;
}

static long
lfdwrite(Chan *c, void *buf, long n, vlong off)
{
    USED(off);  /* Can't pwrite on pipes */
    n = write((int)(uintptr)c->aux, buf, n);
    if(n < 0)
        oserror();
    return n;
}

Dev lfddevtab = {
    'L',
    "lfd",
    
    devreset,
    devinit,
    devshutdown,
    lfdattach,
    lfdwalk,
    lfdstat,
    lfdopen,
    devcreate,
    lfdclose,
    lfdread,
    devbread,
    lfdwrite,
    devbwrite,
    devremove,
    devwstat,
};