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