(linenum→info "unix/slp.c:2238")

coreutils/6.9/lib/fchdir.c

    1: /* fchdir replacement.
    2:    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
    3: 
    4:    This program is free software; you can redistribute it and/or modify
    5:    it under the terms of the GNU General Public License as published by
    6:    the Free Software Foundation; either version 2, or (at your option)
    7:    any later version.
    8: 
    9:    This program is distributed in the hope that it will be useful,
   10:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12:    GNU General Public License for more details.
   13: 
   14:    You should have received a copy of the GNU General Public License
   15:    along with this program; if not, write to the Free Software Foundation,
   16:    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
   17: 
   18: #include <config.h>
   19: 
   20: /* Specification.  */
   21: #include <unistd.h>
   22: 
   23: #include <errno.h>
   24: #include <fcntl.h>
   25: #include <stdarg.h>
   26: #include <stdlib.h>
   27: #include <string.h>
   28: #include <sys/types.h>
   29: #include <sys/stat.h>
   30: #include <dirent.h>
   31: 
   32: #include "canonicalize.h"
   33: #include "dirfd.h"
   34: 
   35: /* This replacement assumes that a directory is not renamed while opened
   36:    through a file descriptor.  */
   37: 
   38: /* Array of file descriptors opened.  If it points to a directory, it stores
   39:    info about this directory; otherwise it stores an errno value of ENOTDIR.  */
   40: typedef struct
   41: {
   42:   char *name;       /* Absolute name of the directory, or NULL.  */
   43:   int saved_errno;  /* If name == NULL: The error code describing the failure
   44:                        reason.  */
   45: } dir_info_t;
   46: static dir_info_t *dirs;
   47: static size_t dirs_allocated;
   48: 
   49: /* Try to ensure dirs has enough room for a slot at index fd.  */
   50: static void
   51: ensure_dirs_slot (size_t fd)
   52: {
   53:   if (fd >= dirs_allocated)
   54:     {
   55:       size_t new_allocated;
   56:       dir_info_t *new_dirs;
   57:       size_t i;
   58: 
   59:       new_allocated = 2 * dirs_allocated + 1;
   60:       if (new_allocated <= fd)
   61:         new_allocated = fd + 1;
   62:       new_dirs =
   63:         (dirs != NULL
   64:          ? (dir_info_t *) realloc (dirs, new_allocated * sizeof (dir_info_t))
   65:          : (dir_info_t *) malloc (new_allocated * sizeof (dir_info_t)));
   66:       if (new_dirs != NULL)
   67:         {
   68:           for (i = dirs_allocated; i < new_allocated; i++)
   69:             {
   70:               new_dirs[i].name = NULL;
   71:               new_dirs[i].saved_errno = ENOTDIR;
   72:             }
   73:           dirs = new_dirs;
   74:           dirs_allocated = new_allocated;
   75:         }
   76:     }
   77: }
   78: 
   79: /* Override open() and close(), to keep track of the open file descriptors.  */
   80: 
   81: int
   82: close (int fd)
   83: #undef close
   84: {
   85:   int retval = close (fd);
   86: 
   87:   if (retval >= 0 && fd >= 0 && fd < dirs_allocated)
   88:     {
   89:       if (dirs[fd].name != NULL)
   90:         free (dirs[fd].name);
   91:       dirs[fd].name = NULL;
   92:       dirs[fd].saved_errno = ENOTDIR;
   93:     }
   94:   return retval;
   95: }
   96: 
   97: int
   98: open (const char *filename, int flags, ...)
   99: #undef open
  100: {
  101:   mode_t mode;
  102:   int fd;
  103:   struct stat statbuf;
  104: 
  105:   mode = 0;
  106:   if (flags & O_CREAT)
  107:     {
  108:       va_list arg;
  109:       va_start (arg, flags);
  110: 
  111:       /* If mode_t is narrower than int, use the promoted type (int),
  112:          not mode_t.  Use sizeof to guess whether mode_t is narrower;
  113:          we don't know of any practical counterexamples.  */
  114:       mode = (sizeof (mode_t) < sizeof (int)
  115:               ? va_arg (arg, int)
  116:               : va_arg (arg, mode_t));
  117: 
  118:       va_end (arg);
  119:     }
  120:   fd = open (filename, flags, mode);
  121:   if (fd >= 0)
  122:     {
  123:       ensure_dirs_slot (fd);
  124:       if (fd < dirs_allocated
  125:           && fstat (fd, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
  126:         {
  127:           dirs[fd].name = canonicalize_file_name (filename);
  128:           if (dirs[fd].name == NULL)
  129:             dirs[fd].saved_errno = errno;
  130:         }
  131:     }
  132:   return fd;
  133: }
  134: 
  135: /* Override opendir() and closedir(), to keep track of the open file
  136:    descriptors.  Needed because there is a function dirfd().  */
  137: 
  138: int
  139: closedir (DIR *dp)
  140: #undef closedir
  141: {
  142:   int fd = dirfd (dp);
  143:   int retval = closedir (dp);
  144: 
  145:   if (retval >= 0 && fd >= 0 && fd < dirs_allocated)
  146:     {
  147:       if (dirs[fd].name != NULL)
  148:         free (dirs[fd].name);
  149:       dirs[fd].name = NULL;
  150:       dirs[fd].saved_errno = ENOTDIR;
  151:     }
  152:   return retval;
  153: }
  154: 
  155: DIR *
  156: opendir (const char *filename)
  157: #undef opendir
  158: {
  159:   DIR *dp;
  160: 
  161:   dp = opendir (filename);
  162:   if (dp != NULL)
  163:     {
  164:       int fd = dirfd (dp);
  165:       if (fd >= 0)
  166:         {
  167:           ensure_dirs_slot (fd);
  168:           if (fd < dirs_allocated)
  169:             {
  170:               dirs[fd].name = canonicalize_file_name (filename);
  171:               if (dirs[fd].name == NULL)
  172:                 dirs[fd].saved_errno = errno;
  173:             }
  174:         }
  175:     }
  176:   return dp;
  177: }
  178: 
  179: /* Override dup() and dup2(), to keep track of open file descriptors.  */
  180: 
  181: int
  182: dup (int oldfd)
  183: #undef dup
  184: {
  185:   int newfd = dup (oldfd);
  186: 
  187:   if (oldfd >= 0 && newfd >= 0)
  188:     {
  189:       ensure_dirs_slot (newfd);
  190:       if (newfd < dirs_allocated)
  191:         {
  192:           if (oldfd < dirs_allocated)
  193:             {
  194:               if (dirs[oldfd].name != NULL)
  195:                 {
  196:                   dirs[newfd].name = strdup (dirs[oldfd].name);
  197:                   if (dirs[newfd].name == NULL)
  198:                     dirs[newfd].saved_errno = ENOMEM;
  199:                 }
  200:               else
  201:                 {
  202:                   dirs[newfd].name = NULL;
  203:                   dirs[newfd].saved_errno = dirs[oldfd].saved_errno;
  204:                 }
  205:             }
  206:           else
  207:             {
  208:               dirs[newfd].name = NULL;
  209:               dirs[newfd].saved_errno = ENOMEM;
  210:             }
  211:         }
  212:     }
  213:   return newfd;
  214: }
  215: 
  216: int
  217: dup2 (int oldfd, int newfd)
  218: #undef dup2
  219: {
  220:   int retval = dup2 (oldfd, newfd);
  221: 
  222:   if (retval >= 0 && oldfd >= 0 && newfd >= 0 && newfd != oldfd)
  223:     {
  224:       ensure_dirs_slot (newfd);
  225:       if (newfd < dirs_allocated)
  226:         {
  227:           if (oldfd < dirs_allocated)
  228:             {
  229:               if (dirs[oldfd].name != NULL)
  230:                 {
  231:                   dirs[newfd].name = strdup (dirs[oldfd].name);
  232:                   if (dirs[newfd].name == NULL)
  233:                     dirs[newfd].saved_errno = ENOMEM;
  234:                 }
  235:               else
  236:                 {
  237:                   dirs[newfd].name = NULL;
  238:                   dirs[newfd].saved_errno = dirs[oldfd].saved_errno;
  239:                 }
  240:             }
  241:           else
  242:             {
  243:               dirs[newfd].name = NULL;
  244:               dirs[newfd].saved_errno = ENOMEM;
  245:             }
  246:         }
  247:     }
  248:   return retval;
  249: }
  250: 
  251: /* Implement fchdir() in terms of chdir().  */
  252: 
  253: int
  254: fchdir (int fd)
  255: {
  256:   if (fd >= 0)
  257:     {
  258:       if (fd < dirs_allocated)
  259:         {
  260:           if (dirs[fd].name != NULL)
  261:             return chdir (dirs[fd].name);
  262:           else
  263:             {
  264:               errno = dirs[fd].saved_errno;
  265:               return -1;
  266:             }
  267:         }
  268:       else
  269:         {
  270:           errno = ENOMEM;
  271:           return -1;
  272:         }
  273:     }
  274:   else
  275:     {
  276:       errno = EBADF;
  277:       return -1;
  278:     }
  279: }
Syntax (Markdown)