. service tells you which device it couldn't stat
[minix3.git] / servers / vfs / link.c
blob69c471bdbdf0a9cc8e23fa48381ea59df52f6dae
1 /* This file handles the LINK and UNLINK system calls. It also deals with
2 * deallocating the storage used by a file when the last UNLINK is done to a
3 * file and the blocks must be returned to the free block pool.
5 * The entry points into this file are
6 * do_link: perform the LINK system call
7 * do_unlink: perform the UNLINK and RMDIR system calls
8 * do_rename: perform the RENAME system call
9 * do_truncate: perform the TRUNCATE system call
10 * do_ftruncate: perform the FTRUNCATE system call
11 * do_rdlink: perform the RDLNK system call
13 * Changes for VFS:
14 * Jul 2006 (Balazs Gerofi)
17 #include "fs.h"
18 #include <sys/stat.h>
19 #include <string.h>
20 #include <minix/com.h>
21 #include <minix/callnr.h>
22 #include <dirent.h>
23 #include "file.h"
24 #include "fproc.h"
25 #include "param.h"
27 #include <minix/vfsif.h>
28 #include "vnode.h"
30 /*===========================================================================*
31 * do_link *
32 *===========================================================================*/
33 PUBLIC int do_link()
35 /* Perform the link(name1, name2) system call. */
36 int linked_fs_e;
37 int linked_inode_nr;
38 int link_lastdir_fs_e;
39 int link_lastdir_inode_nr;
40 char string[NAME_MAX];
41 struct link_req req;
42 struct lookup_req lookup_req;
43 struct node_details res;
44 int r;
46 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK)
47 return(err_code);
49 /* Fill in lookup request fields */
50 lookup_req.path = user_fullpath;
51 lookup_req.lastc = NULL;
52 lookup_req.flags = EAT_PATH;
54 /* Request lookup */
55 if ((r = lookup(&lookup_req, &res)) != OK) return r;
57 linked_fs_e = res.fs_e;
58 req.linked_file = res.inode_nr;
60 /* Does the final directory of 'name2' exist? */
61 if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
62 return(err_code);
65 /* Fill in lookup request fields */
66 lookup_req.path = user_fullpath;
67 lookup_req.lastc = string;
68 lookup_req.flags = LAST_DIR;
70 /* Request lookup */
71 if ((r = lookup(&lookup_req, &res)) != OK) return r;
73 link_lastdir_fs_e = res.fs_e;
74 req.link_parent = res.inode_nr;
76 /* Check for links across devices. */
77 if (linked_fs_e != link_lastdir_fs_e)
78 return EXDEV;
80 /* Send link request. */
81 req.fs_e = linked_fs_e;
82 /* Send the last component of the link name */
83 req.uid = fp->fp_effuid;
84 req.gid = fp->fp_effgid;
85 req.lastc = string;
87 /* Issue request */
88 return req_link(&req);
93 /*===========================================================================*
94 * do_unlink *
95 *===========================================================================*/
96 PUBLIC int do_unlink()
98 /* Perform the unlink(name) or rmdir(name) system call. The code for these two
99 * is almost the same. They differ only in some condition testing. Unlink()
100 * may be used by the superuser to do dangerous things; rmdir() may not.
102 register struct fproc *rfp;
103 char string[NAME_MAX];
104 struct vnode *vp;
105 struct unlink_req req;
106 struct lookup_req lookup_req;
107 struct node_details res;
108 int r;
109 string[0] = '\0';
111 if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
113 /* Fill in lookup request fields */
114 lookup_req.path = user_fullpath;
115 lookup_req.lastc = NULL;
116 lookup_req.flags = EAT_PATH_OPAQUE;
118 /* Request lookup */
119 if ((r = lookup(&lookup_req, &res)) != OK) return r;
121 /* If a directory file has to be removed the following conditions have to met:
122 * - The directory must not be the root of a mounted file system
123 * - The directory must not be anybody's root/working directory
125 if ((res.fmode & I_TYPE) == I_DIRECTORY) {
126 /* Only root can unlink a directory */
127 if (call_nr == UNLINK && !super_user) return EPERM;
129 /* Can't remove a root directory */
130 if (res.inode_nr == ROOT_INODE) return EBUSY;
132 /* Can't remove anybody's working directory */
133 if ((vp = find_vnode(res.fs_e, res.inode_nr)) !=
134 NIL_VNODE) {
135 /* Check directories */
136 for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS];
137 rfp++) {
138 if (rfp->fp_pid != PID_FREE &&
139 (rfp->fp_wd == vp || rfp->fp_rd == vp))
140 return(EBUSY);
145 /* Fill in lookup request fields */
146 lookup_req.path = user_fullpath;
147 lookup_req.lastc = string;
148 lookup_req.flags = LAST_DIR;
150 /* Request lookup */
151 if ((r = lookup(&lookup_req, &res)) != OK) return r;
153 /* Fill in request fields. */
154 req.fs_e = res.fs_e;
155 req.d_inode_nr = res.inode_nr;
156 req.uid = fp->fp_effuid;
157 req.gid = fp->fp_effgid;
158 req.lastc = string;
160 /* Issue request */
161 return (call_nr == UNLINK) ? req_unlink(&req) : req_rmdir(&req);
165 /*===========================================================================*
166 * do_rename *
167 *===========================================================================*/
168 PUBLIC int do_rename()
170 /* Perform the rename(name1, name2) system call. */
171 int old_dir_inode;
172 int old_fs_e;
173 int new_dir_inode;
174 int new_fs_e;
175 char old_name[NAME_MAX];
176 char new_name[NAME_MAX];
177 struct vnode *vp;
178 struct fproc *rfp;
179 struct rename_req req;
180 struct lookup_req lookup_req;
181 struct node_details res;
182 int r;
184 /* See if 'name1' (existing file) exists. Get dir and file inodes. */
185 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
187 /* Fill in lookup request fields */
188 lookup_req.path = user_fullpath;
189 lookup_req.lastc = old_name;
190 lookup_req.flags = LAST_DIR;
192 /* Request lookup */
193 if ((r = lookup(&lookup_req, &res)) != OK) return r;
195 /* Remeber inode number and FS endpoint */
196 old_fs_e = res.fs_e;
197 req.old_dir = res.inode_nr;
199 /* See if 'name2' (new name) exists. Get dir inode */
200 if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code;
202 /* Fill in lookup request fields */
203 lookup_req.path = user_fullpath;
204 lookup_req.lastc = NULL;
205 lookup_req.flags = EAT_PATH_OPAQUE;
207 /* Request lookup */
208 r = lookup(&lookup_req, &res);
210 /* If a directory file has to be removed the following conditions have to met:
211 * - The directory must not be the root of a mounted file system
212 * - The directory must not be anybody's root/working directory
214 if (r == OK && ((res.fmode & I_TYPE) == I_DIRECTORY)) {
215 /* Can't remove a root directory */
216 if (res.inode_nr == ROOT_INODE) return EBUSY;
218 /* Can't remove anybody's working directory */
219 if ((vp = find_vnode(res.fs_e, res.inode_nr)) !=
220 NIL_VNODE) {
221 /* Check directories */
222 for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS];
223 rfp++) {
224 if (rfp->fp_pid != PID_FREE &&
225 (rfp->fp_wd == vp || rfp->fp_rd == vp))
226 return(EBUSY);
231 /* Fill in lookup request fields */
232 lookup_req.path = user_fullpath;
233 lookup_req.lastc = new_name;
234 lookup_req.flags = LAST_DIR;
236 /* Request lookup */
237 if ((r = lookup(&lookup_req, &res)) != OK) return r;
239 /* Remeber inode number and FS endpoint */
240 new_fs_e = res.fs_e;
241 req.new_dir = res.inode_nr;
243 /* Both parent directories must be on the same device. */
244 if (old_fs_e != new_fs_e) return EXDEV;
246 /* Send actual rename request */
247 req.fs_e = old_fs_e;
248 req.uid = fp->fp_effuid;
249 req.gid = fp->fp_effgid;
250 req.old_name = &old_name[0];
251 req.new_name = &new_name[0];
253 /* Issue request */
254 return req_rename(&req);
258 /*===========================================================================*
259 * do_truncate *
260 *===========================================================================*/
261 PUBLIC int do_truncate()
263 /* truncate_inode() does the actual work of do_truncate() and do_ftruncate().
264 * do_truncate() and do_ftruncate() have to get hold of the inode, either
265 * by name or fd, do checks on it, and call truncate_inode() to do the
266 * work.
268 struct vnode *vp;
269 struct trunc_req req;
270 struct lookup_req lookup_req;
271 struct node_details res;
272 int r;
274 printf("in do_truncate\n");
276 if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) return err_code;
278 /* Fill in lookup request fields */
279 lookup_req.path = user_fullpath;
280 lookup_req.lastc = NULL;
281 lookup_req.flags = EAT_PATH;
283 /* Request lookup */
284 if ((r = lookup(&lookup_req, &res)) != OK) return r;
286 /* Check whether the file is in use or not */
287 vp = find_vnode(res.fs_e, res.inode_nr);
289 /* Fill in request message fields.*/
290 req.fs_e = res.fs_e;
291 req.length = m_in.m2_l1;
292 req.inode_nr = res.inode_nr;
293 req.uid = fp->fp_effuid;
294 req.gid = fp->fp_effgid;
296 /* Issue request */
297 if ((r = req_trunc(&req)) != OK) return r;
299 /* Change vnode's size if found */
300 if (vp != NIL_VNODE)
301 vp->v_size = m_in.m2_l1;
303 return OK;
308 /*===========================================================================*
309 * do_ftruncate *
310 *===========================================================================*/
311 PUBLIC int do_ftruncate()
313 /* As with do_truncate(), truncate_inode() does the actual work. */
314 struct filp *rfilp;
316 if ( (rfilp = get_filp(m_in.m2_i1)) == NIL_FILP)
317 return err_code;
318 return truncate_vn(rfilp->filp_vno, m_in.m2_l1);
322 /*===========================================================================*
323 * truncate_vn *
324 *===========================================================================*/
325 PUBLIC int truncate_vn(vp, newsize)
326 struct vnode *vp;
327 off_t newsize;
329 int r;
330 struct ftrunc_req req;
332 if ( (vp->v_mode & I_TYPE) != I_REGULAR &&
333 (vp->v_mode & I_TYPE) != I_NAMED_PIPE) {
334 return EINVAL;
337 /* Fill in FS request */
338 req.fs_e = vp->v_fs_e;
339 req.inode_nr = vp->v_inode_nr;
340 req.start = newsize;
341 req.end = 0; /* Indicate trunc in fs_freesp_trunc */
343 /* Issue request */
344 if ((r = req_ftrunc(&req)) != OK) return r;
346 vp->v_size = newsize;
347 return OK;
350 /*===========================================================================*
351 * do_slink *
352 *===========================================================================*/
353 PUBLIC int do_slink()
355 /* Perform the symlink(name1, name2) system call. */
356 char string[NAME_MAX]; /* last component of the new dir's path name */
357 struct slink_req req;
358 struct lookup_req lookup_req;
359 struct node_details res;
360 int r;
362 if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK)
363 return(err_code);
365 if (m_in.name1_length <= 1 || m_in.name1_length >= _MIN_BLOCK_SIZE)
366 return(ENAMETOOLONG);
368 /* Fill in lookup request fields */
369 lookup_req.path = user_fullpath;
370 lookup_req.lastc = string;
371 lookup_req.flags = LAST_DIR;
373 /* Request lookup */
374 if ((r = lookup(&lookup_req, &res)) != OK) return r;
376 /* Fill in request message */
377 req.fs_e = res.fs_e;
378 req.parent_dir = res.inode_nr;
379 req.uid = fp->fp_effuid;
380 req.gid = fp->fp_effgid;
381 req.lastc = string;
382 req.who_e = who_e;
383 req.path_addr = m_in.name1;
384 req.path_length = m_in.name1_length - 1;
386 /* Issue request */
387 return req_slink(&req);
390 /*===========================================================================*
391 * do_rdlink *
392 *===========================================================================*/
393 PUBLIC int do_rdlink()
395 /* Perform the readlink(name, buf) system call. */
396 int copylen;
397 struct rdlink_req req;
398 struct lookup_req lookup_req;
399 struct node_details res;
400 int r;
402 copylen = m_in.m1_i2;
403 if(copylen < 0) return EINVAL;
405 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
407 /* Fill in lookup request fields */
408 lookup_req.path = user_fullpath;
409 lookup_req.lastc = NULL;
410 lookup_req.flags = EAT_PATH_OPAQUE;
412 /* Request lookup */
413 if ((r = lookup(&lookup_req, &res)) != OK) return r;
415 /* Fill in request message */
416 req.fs_e = res.fs_e;
417 req.inode_nr = res.inode_nr;
418 req.uid = fp->fp_effuid;
419 req.gid = fp->fp_effgid;
420 req.who_e = who_e;
421 req.path_buffer = m_in.name2;
422 req.max_length = copylen;
424 /* Issue request */
425 return req_rdlink(&req);