STATIC off_t fat_seek(fs_handle handle, off_t off, int whence) { off_t curr_pos = (off_t) ((fat_file_handle *)handle)->pos; switch (whence) { case SEEK_SET: if (off < 0) return -EINVAL; /* invalid negative offset */ fat_rewind(handle); break; case SEEK_END: if (off >= 0) break; fat_file_handle *h = (fat_file_handle *) handle; off = (off_t) h->e->DIR_FileSize + off; if (off < 0) return -EINVAL; fat_rewind(handle); break; case SEEK_CUR: if (off < 0) { off = curr_pos + off; if (off < 0) return -EINVAL; fat_rewind(handle); } break; default: return -EINVAL; } return fat_seek_forward(handle, off); }
/* open a directory */ DIR * opendir(const char *dirname) { DEBUGF("opendir(dirname=\"%s\"\n", dirname); DIR *dirp = NULL; file_internal_lock_WRITER(); int rc; struct dirstr_desc * const dir = alloc_dirstr(); if (!dir) FILE_ERROR(EMFILE, RC); rc = open_stream_internal(dirname, FF_DIR, &dir->stream, NULL); if (rc < 0) { DEBUGF("Open failed: %d\n", rc); FILE_ERROR(ERRNO, RC); } #ifdef HAVE_MULTIVOLUME /* volume counter is relevant only to the system root */ dir->volumecounter = rc > 1 ? 0 : INT_MAX; #endif /* HAVE_MULTIVOLUME */ fat_rewind(&dir->stream.fatstr); rewinddir_dirent(&dir->scan); dirp = (DIR *)dir; file_error: file_internal_unlock_WRITER(); return dirp; }
/* actually do the open gruntwork */ static int open_internal_inner2(const char *path, struct filestr_desc *file, unsigned int callflags) { int rc; struct path_component_info compinfo; rc = open_stream_internal(path, callflags, &file->stream, &compinfo); if (rc < 0) { DEBUGF("Open failed: %d\n", rc); FILE_ERROR_RETURN(ERRNO, rc * 10 - 1); } bool created = false; if (rc > 0) { if (callflags & FF_EXCL) { DEBUGF("File exists\n"); FILE_ERROR(EEXIST, -2); } if (compinfo.attr & ATTR_DIRECTORY) { if ((callflags & FD_WRITE) || !(callflags & FF_ANYTYPE)) { DEBUGF("File is a directory\n"); FILE_ERROR(EISDIR, -3); } compinfo.filesize = MAX_DIRECTORY_SIZE; /* allow file ops */ } } else if (callflags & FF_CREAT) { if (compinfo.attr & ATTR_DIRECTORY) { DEBUGF("File is a directory\n"); FILE_ERROR(EISDIR, -5); } /* not found; try to create it */ callflags &= ~FO_TRUNC; rc = create_stream_internal(&compinfo.parentinfo, compinfo.name, compinfo.length, ATTR_NEW_FILE, callflags, &file->stream); if (rc < 0) FILE_ERROR(ERRNO, rc * 10 - 6); created = true; } else { DEBUGF("File not found\n"); FILE_ERROR(ENOENT, -7); } fat_rewind(&file->stream.fatstr); file->sizep = fileobj_get_sizep(&file->stream); file->offset = 0; if (!created) { /* size from storage applies to first stream only otherwise it's already up to date */ const bool first = fileobj_get_flags(&file->stream) & FO_SINGLE; if (first) *file->sizep = compinfo.filesize; if (callflags & FO_TRUNC) { /* if the file is kind of "big" then free some space now */ rc = ftruncate_internal(file, 0, *file->sizep >= O_TRUNC_THRESH); if (rc < 0) { DEBUGF("O_TRUNC failed: %d\n", rc); FILE_ERROR(ERRNO, rc * 10 - 4); } } } rc = 0; file_error: if (rc < 0) close_stream_internal(&file->stream); return rc; }