readdir和getdents接口 - 读取的字节数?

时间:2016-05-20 19:32:19

标签: c unix posix

我正在使用Cygwin,它没有实现getdents,也没有getdirentries

我正在处理的代码依赖于知道读取的字节数,这是这些调用的返回。我似乎只有readdir

Cygwin缺少手册页。关于如何使这些接口兼容,或者如何从readdir读取字节数的任何想法或现有文档?

Cygwin的struct dirent,如果相关的话:

struct dirent
{
  uint32_t __d_version;                 /* Used internally */
  ino_t d_ino;
  unsigned char d_type;
  unsigned char __d_unused1[3];
  __uint32_t __d_internal1;
  char d_name[NAME_MAX + 1];
};

修改

使用getdents的{​​{3}}位于函数readdir中(请参阅完整文件的链接):

static int
mygetdents(int fd, struct dirent *buf, int n) {
  return syscall (getdents, fd, (void*) buf, n);
}

long
dirread(int fd, Dir **dp)
{
    char *buf;
    struct stat st;
    int n;

    *dp = 0;

    if(fstat(fd, &st) < 0)
        return -1;

    if(st.st_blksize < 8192)
        st.st_blksize = 8192;

    buf = malloc(st.st_blksize);
    if(buf == nil)
        return -1;

    n = mygetdents(fd, (void*)buf, st.st_blksize);
    if(n < 0){
        free(buf);
        return -1;
    }
    n = dirpackage(fd, buf, n, dp);
    free(buf);
    return n;
}

static int
dirpackage(int fd, char *buf, int n, Dir **dp)
{
    int oldwd;
    char *p, *str, *estr;
    int i, nstr, m;
    struct dirent *de;
    struct stat st, lst;
    Dir *d;

    n = countde(buf, n);
    if(n <= 0)
        return n;

    if((oldwd = open(".", O_RDONLY)) < 0)
        return -1;
    if(fchdir(fd) < 0)
        return -1;

    p = buf;
    nstr = 0;

    for(i=0; i<n; i++){
        de = (struct dirent*)p;
        memset(&lst, 0, sizeof lst);
        if(de->d_name[0] == 0)
            /* nothing */ {}
        else if(lstat(de->d_name, &lst) < 0)
            de->d_name[0] = 0;
        else{
            st = lst;
            if(S_ISLNK(lst.st_mode))
                stat(de->d_name, &st);
            nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
        }
        p += de->d_reclen;
    }

    d = malloc(sizeof(Dir)*n+nstr);
    if(d == nil){
        fchdir(oldwd);
        close(oldwd);
        return -1;
    }
    str = (char*)&d[n];
    estr = str+nstr;

    p = buf;
    m = 0;
    for(i=0; i<n; i++){
        de = (struct dirent*)p;
        if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
            st = lst;
            if((lst.st_mode&S_IFMT) == S_IFLNK)
                stat(de->d_name, &st);
            _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
        }
        p += de->d_reclen;
    }

    fchdir(oldwd);
    close(oldwd);
    *dp = d;
    return m;
}

static int
countde(char *p, int n)
{
    char *e;
    int m;
    struct dirent *de;

    e = p+n;
    m = 0;
    while(p < e){
        de = (struct dirent*)p;
        if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
            break;
        if(de->d_name[0]=='.' && de->d_name[1]==0)
            de->d_name[0] = 0;
        else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
            de->d_name[0] = 0;
        m++;
        p += de->d_reclen;
    }
    return m;
}

我还没有理解dirpackage,但我认为如果我能以另一种方式获得getdents的回报,我可以解决这个问题

1 个答案:

答案 0 :(得分:1)

从您发布到dirpackage方法的链接:

for(i=0; i<n; i++){
    de = (struct dirent*)p;
    memset(&lst, 0, sizeof lst);
    if(de->d_name[0] == 0)
        /* nothing */ {}
    else if(lstat(de->d_name, &lst) < 0)
        de->d_name[0] = 0;
    else{
        st = lst;
        if(S_ISLNK(lst.st_mode))
            stat(de->d_name, &st);
        nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
    }
    p += de->d_reclen;
}

此处n来自:

n = countde(buf, n);

...从n系统调用的返回提供getdents的原始值。名称countde可能代表&#34;计算目录条目&#34;。

从循环中可以看出,countde的返回表示getdents调用返回的条目数。每次迭代循环都会处理一个目录条目(de = (struct dirent*)p;),然后找到下一个目录条目(p += de->d_reclen;)。

这应该非常简单地转换为使用readdir,因为它只返回一个条目。