ref: 6ca7a7fcb03e0ef651368e5a782b29c392e16149
dir: /kern/devlfd-posix.c/
#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,
};