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
14 * Jul 2006 (Balazs Gerofi)
20 #include <minix/com.h>
21 #include <minix/callnr.h>
27 #include <minix/vfsif.h>
30 /*===========================================================================*
32 *===========================================================================*/
35 /* Perform the link(name1, name2) system call. */
38 int link_lastdir_fs_e
;
39 int link_lastdir_inode_nr
;
40 char string
[NAME_MAX
];
42 struct lookup_req lookup_req
;
43 struct node_details res
;
46 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
)
49 /* Fill in lookup request fields */
50 lookup_req
.path
= user_fullpath
;
51 lookup_req
.lastc
= NULL
;
52 lookup_req
.flags
= EAT_PATH
;
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
) {
65 /* Fill in lookup request fields */
66 lookup_req
.path
= user_fullpath
;
67 lookup_req
.lastc
= string
;
68 lookup_req
.flags
= LAST_DIR
;
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
)
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
;
88 return req_link(&req
);
93 /*===========================================================================*
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
];
105 struct unlink_req req
;
106 struct lookup_req lookup_req
;
107 struct node_details res
;
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
;
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
)) !=
135 /* Check directories */
136 for (rfp
= &fproc
[INIT_PROC_NR
+ 1]; rfp
< &fproc
[NR_PROCS
];
138 if (rfp
->fp_pid
!= PID_FREE
&&
139 (rfp
->fp_wd
== vp
|| rfp
->fp_rd
== vp
))
145 /* Fill in lookup request fields */
146 lookup_req
.path
= user_fullpath
;
147 lookup_req
.lastc
= string
;
148 lookup_req
.flags
= LAST_DIR
;
151 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
153 /* Fill in request fields. */
155 req
.d_inode_nr
= res
.inode_nr
;
156 req
.uid
= fp
->fp_effuid
;
157 req
.gid
= fp
->fp_effgid
;
161 return (call_nr
== UNLINK
) ? req_unlink(&req
) : req_rmdir(&req
);
165 /*===========================================================================*
167 *===========================================================================*/
168 PUBLIC
int do_rename()
170 /* Perform the rename(name1, name2) system call. */
175 char old_name
[NAME_MAX
];
176 char new_name
[NAME_MAX
];
179 struct rename_req req
;
180 struct lookup_req lookup_req
;
181 struct node_details res
;
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
;
193 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
195 /* Remeber inode number and FS endpoint */
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
;
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
)) !=
221 /* Check directories */
222 for (rfp
= &fproc
[INIT_PROC_NR
+ 1]; rfp
< &fproc
[NR_PROCS
];
224 if (rfp
->fp_pid
!= PID_FREE
&&
225 (rfp
->fp_wd
== vp
|| rfp
->fp_rd
== vp
))
231 /* Fill in lookup request fields */
232 lookup_req
.path
= user_fullpath
;
233 lookup_req
.lastc
= new_name
;
234 lookup_req
.flags
= LAST_DIR
;
237 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
239 /* Remeber inode number and FS endpoint */
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 */
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];
254 return req_rename(&req
);
258 /*===========================================================================*
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
269 struct trunc_req req
;
270 struct lookup_req lookup_req
;
271 struct node_details res
;
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
;
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.*/
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
;
297 if ((r
= req_trunc(&req
)) != OK
) return r
;
299 /* Change vnode's size if found */
301 vp
->v_size
= m_in
.m2_l1
;
308 /*===========================================================================*
310 *===========================================================================*/
311 PUBLIC
int do_ftruncate()
313 /* As with do_truncate(), truncate_inode() does the actual work. */
316 if ( (rfilp
= get_filp(m_in
.m2_i1
)) == NIL_FILP
)
318 return truncate_vn(rfilp
->filp_vno
, m_in
.m2_l1
);
322 /*===========================================================================*
324 *===========================================================================*/
325 PUBLIC
int truncate_vn(vp
, newsize
)
330 struct ftrunc_req req
;
332 if ( (vp
->v_mode
& I_TYPE
) != I_REGULAR
&&
333 (vp
->v_mode
& I_TYPE
) != I_NAMED_PIPE
) {
337 /* Fill in FS request */
338 req
.fs_e
= vp
->v_fs_e
;
339 req
.inode_nr
= vp
->v_inode_nr
;
341 req
.end
= 0; /* Indicate trunc in fs_freesp_trunc */
344 if ((r
= req_ftrunc(&req
)) != OK
) return r
;
346 vp
->v_size
= newsize
;
350 /*===========================================================================*
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
;
362 if (fetch_name(m_in
.name2
, m_in
.name2_length
, M1
) != OK
)
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
;
374 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
376 /* Fill in request message */
378 req
.parent_dir
= res
.inode_nr
;
379 req
.uid
= fp
->fp_effuid
;
380 req
.gid
= fp
->fp_effgid
;
383 req
.path_addr
= m_in
.name1
;
384 req
.path_length
= m_in
.name1_length
- 1;
387 return req_slink(&req
);
390 /*===========================================================================*
392 *===========================================================================*/
393 PUBLIC
int do_rdlink()
395 /* Perform the readlink(name, buf) system call. */
397 struct rdlink_req req
;
398 struct lookup_req lookup_req
;
399 struct node_details res
;
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
;
413 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
415 /* Fill in request message */
417 req
.inode_nr
= res
.inode_nr
;
418 req
.uid
= fp
->fp_effuid
;
419 req
.gid
= fp
->fp_effgid
;
421 req
.path_buffer
= m_in
.name2
;
422 req
.max_length
= copylen
;
425 return req_rdlink(&req
);