xref: /minix/minix/fs/ext2/link.c (revision 9f988b79)
1 /* Created (MFS based):
2  *   February 2010 (Evgeniy Ivanov)
3  */
4 
5 #include "fs.h"
6 #include <sys/stat.h>
7 #include <string.h>
8 #include <minix/com.h>
9 #include "buf.h"
10 #include "inode.h"
11 #include "super.h"
12 #include <minix/vfsif.h>
13 #include <sys/param.h>
14 
15 #define SAME 1000
16 
17 static int freesp_inode(struct inode *rip, off_t st, off_t end);
18 static int remove_dir(struct inode *rldirp, struct inode *rip,
19 	const char *dir_name);
20 static int unlink_file(struct inode *dirp, struct inode *rip,
21 	const char *file_name);
22 static off_t nextblock(off_t pos, int blocksize);
23 static void zeroblock_half(struct inode *i, off_t p, int l);
24 static void zeroblock_range(struct inode *i, off_t p, off_t h);
25 
26 /* Args to zeroblock_half() */
27 #define FIRST_HALF	0
28 #define LAST_HALF	1
29 
30 
31 /*===========================================================================*
32  *				fs_link 				     *
33  *===========================================================================*/
34 int fs_link(ino_t dir_nr, char *name, ino_t ino_nr)
35 {
36 /* Perform the link(name1, name2) system call. */
37 
38   struct inode *ip, *rip;
39   register int r;
40   struct inode *new_ip;
41 
42   /* Temporarily open the file. */
43   if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
44 	  return(EINVAL);
45 
46   /* Check to see if the file has maximum number of links already. */
47   r = OK;
48   if (rip->i_links_count >= USHRT_MAX)
49 	  r = EMLINK;
50   if(rip->i_links_count >= LINK_MAX)
51 	  r = EMLINK;
52 
53   /* Linking to directories is too dangerous to allow. */
54   if(r == OK)
55 	  if( (rip->i_mode & I_TYPE) == I_DIRECTORY)
56 		  r = EPERM;
57 
58   /* If error with 'name', return the inode. */
59   if (r != OK) {
60 	  put_inode(rip);
61 	  return(r);
62   }
63 
64   /* Temporarily open the last dir */
65   if( (ip = get_inode(fs_dev, dir_nr)) == NULL) {
66   	put_inode(rip);
67 	return(EINVAL);
68   }
69 
70   if (ip->i_links_count == NO_LINK) {	/* Dir does not actually exist */
71   	put_inode(rip);
72 	put_inode(ip);
73 	return(ENOENT);
74   }
75 
76   /* If 'name2' exists in full (even if no space) set 'r' to error. */
77   if ((new_ip = advance(ip, name)) == NULL) {
78 	r = err_code;
79 	if(r == ENOENT)
80 		r = OK;
81   } else {
82 	put_inode(new_ip);
83 	r = EEXIST;
84   }
85 
86   /* Try to link. */
87   if(r == OK)
88 	  r = search_dir(ip, name, &rip->i_num, ENTER, rip->i_mode & I_TYPE);
89 
90   /* If success, register the linking. */
91   if(r == OK) {
92 	  rip->i_links_count++;
93 	  rip->i_update |= CTIME;
94 	  rip->i_dirt = IN_DIRTY;
95   }
96 
97   /* Done.  Release both inodes. */
98   put_inode(rip);
99   put_inode(ip);
100   return(r);
101 }
102 
103 
104 /*===========================================================================*
105  *				fs_unlink				     *
106  *===========================================================================*/
107 int fs_unlink(ino_t dir_nr, char *name, int call)
108 {
109 /* Perform the unlink(name) or rmdir(name) system call. The code for these two
110  * is almost the same.  They differ only in some condition testing.
111  */
112   register struct inode *rip;
113   struct inode *rldirp;
114   int r;
115 
116   /* Temporarily open the dir. */
117   if((rldirp = get_inode(fs_dev, dir_nr)) == NULL)
118 	  return(EINVAL);
119 
120   /* The last directory exists.  Does the file also exist? */
121   rip = advance(rldirp, name);
122   r = err_code;
123 
124   /* If error, return inode. */
125   if(r != OK) {
126 	put_inode(rldirp);
127 	return(r);
128   }
129   if (rip->i_mountpoint) {
130 	put_inode(rip);
131 	put_inode(rldirp);
132 	return(EBUSY);
133   }
134 
135   /* Now test if the call is allowed, separately for unlink() and rmdir(). */
136   if (call == FSC_UNLINK) {
137 	  if( (rip->i_mode & I_TYPE) == I_DIRECTORY) r = EPERM;
138 
139 	  /* Actually try to unlink the file; fails if parent is mode 0 etc. */
140 	  if (r == OK) r = unlink_file(rldirp, rip, name);
141   } else {
142 	  r = remove_dir(rldirp, rip, name); /* call is RMDIR */
143   }
144 
145   /* If unlink was possible, it has been done, otherwise it has not. */
146   put_inode(rip);
147   put_inode(rldirp);
148   return(r);
149 }
150 
151 
152 /*===========================================================================*
153  *                             fs_rdlink                                     *
154  *===========================================================================*/
155 ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes)
156 {
157   struct buf *bp = NULL;       /* buffer containing link text */
158   char* link_text;             /* either bp->b_data or rip->i_block */
159   register struct inode *rip;  /* target inode */
160   register int r;              /* return value */
161 
162   /* Temporarily open the file. */
163   if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
164 	  return(EINVAL);
165 
166   if (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) {
167   /* normal symlink */
168        	if(!(bp = get_block_map(rip, 0))) {
169 		r = EIO;
170 	} else {
171 		link_text = b_data(bp);
172 		r = OK;
173 	}
174   } else {
175         /* fast symlink, stored in inode */
176         link_text = (char*) rip->i_block;
177 	r = OK;
178   }
179   if (r == OK) {
180 	/* Passed all checks */
181 	if (bytes > rip->i_size)
182 		bytes = rip->i_size;
183 	r = fsdriver_copyout(data, 0, link_text, bytes);
184 	put_block(bp);
185 	if (r == OK)
186 		r = bytes;
187   }
188 
189   put_inode(rip);
190   return(r);
191 }
192 
193 
194 /*===========================================================================*
195  *				remove_dir				     *
196  *===========================================================================*/
197 static int remove_dir(rldirp, rip, dir_name)
198 struct inode *rldirp;		 	/* parent directory */
199 struct inode *rip;			/* directory to be removed */
200 const char *dir_name;			/* name of directory to be removed */
201 {
202   /* A directory file has to be removed. Five conditions have to met:
203    * 	- The file must be a directory
204    *	- The directory must be empty (except for . and ..)
205    *	- The final component of the path must not be . or ..
206    *	- The directory must not be the root of a mounted file system (VFS)
207    *	- The directory must not be anybody's root/working directory (VFS)
208    */
209   int r;
210 
211   /* search_dir checks that rip is a directory too. */
212   if ((r = search_dir(rip, "", NULL, IS_EMPTY, 0)) != OK)
213 	return r;
214 
215   if (rip->i_num == ROOT_INODE) return(EBUSY); /* can't remove 'root' */
216 
217   /* Actually try to unlink the file; fails if parent is mode 0 etc. */
218   if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
219 
220   /* Unlink . and .. from the dir. The super user can link and unlink any dir,
221    * so don't make too many assumptions about them.
222    */
223   (void) unlink_file(rip, NULL, ".");
224   (void) unlink_file(rip, NULL, "..");
225   return(OK);
226 }
227 
228 
229 /*===========================================================================*
230  *				unlink_file				     *
231  *===========================================================================*/
232 static int unlink_file(dirp, rip, file_name)
233 struct inode *dirp;		/* parent directory of file */
234 struct inode *rip;		/* inode of file, may be NULL too. */
235 const char *file_name;		/* name of file to be removed */
236 {
237 /* Unlink 'file_name'; rip must be the inode of 'file_name' or NULL. */
238 
239   ino_t numb;			/* inode number */
240   int	r;
241 
242   /* If rip is not NULL, it is used to get faster access to the inode. */
243   if (rip == NULL) {
244 	/* Search for file in directory and try to get its inode. */
245 	err_code = search_dir(dirp, file_name, &numb, LOOK_UP, 0);
246 	if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
247 	if (err_code != OK || rip == NULL) return(err_code);
248   } else {
249 	dup_inode(rip);		/* inode will be returned with put_inode */
250   }
251 
252   r = search_dir(dirp, file_name, NULL, DELETE, 0);
253 
254   if (r == OK) {
255 	rip->i_links_count--;	/* entry deleted from parent's dir */
256 	rip->i_update |= CTIME;
257 	rip->i_dirt = IN_DIRTY;
258   }
259 
260   put_inode(rip);
261   return(r);
262 }
263 
264 
265 /*===========================================================================*
266  *				fs_rename				     *
267  *===========================================================================*/
268 int fs_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
269 	char *new_name)
270 {
271 /* Perform the rename(name1, name2) system call. */
272   struct inode *old_dirp, *old_ip;	/* ptrs to old dir, file inodes */
273   struct inode *new_dirp, *new_ip;	/* ptrs to new dir, file inodes */
274   struct inode *new_superdirp, *next_new_superdirp;
275   int r = OK;				/* error flag; initially no error */
276   int odir, ndir;			/* TRUE iff {old|new} file is dir */
277   int same_pdir = 0;			/* TRUE iff parent dirs are the same */
278   ino_t numb;
279 
280   /* Get old dir inode */
281   if( (old_dirp = get_inode(fs_dev, old_dir_nr)) == NULL)
282 	return(err_code);
283 
284   old_ip = advance(old_dirp, old_name);
285   r = err_code;
286 
287   if (old_ip == NULL) {
288 	put_inode(old_dirp);
289 	return(r);
290   }
291 
292   if (old_ip->i_mountpoint) {
293 	put_inode(old_ip);
294 	put_inode(old_dirp);
295 	return(EBUSY);
296   }
297 
298   /* Get new dir inode */
299   if ((new_dirp = get_inode(fs_dev, new_dir_nr)) == NULL){
300 	put_inode(old_ip);
301 	put_inode(old_dirp);
302 	return(err_code);
303   } else {
304 	if (new_dirp->i_links_count == NO_LINK) { /* Dir does not exist */
305 		put_inode(old_ip);
306 		put_inode(old_dirp);
307 		put_inode(new_dirp);
308 		return(ENOENT);
309 	}
310   }
311 
312   new_ip = advance(new_dirp, new_name); /* not required to exist */
313 
314   /* If the node does exist, make sure it's not a mountpoint. */
315   if (new_ip != NULL && new_ip->i_mountpoint) {
316 	put_inode(new_ip);
317 	new_ip = NULL;
318 	r = EBUSY;
319   }
320 
321   if(old_ip != NULL)
322 	  odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */
323   else
324 	  odir = FALSE;
325 
326   /* If it is ok, check for a variety of possible errors. */
327   if(r == OK) {
328 	same_pdir = (old_dirp == new_dirp);
329 
330 	/* The old inode must not be a superdirectory of the new last dir. */
331 	if (odir && !same_pdir) {
332 		dup_inode(new_superdirp = new_dirp);
333 		while (TRUE) {	/* may hang in a file system loop */
334 			if (new_superdirp == old_ip) {
335 				put_inode(new_superdirp);
336 				r = EINVAL;
337 				break;
338 			}
339 			next_new_superdirp = advance(new_superdirp, "..");
340 
341 			put_inode(new_superdirp);
342 			if(next_new_superdirp == new_superdirp) {
343 				put_inode(new_superdirp);
344 				break;
345 			}
346 			if(next_new_superdirp->i_num == ROOT_INODE) {
347 				/* imitate that we are back at the root,
348 				 * cross device checked already on VFS */
349 				put_inode(next_new_superdirp);
350 				err_code = OK;
351 				break;
352 			}
353 			new_superdirp = next_new_superdirp;
354 			if(new_superdirp == NULL) {
355 				/* Missing ".." entry.  Assume the worst. */
356 				r = EINVAL;
357 				break;
358 			}
359 		}
360 	}
361 
362 	/* Some tests apply only if the new path exists. */
363 	if(new_ip == NULL) {
364 		if(odir && (new_dirp->i_links_count >= SHRT_MAX ||
365 			    new_dirp->i_links_count >= LINK_MAX) &&
366 		   !same_pdir && r == OK) {
367 			r = EMLINK;
368 		}
369 	} else {
370 		if(old_ip == new_ip) r = SAME; /* old=new */
371 
372 		ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY);/* dir ? */
373 		if(odir == TRUE && ndir == FALSE) r = ENOTDIR;
374 		if(odir == FALSE && ndir == TRUE) r = EISDIR;
375 	}
376   }
377 
378   /* If a process has another root directory than the system root, we might
379    * "accidently" be moving it's working directory to a place where it's
380    * root directory isn't a super directory of it anymore. This can make
381    * the function chroot useless. If chroot will be used often we should
382    * probably check for it here. */
383 
384   /* The rename will probably work. Only two things can go wrong now:
385    * 1. being unable to remove the new file. (when new file already exists)
386    * 2. being unable to make the new directory entry. (new file doesn't exists)
387    *     [directory has to grow by one block and cannot because the disk
388    *      is completely full].
389    */
390   if(r == OK) {
391 	if(new_ip != NULL) {
392 		/* There is already an entry for 'new'. Try to remove it. */
393 		if(odir)
394 			r = remove_dir(new_dirp, new_ip, new_name);
395 		else
396 			r = unlink_file(new_dirp, new_ip, new_name);
397 	}
398 	/* if r is OK, the rename will succeed, while there is now an
399 	 * unused entry in the new parent directory. */
400   }
401 
402   if(r == OK) {
403 	  /* If the new name will be in the same parent directory as the old
404 	   * one, first remove the old name to free an entry for the new name,
405 	   * otherwise first try to create the new name entry to make sure
406 	   * the rename will succeed.
407 	   */
408 	numb = old_ip->i_num;		/* inode number of old file */
409 
410 	if(same_pdir) {
411 		r = search_dir(old_dirp,old_name, NULL, DELETE, 0);
412 						/* shouldn't go wrong. */
413 		if(r == OK)
414 			(void) search_dir(old_dirp, new_name, &numb, ENTER,
415 					  old_ip->i_mode & I_TYPE);
416 	} else {
417 		r = search_dir(new_dirp, new_name, &numb, ENTER,
418 					old_ip->i_mode & I_TYPE);
419 		if(r == OK) {
420 			(void) search_dir(old_dirp, old_name, NULL,
421 					  DELETE, 0);
422 		}
423 	}
424   }
425   /* If r is OK, the ctime and mtime of old_dirp and new_dirp have been marked
426    * for update in search_dir. */
427 
428   if(r == OK && odir && !same_pdir) {
429 	/* Update the .. entry in the directory (still points to old_dirp).*/
430 	numb = new_dirp->i_num;
431 	(void) unlink_file(old_ip, NULL, "..");
432 	if(search_dir(old_ip, "..", &numb, ENTER, I_DIRECTORY) == OK) {
433 		/* New link created. */
434 		new_dirp->i_links_count++;
435 		new_dirp->i_dirt = IN_DIRTY;
436 	}
437   }
438 
439   /* Release the inodes. */
440   put_inode(old_dirp);
441   put_inode(old_ip);
442   put_inode(new_dirp);
443   put_inode(new_ip);
444   return(r == SAME ? OK : r);
445 }
446 
447 
448 /*===========================================================================*
449  *				fs_trunc				     *
450  *===========================================================================*/
451 int fs_trunc(ino_t ino_nr, off_t start, off_t end)
452 {
453   struct inode *rip;
454   int r;
455 
456   if( (rip = find_inode(fs_dev, ino_nr)) == NULL)
457 	  return(EINVAL);
458 
459   if (end == 0)
460 	  r = truncate_inode(rip, start);
461   else
462 	  r = freesp_inode(rip, start, end);
463 
464   return(r);
465 }
466 
467 
468 /*===========================================================================*
469  *				truncate_inode				     *
470  *===========================================================================*/
471 int truncate_inode(rip, newsize)
472 register struct inode *rip;	/* pointer to inode to be truncated */
473 off_t newsize;			/* inode must become this size */
474 {
475 /* Set inode to a certain size, freeing any blocks no longer referenced
476  * and updating the size in the inode. If the inode is extended, the
477  * extra space is a hole that reads as zeroes.
478  *
479  * Nothing special has to happen to file pointers if inode is opened in
480  * O_APPEND mode, as this is different per fd and is checked when
481  * writing is done.
482  */
483   int r;
484   mode_t file_type;
485 
486   discard_preallocated_blocks(rip);
487 
488   file_type = rip->i_mode & I_TYPE;	/* check to see if file is special */
489   if (file_type == I_CHAR_SPECIAL || file_type == I_BLOCK_SPECIAL)
490 	return(EINVAL);
491   if (newsize > rip->i_sp->s_max_size)	/* don't let inode grow too big */
492 	return(EFBIG);
493 
494   /* Free the actual space if truncating. */
495   if (newsize < rip->i_size) {
496 	if ((r = freesp_inode(rip, newsize, rip->i_size)) != OK)
497 		return(r);
498   }
499 
500   /* Clear the rest of the last block if expanding. */
501   if (newsize > rip->i_size) zeroblock_half(rip, rip->i_size, LAST_HALF);
502 
503   /* Next correct the inode size. */
504   rip->i_size = newsize;
505   rip->i_update |= CTIME | MTIME;
506   rip->i_dirt = IN_DIRTY;
507 
508   return(OK);
509 }
510 
511 
512 /*===========================================================================*
513  *				freesp_inode				     *
514  *===========================================================================*/
515 static int freesp_inode(rip, start, end)
516 register struct inode *rip;	/* pointer to inode to be partly freed */
517 off_t start, end;		/* range of bytes to free (end uninclusive) */
518 {
519 /* Cut an arbitrary hole in an inode. The caller is responsible for checking
520  * the reasonableness of the inode type of rip. The reason is this is that
521  * this function can be called for different reasons, for which different
522  * sets of inode types are reasonable. Adjusting the final size of the inode
523  * is to be done by the caller too, if wished.
524  *
525  * Consumers of this function currently are truncate_inode() (used to
526  * free indirect and data blocks for any type of inode, but also to
527  * implement the ftruncate() and truncate() system calls) and the F_FREESP
528  * fcntl().
529  */
530   off_t p, e;
531   int r;
532   unsigned short block_size = rip->i_sp->s_block_size;
533   int zero_last, zero_first;
534 
535   discard_preallocated_blocks(rip);
536 
537   if (rip->i_blocks == 0) {
538   /* Either hole or symlink. Freeing fast symlink using
539    * write_map() causes segfaults since it doesn't use any
540    * blocks, but uses i_block[] to store target.
541    */
542 	return(OK);
543   }
544 
545   if(end > rip->i_size)		/* freeing beyond end makes no sense */
546 	end = rip->i_size;
547   if(end <= start)		/* end is uninclusive, so start<end */
548 	return(EINVAL);
549 
550   /* If freeing doesn't cross a block boundary, then we may only zero
551    * a range of the block.
552    */
553   zero_last = start % block_size;
554   zero_first = end % block_size && end < rip->i_size;
555   if (start/block_size == (end-1)/block_size && (zero_last || zero_first)) {
556 	zeroblock_range(rip, start, end-start);
557   } else {
558 	/* First zero unused part of partly used blocks. */
559 	if (zero_last)
560 		zeroblock_half(rip, start, LAST_HALF);
561 	if (zero_first)
562 		zeroblock_half(rip, end, FIRST_HALF);
563 
564 	/* Now completely free the completely unused blocks.
565 	 * write_map() will free unused indirect
566 	 * blocks too. Converting the range to block numbers avoids
567 	 * overflow on p when doing e.g. 'p += block_size'.
568 	 */
569 	e = end / block_size;
570 	if (end == rip->i_size && (end % block_size))
571 		e++;
572 	for (p = nextblock(start, block_size)/block_size; p < e; p++) {
573 		if ((r = write_map(rip, p*block_size, NO_BLOCK, WMAP_FREE)) != OK)
574 			return(r);
575 	}
576   }
577 
578   rip->i_update |= CTIME | MTIME;
579   rip->i_dirt = IN_DIRTY;
580 
581   return(OK);
582 }
583 
584 
585 /*===========================================================================*
586  *				nextblock				     *
587  *===========================================================================*/
588 static off_t nextblock(pos, block_size)
589 off_t pos;
590 unsigned short block_size;
591 {
592 /* Return the first position in the next block after position 'pos'
593  * (unless this is the first position in the current block).
594  * This can be done in one expression, but that can overflow pos.
595  */
596   off_t p;
597   p = (pos / block_size) * block_size;
598   if (pos % block_size) p += block_size;	/* Round up. */
599   return(p);
600 }
601 
602 
603 /*===========================================================================*
604  *				zeroblock_half				     *
605  *===========================================================================*/
606 static void zeroblock_half(rip, pos, half)
607 struct inode *rip;
608 off_t pos;
609 int half;
610 {
611 /* Zero the upper or lower 'half' of a block that holds position 'pos'.
612  * half can be FIRST_HALF or LAST_HALF.
613  *
614  * FIRST_HALF: 0..pos-1 will be zeroed
615  * LAST_HALF:  pos..blocksize-1 will be zeroed
616  */
617   off_t offset, len;
618 
619   /* Offset of zeroing boundary. */
620   offset = pos % rip->i_sp->s_block_size;
621 
622   if(half == LAST_HALF)  {
623 	len = rip->i_sp->s_block_size - offset;
624   } else {
625 	len = offset;
626 	pos -= offset;
627   }
628 
629   zeroblock_range(rip, pos, len);
630 }
631 
632 
633 /*===========================================================================*
634  *				zeroblock_range				     *
635  *===========================================================================*/
636 static void zeroblock_range(rip, pos, len)
637 struct inode *rip;
638 off_t pos;
639 off_t len;
640 {
641 /* Zero a range in a block.
642  * This function is used to zero a segment of a block.
643  */
644   struct buf *bp;
645   off_t offset;
646 
647   if (!len) return; /* no zeroing to be done. */
648   if (!(bp = get_block_map(rip, rounddown(pos, rip->i_sp->s_block_size))))
649 	return; /* skip holes */
650   offset = pos % rip->i_sp->s_block_size;
651   if (offset + len > rip->i_sp->s_block_size)
652 	panic("zeroblock_range: len too long: %lld", len);
653   memset(b_data(bp) + offset, 0, len);
654   lmfs_markdirty(bp);
655   put_block(bp);
656 }
657