#include <assert.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/queue.h>
#include "sysio.h"
#include "file.h"
#include "inode.h"
-#include "xtio.h"
/*
* Support for file IO.
return NULL;
_SYSIO_FINIT(fil, ino, flags);
+ F_REF(fil);
I_REF(ino);
return fil;
assert(!fil->f_ref);
assert(fil->f_ino);
err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino);
+ I_RELE(fil->f_ino);
assert(!err);
free(fil);
}
return 0;
}
-#if ZERO_SUM_MEMORY
+#ifdef ZERO_SUM_MEMORY
static void free_oftab(oftab_t *ot)
{
if (ot->table) {
#endif
/*
- * Find a free slot in the open files table.
- * target < 0: any free slot
- * target >= 0: get slot [target]
+ * Find a free slot in the open files table which >= @low
+ * low < 0 means any
*/
static int
-find_free_fildes(oftab_t *oftab, int target)
+find_free_fildes(oftab_t *oftab, int low)
{
int n;
int err;
struct file **filp;
- if (target < 0) {
- for (n = 0, filp = oftab->table;
- n < oftab->size && *filp;
- n++, filp++)
- ;
- } else
- n = target - oftab->offset;
+ if (low < 0)
+ low = oftab->offset;
+
+ n = low - oftab->offset;
+ if (n < 0)
+ return -ENFILE;
+
+ for (filp = oftab->table + n;
+ n < oftab->size && *filp;
+ n++, filp++)
+ ;
if (n >= oftab->size) {
err = fd_grow(oftab, n);
assert(!*filp);
}
-#ifdef HAVE_LUSTRE_HACK
- /* FIXME sometimes we could intercept open/socket to create
- * a fd, but missing close()? currently we have this problem
- * with resolv lib. as a workaround simply destroy the file
- * struct here.
- */
- if (oftab->table[n]) {
- free(oftab->table[n]);
- oftab->table[n] = NULL;
- }
-#endif
-
return oftab->offset + n;
}
}
/*
- * Associate open file record with given file descriptor or any available
- * file descriptor if less than zero.
+ * Associate open file record with given file descriptor (if forced), or any
+ * available file descriptor if less than zero, or any available descriptor
+ * greater than or equal to the given one if not forced.
*/
int
-_sysio_fd_set(struct file *fil, int fd)
+_sysio_fd_set(struct file *fil, int fd, int force)
{
int err;
struct file *ofil;
oftab_t *oftab;
+ if (force && fd < 0)
+ abort();
+
init_oftab();
oftab = select_oftab(fd);
/*
- * New fd < 0 => any available descriptor.
+ * Search for a free descriptor if needed.
*/
- fd = find_free_fildes(oftab, fd);
- if (fd < 0)
- return fd;
+ if (!force) {
+ fd = find_free_fildes(oftab, fd);
+ if (fd < 0)
+ return fd;
+ }
- assert(fd < oftab->offset + oftab->size);
+ if (fd - oftab->offset >= oftab->size) {
+ err = fd_grow(oftab, fd - oftab->offset);
+ if (err)
+ return err;
+ }
/*
* Remember old.
*/
ofil = __sysio_fd_get(fd, 1);
- if (ofil)
- F_RELE(ofil);
+ if (ofil) {
+ /* FIXME sometimes we could intercept open/socket to create
+ * a fd, but missing close()? currently we have this problem
+ * with resolv lib. as a workaround simply destroy the file
+ * struct here. And this hack will break the behavior of
+ * DUPFD.
+ */
+ if (fd >= 0 && oftab == &_sysio_oftab[0])
+ free(ofil);
+ else
+ F_RELE(ofil);
+ }
oftab->table[fd - oftab->offset] = fil;
* Duplicate old file descriptor.
*
* If the new file descriptor is less than zero, the new file descriptor
- * is chosen freely.
+ * is chosen freely. Otherwise, choose an available descriptor greater
+ * than or equal to the new, if not forced. Otherwise, if forced, (re)use
+ * the new.
*/
int
-_sysio_fd_dup2(int oldfd, int newfd)
+_sysio_fd_dup(int oldfd, int newfd, int force)
{
struct file *fil;
int fd;
init_oftab();
- if (oldfd == newfd)
- return 0;
+ if (oldfd == newfd && oldfd >= 0)
+ return newfd;
fil = _sysio_fd_find(oldfd);
if (!fil)
if (select_oftab(oldfd) != select_oftab(newfd))
return -EINVAL;
- fd = _sysio_fd_set(fil, newfd);
+ fd = _sysio_fd_set(fil, newfd, force);
if (fd >= 0)
F_REF(fil);
return fd;