13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * link.c --- create links in a ext2fs directory 3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright (C) 1993, 1994 Theodore Ts'o. 519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * 619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header% 7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library 8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2. 919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header% 103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h> 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h> 144cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H 153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h> 164cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif 17f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 18b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "ext2fs.h" 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct link_struct { 228a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ext2_filsys fs; 233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o const char *name; 243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int namelen; 2531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o ext2_ino_t inode; 263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int done; 285dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o unsigned int blocksize; 298a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o errcode_t err; 30e5b38a5fafe4807b54d90a2e70bddf4b41b1695bTheodore Ts'o struct ext2_super_block *sb; 31efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o}; 323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic int link_proc(struct ext2_dir_entry *dirent, 343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int offset, 353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int blocksize, 363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *buf, 37b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o void *priv_data) 383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 39b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o struct link_struct *ls = (struct link_struct *) priv_data; 403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct ext2_dir_entry *next; 418a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o unsigned int rec_len, min_rec_len, curr_rec_len; 423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int ret = 0; 433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 44e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall if (ls->done) 45e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall return DIRENT_ABORT; 46e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall 473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o rec_len = EXT2_DIR_REC_LEN(ls->namelen); 483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 498a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len); 508a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o if (ls->err) 518a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o return DIRENT_ABORT; 525dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o 533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * See if the following directory entry (if any) is unused; 553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * if so, absorb it into this one. 563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 575dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len); 58e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall if ((offset + (int) curr_rec_len < blocksize - 8) && 593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o (next->inode == 0) && 60e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) { 618a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o curr_rec_len += next->rec_len; 628a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); 638a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o if (ls->err) 648a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o return DIRENT_ABORT; 653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ret = DIRENT_CHANGED; 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If the directory entry is used, see if we can split the 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * directory entry to make room for the new name. If so, 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * truncate it and return. 723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (dirent->inode) { 74674a4ee1e3e05133ddad701730bfc21c283272a4Theodore Ts'o min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF); 755dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (curr_rec_len < (min_rec_len + rec_len)) 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ret; 775dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o rec_len = curr_rec_len - min_rec_len; 788a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent); 798a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o if (ls->err) 808a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o return DIRENT_ABORT; 813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o next = (struct ext2_dir_entry *) (buf + offset + 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->rec_len); 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o next->inode = 0; 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o next->name_len = 0; 858a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next); 868a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o if (ls->err) 878a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o return DIRENT_ABORT; 883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return DIRENT_CHANGED; 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * If we get this far, then the directory entry is not used. 933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * See if we can fit the request entry in. If so, do it. 943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 955dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o if (curr_rec_len < rec_len) 963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return ret; 973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->inode = ls->inode; 983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o dirent->name_len = ls->namelen; 993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strncpy(dirent->name, ls->name, ls->namelen); 100e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) 101e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o dirent->name_len |= (ls->flags & 0x7) << 8; 1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ls->done++; 1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return DIRENT_ABORT|DIRENT_CHANGED; 1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 107e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o/* 108e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o * Note: the low 3 bits of the flags field are used as the directory 109e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o * entry filetype. 110e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o */ 1113cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o#ifdef __TURBOC__ 11231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o #pragma argsused 1133cb6c5021d722e17b7105d1bc090880671f6fc6dTheodore Ts'o#endif 114efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'oerrcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, 11531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o ext2_ino_t ino, int flags) 1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 117fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o errcode_t retval; 118fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o struct link_struct ls; 119fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o struct ext2_inode inode; 1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 121f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 122f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (!(fs->flags & EXT2_FLAG_RW)) 1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return EXT2_ET_RO_FILSYS; 1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1268a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ls.fs = fs; 1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ls.name = name; 1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ls.namelen = name ? strlen(name) : 0; 1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ls.inode = ino; 130e6198e5a0191b2cbbf9765c4e4df11c7929279e6Theodore Ts'o ls.flags = flags; 1313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o ls.done = 0; 132e5b38a5fafe4807b54d90a2e70bddf4b41b1695bTheodore Ts'o ls.sb = fs->super; 1335dd77dbe5a0ac6d78c1c6441fae4087be56d9088Theodore Ts'o ls.blocksize = fs->blocksize; 1348a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o ls.err = 0; 1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, 1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 0, link_proc, &ls); 1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (retval) 1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 1408a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o if (ls.err) 1418a480350952f6f0fdbce54326b6d847e66368897Theodore Ts'o return ls.err; 1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 143fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o if (!ls.done) 144fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o return EXT2_ET_DIR_NO_SPACE; 145fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o 146fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0) 147fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o return retval; 148fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o 149fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o if (inode.i_flags & EXT2_INDEX_FL) { 150fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o inode.i_flags &= ~EXT2_INDEX_FL; 151fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0) 152fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o return retval; 153fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o } 154fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o 155fe4dd429dc878d877abe08c2c41eed48df4e4651Theodore Ts'o return 0; 1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 157