Для того, чтобы поместить корневой каталог файловой системы, находящейся на диске
/dev/hd1, вместо каталога /mnt/hd1 уже "собранной" файловой системы, мы должны издать
сисвызов
mount("/dev/hd1", "/mnt/hd1", 0);
Для отключения смонтированной файловой системы мы должны вызвать
umount("/dev/hd1");
(каталог, к которому она смонтирована, уже числится в таблице ядра, поэтому его зада-
вать не надо). При монтировании все содержимое каталога /mnt/hd1 станет недоступным,
зато при обращении к имени /mnt/hd1 мы на самом деле доберемся до (безымянного) кор-
невого каталога на диске /dev/hd1. Такой каталог носит название mount point и может
быть выявлен по тому признаку, что "." и ".." в нем лежат на разных устройствах:
struct stat st1, st2;
stat("/mnt/hd1/.", &st1); stat("/mnt/hd1/..", &st2);
if( st1.st_dev != st2.st_dev) ... ; /*mount point*/
Для st1 поле st_dev означает код устройства /dev/hd1, а для st2 - устройства, содер-
жащего корневую файловую систему. Операции монтирования и отмонтирования файловых
систем доступны только суперпользователю.
И напоследок - сравнение структур I-узла.
на диске в памяти в вызове stat
А. Богатырев, 1992-95 - 252 - Си в UNIX
struct dinode struct inode struct stat
// коды доступа и тип файла
ushort di_mode i_mode st_mode
// число имен файла
short di_nlink i_nlink st_nlink
// номер I-узла
ushort --- i_number st_ino
// идентификатор владельца
ushort di_uid i_uid st_uid
// идентификатор группы владельца
ushort di_gid i_gid st_gid
// размер файла в байтах
off_t di_size i_size st_size
// время создания
time_t di_ctime i_ctime st_ctime
// время последнего изменения (write)
time_t di_mtime i_mtime st_mtime
// время последнего доступа (read/write)
time_t di_atime i_atime st_atime
// устройство, на котором расположен файл
dev_t --- i_dev st_dev
// устройство, к которому приводит спец.файл
dev_t --- i_rdev st_rdev
// адреса блоков
char di_addr[39] i_addr[]
// счетчик ссылок на структуру в ядре
cnt_t i_count
// и кое-что еще
Минусы означают, что данное поле не хранится на диске, а вычисляется ядром. В совре-
менных версиях UNIX могут быть легкие отличия от вышенаписанной таблицы.
6.10.1. Напишите программу pwd, определяющую полное имя текущего рабочего каталога.
#define U42 определяет файловую систему с длинными именами, отсутствие этого флага -
с короткими (14 символов).
А. Богатырев, 1992-95 - 253 - Си в UNIX
/* Команда pwd.
* Текст getwd() взят из исходных текстов библиотеки языка Си.
*/
#include
#include
#include
#include
#include
#define ediag(e,r) (e)
/*
* getwd() возвращает полное имя текущего рабочего каталога.
* При ошибке возвращается NULL, а в pathname копируется сообщение
* об ошибке.
*/
#ifndef MAXPATHLEN
#define MAXPATHLEN 128
#endif
#define CURDIR "." /* имя текущего каталога */
#define PARENTDIR ".." /* имя родительского каталога */
#define PATHSEP "/" /* разделитель компонент пути */
#define ROOTDIR "/" /* корневой каталог */
#define GETWDERR(s) strcpy(pathname, (s));
#define CP(to,from) strncpy(to,from.d_name,DIRSIZ),to[DIRSIZ]='\0'
char *strcpy(char *, char *); char *strncpy(char *, char *, int);
char *getwd(char *pathname);
static char *prepend(char *dirname, char *pathname);
static int pathsize; /* длина имени */
#ifndef U42
char *getwd(char *pathname)
{
char pathbuf[MAXPATHLEN]; /* temporary pathname buffer */
char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
dev_t rdev; /* root device number */
int fil = (-1); /* directory file descriptor */
ino_t rino; /* root inode number */
struct direct dir; /* directory entry struct */
struct stat d ,dd; /* file status struct */
/* d - "." dd - ".." | dname */
char dname[DIRSIZ+1]; /* an directory entry */
pathsize = 0;
*pnptr = '\0';
if (stat(ROOTDIR, &d) < 0) {
GETWDERR(ediag("getwd: can't stat /",
"getwd: нельзя выполнить stat /"));
return (NULL);
}
rdev = d.st_dev; /* код устройства, на котором размещен корень */
rino = d.st_ino; /* номер I-узла, представляющего корневой каталог */
А. Богатырев, 1992-95 - 254 - Си в UNIX
for (;;) {
if (stat(CURDIR, &d) < 0) {
CantStat:
GETWDERR(ediag("getwd: can't stat .",
"getwd: нельзя выполнить stat ."));
goto fail;
}
if (d.st_ino == rino && d.st_dev == rdev)
break; /* достигли корневого каталога */
if ((fil = open(PARENTDIR, O_RDONLY)) < 0) {
GETWDERR(ediag("getwd: can't open ..",
"getwd: нельзя открыть .."));
goto fail;
}
if (chdir(PARENTDIR) < 0) {
GETWDERR(ediag("getwd: can't chdir to ..",
"getwd: нельзя перейти в .."));
goto fail;
}
if (fstat(fil, &dd) < 0)
goto CantStat;
if (d.st_dev == dd.st_dev) { /* то же устройство */
if (d.st_ino == dd.st_ino) {
/* достигли корня ".." == "." */
close(fil); break;
}
do {
if (read(fil, (char *) &dir,
sizeof(dir)) < sizeof(dir)
){
ReadErr:
close(fil);
GETWDERR(ediag("getwd: read error in ..",
"getwd: ошибка чтения .."));
goto fail;
}
} while (dir.d_ino != d.st_ino);
CP(dname,dir);
} else /* ".." находится на другом диске: mount point */
do {
if (read(fil, (char *) &dir,
sizeof(dir)) < sizeof(dir))
goto ReadErr;
if( dir.d_ino == 0 ) /* файл стерт */
continue;
CP(dname,dir);
if (stat(dname, &dd) < 0) {
sprintf (pathname, "getwd: %s %s",
ediag ("can't stat",
"нельзя выполнить stat"), dname);
goto fail;
}
} while(dd.st_ino != d.st_ino ||
dd.st_dev != d.st_dev);
close(fil);
pnptr = prepend(PATHSEP, prepend(dname, pnptr));
}
А. Богатырев, 1992-95 - 255 - Си в UNIX
if (*pnptr == '\0') /* текущий каталог == корневому */
strcpy(pathname, ROOTDIR);
else {
strcpy(pathname, pnptr);
if (chdir(pnptr) < 0) {
GETWDERR(ediag("getwd: can't change back to .",
"getwd: нельзя вернуться в ."));
return (NULL);
}
}
return (pathname);
fail:
close(fil);
chdir(prepend(CURDIR, pnptr));
return (NULL);
}
#else /* U42 */
extern char *strcpy ();
extern DIR *opendir();
char *getwd (char *pathname)
{
char pathbuf[MAXPATHLEN];/* temporary pathname buffer */
char *pnptr = &pathbuf[(sizeof pathbuf) - 1];/* pathname pointer */
char *prepend (); /* prepend dirname to pathname */
dev_t rdev; /* root device number */
DIR * dirp; /* directory stream */
ino_t rino; /* root inode number */
struct dirent *dir; /* directory entry struct */
struct stat d,
dd; /* file status struct */
pathsize = 0;
*pnptr = '\0';
stat (ROOTDIR, &d);
rdev = d.st_dev;
rino = d.st_ino;
for (;;) {
stat (CURDIR, &d);
if (d.st_ino == rino && d.st_dev == rdev)
break; /* reached root directory */
if ((dirp = opendir (PARENTDIR)) == NULL) {
GETWDERR ("getwd: can't open ..");
goto fail;
}
if (chdir (PARENTDIR) < 0) {
closedir (dirp);
GETWDERR ("getwd: can't chdir to ..");
goto fail;
}
А. Богатырев, 1992-95 - 256 - Си в UNIX
fstat (dirp -> dd_fd, &dd);
if (d.st_dev == dd.st_dev) {
if (d.st_ino == dd.st_ino) {
/* reached root directory */
closedir (dirp);
break;
}
do {
if ((dir = readdir (dirp)) == NULL) {
closedir (dirp);
GETWDERR ("getwd: read error in ..");
goto fail;
}
} while (dir -> d_ino != d.st_ino);
}
else
do {
if ((dir = readdir (dirp)) == NULL) {
closedir (dirp);
GETWDERR ("getwd: read error in ..");
goto fail;
}
stat (dir -> d_name, &dd);
} while (dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
closedir (dirp);
pnptr = prepend (PATHSEP, prepend (dir -> d_name, pnptr));
}
if (*pnptr == '\0') /* current dir == root dir */