/* The user must define this function. Attempt to create a file named NAME in DIR (which is locked) for USER with MODE. Set *NP to the new node upon return. On any error, clear *NP. *NP should be locked on success; no matter what, unlock DIR before returning. */ error_t netfs_attempt_create_file (struct iouser *user, struct node *dir, char *name, mode_t mode, struct node **np) { error_t err = fshelp_isowner (&dir->nn_stat, user); if (!backend.create_node) { err = EROFS; *np = NULL; } else { /* Note: create_node () must handle nameless node creation (see netfs_attempt_mkfile ()). */ err = backend.create_node (np, dir, name, mode); /* Lock the new node and add a reference to it on success. */ if (!err && *np) { debug (("Node %s: %i references", name, (*np)->references)); mutex_lock (&(*np)->lock); netfs_nref (*np); } } mutex_unlock (&dir->lock); return err; }
/* The user must define this function. This should sync the entire remote filesystem. If WAIT is set, return only after the sync is completely finished. */ error_t netfs_attempt_syncfs (struct iouser *cred, int wait) { error_t err = 0; if (backend.sync_fs) { if (cred) { err = fshelp_isowner (&netfs_root_node->nn_stat, cred); if (err) return err; err = backend.sync_fs (wait); } else /* From libnetfs source code, CRED is set to zero in the fsys-goaway stub, so we call go_away () here. */ if (backend.go_away) err = backend.go_away (); /* This should call sync_fs () */ else err = backend.sync_fs (wait); } else err = EOPNOTSUPP; return err; }
/* The user must define this function. Delete NAME in DIR (which is locked) for USER. */ error_t netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) { error_t err; if (backend.unlink_node) { struct node *node; err = backend.lookup_node (&node, dir, name); //usleep (500); /* FIXME!!! The incredible race condition! */ if (!err) { mutex_lock (&node->lock); debug (("Node %s: %i references", name, node->references)); err = fshelp_isowner (&node->nn_stat, user); if (!err) err = backend.unlink_node (node); mutex_unlock (&node->lock); } } else err = EROFS; return err; }
/* The user must define this function. This should attempt a chmod call for the user specified by CRED on locked node NP, to change the owner to UID and the group to GID. */ error_t netfs_attempt_chown (struct iouser *cred, struct node *np, uid_t uid, uid_t gid) { error_t err = 0; if (backend.change_stat) { io_statbuf_t st; err = fshelp_isowner (&np->nn_stat, cred); if (! err) { st = np->nn_stat; st.st_uid = uid; st.st_gid = gid; err = backend.change_stat (np, &st); } } else err = EROFS; return err; }
/* The user must define this function. This should attempt a utimes call for the user specified by CRED on locked node NP, to change the atime to ATIME and the mtime to MTIME. If ATIME or MTIME is null, then set to the current time. */ error_t netfs_attempt_utimes (struct iouser *cred, struct node *np, struct timespec *atime, struct timespec *mtime) { error_t err = 0; if (backend.change_stat) { int flags = TOUCH_CTIME; io_statbuf_t st = np->nn_stat; err = fshelp_isowner (&np->nn_stat, cred); if (! err) { if (atime) st.st_atim = *atime; else flags |= TOUCH_ATIME; if (mtime) st.st_mtim = *mtime; else flags |= TOUCH_MTIME; err = backend.change_stat (np, &st); } } else err = EROFS; return err; }
/* This should attempt a utimes call for the user specified by CRED on node NODE, to change the atime to ATIME and the mtime to MTIME. */ error_t netfs_attempt_utimes (struct iouser *cred, struct node *node, struct timespec *atime, struct timespec *mtime) { error_t err = procfs_refresh_node (node); int flags = TOUCH_CTIME; if (! err) err = fshelp_isowner (&node->nn_stat, cred); if (! err) { if (atime) node->nn_stat.st_atim = *atime; else flags |= TOUCH_ATIME; if (mtime) node->nn_stat.st_mtim = *mtime; else flags |= TOUCH_MTIME; fshelp_touch (&node->nn_stat, flags, procfs_maptime); } return err; }
/* Implement file_get_translator_cntl as described in <hurd/fs.defs>. */ kern_return_t diskfs_S_file_get_translator_cntl (struct protid *cred, mach_port_t *ctl, mach_msg_type_name_t *ctltype) { struct node *np; error_t error; if (!cred) return EOPNOTSUPP; np = cred->po->np; mutex_lock (&np->lock); error = fshelp_isowner (&np->dn_stat, cred->user); if (!error) error = fshelp_fetch_control (&np->transbox, ctl); if (!error && *ctl == MACH_PORT_NULL) error = ENXIO; if (!error) *ctltype = MACH_MSG_TYPE_MOVE_SEND; mutex_unlock (&np->lock); return error; }
/* The user must define this function. Attempt to create a new directory named NAME in DIR (which is locked) for USER with mode MODE. */ error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir, char *name, mode_t mode) { error_t err = fshelp_isowner (&dir->nn_stat, user); struct node *newdir; if (!backend.create_node) err = EROFS; else err = backend.create_node (&newdir, dir, name, mode); return err; }
/* The user must define this function. Create a link in DIR with name NAME to FILE for USER. Note that neither DIR nor FILE are locked. If EXCL is set, do not delete the target. Return EEXIST if NAME is already found in DIR. */ error_t netfs_attempt_link (struct iouser *user, struct node *dir, struct node *file, char *name, int excl) { error_t err; if (backend.link_node) { err = fshelp_isowner (&dir->nn_stat, user); if (!err) err = backend.link_node (dir, file, name, excl); } else err = EROFS; return err; }
/* This should attempt a chmod call for the user specified by CRED on node NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning of chmod, this function is also used to attempt to change files into other types. If such a transition is attempted which is impossible, then return EOPNOTSUPP. */ error_t netfs_attempt_chmod (struct iouser *cred, struct node *node, mode_t mode) { error_t err = 0; debug(""); if (node->nn->ln == NULL) return EOPNOTSUPP; mode &= ~S_ITRANS; err = fshelp_isowner (&node->nn->ln->st, cred); if (err) return err; mode |= node->nn->ln->st.st_mode & S_IFMT; node->nn->ln->st.st_mode = mode; fshelp_touch (&node->nn_stat, TOUCH_CTIME, multiplexer_maptime); return err; }
/* The user must define this function. This should attempt a chmod call for the user specified by CRED on locked node NODE, to change the mode to MODE. Unlike the normal Unix and Hurd meaning of chmod, this function is also used to attempt to change files into other types. If such a transition is attempted which is impossible, then return EOPNOTSUPP. */ error_t netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode) { error_t err = 0; if (backend.change_stat) { io_statbuf_t st; err = fshelp_isowner (&np->nn_stat, cred); if (! err) { st = np->nn_stat; if (mode & S_IFMT) { /* User wants to change file type, check whether this is possible */ if (S_ISDIR (st.st_mode) || S_ISDIR (mode)) { /* Any->Dir and Dir->Any are forbidden transitions */ if ((st.st_mode & S_IFMT) != (mode & S_IFMT)) err = EOPNOTSUPP; } else /* Let him do it */ st.st_mode = 0; } else /* Only clear the permission bits */ st.st_mode &= ~S_ISPARE; if (!err) { st.st_mode |= mode; err = backend.change_stat (np, &st); } } } else err = EROFS; return err; }
/* The user must define this function. Attempt to turn NODE (user CRED) into a device. TYPE is either S_IFBLK or S_IFCHR. NP is locked. */ error_t netfs_attempt_mkdev (struct iouser *cred, struct node *np, mode_t type, dev_t indexes) { error_t err; if (backend.mkdev_node) { err = fshelp_isowner (&np->nn_stat, cred); /* FIXME: See above */ if (! err) err = backend.mkdev_node (np, type, indexes); } else err = EOPNOTSUPP; return err; }
/* The user must define this function. Attempt to turn locked node NP (user CRED) into a symlink with target NAME. */ error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name) { error_t err; if (backend.symlink_node) { err = fshelp_isowner (&np->nn_stat, cred); /* FIXME: Call fshelp_access () ?! */ if (! err) err = backend.symlink_node (np, name); } else err = EOPNOTSUPP; return err; }
/* Implement io_revoke as described in <hurd/io.defs>. */ kern_return_t diskfs_S_io_revoke (struct protid *cred) { error_t err; struct node *np; error_t iterator_function (void *port) { struct protid *user = port; if ((user != cred) && (user->po->np == np)) ports_destroy_right (user); return 0; } if (!cred) return EOPNOTSUPP; np = cred->po->np; mutex_lock (&np->lock); err = fshelp_isowner (&np->dn_stat, cred->user); mutex_unlock (&np->lock); if (err) return err; ports_inhibit_bucket_rpcs (diskfs_port_bucket); ports_class_iterate (diskfs_protid_class, iterator_function); ports_resume_bucket_rpcs (diskfs_port_bucket); return 0; }