Vous êtes sur la page 1sur 35

TABLE DES MATIÈRES

Paquetage File utilities.


Myriam Lagarde
myriam.lagardegmail. om
09 janvier 2008

Table des matières

1 Introdu tion. 1

2 Des ription des fon tions. 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

5 Compilation et manipulation du module. 32

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').

2 Des ription des fon tions.

int fn_lstat( onst har *path, stru t stat *sbp, stru t pro *p)

Paquetage File utilities. 1 09 janvier 2008


Cette fon tion agit omme l'appel système lstat()(2).
Elle ré upère des informations on ernant le  hier pointé par path.
Les droits en le ture, é riture et exé ution du  hier nommé ne sont pas né essaires. Cependant, tous
les répertoires listés dans le nom de hemin amenant au  hier doivent pouvoir être par ourus.
Si le  hier est un lien symboli , alors il retourne des informations on ernant le lien lui-même, et non
le  hier qui est référen é par le lien. Contrairement à d'autres objets de système de  hiers, les liens
symboliques ne possèdent pas de propriétaire, de groupe, de mode d'a ès, de dates, . . .. Ces attributs
sont pris à partir du répertoire qui ontient le lien. Les seulsattributs retounés par fn_lstat() et se
réfèrent au lien symbolique lui-même sont le type de  hier (S_IFLNK), la taille, le nombre de blo et
de liens (toujours 1).
L'information est supposée être demandée par le pro essus p.
int fn_readlink( onst har *path, har *buf, size_t size, size_t * ountp, stru t
pro *p)
Cette fon tion agit omme l'appel système readlink()(2).
Pla e le ontenu du lien symbolique path dans le tampon buf (supposé avoir une taille size).
N'ajoute de zéro terminal à la n de buf, mais retourne via * ountp le nombre de ara tères pla és
dans le tampon si la fon tion réussit.
int pr_realpath(stru t pro *p, onst har *pathname, har resolved[PATH_MAX℄)
Cette fon tion agit omme la fon tion realpath()(3).
Trouve le nom réel du hemin, en supprimant toutes les référen es aux répertoires ./ et ../, et en
développant les liens symboliques.
int vn_dirgetabsolutename(stru t vnode *lvp, har **bpp, har *bufp, int limit,
stru t pro *p)
Ré upère le nom absolu du répertoire lvp.
En entrée :
 lvp doit être référen é et verrouillé.
 bufp pointe vers le début de la zone qui ontiendra le nom.
 *bpp pointe vers l'o tet situé après la n de la zone qui ontient le nom. Ainsi, *bpp est égal à
&bufp[len℄, où len est la longueur de la zone.
 Si le paramètre limit est stri tement positif, alors il donne le nombre maximum de omposants
dans le hemin ; sinon, il indique qu'il n'y a au une limite sur le nombre de omposants.
En sortie :
 lvp est déverrouillé et déréféren é.
 *bpp est dépla é en arrière jusqu'à pointer au début du nom re her hé.
int pr_get wd1(stru t pro *p, har **pathp, har *area)
Agit omme la fon tion get wd()(3). Première syntaxe d'appel.
Copie le nom de hemin absolu du répertoire de travail ourant dans area.
En entrée :
 area pointe vers le début de la zone qui ontiendra le nom.
 *pathp pointe vers l'o tet situé après la n de la zone qui ontient le nom. Ainsi, *pathp est égal
à &area[len℄, où len est la longueur de la zone.
En sortie :
 *pathp est dépla é en arrière jusqu'à pointer au début du nom re her hé.
int pr_get wd2(stru t pro *p, har *buf, size_t size)
Agit omme la fon tion get wd()(3). Deuxième syntaxe d'appel.
Copie le nom de hemin absolu du répertoire de travail ourant dans la mémoire référen ée par buf.
L'argument size est la taille (en o tets) du tableau référen é par buf.
int vn_dirgetname(stru t vnode *lvp, stru t vnode *uvp, har **bpp, har *bufp, int
itn, stru t pro *p)
Ré upère le nom du répertoire lvp.
En entrée :

Paquetage File utilities. 2 09 janvier 2008


 lvp est le vnode du répertoire dont on doit déterminer le nom.
 lvp doit être référen é et verrouillé.
 uvp est le vnode parent de lvp. uvp peut égal à NULL (alors le vnode parent sera déterminé en
utilisant vn_dirgetparent()).
 Si uvp n'est pas égal à NULL, alors il doit être référen é et verrouillé.
 bufp pointe vers le début de la zone qui ontiendra le nom.
 *bpp pointe vers l'o tet situé après la n de la zone qui ontient le nom. Ainsi, *bpp est égal à
&bufp[len℄, où len est la longueur de la zone.
 itn indique si on doit insérer un zéro terminal.
En sortie :
 lvp est déverrouillé et déréféren é.
 Si uvp n'était pas égal à NULL en entrée, alors il est onservé verrouillé. S'il était égal à NULL en
entrée, alors le vnode parent trouvé pendant le traitement de ette fon tion est déverrouillé et
déréfen é.
 *bpp est dépla é en arrière jusqu'à pointer au début du nom re her hé.
int vn_dirgetparent(stru t vnode **lvpp, stru t vnode **uvpp, stru t pro *p)
Ré upère le vnode parent en ee tuant un lookup sur ../.
En entrée :
 *lvpp est le vnode du répertoire dont on doit déterminer le parent.
 *lvpp doit être verrouillé.
En sortie :
 *lvpp est soit référen é (mais non verrouillé), soit égal à NULL. *lvpp peut être diérent de NULL
et diérent de sa valeur en entrée, si en entrée il désignait un vnode re ouvert (il désigne alors le
dernier vnode sur la pile de vnode ouverts qui a permis de déterminer le vnode parent).
 *uvpp est le vnode parent. *uvpp est soit verrouillé (en as de su ès) ou égal à NULL (en as
d'é he ).
 La fon tion retourne le ode d'erreur.
Si la fon tion retourne 0 (signiant qu'il n'y a eu au une erreur) et si *lvpp est égal à NULL, ela
signie que lvpp désigne la ra ine. Alors *uvpp est aussi égal à NULL.

3 Mise en ÷uvre.

Le développement est entièrement réalisé sous forme de module.


Il s'agit en fait d'un module d'appel système. L'appel système implémenté n'existe que pour
fa iliter les tests à partir de la ou he appli ative.
Des parties de test ou de débogage sont onditionnées par la ma ro DBGLVL.
D'une manière générale, haque fon tion est odée dans un  hier . séparé. Dans e  hier se
trouve aussi potentiellement une fon tion de test (en adrée par un test impliquant DBGLVL). À titre
d'ex eption, les deux fon tions pr_get wd1() et pr_get wd2() sont odées dans le même  hier . . Les
 hiers . implémentant les fon tions sont a ompagnés de  hiers d'en-tête .h in luant le prototype des
fon tions implémentées (les fon tions opérationnelles ainsi que les fon tions de tests, toujours  pour
es dernières  sous la ondition de véri ation d'un prédi at impliquant DBGLVL).

4 Implémentation.

4.1 C÷ur du module.

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.

#in lude <sys/param.h>

Paquetage File utilities. 3 09 janvier 2008


4.1 C÷ur du module.

#in lude <sys/pro .h>


#in lude <sys/systm.h>
#in lude <sys/mount.h>
#in lude <sys/exe .h>
#in lude <sys/ onf.h>
#in lude <sys/lkm.h>
#in lude <sys/sys allargs.h>
#in lude <sys/types.h>
#in lude <sys/mallo .h>

#in lude "pr_get wd.h"


#in lude "pr_realpath.h"
#in lude "vn_dirgetabsolutename.h"
#in lude "vn_dirgetname.h"
#in lude "vn_dirgetparent.h"

/* Prototypes. */
int sys_test(stru t pro *p, void *v, int *retval);

/* System all arguments. */


stru t sys_test_args {
sys allarg( onst har *) path;
};

/* System all entry. */


stati stru t sysent sys_test_ent = {
1, sizeof(stru t sys_test_args), sys_test
};

/* 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 )
}

/* System all fun tion. */


int
sys_test(p, v, retval)
stru t pro *p;
void *v;
int *retval;
{
stru t sys_test_args /* {
sys allarg( onst har *) path;
} */ *uap = v;
int error;

Paquetage File utilities. 4 09 janvier 2008


4.1 C÷ur du module.

/*
* 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.
*/

Paquetage File utilities. 5 09 janvier 2008


4.2 Fon tion fn_lstat().

printf("\n");

return (0);
}

4.2 Fon tion fn_lstat().


La fon tion fn_lstat() est odée dans le  hier fn_lstat. . Son odage a été ee tué en s'ins-
pirant du ode de la fon tion sys_lstat().

Code 2. fn_lstat. .

#in lude <sys/param.h>


#in lude <sys/types.h>
#in lude <sys/uio.h>
#in lude <sys/namei.h>
#in lude <sys/vnode.h>

#in lude "fn_lstat.h"

/*
* 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;

NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_SYSSPACE,


path, p);
if ((error = namei(&nd)) != 0)
return (error);
error = vn_stat(nd.ni_vp, sbp, p);
vput(nd.ni_vp);
if (error)

Paquetage File utilities. 6 09 janvier 2008


4.3 Fon tion fn_readlink().

return (error);
if (suser(p, 0))
/* Don't let non-root see generation numbers (for NFS se urity).
*/
sbp->st_gen = 0;

return (error);
}

Cette fon tion est exportée à travers le  hier d'en-tête fn_lstat.h.

Code 3. fn_lstat.h.

#ifndef _FN_LSTAT_H_
#define _FN_LSTAT_H_

#in lude <sys/param.h>


#in lude <sys/pro .h>
#in lude <sys/stat.h>

int fn_lstat( onst har *path, stru t stat *sb, stru t pro *p);

#endif /* !_FN_LSTAT_H_ */

4.3 Fon tion fn_readlink().


La fon tion fn_readlink() est odée dans le  hier fn_readlink. . Son odage a été ee tué en
s'inspirant du ode de la fon tion sys_readlink().

Code 4. fn_readlink. .

#in lude <sys/param.h>


#in lude <sys/types.h>
#in lude <sys/uio.h>
#in lude <sys/namei.h>
#in lude <sys/vnode.h>

#in lude "fn_readlink.h"

/*
* 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)

Paquetage File utilities. 7 09 janvier 2008


4.3 Fon tion fn_readlink().

onst har *path;


har *buf;
size_t size;
size_t * ountp;
stru t pro *p;
{
stru t vnode *vp;
stru t iove aiov;
stru t uio auio;
int error = 0;
stru t nameidata nd;

NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);


if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
if (vp->v_type != VLNK)
error = EINVAL;
else {
aiov.iov_base = buf;
aiov.iov_len = size;
auio.uio_iov = &aiov;
auio.uio_iov nt = 1;
auio.uio_offset = 0;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_pro p = p;
auio.uio_resid = size;
error = VOP_READLINK(vp, &auio, p->p_u red);
}
vput(vp);
* ountp = size - auio.uio_resid;
return (error);

Cette fon tion est exportée à travers le  hier d'en-tête fn_readlink.h.

Code 5. fn_readlink.h.

#ifndef _FN_READLINK_H_
#define _FN_READLINK_H_

#in lude <sys/types.h>

int fn_readlink( onst har *path, har *buf, size_t size, size_t * ountp,
stru t pro *p);

#endif /* !_FN_READLINK_H_ */

Paquetage File utilities. 8 09 janvier 2008


4.4 Fon tion pr_get wd().

4.4 Fon tion pr_get wd().


Les fon tions pr_get wd1() et pr_get wd2() sont odées dans le  hier pr_get wd. . Le odage
de pr_get wd1() a été ee tué en s'inspirant du ode de la fon tion linux_sys_get wd() du noyau ;
pr_get wd2() s'appuie sur pr_get wd1().

Code 6. pr_get wd. .

#in lude <sys/param.h>


#in lude <sys/pro .h>
#in lude <sys/types.h>
#in lude <sys/systm.h>
#in lude <sys/mallo .h>
#in lude <sys/filedes .h>
#in lude <sys/vnode.h>

#in lude "vn_dirgetabsolutename.h"


#in lude "pr_get wd.h"

#if BESSSI_DBGLVL > 0


/*
* Test fun tion.
*/
int
pr_get wd_test(p)
stru t pro *p;
{
har *area = NULL;
har *path;
int error = 0;

/*
* 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;
}

Paquetage File utilities. 9 09 janvier 2008


4.4 Fon tion pr_get wd().

printf("[%s℄ Current working dire tory: '%s'.\n", __FUNCTION__, path);

/*
* 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);
}

Paquetage File utilities. 10 09 janvier 2008


4.4 Fon tion pr_get wd().

/*
* 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.

Code 7. pr_get wd.h.

Paquetage File utilities. 11 09 janvier 2008


4.5 Fon tion pr_readpath().

#ifndef _PR_GETCWD_H_
#define _PR_GETCWD_H_

int pr_get wd1(stru t pro *p, har **pathp, har *area);


int pr_get wd2(stru t pro *p, har *buf, size_t size);
#if BESSSI_DBGLVL > 0
int pr_get wd_test(stru t pro *p);
#endif

#endif /* !_PR_GETCWD_H_ */

4.5 Fon tion pr_readpath().


La fon tion pr_readpath() est odée dans le  hier pr_readpath. . Son odage a été ee tué en
s'inspirant du ode de la fon tion realpath() de la bibliothèque standard.

Code 8. pr_readpath. .

#in lude <sys/param.h>


#in lude <sys/pro .h>
#in lude <sys/types.h>
#in lude <sys/systm.h>

#in lude "fn_lstat.h"


#in lude "fn_readlink.h"
#in lude "pr_get wd.h"
#in lude "pr_realpath.h"

#if BESSSI_DBGLVL > 0


/*
* Test fun tion.
*/
int
pr_realpath_test(p, path)
stru t pro *p;
onst har *path;
{
int error = 0;
har resolved[PATH_MAX℄;

/*
* Announ ement.
*/
printf("[%s℄ 'prealpath_test()' has been alled by pro ess %d.\n",
__FUNCTION__, p->p_pid);

/*
* Test.
*/

Paquetage File utilities. 12 09 janvier 2008


4.5 Fon tion pr_readpath().

if ((error = pr_realpath(p, path, resolved))) {


printf("[%s℄ An error o ured while alling 'prealpath()' with "
"'%s'. Error ode: %d.\n", __FUNCTION__, path, error);
goto out;
} else
printf("[%s℄ '%s' has been resolved into '%s'.\n",
__FUNCTION__, path, resolved);

/*
* 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;
}

Paquetage File utilities. 13 09 janvier 2008


4.5 Fon tion pr_readpath().

/*
* 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;

Paquetage File utilities. 14 09 janvier 2008


4.5 Fon tion pr_readpath().

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';

Paquetage File utilities. 15 09 janvier 2008


4.5 Fon tion pr_readpath().

/*
* 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';

Paquetage File utilities. 16 09 janvier 2008


4.6 Fon tion vn_dirgetabsolutename().

out:
return (error);
}

Cette fon tion est exportée à travers le  hier d'en-tête pr_readpath.h.

Code 9. pr_readpath.h.

#ifndef _PR_REALPATH_H_
#define _PR_REALPATH_H_

int pr_realpath(stru t pro *p, onst har *pathname, har resolved[PATH_MAX℄);


#if BESSSI_DBGLVL > 0
int pr_realpath_test(stru t pro *p, onst har *path);
#endif

#endif /* !_PR_REALPATH_H_ */

4.6 Fon tion vn_dirgetabsolutename().


La fon tion vn_dirgetabsolutename() est odée dans le  hier vn_dirgetabsolutename. .

Code 10. vn_dirgetabsolutename. .

#in lude <sys/param.h>


#in lude <sys/pro .h>
#in lude <sys/systm.h>
#in lude <sys/filedes .h>
#in lude <sys/vnode.h>
#in lude <sys/mallo .h>

#in lude "vn_dirgetabsolutename.h"


#in lude "vn_dirgetname.h"
#in lude "vn_dirgetparent.h"

#if BESSSI_DBGLVL > 0


/*
* Test fun tion.
*/
int
vn_dirgetabsolutename_test(p)
stru t pro *p;
{
int error = 0;
har *path;
har *area = NULL;
stru t vnode *wdvp = NULL;

Paquetage File utilities. 17 09 janvier 2008


4.6 Fon tion vn_dirgetabsolutename().

/*
* 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

Paquetage File utilities. 18 09 janvier 2008


4.6 Fon tion vn_dirgetabsolutename().

* 'len' is the length of the area.


* - if 'limit' if is stri tly positive, it gives the maximum number of
* omponents in the path; otherwise, it indi ates that there is no limit on
* the number of omponents.
* On exit:
* - 'lvp' is unlo ked and released.
* - '*bpp' is moved ba kwards to point at the start of the name.
*/
int
vn_dirgetabsolutename(lvp, bpp, bufp, limit, p)
stru t vnode *lvp;
har **bpp;
har *bufp;
int limit;
stru t pro *p;
{
har *bp = *bpp;
stru t vnode *rvp = NULL;
int error = 0;
stru t filedes *fdp = p->p_fd;

/*
* 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.

Paquetage File utilities. 19 09 janvier 2008


4.6 Fon tion vn_dirgetabsolutename().

*/
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:

Paquetage File utilities. 20 09 janvier 2008


4.7 Fon tion vn_dirgetname().

if (bp <= bufp) {


if (pvp)
vput(pvp);
error = ERANGE;
goto out;
}
if (bp)
*(--bp) = '/';

/*
* 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);
}

Cette fon tion est exportée à travers le  hier d'en-tête vn_dirgetabsolutename.h.

Code 11. vn_dirgetabsolutename.h.

#ifndef _VN_DIRGETABSOLUTENAME_H_
#define _VN_DIRGETABSOLUTENAME_H_

#in lude <sys/param.h>


#in lude <sys/pro .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_ */

4.7 Fon tion vn_dirgetname().


La fon tion vn_dirgetname() est odée dans le  hier vn_dirgetname. .

Code 12. vn_dirgetname. .

Paquetage File utilities. 21 09 janvier 2008


4.7 Fon tion vn_dirgetname().

#in lude <sys/param.h>


#in lude <sys/pro .h>
#in lude <sys/types.h>
#in lude <sys/systm.h>
#in lude <sys/filedes .h>
#in lude <sys/vnode.h>
#in lude <ufs/ufs/dir.h>
#in lude <sys/mallo .h>
#in lude <sys/dirent.h>

#in lude "vn_dirgetname.h"


#in lude "vn_dirgetparent.h"

#if BESSSI_DBGLVL > 0


/*
* Test fun tion.
*/
int
vn_dirgetname_test(p)
stru t pro *p;
{
int error = 0;
stru t vnode *wdvp = NULL; /* Working dire tory VNODE pointer. */
har *area, *name;

/*
* 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.

Paquetage File utilities. 22 09 janvier 2008


4.7 Fon tion vn_dirgetname().

*/
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;

Paquetage File utilities. 23 09 janvier 2008


4.7 Fon tion vn_dirgetname().

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.

Paquetage File utilities. 24 09 janvier 2008


4.7 Fon tion vn_dirgetname().

*/
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.

Paquetage File utilities. 25 09 janvier 2008


4.7 Fon tion vn_dirgetname().

*/
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

/* XXX Should perhaps do 'VOP_LOOKUP' to he k that we


got ba k to the right pla e, but getting the
lo king games for that right would be heinous. */

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;

Paquetage File utilities. 26 09 janvier 2008


4.8 Fon tion vn_dirgetparent().

*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);
}

Cette fon tion est exportée à travers le  hier d'en-tête vn_dirgetname.h.

Code 13. vn_dirgetname.h.

#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_ */

4.8 Fon tion vn_dirgetparent().


La fon tion vn_dirgetparent() est odée dans le  hier vn_dirgetparent. .

Code 14. vn_dirgetparent. .

#in lude <sys/param.h>


#in lude <sys/pro .h>
#in lude <sys/mount.h>
#in lude <sys/vnode.h>
#in lude <sys/filedes .h>
#in lude <sys/namei.h>

#in lude "vn_dirgetparent.h"

Paquetage File utilities. 27 09 janvier 2008


4.8 Fon tion vn_dirgetparent().

#if BESSSI_DBGLVL > 0


/*
* Test fun tion.
*/
int
vn_dirgetparent_test(p)
stru t pro *p;
{
int error = 0;
stru t vnode *wdvp = NULL; /* Working dire tory VNODE
pointer. */
stru t vnode *revp = NULL; /* Returned VNODE pointer. */
stru t vnode *savp = NULL; /* saved VNODE pointer. */

/*
* 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
}

Paquetage File utilities. 28 09 janvier 2008


4.8 Fon tion vn_dirgetparent().

/*
* 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;

#if BESSSI_DBGLVL > 0


printf("[%s℄ 'vn_dirgetparent()' has been alled by pro ess %d. Working"

Paquetage File utilities. 29 09 janvier 2008


4.8 Fon tion vn_dirgetparent().

" 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;
}

if ((error = VOP_ACCESS(lvp, VEXEC, p->p_u red, p))) {


/* 'p' annot a ess VNODE 'lvp' with redentials
'p->p_u red' for the mode 'VEXEC'. */
vput(lvp);
*lvpp = NULL;
*uvpp = NULL;
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 BESSSI_DBGLVL > 1


printf("[%s℄ VNODE %p is the root of its filesystem.\n",
__FUNCTION__, lvp);
#endif

if (lvp == rvp) {
/* 'lvp' is the root of the pro ess. */
vput(lvp);
*lvpp = NULL;
*uvpp = NULL;
goto out;
}

tvp = lvp; /* Save 'lvp'. */


lvp = lvp->v_mount->mnt_vnode overed; /* 'lvp' was the root of
its file system. It is now the VNODE on whi h the file
system was mounted on. */
*lvpp = lvp;
vput(tvp); /* Unlo k and releases saved 'lvp' (that is to say
'tvp'). */

if (lvp == NULL) {

Paquetage File utilities. 30 09 janvier 2008


4.8 Fon tion vn_dirgetparent().

/* Hodie natus est radi i frater. */


/* 'lvp' is the root of the VFS. */
/* '*lvpp' is already unlo ked, dereferen ed and set to
'NULL'. */
*uvpp = NULL;
goto out;
}
/* A tually, it seems that 'lvp' may both be the root and be
different from 'rvp'. It seems thus that this test shows
that 'lvp' is the root, better than the test 'lvp == rvp'.
*/

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

Paquetage File utilities. 31 09 janvier 2008


out:
return error;
}

Cette fon tion est exportée à travers le  hier d'en-tête vn_dirgetparent.h.

Code 15. vn_dirgetparent.h.

#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_ */

5 Compilation et manipulation du module.

Le makele suivant permet de ompiler, harger et dé harger le module. Il permet par ailleurs de
nettoyer le répertoire de développement.

Code 16. Makefile.

.PHONY: all lean load unload

# Dire tory ontaining kernel sour es.


KSRCDIR:= $(HOME)/sr _Besssi32/sys

# Intermediate obje ts.


INTOBJS:= module.o fn_lstat.o fn_readlink.o pr_get wd.o pr_realpath.o \
vn_dirgetabsolutename.o vn_dirgetname.o vn_dirgetparent.o

# 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)

Paquetage File utilities. 32 09 janvier 2008


CPPFLAGS+= -DBESSSI_DBGLVL=1

all: $(MODOBJ)

lean:
rm -f $(MODOBJ) $(INTOBJS)

load:
modload -o $(MODNAME) $(MODOBJ)

unload:
modunload -n $(MODNAME)

$(MODOBJ): $(INTOBJS)
$(LD) -r -o $(MODOBJ) $(INTOBJS)

La ompilation s'ee tue par l'intermédiaire de la ommande suivante.

$ make

La ompilation s'ee tue par l'intermédiaire de la ommande suivante.

# make load

Il est alors possible de voir ave la ommande suivante si le module a bien été hargé.

$ modstat

La ompilation s'ee tue par l'intermédiaire de la ommande suivante.

# 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.

#in lude <stdlib.h>


#in lude <sys/sys all.h>
#in lude <sys/syslimits.h>

#define IND_SC_NUMBER 1
#define IND_LINKNAME 2

int
main(arg , argv)
int arg ;
onst har *argv[℄;

Paquetage File utilities. 33 09 janvier 2008


6.2 Manipulation.

{
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)

Paquetage File utilities. 34 09 janvier 2008


6.2 Manipulation.

lean:
rm -f $(STEM) $(LINKNAME)

run:
if [ ! -e $(LINKNAME) ℄ ; then \
ln -s $(LINKTARGET) $(LINKNAME) ; \
fi
./$(STEM) $(SYSCALLNUMBER) $(LINKNAME)

Paquetage File utilities. 35 09 janvier 2008