Главная1-й курс3-й курс4-й курс5-й курсСпецкурсыСсылкиКарта(версия для печати)

Чтение атрибутов файлов в ОС Unix

А. А. Вылиток

Функции stat, lstat и fstat возвращают атрибуты заданного файла:

#include <sys/types.h>
#include <sys/stat.h>
stat  ( char *path, struct stat *buf )
lstat ( char *path, struct stat *buf ) // не преобразует символич.ссылки
fstat ( int fd, struct stat *buf )     // возвращают 0 или -1
 

Усеченное описание структуры «stat» (полное см. в «sys/stat.h») выглядит следующим образом:

struct stat 
{
   dev_t    st_dev;     // идентификатор файловой системы
   ino_t    st_ino;     // номер индексного дескриптора файла
   u_short  st_mode;    // содержит тип файла и флаги доступа
   short    st_nlink;   // значение счетчика жестких связей
   uid_t    st_uid;     // идентификатор владельца файла
   gid_t    st_gid;     // идентификатор группы
   dev_t    st_rdev;    // содержит старший и младший номера устройства
   off_t    st_size;    // размер файла в байтах
   time_t   st_atime;   // время последнего доступа
   time_t   st_mtime;   // время последней модификации
   time_t   st_ctime;   // время последнего изменения индексного дескриптора
};
 

Следующие макросы служат для работы с флагами поля «st_mode»:

#define S_IFMT    0170000 // позволяет “вырезать” тип файла
#define S_IFDIR   0040000 // каталог
#define S_IFCHR   0020000 // байт-ориентированный
#define S_IFBLK   0060000 // блок-ориентированный
#define S_IFREG   0100000 // обычный
#define S_IFLNK   0120000 // символическая ссылка
#define S_IFSOCK  0140000 // сокет
#define S_ISUID   0004000 // установка идентификатора пользователя при выполнении (изменяется eUID процесса)
#define S_ISGID   0002000 // установка идентификатора группы при выполнении (изменяется eGID процесса)
#define S_ISVTX   0001000 // для обычного файла - сохранить текст программы (машинный код) в ОП после завершения процесса; 
/* для каталога – запретить обычному пользователю, не являющемуся владельцем данного каталога, удалять или переименовывать в нем чужие файлы */
 

Функция «getpwuid» позволяет преобразовать идентификатор пользователя в его имя

#include <pwd.h>
 
struct passwd *getpwuid ( int uid )
 

Структура passwd описана следующим образом (полное описание в «pwd.h»):

struct passwd
{
    char *pw_name;    // имя пользователя
    char *pw_passwd;  // пароль
    int   pw_uid;     // идентификатор пользователя
    int   pw_gid;     // идентификатор группы
    char *pw_dir;     // домашний каталог пользователя
    char *pw_shell;   // shell запускаемый после регистрации (по умолчанию "/bin/sh")
};
 

Программа эмуляции команды «ls –l file1 file2 ... fileN»:

#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <stdio.h>
 
#ifndef  MAJOR
  #define MINOR_BITS
  #define MAJOR(dev) ((unsigned) dev >> MINOR_BITS)
  #define MINOR(dev) (dev & MINOR_BITS)
#endif
 
// показать тип файла в первой позиции выходной строки 
void display_file_type ( int st_mode ) 
{                                   
    switch ( st_mode & S_IFMT )
    {
        case S_IFDIR:  putchar ( 'd' ); return;
        case S_IFCHR:  putchar ( 'c' ); return;
        case S_IFBLK:  putchar ( 'b' ); return;
        case S_IFREG:  putchar ( '-' ); return;
        case S_IFLNK:  putchar ( 'l' ); return;
        case S_IFSOCK: putchar ( 's' ); return;
    }
} 
 
// показать права доступа для владельца, группы и прочих пользователей, а также все спец.флаги 
void display_permission ( int st_mode )
{
  static const char xtbl[10] = "rwxrwxrwx";
  char     amode[10];
  int      i, j;
 
  for ( i = 0, j = ( 1 << 8 ); i < 9; i++, j >>= 1 )
    amode[i] = ( st_mode&j ) ? xtbl[i]: '-';
  if ( st_mode & S_ISUID )   amode[2]= 's';
  if ( st_mode & S_ISGID )   amode[5]= 's';
  if ( st_mode & S_ISVTX )   amode[8]= 't';
  amode[9]='\0';
  printf ( "%s ",amode );
}
 
// перечислить атрибуты одного файла
void long_list ( char * path_name )
{
  struct stat     statv;
  struct passwd  *pw_d;
 
  if ( lstat ( path_name, &statv ) )
  { 
    perror ( path_name ); 
    return;
  }
  display_file_type ( statv.st_mode );
  display_permission ( statv.st_mode );
  printf ( "%d ",statv.st_nlink );  // значение счетчика жестких связей
  pw_d = getpwuid ( statv.st_uid ); // преобразовать UID в имя пользователя
  printf ( "%s ",pw_d->pw_name );   // и напечатать его
 
  if (
      ( statv.st_mode & S_IFMT) == S_IFCHR  ||
      ( statv.st_mode & S_IFMT) == S_IFBLK
     )
    // показать старший и младший номера устройства
    printf ( "%d, %d",MAJOR(statv.st_rdev), MINOR(statv.st_rdev) );
  else
    // или размер файла
    printf ( "%d", statv.st_size );
  //  показать имя файла
  printf ( "     %s\n", path_name );
}
 
// главный цикл отображения атрибутов для каждого файла
int main ( int argc, char * argv[] )
{
  if ( argc == 1 )
    fprintf ( stderr, "usage: %s <path name> ...\n", argv[0] );
  else
    while ( argc-- != 1 ) 
      long_list ( *++argv );
  return 0;
}