struct peropen * netfs_make_peropen (struct node *np, int flags, struct peropen *context) { struct peropen *po = malloc (sizeof (struct peropen)); po->filepointer = 0; po->lock_status = LOCK_UN; po->refcnt = 0; po->openstat = flags; po->np = np; if (context) { po->root_parent = context->root_parent; if (po->root_parent != MACH_PORT_NULL) mach_port_mod_refs (mach_task_self (), po->root_parent, MACH_PORT_RIGHT_SEND, 1); po->shadow_root = context->shadow_root; if (po->shadow_root) netfs_nref (po->shadow_root); po->shadow_root_parent = context->shadow_root_parent; if (po->shadow_root_parent != MACH_PORT_NULL) mach_port_mod_refs (mach_task_self (), po->shadow_root_parent, MACH_PORT_RIGHT_SEND, 1); } netfs_nref (np); return po; }
error_t procfs_lookup (struct node *np, const char *name, struct node **npp) { error_t err = ENOENT; if (err && ! strcmp (name, ".")) { netfs_nref(*npp = np); err = 0; } if (err && np->nn->parent && ! strcmp (name, "..")) { netfs_nref(*npp = np->nn->parent); err = 0; } if (err && np->nn->ops->lookup) { err = np->nn->ops->lookup (np->nn->hook, name, npp); if (! err) { (*npp)->nn_stat.st_ino = procfs_make_ino (np, name); netfs_nref ((*npp)->nn->parent = np); } } return err; }
/* 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; }
/* Lookup NAME in DIR for USER; set *NODE to the found name upon return. If the name was not found, then return ENOENT. On any error, clear *NODE. (*NODE, if found, should be locked, this call should unlock DIR no matter what.) */ error_t netfs_attempt_lookup (struct iouser *user, struct node *dir, char *name, struct node **node) { error_t err = 0; debug ("dir: %p, file name: %s", dir, name); if (strcmp(name, ".") == 0) { netfs_nref(dir); *node = dir; return 0; } else if (strcmp(name, "..") == 0) { /*The supplied node is always root*/ err = ENOENT; *node = NULL; /*unlock the directory*/ pthread_mutex_unlock (&dir->lock); /*stop here*/ return err; } *node = lookup (name); pthread_mutex_lock (&(*node)->lock); pthread_mutex_unlock (&dir->lock); return 0; }
/* The user must define this function. Lookup NAME in DIR (which is locked) for USER; set *NP to the found name upon return. If the name was not found, then return ENOENT. On any error, clear *NP. (*NP, if found, should be locked and a reference to it generated. This call should unlock DIR no matter what.) */ error_t netfs_attempt_lookup (struct iouser *user, struct node *dir, char *name, struct node **np) { error_t err = 0; /* Lookups for "." and "..". */ if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')) ) /* Make sure that DIR is an actual directory. */ if (S_ISDIR (dir->nn_stat.st_mode)) { if (name[1] == '.') *np = dir->nn->dir; else *np = dir; } else { *np = NULL; err = ENOTDIR; } else /* Regular nodes. */ err = backend.lookup_node (np, dir, name); /* Create a reference to the node (and lock it); unlock DIR. */ if (!err && *np) { if (*np != dir) mutex_lock (&(*np)->lock); debug (("Node %s: %i references", name, (*np)->references)); netfs_nref (*np); } mutex_unlock (&dir->lock); return err; }
/* Add NODE to the recently-used-node cache, which adds a reference to prevent it from going away. NODE should be locked. */ void ftpfs_cache_node (struct node *node) { struct netnode *nn = node->nn; struct ftpfs *fs = nn->fs; mutex_lock (&fs->node_cache_lock); if (fs->params.node_cache_max > 0 || fs->node_cache_len > 0) { if (fs->node_cache_mru != node) { if (nn->ncache_next || nn->ncache_prev) /* Node is already in the cache. */ node_unlink (node, fs); else /* Add a reference from the cache. */ netfs_nref (node); nn->ncache_next = fs->node_cache_mru; nn->ncache_prev = 0; if (fs->node_cache_mru) fs->node_cache_mru->nn->ncache_prev = node; if (! fs->node_cache_lru) fs->node_cache_lru = node; fs->node_cache_mru = node; fs->node_cache_len++; } /* Forget the least used nodes. */ while (fs->node_cache_len > fs->params.node_cache_max) { struct node *lru = fs->node_cache_lru; node_unlink (lru, fs); netfs_nrele (lru); } } mutex_unlock (&fs->node_cache_lock); }
/* Called by libnetfs when node NP has no more references. (See <hurd/libnetfs.h> for details. */ void netfs_node_norefs (struct node *np) { if (np->nn->dead_dir) { struct fnd *args; pthread_t thread; error_t err; args = malloc (sizeof (struct fnd)); assert (args); netfs_nref (np); args->dir = np->nn->dead_dir; args->name = np->nn->dead_name; np->nn->dead_dir = 0; np->nn->dead_name = 0; netfs_nput (np); /* Do this in a separate thread so that we don't wait for it; it acquires a lock on the dir, which we are not allowed to do. */ err = pthread_create (&thread, NULL, forked_node_delete, args); if (!err) pthread_detach (thread); else { errno = err; perror ("pthread_create"); } } else { if (np->nn->dtrans == SYMLINK) free (np->nn->transarg.name); free (np); } }
/* Lookup NAME in DIR for USER; set *NODE to the found name upon return. If the name was not found, then return ENOENT. On any error, clear *NODE. (*NODE, if found, should be locked, this call should unlock DIR no matter what.) */ error_t netfs_attempt_lookup (struct iouser *user, struct node *dir, char *name, struct node **node) { error_t err; if (dir->nn->name) err = ENOTDIR; else err = fshelp_access (&dir->nn_stat, S_IEXEC, user); if (! err) { if (strcmp (name, ".") == 0) /* Current directory -- just add an additional reference to DIR and return it. */ { netfs_nref (dir); *node = dir; err = 0; } else if (strcmp (name, "..") == 0) err = EAGAIN; else err = lookup_host (dir->nn->mux, name, node); fshelp_touch (&dir->nn_stat, TOUCH_ATIME, hostmux_maptime); } pthread_mutex_unlock (&dir->lock); if (err) *node = 0; else pthread_mutex_lock (&(*node)->lock); return err; }
/* Lookup the file handle HANDLE in the hash table. If it is not present, initialize a new node structure and insert it into the hash table. Whichever course, a new reference is generated and the node is returned in *NPP; the lock on the node, (*NPP)->LOCK, is held. */ void lookup_fhandle (struct fhandle *handle, struct node **npp) { struct node *np; struct netnode *nn; pthread_mutex_lock (&nodehash_ihash_lock); np = hurd_ihash_find (&nodehash, (hurd_ihash_key_t) handle); if (np) { netfs_nref (np); pthread_mutex_unlock (&nodehash_ihash_lock); pthread_mutex_lock (&np->lock); *npp = np; return; } /* Could not find it */ np = netfs_make_node_alloc (sizeof (struct netnode)); assert (np); nn = netfs_node_netnode (np); nn->handle.size = handle->size; memcpy (nn->handle.data, handle->data, handle->size); nn->stat_updated = 0; nn->dtrans = NOT_POSSIBLE; nn->dead_dir = 0; nn->dead_name = 0; hurd_ihash_add (&nodehash, (hurd_ihash_key_t) &nn->handle, np); netfs_nref_light (np); pthread_mutex_unlock (&nodehash_ihash_lock); pthread_mutex_lock (&np->lock); *npp = np; }
/* cvsfs_make_node * * create a struct node* for the specified netnode 'nn'. */ struct node * cvsfs_make_node(struct netnode *nn) { struct node *node; rwlock_writer_lock(&nn->lock); if(nn->node) { /* there already is a node structure, just return another reference * to this one, instead of wasting memory for yet another one */ mutex_lock(&nn->node->lock); netfs_nref(nn->node); mutex_unlock(&nn->node->lock); rwlock_writer_unlock(&nn->lock); return nn->node; } if(! (node = netfs_make_node(nn))) { rwlock_writer_unlock(&nn->lock); return NULL; } /* put timestamp on file */ fshelp_touch(&node->nn_stat, TOUCH_ATIME | TOUCH_MTIME | TOUCH_CTIME, cvsfs_maptime); /* initialize stats of new node ... */ node->nn_stat.st_fstype = FSTYPE_MISC; node->nn_stat.st_fsid = stat_template.fsid; node->nn_stat.st_ino = nn->fileno; node->nn_stat.st_mode = stat_template.mode; node->nn_stat.st_nlink = 1; node->nn_stat.st_uid = stat_template.uid; node->nn_stat.st_gid = stat_template.gid; node->nn_stat.st_size = 0; node->nn_stat.st_blksize = 4096; /* is there a better default?? */ node->nn_stat.st_blocks = 0; node->nn_stat.st_author = stat_template.author; if(! nn->revision) { /* we're creating a node for a directory, mark as such! */ node->nn_stat.st_mode |= S_IFDIR; /* since we got a directory we need to supply "executable" * permissions, so our user is enabled to make use of this dir */ if(node->nn_stat.st_mode & S_IRUSR) node->nn_stat.st_mode |= S_IXUSR; if(node->nn_stat.st_mode & S_IRGRP) node->nn_stat.st_mode |= S_IXGRP; if(node->nn_stat.st_mode & S_IROTH) node->nn_stat.st_mode |= S_IXOTH; } else { if(nn->revision->contents && ! config.nostats) { node->nn_stat.st_mode = nn->revision->perm; node->nn_stat.st_size = nn->revision->length; node->nn_stat.st_blocks = (node->nn_stat.st_size >> 9) + 1; node->nn_stat.st_atime = node->nn_stat.st_mtime = node->nn_stat.st_ctime = nn->revision->time; node->nn_stat.st_atime_usec = node->nn_stat.st_mtime_usec = node->nn_stat.st_ctime_usec = 0; } /* well, we're creating a new node for a file ... */ node->nn_stat.st_mode |= S_IFREG; /* for now simply drop all execute permissions, this needs to be fixed, * since CVS support executables, e.g. shell scripts, that we need to * support .... FIXME */ node->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); }