xref: /minix3/minix/lib/libpuffs/link.c (revision ba736c796854b82e29da17267614db0a449419db)
1*ba736c79SDavid van Moolenbroek #include "fs.h"
2*ba736c79SDavid van Moolenbroek 
3*ba736c79SDavid van Moolenbroek /*===========================================================================*
4*ba736c79SDavid van Moolenbroek  *				fs_trunc				     *
5*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_trunc(ino_t ino_nr,off_t start,off_t end)6*ba736c79SDavid van Moolenbroek int fs_trunc(ino_t ino_nr, off_t start, off_t end)
7*ba736c79SDavid van Moolenbroek {
8*ba736c79SDavid van Moolenbroek   int r;
9*ba736c79SDavid van Moolenbroek   struct puffs_node *pn;
10*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
11*ba736c79SDavid van Moolenbroek 
12*ba736c79SDavid van Moolenbroek   if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
13*ba736c79SDavid van Moolenbroek           return(EINVAL);
14*ba736c79SDavid van Moolenbroek 
15*ba736c79SDavid van Moolenbroek   if (end == 0) {
16*ba736c79SDavid van Moolenbroek 	struct vattr va;
17*ba736c79SDavid van Moolenbroek 
18*ba736c79SDavid van Moolenbroek 	if (pn->pn_va.va_size == (u_quad_t) start)
19*ba736c79SDavid van Moolenbroek 		return(OK);
20*ba736c79SDavid van Moolenbroek 
21*ba736c79SDavid van Moolenbroek 	if (global_pu->pu_ops.puffs_node_setattr == NULL)
22*ba736c79SDavid van Moolenbroek 		return(EINVAL);
23*ba736c79SDavid van Moolenbroek 
24*ba736c79SDavid van Moolenbroek 	puffs_vattr_null(&va);
25*ba736c79SDavid van Moolenbroek 	va.va_size = start;
26*ba736c79SDavid van Moolenbroek 
27*ba736c79SDavid van Moolenbroek 	r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr);
28*ba736c79SDavid van Moolenbroek 	if (r) return(EINVAL);
29*ba736c79SDavid van Moolenbroek   } else {
30*ba736c79SDavid van Moolenbroek 	/* XXX zerofill the given region. Can we make a hole? */
31*ba736c79SDavid van Moolenbroek 	off_t bytes_left = end - start;
32*ba736c79SDavid van Moolenbroek 	char* rw_buf;
33*ba736c79SDavid van Moolenbroek 
34*ba736c79SDavid van Moolenbroek 	if (global_pu->pu_ops.puffs_node_write == NULL)
35*ba736c79SDavid van Moolenbroek 		return(EINVAL);
36*ba736c79SDavid van Moolenbroek 
37*ba736c79SDavid van Moolenbroek 	/* XXX split into chunks? */
38*ba736c79SDavid van Moolenbroek 	rw_buf = malloc(bytes_left);
39*ba736c79SDavid van Moolenbroek 	if (!rw_buf)
40*ba736c79SDavid van Moolenbroek 		panic("fs_ftrunc: failed to allocated memory\n");
41*ba736c79SDavid van Moolenbroek 	memset(rw_buf, 0, bytes_left);
42*ba736c79SDavid van Moolenbroek 
43*ba736c79SDavid van Moolenbroek 	r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf,
44*ba736c79SDavid van Moolenbroek 					start, (size_t *) &bytes_left, pcr, 0);
45*ba736c79SDavid van Moolenbroek 	free(rw_buf);
46*ba736c79SDavid van Moolenbroek 	if (r) return(EINVAL);
47*ba736c79SDavid van Moolenbroek   }
48*ba736c79SDavid van Moolenbroek 
49*ba736c79SDavid van Moolenbroek   update_timens(pn, CTIME | MTIME, NULL);
50*ba736c79SDavid van Moolenbroek 
51*ba736c79SDavid van Moolenbroek   return(r);
52*ba736c79SDavid van Moolenbroek }
53*ba736c79SDavid van Moolenbroek 
54*ba736c79SDavid van Moolenbroek 
55*ba736c79SDavid van Moolenbroek /*===========================================================================*
56*ba736c79SDavid van Moolenbroek  *                              fs_link                                      *
57*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_link(ino_t dir_nr,char * name,ino_t ino_nr)58*ba736c79SDavid van Moolenbroek int fs_link(ino_t dir_nr, char *name, ino_t ino_nr)
59*ba736c79SDavid van Moolenbroek {
60*ba736c79SDavid van Moolenbroek /* Perform the link(name1, name2) system call. */
61*ba736c79SDavid van Moolenbroek 
62*ba736c79SDavid van Moolenbroek   register int r;
63*ba736c79SDavid van Moolenbroek   struct puffs_node *pn, *pn_dir, *new_pn;
64*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
65*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp;
66*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
67*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
68*ba736c79SDavid van Moolenbroek 
69*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_link == NULL)
70*ba736c79SDavid van Moolenbroek 	return(OK);
71*ba736c79SDavid van Moolenbroek 
72*ba736c79SDavid van Moolenbroek   if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
73*ba736c79SDavid van Moolenbroek 	return(EINVAL);
74*ba736c79SDavid van Moolenbroek 
75*ba736c79SDavid van Moolenbroek   /* Check to see if the file has maximum number of links already. */
76*ba736c79SDavid van Moolenbroek   if (pn->pn_va.va_nlink >= LINK_MAX)
77*ba736c79SDavid van Moolenbroek 	return(EMLINK);
78*ba736c79SDavid van Moolenbroek 
79*ba736c79SDavid van Moolenbroek   /* Linking directories is too dangerous to allow. */
80*ba736c79SDavid van Moolenbroek   if (S_ISDIR(pn->pn_va.va_mode))
81*ba736c79SDavid van Moolenbroek 	return(EPERM);
82*ba736c79SDavid van Moolenbroek 
83*ba736c79SDavid van Moolenbroek   if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
84*ba736c79SDavid van Moolenbroek         return(EINVAL);
85*ba736c79SDavid van Moolenbroek 
86*ba736c79SDavid van Moolenbroek   if (pn_dir->pn_va.va_nlink == NO_LINK) {
87*ba736c79SDavid van Moolenbroek 	/* Dir does not actually exist */
88*ba736c79SDavid van Moolenbroek         return(ENOENT);
89*ba736c79SDavid van Moolenbroek   }
90*ba736c79SDavid van Moolenbroek 
91*ba736c79SDavid van Moolenbroek   /* If 'name2' exists in full (even if no space) set 'r' to error. */
92*ba736c79SDavid van Moolenbroek   if ((new_pn = advance(pn_dir, name)) == NULL) {
93*ba736c79SDavid van Moolenbroek         r = err_code;
94*ba736c79SDavid van Moolenbroek         if (r == ENOENT) r = OK;
95*ba736c79SDavid van Moolenbroek   } else {
96*ba736c79SDavid van Moolenbroek         r = EEXIST;
97*ba736c79SDavid van Moolenbroek   }
98*ba736c79SDavid van Moolenbroek 
99*ba736c79SDavid van Moolenbroek   if (r != OK) return(r);
100*ba736c79SDavid van Moolenbroek 
101*ba736c79SDavid van Moolenbroek   /* Try to link. */
102*ba736c79SDavid van Moolenbroek   pcn.pcn_namelen = strlen(name);
103*ba736c79SDavid van Moolenbroek   assert(pcn.pcn_namelen <= NAME_MAX);
104*ba736c79SDavid van Moolenbroek   strcpy(pcn.pcn_name, name);
105*ba736c79SDavid van Moolenbroek 
106*ba736c79SDavid van Moolenbroek   if (buildpath) {
107*ba736c79SDavid van Moolenbroek 	if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0)
108*ba736c79SDavid van Moolenbroek 		return(EINVAL);
109*ba736c79SDavid van Moolenbroek   }
110*ba736c79SDavid van Moolenbroek 
111*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_link(global_pu, pn_dir, pn, &pcn) != 0)
112*ba736c79SDavid van Moolenbroek 	r = EINVAL;
113*ba736c79SDavid van Moolenbroek 
114*ba736c79SDavid van Moolenbroek   if (buildpath)
115*ba736c79SDavid van Moolenbroek 	global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
116*ba736c79SDavid van Moolenbroek 
117*ba736c79SDavid van Moolenbroek   if (r != OK) return(EINVAL);
118*ba736c79SDavid van Moolenbroek 
119*ba736c79SDavid van Moolenbroek   (void)clock_time(&cur_time);
120*ba736c79SDavid van Moolenbroek   update_timens(pn, CTIME, &cur_time);
121*ba736c79SDavid van Moolenbroek   update_timens(pn_dir, MTIME | CTIME, &cur_time);
122*ba736c79SDavid van Moolenbroek 
123*ba736c79SDavid van Moolenbroek   return(OK);
124*ba736c79SDavid van Moolenbroek }
125*ba736c79SDavid van Moolenbroek 
126*ba736c79SDavid van Moolenbroek 
127*ba736c79SDavid van Moolenbroek /*===========================================================================*
128*ba736c79SDavid van Moolenbroek  *                             fs_rdlink                                     *
129*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_rdlink(ino_t ino_nr,struct fsdriver_data * data,size_t bytes)130*ba736c79SDavid van Moolenbroek ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes)
131*ba736c79SDavid van Moolenbroek {
132*ba736c79SDavid van Moolenbroek   register int r;              /* return value */
133*ba736c79SDavid van Moolenbroek   struct puffs_node *pn;
134*ba736c79SDavid van Moolenbroek   char path[PATH_MAX];
135*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr, &global_kcred);
136*ba736c79SDavid van Moolenbroek 
137*ba736c79SDavid van Moolenbroek   if (bytes > sizeof(path))
138*ba736c79SDavid van Moolenbroek 	bytes = sizeof(path);
139*ba736c79SDavid van Moolenbroek 
140*ba736c79SDavid van Moolenbroek   if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
141*ba736c79SDavid van Moolenbroek 	return(EINVAL);
142*ba736c79SDavid van Moolenbroek 
143*ba736c79SDavid van Moolenbroek   if (!S_ISLNK(pn->pn_va.va_mode))
144*ba736c79SDavid van Moolenbroek 	return(EACCES);
145*ba736c79SDavid van Moolenbroek 
146*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_readlink == NULL)
147*ba736c79SDavid van Moolenbroek 	return(EINVAL);
148*ba736c79SDavid van Moolenbroek 
149*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_readlink(global_pu, pn, pcr, path, &bytes);
150*ba736c79SDavid van Moolenbroek   if (r != OK) {
151*ba736c79SDavid van Moolenbroek 	if (r > 0) r = -r;
152*ba736c79SDavid van Moolenbroek 	return(r);
153*ba736c79SDavid van Moolenbroek   }
154*ba736c79SDavid van Moolenbroek 
155*ba736c79SDavid van Moolenbroek   r = fsdriver_copyout(data, 0, path, bytes);
156*ba736c79SDavid van Moolenbroek 
157*ba736c79SDavid van Moolenbroek   return (r == OK) ? (ssize_t)bytes : r;
158*ba736c79SDavid van Moolenbroek }
159*ba736c79SDavid van Moolenbroek 
160*ba736c79SDavid van Moolenbroek 
161*ba736c79SDavid van Moolenbroek /*===========================================================================*
162*ba736c79SDavid van Moolenbroek  *                              fs_rename                                    *
163*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_rename(ino_t old_dir_nr,char * old_name,ino_t new_dir_nr,char * new_name)164*ba736c79SDavid van Moolenbroek int fs_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
165*ba736c79SDavid van Moolenbroek 	char *new_name)
166*ba736c79SDavid van Moolenbroek {
167*ba736c79SDavid van Moolenbroek /* Perform the rename(name1, name2) system call. */
168*ba736c79SDavid van Moolenbroek   struct puffs_node *old_dirp, *old_ip;      /* ptrs to old dir, file pnodes */
169*ba736c79SDavid van Moolenbroek   struct puffs_node *new_dirp, *new_ip;      /* ptrs to new dir, file pnodes */
170*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp_src;
171*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr_src, &global_kcred);
172*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn_src = {&pkcnp_src, (struct puffs_cred *) __UNCONST(pcr_src), {0,0,0}};
173*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp_dest;
174*ba736c79SDavid van Moolenbroek   PUFFS_MAKECRED(pcr_dest, &global_kcred);
175*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn_targ = {&pkcnp_dest, (struct puffs_cred *) __UNCONST(pcr_dest), {0,0,0}};
176*ba736c79SDavid van Moolenbroek   int r = OK;                           /* error flag; initially no error */
177*ba736c79SDavid van Moolenbroek   int odir, ndir;                       /* TRUE iff {old|new} file is dir */
178*ba736c79SDavid van Moolenbroek   int same_pdir;                        /* TRUE iff parent dirs are the same */
179*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
180*ba736c79SDavid van Moolenbroek 
181*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_rename == NULL)
182*ba736c79SDavid van Moolenbroek 	return(EINVAL);
183*ba736c79SDavid van Moolenbroek 
184*ba736c79SDavid van Moolenbroek   /* Copy the last component of the old name */
185*ba736c79SDavid van Moolenbroek   pcn_src.pcn_namelen = strlen(old_name);
186*ba736c79SDavid van Moolenbroek   assert(pcn_src.pcn_namelen <= NAME_MAX);
187*ba736c79SDavid van Moolenbroek   strcpy(pcn_src.pcn_name, old_name);
188*ba736c79SDavid van Moolenbroek 
189*ba736c79SDavid van Moolenbroek   /* Copy the last component of the new name */
190*ba736c79SDavid van Moolenbroek   pcn_targ.pcn_namelen = strlen(new_name);
191*ba736c79SDavid van Moolenbroek   assert(pcn_targ.pcn_namelen <= NAME_MAX);
192*ba736c79SDavid van Moolenbroek   strcpy(pcn_targ.pcn_name, new_name);
193*ba736c79SDavid van Moolenbroek 
194*ba736c79SDavid van Moolenbroek   /* Get old dir pnode */
195*ba736c79SDavid van Moolenbroek   if ((old_dirp = puffs_pn_nodewalk(global_pu, find_inode_cb,
196*ba736c79SDavid van Moolenbroek     &old_dir_nr)) == NULL)
197*ba736c79SDavid van Moolenbroek         return(ENOENT);
198*ba736c79SDavid van Moolenbroek 
199*ba736c79SDavid van Moolenbroek   old_ip = advance(old_dirp, pcn_src.pcn_name);
200*ba736c79SDavid van Moolenbroek   if (!old_ip)
201*ba736c79SDavid van Moolenbroek 	return(err_code);
202*ba736c79SDavid van Moolenbroek 
203*ba736c79SDavid van Moolenbroek   if (old_ip->pn_mountpoint)
204*ba736c79SDavid van Moolenbroek 	return(EBUSY);
205*ba736c79SDavid van Moolenbroek 
206*ba736c79SDavid van Moolenbroek   /* Get new dir pnode */
207*ba736c79SDavid van Moolenbroek   if ((new_dirp = puffs_pn_nodewalk(global_pu, find_inode_cb,
208*ba736c79SDavid van Moolenbroek     &new_dir_nr)) == NULL) {
209*ba736c79SDavid van Moolenbroek         return(ENOENT);
210*ba736c79SDavid van Moolenbroek   } else {
211*ba736c79SDavid van Moolenbroek         if (new_dirp->pn_va.va_nlink == NO_LINK) {
212*ba736c79SDavid van Moolenbroek 		/* Dir does not actually exist */
213*ba736c79SDavid van Moolenbroek                 return(ENOENT);
214*ba736c79SDavid van Moolenbroek         }
215*ba736c79SDavid van Moolenbroek   }
216*ba736c79SDavid van Moolenbroek 
217*ba736c79SDavid van Moolenbroek   /* not required to exist */
218*ba736c79SDavid van Moolenbroek   new_ip = advance(new_dirp, pcn_targ.pcn_name);
219*ba736c79SDavid van Moolenbroek 
220*ba736c79SDavid van Moolenbroek   /* If the node does exist, make sure it's not a mountpoint. */
221*ba736c79SDavid van Moolenbroek   if (new_ip != NULL && new_ip->pn_mountpoint)
222*ba736c79SDavid van Moolenbroek 	return(EBUSY);
223*ba736c79SDavid van Moolenbroek 
224*ba736c79SDavid van Moolenbroek   if (old_ip != NULL) {
225*ba736c79SDavid van Moolenbroek 	/* TRUE iff dir */
226*ba736c79SDavid van Moolenbroek 	odir = ((old_ip->pn_va.va_mode & I_TYPE) == I_DIRECTORY);
227*ba736c79SDavid van Moolenbroek   } else {
228*ba736c79SDavid van Moolenbroek 	odir = FALSE;
229*ba736c79SDavid van Moolenbroek   }
230*ba736c79SDavid van Moolenbroek 
231*ba736c79SDavid van Moolenbroek   /* Check for a variety of possible errors. */
232*ba736c79SDavid van Moolenbroek   same_pdir = (old_dirp == new_dirp);
233*ba736c79SDavid van Moolenbroek 
234*ba736c79SDavid van Moolenbroek   /* Some tests apply only if the new path exists. */
235*ba736c79SDavid van Moolenbroek   if (new_ip == NULL) {
236*ba736c79SDavid van Moolenbroek 	if (odir && (new_dirp->pn_va.va_nlink >= SHRT_MAX ||
237*ba736c79SDavid van Moolenbroek 		     new_dirp->pn_va.va_nlink >= LINK_MAX) && !same_pdir) {
238*ba736c79SDavid van Moolenbroek 		return(EMLINK);
239*ba736c79SDavid van Moolenbroek 	}
240*ba736c79SDavid van Moolenbroek   } else {
241*ba736c79SDavid van Moolenbroek 	if (old_ip == new_ip) /* old=new */
242*ba736c79SDavid van Moolenbroek 		return(OK); /* do NOT update directory times in this case */
243*ba736c79SDavid van Moolenbroek 
244*ba736c79SDavid van Moolenbroek 	/* dir ? */
245*ba736c79SDavid van Moolenbroek 	ndir = ((new_ip->pn_va.va_mode & I_TYPE) == I_DIRECTORY);
246*ba736c79SDavid van Moolenbroek 	if (odir == TRUE && ndir == FALSE) return(ENOTDIR);
247*ba736c79SDavid van Moolenbroek 	if (odir == FALSE && ndir == TRUE) return(EISDIR);
248*ba736c79SDavid van Moolenbroek   }
249*ba736c79SDavid van Moolenbroek 
250*ba736c79SDavid van Moolenbroek   /* If a process has another root directory than the system root, we might
251*ba736c79SDavid van Moolenbroek    * "accidently" be moving it's working directory to a place where it's
252*ba736c79SDavid van Moolenbroek    * root directory isn't a super directory of it anymore. This can make
253*ba736c79SDavid van Moolenbroek    * the function chroot useless. If chroot will be used often we should
254*ba736c79SDavid van Moolenbroek    * probably check for it here. */
255*ba736c79SDavid van Moolenbroek 
256*ba736c79SDavid van Moolenbroek   /* The rename will probably work. Only two things can go wrong now:
257*ba736c79SDavid van Moolenbroek    * 1. being unable to remove the new file. (when new file already exists)
258*ba736c79SDavid van Moolenbroek    * 2. being unable to make the new directory entry. (new file doesn't exists)
259*ba736c79SDavid van Moolenbroek    *     [directory has to grow by one block and cannot because the disk
260*ba736c79SDavid van Moolenbroek    *      is completely full].
261*ba736c79SDavid van Moolenbroek    * 3. Something (doubtfully) else depending on the FS.
262*ba736c79SDavid van Moolenbroek    */
263*ba736c79SDavid van Moolenbroek 
264*ba736c79SDavid van Moolenbroek   if (buildpath) {
265*ba736c79SDavid van Moolenbroek 	pcn_src.pcn_po_full = old_ip->pn_po;
266*ba736c79SDavid van Moolenbroek 
267*ba736c79SDavid van Moolenbroek 	if (puffs_path_pcnbuild(global_pu, &pcn_targ, new_dirp) != 0)
268*ba736c79SDavid van Moolenbroek 		return(EINVAL);
269*ba736c79SDavid van Moolenbroek   }
270*ba736c79SDavid van Moolenbroek 
271*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_rename(global_pu, old_dirp, old_ip, &pcn_src,
272*ba736c79SDavid van Moolenbroek 						new_dirp, new_ip, &pcn_targ);
273*ba736c79SDavid van Moolenbroek   if (r > 0) r = -r;
274*ba736c79SDavid van Moolenbroek 
275*ba736c79SDavid van Moolenbroek   if (buildpath) {
276*ba736c79SDavid van Moolenbroek 	if (r) {
277*ba736c79SDavid van Moolenbroek 		global_pu->pu_pathfree(global_pu, &pcn_targ.pcn_po_full);
278*ba736c79SDavid van Moolenbroek 	} else {
279*ba736c79SDavid van Moolenbroek 		struct puffs_pathinfo pi;
280*ba736c79SDavid van Moolenbroek 		struct puffs_pathobj po_old;
281*ba736c79SDavid van Moolenbroek 
282*ba736c79SDavid van Moolenbroek 		/* handle this node */
283*ba736c79SDavid van Moolenbroek 		po_old = old_ip->pn_po;
284*ba736c79SDavid van Moolenbroek 		old_ip->pn_po = pcn_targ.pcn_po_full;
285*ba736c79SDavid van Moolenbroek 
286*ba736c79SDavid van Moolenbroek 		if (old_ip->pn_va.va_type != VDIR) {
287*ba736c79SDavid van Moolenbroek 			global_pu->pu_pathfree(global_pu, &po_old);
288*ba736c79SDavid van Moolenbroek 			return(OK);
289*ba736c79SDavid van Moolenbroek 		}
290*ba736c79SDavid van Moolenbroek 
291*ba736c79SDavid van Moolenbroek 		/* handle all child nodes for DIRs */
292*ba736c79SDavid van Moolenbroek 		pi.pi_old = &pcn_src.pcn_po_full;
293*ba736c79SDavid van Moolenbroek 		pi.pi_new = &pcn_targ.pcn_po_full;
294*ba736c79SDavid van Moolenbroek 
295*ba736c79SDavid van Moolenbroek 		PU_LOCK();
296*ba736c79SDavid van Moolenbroek 		if (puffs_pn_nodewalk(global_pu, puffs_path_prefixadj, &pi)
297*ba736c79SDavid van Moolenbroek 				!= NULL) {
298*ba736c79SDavid van Moolenbroek 			/* Actually nomem */
299*ba736c79SDavid van Moolenbroek 			return(EINVAL);
300*ba736c79SDavid van Moolenbroek 		}
301*ba736c79SDavid van Moolenbroek 		PU_UNLOCK();
302*ba736c79SDavid van Moolenbroek 		global_pu->pu_pathfree(global_pu, &po_old);
303*ba736c79SDavid van Moolenbroek 	}
304*ba736c79SDavid van Moolenbroek   }
305*ba736c79SDavid van Moolenbroek 
306*ba736c79SDavid van Moolenbroek   (void)clock_time(&cur_time);
307*ba736c79SDavid van Moolenbroek   update_timens(old_dirp, MTIME | CTIME, &cur_time);
308*ba736c79SDavid van Moolenbroek   update_timens(new_dirp, MTIME | CTIME, &cur_time);
309*ba736c79SDavid van Moolenbroek 
310*ba736c79SDavid van Moolenbroek   /* XXX see release_node comment in fs_unlink */
311*ba736c79SDavid van Moolenbroek   if (new_ip && new_ip->pn_count == 0) {
312*ba736c79SDavid van Moolenbroek 	release_node(global_pu, new_ip);
313*ba736c79SDavid van Moolenbroek   }
314*ba736c79SDavid van Moolenbroek 
315*ba736c79SDavid van Moolenbroek   return(r);
316*ba736c79SDavid van Moolenbroek }
317*ba736c79SDavid van Moolenbroek 
318*ba736c79SDavid van Moolenbroek static int remove_dir(struct puffs_node *pn_dir, struct puffs_node *pn,
319*ba736c79SDavid van Moolenbroek 	struct puffs_cn *pcn);
320*ba736c79SDavid van Moolenbroek static int unlink_file(struct puffs_node *dirp, struct puffs_node *pn,
321*ba736c79SDavid van Moolenbroek 	struct puffs_cn *pcn);
322*ba736c79SDavid van Moolenbroek 
323*ba736c79SDavid van Moolenbroek /*===========================================================================*
324*ba736c79SDavid van Moolenbroek  *				fs_unlink				     *
325*ba736c79SDavid van Moolenbroek  *===========================================================================*/
fs_unlink(ino_t dir_nr,char * name,int call)326*ba736c79SDavid van Moolenbroek int fs_unlink(ino_t dir_nr, char *name, int call)
327*ba736c79SDavid van Moolenbroek {
328*ba736c79SDavid van Moolenbroek /* Perform the unlink(name) or rmdir(name) system call. The code for these two
329*ba736c79SDavid van Moolenbroek  * is almost the same.  They differ only in some condition testing.
330*ba736c79SDavid van Moolenbroek  */
331*ba736c79SDavid van Moolenbroek   int r;
332*ba736c79SDavid van Moolenbroek   struct puffs_node *pn, *pn_dir;
333*ba736c79SDavid van Moolenbroek   struct timespec cur_time;
334*ba736c79SDavid van Moolenbroek   struct puffs_kcn pkcnp;
335*ba736c79SDavid van Moolenbroek   struct puffs_cn pcn = {&pkcnp, 0, {0,0,0}};
336*ba736c79SDavid van Moolenbroek   PUFFS_KCREDTOCRED(pcn.pcn_cred, &global_kcred);
337*ba736c79SDavid van Moolenbroek 
338*ba736c79SDavid van Moolenbroek   /* Copy the last component */
339*ba736c79SDavid van Moolenbroek   pcn.pcn_namelen = strlen(name);
340*ba736c79SDavid van Moolenbroek   assert(pcn.pcn_namelen <= NAME_MAX);
341*ba736c79SDavid van Moolenbroek   strcpy(pcn.pcn_name, name);
342*ba736c79SDavid van Moolenbroek 
343*ba736c79SDavid van Moolenbroek   if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
344*ba736c79SDavid van Moolenbroek 	return(EINVAL);
345*ba736c79SDavid van Moolenbroek 
346*ba736c79SDavid van Moolenbroek   /* The last directory exists. Does the file also exist? */
347*ba736c79SDavid van Moolenbroek   pn = advance(pn_dir, pcn.pcn_name);
348*ba736c79SDavid van Moolenbroek   r = err_code;
349*ba736c79SDavid van Moolenbroek 
350*ba736c79SDavid van Moolenbroek   /* If error, return pnode. */
351*ba736c79SDavid van Moolenbroek   if (r != OK)
352*ba736c79SDavid van Moolenbroek         return(r);
353*ba736c79SDavid van Moolenbroek   if (pn->pn_mountpoint)
354*ba736c79SDavid van Moolenbroek 	return EBUSY;
355*ba736c79SDavid van Moolenbroek 
356*ba736c79SDavid van Moolenbroek   /* Now test if the call is allowed, separately for unlink() and rmdir(). */
357*ba736c79SDavid van Moolenbroek   if (call == FSC_UNLINK) {
358*ba736c79SDavid van Moolenbroek 	r = unlink_file(pn_dir, pn, &pcn);
359*ba736c79SDavid van Moolenbroek   } else {
360*ba736c79SDavid van Moolenbroek 	r = remove_dir(pn_dir, pn, &pcn); /* call is RMDIR */
361*ba736c79SDavid van Moolenbroek   }
362*ba736c79SDavid van Moolenbroek 
363*ba736c79SDavid van Moolenbroek   if (pn->pn_va.va_nlink != 0) {
364*ba736c79SDavid van Moolenbroek 	(void)clock_time(&cur_time);
365*ba736c79SDavid van Moolenbroek 	update_timens(pn, CTIME, &cur_time);
366*ba736c79SDavid van Moolenbroek 	update_timens(pn_dir, MTIME | CTIME, &cur_time);
367*ba736c79SDavid van Moolenbroek   }
368*ba736c79SDavid van Moolenbroek 
369*ba736c79SDavid van Moolenbroek   /* XXX Ideally, we should check pn->pn_flags & PUFFS_NODE_REMOVED, but
370*ba736c79SDavid van Moolenbroek    * librefuse doesn't set it (neither manually or via puffs_pn_remove() ).
371*ba736c79SDavid van Moolenbroek    * Thus we just check that "pn_count == 0". Otherwise release_node()
372*ba736c79SDavid van Moolenbroek    * will be called in fs_put().
373*ba736c79SDavid van Moolenbroek    */
374*ba736c79SDavid van Moolenbroek   if (pn->pn_count == 0)
375*ba736c79SDavid van Moolenbroek 	release_node(global_pu, pn);
376*ba736c79SDavid van Moolenbroek 
377*ba736c79SDavid van Moolenbroek   return(r);
378*ba736c79SDavid van Moolenbroek }
379*ba736c79SDavid van Moolenbroek 
380*ba736c79SDavid van Moolenbroek 
381*ba736c79SDavid van Moolenbroek /*===========================================================================*
382*ba736c79SDavid van Moolenbroek  *				remove_dir				     *
383*ba736c79SDavid van Moolenbroek  *===========================================================================*/
remove_dir(struct puffs_node * pn_dir,struct puffs_node * pn,struct puffs_cn * pcn)384*ba736c79SDavid van Moolenbroek static int remove_dir(
385*ba736c79SDavid van Moolenbroek 	struct puffs_node *pn_dir,	/* parent directory */
386*ba736c79SDavid van Moolenbroek 	struct puffs_node *pn,		/* directory to be removed */
387*ba736c79SDavid van Moolenbroek 	struct puffs_cn *pcn		/* Name, creads of directory */
388*ba736c79SDavid van Moolenbroek )
389*ba736c79SDavid van Moolenbroek {
390*ba736c79SDavid van Moolenbroek   /* A directory file has to be removed. Five conditions have to met:
391*ba736c79SDavid van Moolenbroek    *	- The file must be a directory
392*ba736c79SDavid van Moolenbroek    *	- The directory must be empty (except for . and ..)
393*ba736c79SDavid van Moolenbroek    *	- The final component of the path must not be . or ..
394*ba736c79SDavid van Moolenbroek    *	- The directory must not be the root of a mounted file system (VFS)
395*ba736c79SDavid van Moolenbroek    *	- The directory must not be anybody's root/working directory (VFS)
396*ba736c79SDavid van Moolenbroek    */
397*ba736c79SDavid van Moolenbroek 
398*ba736c79SDavid van Moolenbroek   /* "." and ".." dentries can be stored in 28 bytes */
399*ba736c79SDavid van Moolenbroek   #define EMPTY_DIR_DENTRIES_SIZE	28
400*ba736c79SDavid van Moolenbroek   int r;
401*ba736c79SDavid van Moolenbroek   char remove_dir_buf[EMPTY_DIR_DENTRIES_SIZE];
402*ba736c79SDavid van Moolenbroek   struct dirent *dent = (struct dirent*) remove_dir_buf;
403*ba736c79SDavid van Moolenbroek   int buf_left = EMPTY_DIR_DENTRIES_SIZE;
404*ba736c79SDavid van Moolenbroek   off_t pos = 0;
405*ba736c79SDavid van Moolenbroek   int eofflag = 0;
406*ba736c79SDavid van Moolenbroek 
407*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_rmdir == NULL)
408*ba736c79SDavid van Moolenbroek 	return(EINVAL);
409*ba736c79SDavid van Moolenbroek 
410*ba736c79SDavid van Moolenbroek   if (!S_ISDIR(pn->pn_va.va_mode))
411*ba736c79SDavid van Moolenbroek 	return(ENOTDIR);
412*ba736c79SDavid van Moolenbroek 
413*ba736c79SDavid van Moolenbroek   /* Check if directory is empty */
414*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, &pos,
415*ba736c79SDavid van Moolenbroek 			(size_t *)&buf_left, pcn->pcn_cred, &eofflag, 0, 0);
416*ba736c79SDavid van Moolenbroek   if (r) return(EINVAL);
417*ba736c79SDavid van Moolenbroek   if (!eofflag) return(ENOTEMPTY);
418*ba736c79SDavid van Moolenbroek 
419*ba736c79SDavid van Moolenbroek   if (pn->pn_va.va_fileid == global_pu->pu_pn_root->pn_va.va_fileid)
420*ba736c79SDavid van Moolenbroek 	return(EBUSY); /* can't remove 'root' */
421*ba736c79SDavid van Moolenbroek 
422*ba736c79SDavid van Moolenbroek   if (buildpath) {
423*ba736c79SDavid van Moolenbroek 	r = puffs_path_pcnbuild(global_pu, pcn, pn_dir);
424*ba736c79SDavid van Moolenbroek 	if (r) return(EINVAL);
425*ba736c79SDavid van Moolenbroek   }
426*ba736c79SDavid van Moolenbroek 
427*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_rmdir(global_pu, pn_dir, pn, pcn);
428*ba736c79SDavid van Moolenbroek 
429*ba736c79SDavid van Moolenbroek   global_pu->pu_pathfree(global_pu, &pcn->pcn_po_full);
430*ba736c79SDavid van Moolenbroek 
431*ba736c79SDavid van Moolenbroek   if (r) return(EINVAL);
432*ba736c79SDavid van Moolenbroek 
433*ba736c79SDavid van Moolenbroek   return(OK);
434*ba736c79SDavid van Moolenbroek }
435*ba736c79SDavid van Moolenbroek 
436*ba736c79SDavid van Moolenbroek 
437*ba736c79SDavid van Moolenbroek /*===========================================================================*
438*ba736c79SDavid van Moolenbroek  *				unlink_file				     *
439*ba736c79SDavid van Moolenbroek  *===========================================================================*/
unlink_file(struct puffs_node * dirp,struct puffs_node * pn,struct puffs_cn * pcn)440*ba736c79SDavid van Moolenbroek static int unlink_file(
441*ba736c79SDavid van Moolenbroek 	struct puffs_node *dirp,	/* parent directory of file */
442*ba736c79SDavid van Moolenbroek 	struct puffs_node *pn,		/* pnode of file, may be NULL too. */
443*ba736c79SDavid van Moolenbroek 	struct puffs_cn *pcn		/* Name, creads of file */
444*ba736c79SDavid van Moolenbroek )
445*ba736c79SDavid van Moolenbroek {
446*ba736c79SDavid van Moolenbroek /* Unlink 'file_name'; pn must be the pnode of 'file_name' */
447*ba736c79SDavid van Moolenbroek   int	r;
448*ba736c79SDavid van Moolenbroek 
449*ba736c79SDavid van Moolenbroek   assert(pn != NULL);
450*ba736c79SDavid van Moolenbroek 
451*ba736c79SDavid van Moolenbroek   if (global_pu->pu_ops.puffs_node_remove == NULL)
452*ba736c79SDavid van Moolenbroek 	return(EINVAL);
453*ba736c79SDavid van Moolenbroek 
454*ba736c79SDavid van Moolenbroek   if (S_ISDIR(pn->pn_va.va_mode))
455*ba736c79SDavid van Moolenbroek 	return(EPERM);
456*ba736c79SDavid van Moolenbroek 
457*ba736c79SDavid van Moolenbroek   if (buildpath) {
458*ba736c79SDavid van Moolenbroek 	r = puffs_path_pcnbuild(global_pu, pcn, dirp);
459*ba736c79SDavid van Moolenbroek 	if (r)
460*ba736c79SDavid van Moolenbroek 		return(EINVAL);
461*ba736c79SDavid van Moolenbroek   }
462*ba736c79SDavid van Moolenbroek 
463*ba736c79SDavid van Moolenbroek   r = global_pu->pu_ops.puffs_node_remove(global_pu, dirp, pn, pcn);
464*ba736c79SDavid van Moolenbroek 
465*ba736c79SDavid van Moolenbroek   global_pu->pu_pathfree(global_pu, &pcn->pcn_po_full);
466*ba736c79SDavid van Moolenbroek 
467*ba736c79SDavid van Moolenbroek   if (r) return(EINVAL);
468*ba736c79SDavid van Moolenbroek 
469*ba736c79SDavid van Moolenbroek   return(OK);
470*ba736c79SDavid van Moolenbroek }
471