119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project/*
219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project * link.c --- create links in a ext2fs directory
33984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt *
419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project * Copyright (C) 1993, 1994 Theodore Ts'o.
519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project *
619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project * %Begin-Header%
78558eab78390d1924cd6b255686ceef133f294d5Ken Sumrall * This file may be redistributed under the terms of the GNU Library
88558eab78390d1924cd6b255686ceef133f294d5Ken Sumrall * General Public License, version 2.
919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project * %End-Header%
1019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project */
1119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
1219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#include <stdio.h>
1319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#include <string.h>
1419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#if HAVE_UNISTD_H
1519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#include <unistd.h>
1619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#endif
1719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
1819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#include "ext2_fs.h"
1919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#include "ext2fs.h"
2019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
2119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Projectstruct link_struct  {
223984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ext2_filsys	fs;
2319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	const char	*name;
2419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	int		namelen;
2519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ext2_ino_t	inode;
2619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	int		flags;
2719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	int		done;
283984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned int	blocksize;
293984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	errcode_t	err;
3019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	struct ext2_super_block *sb;
313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt};
3219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
3319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Projectstatic int link_proc(struct ext2_dir_entry *dirent,
3419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		     int	offset,
3519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		     int	blocksize,
3619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		     char	*buf,
3719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		     void	*priv_data)
3819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project{
3919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	struct link_struct *ls = (struct link_struct *) priv_data;
4019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	struct ext2_dir_entry *next;
413984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	unsigned int rec_len, min_rec_len, curr_rec_len;
4219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	int ret = 0;
4319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
4419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	rec_len = EXT2_DIR_REC_LEN(ls->namelen);
4519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
463984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
473984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (ls->err)
483984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return DIRENT_ABORT;
493984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt
5019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	/*
5119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * See if the following directory entry (if any) is unused;
5219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * if so, absorb it into this one.
5319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 */
543984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
553984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if ((offset + curr_rec_len < blocksize - 8) &&
5619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	    (next->inode == 0) &&
573984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	    (offset + curr_rec_len + next->rec_len <= blocksize)) {
583984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		curr_rec_len += next->rec_len;
593984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
603984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (ls->err)
613984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return DIRENT_ABORT;
6219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		ret = DIRENT_CHANGED;
6319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	}
6419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
6519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	/*
6619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * If the directory entry is used, see if we can split the
6719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * directory entry to make room for the new name.  If so,
6819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * truncate it and return.
6919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 */
7019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if (dirent->inode) {
7119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
723984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (curr_rec_len < (min_rec_len + rec_len))
7319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project			return ret;
743984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		rec_len = curr_rec_len - min_rec_len;
753984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent);
763984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (ls->err)
773984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return DIRENT_ABORT;
7819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		next = (struct ext2_dir_entry *) (buf + offset +
7919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project						  dirent->rec_len);
8019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		next->inode = 0;
8119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		next->name_len = 0;
823984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
833984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		if (ls->err)
843984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt			return DIRENT_ABORT;
8519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		return DIRENT_CHANGED;
8619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	}
8719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
8819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	/*
8919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * If we get this far, then the directory entry is not used.
9019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 * See if we can fit the request entry in.  If so, do it.
9119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	 */
923984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (curr_rec_len < rec_len)
9319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		return ret;
9419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	dirent->inode = ls->inode;
9519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	dirent->name_len = ls->namelen;
9619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	strncpy(dirent->name, ls->name, ls->namelen);
9719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
9819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		dirent->name_len |= (ls->flags & 0x7) << 8;
9919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
10019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls->done++;
10119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	return DIRENT_ABORT|DIRENT_CHANGED;
10219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project}
10319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
10419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project/*
10519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project * Note: the low 3 bits of the flags field are used as the directory
10619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project * entry filetype.
10719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project */
10819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#ifdef __TURBOC__
10919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project #pragma argsused
11019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project#endif
1113984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidterrcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
11219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		      ext2_ino_t ino, int flags)
11319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project{
11419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	errcode_t		retval;
11519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	struct link_struct	ls;
11619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	struct ext2_inode	inode;
11719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
11819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
11919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
12019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if (!(fs->flags & EXT2_FLAG_RW))
12119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		return EXT2_ET_RO_FILSYS;
12219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
1233984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ls.fs = fs;
12419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls.name = name;
12519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls.namelen = name ? strlen(name) : 0;
12619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls.inode = ino;
12719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls.flags = flags;
12819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls.done = 0;
12919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	ls.sb = fs->super;
1303984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ls.blocksize = fs->blocksize;
1313984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	ls.err = 0;
13219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
13319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
13419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project				    0, link_proc, &ls);
13519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if (retval)
13619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		return retval;
1373984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt	if (ls.err)
1383984b61df41c68966bdfbb2a5e5a45ef4b9a536cDmitry Shmidt		return ls.err;
13919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
14019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if (!ls.done)
14119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		return EXT2_ET_DIR_NO_SPACE;
14219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
14319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
14419dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		return retval;
14519dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
14619dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	if (inode.i_flags & EXT2_INDEX_FL) {
14719dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		inode.i_flags &= ~EXT2_INDEX_FL;
14819dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project		if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
14919dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project			return retval;
15019dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	}
15119dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project
15219dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project	return 0;
15319dacda2b02bb08c0ffb649f84526b249c749279The Android Open Source Project}
154