/*
* To avoid deadlock, the following rules must be followed.
* Always lock child then parent, never parent then child.
* If holding the free file lock, do not lock any Files.
*/
struct Filelist
{
File *f;
Filelist *link;
};
struct Readdir
{
File *dir;
Filelist *fl;
};
static QLock filelk;
static File *freefilelist;
static File*
allocfile(void)
{
int i, a;
File *f;
enum { N = 16 };
/*
* can't delete filelist structures while there
* are open readers of this directory, because
* they might have references to the structures.
* instead, just leave the empty refs in the list
* until there is no activity and then clean up.
*/
if(f->readers.ref != 0)
return;
if(f->nxchild == 0)
return;
/*
* no dir readers, file is locked, and
* there are empty entries in the file list.
* clean them out.
*/
for(l=&f->filelist; fl=*l; ){
if(fl->f == nil){
*l = (*l)->link;
free(fl);
}else
l = &(*l)->link;
}
f->nxchild = 0;
}
/*
* We might encounter blank spots along the
* way due to deleted files that have not yet
* been flushed from the file list. Don't reuse
* those - some apps (e.g., omero) depend on
* the file order reflecting creation order.
* Always create at the end of the list.
*/
for(l=&fp->filelist; fl=*l; l=&fl->link){
if(fl->f && strcmp(fl->f->name, name) == 0){
wunlock(fp);
werrstr("file already exists");
return nil;
}
}
/*
* This reference won't go away while we're
* using it because file list entries are not freed
* until the directory is removed and all refs to
* it (our fid is one!) have gone away.
*/
r->fl = dir->filelist;
r->dir = dir;
incref(&dir->readers);
runlock(dir);
return r;
}
long
readdirfile(Readdir *r, uchar *buf, long n, long o)
{
long x, m;
Filelist *fl;