📄 fs_native.c
字号:
ident.dev = stbp->st_dev; ident.ino = stbp->st_ino;#ifdef HAVE_GENERATION ident.gen = stbp->st_gen;#endif fileid.fid_data = &ident; fileid.fid_len = sizeof(ident); ino = _sysio_i_find(fs, &fileid); if (ino) { ino->i_stbuf = *stbp; I2NI(ino)->ni_attrtim = expire; return ino; } return native_i_new(fs, expire, stbp);}/* * Find, and validate, or create i-node by host-relative path. Returned i-node * is referenced. */static intnative_ibind(struct filesys *fs, char *path, time_t t, struct inode **inop){ struct intnl_stat ostbuf, stbuf; int err; struct inode *ino; if (*inop) ostbuf = (*inop)->i_stbuf; err = native_stat(path, *inop, t, &stbuf); if (err) return err; /* * Validate? */ if (*inop) { if (!native_i_invalid(*inop, &ostbuf)) return 0; /* * Invalidate. */ _sysio_i_undead(*inop); *inop = NULL; } if (!(ino = native_iget(fs, t + FS2NFS(fs)->nfs_atimo, &stbuf))) return -ENOMEM; *inop = ino; return 0;}static intnative_inop_lookup(struct pnode *pno, struct inode **inop, struct intent *intnt __IS_UNUSED, const char *path __IS_UNUSED){ time_t t; char *fqpath; struct filesys *fs; int err; *inop = pno->p_base->pb_ino; /* * Try to use the cached attributes unless the intent * indicates we are looking up the last component and * caller wants attributes. In that case, force a refresh. */ t = _SYSIO_LOCAL_TIME(); if (*inop && (path || !intnt || (intnt->int_opmask & INT_GETATTR) == 0) && NATIVE_ATTRS_VALID(I2NI(*inop), t)) return 0; /* * Don't have an inode yet. Because we translate everything back to * a single name space for the host, we will assume the object the * caller is looking for has no existing alias in our internal * name space. We don't see the same file on different mounts in the * underlying host FS as the same file. * * The file identifier *will* be unique. It's got to have a different * dev. */ fqpath = _sysio_pb_path(pno->p_base, '/'); if (!fqpath) return -ENOMEM; fs = pno->p_mount->mnt_fs; err = native_ibind(fs, fqpath, t + FS2NFS(fs)->nfs_atimo, inop); free(fqpath); if (err) *inop = NULL; return err;}static intnative_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stat){ struct native_inode *nino; int err; /* * We just cannot use the cached attributes when getattr is * called. Had the caller felt those were sufficient then * they could have (would have?) simply used what was cached * after revalidating. In this case, there's a good chance the * caller is looking for the current time stamps and/or size. Something * pretty volatile anyway. */ err = 0; /* compiler cookie */ if (pno) { char *path; struct filesys *fs; time_t t; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; fs = pno->p_mount->mnt_fs; t = _SYSIO_LOCAL_TIME(); err = native_stat(path, ino, t + FS2NFS(fs)->nfs_atimo, stat); free(path); } else if ((nino = I2NI(ino))->ni_fd >= 0) /* * Don't have access to the fs record anymore. Just * refresh but keep the current timeout. */ err = native_stat(NULL, ino, nino->ni_attrtim, stat); else { /* * Dev inodes don't open in this driver. We won't have * a file descriptor with which to do the deed then. Satisfy * the request from the cached copy of the attributes. */ (void )memcpy(stat, &ino->i_stbuf, sizeof(struct intnl_stat)); err = 0; } return err;}#ifdef SYSIO_SYS_utimestatic int_ut(const char *path, time_t actime, time_t modtime){ struct utimbuf ut; ut.actime = actime; ut.modtime = modtime; return syscall(SYSIO_SYS_utime, path, &ut);}#elsestatic int_ut(const char *path, time_t actime, time_t modtime){ struct timeval tv[2]; tv[0].tv_sec = actime; tv[0].tv_usec = 0; tv[1].tv_sec = modtime; tv[1].tv_usec = 0; return syscall(SYSIO_SYS_utimes, path, &tv);}#endifstatic intnative_inop_setattr(struct pnode *pno, struct inode *ino, unsigned mask, struct intnl_stat *stat){ char *path; struct native_inode *nino; int fd; int err; path = NULL; nino = ino ? I2NI(ino) : NULL; fd = -1; if (nino) fd = nino->ni_fd; if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) { if (!pno) return -EEXIST; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; } /* * Get current status for undo. */ err = native_stat(path, ino, 0, NULL); if (err) goto out; if (mask & SETATTR_MODE) { mode_t mode; /* * Alter permissions attribute. */ mode = stat->st_mode & 07777; err = fd < 0 ? syscall(SYSIO_SYS_chmod, path, mode) : syscall(SYSIO_SYS_fchmod, fd, mode); if (err) err = -errno; } if (err) mask &= ~SETATTR_MODE; else if (mask & (SETATTR_MTIME|SETATTR_ATIME)) { time_t actime, modtime; /* * Alter access and/or modify time attributes. */ actime = ino->i_stbuf.st_atime; modtime = ino->i_stbuf.st_mtime; if (mask & SETATTR_ATIME) actime = stat->st_atime; if (mask & SETATTR_MTIME) modtime = stat->st_mtime; if (_ut(path, actime, modtime) != 0) return -errno; } if (err) mask &= ~(SETATTR_MTIME|SETATTR_ATIME); else if (mask & (SETATTR_UID|SETATTR_GID)) { /* * Alter owner and/or group identifiers. */ err = fd < 0 ? syscall(SYSIO_SYS_chown, path, mask & SETATTR_UID ? stat->st_uid : (uid_t )-1, mask & SETATTR_GID ? stat->st_gid : (gid_t )-1) : syscall(SYSIO_SYS_fchown, fd, mask & SETATTR_UID ? stat->st_uid : (uid_t )-1, mask & SETATTR_GID ? stat->st_gid : (gid_t )-1); if (err) err = -errno; } if (err) mask &= ~(SETATTR_UID|SETATTR_GID); else if (mask & SETATTR_LEN) { /* * Do the truncate last. It can't be undone. */ err = fd < 0 ? syscall(SYSIO_SYS_truncate, path, stat->st_size) : syscall(SYSIO_SYS_ftruncate, fd, stat->st_size); if (err) err = -errno; } if (!err) goto out; /* * Undo after error. Some or all of this might not work... We * can but try. */ if (mask & (SETATTR_UID|SETATTR_GID)) { (void )(fd < 0 ? syscall(SYSIO_SYS_chown, path, mask & SETATTR_UID ? ino->i_stbuf.st_uid : (uid_t )-1, mask & SETATTR_GID ? ino->i_stbuf.st_gid : (gid_t )-1) : syscall(SYSIO_SYS_fchown, fd, mask & SETATTR_UID ? ino->i_stbuf.st_uid : (uid_t )-1, mask & SETATTR_GID ? ino->i_stbuf.st_gid : (gid_t )-1)); } if (mask & (SETATTR_MTIME|SETATTR_ATIME)) (void )_ut(path, ino->i_stbuf.st_atime, ino->i_stbuf.st_mtime); if (mask & SETATTR_MODE) { fd < 0 ? syscall(SYSIO_SYS_chmod, path, ino->i_stbuf.st_mode & 07777) : syscall(SYSIO_SYS_fchmod, ino->i_stbuf.st_mode & 07777); }out: /* * We must refresh the cached attributes. */ if (!err && native_stat(path, ino, _SYSIO_LOCAL_TIME(), NULL) != 0) abort(); if (path) free(path); return err;}static intnative_pos(int fd, _SYSIO_OFF_T *offset, int whence){ _SYSIO_OFF_T off; assert(fd >= 0); assert(*offset >= 0); off = *offset;#if defined(_LARGEFILE64_SOURCE) && defined(SYSIO_SYS__llseek) { int err; err = syscall(SYSIO_SYS__llseek, (unsigned int)fd, (unsigned int)(off >> 32), (unsigned int)off, &off, whence); if (err == -1) return -errno; }#else off = syscall(SYSIO_SYS_lseek, fd, off, whence); if (off == -1) return -errno;#endif *offset = off; return 0;}static ssize_tnative_ifilldirentries(struct native_inode *nino, _SYSIO_OFF_T *posp, char *buf, size_t nbytes){ int err; ssize_t cc;#if defined(SYSIO_SYS_getdirentries) _SYSIO_OFF_T waste=*posp;#endif if (*posp < 0) return -EINVAL; /* * Stream-oriented access requires that we reposition prior to the * fill call. */ assert(nino->ni_seekok); if (*posp != nino->ni_fpos || nino->ni_resetfpos) { nino->ni_fpos = *posp; err = native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_SET); if (err) { nino->ni_resetfpos = 1; return err; } nino->ni_resetfpos = 0; } cc =#if defined(SYSIO_SYS_getdirentries) syscall(SYSIO_SYS_getdirentries, nino->ni_fd, buf, nbytes, &waste);#elif defined(SYSIO_SYS_getdents64) syscall(SYSIO_SYS_getdents64, nino->ni_fd, buf, nbytes);#elif defined(SYSIO_SYS_getdents) syscall(SYSIO_SYS_getdents, nino->ni_fd, buf, nbytes);#endif if (cc < 0) return -errno; /* * Stream-oriented access requires that we discover where we are * after the call. */ if ((err = native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR)) != 0) { /* * Leave the position at the old I suppose. */ nino->ni_resetfpos = 1; return err; } *posp = nino->ni_fpos; return cc;}static ssize_tnative_filldirentries(struct inode *ino, _SYSIO_OFF_T *posp, char *buf, size_t nbytes){ struct native_inode *nino = I2NI(ino);#if DIR_CVT_64 char *bp; size_t count; struct linux_dirent *ldp; struct dirent64 *d64p; size_t namlen; size_t reclen;#else#define bp buf#define count nbytes#endif ssize_t cc; assert(nino->ni_fd >= 0);#if DIR_CVT_64 count = nbytes; while (!(bp = malloc(count))) { count /= 2; if (count < sizeof(struct dirent)) return -ENOMEM; }#endif cc = native_ifilldirentries(nino, posp, bp, count); if (cc < 0) {#if DIR_CVT_64 free(bp);#endif return cc; }#if DIR_CVT_64 ldp = (struct linux_dirent *)bp; d64p = (struct dirent64 *)buf; while (cc) { namlen = strlen(ldp->ld_name); reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen; if (nbytes <= reclen) break; d64p->d_ino = ldp->ld_ino; d64p->d_off = nino->ni_fpos = ldp->ld_off; d64p->d_reclen = (((reclen + sizeof(long))) / sizeof(long)) * sizeof(long); if (nbytes < d64p->d_reclen) d64p->d_reclen = reclen + 1; d64p->d_type = DT_UNKNOWN; /* you lose -- sorry. */ (void )memcpy(d64p->d_name, ldp->ld_name, namlen); /* * Zero pad the rest. */ for (cp = d64p->d_name + namlen, n = d64p->d_reclen - reclen; n; n--) *cp++ = 0; cc -= ldp->ld_reclen; ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen); nbytes -= d64p->d_reclen; d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen); } free(bp); cc = (d64p == (struct dirent64 *)buf && cc) ? -EINVAL : (char *)d64p - buf;#else#undef bp#undef count#endif return cc;}static intnative_inop_mkdir(struct pnode *pno, mode_t mode){ char *path; int err; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; err = syscall(SYSIO_SYS_mkdir, path, mode); if (err != 0) err = -errno; free(path); return err;}static intnative_inop_rmdir(struct pnode *pno){ char *path; int err; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; err = syscall(SYSIO_SYS_rmdir, path); if (err != 0) err = -errno; free(path); return err;}static intnative_inop_symlink(struct pnode *pno, const char *data){ char *path; int err; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; err = syscall(SYSIO_SYS_symlink, data, path); if (err != 0) err = -errno; free(path); return err;}static intnative_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz){ char *path; int i; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; i = syscall(SYSIO_SYS_readlink, path, buf, bufsiz); if (i < 0) i = -errno; free(path); return i;}static int native_inop_open(struct pnode *pno, int flags, mode_t mode){ struct native_inode *nino; char *path; int fd; path = _sysio_pb_path(pno->p_base, '/'); if (!path) return -ENOMEM; /* * Whether the file is already open, or not, makes no difference. * Want to always give the host OS a chance to authorize in case * something has changed underneath us. */ if (flags & O_WRONLY) { /* * Promote write-only attempt to RW. */ flags &= ~O_WRONLY; flags |= O_RDWR; }#ifdef O_LARGEFILE flags |= O_LARGEFILE;#endif fd = syscall(SYSIO_SYS_open, path, flags, mode); if (!pno->p_base->pb_ino && fd >= 0) { struct filesys *fs; int err; /* * Success but we need to return an i-node. */ fs = pno->p_mount->mnt_fs; err = native_ibind(fs, path, _SYSIO_LOCAL_TIME() + FS2NFS(fs)->nfs_atimo, &pno->p_base->pb_ino); if (err) { (void )syscall(SYSIO_SYS_close, fd); if (err == -EEXIST) abort();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -