Académique Documents
Professionnel Documents
Culture Documents
1 Introdu tion. 1
3 Mise en ÷uvre. 3
4 Implémentation. 3
4.1 C÷ur du module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.2 Fon
tion fn_lstat(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.3 Fon
tion fn_readlink(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.4 Fon
tion pr_get
wd(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.5 Fon
tion pr_readpath(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.6 Fon
tion vn_dirgetabsolutename(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.7 Fon
tion vn_dirgetname(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.8 Fon
tion vn_dirgetparent(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
6 Programme de test. 33
6.1 Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.2 Manipulation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1 Introdu tion.
L'obje
tif de
e développement est de fournir plusieurs fon
tions noyau relatives aux
hiers. Elles
se manipulent par l'intermédiaire de trois
atégories d'objets :
Les noms de
hiers : les fon
tions manipulées par l'intermédiaire de
ette
atégorie sont préxées
par fn_ (`le name').
Les pro
essus : les fon
tions manipulées par l'intermédiaire de
ette
atégorie sont préxées par
pr_ (`pro
ess').
Les vnode : les fon
tions manipulées par l'intermédiaire de
ette
atégorie sont préxées par
vn_ (`vnode').
int fn_lstat( onst har *path, stru t stat *sbp, stru t pro *p)
3 Mise en ÷uvre.
4 Implémentation.
Le
÷ur du module (paramètres, point d'entrée) ainsi que l'appel système de test sont
odés dans
le
hier module.
.
Code 1. Makefile.
/* Prototypes. */
int sys_test(stru
t pro
*p, void *v, int *retval);
/* Module initialisation. */
MOD_SYSCALL("fileutilities", -1, &sys_test_ent);
/* Module entry. */
int
fileutilities_lkmentry(lkmtp,
md, ver)
stru
t lkm_table *lkmtp;
int
md;
int ver;
{
DISPATCH(lkmtp,
md, ver, lkm_nofun
, lkm_nofun
, lkm_nofun
)
}
/*
* Insert verti
al spa
e whithin the logs.
*/
printf("\n");
/*
* Announ
ement.
*/
printf("[%s℄ 'sys_test()' has been
alled by pro
ess %d.\n",
__FUNCTION__, p->p_pid);
/*
* 'vn_dirgetparent()'.
*/
if ((error = vn_dirgetparent_test(p))) {
printf("[%s℄ Error
ode %d o
ured while
alling "
"'vn_dirgetparent_test()'.\n", __FUNCTION__, error);
}
/*
* 'vn_dirgetname()'.
*/
if ((error = vn_dirgetname_test(p))) {
printf("[%s℄ Error
ode %d o
ured while
alling "
"'vn_dirgetname_test()'.\n", __FUNCTION__, error);
}
/*
* 'vn_dirgetabsolutename()'.
*/
if ((error = vn_dirgetabsolutename_test(p))) {
printf("[%s℄ Error
ode %d o
ured while
alling "
"'vn_dirgetabsolutename_test()'.\n", __FUNCTION__, error);
}
/*
* 'pget
wd()'.
*/
if ((error = pr_get
wd_test(p))) {
printf("[%s℄ Error
ode %d o
ured while
alling "
"'pget
wd_test()'.\n", __FUNCTION__, error);
}
/*
* 'prealpath()'.
*/
if ((error = pr_realpath_test(p, SCARG(uap, path)))) {
printf("[%s℄ Error
ode %d o
ured while
alling "
"'prealpath_test()'.\n", __FUNCTION__, error);
}
/*
* Insert verti
al spa
e whithin the logs.
*/
printf("\n");
return (0);
}
Code 2. fn_lstat. .
/*
* A
t like the 'lstat()'(2) system
all.
* The 'fn_lstat()' fun
tion obtains information about the file pointed to by
* 'path'.
* Read, write or exe
ute permission of the named file is not required, but all
* dire
tories listed in the path name leading to the file must be sear
hable.
* If the file is a symboli
link, then it returns information about the link
* itself, not the file the link referen
es. Unlinke other file system obje
ts,
* symboli
link do not have an owner, group, a
ess mode, times, .... Instead,
* these attributes are taken from the dire
tory that
ontains the link. The
* only attributes returned from an 'fn_lstat()' that refer to the symboli
* link itself are the file type ('S_IFLNK'), size, blo
ks and link
ount
* (always 1).
* The information is supposed to be sear
hed by the pro
ess 'p'.
*/
int
fn_lstat(path, sbp, p)
onst
har *path;
stru
t stat *sbp;
stru
t pro
*p;
{
int error = 0;
stru
t nameidata nd;
return (error);
if (suser(p, 0))
/* Don't let non-root see generation numbers (for NFS se
urity).
*/
sbp->st_gen = 0;
return (error);
}
Code 3. fn_lstat.h.
#ifndef _FN_LSTAT_H_
#define _FN_LSTAT_H_
int fn_lstat( onst har *path, stru t stat *sb, stru t pro *p);
#endif /* !_FN_LSTAT_H_ */
Code 4. fn_readlink. .
/*
* A
t like the 'readlink()'(2) system
all.
* Pla
es the
ontents of the symboli
link 'path' in the buffer 'buf', whi
h
* has size 'size'. Does not append a nul
hara
ter to 'buf', but returns via
* '*
ountp' the
ount of
hara
ters pla
ed in the buffer if it su
eeds.
*/
int
fn_readlink(path, buf, size,
ountp, p)
Code 5. fn_readlink.h.
#ifndef _FN_READLINK_H_
#define _FN_READLINK_H_
int fn_readlink(
onst
har *path,
har *buf, size_t size, size_t *
ountp,
stru
t pro
*p);
#endif /* !_FN_READLINK_H_ */
/*
* Announ
ement.
*/
printf("[%s℄ 'pr_get
wd_test()' has been
alled by pro
ess %d.\n",
__FUNCTION__, p->p_pid);
/*
* Allo
ate 'area' and initialize 'path'.
*/
#define AREALEN PATH_MAX
area = (
har *)mallo
(AREALEN, M_TEMP, M_WAITOK);
path = &area[AREALEN℄;
#undef AREALEN
/*
* Get
urrent working dire
tory.
*/
if ((error = pr_get
wd1(p, &path, area))) {
printf("[%s℄ Calling 'pr_get
wd1()' has failed, with error
ode"
" %d.\n", __FUNCTION__, error);
goto out;
}
/*
* Finalize.
*/
out:
if (area)
free(area, M_TEMP);
return (error);
}
#endif /* BESSSI_DBGLVL > 0 */
/*
* A
t like the fun
tion 'get
wd()'(3). First
all syntax.
* Copies the absolute pathname of the
urrent working dire
tory into 'area'.
* On entry:
* - 'area' points to the beginning of the area whi
h will
ontain the name;
* - '*pathp' points to the byte lo
ated after the end of the area whi
h will
*
ontain the name; that is to say that '*pathp' equals to '&area[len℄',
* where 'len' is the length of the area.
* On exit:
* - '*pathp' is moved ba
kwards to point at the start of the name.
*/
int
pr_get
wd1(p, pathp, area)
stru
t pro
*p;
har **pathp;
har *area;
{
stru
t vnode *wdvp;
int error = 0;
/*
* Get, referen
e and lo
k
urrent working dire
tory VNODE.
*/
wdvp = p->p_fd->fd_
dir; /* Get the
urrent working dire
tory. */
VREF(wdvp);
if ((error = vn_lo
k(wdvp, LK_EXCLUSIVE | LK_RETRY, p))) {
vrele(wdvp);
goto out;
}
/*
* Get dire
tory absolute name.
*/
error = vn_dirgetabsolutename(wdvp, pathp, area, 0, p);
/* Here, 'wdvp' is released and unlo
ked. */
if (error)
goto out;
out:
return (error);
}
/*
* A
t like the fun
tion 'get
wd()'(3). Se
ond
all syntax.
* Copies the absolute pathname of the
urrent working dire
tory into the
* memory referen
ed by 'buf'. The 'size' argument is the size, in bytes, of
* the array referen
ed by 'buf'.
*/
int
pr_get
wd2(p, buf, size)
stru
t pro
*p;
har *buf;
size_t size;
{
har *area = NULL;
har *path;
int error = 0;
/*
* Che
k the size.
*/
if (size < 1)
return (ERANGE);
/*
* Allo
ate 'area' and initialize 'path'.
*/
area = (
har *)mallo
(size, M_TEMP, M_WAITOK);
path = &area[size℄;
/*
* Get
urrent working dire
tory.
*/
if ((error = pr_get
wd1(p, &path, area)))
goto out;
/*
* Copy the path.
*/
if (strl
py(buf, path, size) >= size) {
error = ENAMETOOLONG;
goto out;
}
/*
* Finalize.
*/
out:
if (area)
free(area, M_TEMP);
return (error);
}
Ces fon tions sont exportées à travers le hier d'en-tête pr_get wd.h.
#ifndef _PR_GETCWD_H_
#define _PR_GETCWD_H_
#endif /* !_PR_GETCWD_H_ */
Code 8. pr_readpath. .
/*
* Announ
ement.
*/
printf("[%s℄ 'prealpath_test()' has been
alled by pro
ess %d.\n",
__FUNCTION__, p->p_pid);
/*
* Test.
*/
/*
* Finalize.
*/
out:
return (error);
}
#endif
/*
* A
t like fun
tion 'realpath()'(3).
* Find the real name of path, by removing all '.', '..' and symlink
*
omponents.
*/
int
pr_realpath(p, pathname, resolved)
stru
t pro
*p;
onst
har *pathname;
har resolved[PATH_MAX℄;
{
int error = 0;
size_t resolved_len, left_len;
har left[PATH_MAX℄;
/*
* Initialization.
*/
if (pathname[0℄ == '/') {
resolved[0℄ = '/';
resolved[1℄ = '\0';
if (pathname[1℄ == '\0')
return (0);
resolved_len = 1;
left_len = strl
py(left, pathname + 1, sizeof(left));
} else {
if ((error = pr_get
wd2(p, resolved, PATH_MAX))) {
strl
py(resolved, ".", PATH_MAX);
goto out;
}
resolved_len = strlen(resolved);
left_len = strl
py(left, pathname, sizeof(left));
}
if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
error = ENAMETOOLONG;
goto out;
}
/*
* Iterate over path
omponents in 'left'.
*/
while (left_len != 0) {
har *r, *s;
har next_token[PATH_MAX℄;
stru
t stat sb;
/*
* Extra
t the next path
omponent and adjust 'left' and its
* length.
*/
r = str
hr(left, '/');
s = r ? r : left + left_len;
if (s - left >= sizeof(next_token)) {
error = ENAMETOOLONG;
goto out;
}
/* 's' now points to the
hara
ter following the next token. */
mem
py(next_token, left, s - left);
next_token[s - left℄ = '\0';
/* 'next_token'
ontains now the next token ('path
omponent').
*/
left_len -= s - left;
if (r != NULL)
mem
py(left, s + 1, left_len + 1);
/* 'left' and its length are now adjusted. */
/*
* Append '/' to the end of 'resolved'.
*/
if (resolved[resolved_len - 1℄ != '/') {
if (resolved_len + 1 >= PATH_MAX) {
error = ENAMETOOLONG;
goto out;
}
resolved[resolved_len++℄ = '/';
resolved[resolved_len℄ = '\0';
}
/*
* Deal with spe
ial tokens.
*/
if (next_token[0℄ == '\0')
ontinue;
else if (str
mp(next_token, ".") == 0)
ontinue;
else if (str
mp(next_token, "..") == 0) {
/*
* Strip the last path
omponent ex
ept when we have
* single '/'.
*/
if (resolved_len > 1) {
har *q;
resolved[resolved_len - 1℄ = '\0';
q = strr
hr(resolved, '/') + 1;
*q = '\0';
resolved_len = q - resolved;
}
ontinue;
}
/*
* Append the next path
omponent and 'lstat()' it. If
* 'lstat()' fails we still
an return su
essfully if
* there are no more path
omponents left.
*/
resolved_len = strl
at(resolved, next_token, PATH_MAX);
if (resolved_len >= PATH_MAX) {
error = ENAMETOOLONG;
goto out;
}
/*
* Analyse the resolved path through 'lstat'.
*/
if ((error = fn_lstat(resolved, &sb, p))) {
if (error == ENOENT && r == NULL) {
/* If 'lstat' fails, we still
an return
su
essfuly if there are no more path
omponents left. */
error = 0;
goto out;
}
goto out;
}
if (S_ISLNK(sb.st_mode)) {
har symlink[PATH_MAX℄;
stati
unsigned int symlinks = 0;
size_t slen;
/*
* Che
k if we are in a loop.
*/
if (symlinks++ > MAXSYMLINKS) {
error = ELOOP;
goto out;
}
/*
* Read the link.
*/
if ((error = fn_readlink(resolved, symlink,
sizeof(symlink) - 1, &slen, p))) {
goto out;
}
symlink[slen℄ = '\0';
/*
* Strip the resolved path.
*/
if (symlink[0℄ == '/') {
/*
* Keep only the '/' lo
ated at the first pla
e
* in 'resolved'.
*/
resolved[1℄ = 0;
resolved_len = 1;
} else if (resolved_len > 1) {
har *q;
/*
* Strip the last path
omponent.
*/
resolved[resolved_len - 1℄ = '\0';
q = strr
hr(resolved, '/') + 1;
*q = '\0';
resolved_len = q - resolved;
}
/*
* If there are any path
omponents left, then
* append them to symlink. The result is pla
ed
* in 'left'.
*/
if (r != NULL) {
if (symlink[slen - 1℄ != '/') {
if (slen + 1 >= sizeof(symlink)) {
error = ENAMETOOLONG;
goto out;
}
symlink[slen℄ = '/';
symlink[slen + 1℄ = 0;
}
left_len = strl
at(symlink, left, sizeof(left));
if (left_len >= sizeof(left)) {
error = ENAMETOOLONG;
goto out;
}
}
left_len = strl
py(left, symlink, sizeof(left));
}
}
/*
* Remove trailing slash ex
ept when the resolved pathname is a single
* '/'.
*/
if (resolved_len > 1 && resolved[resolved_len - 1℄ == '/')
resolved[resolved_len - 1℄ = '\0';
out:
return (error);
}
Code 9. pr_readpath.h.
#ifndef _PR_REALPATH_H_
#define _PR_REALPATH_H_
#endif /* !_PR_REALPATH_H_ */
/*
* Announ
ement.
*/
printf("[%s℄ 'vn_dirgetabsolutename_test()' has been
alled by pro
ess "
"%d.\n", __FUNCTION__, p->p_pid);
/*
* Get, referen
e and lo
k
urrent working dire
tory VNODE.
*/
wdvp = p->p_fd->fd_
dir; /* Get the
urrent working dire
tory. */
VREF(wdvp);
if ((error = vn_lo
k(wdvp, LK_EXCLUSIVE | LK_RETRY, p))) {
printf("[%s℄ Calling 'vn_lo
k()' has failed, with error
ode "
"%d.\n", __FUNCTION__, error);
vrele(wdvp);
return (error);
}
/*
* Allo
ate 'area' and initialize 'path'.
*/
#define AREALEN PATH_MAX
area = (
har *)mallo
(AREALEN, M_TEMP, M_WAITOK);
path = &area[AREALEN℄;
#undef AREALEN
/*
* Get dire
tory absolute name.
*/
if ((error = vn_dirgetabsolutename(wdvp, &path, area, 0, p))) {
printf("[%s℄ Calling 'vn_dirgetabsolutename()' has failed, with"
" error
ode %d.\n", __FUNCTION__, error);
goto out;
}
printf("[%s℄ Dire
tory absolute name: '%s'.\n", __FUNCTION__, path);
/*
* Finalize.
*/
out:
if (area)
free(area, M_TEMP);
return (error);
}
#endif /* BESSSI_DBGLVL > 0 */
/*
* Get dire
tory absolute name.
* On entry:
* - 'lvp' must be referen
ed and lo
ked.
* - 'bufp' points to the beginning of the area whi
h will
ontain the name;
* - '*bpp' points to the byte lo
ated after the end of the area whi
h will
*
ontain the name; that is to say that '*bpp' equals to '&bufp[len℄', where
/*
* Che
k whether there is enough spa
e in the buffer.
*/
if (bp - bufp < 2) {
vput(lvp);
error = ERANGE;
goto out;
}
/*
* Insert the terminating null
hara
ter.
*/
*(--bp) = '\0';
/*
* Initialize 'rvp'.
*/
rvp = fdp->fd_rdir;
if (rvp == NULL)
rvp = rootvnode;
VREF(rvp);
if ((error = vn_lo
k(rvp, LK_EXCLUSIVE | LK_RETRY, p))) {
vrele(rvp);
rvp = NULL;
goto out;
}
/*
* This loop will terminate when one of the following happens:
* - we hit the root;
* - getting dire
tory entries or lookup fails;
* - we got 'limit' names;
* - we run out of spa
e in the buffer.
*/
if (lvp == rvp) {
/* We already hit the root. */
if (bp)
*(--bp) = '/';
goto out;
}
do {
stru
t vnode *pvp = NULL;
if (lvp->v_type != VDIR) {
/* Current VNODE is not a dire
tory. */
error = ENOTDIR;
goto out;
}
/*
* Get parent VNODE.
*/
error = vn_dirgetparent(&lvp, &pvp, p);
/* If different from 'NULL', 'lvp' is here referen
ed, but not
lo
ked. */
if (error) {
if (lvp) {
vrele(lvp);
lvp = NULL;
}
if (pvp)
vput(pvp);
goto out;
}
if (lvp == NULL)
/* We hit the root. */
goto slashinsert;
/*
* Get name.
*/
if ((error = vn_lo
k(lvp, LK_EXCLUSIVE | LK_RETRY, p))) {
vrele(lvp);
lvp = NULL;
if (pvp)
vput(pvp);
goto out;
}
if ((error = vn_dirgetname(lvp, pvp, &bp, bufp, 0, p))) {
vput(pvp);
goto out;
}
/*
* Insert '/'.
*/
slashinsert:
/*
* Prepare next o
urren
e.
*/
lvp = pvp;
pvp = NULL;
limit--;
} while ((lvp != rvp) && (lvp != NULL) && (limit != 0));
out:
*bpp = bp;
if (rvp)
vput(rvp);
if (lvp)
vput(lvp);
return (error);
}
#ifndef _VN_DIRGETABSOLUTENAME_H_
#define _VN_DIRGETABSOLUTENAME_H_
int vn_dirgetabsolutename(stru
t vnode *lvp,
har **bpp,
har *bufp, int limit,
stru
t pro
*p);
#if BESSSI_DBGLVL > 0
int vn_dirgetabsolutename_test(stru
t pro
*p);
#endif
#endif /* !_VN_DIRGETABSOLUTENAME_H_ */
/*
* Announ
ement.
*/
printf("[%s℄ 'vn_dirgetname_test()' has been
alled by pro
ess %d.\n",
__FUNCTION__, p->p_pid);
/*
* Get, referen
e and lo
k
urrent working dire
tory VNODE.
*/
wdvp = p->p_fd->fd_
dir; /* Get the
urrent working dire
tory. */
VREF(wdvp);
if ((error = vn_lo
k(wdvp, LK_EXCLUSIVE | LK_RETRY, p))) {
printf("[%s℄ Calling 'vn_lo
k()' has failed, with error
ode "
"%d.\n", __FUNCTION__, error);
vrele(wdvp);
return (error);
}
/*
* Allo
ate 'area' and initialize 'name'.
*/
#define AREALEN NAME_MAX
area = (
har *)mallo
(AREALEN, M_TEMP, M_WAITOK);
name = &area[AREALEN℄;
#undef AREALEN
/*
* Get dire
tory name.
*/
if ((error = vn_dirgetname(wdvp, NULL, &name, area, 1, p))) {
printf("[%s℄ Calling 'vn_dirgetname()' has failed, with error "
"
ode %d.\n", __FUNCTION__, error);
goto out;
}
/* Calling 'vn_dirgetname()' has made 'wdvp' unlo
ked and released. */
printf("[%s℄ Dire
tory name: '%s'.\n", __FUNCTION__, name);
/*
* Finalize.
*/
out:
if (area)
free(area, M_TEMP);
return (error);
}
#endif /* BESSSI_DBGLVL > 0 */
/*
* Get dire
tory name.
* On entry:
* - 'lvp' is the dire
tory VNODE of whi
h we must determine the name;
* - 'lvp' must be referen
ed and lo
ked;
* - 'uvp' is the parent VNODE of 'lvp'; 'uvp' may be set to 'NULL' (then,
* the parent VNODE will be determined by using 'vn_dirgetparent()');
* - if 'uvp' is not set to 'NULL', then it must be referen
ed and lo
ked;
* - 'bufp' points to the beginning of the area whi
h will
ontain the name;
* - '*bpp' points to the byte lo
ated after the end of the area whi
h will
*
ontain the name; that is to say that '*bpp' equals to '&bufp[len℄', where
* 'len' is the length of the area.
* - 'itn' ('insert terminating null') determine whether a terminating null
*
hara
ter has to be inserted.
* On exit:
* - 'lvp' is unlo
ked and released;
* - if 'uvp' was not set to 'NULL' on entry, then it is kept lo
ked; if it was
* set to 'NULL' on entry, then the parent VNODE found inside the treatment
* of this fun
tion is unlo
ked and released;
* - '*bpp' is moved ba
kwards to point at the start of the name.
*/
int
vn_dirgetname(lvp, uvp, bpp, bufp, itn, p)
stru
t vnode *lvp;
stru
t vnode *uvp;
har **bpp;
har *bufp;
int itn;
stru
t pro
*p;
{
int error = 0;
stru
t vattr va; /* Information relative to 'lvp'. */
stru
t vnode *pvp = uvp; /* Parent VNODE. */
ino_t fileno;
har *dirbuf = NULL;
int dirbuflen;
off_t off;
int eofflag;
int tries = 0;
/*
* Che
k whether there is enough spa
e in the buffer.
*/
if (*bpp - bufp < 2) {
vput(lvp);
error = ERANGE;
goto out;
}
/*
* Che
k if 'lvp' is a dire
tory.
*/
if (lvp->v_type != VDIR) {
/* 'lvp' is not a dire
tory. */
vput(lvp);
error = ENOTDIR;
goto out;
}
/*
* Get some information we need while the
urrent dire
tory is still
* lo
ked.
*/
if ((error = VOP_GETATTR(lvp, &va, p->p_u
red, p))) {
vput(lvp);
goto out;
}
/*
* Get the file identifier.
*/
fileno = va.va_fileid;
/*
* Determine the parent VNODE.
*/
if (!pvp) {
error = vn_dirgetparent(&lvp, &pvp, p);
if (lvp)
vrele(lvp);
} else
vput(lvp);
/* At this point, 'lvp' is unlo
ked and released, and 'pvp' is lo
ked
and
ontains the parent VNODE. */
if (error)
goto out;
/*
* Allo
ate the dire
tory buffer.
*/
dirbuflen = DIRBLKSIZ;
if (dirbuflen < va.va_blo
ksize)
dirbuflen = va.va_blo
ksize;
dirbuf = (
har *)mallo
(dirbuflen, M_TEMP, M_WAITOK);
/*
* Sear
h in the parent dire
tory's entries.
*/
off = 0;
tries = 0;
do {
har *
pos;
stru
t dirent *dp;
stru
t iove
iov;
stru
t uio uio;
int len, re
len;
/*
* Call 'VOP_READDIR()' from parent.
*/
iov.iov_base = dirbuf;
iov.iov_len = dirbuflen;
uio.uio_iov = &iov;
uio.uio_iov
nt = 1;
uio.uio_offset = off;
uio.uio_resid = dirbuflen;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_rw = UIO_READ;
uio.uio_pro
p = p;
eofflag = 0;
error = VOP_READDIR(pvp, &uio, p->p_u
red, &eofflag, 0, 0);
off = uio.uio_offset;
/*
* Try again if NFS tosses its
ookies.
* XXX This
an still loop forever if the dire
tory is busted
* su
h that the se
ond or subsequent page of it always
* returns 'EINVAL'.
*/
if ((error == EINVAL) && (tries < 3)) {
off = 0;
tries++;
ontinue; /* On
e more, with feeling. */
}
if (error)
goto out;
pos = dirbuf;
tries = 0;
/*
* S
an dire
tory page looking for mat
hing VNODE.
*/
for (len = (dirbuflen - uio.uio_resid); len > 0; len -= re
len,
pos += re
len) {
dp = (stru
t dirent *)
pos;
re
len = dp->d_re
len;
/*
* Che
k for malformed dire
tory.
*/
#define DIRENT_MINSIZE (sizeof(stru
t dirent) - (MAXNAMLEN+1) + 4)
if (re
len < DIRENT_MINSIZE) {
error = EINVAL;
goto out;
}
#undef DIRENT_MINSIZE
if (dp->d_fileno == fileno) {
/* The target entry has been found. */
har *bp = *bpp;
/*
* Insert the terminating null
hara
ter.
*/
if (itn) {
*(--bp) = '\0';
/* We have already
he
ked -- at the
beginning of the fun
tion -- if
there was enough spa
e in the
buffer. */
}
/*
* Moves 'bp' so that it
an
ontain the name
* of the entry.
*/
bp -= dp->d_namlen;
if (bp <= bufp) {
error = ERANGE;
goto out;
}
/*
* Copy the name.
*/
b
opy(dp->d_name, bp, dp->d_namlen);
/*
* Finalize.
*/
error = 0;
*bpp = bp;
goto out;
}
}
} while (!eofflag);
/* The target entry has not been found. */
error = ENOENT;
out:
if (dirbuf)
free(dirbuf, M_TEMP);
if (pvp && !uvp)
/* 'pvp' may equal to 'NULL' if 'vn_dirgetparent()' has failed.
'pvp' must not be unlo
ked and released if it was given on
entry. */
vput(pvp);
return (error);
}
#ifndef _VN_DIRGETNAME_H_
#define _VN_DIRGETNAME_H_
int vn_dirgetname(stru
t vnode *lvp, stru
t vnode *uvp,
har **bpp,
har *bufp,
int itn, stru
t pro
*p);
#if BESSSI_DBGLVL > 0
int vn_dirgetname_test(stru
t pro
*p);
#endif
#endif /* !_VN_DIRGETNAME_H_ */
/*
* Announ
ement.
*/
printf("[%s℄ 'vn_dirgetparent_test()' has been
alled by pro
ess %d.\n",
__FUNCTION__, p->p_pid);
/*
* Get, referen
e and lo
k
urrent working dire
tory VNODE.
*/
wdvp = p->p_fd->fd_
dir; /* Get the
urrent working dire
tory. */
VREF(wdvp);
if ((error = vn_lo
k(wdvp, LK_EXCLUSIVE | LK_RETRY, p))) {
printf("[%s℄ Calling 'vn_lo
k()' has failed, with error
ode "
"%d.\n", __FUNCTION__, error);
vrele(wdvp);
return (error);
}
#if BESSSI_DBGLVL > 1
printf("[%s℄ Current working dire
tory VNODE (%p) has been su
essfuly "
"lo
ked.\n", __FUNCTION__, wdvp);
#endif
/*
* Get dire
tory parent.
*/
savp = wdvp;
if ((error = vn_dirgetparent(&wdvp, &revp, p)))
printf("[%s℄ Calling 'vn_dirgetparent()' has failed, with error"
"
ode %d.\n", __FUNCTION__, error);
else {
#if BESSSI_DBGLVL > 1
printf("[%s℄ Initial working VNODE: %p. Final working VNODE: "
"%p. Parent VNODE: %p.\n", __FUNCTION__, savp, wdvp, revp);
if (! wdvp)
printf("[%s℄ VNODE %p is the root.\n", __FUNCTION__,
savp);
#endif
}
/*
* Finalize.
*/
if (wdvp) {
vrele(wdvp);
#if BESSSI_DBGLVL > 1
printf("[%s℄ Current working dire
tory VNODE (%p) has been "
"released.\n", __FUNCTION__, wdvp);
#endif
}
if (revp) {
vput(revp);
#if BESSSI_DBGLVL > 1
printf("[%s℄ Returned VNODE (%p) has been unlo
ked.\n",
__FUNCTION__, revp);
#endif
}
return (error);
}
#endif /* BESSSI_DBGLVL > 0 */
/*
* Get parent VNODE using lookup of '..'.
* On entry:
* - '*lvpp' is the dire
tory VNODE of whi
h we must determine the parent;
'*lvpp' must be lo
ked.
* On exit:
* - '*lvpp' is either referen
ed (but not lo
ked) or set to 'NULL'; '*lvpp'
* may be different from 'NULL' and different from its value on entry, if on
* entry it designated a
overed VNODE (then it designates the last VNODE on
* the sta
k of
overed VNODE whi
h enabled to determine the parent VNODE).
* - '*uvpp' is the parent VNODE; '*uvpp' is either lo
ked (on su
ess) or set
* to 'NULL' (on failure);
* - the fun
tion returns the error
ode.
* If the fun
tion returns 0 (meaning that there had been no error) and if
* '*lvpp' is set to 'NULL', that means that '*lvpp' designates the root. Then,
* '*uvpp' is also set to 'NULL'.
*/
int
vn_dirgetparent(lvpp, uvpp, p)
stru
t vnode **lvpp;
stru
t vnode **uvpp;
stru
t pro
*p;
{
int error = 0;
stru
t vnode *lvp = *lvpp;
stru
t
omponentname
n;
stru
t vnode *rvp = p->p_fd->fd_rdir;
" dire
tory VNODE: %p. Root dire
tory VNODE: %p.\n", __FUNCTION__,
p->p_pid, *lvpp, rvp);
#endif
*uvpp = NULL;
if (lvp->v_type != VDIR) {
/* 'lvp' is not a dire
tory. */
vput(lvp);
*lvpp = NULL;
*uvpp = NULL;
error = ENOTDIR;
goto out;
}
/*
* Determine the last VNODE on the sta
k of
overed VNODE.
*/
while (lvp->v_flag & VROOT) {
/* 'lvp' is the root of its filesystem. If it is a
overed
VNODE, we must step up. */
stru
t vnode *tvp; /* Saved 'lvp'. */
if (lvp == rvp) {
/* 'lvp' is the root of the pro
ess. */
vput(lvp);
*lvpp = NULL;
*uvpp = NULL;
goto out;
}
if (lvp == NULL) {
VREF(lvp);
if ((error = vn_lo
k(lvp, LK_EXCLUSIVE | LK_RETRY, p))) {
vrele(lvp);
*lvpp = NULL;
*uvpp = NULL;
goto out;
}
}
#if BESSSI_DBGLVL > 1
printf("[%s℄ VNODE %p is not the root of its filesystem.\n",
__FUNCTION__, lvp);
#endif
n.
n_nameiop = LOOKUP;
n.
n_flags = ISLASTCN | ISDOTDOT | RDONLY;
n.
n_pro
= p;
n.
n_
red = p->p_u
red;
n.
n_pnbuf = NULL;
n.
n_nameptr = "..";
n.
n_namelen = 2;
n.
n_hash = 0;
n.
n_
onsume = 0;
if ((error = VOP_LOOKUP(lvp, uvpp, &
n))) {
#if BESSSI_DBGLVL > 0
printf("[%s℄ Error %d o
ured while lookup of VNODE %p.\n",
__FUNCTION__, error, lvp);
#endif
if (! (
n.
n_flags & PDIRUNLOCK)) {
vput(lvp);
*lvpp = NULL;
}
/* If flag 'PDIRUNLOCK' has been set by 'VOP_LOOKUP', then
'lvp' has been unlo
ked for an unsu
essful return. */
*uvpp = NULL;
goto out;
}
/* If the
all of 'VOP_LOOKUP' is su
essful, then 'lvp' is unlo
ked
and '*uvpp' is lo
ked by the lookup. */
#if BESSSI_DBGLVL > 1
printf("[%s℄ Su
essful lookup of VNODE %p.\n", __FUNCTION__, lvp);
#endif
#ifndef _VN_DIRGETPARENT_H_
#define _VN_DIRGETPARENT_H_
int vn_dirgetparent(stru
t vnode **lvpp, stru
t vnode **uvpp, stru
t pro
*p);
#if BESSSI_DBGLVL > 0
int vn_dirgetparent_test(stru
t pro
*p);
#endif
#endif /* !_VN_DIRGETPARENT_H_ */
Le makele suivant permet de
ompiler,
harger et dé
harger le module. Il permet par ailleurs de
nettoyer le répertoire de développement.
# Module name.
MODNAME:= fileutilities
# Module obje
t.
MODOBJ:= $(MODNAME).o
# Compilator.
# '-W
ast-qual' involves problems with header file '<uvm/uvm_map.h>'.
#CFLAGS+= -W
ast-qual
# Prepro
essor.
CPPFLAGS+= -D_KERNEL -Wall -Werror
CPPFLAGS+= -nostdin
-I. -I$(KSRCDIR)
all: $(MODOBJ)
lean:
rm -f $(MODOBJ) $(INTOBJS)
load:
modload -o $(MODNAME) $(MODOBJ)
unload:
modunload -n $(MODNAME)
$(MODOBJ): $(INTOBJS)
$(LD) -r -o $(MODOBJ) $(INTOBJS)
$ make
# make load
Il est alors possible de voir ave la ommande suivante si le module a bien été hargé.
$ modstat
# make unload
Important. Remarque 1.
Le
hargement et le dé
hargement du module ne peuvent se faire que par root sous un se
urelevel
stri
tement inférieur à 1.
6 Programme de test.
6.1 Code.
#define IND_SC_NUMBER 1
#define IND_LINKNAME 2
int
main(arg
, argv)
int arg
;
onst
har *argv[℄;
{
int s
_number;
har path[PATH_MAX℄;
onst
har *errstr;
/*
* Analyse de la syntaxe.
*/
if (arg
!= 3)
errx(EXIT_FAILURE, "Erreur de syntaxe. Il doit y avoir "
"exa
tement 2 arguments. Il y en a %d.\n", arg
- 1);
s
_number = strtonum(argv[IND_SC_NUMBER℄, 0, SYS_MAXSYSCALL - 1, &errstr);
if (errstr)
errx(EXIT_FAILURE, "System
all number ('%s') is %s",
argv[IND_SC_NUMBER℄, errstr);
snprintf(path, PATH_MAX, "%s/Fi
hier4", argv[IND_LINKNAME℄);
/*
* Message d'annon
e.
*/
printf("Identifiant de pro
essus : %d.\n", getpid());
/*
* Tests.
*/
if (sys
all(s
_number, "Fi
hier1"))
err(EXIT_FAILURE, NULL);
if (sys
all(s
_number, "./Fi
hier2"))
err(EXIT_FAILURE, NULL);
if (sys
all(s
_number, "../Fi
hier3"))
err(EXIT_FAILURE, NULL);
if (sys
all(s
_number, path))
err(EXIT_FAILURE, NULL);
return EXIT_SUCCESS;
}
Ce programme demande deux arguments : le numéro de l'appel système de test qui a été
réé ave
le
module, le nom du
hier dont on re
her
he le
hemin réel. On peut vérier le bon fon
tionnement des
fon
tions intégrées en analysant la sortie de la
ommande dmesg(8).
6.2 Manipulation.
La
ompilation et le lan
ement du programme de test, ainsi que le nettoyage du répertoire
ourant,
peuvent s'ee
tuer à l'aide du makele suivant.
STEM:= test
SYSCALLNUMBER:= 210
LINKNAME:= symboli
link
LINKTARGET:= /tmp/
all: $(STEM)
lean:
rm -f $(STEM) $(LINKNAME)
run:
if [ ! -e $(LINKNAME) ℄ ; then \
ln -s $(LINKTARGET) $(LINKNAME) ; \
fi
./$(STEM) $(SYSCALLNUMBER) $(LINKNAME)