xref: /minix3/minix/lib/libpuffs/open.c (revision ba736c796854b82e29da17267614db0a449419db)
1*ba736c79SDavid van Moolenbroek /* Created (MFS based):
2*ba736c79SDavid van Moolenbroek  *   June 2011 (Evgeniy Ivanov)
3*ba736c79SDavid van Moolenbroek  */
4*ba736c79SDavid van Moolenbroek 
5*ba736c79SDavid van Moolenbroek #include "fs.h"
6*ba736c79SDavid van Moolenbroek 
7*ba736c79SDavid van Moolenbroek /*===========================================================================*
8*ba736c79SDavid van Moolenbroek  *				fs_create				     *
9*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_create(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid,struct fsdriver_node * node)10*ba736c79SDavid van Moolenbroek int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
11*ba736c79SDavid van Moolenbroek 	struct fsdriver_node *node)
12*ba736c79SDavid van Moolenbroek {
13*ba736c79SDavid van Moolenbroek   int r;
14*ba736c79SDavid van Moolenbroek   struct puffs_node *pn_dir;
15*ba736c79SDavid van Moolenbroek   struct puffs_node *pn;
16*ba736c79SDavid van Moolenbroek   struct puffs_newinfo pni;
17*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp;
18*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
19*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
20*ba736c79SDavid van Moolenbroek   struct vattr va;
21*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
22*ba736c79SDavid van Moolenbroek 
23*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_create == NULL) {
24*ba736c79SDavid van Moolenbroek 	lpuffs_debug("No puffs_node_create");
25*ba736c79SDavid van Moolenbroek 	return(ENFILE);
26*ba736c79SDavid van Moolenbroek   }
27*ba736c79SDavid van Moolenbroek 
28*ba736c79SDavid van Moolenbroek   /* Copy the last component (i.e., file name) */
29*ba736c79SDavid van Moolenbroek   pcn.pcn_namelen = strlen(name);
30*ba736c79SDavid van Moolenbroek   assert(pcn.pcn_namelen <= NAME_MAX);
31*ba736c79SDavid van Moolenbroek   strcpy(pcn.pcn_name, name);
32*ba736c79SDavid van Moolenbroek 
33*ba736c79SDavid van Moolenbroek   /* Get last directory pnode (i.e., directory that will hold the new pnode) */
34*ba736c79SDavid van Moolenbroek   if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
35*ba736c79SDavid van Moolenbroek 	return(ENOENT);
36*ba736c79SDavid van Moolenbroek 
37*ba736c79SDavid van Moolenbroek   memset(&pni, 0, sizeof(pni));
38*ba736c79SDavid van Moolenbroek   pni.pni_cookie = (void** )&pn;
39*ba736c79SDavid van Moolenbroek 
40*ba736c79SDavid van Moolenbroek   (void)clock_time(&cur_time);
41*ba736c79SDavid van Moolenbroek 
42*ba736c79SDavid van Moolenbroek   memset(&va, 0, sizeof(va));
43*ba736c79SDavid van Moolenbroek   va.va_type = VREG;
44*ba736c79SDavid van Moolenbroek   va.va_mode = mode;
45*ba736c79SDavid van Moolenbroek   va.va_uid = uid;
46*ba736c79SDavid van Moolenbroek   va.va_gid = gid;
47*ba736c79SDavid van Moolenbroek   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
48*ba736c79SDavid van Moolenbroek 
49*ba736c79SDavid van Moolenbroek   if (buildpath) {
50*ba736c79SDavid van Moolenbroek 	r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
51*ba736c79SDavid van Moolenbroek 	if (r) {
52*ba736c79SDavid van Moolenbroek 		lpuffs_debug("pathbuild error\n");
53*ba736c79SDavid van Moolenbroek 		return(ENOENT);
54*ba736c79SDavid van Moolenbroek 	}
55*ba736c79SDavid van Moolenbroek   }
56*ba736c79SDavid van Moolenbroek 
57*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_create(global_pu, pn_dir, &pni, &pcn, &va);
58*ba736c79SDavid van Moolenbroek   if (buildpath) {
59*ba736c79SDavid van Moolenbroek 	if (r) {
60*ba736c79SDavid van Moolenbroek 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
61*ba736c79SDavid van Moolenbroek 	} else {
62*ba736c79SDavid van Moolenbroek 		struct puffs_node *_pn;
63*ba736c79SDavid van Moolenbroek 
64*ba736c79SDavid van Moolenbroek 		_pn = PU_CMAP(global_pu, pn);
65*ba736c79SDavid van Moolenbroek 		_pn->pn_po = pcn.pcn_po_full;
66*ba736c79SDavid van Moolenbroek 	}
67*ba736c79SDavid van Moolenbroek   }
68*ba736c79SDavid van Moolenbroek 
69*ba736c79SDavid van Moolenbroek   if (r != OK) {
70*ba736c79SDavid van Moolenbroek 	if (r > 0) r = -r;
71*ba736c79SDavid van Moolenbroek 	return(r);
72*ba736c79SDavid van Moolenbroek   }
73*ba736c79SDavid van Moolenbroek 
74*ba736c79SDavid van Moolenbroek   /* Open pnode */
75*ba736c79SDavid van Moolenbroek   pn->pn_count++;
76*ba736c79SDavid van Moolenbroek 
77*ba736c79SDavid van Moolenbroek   update_timens(pn_dir, MTIME | CTIME, &cur_time);
78*ba736c79SDavid van Moolenbroek 
79*ba736c79SDavid van Moolenbroek   /* Reply message */
80*ba736c79SDavid van Moolenbroek   node->fn_ino_nr = pn->pn_va.va_fileid;
81*ba736c79SDavid van Moolenbroek   node->fn_mode = pn->pn_va.va_mode;
82*ba736c79SDavid van Moolenbroek   node->fn_size = pn->pn_va.va_size;
83*ba736c79SDavid van Moolenbroek   node->fn_uid = pn->pn_va.va_uid;
84*ba736c79SDavid van Moolenbroek   node->fn_gid = pn->pn_va.va_gid;
85*ba736c79SDavid van Moolenbroek   node->fn_dev = NO_DEV;
86*ba736c79SDavid van Moolenbroek 
87*ba736c79SDavid van Moolenbroek   return(OK);
88*ba736c79SDavid van Moolenbroek }
89*ba736c79SDavid van Moolenbroek 
90*ba736c79SDavid van Moolenbroek 
91*ba736c79SDavid van Moolenbroek /*===========================================================================*
92*ba736c79SDavid van Moolenbroek  *				fs_mknod				     *
93*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_mknod(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid,dev_t dev)94*ba736c79SDavid van Moolenbroek int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
95*ba736c79SDavid van Moolenbroek 	dev_t dev)
96*ba736c79SDavid van Moolenbroek {
97*ba736c79SDavid van Moolenbroek   int r;
98*ba736c79SDavid van Moolenbroek   struct puffs_node *pn_dir;
99*ba736c79SDavid van Moolenbroek   struct puffs_node *pn;
100*ba736c79SDavid van Moolenbroek   struct puffs_newinfo pni;
101*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp;
102*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
103*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
104*ba736c79SDavid van Moolenbroek   struct vattr va;
105*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
106*ba736c79SDavid van Moolenbroek 
107*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_mknod == NULL) {
108*ba736c79SDavid van Moolenbroek 	lpuffs_debug("No puffs_node_mknod");
109*ba736c79SDavid van Moolenbroek 	return(ENFILE);
110*ba736c79SDavid van Moolenbroek   }
111*ba736c79SDavid van Moolenbroek 
112*ba736c79SDavid van Moolenbroek   /* Copy the last component */
113*ba736c79SDavid van Moolenbroek   pcn.pcn_namelen = strlen(name);
114*ba736c79SDavid van Moolenbroek   assert(pcn.pcn_namelen <= NAME_MAX);
115*ba736c79SDavid van Moolenbroek   strcpy(pcn.pcn_name, name);
116*ba736c79SDavid van Moolenbroek 
117*ba736c79SDavid van Moolenbroek   /* Get last directory pnode */
118*ba736c79SDavid van Moolenbroek   if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
119*ba736c79SDavid van Moolenbroek 	return(ENOENT);
120*ba736c79SDavid van Moolenbroek 
121*ba736c79SDavid van Moolenbroek   memset(&pni, 0, sizeof(pni));
122*ba736c79SDavid van Moolenbroek   pni.pni_cookie = (void** )&pn;
123*ba736c79SDavid van Moolenbroek 
124*ba736c79SDavid van Moolenbroek   (void)clock_time(&cur_time);
125*ba736c79SDavid van Moolenbroek 
126*ba736c79SDavid van Moolenbroek   memset(&va, 0, sizeof(va));
127*ba736c79SDavid van Moolenbroek   va.va_type = VDIR;
128*ba736c79SDavid van Moolenbroek   va.va_mode = mode;
129*ba736c79SDavid van Moolenbroek   va.va_uid = uid;
130*ba736c79SDavid van Moolenbroek   va.va_gid = gid;
131*ba736c79SDavid van Moolenbroek   va.va_rdev = dev;
132*ba736c79SDavid van Moolenbroek   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
133*ba736c79SDavid van Moolenbroek 
134*ba736c79SDavid van Moolenbroek   if (buildpath) {
135*ba736c79SDavid van Moolenbroek 	if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0) {
136*ba736c79SDavid van Moolenbroek 		lpuffs_debug("pathbuild error\n");
137*ba736c79SDavid van Moolenbroek 		return(ENOENT);
138*ba736c79SDavid van Moolenbroek 	}
139*ba736c79SDavid van Moolenbroek   }
140*ba736c79SDavid van Moolenbroek 
141*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_mknod(global_pu, pn_dir, &pni, &pcn, &va);
142*ba736c79SDavid van Moolenbroek   if (buildpath) {
143*ba736c79SDavid van Moolenbroek 	if (r) {
144*ba736c79SDavid van Moolenbroek 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
145*ba736c79SDavid van Moolenbroek 	} else {
146*ba736c79SDavid van Moolenbroek 		struct puffs_node *_pn;
147*ba736c79SDavid van Moolenbroek 
148*ba736c79SDavid van Moolenbroek 		_pn = PU_CMAP(global_pu, pn);
149*ba736c79SDavid van Moolenbroek 		_pn->pn_po = pcn.pcn_po_full;
150*ba736c79SDavid van Moolenbroek 	  }
151*ba736c79SDavid van Moolenbroek   }
152*ba736c79SDavid van Moolenbroek 
153*ba736c79SDavid van Moolenbroek   if (r != OK) {
154*ba736c79SDavid van Moolenbroek 	if (r > 0) r = -r;
155*ba736c79SDavid van Moolenbroek 	return(r);
156*ba736c79SDavid van Moolenbroek   }
157*ba736c79SDavid van Moolenbroek 
158*ba736c79SDavid van Moolenbroek   update_timens(pn_dir, MTIME | CTIME, &cur_time);
159*ba736c79SDavid van Moolenbroek 
160*ba736c79SDavid van Moolenbroek   return(OK);
161*ba736c79SDavid van Moolenbroek }
162*ba736c79SDavid van Moolenbroek 
163*ba736c79SDavid van Moolenbroek 
164*ba736c79SDavid van Moolenbroek /*===========================================================================*
165*ba736c79SDavid van Moolenbroek  *				fs_mkdir				     *
166*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_mkdir(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid)167*ba736c79SDavid van Moolenbroek int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
168*ba736c79SDavid van Moolenbroek {
169*ba736c79SDavid van Moolenbroek   int r;
170*ba736c79SDavid van Moolenbroek   struct puffs_node *pn_dir;
171*ba736c79SDavid van Moolenbroek   struct puffs_node *pn;
172*ba736c79SDavid van Moolenbroek   struct puffs_newinfo pni;
173*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp;
174*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
175*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
176*ba736c79SDavid van Moolenbroek   struct vattr va;
177*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
178*ba736c79SDavid van Moolenbroek 
179*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_mkdir == NULL) {
180*ba736c79SDavid van Moolenbroek 	lpuffs_debug("No puffs_node_mkdir");
181*ba736c79SDavid van Moolenbroek 	return(ENFILE);
182*ba736c79SDavid van Moolenbroek   }
183*ba736c79SDavid van Moolenbroek 
184*ba736c79SDavid van Moolenbroek   /* Copy the last component */
185*ba736c79SDavid van Moolenbroek   pcn.pcn_namelen = strlen(name);
186*ba736c79SDavid van Moolenbroek   assert(pcn.pcn_namelen <= NAME_MAX);
187*ba736c79SDavid van Moolenbroek   strcpy(pcn.pcn_name, name);
188*ba736c79SDavid van Moolenbroek 
189*ba736c79SDavid van Moolenbroek   /* Get last directory pnode */
190*ba736c79SDavid van Moolenbroek   if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
191*ba736c79SDavid van Moolenbroek 	return(ENOENT);
192*ba736c79SDavid van Moolenbroek 
193*ba736c79SDavid van Moolenbroek   (void)clock_time(&cur_time);
194*ba736c79SDavid van Moolenbroek 
195*ba736c79SDavid van Moolenbroek   memset(&pni, 0, sizeof(pni));
196*ba736c79SDavid van Moolenbroek   pni.pni_cookie = (void** )&pn;
197*ba736c79SDavid van Moolenbroek 
198*ba736c79SDavid van Moolenbroek   memset(&va, 0, sizeof(va));
199*ba736c79SDavid van Moolenbroek   va.va_type = VDIR;
200*ba736c79SDavid van Moolenbroek   va.va_mode = mode;
201*ba736c79SDavid van Moolenbroek   va.va_uid = uid;
202*ba736c79SDavid van Moolenbroek   va.va_gid = gid;
203*ba736c79SDavid van Moolenbroek   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
204*ba736c79SDavid van Moolenbroek 
205*ba736c79SDavid van Moolenbroek   if (buildpath) {
206*ba736c79SDavid van Moolenbroek 	r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
207*ba736c79SDavid van Moolenbroek 	if (r) {
208*ba736c79SDavid van Moolenbroek 		lpuffs_debug("pathbuild error\n");
209*ba736c79SDavid van Moolenbroek 		return(ENOENT);
210*ba736c79SDavid van Moolenbroek 	}
211*ba736c79SDavid van Moolenbroek   }
212*ba736c79SDavid van Moolenbroek 
213*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_mkdir(global_pu, pn_dir, &pni, &pcn, &va);
214*ba736c79SDavid van Moolenbroek   if (buildpath) {
215*ba736c79SDavid van Moolenbroek 	if (r) {
216*ba736c79SDavid van Moolenbroek 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
217*ba736c79SDavid van Moolenbroek 	} else {
218*ba736c79SDavid van Moolenbroek 		struct puffs_node *_pn;
219*ba736c79SDavid van Moolenbroek 
220*ba736c79SDavid van Moolenbroek 		_pn = PU_CMAP(global_pu, pn);
221*ba736c79SDavid van Moolenbroek 		_pn->pn_po = pcn.pcn_po_full;
222*ba736c79SDavid van Moolenbroek 	}
223*ba736c79SDavid van Moolenbroek   }
224*ba736c79SDavid van Moolenbroek 
225*ba736c79SDavid van Moolenbroek   if (r != OK) {
226*ba736c79SDavid van Moolenbroek 	if (r > 0) r = -r;
227*ba736c79SDavid van Moolenbroek 	return(r);
228*ba736c79SDavid van Moolenbroek   }
229*ba736c79SDavid van Moolenbroek 
230*ba736c79SDavid van Moolenbroek   update_timens(pn_dir, MTIME | CTIME, &cur_time);
231*ba736c79SDavid van Moolenbroek 
232*ba736c79SDavid van Moolenbroek   return(OK);
233*ba736c79SDavid van Moolenbroek }
234*ba736c79SDavid van Moolenbroek 
235*ba736c79SDavid van Moolenbroek 
236*ba736c79SDavid van Moolenbroek /*===========================================================================*
237*ba736c79SDavid van Moolenbroek  *                             fs_slink 				     *
238*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_slink(ino_t dir_nr,char * name,uid_t uid,gid_t gid,struct fsdriver_data * data,size_t bytes)239*ba736c79SDavid van Moolenbroek int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
240*ba736c79SDavid van Moolenbroek 	struct fsdriver_data *data, size_t bytes)
241*ba736c79SDavid van Moolenbroek {
242*ba736c79SDavid van Moolenbroek   int r;
243*ba736c79SDavid van Moolenbroek   struct pnode *pn;		/* pnode containing symbolic link */
244*ba736c79SDavid van Moolenbroek   struct pnode *pn_dir;		/* directory containing link */
245*ba736c79SDavid van Moolenbroek   char target[PATH_MAX + 1];	/* target path */
246*ba736c79SDavid van Moolenbroek   struct puffs_newinfo pni;
247*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp;
248*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
249*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
250*ba736c79SDavid van Moolenbroek   struct vattr va;
251*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
252*ba736c79SDavid van Moolenbroek 
253*ba736c79SDavid van Moolenbroek   /* Copy the link name's last component */
254*ba736c79SDavid van Moolenbroek   pcn.pcn_namelen = strlen(name);
255*ba736c79SDavid van Moolenbroek   if (pcn.pcn_namelen > NAME_MAX)
256*ba736c79SDavid van Moolenbroek 	return(ENAMETOOLONG);
257*ba736c79SDavid van Moolenbroek   strcpy(pcn.pcn_name, name);
258*ba736c79SDavid van Moolenbroek 
259*ba736c79SDavid van Moolenbroek   if (bytes >= PATH_MAX)
260*ba736c79SDavid van Moolenbroek 	return(ENAMETOOLONG);
261*ba736c79SDavid van Moolenbroek 
262*ba736c79SDavid van Moolenbroek   /* Copy the target path (note that it's not null terminated) */
263*ba736c79SDavid van Moolenbroek   if ((r = fsdriver_copyin(data, 0, target, bytes)) != OK)
264*ba736c79SDavid van Moolenbroek 	return r;
265*ba736c79SDavid van Moolenbroek 
266*ba736c79SDavid van Moolenbroek   target[bytes] = '\0';
267*ba736c79SDavid van Moolenbroek 
268*ba736c79SDavid van Moolenbroek   if (strlen(target) != bytes) {
269*ba736c79SDavid van Moolenbroek 	/* This can happen if the user provides a buffer
270*ba736c79SDavid van Moolenbroek 	 * with a \0 in it. This can cause a lot of trouble
271*ba736c79SDavid van Moolenbroek 	 * when the symlink is used later. We could just use
272*ba736c79SDavid van Moolenbroek 	 * the strlen() value, but we want to let the user
273*ba736c79SDavid van Moolenbroek 	 * know he did something wrong. ENAMETOOLONG doesn't
274*ba736c79SDavid van Moolenbroek 	 * exactly describe the error, but there is no
275*ba736c79SDavid van Moolenbroek 	 * ENAMETOOWRONG.
276*ba736c79SDavid van Moolenbroek 	 */
277*ba736c79SDavid van Moolenbroek 	return(ENAMETOOLONG);
278*ba736c79SDavid van Moolenbroek   }
279*ba736c79SDavid van Moolenbroek 
280*ba736c79SDavid van Moolenbroek   if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
281*ba736c79SDavid van Moolenbroek 	return(EINVAL);
282*ba736c79SDavid van Moolenbroek 
283*ba736c79SDavid van Moolenbroek   memset(&pni, 0, sizeof(pni));
284*ba736c79SDavid van Moolenbroek   pni.pni_cookie = (void** )&pn;
285*ba736c79SDavid van Moolenbroek 
286*ba736c79SDavid van Moolenbroek   (void)clock_time(&cur_time);
287*ba736c79SDavid van Moolenbroek 
288*ba736c79SDavid van Moolenbroek   memset(&va, 0, sizeof(va));
289*ba736c79SDavid van Moolenbroek   va.va_type = VLNK;
290*ba736c79SDavid van Moolenbroek   va.va_mode = (I_SYMBOLIC_LINK | RWX_MODES);
291*ba736c79SDavid van Moolenbroek   va.va_uid = uid;
292*ba736c79SDavid van Moolenbroek   va.va_gid = gid;
293*ba736c79SDavid van Moolenbroek   va.va_atime = va.va_mtime = va.va_ctime = cur_time;
294*ba736c79SDavid van Moolenbroek 
295*ba736c79SDavid van Moolenbroek   if (buildpath) {
296*ba736c79SDavid van Moolenbroek 	r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
297*ba736c79SDavid van Moolenbroek 	if (r) {
298*ba736c79SDavid van Moolenbroek 		lpuffs_debug("pathbuild error\n");
299*ba736c79SDavid van Moolenbroek 		return(ENOENT);
300*ba736c79SDavid van Moolenbroek 	}
301*ba736c79SDavid van Moolenbroek   }
302*ba736c79SDavid van Moolenbroek 
303*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_symlink(global_pu, pn_dir, &pni, &pcn, &va, target);
304*ba736c79SDavid van Moolenbroek   if (buildpath) {
305*ba736c79SDavid van Moolenbroek 	if (r) {
306*ba736c79SDavid van Moolenbroek 		global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
307*ba736c79SDavid van Moolenbroek 	} else {
308*ba736c79SDavid van Moolenbroek 		struct puffs_node *_pn;
309*ba736c79SDavid van Moolenbroek 
310*ba736c79SDavid van Moolenbroek 		_pn = PU_CMAP(global_pu, pn);
311*ba736c79SDavid van Moolenbroek 		_pn->pn_po = pcn.pcn_po_full;
312*ba736c79SDavid van Moolenbroek 	}
313*ba736c79SDavid van Moolenbroek   }
314*ba736c79SDavid van Moolenbroek 
315*ba736c79SDavid van Moolenbroek   if (r > 0) r = -r;
316*ba736c79SDavid van Moolenbroek 
317*ba736c79SDavid van Moolenbroek   return(r);
318*ba736c79SDavid van Moolenbroek }
319