home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / win95 / ext2tool.exe / EXT2FS / LINK.C < prev    next >
C/C++ Source or Header  |  1995-05-10  |  4KB  |  153 lines

  1. /*
  2.  * link.c --- create or delete links in a ext2fs directory
  3.  * 
  4.  * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
  5.  * under the terms of the GNU Public License.
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <stdlib.h>
  12. #include <errno.h>
  13.  
  14. #include <linux/ext2_fs.h>
  15.  
  16. #include "ext2fs.h"
  17.  
  18. struct link_struct  {
  19.     const char    *name;
  20.     int        namelen;
  21.     ino_t        inode;
  22.     int        flags;
  23.     int        done;
  24. };    
  25.  
  26. static int link_proc(struct ext2_dir_entry *dirent,
  27.              int    offset,
  28.              int    blocksize,
  29.              char    *buf,
  30.              void    *private)
  31. {
  32.     struct link_struct *ls = (struct link_struct *) private;
  33.     struct ext2_dir_entry *next;
  34.     int rec_len;
  35.     int ret = 0;
  36.  
  37.     rec_len = EXT2_DIR_REC_LEN(ls->namelen);
  38.  
  39.     /*
  40.      * See if the following directory entry (if any) is unused;
  41.      * if so, absorb it into this one.
  42.      */
  43.     next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
  44.     if ((offset + dirent->rec_len < blocksize - 8) &&
  45.         (next->inode == 0) &&
  46.         (offset + dirent->rec_len + next->rec_len <= blocksize)) {
  47.         dirent->rec_len += next->rec_len;
  48.         ret = DIRENT_CHANGED;
  49.     }
  50.  
  51.     /*
  52.      * If the directory entry is used, see if we can split the
  53.      * directory entry to make room for the new name.  If so,
  54.      * truncate it and return.
  55.      */
  56.     if (dirent->inode) {
  57.         if (dirent->rec_len < (EXT2_DIR_REC_LEN(dirent->name_len) +
  58.                        rec_len))
  59.             return ret;
  60.         rec_len = dirent->rec_len - EXT2_DIR_REC_LEN(dirent->name_len);
  61.         dirent->rec_len = EXT2_DIR_REC_LEN(dirent->name_len);
  62.         next = (struct ext2_dir_entry *) (buf + offset +
  63.                           dirent->rec_len);
  64.         next->inode = 0;
  65.         next->name_len = 0;
  66.         next->rec_len = rec_len;
  67.         return DIRENT_CHANGED;
  68.     }
  69.  
  70.     /*
  71.      * If we get this far, then the directory entry is not used.
  72.      * See if we can fit the request entry in.  If so, do it.
  73.      */
  74.     if (dirent->rec_len < rec_len)
  75.         return ret;
  76.     dirent->inode = ls->inode;
  77.     dirent->name_len = ls->namelen;
  78.     strncpy(dirent->name, ls->name, ls->namelen);
  79.  
  80.     ls->done++;
  81.     return DIRENT_ABORT|DIRENT_CHANGED;
  82. }
  83.  
  84. errcode_t ext2fs_link(ext2_filsys fs, ino_t dir, const char *name, ino_t ino,
  85.               int flags)
  86. {
  87.     errcode_t    retval;
  88.     struct link_struct ls;
  89.  
  90.     EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  91.  
  92.     if (!(fs->flags & EXT2_FLAG_RW))
  93.         return EXT2_ET_RO_FILSYS;
  94.  
  95.     ls.name = name;
  96.     ls.namelen = name ? strlen(name) : 0;
  97.     ls.inode = ino;
  98.     ls.flags = 0;
  99.     ls.done = 0;
  100.  
  101.     retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
  102.                     0, link_proc, &ls);
  103.     if (retval)
  104.         return retval;
  105.  
  106.     return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
  107. }
  108.  
  109. static int unlink_proc(struct ext2_dir_entry *dirent,
  110.              int    offset,
  111.              int    blocksize,
  112.              char    *buf,
  113.              void    *private)
  114. {
  115.     struct link_struct *ls = (struct link_struct *) private;
  116.  
  117.     if (ls->name && (dirent->name_len != ls->namelen))
  118.         return 0;
  119.     if (ls->name && strncmp(ls->name, dirent->name, dirent->name_len))
  120.         return 0;
  121.     if (ls->inode && (dirent->inode != ls->inode))
  122.         return 0;
  123.  
  124.     dirent->inode = 0;
  125.     ls->done++;
  126.     return DIRENT_ABORT|DIRENT_CHANGED;
  127. }
  128.  
  129. errcode_t ext2fs_unlink(ext2_filsys fs, ino_t dir, const char *name, ino_t ino,
  130.             int flags)
  131. {
  132.     errcode_t    retval;
  133.     struct link_struct ls;
  134.  
  135.     EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  136.  
  137.     if (!(fs->flags & EXT2_FLAG_RW))
  138.         return EXT2_ET_RO_FILSYS;
  139.  
  140.     ls.name = name;
  141.     ls.namelen = name ? strlen(name) : 0;
  142.     ls.inode = ino;
  143.     ls.flags = 0;
  144.     ls.done = 0;
  145.  
  146.     retval = ext2fs_dir_iterate(fs, dir, 0, 0, unlink_proc, &ls);
  147.     if (retval)
  148.         return retval;
  149.  
  150.     return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
  151. }
  152.  
  153.