Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

stat fs-unabhaengig (xfs, ext3, etc.) S_ISREG und S_ISDIR macros

6 views
Skip to first unread message

Yoshi Rokuko

unread,
Nov 15, 2009, 5:55:27 AM11/15/09
to
Hallo, uebe mich gerade im implementieren von so etwas wie tree, find etc.
(brauche nur einen teil der funktionalitaet).
die dirent struktur wird ja nicht bei allen dateisystemen mit dem typ
DT_REG bzw DT_DIR gefuellt, so sind unter xfs extra stat aufrufe notwendig (?)
hier kann ich dann testen ob es sich um eine regulaere datei, ordner oder
etwas ganz anderes handelt. habe das einmal mit macros und einmal ohne
probiert (auskommentiert) beides entdeckt bei mir die ordner nicht, was
mache ich denn falsch? zudem werden manche ordner, bzw. dateien einfach
uebersprungen (auf xfs).

hier mal der quellcode:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

void dirprint(char *dir, char *name);
void dirread(char *dir);
void regprint(char *name);

void
dirprint(char *dir, char *name) {
char buf[1024];

printf("%s/\n", name);
sprintf(buf, "%s/%s", dir, name);
dirread(buf);
}

void
dirread(char *dir) {
DIR *d;
struct dirent *e;
struct stat st;

d = opendir(dir);
while((e = readdir(d)) != NULL) {
if((strcmp(e->d_name, ".") == 0)
|| (strcmp(e->d_name, "..") == 0))
continue;
switch(e->d_type) {
case DT_REG:
regprint(e->d_name);
break;
case DT_DIR:
dirprint(dir, e->d_name);
break;
case DT_UNKNOWN:
stat(e->d_name, &st);
if(S_ISREG(st.st_mode))
regprint(e->d_name);
if(S_ISDIR(st.st_mode))
dirprint(dir, e->d_name);
/*
switch(st.st_mode & S_IFMT) {
case S_IFREG:
printf("ifreg:");
regprint(e->d_name);
break;
case S_IFDIR:
dirprint(dir, e->d_name);
break;
default:
break;
}
*/
break;
default:
break;
}
}
closedir(d);
}

void
regprint(char *name) {
puts(name);
}

int
main(int argc, char *argv[]) {
dirread(argv[1]);
return 0;
}

ich versuche das gerade so einfach und leicht verstaendlich wie moeglich
zu implementieren fuer jegliche hinweise bin ich dankbar.

gruss yoshi

Erich Fruehstueck

unread,
Nov 15, 2009, 6:22:04 AM11/15/09
to
Am Sun, 15 Nov 2009 10:55:27 +0000 schrieb Yoshi Rokuko:

> Hallo, uebe mich gerade im implementieren von so etwas wie tree, find
> etc. (brauche nur einen teil der funktionalitaet). die dirent struktur
> wird ja nicht bei allen dateisystemen mit dem typ DT_REG bzw DT_DIR
> gefuellt, so sind unter xfs extra stat aufrufe notwendig (?) hier kann
> ich dann testen ob es sich um eine regulaere datei, ordner oder etwas
> ganz anderes handelt. habe das einmal mit macros und einmal ohne
> probiert (auskommentiert) beides entdeckt bei mir die ordner nicht, was
> mache ich denn falsch? zudem werden manche ordner, bzw. dateien einfach
> uebersprungen (auf xfs).

Die Komponente d_name enthält nur den Basisnamen der Datei, nicht den
Pfad. Du must dir also zuvor den Pfad zusammenstellen, ewta mit

snprintf(buf, sizeof buf, "%s/%s", dir, e->d_name);

PS: sprintf kann einen Bufferüberlauf verursachen.

Grüße Erich

--
EFEU 3.2 is released!
Get the open source from http://efeu.cybertec.at.

Martin Freiberg

unread,
Nov 15, 2009, 11:30:34 AM11/15/09
to
Yoshi Rokuko schrieb:

Hi,


> case DT_REG:
> regprint(e->d_name);
> break;
> case DT_DIR:
> dirprint(dir, e->d_name);
> break;
> case DT_UNKNOWN:

> ....
> break;
> default:
> break;

Was machst Du z.B. mit Softlinks, Sockets, Fifo, etc.?

> ... DT_REG bzw DT_DIR gefuellt, so sind unter xfs extra
> stat aufrufe notwendig (?)

Sollte das nicht nach default erfolgen?

DT_UNKNOWN beinhaltet die anderen nicht.

Auszug aus include/linux/fs.h

/*
* File types
*
* NOTE! These match bits 12..15 of stat.st_mode
* (ie "(i_mode >> 12) & 15").
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14

#define OSYNC_METADATA (1<<0)
#define OSYNC_DATA (1<<1)
#define OSYNC_INODE (1<<2)
int generic_osync_inode(struct inode *, struct address_space *, int);


Gru�
Martin

Rainer Weikusat

unread,
Nov 15, 2009, 2:11:04 PM11/15/09
to
Erich Fruehstueck <ef....@aon.at> writes:

[...]

> PS: sprintf kann einen Buffer�berlauf verursachen.

Diese Aussage ist falsch. 'sprintf' ist eine Routine in der
C-Standardbibliothek und kann aus sich heraus gar nichts tun, sondern
jemand kann etwas damit tun: ZB, wie in dem fraglichen Code,
Zeichenketten unbekannter und grundsaetzlich beliebiger Laenge in
einen reservierten Speicherbereich endlicher Groesse zu kopieren. DAS
kann einen sogenannten 'Pufferueberlauf' verursachen, naemlich das
ueberschreiben von 'Speicher-Bytes' die nicht mehr zu dem reservierten
Bereich gehoeren, sondern lediglich mit Adressen korrespondieren, die
'hinter'[*] dem reservierten Bereich liegen.

[*] Man stelle sich zu diesem Zweck eine lange Reihe kleiner
Kisten vor vor der man steht. Die 'Speicheradresse' einer
dieser Kisten entsprich dann der Entfernung (in 'Kisten'
ausgedrueckt), die diese von der ersten Kiste hat.

Yoshi Rokuko

unread,
Nov 16, 2009, 3:53:37 PM11/16/09
to
ich verwende sprintf um mir den pfad zu bauen und sollte da sicherlich
besser snprintf verwenden, aber das ist ja nich das problem welches ich
habe - will sagen wenn ich snprintf verwende bleibt mein problem bestehen.

trotzdem danke fuer den hinweis, gruss yoshi

Rainer Weikusat <rwei...@mssgmbh.com> schrieb:


> Erich Fruehstueck <ef....@aon.at> writes:
>
> [...]
>

>> PS: sprintf kann einen Bufferüberlauf verursachen.

Yoshi Rokuko

unread,
Nov 16, 2009, 4:03:16 PM11/16/09
to
Martin Freiberg <ly...@web.de> schrieb:

> Yoshi Rokuko schrieb:
>
> Hi,
>
>
>> case DT_REG:
>> regprint(e->d_name);
>> break;
>> case DT_DIR:
>> dirprint(dir, e->d_name);
>> break;
>> case DT_UNKNOWN:
> > ....
>> break;
>> default:
>> break;
>
> Was machst Du z.B. mit Softlinks, Sockets, Fifo, etc.?

ich moechte nur normale dateien und ordner betrachten, alles andere
moechte ich ignorieren

>
> > ... DT_REG bzw DT_DIR gefuellt, so sind unter xfs extra
> > stat aufrufe notwendig (?)
>
> Sollte das nicht nach default erfolgen?
>
> DT_UNKNOWN beinhaltet die anderen nicht.

so wie ich das verstanden habe wird d_type auf DT_UNKNOWN gesetzt
wenn z.B. auf einem xfs eine normale datei betrachtet wird.

anders gesagt wird d_type nur auf bestimmten fs (z.B. ext3 und ext4)
sinnvoll besetzt.

ich will mir unter ext3 etc. den extra stat aufruf sparen, das
funktioniert ja auch, was nicht funktioniert ist der stat aufruf selber
(auf xfs in meinem fall).

ich mache also irgendwas mit stat falsch oder xfs kann das auch nicht,
was ich aber nicht glaube.

danke und gruss, yoshi

Erich Fruehstueck

unread,
Nov 16, 2009, 4:22:39 PM11/16/09
to
Am Mon, 16 Nov 2009 20:53:37 +0000 schrieb Yoshi Rokuko:

> ich verwende sprintf um mir den pfad zu bauen und sollte da sicherlich
> besser snprintf verwenden, aber das ist ja nich das problem welches ich
> habe - will sagen wenn ich snprintf verwende bleibt mein problem
> bestehen.

Aber stat() rufst Du ohne zusammengebauten Pfad auf. Und hier liegt das
Problem.

Thomas Rachel

unread,
Nov 17, 2009, 1:29:42 AM11/17/09
to
Yoshi Rokuko schrieb:

> habe das einmal mit macros und einmal ohne
> probiert (auskommentiert) beides entdeckt bei mir die ordner nicht, was
> mache ich denn falsch? zudem werden manche ordner, bzw. dateien einfach
> uebersprungen (auf xfs).

Daß es am fehlerhaften stat-Aufruf liegt, weißt Du ja nun.

Ich würde so vorgehen:

[snip]

> void
> dirread(char *dir) {
> DIR *d;
> struct dirent *e;
> struct stat st;
>
> d = opendir(dir);
> while((e = readdir(d)) != NULL) {

unsigned char my_dt = e->d_type;

> if((strcmp(e->d_name, ".") == 0)
> || (strcmp(e->d_name, "..") == 0))
> continue;

if (my_dt == DT_UNKNOWN) {
// hier liegt, wie gesagt, Dein Problem:
char buf[100000]; // oder so ;-)
snprintf(buf,sizeof buf, "%s/%s",
dir, name); // hier...
stat(buf, &st);
// ...und hier fehlt noch Fehlerprüfung
// dann wäre auch klar geworden, was
// falsch ist
if(S_ISREG(st.st_mode)) {
my_dt = DT_REG;
} else if if(S_ISDIR(st.st_mode)) {
my_dt = DT_DIR;
}
}
switch(my_dt) {


> case DT_REG:
> regprint(e->d_name);
> break;
> case DT_DIR:
> dirprint(dir, e->d_name);
> break;
> }
> }

> closedir(d);
> }

HTH,

Thomas

Yoshi Rokuko

unread,
Nov 17, 2009, 10:22:47 AM11/17/09
to
ok jetzt hab ichs, danke fuer die hilfe an alle!
(irgendwie habe ich wohl geglaubt, dass wenn ich einen ordner oeffne
und den inhalt betrachte, das ich dann "in" diesem ordner bin - naja ...

danke und gruss, yoshi

Thomas Rachel <nutznetz-drei-...@spamschutz.glglgl.net> schrieb:

0 new messages