/*===========================================================================* * fs_stat * *===========================================================================*/ int fs_stat(ino_t ino_nr, struct stat *statbuf) { struct inode *rip; mode_t mo; int s; if ((rip = get_inode(fs_dev, ino_nr)) == NULL) return(EINVAL); /* Update the atime, ctime, and mtime fields in the inode, if need be. */ if (rip->i_update) update_times(rip); /* Fill in the statbuf struct. */ mo = rip->i_mode & I_TYPE; /* true iff special */ s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); statbuf->st_mode = (mode_t) rip->i_mode; statbuf->st_nlink = (nlink_t) rip->i_nlinks; statbuf->st_uid = rip->i_uid; statbuf->st_gid = rip->i_gid; statbuf->st_rdev = (s ? (dev_t)rip->i_zone[0] : NO_DEV); statbuf->st_size = rip->i_size; statbuf->st_atime = rip->i_atime; statbuf->st_mtime = rip->i_mtime; statbuf->st_ctime = rip->i_ctime; statbuf->st_blksize = lmfs_fs_block_size(); statbuf->st_blocks = estimate_blocks(rip); put_inode(rip); /* release the inode */ return(OK); }
/** * Common code for stat and fstat system calls. * @param rip pointer to inode to stat * @param who_e caller endpoint * @param gid grant for the stat buf * @return 0 on success */ static int stat_inode(struct pipe_inode *rip, int who_e, cp_grant_id_t gid) { struct kstat ksb; int r, s; /* Update the atime, ctime, and mtime fields in the inode, if need be. */ if (rip->i_update) update_times(rip); ksb.dev = rip->i_dev; ksb.ino = rip->i_num; ksb.mode = rip->i_mode; ksb.nlink = rip->i_nlinks; ksb.uid = rip->i_uid; ksb.gid = rip->i_gid; ksb.rdev = (dev_t) 0; ksb.size = rip->i_size; ksb.mode &= ~I_REGULAR; /* wipe out I_REGULAR bit for pipes */ ksb.blksize = 1024; /* @nucleos: what it should be for pipes? */ ksb.blocks = 0; ksb.atime.tv_sec = rip->i_atime; ksb.mtime.tv_sec = rip->i_mtime; ksb.ctime.tv_sec = rip->i_ctime; ksb.atime.tv_nsec = 0; ksb.mtime.tv_nsec = 0; ksb.ctime.tv_nsec = 0; /* Copy the struct to caller space. */ r = sys_safecopyto(who_e, gid, 0, (vir_bytes)&ksb,(phys_bytes)sizeof(ksb), D); return(r); }
/*===========================================================================* * fs_getdents * *===========================================================================*/ PUBLIC int fs_getdents(void) { int r; register struct puffs_node *pn; ino_t ino; cp_grant_id_t gid; size_t size, buf_left; off_t pos; struct dirent *dent; int eofflag = 0; size_t written; PUFFS_MAKECRED(pcr, &global_kcred); ino = (ino_t) fs_m_in.REQ_INODE_NR; gid = (gid_t) fs_m_in.REQ_GRANT; size = buf_left = (size_t) fs_m_in.REQ_MEM_SIZE; pos = (off_t) fs_m_in.REQ_SEEK_POS_LO; if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino)) == NULL) { lpuffs_debug("walk failed...\n"); return(EINVAL); } if (GETDENTS_BUFSIZ < size) size = buf_left = GETDENTS_BUFSIZ; memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */ dent = (struct dirent*) getdents_buf; r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, &pos, &buf_left, pcr, &eofflag, 0, 0); if (r) { lpuffs_debug("puffs_node_readdir returned error\n"); return(EINVAL); } assert(buf_left <= size); written = size - buf_left; if (written == 0 && !eofflag) { lpuffs_debug("The user's buffer is too small\n"); return(EINVAL); } if (written) { r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0, (vir_bytes) getdents_buf, written, D); if (r != OK) return(r); } update_times(pn, ATIME, 0); fs_m_out.RES_NBYTES = written; fs_m_out.RES_SEEK_POS_LO = pos; return(OK); }
static void app_message_init(void) { // Register message handlers app_message_register_inbox_received(in_received_handler); app_message_register_inbox_dropped(in_dropped_handler); app_message_register_outbox_failed(out_failed_handler); // Init buffers app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum()); update_times(); }
static inline void driver_cycle (oss_driver_t *driver) { update_times(driver); driver->engine->transport_cycle_start(driver->engine, driver->last_periodtime); driver->last_wait_ust = driver->last_periodtime; driver->engine->run_cycle(driver->engine, driver->period_size, driver->iodelay); }
/*===========================================================================* * fs_ftrunc * *===========================================================================*/ PUBLIC int fs_ftrunc(void) { int r; struct puffs_node *pn; off_t start, end; PUFFS_MAKECRED(pcr, &global_kcred); if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); start = fs_m_in.REQ_TRC_START_LO; end = fs_m_in.REQ_TRC_END_LO; if (end == 0) { struct vattr va; if (pn->pn_va.va_size == start) return(OK); if (global_pu->pu_ops.puffs_node_setattr == NULL) return(EINVAL); puffs_vattr_null(&va); va.va_size = start; r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr); if (r) return(EINVAL); } else { /* XXX zerofill the given region. Can we make a hole? */ off_t bytes_left = end - start; char* rw_buf; if (global_pu->pu_ops.puffs_node_write == NULL) return(EINVAL); /* XXX split into chunks? */ rw_buf = malloc(bytes_left); if (!rw_buf) panic("fs_ftrunc: failed to allocated memory\n"); memset(rw_buf, 0, bytes_left); r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf, start, (size_t *) &bytes_left, pcr, 0); free(rw_buf); if (r) return(EINVAL); } update_times(pn, CTIME | MTIME, 0); return(r); }
/*===========================================================================* * stat_inode * *===========================================================================*/ static int stat_inode( register struct inode *rip, /* pointer to inode to stat */ endpoint_t who_e, /* Caller endpoint */ cp_grant_id_t gid /* grant for the stat buf */ ) { /* Common code for stat and fstat system calls. */ struct stat statbuf; mode_t mo; int r, s; /* Update the atime, ctime, and mtime fields in the inode, if need be. */ if (rip->i_update) update_times(rip); /* Fill in the statbuf struct. */ mo = rip->i_mode & I_TYPE; /* true iff special */ s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); memset(&statbuf, 0, sizeof(struct stat)); statbuf.st_dev = rip->i_dev; statbuf.st_ino = rip->i_num; statbuf.st_mode = rip->i_mode; statbuf.st_nlink = rip->i_nlinks; statbuf.st_uid = rip->i_uid; statbuf.st_gid = rip->i_gid; statbuf.st_rdev = (s ? (dev_t) rip->i_zone[0] : NO_DEV); statbuf.st_size = rip->i_size; statbuf.st_atime = rip->i_atime; statbuf.st_mtime = rip->i_mtime; statbuf.st_ctime = rip->i_ctime; statbuf.st_blksize = fs_block_size; statbuf.st_blocks = estimate_blocks(rip); /* Copy the struct to user space. */ r = sys_safecopyto(who_e, gid, (vir_bytes) 0, (vir_bytes) &statbuf, (size_t) sizeof(statbuf)); return(r); }
/** * Common code for stat and fstat system calls. * @param rip pointer to inode to stat * @param who_e caller endpoint * @param gid grant for the stat buf * @return 0 on success */ static int stat_inode(struct minix_inode *rip, int who_e, cp_grant_id_t gid) { struct kstat ksb; mode_t mo; int r, s; /* Update the atime, ctime, and mtime fields in the inode, if need be. */ if (rip->i_update) update_times(rip); /* Fill in the ksb struct. */ mo = rip->i_mode & I_TYPE; /* true iff special */ s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL); memset(&ksb, 0, sizeof(ksb)); ksb.dev = rip->i_dev; ksb.ino = rip->i_num; ksb.mode = rip->i_mode; ksb.nlink = rip->i_nlinks; ksb.uid = rip->i_uid; ksb.gid = rip->i_gid; ksb.rdev = (dev_t)(s ? rip->i_zone[0] : NO_DEV); ksb.size = rip->i_size; ksb.atime.tv_sec = rip->i_atime; ksb.mtime.tv_sec = rip->i_mtime; ksb.ctime.tv_sec = rip->i_ctime; ksb.atime.tv_nsec = 0; ksb.mtime.tv_nsec = 0; ksb.ctime.tv_nsec = 0; /* @nucleos: NOT correct e.g. see minix_getattr() in linux sources fs/minix/inode.c */ ksb.blksize = 1024; ksb.blocks = ((ksb.size + 511) >> 9); r = sys_safecopyto(who_e, gid, 0, (vir_bytes)&ksb, (phys_bytes)sizeof(ksb), D); return(r); }
void * tick_clock (void *unused) { register clock_t start, end; register int tick = 0; for (;;) { start = times (NULL); tsk_delay (0, MILLISEC_2_NANOSEC (TICK_TIMER_GRANULARITY)); end = times (NULL); tick = end - start; if (tick <= 0) tick = 1; while (tick--) { update_times (); } } return NULL; }
/*===========================================================================* * stat_inode * *===========================================================================*/ PRIVATE int stat_inode( register struct inode *rip, /* pointer to inode to stat */ endpoint_t who_e, /* Caller endpoint */ cp_grant_id_t gid /* grant for the stat buf */ ) { /* Common code for stat and fstat system calls. */ mode_t type; struct stat statbuf; int r, s; type = rip->i_mode & I_TYPE; s = (type == I_CHAR_SPECIAL || type == I_BLOCK_SPECIAL); /* Update the atime, ctime, and mtime fields in the inode, if need be. */ if (rip->i_update) update_times(rip); statbuf.st_dev = rip->i_dev; statbuf.st_ino = rip->i_num; statbuf.st_mode = rip->i_mode; statbuf.st_nlink = rip->i_nlinks; statbuf.st_uid = rip->i_uid; statbuf.st_gid = (short int) rip->i_gid; statbuf.st_rdev = (dev_t) (s ? rip->i_rdev : NO_DEV); statbuf.st_size = rip->i_size; if (!s) statbuf.st_mode &= ~I_REGULAR;/* wipe out I_REGULAR bit for pipes */ statbuf.st_atime = rip->i_atime; statbuf.st_mtime = rip->i_mtime; statbuf.st_ctime = rip->i_ctime; /* Copy the struct to user space. */ r = sys_safecopyto(who_e, gid, (vir_bytes) 0, (vir_bytes) &statbuf, (size_t) sizeof(statbuf), D); return(r); }
/*===========================================================================* * fs_readwrite * *===========================================================================*/ PUBLIC int fs_readwrite(void) { int r = OK, rw_flag; cp_grant_id_t gid; off_t pos; size_t nrbytes, bytes_left, bytes_done; struct puffs_node *pn; struct vattr va; PUFFS_MAKECRED(pcr, &global_kcred); if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL) { lpuffs_debug("walk failed...\n"); return(EINVAL); } /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; pos = (off_t) fs_m_in.REQ_SEEK_POS_LO; nrbytes = bytes_left = (size_t) fs_m_in.REQ_NBYTES; if (nrbytes > RW_BUFSIZ) nrbytes = bytes_left = RW_BUFSIZ; memset(getdents_buf, '\0', RW_BUFSIZ); /* Avoid leaking any data */ if (rw_flag == READING) { if (global_pu->pu_ops.puffs_node_read == NULL) return(EINVAL); r = global_pu->pu_ops.puffs_node_read(global_pu, pn, (uint8_t *)rw_buf, pos, &bytes_left, pcr, 0); if (r) { lpuffs_debug("puffs_node_read failed\n"); return(EINVAL); } bytes_done = nrbytes - bytes_left; if (bytes_done) { r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0, (vir_bytes) rw_buf, bytes_done, D); update_times(pn, ATIME, 0); } } else if (rw_flag == WRITING) { /* At first try to change vattr */ if (global_pu->pu_ops.puffs_node_setattr == NULL) return(EINVAL); puffs_vattr_null(&va); if ( (pos + bytes_left) > pn->pn_va.va_size) va.va_size = bytes_left + pos; va.va_ctime.tv_sec = va.va_mtime.tv_sec = clock_time(); va.va_atime.tv_sec = pn->pn_va.va_atime.tv_sec; r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr); if (r) return(EINVAL); r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) 0, (vir_bytes) rw_buf, nrbytes, D); if (r != OK) return(EINVAL); if (global_pu->pu_ops.puffs_node_write == NULL) return(EINVAL); r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf, pos, &bytes_left, pcr, 0); bytes_done = nrbytes - bytes_left; } if (r != OK) return(EINVAL); fs_m_out.RES_SEEK_POS_LO = pos + bytes_done; fs_m_out.RES_NBYTES = bytes_done; return(r); }
/*===========================================================================* * fs_link * *===========================================================================*/ PUBLIC int fs_link() { /* Perform the link(name1, name2) system call. */ register int r; char string[NAME_MAX + 1]; phys_bytes len; struct puffs_node *pn, *pn_dir, *new_pn; time_t cur_time; struct puffs_kcn pkcnp; PUFFS_MAKECRED(pcr, &global_kcred); struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}}; if (global_pu->pu_ops.puffs_node_link == NULL) return(OK); /* Copy the link name's last component */ len = fs_m_in.REQ_PATH_LEN; if (len > NAME_MAX + 1) return(ENAMETOOLONG); r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, 0, (vir_bytes) string, (size_t) len, D); if (r != OK) return(r); NUL(string, len, sizeof(string)); if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* Check to see if the file has maximum number of links already. */ if (pn->pn_va.va_nlink >= LINK_MAX) return(EMLINK); /* Only super_user may link to directories. */ if ((pn->pn_va.va_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID) return(EPERM); if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_DIR_INO)) == NULL) return(EINVAL); if (pn_dir->pn_va.va_nlink == NO_LINK) { /* Dir does not actually exist */ return(ENOENT); } /* If 'name2' exists in full (even if no space) set 'r' to error. */ if ((new_pn = advance(pn_dir, string, IGN_PERM)) == NULL) { r = err_code; if (r == ENOENT) r = OK; } else { r = EEXIST; } if (r != OK) return(r); /* Try to link. */ pcn.pcn_namelen = strlen(string); assert(pcn.pcn_namelen <= MAXPATHLEN); strcpy(pcn.pcn_name, string); if (buildpath) { if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0) return(EINVAL); } if (global_pu->pu_ops.puffs_node_link(global_pu, pn_dir, pn, &pcn) != 0) r = EINVAL; if (buildpath) global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full); if (r != OK) return(EINVAL); cur_time = clock_time(); update_times(pn, CTIME, cur_time); update_times(pn_dir, MTIME | CTIME, cur_time); return(OK); }
/*===========================================================================* * fs_unlink * *===========================================================================*/ PUBLIC int fs_unlink() { /* Perform the unlink(name) or rmdir(name) system call. The code for these two * is almost the same. They differ only in some condition testing. Unlink() * may be used by the superuser to do dangerous things; rmdir() may not. */ int r; struct puffs_node *pn, *pn_dir; time_t cur_time; struct puffs_kcn pkcnp; struct puffs_cn pcn = {&pkcnp, 0, {0,0,0}}; PUFFS_KCREDTOCRED(pcn.pcn_cred, &global_kcred); int len; /* Copy the last component */ len = fs_m_in.REQ_PATH_LEN; pcn.pcn_namelen = len - 1; if (pcn.pcn_namelen > NAME_MAX) return(ENAMETOOLONG); r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) pcn.pcn_name, (size_t) len, D); if (r != OK) return (r); NUL(pcn.pcn_name, len, sizeof(pcn.pcn_name)); if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* The last directory exists. Does the file also exist? */ pn = advance(pn_dir, pcn.pcn_name, IGN_PERM); r = err_code; /* If error, return pnode. */ if (r != OK) { /* Mount point? */ if (r == EENTERMOUNT || r == ELEAVEMOUNT) { r = EBUSY; } return(r); } /* Now test if the call is allowed, separately for unlink() and rmdir(). */ if (fs_m_in.m_type == REQ_UNLINK) { /* Only the su may unlink directories, but the su can unlink any dir */ if ((pn->pn_va.va_mode & I_TYPE) == I_DIRECTORY) r = EPERM; if (r == OK) r = unlink_file(pn_dir, pn, &pcn); } else { r = remove_dir(pn_dir, pn, &pcn); /* call is RMDIR */ } if (pn->pn_va.va_nlink != 0) { cur_time = clock_time(); update_times(pn, CTIME, cur_time); update_times(pn_dir, MTIME | CTIME, cur_time); } /* XXX Ideally, we should check pn->pn_flags & PUFFS_NODE_REMOVED, but * librefuse doesn't set it (neither manually or via puffs_pn_remove() ). * Thus we just check that "pn_count == 0". Otherwise release_node() * will be called in fs_put(). */ if (pn->pn_count == 0) release_node(global_pu, pn); return(r); }
/*===========================================================================* * fs_rename * *===========================================================================*/ PUBLIC int fs_rename() { /* Perform the rename(name1, name2) system call. */ struct puffs_node *old_dirp, *old_ip; /* ptrs to old dir, file pnodes */ struct puffs_node *new_dirp, *new_ip; /* ptrs to new dir, file pnodes */ struct puffs_kcn pkcnp_src; PUFFS_MAKECRED(pcr_src, &global_kcred); struct puffs_cn pcn_src = {&pkcnp_src, (struct puffs_cred *) __UNCONST(pcr_src), {0,0,0}}; struct puffs_kcn pkcnp_dest; PUFFS_MAKECRED(pcr_dest, &global_kcred); struct puffs_cn pcn_targ = {&pkcnp_dest, (struct puffs_cred *) __UNCONST(pcr_dest), {0,0,0}}; int r = OK; /* error flag; initially no error */ int odir, ndir; /* TRUE iff {old|new} file is dir */ int same_pdir; /* TRUE iff parent dirs are the same */ phys_bytes len; time_t cur_time; if (global_pu->pu_ops.puffs_node_rename == NULL) return(EINVAL); /* Copy the last component of the old name */ len = fs_m_in.REQ_REN_LEN_OLD; /* including trailing '\0' */ if (len > NAME_MAX + 1) return(ENAMETOOLONG); r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_REN_GRANT_OLD, (vir_bytes) 0, (vir_bytes) pcn_src.pcn_name, (size_t) len, D); if (r != OK) return(r); NUL(pcn_src.pcn_name, len, sizeof(pcn_src.pcn_name)); pcn_src.pcn_namelen = len - 1; /* Copy the last component of the new name */ len = fs_m_in.REQ_REN_LEN_NEW; /* including trailing '\0' */ if (len > NAME_MAX + 1) return(ENAMETOOLONG); r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_REN_GRANT_NEW, (vir_bytes) 0, (vir_bytes) pcn_targ.pcn_name, (size_t) len, D); if (r != OK) return(r); NUL(pcn_targ.pcn_name, len, sizeof(pcn_targ.pcn_name)); pcn_targ.pcn_namelen = len - 1; /* Get old dir pnode */ if ((old_dirp = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_REN_OLD_DIR)) == NULL) return(ENOENT); old_ip = advance(old_dirp, pcn_src.pcn_name, IGN_PERM); if (!old_ip) { return(ENOENT); } r = err_code; if (r == EENTERMOUNT || r == ELEAVEMOUNT) { old_ip = NULL; if (r == EENTERMOUNT) r = EXDEV; /* should this fail at all? */ else if (r == ELEAVEMOUNT) r = EINVAL; /* rename on dot-dot */ } /* Get new dir pnode */ if ((new_dirp = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_REN_NEW_DIR)) == NULL) { r = ENOENT; } else { if (new_dirp->pn_va.va_nlink == NO_LINK) { /* Dir does not actually exist */ return(ENOENT); } } /* not required to exist */ new_ip = advance(new_dirp, pcn_targ.pcn_name, IGN_PERM); /* However, if the check failed because the file does exist, don't continue. * Note that ELEAVEMOUNT is covered by the dot-dot check later. */ if (err_code == EENTERMOUNT) { new_ip = NULL; r = EBUSY; } if (old_ip != NULL) { /* TRUE iff dir */ odir = ((old_ip->pn_va.va_mode & I_TYPE) == I_DIRECTORY); } else { odir = FALSE; } if (r != OK) return(r); /* Check for a variety of possible errors. */ same_pdir = (old_dirp == new_dirp); /* The old or new name must not be . or .. */ if (strcmp(pcn_src.pcn_name, ".") == 0 || strcmp(pcn_src.pcn_name, "..") == 0 || strcmp(pcn_targ.pcn_name, ".") == 0 || strcmp(pcn_targ.pcn_name, "..") == 0) { r = EINVAL; } /* Some tests apply only if the new path exists. */ if (new_ip == NULL) { if (odir && (new_dirp->pn_va.va_nlink >= SHRT_MAX || new_dirp->pn_va.va_nlink >= LINK_MAX) && !same_pdir && r == OK) { r = EMLINK; } } else { if (old_ip == new_ip) r = SAME; /* old=new */ /* dir ? */ ndir = ((new_ip->pn_va.va_mode & I_TYPE) == I_DIRECTORY); if (odir == TRUE && ndir == FALSE) r = ENOTDIR; if (odir == FALSE && ndir == TRUE) r = EISDIR; } if (r == SAME) { r = OK; goto rename_out; } if (r != OK) return(r); /* If a process has another root directory than the system root, we might * "accidently" be moving it's working directory to a place where it's * root directory isn't a super directory of it anymore. This can make * the function chroot useless. If chroot will be used often we should * probably check for it here. */ /* The rename will probably work. Only two things can go wrong now: * 1. being unable to remove the new file. (when new file already exists) * 2. being unable to make the new directory entry. (new file doesn't exists) * [directory has to grow by one block and cannot because the disk * is completely full]. * 3. Something (doubtfully) else depending on the FS. */ if (buildpath) { pcn_src.pcn_po_full = old_ip->pn_po; if (puffs_path_pcnbuild(global_pu, &pcn_targ, new_dirp) != 0) return(EINVAL); } r = global_pu->pu_ops.puffs_node_rename(global_pu, old_dirp, old_ip, &pcn_src, new_dirp, new_ip, &pcn_targ); if (r > 0) r = -r; if (buildpath) { if (r) { global_pu->pu_pathfree(global_pu, &pcn_targ.pcn_po_full); } else { struct puffs_pathinfo pi; struct puffs_pathobj po_old; /* handle this node */ po_old = old_ip->pn_po; old_ip->pn_po = pcn_targ.pcn_po_full; if (old_ip->pn_va.va_type != VDIR) { global_pu->pu_pathfree(global_pu, &po_old); return(OK); } /* handle all child nodes for DIRs */ pi.pi_old = &pcn_src.pcn_po_full; pi.pi_new = &pcn_targ.pcn_po_full; PU_LOCK(); if (puffs_pn_nodewalk(global_pu, puffs_path_prefixadj, &pi) != NULL) { /* Actually nomem */ return(EINVAL); } PU_UNLOCK(); global_pu->pu_pathfree(global_pu, &po_old); } } rename_out: cur_time = clock_time(); update_times(old_dirp, MTIME | CTIME, cur_time); update_times(new_dirp, MTIME | CTIME, cur_time); /* XXX see release_node comment in fs_unlink */ if (new_ip && new_ip->pn_count == 0) { release_node(global_pu, new_ip); } return(r); }
static void select_click_handler(ClickRecognizerRef recognizer, void *context) { update_times(); }