324 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Created (MFS based):
 | |
|  *   June 2011 (Evgeniy Ivanov)
 | |
|  */
 | |
| 
 | |
| #include "fs.h"
 | |
| #include <string.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #include "puffs.h"
 | |
| #include "puffs_priv.h"
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				fs_create				     *
 | |
|  *===========================================================================*/
 | |
| int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
 | |
| 	struct fsdriver_node *node)
 | |
| {
 | |
|   int r;
 | |
|   struct puffs_node *pn_dir;
 | |
|   struct puffs_node *pn;
 | |
|   struct puffs_newinfo pni;
 | |
|   struct puffs_kcn pkcnp;
 | |
|   PUFFS_MAKECRED(pcr, &global_kcred);
 | |
|   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
 | |
|   struct vattr va;
 | |
|   struct timespec cur_time;
 | |
| 
 | |
|   if (global_pu->pu_ops.puffs_node_create == NULL) {
 | |
|   	lpuffs_debug("No puffs_node_create");
 | |
| 	return(ENFILE);
 | |
|   }
 | |
| 
 | |
|   /* Copy the last component (i.e., file name) */
 | |
|   pcn.pcn_namelen = strlen(name);
 | |
|   assert(pcn.pcn_namelen <= NAME_MAX);
 | |
|   strcpy(pcn.pcn_name, name);
 | |
| 
 | |
|   /* Get last directory pnode (i.e., directory that will hold the new pnode) */
 | |
|   if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
 | |
| 	return(ENOENT);
 | |
| 
 | |
|   memset(&pni, 0, sizeof(pni));
 | |
|   pni.pni_cookie = (void** )&pn;
 | |
| 
 | |
|   (void)clock_time(&cur_time);
 | |
|   
 | |
|   memset(&va, 0, sizeof(va));
 | |
|   va.va_type = VREG;
 | |
|   va.va_mode = mode;
 | |
|   va.va_uid = uid;
 | |
|   va.va_gid = gid;
 | |
|   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
 | |
| 
 | |
|   if (buildpath) {
 | |
| 	r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
 | |
| 	if (r) {
 | |
| 		lpuffs_debug("pathbuild error\n");
 | |
| 		return(ENOENT);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   r = global_pu->pu_ops.puffs_node_create(global_pu, pn_dir, &pni, &pcn, &va);
 | |
|   if (buildpath) {
 | |
| 	if (r) {
 | |
| 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
 | |
| 	} else {
 | |
| 		struct puffs_node *_pn;
 | |
| 
 | |
| 		_pn = PU_CMAP(global_pu, pn);
 | |
| 		_pn->pn_po = pcn.pcn_po_full;
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   if (r != OK) {
 | |
| 	if (r > 0) r = -r;
 | |
| 	return(r);
 | |
|   }
 | |
| 
 | |
|   /* Open pnode */
 | |
|   pn->pn_count++;
 | |
| 
 | |
|   update_timens(pn_dir, MTIME | CTIME, &cur_time);
 | |
| 
 | |
|   /* Reply message */
 | |
|   node->fn_ino_nr = pn->pn_va.va_fileid;
 | |
|   node->fn_mode = pn->pn_va.va_mode;
 | |
|   node->fn_size = pn->pn_va.va_size;
 | |
|   node->fn_uid = pn->pn_va.va_uid;
 | |
|   node->fn_gid = pn->pn_va.va_gid;
 | |
|   node->fn_dev = NO_DEV;
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				fs_mknod				     *
 | |
|  *===========================================================================*/
 | |
| int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
 | |
| 	dev_t dev)
 | |
| {
 | |
|   int r;
 | |
|   struct puffs_node *pn_dir;
 | |
|   struct puffs_node *pn;
 | |
|   struct puffs_newinfo pni;
 | |
|   struct puffs_kcn pkcnp;
 | |
|   PUFFS_MAKECRED(pcr, &global_kcred);
 | |
|   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
 | |
|   struct vattr va;
 | |
|   struct timespec cur_time;
 | |
| 
 | |
|   if (global_pu->pu_ops.puffs_node_mknod == NULL) {
 | |
|   	lpuffs_debug("No puffs_node_mknod");
 | |
| 	return(ENFILE);
 | |
|   }
 | |
| 
 | |
|   /* Copy the last component */
 | |
|   pcn.pcn_namelen = strlen(name);
 | |
|   assert(pcn.pcn_namelen <= NAME_MAX);
 | |
|   strcpy(pcn.pcn_name, name);
 | |
| 
 | |
|   /* Get last directory pnode */
 | |
|   if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
 | |
| 	return(ENOENT);
 | |
| 
 | |
|   memset(&pni, 0, sizeof(pni));
 | |
|   pni.pni_cookie = (void** )&pn;
 | |
| 
 | |
|   (void)clock_time(&cur_time);
 | |
| 
 | |
|   memset(&va, 0, sizeof(va));
 | |
|   va.va_type = VDIR;
 | |
|   va.va_mode = mode;
 | |
|   va.va_uid = uid;
 | |
|   va.va_gid = gid;
 | |
|   va.va_rdev = dev;
 | |
|   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
 | |
| 
 | |
|   if (buildpath) {
 | |
| 	if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0) {
 | |
| 		lpuffs_debug("pathbuild error\n");
 | |
| 		return(ENOENT);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   r = global_pu->pu_ops.puffs_node_mknod(global_pu, pn_dir, &pni, &pcn, &va);
 | |
|   if (buildpath) {
 | |
| 	if (r) {
 | |
| 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
 | |
| 	} else {
 | |
| 		struct puffs_node *_pn;
 | |
| 
 | |
| 		_pn = PU_CMAP(global_pu, pn);
 | |
| 		_pn->pn_po = pcn.pcn_po_full;
 | |
| 	  }
 | |
|   }
 | |
| 
 | |
|   if (r != OK) {
 | |
| 	if (r > 0) r = -r;
 | |
| 	return(r);
 | |
|   }
 | |
| 
 | |
|   update_timens(pn_dir, MTIME | CTIME, &cur_time);
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				fs_mkdir				     *
 | |
|  *===========================================================================*/
 | |
| int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
 | |
| {
 | |
|   int r;
 | |
|   struct puffs_node *pn_dir;
 | |
|   struct puffs_node *pn;
 | |
|   struct puffs_newinfo pni;
 | |
|   struct puffs_kcn pkcnp;
 | |
|   PUFFS_MAKECRED(pcr, &global_kcred);
 | |
|   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
 | |
|   struct vattr va;
 | |
|   struct timespec cur_time;
 | |
| 
 | |
|   if (global_pu->pu_ops.puffs_node_mkdir == NULL) {
 | |
|   	lpuffs_debug("No puffs_node_mkdir");
 | |
| 	return(ENFILE);
 | |
|   }
 | |
| 
 | |
|   /* Copy the last component */
 | |
|   pcn.pcn_namelen = strlen(name);
 | |
|   assert(pcn.pcn_namelen <= NAME_MAX);
 | |
|   strcpy(pcn.pcn_name, name);
 | |
| 
 | |
|   /* Get last directory pnode */
 | |
|   if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
 | |
| 	return(ENOENT);
 | |
|   
 | |
|   (void)clock_time(&cur_time);
 | |
| 
 | |
|   memset(&pni, 0, sizeof(pni));
 | |
|   pni.pni_cookie = (void** )&pn;
 | |
| 
 | |
|   memset(&va, 0, sizeof(va));
 | |
|   va.va_type = VDIR;
 | |
|   va.va_mode = mode;
 | |
|   va.va_uid = uid;
 | |
|   va.va_gid = gid;
 | |
|   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
 | |
| 
 | |
|   if (buildpath) {
 | |
| 	r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
 | |
| 	if (r) {
 | |
| 		lpuffs_debug("pathbuild error\n");
 | |
| 		return(ENOENT);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   r = global_pu->pu_ops.puffs_node_mkdir(global_pu, pn_dir, &pni, &pcn, &va);
 | |
|   if (buildpath) {
 | |
| 	if (r) {
 | |
| 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
 | |
| 	} else {
 | |
| 		struct puffs_node *_pn;
 | |
| 
 | |
| 		_pn = PU_CMAP(global_pu, pn);
 | |
| 		_pn->pn_po = pcn.pcn_po_full;
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   if (r != OK) {
 | |
| 	if (r > 0) r = -r;
 | |
| 	return(r);
 | |
|   }
 | |
| 
 | |
|   update_timens(pn_dir, MTIME | CTIME, &cur_time);
 | |
| 
 | |
|   return(OK);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *                             fs_slink 				     *
 | |
|  *===========================================================================*/
 | |
| int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
 | |
| 	struct fsdriver_data *data, size_t bytes)
 | |
| {
 | |
|   int r;
 | |
|   struct pnode *pn;		/* pnode containing symbolic link */
 | |
|   struct pnode *pn_dir;		/* directory containing link */
 | |
|   char target[PATH_MAX + 1];	/* target path */
 | |
|   struct puffs_newinfo pni;
 | |
|   struct puffs_kcn pkcnp;
 | |
|   PUFFS_MAKECRED(pcr, &global_kcred);
 | |
|   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
 | |
|   struct vattr va;
 | |
|   struct timespec cur_time;
 | |
| 
 | |
|   /* Copy the link name's last component */
 | |
|   pcn.pcn_namelen = strlen(name);
 | |
|   if (pcn.pcn_namelen <= NAME_MAX);
 | |
|   strcpy(pcn.pcn_name, name);
 | |
| 
 | |
|   if (bytes >= PATH_MAX)
 | |
| 	return(ENAMETOOLONG);
 | |
| 
 | |
|   /* Copy the target path (note that it's not null terminated) */
 | |
|   if ((r = fsdriver_copyin(data, 0, target, bytes)) != OK)
 | |
| 	return r;
 | |
| 
 | |
|   target[bytes] = '\0';
 | |
| 
 | |
|   if (strlen(target) != bytes) {
 | |
| 	/* This can happen if the user provides a buffer
 | |
| 	 * with a \0 in it. This can cause a lot of trouble
 | |
| 	 * when the symlink is used later. We could just use
 | |
| 	 * the strlen() value, but we want to let the user
 | |
| 	 * know he did something wrong. ENAMETOOLONG doesn't
 | |
| 	 * exactly describe the error, but there is no
 | |
| 	 * ENAMETOOWRONG.
 | |
| 	 */
 | |
| 	return(ENAMETOOLONG);
 | |
|   }
 | |
| 
 | |
|   if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
 | |
| 	return(EINVAL);
 | |
| 
 | |
|   memset(&pni, 0, sizeof(pni));
 | |
|   pni.pni_cookie = (void** )&pn;
 | |
| 
 | |
|   (void)clock_time(&cur_time);
 | |
| 
 | |
|   memset(&va, 0, sizeof(va));
 | |
|   va.va_type = VLNK;
 | |
|   va.va_mode = (I_SYMBOLIC_LINK | RWX_MODES);
 | |
|   va.va_uid = uid;
 | |
|   va.va_gid = gid;
 | |
|   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
 | |
| 
 | |
|   if (buildpath) {
 | |
| 	r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
 | |
| 	if (r) {
 | |
| 		lpuffs_debug("pathbuild error\n");
 | |
| 		return(ENOENT);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   r = global_pu->pu_ops.puffs_node_symlink(global_pu, pn_dir, &pni, &pcn, &va, target);
 | |
|   if (buildpath) {
 | |
| 	if (r) {
 | |
| 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
 | |
| 	} else {
 | |
| 		struct puffs_node *_pn;
 | |
| 
 | |
| 		_pn = PU_CMAP(global_pu, pn);
 | |
| 		_pn->pn_po = pcn.pcn_po_full;
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   if (r > 0) r = -r;
 | |
| 
 | |
|   return(r);
 | |
| }
 | 
