int dup(int oldfn) { filedesc *newfd = filedesc_alloc(); if (!newfd) return -1; return dup2(oldfn, newfd - files->fd); }
FILE * fopen(const char *path, const char *mode) { // Find an unused file descriptor and use it for the open FILE *fd = filedesc_alloc(); if (fd == NULL) return NULL; return freopen(path, mode, fd); }
// Find or create and open a file, optionally using a given file descriptor. // The argument 'fd' must point to a currently unused file descriptor, // or may be NULL, in which case this function finds an unused file descriptor. // The 'openflags' determines whether the file is created, truncated, etc. // Returns the opened file descriptor on success, // or returns NULL and sets errno on failure. filedesc * filedesc_open(filedesc *fd, const char *path, int openflags, mode_t mode) { if (!fd && !(fd = filedesc_alloc())) return NULL; assert(fd->ino == FILEINO_NULL); // Determine the complete file mode if it is to be created. mode_t createmode = (openflags & O_CREAT) ? S_IFREG | (mode & 0777) : 0; // Walk the directory tree to find the desired directory entry, // creating an entry if it doesn't exist and O_CREAT is set. int ino = dir_walk(path, createmode); if (ino < 0) return NULL; assert(fileino_exists(ino)); // Refuse to open conflict-marked files; // the user needs to resolve the conflict and clear the conflict flag, // or just delete the conflicted file. if (files->fi[ino].mode & S_IFCONF) { errno = ECONFLICT; return NULL; } // Truncate the file if we were asked to if (openflags & O_TRUNC) { if (!(openflags & O_WRONLY)) { warn("filedesc_open: can't truncate non-writable file"); errno = EINVAL; return NULL; } if (fileino_truncate(ino, 0) < 0) return NULL; } // Initialize the file descriptor fd->ino = ino; fd->flags = openflags; fd->ofs = (openflags & O_APPEND) ? files->fi[ino].size : 0; fd->err = 0; assert(filedesc_isopen(fd)); return fd; }