(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
pathconf.c
       1  /* Get file-specific information about a file.  Linux version.
       2     Copyright (C) 1991-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <mntent.h>
      21  #include <stdio_ext.h>
      22  #include <string.h>
      23  #include <unistd.h>
      24  #include <sys/sysmacros.h>
      25  
      26  #include "pathconf.h"
      27  #include "linux_fsinfo.h"
      28  #include <not-cancel.h>
      29  
      30  static long int posix_pathconf (const char *file, int name);
      31  
      32  /* Define this first, so it can be inlined.  */
      33  #define __pathconf static posix_pathconf
      34  #include <sysdeps/posix/pathconf.c>
      35  
      36  
      37  /* Get file-specific information about FILE.  */
      38  long int
      39  __pathconf (const char *file, int name)
      40  {
      41    struct statfs fsbuf;
      42  
      43    switch (name)
      44      {
      45      case _PC_LINK_MAX:
      46        return __statfs_link_max (__statfs (file, &fsbuf), &fsbuf, file, -1);
      47  
      48      case _PC_FILESIZEBITS:
      49        return __statfs_filesize_max (__statfs (file, &fsbuf), &fsbuf);
      50  
      51      case _PC_2_SYMLINKS:
      52        return __statfs_symlinks (__statfs (file, &fsbuf), &fsbuf);
      53  
      54      case _PC_CHOWN_RESTRICTED:
      55        return __statfs_chown_restricted (__statfs (file, &fsbuf), &fsbuf);
      56  
      57      default:
      58        return posix_pathconf (file, name);
      59      }
      60  }
      61  
      62  
      63  static long int
      64  distinguish_extX (const struct statfs *fsbuf, const char *file, int fd)
      65  {
      66    char buf[64];
      67    char path[PATH_MAX];
      68    struct __stat64_t64 st;
      69  
      70    if ((file == NULL ? __fstat64_time64 (fd, &st)
      71  		    : __stat64_time64 (file, &st)) != 0)
      72      /* Strange.  The statfd call worked, but stat fails.  Default to
      73         the more pessimistic value.  */
      74      return EXT2_LINK_MAX;
      75  
      76    __snprintf (buf, sizeof (buf), "/sys/dev/block/%u:%u",
      77  	      __gnu_dev_major (st.st_dev), __gnu_dev_minor (st.st_dev));
      78  
      79    ssize_t n = __readlink (buf, path, sizeof (path));
      80    if (n != -1 && n < sizeof (path))
      81      {
      82        path[n] = '\0';
      83        char *base = strdupa (__basename (path));
      84        __snprintf (path, sizeof (path), "/sys/fs/ext4/%s", base);
      85  
      86        return __access (path, F_OK) == 0 ? EXT4_LINK_MAX : EXT2_LINK_MAX;
      87      }
      88  
      89    /* XXX Is there a better way to distinguish ext2/3 from ext4 than
      90       iterating over the mounted filesystems and compare the device
      91       numbers?  */
      92    FILE *mtab = __setmntent ("/proc/mounts", "r");
      93    if (mtab == NULL)
      94      mtab = __setmntent (_PATH_MOUNTED, "r");
      95  
      96    /* By default be conservative.  */
      97    long int result = EXT2_LINK_MAX;
      98    if (mtab != NULL)
      99      {
     100        struct mntent mntbuf;
     101        char tmpbuf[1024];
     102  
     103        /* No locking needed.  */
     104        (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER);
     105  
     106        while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf)))
     107  	{
     108  	  if (strcmp (mntbuf.mnt_type, "ext2") != 0
     109  	      && strcmp (mntbuf.mnt_type, "ext3") != 0
     110  	      && strcmp (mntbuf.mnt_type, "ext4") != 0)
     111  	    continue;
     112  
     113  	  struct __stat64_t64 fsst;
     114  	  if (__stat64_time64 (mntbuf.mnt_dir, &fsst) >= 0
     115  	      && st.st_dev == fsst.st_dev)
     116  	    {
     117  	      if (strcmp (mntbuf.mnt_type, "ext4") == 0)
     118  		result = EXT4_LINK_MAX;
     119  	      break;
     120  	    }
     121  	}
     122  
     123        /* Close the file.  */
     124        __endmntent (mtab);
     125      }
     126  
     127    return result;
     128  }
     129  
     130  
     131  /* Used like: return statfs_link_max (__statfs (name, &buf), &buf); */
     132  long int
     133  __statfs_link_max (int result, const struct statfs *fsbuf, const char *file,
     134  		   int fd)
     135  {
     136    if (result < 0)
     137      {
     138        if (errno == ENOSYS)
     139  	/* Not possible, return the default value.  */
     140  	return LINUX_LINK_MAX;
     141  
     142        /* Some error occurred.  */
     143        return -1;
     144      }
     145  
     146    switch (fsbuf->f_type)
     147      {
     148      case EXT2_SUPER_MAGIC:
     149        /* Unfortunately the kernel does not return a different magic number
     150  	 for ext4.  This would be necessary to easily detect etx4 since it
     151  	 has a different LINK_MAX value.  Therefore we have to find it out
     152  	 the hard way.  */
     153        return distinguish_extX (fsbuf, file, fd);
     154  
     155      case F2FS_SUPER_MAGIC:
     156        return F2FS_LINK_MAX;
     157  
     158      case MINIX_SUPER_MAGIC:
     159      case MINIX_SUPER_MAGIC2:
     160        return MINIX_LINK_MAX;
     161  
     162      case MINIX2_SUPER_MAGIC:
     163      case MINIX2_SUPER_MAGIC2:
     164        return MINIX2_LINK_MAX;
     165  
     166      case XENIX_SUPER_MAGIC:
     167        return XENIX_LINK_MAX;
     168  
     169      case SYSV4_SUPER_MAGIC:
     170      case SYSV2_SUPER_MAGIC:
     171        return SYSV_LINK_MAX;
     172  
     173      case COH_SUPER_MAGIC:
     174        return COH_LINK_MAX;
     175  
     176      case UFS_MAGIC:
     177      case UFS_CIGAM:
     178        return UFS_LINK_MAX;
     179  
     180      case REISERFS_SUPER_MAGIC:
     181        return REISERFS_LINK_MAX;
     182  
     183      case XFS_SUPER_MAGIC:
     184        return XFS_LINK_MAX;
     185  
     186      case LUSTRE_SUPER_MAGIC:
     187        return LUSTRE_LINK_MAX;
     188  
     189      default:
     190        return LINUX_LINK_MAX;
     191      }
     192  }
     193  
     194  
     195  /* Used like: return statfs_filesize_max (__statfs (name, &buf), &buf); */
     196  long int
     197  __statfs_filesize_max (int result, const struct statfs *fsbuf)
     198  {
     199    if (result < 0)
     200      {
     201        if (errno == ENOSYS)
     202  	/* Not possible, return the default value.  */
     203  	return 32;
     204  
     205        /* Some error occurred.  */
     206        return -1;
     207      }
     208  
     209    switch (fsbuf->f_type)
     210      {
     211      case F2FS_SUPER_MAGIC:
     212        return 256;
     213  
     214      case BTRFS_SUPER_MAGIC:
     215        return 255;
     216  
     217      case EXT2_SUPER_MAGIC:
     218      case UFS_MAGIC:
     219      case UFS_CIGAM:
     220      case REISERFS_SUPER_MAGIC:
     221      case XFS_SUPER_MAGIC:
     222      case SMB_SUPER_MAGIC:
     223      case NTFS_SUPER_MAGIC:
     224      case UDF_SUPER_MAGIC:
     225      case JFS_SUPER_MAGIC:
     226      case VXFS_SUPER_MAGIC:
     227      case CGROUP_SUPER_MAGIC:
     228      case LUSTRE_SUPER_MAGIC:
     229        return 64;
     230  
     231      case MSDOS_SUPER_MAGIC:
     232      case JFFS_SUPER_MAGIC:
     233      case JFFS2_SUPER_MAGIC:
     234      case NCP_SUPER_MAGIC:
     235      case ROMFS_SUPER_MAGIC:
     236        return 32;
     237  
     238      default:
     239        return 32;
     240      }
     241  }
     242  
     243  
     244  /* Used like: return statfs_link_max (__statfs (name, &buf), &buf); */
     245  long int
     246  __statfs_symlinks (int result, const struct statfs *fsbuf)
     247  {
     248    if (result < 0)
     249      {
     250        if (errno == ENOSYS)
     251  	/* Not possible, return the default value.  */
     252  	return 1;
     253  
     254        /* Some error occurred.  */
     255        return -1;
     256      }
     257  
     258    switch (fsbuf->f_type)
     259      {
     260      case ADFS_SUPER_MAGIC:
     261      case BFS_MAGIC:
     262      case CRAMFS_MAGIC:
     263      case DEVPTS_SUPER_MAGIC:
     264      case EFS_SUPER_MAGIC:
     265      case EFS_MAGIC:
     266      case MSDOS_SUPER_MAGIC:
     267      case NTFS_SUPER_MAGIC:
     268      case QNX4_SUPER_MAGIC:
     269      case ROMFS_SUPER_MAGIC:
     270        /* No symlink support.  */
     271        return 0;
     272  
     273      default:
     274        return 1;
     275      }
     276  }
     277  
     278  
     279  /* Used like: return __statfs_chown_restricted (__statfs (name, &buf), &buf);*/
     280  long int
     281  __statfs_chown_restricted (int result, const struct statfs *fsbuf)
     282  {
     283    if (result < 0)
     284      {
     285        if (errno == ENOSYS)
     286  	/* Not possible, return the default value.  */
     287  	return 1;
     288  
     289        /* Some error occurred.  */
     290        return -1;
     291      }
     292  
     293    return 1;
     294  }